kernel: fix a bridge issue that broke WDS client handling in 3.9+

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 37341
This commit is contained in:
Felix Fietkau 2013-07-15 12:25:58 +00:00
parent 866e229299
commit 93cb862260
4 changed files with 130 additions and 4 deletions

View file

@ -0,0 +1,54 @@
From: Stephen Hemminger <stephen@networkplumber.org>
Subject: bridge: allow receiption on disabled port
When an ethernet device is enslaved to a bridge, and the bridge STP
detects loss of carrier (or operational state down), then normally
packet receiption is blocked.
This breaks control applications like WPA which maybe expecting to
receive packets to negotiate to bring link up. The bridge needs to
block forwarding packets from these disabled ports, but there is no
hard requirement to not allow local packet delivery.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -139,10 +139,14 @@ drop:
static int br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
- u16 vid = 0;
- br_vlan_get_tag(skb, &vid);
- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
+ if (p->state != BR_STATE_DISABLED) {
+ u16 vid = 0;
+
+ br_vlan_get_tag(skb, &vid);
+ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
+ }
+
return 0; /* process further */
}
@@ -212,6 +216,18 @@ rx_handler_result_t br_handle_frame(stru
forward:
switch (p->state) {
+ case BR_STATE_DISABLED:
+ if (!ether_addr_equal(p->br->dev->dev_addr, dest))
+ goto drop;
+
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ br_handle_local_finish))
+ break;
+
+ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
+ br_pass_frame_up(skb);
+ break;
+
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {

View file

@ -38,7 +38,7 @@
netif_receive_skb);
}
@@ -205,7 +205,7 @@ rx_handler_result_t br_handle_frame(stru
@@ -209,7 +209,7 @@ rx_handler_result_t br_handle_frame(stru
}
/* Deliver packet to local host only */
@ -47,7 +47,16 @@
NULL, br_handle_local_finish)) {
return RX_HANDLER_CONSUMED; /* consumed by filter */
} else {
@@ -230,7 +230,7 @@ forward:
@@ -224,7 +224,7 @@ forward:
if (!ether_addr_equal(p->br->dev->dev_addr, dest))
goto drop;
- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_local_finish))
break;
@@ -246,7 +246,7 @@ forward:
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;

View file

@ -0,0 +1,54 @@
From: Stephen Hemminger <stephen@networkplumber.org>
Subject: bridge: allow receiption on disabled port
When an ethernet device is enslaved to a bridge, and the bridge STP
detects loss of carrier (or operational state down), then normally
packet receiption is blocked.
This breaks control applications like WPA which maybe expecting to
receive packets to negotiate to bring link up. The bridge needs to
block forwarding packets from these disabled ports, but there is no
hard requirement to not allow local packet delivery.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -139,10 +139,14 @@ drop:
static int br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
- u16 vid = 0;
- br_vlan_get_tag(skb, &vid);
- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
+ if (p->state != BR_STATE_DISABLED) {
+ u16 vid = 0;
+
+ br_vlan_get_tag(skb, &vid);
+ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
+ }
+
return 0; /* process further */
}
@@ -212,6 +216,18 @@ rx_handler_result_t br_handle_frame(stru
forward:
switch (p->state) {
+ case BR_STATE_DISABLED:
+ if (!ether_addr_equal(p->br->dev->dev_addr, dest))
+ goto drop;
+
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ br_handle_local_finish))
+ break;
+
+ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
+ br_pass_frame_up(skb);
+ break;
+
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {

View file

@ -38,7 +38,7 @@
netif_receive_skb);
}
@@ -205,7 +205,7 @@ rx_handler_result_t br_handle_frame(stru
@@ -209,7 +209,7 @@ rx_handler_result_t br_handle_frame(stru
}
/* Deliver packet to local host only */
@ -47,7 +47,16 @@
NULL, br_handle_local_finish)) {
return RX_HANDLER_CONSUMED; /* consumed by filter */
} else {
@@ -230,7 +230,7 @@ forward:
@@ -224,7 +224,7 @@ forward:
if (!ether_addr_equal(p->br->dev->dev_addr, dest))
goto drop;
- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_local_finish))
break;
@@ -246,7 +246,7 @@ forward:
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;