18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright 2011-2014 Autronica Fire and Security AS 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author(s): 58c2ecf20Sopenharmony_ci * 2011-2014 Arvid Brodin, arvid.brodin@alten.se 68c2ecf20Sopenharmony_ci * This file contains device methods for creating, using and destroying 78c2ecf20Sopenharmony_ci * virtual HSR or PRP devices. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 148c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 158c2ecf20Sopenharmony_ci#include "hsr_device.h" 168c2ecf20Sopenharmony_ci#include "hsr_slave.h" 178c2ecf20Sopenharmony_ci#include "hsr_framereg.h" 188c2ecf20Sopenharmony_ci#include "hsr_main.h" 198c2ecf20Sopenharmony_ci#include "hsr_forward.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic bool is_admin_up(struct net_device *dev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return dev && (dev->flags & IFF_UP); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic bool is_slave_up(struct net_device *dev) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return dev && is_admin_up(dev) && netif_oper_up(dev); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void __hsr_set_operstate(struct net_device *dev, int transition) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci write_lock_bh(&dev_base_lock); 348c2ecf20Sopenharmony_ci if (dev->operstate != transition) { 358c2ecf20Sopenharmony_ci dev->operstate = transition; 368c2ecf20Sopenharmony_ci write_unlock_bh(&dev_base_lock); 378c2ecf20Sopenharmony_ci netdev_state_change(dev); 388c2ecf20Sopenharmony_ci } else { 398c2ecf20Sopenharmony_ci write_unlock_bh(&dev_base_lock); 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void hsr_set_operstate(struct hsr_port *master, bool has_carrier) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (!is_admin_up(master->dev)) { 468c2ecf20Sopenharmony_ci __hsr_set_operstate(master->dev, IF_OPER_DOWN); 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (has_carrier) 518c2ecf20Sopenharmony_ci __hsr_set_operstate(master->dev, IF_OPER_UP); 528c2ecf20Sopenharmony_ci else 538c2ecf20Sopenharmony_ci __hsr_set_operstate(master->dev, IF_OPER_LOWERLAYERDOWN); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool hsr_check_carrier(struct hsr_port *master) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct hsr_port *port; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ASSERT_RTNL(); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci hsr_for_each_port(master->hsr, port) { 638c2ecf20Sopenharmony_ci if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) { 648c2ecf20Sopenharmony_ci netif_carrier_on(master->dev); 658c2ecf20Sopenharmony_ci return true; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci netif_carrier_off(master->dev); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return false; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void hsr_check_announce(struct net_device *hsr_dev, 758c2ecf20Sopenharmony_ci unsigned char old_operstate) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct hsr_priv *hsr; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci hsr = netdev_priv(hsr_dev); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (hsr_dev->operstate == IF_OPER_UP && old_operstate != IF_OPER_UP) { 828c2ecf20Sopenharmony_ci /* Went up */ 838c2ecf20Sopenharmony_ci hsr->announce_count = 0; 848c2ecf20Sopenharmony_ci mod_timer(&hsr->announce_timer, 858c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL)); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (hsr_dev->operstate != IF_OPER_UP && old_operstate == IF_OPER_UP) 898c2ecf20Sopenharmony_ci /* Went down */ 908c2ecf20Sopenharmony_ci del_timer(&hsr->announce_timer); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_civoid hsr_check_carrier_and_operstate(struct hsr_priv *hsr) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct hsr_port *master; 968c2ecf20Sopenharmony_ci unsigned char old_operstate; 978c2ecf20Sopenharmony_ci bool has_carrier; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 1008c2ecf20Sopenharmony_ci /* netif_stacked_transfer_operstate() cannot be used here since 1018c2ecf20Sopenharmony_ci * it doesn't set IF_OPER_LOWERLAYERDOWN (?) 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci old_operstate = master->dev->operstate; 1048c2ecf20Sopenharmony_ci has_carrier = hsr_check_carrier(master); 1058c2ecf20Sopenharmony_ci hsr_set_operstate(master, has_carrier); 1068c2ecf20Sopenharmony_ci hsr_check_announce(master->dev, old_operstate); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint hsr_get_max_mtu(struct hsr_priv *hsr) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned int mtu_max; 1128c2ecf20Sopenharmony_ci struct hsr_port *port; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci mtu_max = ETH_DATA_LEN; 1158c2ecf20Sopenharmony_ci hsr_for_each_port(hsr, port) 1168c2ecf20Sopenharmony_ci if (port->type != HSR_PT_MASTER) 1178c2ecf20Sopenharmony_ci mtu_max = min(port->dev->mtu, mtu_max); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (mtu_max < HSR_HLEN) 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci return mtu_max - HSR_HLEN; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct hsr_priv *hsr; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci hsr = netdev_priv(dev); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (new_mtu > hsr_get_max_mtu(hsr)) { 1318c2ecf20Sopenharmony_ci netdev_info(dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", 1328c2ecf20Sopenharmony_ci HSR_HLEN); 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int hsr_dev_open(struct net_device *dev) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct hsr_priv *hsr; 1448c2ecf20Sopenharmony_ci struct hsr_port *port; 1458c2ecf20Sopenharmony_ci char designation; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci hsr = netdev_priv(dev); 1488c2ecf20Sopenharmony_ci designation = '\0'; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci hsr_for_each_port(hsr, port) { 1518c2ecf20Sopenharmony_ci if (port->type == HSR_PT_MASTER) 1528c2ecf20Sopenharmony_ci continue; 1538c2ecf20Sopenharmony_ci switch (port->type) { 1548c2ecf20Sopenharmony_ci case HSR_PT_SLAVE_A: 1558c2ecf20Sopenharmony_ci designation = 'A'; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case HSR_PT_SLAVE_B: 1588c2ecf20Sopenharmony_ci designation = 'B'; 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci default: 1618c2ecf20Sopenharmony_ci designation = '?'; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci if (!is_slave_up(port->dev)) 1648c2ecf20Sopenharmony_ci netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a fully working HSR network\n", 1658c2ecf20Sopenharmony_ci designation, port->dev->name); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (designation == '\0') 1698c2ecf20Sopenharmony_ci netdev_warn(dev, "No slave devices configured\n"); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int hsr_dev_close(struct net_device *dev) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci /* Nothing to do here. */ 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic netdev_features_t hsr_features_recompute(struct hsr_priv *hsr, 1818c2ecf20Sopenharmony_ci netdev_features_t features) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci netdev_features_t mask; 1848c2ecf20Sopenharmony_ci struct hsr_port *port; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci mask = features; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Mask out all features that, if supported by one device, should be 1898c2ecf20Sopenharmony_ci * enabled for all devices (see NETIF_F_ONE_FOR_ALL). 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * Anything that's off in mask will not be enabled - so only things 1928c2ecf20Sopenharmony_ci * that were in features originally, and also is in NETIF_F_ONE_FOR_ALL, 1938c2ecf20Sopenharmony_ci * may become enabled. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci features &= ~NETIF_F_ONE_FOR_ALL; 1968c2ecf20Sopenharmony_ci hsr_for_each_port(hsr, port) 1978c2ecf20Sopenharmony_ci features = netdev_increment_features(features, 1988c2ecf20Sopenharmony_ci port->dev->features, 1998c2ecf20Sopenharmony_ci mask); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return features; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic netdev_features_t hsr_fix_features(struct net_device *dev, 2058c2ecf20Sopenharmony_ci netdev_features_t features) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct hsr_priv *hsr = netdev_priv(dev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return hsr_features_recompute(hsr, features); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct hsr_priv *hsr = netdev_priv(dev); 2158c2ecf20Sopenharmony_ci struct hsr_port *master; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 2188c2ecf20Sopenharmony_ci if (master) { 2198c2ecf20Sopenharmony_ci skb->dev = master->dev; 2208c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 2218c2ecf20Sopenharmony_ci skb_reset_mac_len(skb); 2228c2ecf20Sopenharmony_ci spin_lock_bh(&hsr->seqnr_lock); 2238c2ecf20Sopenharmony_ci hsr_forward_skb(skb, master); 2248c2ecf20Sopenharmony_ci spin_unlock_bh(&hsr->seqnr_lock); 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci atomic_long_inc(&dev->tx_dropped); 2278c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct header_ops hsr_header_ops = { 2338c2ecf20Sopenharmony_ci .create = eth_header, 2348c2ecf20Sopenharmony_ci .parse = eth_header_parse, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic struct sk_buff *hsr_init_skb(struct hsr_port *master) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct hsr_priv *hsr = master->hsr; 2408c2ecf20Sopenharmony_ci struct sk_buff *skb; 2418c2ecf20Sopenharmony_ci int hlen, tlen; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci hlen = LL_RESERVED_SPACE(master->dev); 2448c2ecf20Sopenharmony_ci tlen = master->dev->needed_tailroom; 2458c2ecf20Sopenharmony_ci /* skb size is same for PRP/HSR frames, only difference 2468c2ecf20Sopenharmony_ci * being, for PRP it is a trailer and for HSR it is a 2478c2ecf20Sopenharmony_ci * header 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci skb = dev_alloc_skb(sizeof(struct hsr_sup_tag) + 2508c2ecf20Sopenharmony_ci sizeof(struct hsr_sup_payload) + hlen + tlen); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (!skb) 2538c2ecf20Sopenharmony_ci return skb; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci skb_reserve(skb, hlen); 2568c2ecf20Sopenharmony_ci skb->dev = master->dev; 2578c2ecf20Sopenharmony_ci skb->priority = TC_PRIO_CONTROL; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (dev_hard_header(skb, skb->dev, ETH_P_PRP, 2608c2ecf20Sopenharmony_ci hsr->sup_multicast_addr, 2618c2ecf20Sopenharmony_ci skb->dev->dev_addr, skb->len) <= 0) 2628c2ecf20Sopenharmony_ci goto out; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 2658c2ecf20Sopenharmony_ci skb_reset_mac_len(skb); 2668c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2678c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return skb; 2708c2ecf20Sopenharmony_ciout: 2718c2ecf20Sopenharmony_ci kfree_skb(skb); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return NULL; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void send_hsr_supervision_frame(struct hsr_port *master, 2778c2ecf20Sopenharmony_ci unsigned long *interval) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct hsr_priv *hsr = master->hsr; 2808c2ecf20Sopenharmony_ci __u8 type = HSR_TLV_LIFE_CHECK; 2818c2ecf20Sopenharmony_ci struct hsr_sup_payload *hsr_sp; 2828c2ecf20Sopenharmony_ci struct hsr_sup_tag *hsr_stag; 2838c2ecf20Sopenharmony_ci struct sk_buff *skb; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci *interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); 2868c2ecf20Sopenharmony_ci if (hsr->announce_count < 3 && hsr->prot_version == 0) { 2878c2ecf20Sopenharmony_ci type = HSR_TLV_ANNOUNCE; 2888c2ecf20Sopenharmony_ci *interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); 2898c2ecf20Sopenharmony_ci hsr->announce_count++; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci skb = hsr_init_skb(master); 2938c2ecf20Sopenharmony_ci if (!skb) { 2948c2ecf20Sopenharmony_ci netdev_warn_once(master->dev, "HSR: Could not send supervision frame\n"); 2958c2ecf20Sopenharmony_ci return; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag)); 2998c2ecf20Sopenharmony_ci set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf)); 3008c2ecf20Sopenharmony_ci set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* From HSRv1 on we have separate supervision sequence numbers. */ 3038c2ecf20Sopenharmony_ci spin_lock_bh(&hsr->seqnr_lock); 3048c2ecf20Sopenharmony_ci if (hsr->prot_version > 0) { 3058c2ecf20Sopenharmony_ci hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); 3068c2ecf20Sopenharmony_ci hsr->sup_sequence_nr++; 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci hsr_stag->sequence_nr = htons(hsr->sequence_nr); 3098c2ecf20Sopenharmony_ci hsr->sequence_nr++; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci hsr_stag->HSR_TLV_type = type; 3138c2ecf20Sopenharmony_ci /* TODO: Why 12 in HSRv0? */ 3148c2ecf20Sopenharmony_ci hsr_stag->HSR_TLV_length = hsr->prot_version ? 3158c2ecf20Sopenharmony_ci sizeof(struct hsr_sup_payload) : 12; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Payload: MacAddressA */ 3188c2ecf20Sopenharmony_ci hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); 3198c2ecf20Sopenharmony_ci ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (skb_put_padto(skb, ETH_ZLEN)) { 3228c2ecf20Sopenharmony_ci spin_unlock_bh(&hsr->seqnr_lock); 3238c2ecf20Sopenharmony_ci return; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci hsr_forward_skb(skb, master); 3278c2ecf20Sopenharmony_ci spin_unlock_bh(&hsr->seqnr_lock); 3288c2ecf20Sopenharmony_ci return; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void send_prp_supervision_frame(struct hsr_port *master, 3328c2ecf20Sopenharmony_ci unsigned long *interval) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct hsr_priv *hsr = master->hsr; 3358c2ecf20Sopenharmony_ci struct hsr_sup_payload *hsr_sp; 3368c2ecf20Sopenharmony_ci struct hsr_sup_tag *hsr_stag; 3378c2ecf20Sopenharmony_ci struct sk_buff *skb; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci skb = hsr_init_skb(master); 3408c2ecf20Sopenharmony_ci if (!skb) { 3418c2ecf20Sopenharmony_ci netdev_warn_once(master->dev, "PRP: Could not send supervision frame\n"); 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci *interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); 3468c2ecf20Sopenharmony_ci hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag)); 3478c2ecf20Sopenharmony_ci set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf)); 3488c2ecf20Sopenharmony_ci set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0)); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* From HSRv1 on we have separate supervision sequence numbers. */ 3518c2ecf20Sopenharmony_ci spin_lock_bh(&hsr->seqnr_lock); 3528c2ecf20Sopenharmony_ci hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); 3538c2ecf20Sopenharmony_ci hsr->sup_sequence_nr++; 3548c2ecf20Sopenharmony_ci hsr_stag->HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD; 3558c2ecf20Sopenharmony_ci hsr_stag->HSR_TLV_length = sizeof(struct hsr_sup_payload); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Payload: MacAddressA */ 3588c2ecf20Sopenharmony_ci hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); 3598c2ecf20Sopenharmony_ci ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (skb_put_padto(skb, ETH_ZLEN)) { 3628c2ecf20Sopenharmony_ci spin_unlock_bh(&hsr->seqnr_lock); 3638c2ecf20Sopenharmony_ci return; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci hsr_forward_skb(skb, master); 3678c2ecf20Sopenharmony_ci spin_unlock_bh(&hsr->seqnr_lock); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/* Announce (supervision frame) timer function 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_cistatic void hsr_announce(struct timer_list *t) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct hsr_priv *hsr; 3758c2ecf20Sopenharmony_ci struct hsr_port *master; 3768c2ecf20Sopenharmony_ci unsigned long interval; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci hsr = from_timer(hsr, t, announce_timer); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci rcu_read_lock(); 3818c2ecf20Sopenharmony_ci master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 3828c2ecf20Sopenharmony_ci hsr->proto_ops->send_sv_frame(master, &interval); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (is_admin_up(master->dev)) 3858c2ecf20Sopenharmony_ci mod_timer(&hsr->announce_timer, jiffies + interval); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci rcu_read_unlock(); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_civoid hsr_del_ports(struct hsr_priv *hsr) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct hsr_port *port; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); 3958c2ecf20Sopenharmony_ci if (port) 3968c2ecf20Sopenharmony_ci hsr_del_port(port); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); 3998c2ecf20Sopenharmony_ci if (port) 4008c2ecf20Sopenharmony_ci hsr_del_port(port); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 4038c2ecf20Sopenharmony_ci if (port) 4048c2ecf20Sopenharmony_ci hsr_del_port(port); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic const struct net_device_ops hsr_device_ops = { 4088c2ecf20Sopenharmony_ci .ndo_change_mtu = hsr_dev_change_mtu, 4098c2ecf20Sopenharmony_ci .ndo_open = hsr_dev_open, 4108c2ecf20Sopenharmony_ci .ndo_stop = hsr_dev_close, 4118c2ecf20Sopenharmony_ci .ndo_start_xmit = hsr_dev_xmit, 4128c2ecf20Sopenharmony_ci .ndo_fix_features = hsr_fix_features, 4138c2ecf20Sopenharmony_ci}; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic struct device_type hsr_type = { 4168c2ecf20Sopenharmony_ci .name = "hsr", 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic struct hsr_proto_ops hsr_ops = { 4208c2ecf20Sopenharmony_ci .send_sv_frame = send_hsr_supervision_frame, 4218c2ecf20Sopenharmony_ci .create_tagged_frame = hsr_create_tagged_frame, 4228c2ecf20Sopenharmony_ci .get_untagged_frame = hsr_get_untagged_frame, 4238c2ecf20Sopenharmony_ci .fill_frame_info = hsr_fill_frame_info, 4248c2ecf20Sopenharmony_ci .invalid_dan_ingress_frame = hsr_invalid_dan_ingress_frame, 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic struct hsr_proto_ops prp_ops = { 4288c2ecf20Sopenharmony_ci .send_sv_frame = send_prp_supervision_frame, 4298c2ecf20Sopenharmony_ci .create_tagged_frame = prp_create_tagged_frame, 4308c2ecf20Sopenharmony_ci .get_untagged_frame = prp_get_untagged_frame, 4318c2ecf20Sopenharmony_ci .drop_frame = prp_drop_frame, 4328c2ecf20Sopenharmony_ci .fill_frame_info = prp_fill_frame_info, 4338c2ecf20Sopenharmony_ci .handle_san_frame = prp_handle_san_frame, 4348c2ecf20Sopenharmony_ci .update_san_info = prp_update_san_info, 4358c2ecf20Sopenharmony_ci}; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_civoid hsr_dev_setup(struct net_device *dev) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ether_setup(dev); 4428c2ecf20Sopenharmony_ci dev->min_mtu = 0; 4438c2ecf20Sopenharmony_ci dev->header_ops = &hsr_header_ops; 4448c2ecf20Sopenharmony_ci dev->netdev_ops = &hsr_device_ops; 4458c2ecf20Sopenharmony_ci SET_NETDEV_DEVTYPE(dev, &hsr_type); 4468c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 4518c2ecf20Sopenharmony_ci NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | 4528c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci dev->features = dev->hw_features; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Prevent recursive tx locking */ 4578c2ecf20Sopenharmony_ci dev->features |= NETIF_F_LLTX; 4588c2ecf20Sopenharmony_ci /* VLAN on top of HSR needs testing and probably some work on 4598c2ecf20Sopenharmony_ci * hsr_header_create() etc. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ci dev->features |= NETIF_F_VLAN_CHALLENGED; 4628c2ecf20Sopenharmony_ci /* Not sure about this. Taken from bridge code. netdev_features.h says 4638c2ecf20Sopenharmony_ci * it means "Does not change network namespaces". 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci dev->features |= NETIF_F_NETNS_LOCAL; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* Return true if dev is a HSR master; return false otherwise. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ciinline bool is_hsr_master(struct net_device *dev) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* Default multicast address for HSR Supervision frames */ 4768c2ecf20Sopenharmony_cistatic const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { 4778c2ecf20Sopenharmony_ci 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciint hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], 4818c2ecf20Sopenharmony_ci unsigned char multicast_spec, u8 protocol_version, 4828c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci bool unregister = false; 4858c2ecf20Sopenharmony_ci struct hsr_priv *hsr; 4868c2ecf20Sopenharmony_ci int res; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci hsr = netdev_priv(hsr_dev); 4898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hsr->ports); 4908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hsr->node_db); 4918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hsr->self_node_db); 4928c2ecf20Sopenharmony_ci spin_lock_init(&hsr->list_lock); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci ether_addr_copy(hsr_dev->dev_addr, slave[0]->dev_addr); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* initialize protocol specific functions */ 4978c2ecf20Sopenharmony_ci if (protocol_version == PRP_V1) { 4988c2ecf20Sopenharmony_ci /* For PRP, lan_id has most significant 3 bits holding 4998c2ecf20Sopenharmony_ci * the net_id of PRP_LAN_ID 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci hsr->net_id = PRP_LAN_ID << 1; 5028c2ecf20Sopenharmony_ci hsr->proto_ops = &prp_ops; 5038c2ecf20Sopenharmony_ci } else { 5048c2ecf20Sopenharmony_ci hsr->proto_ops = &hsr_ops; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Make sure we recognize frames from ourselves in hsr_rcv() */ 5088c2ecf20Sopenharmony_ci res = hsr_create_self_node(hsr, hsr_dev->dev_addr, 5098c2ecf20Sopenharmony_ci slave[1]->dev_addr); 5108c2ecf20Sopenharmony_ci if (res < 0) 5118c2ecf20Sopenharmony_ci return res; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci spin_lock_init(&hsr->seqnr_lock); 5148c2ecf20Sopenharmony_ci /* Overflow soon to find bugs easier: */ 5158c2ecf20Sopenharmony_ci hsr->sequence_nr = HSR_SEQNR_START; 5168c2ecf20Sopenharmony_ci hsr->sup_sequence_nr = HSR_SUP_SEQNR_START; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci timer_setup(&hsr->announce_timer, hsr_announce, 0); 5198c2ecf20Sopenharmony_ci timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); 5228c2ecf20Sopenharmony_ci hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci hsr->prot_version = protocol_version; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* FIXME: should I modify the value of these? 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * - hsr_dev->flags - i.e. 5298c2ecf20Sopenharmony_ci * IFF_MASTER/SLAVE? 5308c2ecf20Sopenharmony_ci * - hsr_dev->priv_flags - i.e. 5318c2ecf20Sopenharmony_ci * IFF_EBRIDGE? 5328c2ecf20Sopenharmony_ci * IFF_TX_SKB_SHARING? 5338c2ecf20Sopenharmony_ci * IFF_HSR_MASTER/SLAVE? 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Make sure the 1st call to netif_carrier_on() gets through */ 5378c2ecf20Sopenharmony_ci netif_carrier_off(hsr_dev); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci res = hsr_add_port(hsr, hsr_dev, HSR_PT_MASTER, extack); 5408c2ecf20Sopenharmony_ci if (res) 5418c2ecf20Sopenharmony_ci goto err_add_master; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci res = register_netdevice(hsr_dev); 5448c2ecf20Sopenharmony_ci if (res) 5458c2ecf20Sopenharmony_ci goto err_unregister; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci unregister = true; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci res = hsr_add_port(hsr, slave[0], HSR_PT_SLAVE_A, extack); 5508c2ecf20Sopenharmony_ci if (res) 5518c2ecf20Sopenharmony_ci goto err_unregister; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci res = hsr_add_port(hsr, slave[1], HSR_PT_SLAVE_B, extack); 5548c2ecf20Sopenharmony_ci if (res) 5558c2ecf20Sopenharmony_ci goto err_unregister; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci hsr_debugfs_init(hsr, hsr_dev); 5588c2ecf20Sopenharmony_ci mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD)); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cierr_unregister: 5638c2ecf20Sopenharmony_ci hsr_del_ports(hsr); 5648c2ecf20Sopenharmony_cierr_add_master: 5658c2ecf20Sopenharmony_ci hsr_del_self_node(hsr); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (unregister) 5688c2ecf20Sopenharmony_ci unregister_netdevice(hsr_dev); 5698c2ecf20Sopenharmony_ci return res; 5708c2ecf20Sopenharmony_ci} 571