10e7623bdSMurali Karicheri // SPDX-License-Identifier: GPL-2.0 281ba6afdSArvid Brodin /* Copyright 2011-2014 Autronica Fire and Security AS 381ba6afdSArvid Brodin * 481ba6afdSArvid Brodin * Author(s): 581ba6afdSArvid Brodin * 2011-2014 Arvid Brodin, arvid.brodin@alten.se 68f4c0e01SMurali Karicheri * 78f4c0e01SMurali Karicheri * Frame handler other utility functions for HSR and PRP. 881ba6afdSArvid Brodin */ 981ba6afdSArvid Brodin 1081ba6afdSArvid Brodin #include "hsr_slave.h" 1181ba6afdSArvid Brodin #include <linux/etherdevice.h> 1251f3c605SArvid Brodin #include <linux/if_arp.h> 13d0d7b10bSParav Pandit #include <linux/if_vlan.h> 1481ba6afdSArvid Brodin #include "hsr_main.h" 1551f3c605SArvid Brodin #include "hsr_device.h" 16f266a683SArvid Brodin #include "hsr_forward.h" 1781ba6afdSArvid Brodin #include "hsr_framereg.h" 1881ba6afdSArvid Brodin 19451d8123SMurali Karicheri bool hsr_invalid_dan_ingress_frame(__be16 protocol) 20451d8123SMurali Karicheri { 21451d8123SMurali Karicheri return (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR)); 22451d8123SMurali Karicheri } 23451d8123SMurali Karicheri 24f266a683SArvid Brodin static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) 25f266a683SArvid Brodin { 26f266a683SArvid Brodin struct sk_buff *skb = *pskb; 27f266a683SArvid Brodin struct hsr_port *port; 28451d8123SMurali Karicheri struct hsr_priv *hsr; 29f5dda315SMurali Karicheri __be16 protocol; 30f266a683SArvid Brodin 31451d8123SMurali Karicheri /* Packets from dev_loopback_xmit() do not have L2 header, bail out */ 32451d8123SMurali Karicheri if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) 33451d8123SMurali Karicheri return RX_HANDLER_PASS; 34451d8123SMurali Karicheri 35f266a683SArvid Brodin if (!skb_mac_header_was_set(skb)) { 36f266a683SArvid Brodin WARN_ONCE(1, "%s: skb invalid", __func__); 37f266a683SArvid Brodin return RX_HANDLER_PASS; 38f266a683SArvid Brodin } 39f266a683SArvid Brodin 40f266a683SArvid Brodin port = hsr_port_get_rcu(skb->dev); 412b5b8251SEric Dumazet if (!port) 422b5b8251SEric Dumazet goto finish_pass; 43451d8123SMurali Karicheri hsr = port->hsr; 44f266a683SArvid Brodin 45f266a683SArvid Brodin if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) { 46f266a683SArvid Brodin /* Directly kill frames sent by ourselves */ 47f266a683SArvid Brodin kfree_skb(skb); 48f266a683SArvid Brodin goto finish_consume; 49f266a683SArvid Brodin } 50f266a683SArvid Brodin 51dcf0cd1cSGeorge McCollister /* For HSR, only tagged frames are expected (unless the device offloads 52dcf0cd1cSGeorge McCollister * HSR tag removal), but for PRP there could be non tagged frames as 53dcf0cd1cSGeorge McCollister * well from Single attached nodes (SANs). 54451d8123SMurali Karicheri */ 55ee1c2797SPeter Heise protocol = eth_hdr(skb)->h_proto; 56dcf0cd1cSGeorge McCollister 57dcf0cd1cSGeorge McCollister if (!(port->dev->features & NETIF_F_HW_HSR_TAG_RM) && 58dcf0cd1cSGeorge McCollister hsr->proto_ops->invalid_dan_ingress_frame && 59451d8123SMurali Karicheri hsr->proto_ops->invalid_dan_ingress_frame(protocol)) 60f266a683SArvid Brodin goto finish_pass; 61f266a683SArvid Brodin 62f266a683SArvid Brodin skb_push(skb, ETH_HLEN); 6348b491a5SGeorge McCollister skb_reset_mac_header(skb); 6448b491a5SGeorge McCollister if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) || 6548b491a5SGeorge McCollister protocol == htons(ETH_P_HSR)) 6648b491a5SGeorge McCollister skb_set_network_header(skb, ETH_HLEN + HSR_HLEN); 6748b491a5SGeorge McCollister skb_reset_mac_len(skb); 68451d8123SMurali Karicheri 69f266a683SArvid Brodin hsr_forward_skb(skb, port); 70f266a683SArvid Brodin 71f266a683SArvid Brodin finish_consume: 72f266a683SArvid Brodin return RX_HANDLER_CONSUMED; 73f266a683SArvid Brodin 74f266a683SArvid Brodin finish_pass: 75f266a683SArvid Brodin return RX_HANDLER_PASS; 76f266a683SArvid Brodin } 77f266a683SArvid Brodin 78f266a683SArvid Brodin bool hsr_port_exists(const struct net_device *dev) 79f266a683SArvid Brodin { 80f266a683SArvid Brodin return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame; 81f266a683SArvid Brodin } 82f266a683SArvid Brodin 8313eeb5feSTaehee Yoo static int hsr_check_dev_ok(struct net_device *dev, 8413eeb5feSTaehee Yoo struct netlink_ext_ack *extack) 8551f3c605SArvid Brodin { 8651f3c605SArvid Brodin /* Don't allow HSR on non-ethernet like devices */ 875670342cSMurali Karicheri if ((dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || 885670342cSMurali Karicheri dev->addr_len != ETH_ALEN) { 8913eeb5feSTaehee Yoo NL_SET_ERR_MSG_MOD(extack, "Cannot use loopback or non-ethernet device as HSR slave."); 9051f3c605SArvid Brodin return -EINVAL; 9151f3c605SArvid Brodin } 9251f3c605SArvid Brodin 9351f3c605SArvid Brodin /* Don't allow enslaving hsr devices */ 9451f3c605SArvid Brodin if (is_hsr_master(dev)) { 9513eeb5feSTaehee Yoo NL_SET_ERR_MSG_MOD(extack, 9613eeb5feSTaehee Yoo "Cannot create trees of HSR devices."); 9751f3c605SArvid Brodin return -EINVAL; 9851f3c605SArvid Brodin } 9951f3c605SArvid Brodin 100c5a75911SArvid Brodin if (hsr_port_exists(dev)) { 10113eeb5feSTaehee Yoo NL_SET_ERR_MSG_MOD(extack, 10213eeb5feSTaehee Yoo "This device is already a HSR slave."); 10351f3c605SArvid Brodin return -EINVAL; 10451f3c605SArvid Brodin } 10551f3c605SArvid Brodin 106d0d7b10bSParav Pandit if (is_vlan_dev(dev)) { 10713eeb5feSTaehee Yoo NL_SET_ERR_MSG_MOD(extack, "HSR on top of VLAN is not yet supported in this driver."); 10851f3c605SArvid Brodin return -EINVAL; 10951f3c605SArvid Brodin } 11051f3c605SArvid Brodin 111f266a683SArvid Brodin if (dev->priv_flags & IFF_DONT_BRIDGE) { 11213eeb5feSTaehee Yoo NL_SET_ERR_MSG_MOD(extack, 11313eeb5feSTaehee Yoo "This device does not support bridging."); 114f266a683SArvid Brodin return -EOPNOTSUPP; 115f266a683SArvid Brodin } 116f266a683SArvid Brodin 11751f3c605SArvid Brodin /* HSR over bonded devices has not been tested, but I'm not sure it 11851f3c605SArvid Brodin * won't work... 11951f3c605SArvid Brodin */ 12051f3c605SArvid Brodin 12151f3c605SArvid Brodin return 0; 12251f3c605SArvid Brodin } 12351f3c605SArvid Brodin 124c5a75911SArvid Brodin /* Setup device to be added to the HSR bridge. */ 125e0a4b997STaehee Yoo static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, 126e0a4b997STaehee Yoo struct hsr_port *port, 127e0a4b997STaehee Yoo struct netlink_ext_ack *extack) 128e0a4b997STaehee Yoo 12951f3c605SArvid Brodin { 130e0a4b997STaehee Yoo struct net_device *hsr_dev; 131e0a4b997STaehee Yoo struct hsr_port *master; 13251f3c605SArvid Brodin int res; 13351f3c605SArvid Brodin 134e748d0fdSRavi Gunasekaran /* Don't use promiscuous mode for offload since L2 frame forward 135e748d0fdSRavi Gunasekaran * happens at the offloaded hardware. 136e748d0fdSRavi Gunasekaran */ 137e748d0fdSRavi Gunasekaran if (!port->hsr->fwd_offloaded) { 13851f3c605SArvid Brodin res = dev_set_promiscuity(dev, 1); 13951f3c605SArvid Brodin if (res) 14056dc0a0eSTaehee Yoo return res; 141e748d0fdSRavi Gunasekaran } 14251f3c605SArvid Brodin 143e0a4b997STaehee Yoo master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 144e0a4b997STaehee Yoo hsr_dev = master->dev; 145e0a4b997STaehee Yoo 146e0a4b997STaehee Yoo res = netdev_upper_dev_link(dev, hsr_dev, extack); 147e0a4b997STaehee Yoo if (res) 148e0a4b997STaehee Yoo goto fail_upper_dev_link; 14951f3c605SArvid Brodin 150f266a683SArvid Brodin res = netdev_rx_handler_register(dev, hsr_handle_frame, port); 151f266a683SArvid Brodin if (res) 152f266a683SArvid Brodin goto fail_rx_handler; 153f266a683SArvid Brodin dev_disable_lro(dev); 154f266a683SArvid Brodin 15551f3c605SArvid Brodin return 0; 15651f3c605SArvid Brodin 15751f3c605SArvid Brodin fail_rx_handler: 158e0a4b997STaehee Yoo netdev_upper_dev_unlink(dev, hsr_dev); 159e0a4b997STaehee Yoo fail_upper_dev_link: 160e748d0fdSRavi Gunasekaran if (!port->hsr->fwd_offloaded) 16151f3c605SArvid Brodin dev_set_promiscuity(dev, -1); 162e748d0fdSRavi Gunasekaran 16351f3c605SArvid Brodin return res; 16451f3c605SArvid Brodin } 16551f3c605SArvid Brodin 166c5a75911SArvid Brodin int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, 16713eeb5feSTaehee Yoo enum hsr_port_type type, struct netlink_ext_ack *extack) 16851f3c605SArvid Brodin { 169c5a75911SArvid Brodin struct hsr_port *port, *master; 170c5a75911SArvid Brodin int res; 17151f3c605SArvid Brodin 172c5a75911SArvid Brodin if (type != HSR_PT_MASTER) { 17313eeb5feSTaehee Yoo res = hsr_check_dev_ok(dev, extack); 174c5a75911SArvid Brodin if (res) 175c5a75911SArvid Brodin return res; 17651f3c605SArvid Brodin } 17751f3c605SArvid Brodin 178c5a75911SArvid Brodin port = hsr_port_get_hsr(hsr, type); 17905ca6e64SMurali Karicheri if (port) 180c5a75911SArvid Brodin return -EBUSY; /* This port already exists */ 181c5a75911SArvid Brodin 182c5a75911SArvid Brodin port = kzalloc(sizeof(*port), GFP_KERNEL); 18305ca6e64SMurali Karicheri if (!port) 184c5a75911SArvid Brodin return -ENOMEM; 185c5a75911SArvid Brodin 1863a303cfdSTaehee Yoo port->hsr = hsr; 1873a303cfdSTaehee Yoo port->dev = dev; 1883a303cfdSTaehee Yoo port->type = type; 1893a303cfdSTaehee Yoo 190c5a75911SArvid Brodin if (type != HSR_PT_MASTER) { 191e0a4b997STaehee Yoo res = hsr_portdev_setup(hsr, dev, port, extack); 192c5a75911SArvid Brodin if (res) 193c5a75911SArvid Brodin goto fail_dev_setup; 194c5a75911SArvid Brodin } 195c5a75911SArvid Brodin 196c5a75911SArvid Brodin list_add_tail_rcu(&port->port_list, &hsr->ports); 19751f3c605SArvid Brodin synchronize_rcu(); 198c5a75911SArvid Brodin 199c5a75911SArvid Brodin master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 2001cc1eb52SArvid Brodin netdev_update_features(master->dev); 201c5a75911SArvid Brodin dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); 202c5a75911SArvid Brodin 203c5a75911SArvid Brodin return 0; 204c5a75911SArvid Brodin 205c5a75911SArvid Brodin fail_dev_setup: 206c5a75911SArvid Brodin kfree(port); 207c5a75911SArvid Brodin return res; 208c5a75911SArvid Brodin } 209c5a75911SArvid Brodin 210c5a75911SArvid Brodin void hsr_del_port(struct hsr_port *port) 211c5a75911SArvid Brodin { 212c5a75911SArvid Brodin struct hsr_priv *hsr; 213c5a75911SArvid Brodin struct hsr_port *master; 214c5a75911SArvid Brodin 215c5a75911SArvid Brodin hsr = port->hsr; 216c5a75911SArvid Brodin master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 217c5a75911SArvid Brodin list_del_rcu(&port->port_list); 218c5a75911SArvid Brodin 219c5a75911SArvid Brodin if (port != master) { 2201cc1eb52SArvid Brodin netdev_update_features(master->dev); 221c5a75911SArvid Brodin dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); 222c5a75911SArvid Brodin netdev_rx_handler_unregister(port->dev); 223*984c3d96SRavi Gunasekaran if (!port->hsr->fwd_offloaded) 224c5a75911SArvid Brodin dev_set_promiscuity(port->dev, -1); 225e0a4b997STaehee Yoo netdev_upper_dev_unlink(port->dev, master->dev); 226c5a75911SArvid Brodin } 227c5a75911SArvid Brodin 228c5a75911SArvid Brodin synchronize_rcu(); 22956b08fdcSArvid Brodin 230619afef0SCong Wang kfree(port); 23151f3c605SArvid Brodin } 232