diff options
-rw-r--r-- | include/linux/if_vlan.h | 8 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 10 | ||||
-rw-r--r-- | net/core/dev.c | 7 |
3 files changed, 11 insertions, 14 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index e6ff12dd717b..c0ff748d0aa5 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
@@ -80,6 +80,8 @@ static inline int is_vlan_dev(struct net_device *dev) | |||
80 | } | 80 | } |
81 | 81 | ||
82 | #define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) | 82 | #define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) |
83 | #define vlan_tx_nonzero_tag_present(__skb) \ | ||
84 | (vlan_tx_tag_present(__skb) && ((__skb)->vlan_tci & VLAN_VID_MASK)) | ||
83 | #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) | 85 | #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) |
84 | 86 | ||
85 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | 87 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
@@ -89,7 +91,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev, | |||
89 | extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); | 91 | extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); |
90 | extern u16 vlan_dev_vlan_id(const struct net_device *dev); | 92 | extern u16 vlan_dev_vlan_id(const struct net_device *dev); |
91 | 93 | ||
92 | extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); | 94 | extern bool vlan_do_receive(struct sk_buff **skb); |
93 | extern struct sk_buff *vlan_untag(struct sk_buff *skb); | 95 | extern struct sk_buff *vlan_untag(struct sk_buff *skb); |
94 | 96 | ||
95 | extern int vlan_vid_add(struct net_device *dev, unsigned short vid); | 97 | extern int vlan_vid_add(struct net_device *dev, unsigned short vid); |
@@ -120,10 +122,8 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev) | |||
120 | return 0; | 122 | return 0; |
121 | } | 123 | } |
122 | 124 | ||
123 | static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler) | 125 | static inline bool vlan_do_receive(struct sk_buff **skb) |
124 | { | 126 | { |
125 | if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler) | ||
126 | (*skb)->pkt_type = PACKET_OTHERHOST; | ||
127 | return false; | 127 | return false; |
128 | } | 128 | } |
129 | 129 | ||
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index add69d0fd99d..fbbf1fa00940 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/export.h> | 5 | #include <linux/export.h> |
6 | #include "vlan.h" | 6 | #include "vlan.h" |
7 | 7 | ||
8 | bool vlan_do_receive(struct sk_buff **skbp, bool last_handler) | 8 | bool vlan_do_receive(struct sk_buff **skbp) |
9 | { | 9 | { |
10 | struct sk_buff *skb = *skbp; | 10 | struct sk_buff *skb = *skbp; |
11 | u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; | 11 | u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; |
@@ -13,14 +13,8 @@ bool vlan_do_receive(struct sk_buff **skbp, bool last_handler) | |||
13 | struct vlan_pcpu_stats *rx_stats; | 13 | struct vlan_pcpu_stats *rx_stats; |
14 | 14 | ||
15 | vlan_dev = vlan_find_dev(skb->dev, vlan_id); | 15 | vlan_dev = vlan_find_dev(skb->dev, vlan_id); |
16 | if (!vlan_dev) { | 16 | if (!vlan_dev) |
17 | /* Only the last call to vlan_do_receive() should change | ||
18 | * pkt_type to PACKET_OTHERHOST | ||
19 | */ | ||
20 | if (vlan_id && last_handler) | ||
21 | skb->pkt_type = PACKET_OTHERHOST; | ||
22 | return false; | 17 | return false; |
23 | } | ||
24 | 18 | ||
25 | skb = *skbp = skb_share_check(skb, GFP_ATOMIC); | 19 | skb = *skbp = skb_share_check(skb, GFP_ATOMIC); |
26 | if (unlikely(!skb)) | 20 | if (unlikely(!skb)) |
diff --git a/net/core/dev.c b/net/core/dev.c index d44668f63c88..09cb3f6dc40c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3300,18 +3300,18 @@ ncls: | |||
3300 | && !skb_pfmemalloc_protocol(skb)) | 3300 | && !skb_pfmemalloc_protocol(skb)) |
3301 | goto drop; | 3301 | goto drop; |
3302 | 3302 | ||
3303 | rx_handler = rcu_dereference(skb->dev->rx_handler); | ||
3304 | if (vlan_tx_tag_present(skb)) { | 3303 | if (vlan_tx_tag_present(skb)) { |
3305 | if (pt_prev) { | 3304 | if (pt_prev) { |
3306 | ret = deliver_skb(skb, pt_prev, orig_dev); | 3305 | ret = deliver_skb(skb, pt_prev, orig_dev); |
3307 | pt_prev = NULL; | 3306 | pt_prev = NULL; |
3308 | } | 3307 | } |
3309 | if (vlan_do_receive(&skb, !rx_handler)) | 3308 | if (vlan_do_receive(&skb)) |
3310 | goto another_round; | 3309 | goto another_round; |
3311 | else if (unlikely(!skb)) | 3310 | else if (unlikely(!skb)) |
3312 | goto unlock; | 3311 | goto unlock; |
3313 | } | 3312 | } |
3314 | 3313 | ||
3314 | rx_handler = rcu_dereference(skb->dev->rx_handler); | ||
3315 | if (rx_handler) { | 3315 | if (rx_handler) { |
3316 | if (pt_prev) { | 3316 | if (pt_prev) { |
3317 | ret = deliver_skb(skb, pt_prev, orig_dev); | 3317 | ret = deliver_skb(skb, pt_prev, orig_dev); |
@@ -3331,6 +3331,9 @@ ncls: | |||
3331 | } | 3331 | } |
3332 | } | 3332 | } |
3333 | 3333 | ||
3334 | if (vlan_tx_nonzero_tag_present(skb)) | ||
3335 | skb->pkt_type = PACKET_OTHERHOST; | ||
3336 | |||
3334 | /* deliver only exact match when indicated */ | 3337 | /* deliver only exact match when indicated */ |
3335 | null_or_dev = deliver_exact ? skb->dev : NULL; | 3338 | null_or_dev = deliver_exact ? skb->dev : NULL; |
3336 | 3339 | ||