kernel: fix another corner case in the bridge state patch (#13874)
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-3.10 / 120-bridge_allow_receiption_on_disabled_port.patch
1 From: Stephen Hemminger <stephen@networkplumber.org>
2 Subject: bridge: allow receiption on disabled port
3
4 When an ethernet device is enslaved to a bridge, and the bridge STP
5 detects loss of carrier (or operational state down), then normally
6 packet receiption is blocked.
7
8 This breaks control applications like WPA which maybe expecting to
9 receive packets to negotiate to bring link up. The bridge needs to
10 block forwarding packets from these disabled ports, but there is no
11 hard requirement to not allow local packet delivery.
12
13 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
14 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
15
16 --- a/net/bridge/br_input.c
17 +++ b/net/bridge/br_input.c
18 @@ -139,10 +139,14 @@ drop:
19 static int br_handle_local_finish(struct sk_buff *skb)
20 {
21 struct net_bridge_port *p = br_port_get_rcu(skb->dev);
22 - u16 vid = 0;
23
24 - br_vlan_get_tag(skb, &vid);
25 - br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
26 + if (p->state != BR_STATE_DISABLED) {
27 + u16 vid = 0;
28 +
29 + br_vlan_get_tag(skb, &vid);
30 + br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
31 + }
32 +
33 return 0; /* process further */
34 }
35
36 @@ -212,6 +216,18 @@ rx_handler_result_t br_handle_frame(stru
37
38 forward:
39 switch (p->state) {
40 + case BR_STATE_DISABLED:
41 + if (ether_addr_equal(p->br->dev->dev_addr, dest))
42 + skb->pkt_type = PACKET_HOST;
43 +
44 + if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
45 + br_handle_local_finish))
46 + break;
47 +
48 + BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
49 + br_pass_frame_up(skb);
50 + break;
51 +
52 case BR_STATE_FORWARDING:
53 rhook = rcu_dereference(br_should_route_hook);
54 if (rhook) {