Patch to 2.6.15 stable kernel to fix race conditions on device
removal.  These are reproducible by doing delif while packets are
in flight.

Signed-off-by: Stephen Hemminger <[EMAIL PROTECTED]>


--- linux-2.6.15.2.orig/net/bridge/br_if.c
+++ linux-2.6.15.2/net/bridge/br_if.c
@@ -99,7 +99,6 @@ static void del_nbp(struct net_bridge_po
        struct net_bridge *br = p->br;
        struct net_device *dev = p->dev;
 
-       dev->br_port = NULL;
        dev_set_promiscuity(dev, -1);
 
        spin_lock_bh(&br->lock);
@@ -110,9 +109,7 @@ static void del_nbp(struct net_bridge_po
 
        list_del_rcu(&p->list);
 
-       del_timer_sync(&p->message_age_timer);
-       del_timer_sync(&p->forward_delay_timer);
-       del_timer_sync(&p->hold_timer);
+       rcu_assign_pointer(dev->br_port, NULL);
        
        call_rcu(&p->rcu, destroy_nbp_rcu);
 }
@@ -217,7 +214,6 @@ static struct net_bridge_port *new_nbp(s
        p->dev = dev;
        p->path_cost = cost;
        p->priority = 0x8000 >> BR_PORT_BITS;
-       dev->br_port = p;
        p->port_no = index;
        br_init_port(p);
        p->state = BR_STATE_DISABLED;
@@ -360,6 +356,7 @@ int br_add_if(struct net_bridge *br, str
        else if ((err = br_sysfs_addif(p)))
                del_nbp(p);
        else {
+               rcu_assign_pointer(dev->br_port, p);
                dev_set_promiscuity(dev, 1);
 
                list_add_rcu(&p->list, &br->port_list);
--- linux-2.6.15.2.orig/net/bridge/br_input.c
+++ linux-2.6.15.2/net/bridge/br_input.c
@@ -45,11 +45,17 @@ static void br_pass_frame_up(struct net_
 int br_handle_frame_finish(struct sk_buff *skb)
 {
        const unsigned char *dest = eth_hdr(skb)->h_dest;
-       struct net_bridge_port *p = skb->dev->br_port;
-       struct net_bridge *br = p->br;
+       struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+       struct net_bridge *br;
        struct net_bridge_fdb_entry *dst;
        int passedup = 0;
 
+       if (unlikely(!p || p->state == BR_STATE_DISABLED)) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       br = p->br;
        /* insert into forwarding database after filtering to avoid spoofing */
        br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
 
--- linux-2.6.15.2.orig/net/bridge/br_stp_bpdu.c
+++ linux-2.6.15.2/net/bridge/br_stp_bpdu.c
@@ -136,10 +136,13 @@ static const unsigned char header[6] = {
 /* NO locks */
 int br_stp_handle_bpdu(struct sk_buff *skb)
 {
-       struct net_bridge_port *p = skb->dev->br_port;
-       struct net_bridge *br = p->br;
+       struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+       struct net_bridge *br;
        unsigned char *buf;
 
+       if (!p)
+               goto err;
+
        /* insert into forwarding database after filtering to avoid spoofing */
        br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
 
@@ -150,6 +153,7 @@ int br_stp_handle_bpdu(struct sk_buff *s
 
        buf = skb_pull(skb, sizeof(header));
 
+       br = p->br;
        spin_lock_bh(&br->lock);
        if (p->state == BR_STATE_DISABLED 
            || !(br->dev->flags & IFF_UP)
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to