2019-04-05 20:31:34 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-07-05 01:34:38 +04:00
/* Copyright 2011-2014 Autronica Fire and Security AS
2013-10-31 00:10:47 +04:00
*
* Author ( s ) :
2014-07-05 01:34:38 +04:00
* 2011 - 2014 Arvid Brodin , arvid . brodin @ alten . se
2013-10-31 00:10:47 +04:00
*/
# include <linux/netdevice.h>
2020-06-21 16:46:25 +03:00
# include <net/rtnetlink.h>
2013-10-31 00:10:47 +04:00
# include <linux/rculist.h>
# include <linux/timer.h>
# include <linux/etherdevice.h>
# include "hsr_main.h"
# include "hsr_device.h"
# include "hsr_netlink.h"
# include "hsr_framereg.h"
2014-07-05 01:37:27 +04:00
# include "hsr_slave.h"
2013-10-31 00:10:47 +04:00
2020-04-30 20:37:02 +03:00
static bool hsr_slave_empty ( struct hsr_priv * hsr )
{
struct hsr_port * port ;
hsr_for_each_port ( hsr , port )
if ( port - > type ! = HSR_PT_MASTER )
return false ;
return true ;
}
2013-10-31 00:10:47 +04:00
static int hsr_netdev_notify ( struct notifier_block * nb , unsigned long event ,
void * ptr )
{
2014-07-05 01:38:05 +04:00
struct hsr_port * port , * master ;
2020-04-30 20:37:02 +03:00
struct net_device * dev ;
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2020-04-30 20:37:02 +03:00
LIST_HEAD ( list_kill ) ;
2013-10-31 00:10:47 +04:00
int mtu_max ;
int res ;
dev = netdev_notifier_info_to_dev ( ptr ) ;
2014-07-05 01:38:05 +04:00
port = hsr_port_get_rtnl ( dev ) ;
2019-04-05 20:31:28 +03:00
if ( ! port ) {
2013-10-31 00:10:47 +04:00
if ( ! is_hsr_master ( dev ) )
2014-07-05 01:38:05 +04:00
return NOTIFY_DONE ; /* Not an HSR device */
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( dev ) ;
2014-07-05 01:38:05 +04:00
port = hsr_port_get_hsr ( hsr , HSR_PT_MASTER ) ;
2019-04-05 20:31:28 +03:00
if ( ! port ) {
2015-02-27 23:26:03 +03:00
/* Resend of notification concerning removed device? */
return NOTIFY_DONE ;
}
2014-07-05 01:38:05 +04:00
} else {
hsr = port - > hsr ;
2013-10-31 00:10:47 +04:00
}
switch ( event ) {
case NETDEV_UP : /* Administrative state DOWN */
case NETDEV_DOWN : /* Administrative state UP */
case NETDEV_CHANGE : /* Link (carrier) state changes */
2014-07-05 01:36:40 +04:00
hsr_check_carrier_and_operstate ( hsr ) ;
2013-10-31 00:10:47 +04:00
break ;
2019-12-22 14:26:39 +03:00
case NETDEV_CHANGENAME :
2019-12-28 19:28:09 +03:00
if ( is_hsr_master ( dev ) )
hsr_debugfs_rename ( dev ) ;
2019-12-22 14:26:39 +03:00
break ;
2013-10-31 00:10:47 +04:00
case NETDEV_CHANGEADDR :
2014-07-05 01:38:05 +04:00
if ( port - > type = = HSR_PT_MASTER ) {
/* This should not happen since there's no
* ndo_set_mac_address ( ) for HSR devices - i . e . not
* supported .
*/
2013-10-31 00:10:47 +04:00
break ;
2014-07-05 01:38:05 +04:00
}
2013-10-31 00:10:47 +04:00
2014-07-05 01:38:05 +04:00
master = hsr_port_get_hsr ( hsr , HSR_PT_MASTER ) ;
if ( port - > type = = HSR_PT_SLAVE_A ) {
ether_addr_copy ( master - > dev - > dev_addr , dev - > dev_addr ) ;
2019-04-05 20:31:23 +03:00
call_netdevice_notifiers ( NETDEV_CHANGEADDR ,
master - > dev ) ;
2014-07-05 01:37:27 +04:00
}
2013-10-31 00:10:47 +04:00
/* Make sure we recognize frames from ourselves in hsr_rcv() */
2014-07-05 01:38:05 +04:00
port = hsr_port_get_hsr ( hsr , HSR_PT_SLAVE_B ) ;
2019-12-22 14:26:54 +03:00
res = hsr_create_self_node ( hsr ,
2014-07-05 01:38:05 +04:00
master - > dev - > dev_addr ,
port ?
port - > dev - > dev_addr :
master - > dev - > dev_addr ) ;
2013-10-31 00:10:47 +04:00
if ( res )
2014-07-05 01:38:05 +04:00
netdev_warn ( master - > dev ,
2013-10-31 00:10:47 +04:00
" Could not update HSR node address. \n " ) ;
break ;
case NETDEV_CHANGEMTU :
2014-07-05 01:38:05 +04:00
if ( port - > type = = HSR_PT_MASTER )
2013-10-31 00:10:47 +04:00
break ; /* Handled in ndo_change_mtu() */
2014-07-05 01:38:05 +04:00
mtu_max = hsr_get_max_mtu ( port - > hsr ) ;
master = hsr_port_get_hsr ( port - > hsr , HSR_PT_MASTER ) ;
master - > dev - > mtu = mtu_max ;
2013-10-31 00:10:47 +04:00
break ;
case NETDEV_UNREGISTER :
2020-04-30 20:37:02 +03:00
if ( ! is_hsr_master ( dev ) ) {
master = hsr_port_get_hsr ( port - > hsr , HSR_PT_MASTER ) ;
2020-02-28 21:02:10 +03:00
hsr_del_port ( port ) ;
2020-04-30 20:37:02 +03:00
if ( hsr_slave_empty ( master - > hsr ) ) {
2020-06-21 16:46:25 +03:00
const struct rtnl_link_ops * ops ;
ops = master - > dev - > rtnl_link_ops ;
ops - > dellink ( master - > dev , & list_kill ) ;
2020-04-30 20:37:02 +03:00
unregister_netdevice_many ( & list_kill ) ;
}
}
2013-10-31 00:10:47 +04:00
break ;
case NETDEV_PRE_TYPE_CHANGE :
/* HSR works only on Ethernet devices. Refuse slave to change
* its type .
*/
return NOTIFY_BAD ;
}
return NOTIFY_DONE ;
}
2014-07-05 01:38:05 +04:00
struct hsr_port * hsr_port_get_hsr ( struct hsr_priv * hsr , enum hsr_port_type pt )
{
struct hsr_port * port ;
hsr_for_each_port ( hsr , port )
if ( port - > type = = pt )
return port ;
return NULL ;
}
2013-10-31 00:10:47 +04:00
static struct notifier_block hsr_nb = {
. notifier_call = hsr_netdev_notify , /* Slave event notifications */
} ;
static int __init hsr_init ( void )
{
int res ;
2014-07-05 01:34:38 +04:00
BUILD_BUG_ON ( sizeof ( struct hsr_tag ) ! = HSR_HLEN ) ;
2013-10-31 00:10:47 +04:00
register_netdevice_notifier ( & hsr_nb ) ;
res = hsr_netlink_init ( ) ;
return res ;
}
static void __exit hsr_exit ( void )
{
hsr_netlink_exit ( ) ;
2019-12-22 14:26:27 +03:00
hsr_debugfs_remove_root ( ) ;
2020-06-21 16:46:25 +03:00
unregister_netdevice_notifier ( & hsr_nb ) ;
2013-10-31 00:10:47 +04:00
}
module_init ( hsr_init ) ;
module_exit ( hsr_exit ) ;
MODULE_LICENSE ( " GPL " ) ;