#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/notifier.h>
EXPORT_SYMBOL(netif_rx_ni);
+#include <../drivers/net/bonding/bonding.h>
+
static inline struct net_device *skb_bond(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
return NULL;
}
skb->dev = dev->master;
+
+ /* The bonding driver claims to support rx vlan h/w acceleration.
+ * It actually just assumes the slave supports it and offloads the
+ * the responsibility for the acceleration to the slave.
+ * If the slave does not support rx vlan h/w acceleration
+ * then the tagged frames will end up here.
+ * When this happens we need to emulate the rx vlan h/w acceleration
+ * feature that is missing in the slave.
+ */
+ if (!(dev->features & NETIF_F_HW_VLAN_RX) &&
+ (dev->master->features & NETIF_F_HW_VLAN_RX)) {
+
+ struct bonding *bond = dev->master->priv;
+ struct vlan_group *grp = bond->vlgrp;
+ struct ethhdr *hdr = eth_hdr(skb);
+
+ if (hdr->h_proto == htons(ETH_P_8021Q) && grp &&
+ skb->len >= VLAN_ETH_HLEN) {
+ struct vlan_ethhdr *vhdr = vlan_eth_hdr(skb);
+ u16 vtag = ntohs(vhdr->h_vlan_TCI);
+
+ /* Reset skb->data to the start of the frame */
+ __skb_push(skb, skb->data - skb->mac.raw);
+
+ /* Ditch the 4 byte vlan shim */
+ memmove(skb->mac.raw + VLAN_HLEN, skb->mac.raw, ETH_ALEN * 2);
+ __skb_pull(skb, VLAN_HLEN);
+
+ /* Update the skb details */
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ /* Pass up the stack as if it came from bond0 */
+ vlan_hwaccel_rx(skb, grp, vtag);
+ return NULL;
+ }
+ }
}
return dev;