diff options
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r-- | net/bridge/br_input.c | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 4eef83755315..b7766562d72c 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -19,13 +19,8 @@ | |||
19 | #include <linux/netfilter_bridge.h> | 19 | #include <linux/netfilter_bridge.h> |
20 | #include "br_private.h" | 20 | #include "br_private.h" |
21 | 21 | ||
22 | const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | 22 | /* Bridge group multicast address 802.1d (pg 51). */ |
23 | 23 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | |
24 | static int br_pass_frame_up_finish(struct sk_buff *skb) | ||
25 | { | ||
26 | netif_receive_skb(skb); | ||
27 | return 0; | ||
28 | } | ||
29 | 24 | ||
30 | static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) | 25 | static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) |
31 | { | 26 | { |
@@ -38,7 +33,7 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) | |||
38 | skb->dev = br->dev; | 33 | skb->dev = br->dev; |
39 | 34 | ||
40 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, | 35 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, |
41 | br_pass_frame_up_finish); | 36 | netif_receive_skb); |
42 | } | 37 | } |
43 | 38 | ||
44 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 39 | /* note: already called with rcu_read_lock (preempt_disabled) */ |
@@ -100,6 +95,25 @@ drop: | |||
100 | goto out; | 95 | goto out; |
101 | } | 96 | } |
102 | 97 | ||
98 | /* note: already called with rcu_read_lock (preempt_disabled) */ | ||
99 | static int br_handle_local_finish(struct sk_buff *skb) | ||
100 | { | ||
101 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | ||
102 | |||
103 | if (p && p->state != BR_STATE_DISABLED) | ||
104 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | ||
105 | |||
106 | return 0; /* process further */ | ||
107 | } | ||
108 | |||
109 | /* Does address match the link local multicast address. | ||
110 | * 01:80:c2:00:00:0X | ||
111 | */ | ||
112 | static inline int is_link_local(const unsigned char *dest) | ||
113 | { | ||
114 | return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0; | ||
115 | } | ||
116 | |||
103 | /* | 117 | /* |
104 | * Called via br_handle_frame_hook. | 118 | * Called via br_handle_frame_hook. |
105 | * Return 0 if *pskb should be processed furthur | 119 | * Return 0 if *pskb should be processed furthur |
@@ -117,15 +131,10 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) | |||
117 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 131 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
118 | goto err; | 132 | goto err; |
119 | 133 | ||
120 | if (p->br->stp_enabled && | 134 | if (unlikely(is_link_local(dest))) { |
121 | !memcmp(dest, bridge_ula, 5) && | 135 | skb->pkt_type = PACKET_HOST; |
122 | !(dest[5] & 0xF0)) { | 136 | return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, |
123 | if (!dest[5]) { | 137 | NULL, br_handle_local_finish) != 0; |
124 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | ||
125 | NULL, br_stp_handle_bpdu); | ||
126 | return 1; | ||
127 | } | ||
128 | goto err; | ||
129 | } | 138 | } |
130 | 139 | ||
131 | if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) { | 140 | if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) { |