diff options
Diffstat (limited to 'net/8021q/vlan_core.c')
-rw-r--r-- | net/8021q/vlan_core.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 118adef476c3..dd86a1dc4cd0 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -3,11 +3,20 @@ | |||
3 | #include <linux/if_vlan.h> | 3 | #include <linux/if_vlan.h> |
4 | #include "vlan.h" | 4 | #include "vlan.h" |
5 | 5 | ||
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 | |||
6 | /* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ | 15 | /* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ |
7 | int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, | 16 | int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, |
8 | u16 vlan_tci, int polling) | 17 | u16 vlan_tci, int polling) |
9 | { | 18 | { |
10 | struct net_device_stats *stats; | 19 | struct vlan_hwaccel_cb *cb = vlan_hwaccel_cb(skb); |
11 | 20 | ||
12 | if (skb_bond_should_drop(skb)) { | 21 | if (skb_bond_should_drop(skb)) { |
13 | dev_kfree_skb_any(skb); | 22 | dev_kfree_skb_any(skb); |
@@ -15,22 +24,33 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, | |||
15 | } | 24 | } |
16 | 25 | ||
17 | skb->vlan_tci = vlan_tci; | 26 | skb->vlan_tci = vlan_tci; |
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 | |||
18 | netif_nit_deliver(skb); | 39 | netif_nit_deliver(skb); |
19 | 40 | ||
20 | skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); | 41 | if (dev == NULL) { |
21 | if (skb->dev == NULL) { | 42 | kfree_skb(skb); |
22 | dev_kfree_skb_any(skb); | 43 | return -1; |
23 | /* Not NET_RX_DROP, this is not being dropped | ||
24 | * due to congestion. */ | ||
25 | return NET_RX_SUCCESS; | ||
26 | } | 44 | } |
45 | |||
46 | skb->dev = dev; | ||
47 | skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); | ||
27 | skb->vlan_tci = 0; | 48 | skb->vlan_tci = 0; |
28 | 49 | ||
29 | stats = &skb->dev->stats; | 50 | stats = &dev->stats; |
30 | stats->rx_packets++; | 51 | stats->rx_packets++; |
31 | stats->rx_bytes += skb->len; | 52 | stats->rx_bytes += skb->len; |
32 | 53 | ||
33 | skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); | ||
34 | switch (skb->pkt_type) { | 54 | switch (skb->pkt_type) { |
35 | case PACKET_BROADCAST: | 55 | case PACKET_BROADCAST: |
36 | break; | 56 | break; |
@@ -42,13 +62,12 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, | |||
42 | * This allows the VLAN to have a different MAC than the | 62 | * This allows the VLAN to have a different MAC than the |
43 | * underlying device, and still route correctly. */ | 63 | * underlying device, and still route correctly. */ |
44 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, | 64 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, |
45 | skb->dev->dev_addr)) | 65 | dev->dev_addr)) |
46 | skb->pkt_type = PACKET_HOST; | 66 | skb->pkt_type = PACKET_HOST; |
47 | break; | 67 | break; |
48 | }; | 68 | }; |
49 | return (polling ? netif_receive_skb(skb) : netif_rx(skb)); | 69 | return 0; |
50 | } | 70 | } |
51 | EXPORT_SYMBOL(__vlan_hwaccel_rx); | ||
52 | 71 | ||
53 | struct net_device *vlan_dev_real_dev(const struct net_device *dev) | 72 | struct net_device *vlan_dev_real_dev(const struct net_device *dev) |
54 | { | 73 | { |