aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Zumbiehl <florz@florz.de>2012-10-07 11:51:58 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-08 15:21:55 -0400
commit48cc32d38a52d0b68f91a171a8d00531edc6a46e (patch)
tree780c4919aeda44d0c6859b840a29847aeb792d1a
parent2e71a6f8084e7ac87166dd77d99c44190fb844fc (diff)
vlan: don't deliver frames for unknown vlans to protocols
6a32e4f9dd9219261f8856f817e6655114cfec2f made the vlan code skip marking vlan-tagged frames for not locally configured vlans as PACKET_OTHERHOST if there was an rx_handler, as the rx_handler could cause the frame to be received on a different (virtual) vlan-capable interface where that vlan might be configured. As rx_handlers do not necessarily return RX_HANDLER_ANOTHER, this could cause frames for unknown vlans to be delivered to the protocol stack as if they had been received untagged. For example, if an ipv6 router advertisement that's tagged for a locally not configured vlan is received on an interface with macvlan interfaces attached, macvlan's rx_handler returns RX_HANDLER_PASS after delivering the frame to the macvlan interfaces, which caused it to be passed to the protocol stack, leading to ipv6 addresses for the announced prefix being configured even though those are completely unusable on the underlying interface. The fix moves marking as PACKET_OTHERHOST after the rx_handler so the rx_handler, if there is one, sees the frame unchanged, but afterwards, before the frame is delivered to the protocol stack, it gets marked whether there is an rx_handler or not. Signed-off-by: Florian Zumbiehl <florz@florz.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_vlan.h8
-rw-r--r--net/8021q/vlan_core.c10
-rw-r--r--net/core/dev.c7
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,
89extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); 91extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
90extern u16 vlan_dev_vlan_id(const struct net_device *dev); 92extern u16 vlan_dev_vlan_id(const struct net_device *dev);
91 93
92extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); 94extern bool vlan_do_receive(struct sk_buff **skb);
93extern struct sk_buff *vlan_untag(struct sk_buff *skb); 95extern struct sk_buff *vlan_untag(struct sk_buff *skb);
94 96
95extern int vlan_vid_add(struct net_device *dev, unsigned short vid); 97extern 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
123static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler) 125static 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
8bool vlan_do_receive(struct sk_buff **skbp, bool last_handler) 8bool 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