Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
[safe/jmp/linux-2.6] / net / bridge / br_notify.c
index f8fb49e..763a3ec 100644 (file)
@@ -5,8 +5,6 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br_notify.c,v 1.2 2000/02/21 15:51:34 davem Exp $
- *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
  *     as published by the Free Software Foundation; either version
@@ -14,6 +12,8 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
 
 #include "br_private.h"
 
@@ -25,7 +25,7 @@ struct notifier_block br_device_notifier = {
 
 /*
  * Handle changes in state of network devices enslaved to a bridge.
- * 
+ *
  * Note: don't care about up/down if bridge itself is down, because
  *     port state is checked when bridge is brought up.
  */
@@ -41,47 +41,53 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 
        br = p->br;
 
-       spin_lock_bh(&br->lock);
        switch (event) {
        case NETDEV_CHANGEMTU:
                dev_set_mtu(br->dev, br_min_mtu(br));
                break;
 
        case NETDEV_CHANGEADDR:
+               spin_lock_bh(&br->lock);
                br_fdb_changeaddr(p, dev->dev_addr);
                br_stp_recalculate_bridge_id(br);
+               spin_unlock_bh(&br->lock);
                break;
 
-       case NETDEV_CHANGE:     /* device is up but carrier changed */
-               if (!(br->dev->flags & IFF_UP))
-                       break;
+       case NETDEV_CHANGE:
+               br_port_carrier_check(p);
+               break;
 
-               if (netif_carrier_ok(dev)) {
-                       if (p->state == BR_STATE_DISABLED)
-                               br_stp_enable_port(p);
-               } else {
-                       if (p->state != BR_STATE_DISABLED)
-                               br_stp_disable_port(p);
-               }
+       case NETDEV_FEAT_CHANGE:
+               spin_lock_bh(&br->lock);
+               if (netif_running(br->dev))
+                       br_features_recompute(br);
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_DOWN:
+               spin_lock_bh(&br->lock);
                if (br->dev->flags & IFF_UP)
                        br_stp_disable_port(p);
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_UP:
-               if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) 
+               if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) {
+                       spin_lock_bh(&br->lock);
                        br_stp_enable_port(p);
+                       spin_unlock_bh(&br->lock);
+               }
                break;
 
        case NETDEV_UNREGISTER:
-               spin_unlock_bh(&br->lock);
                br_del_if(br, dev);
-               goto done;
-       } 
-       spin_unlock_bh(&br->lock);
+               break;
+       }
+
+       /* Events that may cause spanning tree to refresh */
+       if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
+           event == NETDEV_CHANGE || event == NETDEV_DOWN)
+               br_ifinfo_notify(RTM_NEWLINK, p);
 
- done:
        return NOTIFY_DONE;
 }