Commit d5e0fad5 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Hideaki Yoshifuji

[BRIDGE]: Get write lock in config PDU processing.

parent 7301e730
...@@ -167,13 +167,8 @@ int br_handle_frame(struct sk_buff *skb) ...@@ -167,13 +167,8 @@ int br_handle_frame(struct sk_buff *skb)
return 0; return 0;
handle_special_frame: handle_special_frame:
if (!dest[5]) {
br_stp_handle_bpdu(skb);
read_unlock(&br->lock); read_unlock(&br->lock);
return 0; if (!dest[5])
} br_stp_handle_bpdu(skb);
goto err_nolock;
kfree_skb(skb);
read_unlock(&br->lock);
return 0;
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/* called under ioctl_lock or bridge lock */ /* called under bridge lock */
int br_is_root_bridge(struct net_bridge *br) int br_is_root_bridge(struct net_bridge *br)
{ {
return !memcmp(&br->bridge_id, &br->designated_root, 8); return !memcmp(&br->bridge_id, &br->designated_root, 8);
...@@ -35,7 +35,7 @@ int br_is_designated_port(struct net_bridge_port *p) ...@@ -35,7 +35,7 @@ int br_is_designated_port(struct net_bridge_port *p)
(p->designated_port == p->port_id); (p->designated_port == p->port_id);
} }
/* called under ioctl_lock or bridge lock */ /* called under bridge lock */
struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no) struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no)
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
...@@ -419,18 +419,13 @@ static void br_topology_change_acknowledge(struct net_bridge_port *p) ...@@ -419,18 +419,13 @@ static void br_topology_change_acknowledge(struct net_bridge_port *p)
br_transmit_config(p); br_transmit_config(p);
} }
/* lock-safe */ /* called under bridge lock */
void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
{ {
struct net_bridge *br; struct net_bridge *br;
int was_root; int was_root;
if (p->state == BR_STATE_DISABLED)
return;
br = p->br; br = p->br;
read_lock(&br->lock);
was_root = br_is_root_bridge(br); was_root = br_is_root_bridge(br);
if (br_supersedes_port_info(p, bpdu)) { if (br_supersedes_port_info(p, bpdu)) {
br_record_config_information(p, bpdu); br_record_config_information(p, bpdu);
...@@ -455,21 +450,16 @@ void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *b ...@@ -455,21 +450,16 @@ void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *b
} else if (br_is_designated_port(p)) { } else if (br_is_designated_port(p)) {
br_reply(p); br_reply(p);
} }
read_unlock(&br->lock);
} }
/* lock-safe */ /* called under bridge lock */
void br_received_tcn_bpdu(struct net_bridge_port *p) void br_received_tcn_bpdu(struct net_bridge_port *p)
{ {
read_lock(&p->br->lock); if (br_is_designated_port(p)) {
if (p->state != BR_STATE_DISABLED &&
br_is_designated_port(p)) {
printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n", printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n",
p->br->dev.name, p->port_no, p->dev->name); p->br->dev.name, p->port_no, p->dev->name);
br_topology_change_detection(p->br); br_topology_change_detection(p->br);
br_topology_change_acknowledge(p); br_topology_change_acknowledge(p);
} }
read_unlock(&p->br->lock);
} }
...@@ -132,18 +132,23 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) ...@@ -132,18 +132,23 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
/* called under bridge lock */ /* NO locks */
void br_stp_handle_bpdu(struct sk_buff *skb) void br_stp_handle_bpdu(struct sk_buff *skb)
{ {
unsigned char *buf; unsigned char *buf;
struct net_bridge_port *p; struct net_bridge_port *p;
struct net_bridge *br;
buf = skb->mac.raw + 14; buf = skb->mac.raw + 14;
p = skb->dev->br_port; p = skb->dev->br_port;
if (!p->br->stp_enabled || memcmp(buf, header, 6)) { br = p->br;
kfree_skb(skb);
return; write_lock_bh(&br->lock);
} if (p->state == BR_STATE_DISABLED
|| !(br->dev.flags & IFF_UP)
|| !br->stp_enabled
|| memcmp(buf, header, 6))
goto out;
if (buf[6] == BPDU_TYPE_CONFIG) { if (buf[6] == BPDU_TYPE_CONFIG) {
struct br_config_bpdu bpdu; struct br_config_bpdu bpdu;
...@@ -178,16 +183,14 @@ void br_stp_handle_bpdu(struct sk_buff *skb) ...@@ -178,16 +183,14 @@ void br_stp_handle_bpdu(struct sk_buff *skb)
bpdu.hello_time = br_get_ticks(buf+34); bpdu.hello_time = br_get_ticks(buf+34);
bpdu.forward_delay = br_get_ticks(buf+36); bpdu.forward_delay = br_get_ticks(buf+36);
kfree_skb(skb);
br_received_config_bpdu(p, &bpdu); br_received_config_bpdu(p, &bpdu);
return; goto out;
} }
if (buf[6] == BPDU_TYPE_TCN) { if (buf[6] == BPDU_TYPE_TCN) {
br_received_tcn_bpdu(p); br_received_tcn_bpdu(p);
kfree_skb(skb); goto out;
return;
} }
out:
kfree_skb(skb); write_unlock_bh(&br->lock);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment