diff options
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r-- | net/bridge/br_input.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 88e4aa9cb1f9..0c7badad62af 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -139,21 +139,22 @@ static inline int is_link_local(const unsigned char *dest) | |||
139 | * Return NULL if skb is handled | 139 | * Return NULL if skb is handled |
140 | * note: already called with rcu_read_lock | 140 | * note: already called with rcu_read_lock |
141 | */ | 141 | */ |
142 | struct sk_buff *br_handle_frame(struct sk_buff *skb) | 142 | rx_handler_result_t br_handle_frame(struct sk_buff **pskb) |
143 | { | 143 | { |
144 | struct net_bridge_port *p; | 144 | struct net_bridge_port *p; |
145 | struct sk_buff *skb = *pskb; | ||
145 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 146 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
146 | br_should_route_hook_t *rhook; | 147 | br_should_route_hook_t *rhook; |
147 | 148 | ||
148 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) | 149 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) |
149 | return skb; | 150 | return RX_HANDLER_PASS; |
150 | 151 | ||
151 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 152 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
152 | goto drop; | 153 | goto drop; |
153 | 154 | ||
154 | skb = skb_share_check(skb, GFP_ATOMIC); | 155 | skb = skb_share_check(skb, GFP_ATOMIC); |
155 | if (!skb) | 156 | if (!skb) |
156 | return NULL; | 157 | return RX_HANDLER_CONSUMED; |
157 | 158 | ||
158 | p = br_port_get_rcu(skb->dev); | 159 | p = br_port_get_rcu(skb->dev); |
159 | 160 | ||
@@ -163,14 +164,16 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb) | |||
163 | goto drop; | 164 | goto drop; |
164 | 165 | ||
165 | /* If STP is turned off, then forward */ | 166 | /* If STP is turned off, then forward */ |
166 | if (p->br->stp_enabled == BR_NO_STP) | 167 | if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) |
167 | goto forward; | 168 | goto forward; |
168 | 169 | ||
169 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | 170 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, |
170 | NULL, br_handle_local_finish)) | 171 | NULL, br_handle_local_finish)) { |
171 | return NULL; /* frame consumed by filter */ | 172 | return RX_HANDLER_CONSUMED; /* consumed by filter */ |
172 | else | 173 | } else { |
173 | return skb; /* continue processing */ | 174 | *pskb = skb; |
175 | return RX_HANDLER_PASS; /* continue processing */ | ||
176 | } | ||
174 | } | 177 | } |
175 | 178 | ||
176 | forward: | 179 | forward: |
@@ -178,8 +181,10 @@ forward: | |||
178 | case BR_STATE_FORWARDING: | 181 | case BR_STATE_FORWARDING: |
179 | rhook = rcu_dereference(br_should_route_hook); | 182 | rhook = rcu_dereference(br_should_route_hook); |
180 | if (rhook) { | 183 | if (rhook) { |
181 | if ((*rhook)(skb)) | 184 | if ((*rhook)(skb)) { |
182 | return skb; | 185 | *pskb = skb; |
186 | return RX_HANDLER_PASS; | ||
187 | } | ||
183 | dest = eth_hdr(skb)->h_dest; | 188 | dest = eth_hdr(skb)->h_dest; |
184 | } | 189 | } |
185 | /* fall through */ | 190 | /* fall through */ |
@@ -194,5 +199,5 @@ forward: | |||
194 | drop: | 199 | drop: |
195 | kfree_skb(skb); | 200 | kfree_skb(skb); |
196 | } | 201 | } |
197 | return NULL; | 202 | return RX_HANDLER_CONSUMED; |
198 | } | 203 | } |