2014-07-05 01:34:38 +04:00
/* Copyright 2011-2014 Autronica Fire and Security AS
2013-10-31 00:10:47 +04:00
*
* 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 .
*
* 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
*
* This file contains device methods for creating , using and destroying
* virtual HSR devices .
*/
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/etherdevice.h>
# include <linux/rtnetlink.h>
# include <linux/pkt_sched.h>
# include "hsr_device.h"
2014-07-05 01:35:24 +04:00
# include "hsr_slave.h"
2013-10-31 00:10:47 +04:00
# include "hsr_framereg.h"
# include "hsr_main.h"
2014-07-05 01:41:03 +04:00
# include "hsr_forward.h"
2013-10-31 00:10:47 +04:00
static bool is_admin_up ( struct net_device * dev )
{
return dev & & ( dev - > flags & IFF_UP ) ;
}
static bool is_slave_up ( struct net_device * dev )
{
return dev & & is_admin_up ( dev ) & & netif_oper_up ( dev ) ;
}
static void __hsr_set_operstate ( struct net_device * dev , int transition )
{
write_lock_bh ( & dev_base_lock ) ;
if ( dev - > operstate ! = transition ) {
dev - > operstate = transition ;
write_unlock_bh ( & dev_base_lock ) ;
netdev_state_change ( dev ) ;
} else {
write_unlock_bh ( & dev_base_lock ) ;
}
}
2014-07-05 01:38:05 +04:00
static void hsr_set_operstate ( struct hsr_port * master , bool has_carrier )
2013-10-31 00:10:47 +04:00
{
2014-07-05 01:38:05 +04:00
if ( ! is_admin_up ( master - > dev ) ) {
__hsr_set_operstate ( master - > dev , IF_OPER_DOWN ) ;
2013-10-31 00:10:47 +04:00
return ;
}
2014-07-05 01:36:40 +04:00
if ( has_carrier )
2014-07-05 01:38:05 +04:00
__hsr_set_operstate ( master - > dev , IF_OPER_UP ) ;
2013-10-31 00:10:47 +04:00
else
2014-07-05 01:38:05 +04:00
__hsr_set_operstate ( master - > dev , IF_OPER_LOWERLAYERDOWN ) ;
2013-10-31 00:10:47 +04:00
}
2014-07-05 01:38:05 +04:00
static bool hsr_check_carrier ( struct hsr_port * master )
2013-10-31 00:10:47 +04:00
{
2014-07-05 01:38:05 +04:00
struct hsr_port * port ;
2014-07-05 01:36:40 +04:00
bool has_carrier ;
2014-07-05 01:38:05 +04:00
has_carrier = false ;
rcu_read_lock ( ) ;
hsr_for_each_port ( master - > hsr , port )
if ( ( port - > type ! = HSR_PT_MASTER ) & & is_slave_up ( port - > dev ) ) {
has_carrier = true ;
break ;
}
rcu_read_unlock ( ) ;
2014-07-05 01:36:40 +04:00
if ( has_carrier )
2014-07-05 01:38:05 +04:00
netif_carrier_on ( master - > dev ) ;
2013-10-31 00:10:47 +04:00
else
2014-07-05 01:38:05 +04:00
netif_carrier_off ( master - > dev ) ;
2014-07-05 01:36:40 +04:00
return has_carrier ;
2013-10-31 00:10:47 +04:00
}
2014-07-05 01:36:40 +04:00
static void hsr_check_announce ( struct net_device * hsr_dev ,
unsigned char old_operstate )
2013-10-31 00:10:47 +04:00
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( hsr_dev ) ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
if ( ( hsr_dev - > operstate = = IF_OPER_UP )
& & ( old_operstate ! = IF_OPER_UP ) ) {
2013-10-31 00:10:47 +04:00
/* Went up */
2014-07-05 01:34:38 +04:00
hsr - > announce_count = 0 ;
hsr - > announce_timer . expires = jiffies +
2013-10-31 00:10:47 +04:00
msecs_to_jiffies ( HSR_ANNOUNCE_INTERVAL ) ;
2014-07-05 01:34:38 +04:00
add_timer ( & hsr - > announce_timer ) ;
2013-10-31 00:10:47 +04:00
}
if ( ( hsr_dev - > operstate ! = IF_OPER_UP ) & & ( old_operstate = = IF_OPER_UP ) )
/* Went down */
2014-07-05 01:34:38 +04:00
del_timer ( & hsr - > announce_timer ) ;
2013-10-31 00:10:47 +04:00
}
2014-07-05 01:36:40 +04:00
void hsr_check_carrier_and_operstate ( struct hsr_priv * hsr )
{
2014-07-05 01:38:05 +04:00
struct hsr_port * master ;
2014-07-05 01:36:40 +04:00
unsigned char old_operstate ;
bool has_carrier ;
2014-07-05 01:38:05 +04:00
master = hsr_port_get_hsr ( hsr , HSR_PT_MASTER ) ;
2014-07-05 01:36:40 +04:00
/* netif_stacked_transfer_operstate() cannot be used here since
* it doesn ' t set IF_OPER_LOWERLAYERDOWN ( ? )
*/
2014-07-05 01:38:05 +04:00
old_operstate = master - > dev - > operstate ;
has_carrier = hsr_check_carrier ( master ) ;
hsr_set_operstate ( master , has_carrier ) ;
hsr_check_announce ( master - > dev , old_operstate ) ;
2014-07-05 01:36:40 +04:00
}
2014-07-05 01:34:38 +04:00
int hsr_get_max_mtu ( struct hsr_priv * hsr )
2013-10-31 00:10:47 +04:00
{
2014-07-05 01:37:27 +04:00
unsigned int mtu_max ;
2014-07-05 01:38:05 +04:00
struct hsr_port * port ;
2014-07-05 01:37:27 +04:00
mtu_max = ETH_DATA_LEN ;
rcu_read_lock ( ) ;
2014-07-05 01:38:05 +04:00
hsr_for_each_port ( hsr , port )
if ( port - > type ! = HSR_PT_MASTER )
mtu_max = min ( port - > dev - > mtu , mtu_max ) ;
2014-07-05 01:37:27 +04:00
rcu_read_unlock ( ) ;
if ( mtu_max < HSR_HLEN )
return 0 ;
2014-07-05 01:34:38 +04:00
return mtu_max - HSR_HLEN ;
2013-10-31 00:10:47 +04:00
}
2014-07-05 01:37:27 +04:00
2013-10-31 00:10:47 +04:00
static int hsr_dev_change_mtu ( struct net_device * dev , int new_mtu )
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2014-07-05 01:38:05 +04:00
struct hsr_port * master ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( dev ) ;
2014-07-05 01:38:05 +04:00
master = hsr_port_get_hsr ( hsr , HSR_PT_MASTER ) ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
if ( new_mtu > hsr_get_max_mtu ( hsr ) ) {
2014-07-05 01:38:05 +04:00
netdev_info ( master - > dev , " A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets). \n " ,
2014-07-05 01:34:38 +04:00
HSR_HLEN ) ;
2013-10-31 00:10:47 +04:00
return - EINVAL ;
}
dev - > mtu = new_mtu ;
return 0 ;
}
static int hsr_dev_open ( struct net_device * dev )
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2014-07-05 01:38:05 +04:00
struct hsr_port * port ;
char designation ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( dev ) ;
2014-07-05 01:38:05 +04:00
designation = ' \0 ' ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:38:05 +04:00
rcu_read_lock ( ) ;
hsr_for_each_port ( hsr , port ) {
if ( port - > type = = HSR_PT_MASTER )
continue ;
switch ( port - > type ) {
case HSR_PT_SLAVE_A :
designation = ' A ' ;
break ;
case HSR_PT_SLAVE_B :
designation = ' B ' ;
break ;
default :
designation = ' ? ' ;
}
if ( ! is_slave_up ( port - > dev ) )
netdev_warn ( dev , " Slave %c (%s) is not up; please bring it up to get a fully working HSR network \n " ,
designation , port - > dev - > name ) ;
2013-10-31 00:10:47 +04:00
}
2014-07-05 01:38:05 +04:00
rcu_read_unlock ( ) ;
if ( designation = = ' \0 ' )
netdev_warn ( dev , " No slave devices configured \n " ) ;
2013-10-31 00:10:47 +04:00
return 0 ;
}
2014-07-05 01:38:05 +04:00
2013-10-31 00:10:47 +04:00
static int hsr_dev_close ( struct net_device * dev )
{
2014-07-05 01:38:05 +04:00
/* Nothing to do here. */
2013-10-31 00:10:47 +04:00
return 0 ;
}
2014-07-05 01:38:57 +04:00
static netdev_features_t hsr_features_recompute ( struct hsr_priv * hsr ,
netdev_features_t features )
{
netdev_features_t mask ;
struct hsr_port * port ;
mask = features ;
/* Mask out all features that, if supported by one device, should be
* enabled for all devices ( see NETIF_F_ONE_FOR_ALL ) .
*
* Anything that ' s off in mask will not be enabled - so only things
* that were in features originally , and also is in NETIF_F_ONE_FOR_ALL ,
* may become enabled .
*/
features & = ~ NETIF_F_ONE_FOR_ALL ;
hsr_for_each_port ( hsr , port )
features = netdev_increment_features ( features ,
port - > dev - > features ,
mask ) ;
return features ;
}
static netdev_features_t hsr_fix_features ( struct net_device * dev ,
netdev_features_t features )
{
struct hsr_priv * hsr = netdev_priv ( dev ) ;
return hsr_features_recompute ( hsr , features ) ;
}
2013-10-31 00:10:47 +04:00
static int hsr_dev_xmit ( struct sk_buff * skb , struct net_device * dev )
{
2014-07-05 01:41:03 +04:00
struct hsr_priv * hsr = netdev_priv ( dev ) ;
2014-07-05 01:38:05 +04:00
struct hsr_port * master ;
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 ) ;
2014-07-05 01:41:03 +04:00
skb - > dev = master - > dev ;
hsr_forward_skb ( skb , master ) ;
2013-10-31 00:10:47 +04:00
return NETDEV_TX_OK ;
}
static const struct header_ops hsr_header_ops = {
2014-07-05 01:41:03 +04:00
. create = eth_header ,
2013-10-31 00:10:47 +04:00
. parse = eth_header_parse ,
} ;
2016-04-13 14:52:22 +03:00
static void send_hsr_supervision_frame ( struct hsr_port * master ,
u8 type , u8 hsrVer )
2013-10-31 00:10:47 +04:00
{
struct sk_buff * skb ;
int hlen , tlen ;
2016-04-13 14:52:22 +03:00
struct hsr_tag * hsr_tag ;
2013-10-31 00:10:47 +04:00
struct hsr_sup_tag * hsr_stag ;
struct hsr_sup_payload * hsr_sp ;
unsigned long irqflags ;
2014-07-05 01:38:05 +04:00
hlen = LL_RESERVED_SPACE ( master - > dev ) ;
tlen = master - > dev - > needed_tailroom ;
2016-04-13 14:52:22 +03:00
skb = dev_alloc_skb (
sizeof ( struct hsr_tag ) +
sizeof ( struct hsr_sup_tag ) +
sizeof ( struct hsr_sup_payload ) + hlen + tlen ) ;
2013-10-31 00:10:47 +04:00
if ( skb = = NULL )
return ;
skb_reserve ( skb , hlen ) ;
2014-07-05 01:38:05 +04:00
skb - > dev = master - > dev ;
2016-04-13 14:52:22 +03:00
skb - > protocol = htons ( hsrVer ? ETH_P_HSR : ETH_P_PRP ) ;
2013-10-31 00:10:47 +04:00
skb - > priority = TC_PRIO_CONTROL ;
2016-04-13 14:52:22 +03:00
if ( dev_hard_header ( skb , skb - > dev , ( hsrVer ? ETH_P_HSR : ETH_P_PRP ) ,
2014-07-05 01:41:03 +04:00
master - > hsr - > sup_multicast_addr ,
skb - > dev - > dev_addr , skb - > len ) < = 0 )
2013-10-31 00:10:47 +04:00
goto out ;
2014-07-05 01:41:03 +04:00
skb_reset_mac_header ( skb ) ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
if ( hsrVer > 0 ) {
hsr_tag = ( typeof ( hsr_tag ) ) skb_put ( skb , sizeof ( struct hsr_tag ) ) ;
hsr_tag - > encap_proto = htons ( ETH_P_PRP ) ;
set_hsr_tag_LSDU_size ( hsr_tag , HSR_V1_SUP_LSDUSIZE ) ;
}
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
hsr_stag = ( typeof ( hsr_stag ) ) skb_put ( skb , sizeof ( struct hsr_sup_tag ) ) ;
set_hsr_stag_path ( hsr_stag , ( hsrVer ? 0x0 : 0xf ) ) ;
set_hsr_stag_HSR_Ver ( hsr_stag , hsrVer ) ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
/* From HSRv1 on we have separate supervision sequence numbers. */
2014-07-05 01:41:03 +04:00
spin_lock_irqsave ( & master - > hsr - > seqnr_lock , irqflags ) ;
2016-04-13 14:52:22 +03:00
if ( hsrVer > 0 ) {
hsr_stag - > sequence_nr = htons ( master - > hsr - > sup_sequence_nr ) ;
hsr_tag - > sequence_nr = htons ( master - > hsr - > sequence_nr ) ;
master - > hsr - > sup_sequence_nr + + ;
master - > hsr - > sequence_nr + + ;
} else {
hsr_stag - > sequence_nr = htons ( master - > hsr - > sequence_nr ) ;
master - > hsr - > sequence_nr + + ;
}
2014-07-05 01:41:03 +04:00
spin_unlock_irqrestore ( & master - > hsr - > seqnr_lock , irqflags ) ;
2013-10-31 00:10:47 +04:00
hsr_stag - > HSR_TLV_Type = type ;
2016-04-13 14:52:22 +03:00
/* TODO: Why 12 in HSRv0? */
hsr_stag - > HSR_TLV_Length = hsrVer ? sizeof ( struct hsr_sup_payload ) : 12 ;
2013-10-31 00:10:47 +04:00
/* Payload: MacAddressA */
2016-04-13 14:52:22 +03:00
hsr_sp = ( typeof ( hsr_sp ) ) skb_put ( skb , sizeof ( struct hsr_sup_payload ) ) ;
2014-07-05 01:38:05 +04:00
ether_addr_copy ( hsr_sp - > MacAddressA , master - > dev - > dev_addr ) ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
skb_put_padto ( skb , ETH_ZLEN + HSR_HLEN ) ;
2014-07-05 01:41:03 +04:00
hsr_forward_skb ( skb , master ) ;
2013-10-31 00:10:47 +04:00
return ;
out :
2015-11-21 13:34:12 +03:00
WARN_ONCE ( 1 , " HSR: Could not send supervision frame \n " ) ;
2013-10-31 00:10:47 +04:00
kfree_skb ( skb ) ;
}
/* Announce (supervision frame) timer function
*/
static void hsr_announce ( unsigned long data )
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2014-07-05 01:38:05 +04:00
struct hsr_port * master ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr = ( struct hsr_priv * ) data ;
2014-07-05 01:41:03 +04:00
rcu_read_lock ( ) ;
2014-07-05 01:38:05 +04:00
master = hsr_port_get_hsr ( hsr , HSR_PT_MASTER ) ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
if ( hsr - > announce_count < 3 & & hsr - > protVersion = = 0 ) {
send_hsr_supervision_frame ( master , HSR_TLV_ANNOUNCE ,
hsr - > protVersion ) ;
2014-07-05 01:34:38 +04:00
hsr - > announce_count + + ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr - > announce_timer . expires = jiffies +
2013-10-31 00:10:47 +04:00
msecs_to_jiffies ( HSR_ANNOUNCE_INTERVAL ) ;
2016-04-13 14:52:22 +03:00
} else {
send_hsr_supervision_frame ( master , HSR_TLV_LIFE_CHECK ,
hsr - > protVersion ) ;
2014-07-05 01:34:38 +04:00
hsr - > announce_timer . expires = jiffies +
2013-10-31 00:10:47 +04:00
msecs_to_jiffies ( HSR_LIFE_CHECK_INTERVAL ) ;
2016-04-13 14:52:22 +03:00
}
2013-10-31 00:10:47 +04:00
2014-07-05 01:38:05 +04:00
if ( is_admin_up ( master - > dev ) )
2014-07-05 01:34:38 +04:00
add_timer ( & hsr - > announce_timer ) ;
2014-07-05 01:41:03 +04:00
rcu_read_unlock ( ) ;
2013-10-31 00:10:47 +04:00
}
/* According to comments in the declaration of struct net_device, this function
* is " Called from unregister, can be used to call free_netdev " . Ok then . . .
*/
static void hsr_dev_destroy ( struct net_device * hsr_dev )
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2014-07-05 01:38:05 +04:00
struct hsr_port * port ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( hsr_dev ) ;
2015-02-27 23:26:03 +03:00
rtnl_lock ( ) ;
2014-07-05 01:38:05 +04:00
hsr_for_each_port ( hsr , port )
hsr_del_port ( port ) ;
2015-02-27 23:26:03 +03:00
rtnl_unlock ( ) ;
2013-10-31 00:10:47 +04:00
2014-07-05 01:35:47 +04:00
del_timer_sync ( & hsr - > prune_timer ) ;
del_timer_sync ( & hsr - > announce_timer ) ;
2014-07-05 01:38:05 +04:00
synchronize_rcu ( ) ;
free_netdev ( hsr_dev ) ;
2013-10-31 00:10:47 +04:00
}
static const struct net_device_ops hsr_device_ops = {
. ndo_change_mtu = hsr_dev_change_mtu ,
. ndo_open = hsr_dev_open ,
. ndo_stop = hsr_dev_close ,
. ndo_start_xmit = hsr_dev_xmit ,
2014-07-05 01:38:57 +04:00
. ndo_fix_features = hsr_fix_features ,
2013-10-31 00:10:47 +04:00
} ;
2014-07-05 01:39:42 +04:00
static struct device_type hsr_type = {
. name = " hsr " ,
} ;
2013-10-31 00:10:47 +04:00
void hsr_dev_setup ( struct net_device * dev )
{
2017-02-21 16:04:59 +03:00
eth_hw_addr_random ( dev ) ;
2013-10-31 00:10:47 +04:00
ether_setup ( dev ) ;
net: use core MTU range checking in misc drivers
firewire-net:
- set min/max_mtu
- remove fwnet_change_mtu
nes:
- set max_mtu
- clean up nes_netdev_change_mtu
xpnet:
- set min/max_mtu
- remove xpnet_dev_change_mtu
hippi:
- set min/max_mtu
- remove hippi_change_mtu
batman-adv:
- set max_mtu
- remove batadv_interface_change_mtu
- initialization is a little async, not 100% certain that max_mtu is set
in the optimal place, don't have hardware to test with
rionet:
- set min/max_mtu
- remove rionet_change_mtu
slip:
- set min/max_mtu
- streamline sl_change_mtu
um/net_kern:
- remove pointless ndo_change_mtu
hsi/clients/ssi_protocol:
- use core MTU range checking
- remove now redundant ssip_pn_set_mtu
ipoib:
- set a default max MTU value
- Note: ipoib's actual max MTU can vary, depending on if the device is in
connected mode or not, so we'll just set the max_mtu value to the max
possible, and let the ndo_change_mtu function continue to validate any new
MTU change requests with checks for CM or not. Note that ipoib has no
min_mtu set, and thus, the network core's mtu > 0 check is the only lower
bounds here.
mptlan:
- use net core MTU range checking
- remove now redundant mpt_lan_change_mtu
fddi:
- min_mtu = 21, max_mtu = 4470
- remove now redundant fddi_change_mtu (including export)
fjes:
- min_mtu = 8192, max_mtu = 65536
- The max_mtu value is actually one over IP_MAX_MTU here, but the idea is to
get past the core net MTU range checks so fjes_change_mtu can validate a
new MTU against what it supports (see fjes_support_mtu in fjes_hw.c)
hsr:
- min_mtu = 0 (calls ether_setup, max_mtu is 1500)
f_phonet:
- min_mtu = 6, max_mtu = 65541
u_ether:
- min_mtu = 14, max_mtu = 15412
phonet/pep-gprs:
- min_mtu = 576, max_mtu = 65530
- remove redundant gprs_set_mtu
CC: netdev@vger.kernel.org
CC: linux-rdma@vger.kernel.org
CC: Stefan Richter <stefanr@s5r6.in-berlin.de>
CC: Faisal Latif <faisal.latif@intel.com>
CC: linux-rdma@vger.kernel.org
CC: Cliff Whickman <cpw@sgi.com>
CC: Robin Holt <robinmholt@gmail.com>
CC: Jes Sorensen <jes@trained-monkey.org>
CC: Marek Lindner <mareklindner@neomailbox.ch>
CC: Simon Wunderlich <sw@simonwunderlich.de>
CC: Antonio Quartulli <a@unstable.cc>
CC: Sathya Prakash <sathya.prakash@broadcom.com>
CC: Chaitra P B <chaitra.basappa@broadcom.com>
CC: Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
CC: MPT-FusionLinux.pdl@broadcom.com
CC: Sebastian Reichel <sre@kernel.org>
CC: Felipe Balbi <balbi@kernel.org>
CC: Arvid Brodin <arvid.brodin@alten.se>
CC: Remi Denis-Courmont <courmisch@gmail.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-10-20 20:55:22 +03:00
dev - > min_mtu = 0 ;
2014-07-05 01:39:42 +04:00
dev - > header_ops = & hsr_header_ops ;
dev - > netdev_ops = & hsr_device_ops ;
SET_NETDEV_DEVTYPE ( dev , & hsr_type ) ;
2015-08-18 11:30:45 +03:00
dev - > priv_flags | = IFF_NO_QUEUE ;
2013-10-31 00:10:47 +04:00
dev - > destructor = hsr_dev_destroy ;
2014-07-05 01:38:57 +04:00
dev - > hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_CTAG_TX ;
dev - > features = dev - > hw_features ;
/* Prevent recursive tx locking */
dev - > features | = NETIF_F_LLTX ;
/* VLAN on top of HSR needs testing and probably some work on
* hsr_header_create ( ) etc .
*/
dev - > features | = NETIF_F_VLAN_CHALLENGED ;
2014-07-05 01:39:42 +04:00
/* Not sure about this. Taken from bridge code. netdev_features.h says
* it means " Does not change network namespaces " .
*/
dev - > features | = NETIF_F_NETNS_LOCAL ;
2013-10-31 00:10:47 +04:00
}
/* Return true if dev is a HSR master; return false otherwise.
*/
2014-07-05 01:38:05 +04:00
inline bool is_hsr_master ( struct net_device * dev )
2013-10-31 00:10:47 +04:00
{
return ( dev - > netdev_ops - > ndo_start_xmit = = hsr_dev_xmit ) ;
}
/* Default multicast address for HSR Supervision frames */
2014-02-18 22:37:20 +04:00
static const unsigned char def_multicast_addr [ ETH_ALEN ] __aligned ( 2 ) = {
2013-10-31 00:10:47 +04:00
0x01 , 0x15 , 0x4e , 0x00 , 0x01 , 0x00
} ;
int hsr_dev_finalize ( struct net_device * hsr_dev , struct net_device * slave [ 2 ] ,
2016-04-13 14:52:22 +03:00
unsigned char multicast_spec , u8 protocol_version )
2013-10-31 00:10:47 +04:00
{
2014-07-05 01:34:38 +04:00
struct hsr_priv * hsr ;
2014-07-05 01:38:05 +04:00
struct hsr_port * port ;
2013-10-31 00:10:47 +04:00
int res ;
2014-07-05 01:34:38 +04:00
hsr = netdev_priv ( hsr_dev ) ;
2014-07-05 01:38:05 +04:00
INIT_LIST_HEAD ( & hsr - > ports ) ;
2014-07-05 01:34:38 +04:00
INIT_LIST_HEAD ( & hsr - > node_db ) ;
INIT_LIST_HEAD ( & hsr - > self_node_db ) ;
2014-07-05 01:37:27 +04:00
ether_addr_copy ( hsr_dev - > dev_addr , slave [ 0 ] - > dev_addr ) ;
/* Make sure we recognize frames from ourselves in hsr_rcv() */
res = hsr_create_self_node ( & hsr - > self_node_db , hsr_dev - > dev_addr ,
slave [ 1 ] - > dev_addr ) ;
if ( res < 0 )
return res ;
2014-07-05 01:34:38 +04:00
spin_lock_init ( & hsr - > seqnr_lock ) ;
2013-10-31 00:10:47 +04:00
/* Overflow soon to find bugs easier: */
2014-07-05 01:41:03 +04:00
hsr - > sequence_nr = HSR_SEQNR_START ;
2016-04-13 14:52:22 +03:00
hsr - > sup_sequence_nr = HSR_SUP_SEQNR_START ;
2013-10-31 00:10:47 +04:00
2016-05-15 17:07:44 +03:00
setup_timer ( & hsr - > announce_timer , hsr_announce , ( unsigned long ) hsr ) ;
2013-10-31 00:10:47 +04:00
2016-05-15 17:07:44 +03:00
setup_timer ( & hsr - > prune_timer , hsr_prune_nodes , ( unsigned long ) hsr ) ;
2014-07-05 01:35:47 +04:00
2014-07-05 01:34:38 +04:00
ether_addr_copy ( hsr - > sup_multicast_addr , def_multicast_addr ) ;
hsr - > sup_multicast_addr [ ETH_ALEN - 1 ] = multicast_spec ;
2013-10-31 00:10:47 +04:00
2016-04-13 14:52:22 +03:00
hsr - > protVersion = protocol_version ;
2014-07-05 01:38:05 +04:00
/* FIXME: should I modify the value of these?
*
* - hsr_dev - > flags - i . e .
* IFF_MASTER / SLAVE ?
* - hsr_dev - > priv_flags - i . e .
* IFF_EBRIDGE ?
* IFF_TX_SKB_SHARING ?
* IFF_HSR_MASTER / SLAVE ?
*/
2013-10-31 00:10:47 +04:00
/* Make sure the 1st call to netif_carrier_on() gets through */
netif_carrier_off ( hsr_dev ) ;
2014-07-05 01:38:05 +04:00
res = hsr_add_port ( hsr , hsr_dev , HSR_PT_MASTER ) ;
2013-10-31 00:10:47 +04:00
if ( res )
2014-07-05 01:37:27 +04:00
return res ;
2014-07-05 01:38:05 +04:00
res = register_netdevice ( hsr_dev ) ;
2014-07-05 01:37:27 +04:00
if ( res )
2014-07-05 01:38:05 +04:00
goto fail ;
res = hsr_add_port ( hsr , slave [ 0 ] , HSR_PT_SLAVE_A ) ;
if ( res )
goto fail ;
res = hsr_add_port ( hsr , slave [ 1 ] , HSR_PT_SLAVE_B ) ;
if ( res )
goto fail ;
2013-10-31 00:10:47 +04:00
2016-05-15 17:07:44 +03:00
mod_timer ( & hsr - > prune_timer , jiffies + msecs_to_jiffies ( PRUNE_PERIOD ) ) ;
2014-07-05 01:35:47 +04:00
2013-10-31 00:10:47 +04:00
return 0 ;
2014-07-05 01:38:05 +04:00
fail :
hsr_for_each_port ( hsr , port )
hsr_del_port ( port ) ;
return res ;
2013-10-31 00:10:47 +04:00
}