Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 1 | #include <linux/skbuff.h> |
| 2 | #include <linux/netdevice.h> |
| 3 | #include <linux/if_vlan.h> |
| 4 | #include "vlan.h" |
| 5 | |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 6 | struct vlan_hwaccel_cb { |
| 7 | struct net_device *dev; |
| 8 | }; |
| 9 | |
| 10 | static inline struct vlan_hwaccel_cb *vlan_hwaccel_cb(struct sk_buff *skb) |
| 11 | { |
| 12 | return (struct vlan_hwaccel_cb *)skb->cb; |
| 13 | } |
| 14 | |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 15 | /* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ |
| 16 | int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, |
Patrick McHardy | 9bb8582 | 2008-07-08 03:24:44 -0700 | [diff] [blame] | 17 | u16 vlan_tci, int polling) |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 18 | { |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 19 | struct vlan_hwaccel_cb *cb = vlan_hwaccel_cb(skb); |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 20 | |
| 21 | if (skb_bond_should_drop(skb)) { |
| 22 | dev_kfree_skb_any(skb); |
| 23 | return NET_RX_DROP; |
| 24 | } |
| 25 | |
Patrick McHardy | bc1d041 | 2008-07-14 22:49:30 -0700 | [diff] [blame] | 26 | skb->vlan_tci = vlan_tci; |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 27 | cb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); |
| 28 | |
| 29 | return (polling ? netif_receive_skb(skb) : netif_rx(skb)); |
| 30 | } |
| 31 | EXPORT_SYMBOL(__vlan_hwaccel_rx); |
| 32 | |
| 33 | int vlan_hwaccel_do_receive(struct sk_buff *skb) |
| 34 | { |
| 35 | struct vlan_hwaccel_cb *cb = vlan_hwaccel_cb(skb); |
| 36 | struct net_device *dev = cb->dev; |
| 37 | struct net_device_stats *stats; |
| 38 | |
Patrick McHardy | bc1d041 | 2008-07-14 22:49:30 -0700 | [diff] [blame] | 39 | netif_nit_deliver(skb); |
| 40 | |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 41 | if (dev == NULL) { |
| 42 | kfree_skb(skb); |
| 43 | return -1; |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 44 | } |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 45 | |
| 46 | skb->dev = dev; |
| 47 | skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); |
Patrick McHardy | bc1d041 | 2008-07-14 22:49:30 -0700 | [diff] [blame] | 48 | skb->vlan_tci = 0; |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 49 | |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 50 | stats = &dev->stats; |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 51 | stats->rx_packets++; |
| 52 | stats->rx_bytes += skb->len; |
| 53 | |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 54 | switch (skb->pkt_type) { |
| 55 | case PACKET_BROADCAST: |
| 56 | break; |
| 57 | case PACKET_MULTICAST: |
| 58 | stats->multicast++; |
| 59 | break; |
| 60 | case PACKET_OTHERHOST: |
| 61 | /* Our lower layer thinks this is not local, let's make sure. |
| 62 | * This allows the VLAN to have a different MAC than the |
| 63 | * underlying device, and still route correctly. */ |
| 64 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 65 | dev->dev_addr)) |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 66 | skb->pkt_type = PACKET_HOST; |
| 67 | break; |
| 68 | }; |
Patrick McHardy | 9b22ea5 | 2008-11-04 14:49:57 -0800 | [diff] [blame] | 69 | return 0; |
Patrick McHardy | 7750f40 | 2008-07-08 03:23:36 -0700 | [diff] [blame] | 70 | } |
Patrick McHardy | 22d1ba7 | 2008-07-08 03:23:57 -0700 | [diff] [blame] | 71 | |
| 72 | struct net_device *vlan_dev_real_dev(const struct net_device *dev) |
| 73 | { |
| 74 | return vlan_dev_info(dev)->real_dev; |
| 75 | } |
| 76 | EXPORT_SYMBOL_GPL(vlan_dev_real_dev); |
| 77 | |
| 78 | u16 vlan_dev_vlan_id(const struct net_device *dev) |
| 79 | { |
| 80 | return vlan_dev_info(dev)->vlan_id; |
| 81 | } |
| 82 | EXPORT_SYMBOL_GPL(vlan_dev_vlan_id); |