/* * Device event handling * Linux ethernet bridge * * Authors: * Lennert Buytenhek * * 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 * 2 of the License, or (at your option) any later version. */ #include #include #include #include "br_private.h" static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr); struct notifier_block br_device_notifier = { .notifier_call = br_device_event }; /* * 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. */ static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { #if 0 /* AVM: not present in 2.6.32: added around 3.10 * * commit: * 351638e7deeed2ec8ce451b53d33921b3da68f83 net: pass info struct via netdevice notifier */ struct net_device *dev = netdev_notifier_info_to_dev(ptr); #else struct net_device *dev = ptr; #endif struct net_bridge_port *p; struct net_bridge *br; bool changed_addr; #if 0 int err; #endif /* register of bridge completed, add sysfs entries */ if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) { br_sysfs_addbr(dev); return NOTIFY_DONE; } /* not a port of a bridge */ p = br_port_get_rtnl(dev); if (!p) return NOTIFY_DONE; br = p->br; 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); changed_addr = br_stp_recalculate_bridge_id(br); spin_unlock_bh(&br->lock); if (changed_addr) call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); break; case NETDEV_CHANGE: br_port_carrier_check(p); break; 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_running(br->dev) && netif_oper_up(dev)) { spin_lock_bh(&br->lock); br_stp_enable_port(p); spin_unlock_bh(&br->lock); } break; case NETDEV_UNREGISTER: br_del_if(br, dev); break; #if 0 /* AVM: revert effect of commit * e0f43752a942b7be1bc06b9fd74e20ae337c1cca bridge: update sysfs link names if port device names have changed */ case NETDEV_CHANGENAME: err = br_sysfs_renameif(p); if (err) return notifier_from_errno(err); break; #endif #if 0 /* AVM: not present in 2.6.32, added around 3.11 * * commit: * 4aa5dee4d9997879adff858514844efab5a15a01 net: convert resend IGMP to notifier event */ case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ return NOTIFY_BAD; #endif #if 0 /* AVM: not present in 2.6.32, added around 2.6.34 * * commit: * 1c01fe14a87332cc88266fbd6e598319322eb96f net: forbid underlaying devices to change its type */ case NETDEV_RESEND_IGMP: /* Propagate to master device */ call_netdevice_notifiers(event, br->dev); break; #endif } /* 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); return NOTIFY_DONE; }