2005-04-17 02:20:36 +04:00
/*
* Device event handling
* Linux ethernet bridge
*
* Authors :
* Lennert Buytenhek < buytenh @ gnu . org >
*
* 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 <linux/kernel.h>
2006-05-26 03:00:12 +04:00
# include <linux/rtnetlink.h>
2007-09-12 15:02:17 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
# 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 .
2007-02-09 17:24:35 +03:00
*
2005-04-17 02:20:36 +04:00
* 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 )
{
struct net_device * dev = ptr ;
2010-11-15 09:38:13 +03:00
struct net_bridge_port * p ;
2005-04-17 02:20:36 +04:00
struct net_bridge * br ;
2011-08-05 15:04:10 +04:00
bool changed_addr ;
2010-05-10 13:31:11 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2011-04-04 18:03:32 +04:00
/* register of bridge completed, add sysfs entries */
2011-04-18 04:52:51 +04:00
if ( ( dev - > priv_flags & IFF_EBRIDGE ) & & event = = NETDEV_REGISTER ) {
2011-04-04 18:03:32 +04:00
br_sysfs_addbr ( dev ) ;
return NOTIFY_DONE ;
}
2005-04-17 02:20:36 +04:00
/* not a port of a bridge */
2010-11-15 09:38:14 +03:00
p = br_port_get_rtnl ( dev ) ;
if ( ! p )
2005-04-17 02:20:36 +04:00
return NOTIFY_DONE ;
br = p - > br ;
switch ( event ) {
case NETDEV_CHANGEMTU :
dev_set_mtu ( br - > dev , br_min_mtu ( br ) ) ;
break ;
case NETDEV_CHANGEADDR :
2007-02-22 12:10:18 +03:00
spin_lock_bh ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
br_fdb_changeaddr ( p , dev - > dev_addr ) ;
2011-08-05 15:04:10 +04:00
changed_addr = br_stp_recalculate_bridge_id ( br ) ;
2007-02-22 12:10:18 +03:00
spin_unlock_bh ( & br - > lock ) ;
2011-08-05 15:04:10 +04:00
if ( changed_addr )
call_netdevice_notifiers ( NETDEV_CHANGEADDR , br - > dev ) ;
2005-04-17 02:20:36 +04:00
break ;
2005-12-21 02:19:51 +03:00
case NETDEV_CHANGE :
2007-02-22 12:10:18 +03:00
br_port_carrier_check ( p ) ;
2005-04-17 02:20:36 +04:00
break ;
2005-05-30 01:15:17 +04:00
case NETDEV_FEAT_CHANGE :
2011-04-22 10:31:16 +04:00
netdev_update_features ( br - > dev ) ;
2005-05-30 01:15:17 +04:00
break ;
2005-04-17 02:20:36 +04:00
case NETDEV_DOWN :
2007-02-22 12:10:18 +03:00
spin_lock_bh ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( br - > dev - > flags & IFF_UP )
br_stp_disable_port ( p ) ;
2007-02-22 12:10:18 +03:00
spin_unlock_bh ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
break ;
case NETDEV_UP :
2007-03-23 00:08:46 +03:00
if ( netif_carrier_ok ( dev ) & & ( br - > dev - > flags & IFF_UP ) ) {
spin_lock_bh ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
br_stp_enable_port ( p ) ;
2007-03-23 00:08:46 +03:00
spin_unlock_bh ( & br - > lock ) ;
}
2005-04-17 02:20:36 +04:00
break ;
case NETDEV_UNREGISTER :
br_del_if ( br , dev ) ;
2007-02-22 12:10:18 +03:00
break ;
2010-03-10 13:30:19 +03:00
2010-05-10 13:31:11 +04:00
case NETDEV_CHANGENAME :
err = br_sysfs_renameif ( p ) ;
if ( err )
return notifier_from_errno ( err ) ;
break ;
2010-03-10 13:30:19 +03:00
case NETDEV_PRE_TYPE_CHANGE :
/* Forbid underlaying device to change its type. */
return NOTIFY_BAD ;
2007-02-09 17:24:35 +03:00
}
2005-04-17 02:20:36 +04:00
2007-03-23 00:08:46 +03:00
/* 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 ) ;
2005-04-17 02:20:36 +04:00
return NOTIFY_DONE ;
}