170ebe4a4SArvid Brodin /* Copyright 2011-2014 Autronica Fire and Security AS 2f421436aSArvid Brodin * 3f421436aSArvid Brodin * This program is free software; you can redistribute it and/or modify it 4f421436aSArvid Brodin * under the terms of the GNU General Public License as published by the Free 5f421436aSArvid Brodin * Software Foundation; either version 2 of the License, or (at your option) 6f421436aSArvid Brodin * any later version. 7f421436aSArvid Brodin * 8f421436aSArvid Brodin * Author(s): 970ebe4a4SArvid Brodin * 2011-2014 Arvid Brodin, arvid.brodin@alten.se 10f421436aSArvid Brodin * 11f421436aSArvid Brodin * Routines for handling Netlink messages for HSR. 12f421436aSArvid Brodin */ 13f421436aSArvid Brodin 14f421436aSArvid Brodin #include "hsr_netlink.h" 15f421436aSArvid Brodin #include <linux/kernel.h> 16f421436aSArvid Brodin #include <net/rtnetlink.h> 17f421436aSArvid Brodin #include <net/genetlink.h> 18f421436aSArvid Brodin #include "hsr_main.h" 19f421436aSArvid Brodin #include "hsr_device.h" 20f421436aSArvid Brodin #include "hsr_framereg.h" 21f421436aSArvid Brodin 22f421436aSArvid Brodin static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = { 23f421436aSArvid Brodin [IFLA_HSR_SLAVE1] = { .type = NLA_U32 }, 24f421436aSArvid Brodin [IFLA_HSR_SLAVE2] = { .type = NLA_U32 }, 25f421436aSArvid Brodin [IFLA_HSR_MULTICAST_SPEC] = { .type = NLA_U8 }, 26ee1c2797SPeter Heise [IFLA_HSR_VERSION] = { .type = NLA_U8 }, 2798bf8362SArvid Brodin [IFLA_HSR_SUPERVISION_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN }, 2898bf8362SArvid Brodin [IFLA_HSR_SEQ_NR] = { .type = NLA_U16 }, 29f421436aSArvid Brodin }; 30f421436aSArvid Brodin 31f421436aSArvid Brodin 32f421436aSArvid Brodin /* Here, it seems a netdevice has already been allocated for us, and the 33f421436aSArvid Brodin * hsr_dev_setup routine has been executed. Nice! 34f421436aSArvid Brodin */ 35f421436aSArvid Brodin static int hsr_newlink(struct net *src_net, struct net_device *dev, 36f421436aSArvid Brodin struct nlattr *tb[], struct nlattr *data[]) 37f421436aSArvid Brodin { 38f421436aSArvid Brodin struct net_device *link[2]; 39ee1c2797SPeter Heise unsigned char multicast_spec, hsr_version; 40f421436aSArvid Brodin 41a718dcc5SArvid Brodin if (!data) { 42a718dcc5SArvid Brodin netdev_info(dev, "HSR: No slave devices specified\n"); 43a718dcc5SArvid Brodin return -EINVAL; 44a718dcc5SArvid Brodin } 45f421436aSArvid Brodin if (!data[IFLA_HSR_SLAVE1]) { 46a718dcc5SArvid Brodin netdev_info(dev, "HSR: Slave1 device not specified\n"); 47f421436aSArvid Brodin return -EINVAL; 48f421436aSArvid Brodin } 49f421436aSArvid Brodin link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1])); 50f421436aSArvid Brodin if (!data[IFLA_HSR_SLAVE2]) { 51a718dcc5SArvid Brodin netdev_info(dev, "HSR: Slave2 device not specified\n"); 52f421436aSArvid Brodin return -EINVAL; 53f421436aSArvid Brodin } 54f421436aSArvid Brodin link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2])); 55f421436aSArvid Brodin 56f421436aSArvid Brodin if (!link[0] || !link[1]) 57f421436aSArvid Brodin return -ENODEV; 58f421436aSArvid Brodin if (link[0] == link[1]) 59f421436aSArvid Brodin return -EINVAL; 60f421436aSArvid Brodin 61f421436aSArvid Brodin if (!data[IFLA_HSR_MULTICAST_SPEC]) 62f421436aSArvid Brodin multicast_spec = 0; 63f421436aSArvid Brodin else 64f421436aSArvid Brodin multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]); 65f421436aSArvid Brodin 66ee1c2797SPeter Heise if (!data[IFLA_HSR_VERSION]) 67ee1c2797SPeter Heise hsr_version = 0; 68ee1c2797SPeter Heise else 69ee1c2797SPeter Heise hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]); 70ee1c2797SPeter Heise 71ee1c2797SPeter Heise return hsr_dev_finalize(dev, link, multicast_spec, hsr_version); 72f421436aSArvid Brodin } 73f421436aSArvid Brodin 7498bf8362SArvid Brodin static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) 7598bf8362SArvid Brodin { 7670ebe4a4SArvid Brodin struct hsr_priv *hsr; 77c5a75911SArvid Brodin struct hsr_port *port; 7851f3c605SArvid Brodin int res; 7998bf8362SArvid Brodin 8070ebe4a4SArvid Brodin hsr = netdev_priv(dev); 8198bf8362SArvid Brodin 8251f3c605SArvid Brodin res = 0; 8351f3c605SArvid Brodin 8451f3c605SArvid Brodin rcu_read_lock(); 85c5a75911SArvid Brodin port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); 86c5a75911SArvid Brodin if (port) 87c5a75911SArvid Brodin res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex); 8851f3c605SArvid Brodin rcu_read_unlock(); 8951f3c605SArvid Brodin if (res) 9098bf8362SArvid Brodin goto nla_put_failure; 9198bf8362SArvid Brodin 9251f3c605SArvid Brodin rcu_read_lock(); 93c5a75911SArvid Brodin port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); 94c5a75911SArvid Brodin if (port) 95c5a75911SArvid Brodin res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex); 9651f3c605SArvid Brodin rcu_read_unlock(); 9751f3c605SArvid Brodin if (res) 9898bf8362SArvid Brodin goto nla_put_failure; 9998bf8362SArvid Brodin 10098bf8362SArvid Brodin if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, 10170ebe4a4SArvid Brodin hsr->sup_multicast_addr) || 10270ebe4a4SArvid Brodin nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr)) 10398bf8362SArvid Brodin goto nla_put_failure; 10498bf8362SArvid Brodin 10598bf8362SArvid Brodin return 0; 10698bf8362SArvid Brodin 10798bf8362SArvid Brodin nla_put_failure: 10898bf8362SArvid Brodin return -EMSGSIZE; 10998bf8362SArvid Brodin } 11098bf8362SArvid Brodin 111f421436aSArvid Brodin static struct rtnl_link_ops hsr_link_ops __read_mostly = { 112f421436aSArvid Brodin .kind = "hsr", 113f421436aSArvid Brodin .maxtype = IFLA_HSR_MAX, 114f421436aSArvid Brodin .policy = hsr_policy, 115f421436aSArvid Brodin .priv_size = sizeof(struct hsr_priv), 116f421436aSArvid Brodin .setup = hsr_dev_setup, 117f421436aSArvid Brodin .newlink = hsr_newlink, 11898bf8362SArvid Brodin .fill_info = hsr_fill_info, 119f421436aSArvid Brodin }; 120f421436aSArvid Brodin 121f421436aSArvid Brodin 122f421436aSArvid Brodin 123f421436aSArvid Brodin /* attribute policy */ 124f421436aSArvid Brodin /* NLA_BINARY missing in libnl; use NLA_UNSPEC in userspace instead. */ 125f421436aSArvid Brodin static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = { 126f421436aSArvid Brodin [HSR_A_NODE_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN }, 127f421436aSArvid Brodin [HSR_A_NODE_ADDR_B] = { .type = NLA_BINARY, .len = ETH_ALEN }, 128f421436aSArvid Brodin [HSR_A_IFINDEX] = { .type = NLA_U32 }, 129f421436aSArvid Brodin [HSR_A_IF1_AGE] = { .type = NLA_U32 }, 130f421436aSArvid Brodin [HSR_A_IF2_AGE] = { .type = NLA_U32 }, 131f421436aSArvid Brodin [HSR_A_IF1_SEQ] = { .type = NLA_U16 }, 132f421436aSArvid Brodin [HSR_A_IF2_SEQ] = { .type = NLA_U16 }, 133f421436aSArvid Brodin }; 134f421436aSArvid Brodin 135f421436aSArvid Brodin static struct genl_family hsr_genl_family = { 136f421436aSArvid Brodin .id = GENL_ID_GENERATE, 137f421436aSArvid Brodin .hdrsize = 0, 138f421436aSArvid Brodin .name = "HSR", 139f421436aSArvid Brodin .version = 1, 140f421436aSArvid Brodin .maxattr = HSR_A_MAX, 141f421436aSArvid Brodin }; 142f421436aSArvid Brodin 1432a94fe48SJohannes Berg static const struct genl_multicast_group hsr_mcgrps[] = { 1442a94fe48SJohannes Berg { .name = "hsr-network", }, 145f421436aSArvid Brodin }; 146f421436aSArvid Brodin 147f421436aSArvid Brodin 148f421436aSArvid Brodin 149f421436aSArvid Brodin /* This is called if for some node with MAC address addr, we only get frames 150f421436aSArvid Brodin * over one of the slave interfaces. This would indicate an open network ring 151f421436aSArvid Brodin * (i.e. a link has failed somewhere). 152f421436aSArvid Brodin */ 15370ebe4a4SArvid Brodin void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], 154c5a75911SArvid Brodin struct hsr_port *port) 155f421436aSArvid Brodin { 156f421436aSArvid Brodin struct sk_buff *skb; 157f421436aSArvid Brodin void *msg_head; 158c5a75911SArvid Brodin struct hsr_port *master; 159f421436aSArvid Brodin int res; 160f421436aSArvid Brodin 161f421436aSArvid Brodin skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 162f421436aSArvid Brodin if (!skb) 163f421436aSArvid Brodin goto fail; 164f421436aSArvid Brodin 165f421436aSArvid Brodin msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_RING_ERROR); 166f421436aSArvid Brodin if (!msg_head) 167f421436aSArvid Brodin goto nla_put_failure; 168f421436aSArvid Brodin 169f421436aSArvid Brodin res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr); 170f421436aSArvid Brodin if (res < 0) 171f421436aSArvid Brodin goto nla_put_failure; 172f421436aSArvid Brodin 173c5a75911SArvid Brodin res = nla_put_u32(skb, HSR_A_IFINDEX, port->dev->ifindex); 174f421436aSArvid Brodin if (res < 0) 175f421436aSArvid Brodin goto nla_put_failure; 176f421436aSArvid Brodin 177f421436aSArvid Brodin genlmsg_end(skb, msg_head); 1782a94fe48SJohannes Berg genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); 179f421436aSArvid Brodin 180f421436aSArvid Brodin return; 181f421436aSArvid Brodin 182f421436aSArvid Brodin nla_put_failure: 183f421436aSArvid Brodin kfree_skb(skb); 184f421436aSArvid Brodin 185f421436aSArvid Brodin fail: 186c5a75911SArvid Brodin rcu_read_lock(); 187c5a75911SArvid Brodin master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 188c5a75911SArvid Brodin netdev_warn(master->dev, "Could not send HSR ring error message\n"); 189c5a75911SArvid Brodin rcu_read_unlock(); 190f421436aSArvid Brodin } 191f421436aSArvid Brodin 192f421436aSArvid Brodin /* This is called when we haven't heard from the node with MAC address addr for 193f421436aSArvid Brodin * some time (just before the node is removed from the node table/list). 194f421436aSArvid Brodin */ 19570ebe4a4SArvid Brodin void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]) 196f421436aSArvid Brodin { 197f421436aSArvid Brodin struct sk_buff *skb; 198f421436aSArvid Brodin void *msg_head; 199c5a75911SArvid Brodin struct hsr_port *master; 200f421436aSArvid Brodin int res; 201f421436aSArvid Brodin 202f421436aSArvid Brodin skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 203f421436aSArvid Brodin if (!skb) 204f421436aSArvid Brodin goto fail; 205f421436aSArvid Brodin 206f421436aSArvid Brodin msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_NODE_DOWN); 207f421436aSArvid Brodin if (!msg_head) 208f421436aSArvid Brodin goto nla_put_failure; 209f421436aSArvid Brodin 210f421436aSArvid Brodin 211f421436aSArvid Brodin res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr); 212f421436aSArvid Brodin if (res < 0) 213f421436aSArvid Brodin goto nla_put_failure; 214f421436aSArvid Brodin 215f421436aSArvid Brodin genlmsg_end(skb, msg_head); 2162a94fe48SJohannes Berg genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); 217f421436aSArvid Brodin 218f421436aSArvid Brodin return; 219f421436aSArvid Brodin 220f421436aSArvid Brodin nla_put_failure: 221f421436aSArvid Brodin kfree_skb(skb); 222f421436aSArvid Brodin 223f421436aSArvid Brodin fail: 224c5a75911SArvid Brodin rcu_read_lock(); 225c5a75911SArvid Brodin master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); 226c5a75911SArvid Brodin netdev_warn(master->dev, "Could not send HSR node down\n"); 227c5a75911SArvid Brodin rcu_read_unlock(); 228f421436aSArvid Brodin } 229f421436aSArvid Brodin 230f421436aSArvid Brodin 231f421436aSArvid Brodin /* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table 232f421436aSArvid Brodin * about the status of a specific node in the network, defined by its MAC 233f421436aSArvid Brodin * address. 234f421436aSArvid Brodin * 235f421436aSArvid Brodin * Input: hsr ifindex, node mac address 236f421436aSArvid Brodin * Output: hsr ifindex, node mac address (copied from request), 237f421436aSArvid Brodin * age of latest frame from node over slave 1, slave 2 [ms] 238f421436aSArvid Brodin */ 239f421436aSArvid Brodin static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) 240f421436aSArvid Brodin { 241f421436aSArvid Brodin /* For receiving */ 242f421436aSArvid Brodin struct nlattr *na; 243c5a75911SArvid Brodin struct net_device *hsr_dev; 244f421436aSArvid Brodin 245f421436aSArvid Brodin /* For sending */ 246f421436aSArvid Brodin struct sk_buff *skb_out; 247f421436aSArvid Brodin void *msg_head; 24870ebe4a4SArvid Brodin struct hsr_priv *hsr; 249c5a75911SArvid Brodin struct hsr_port *port; 250f421436aSArvid Brodin unsigned char hsr_node_addr_b[ETH_ALEN]; 251f421436aSArvid Brodin int hsr_node_if1_age; 252f421436aSArvid Brodin u16 hsr_node_if1_seq; 253f421436aSArvid Brodin int hsr_node_if2_age; 254f421436aSArvid Brodin u16 hsr_node_if2_seq; 255f421436aSArvid Brodin int addr_b_ifindex; 256f421436aSArvid Brodin int res; 257f421436aSArvid Brodin 258f421436aSArvid Brodin if (!info) 259f421436aSArvid Brodin goto invalid; 260f421436aSArvid Brodin 261f421436aSArvid Brodin na = info->attrs[HSR_A_IFINDEX]; 262f421436aSArvid Brodin if (!na) 263f421436aSArvid Brodin goto invalid; 264f421436aSArvid Brodin na = info->attrs[HSR_A_NODE_ADDR]; 265f421436aSArvid Brodin if (!na) 266f421436aSArvid Brodin goto invalid; 267f421436aSArvid Brodin 268f421436aSArvid Brodin hsr_dev = __dev_get_by_index(genl_info_net(info), 269f421436aSArvid Brodin nla_get_u32(info->attrs[HSR_A_IFINDEX])); 270f421436aSArvid Brodin if (!hsr_dev) 271f421436aSArvid Brodin goto invalid; 272f421436aSArvid Brodin if (!is_hsr_master(hsr_dev)) 273f421436aSArvid Brodin goto invalid; 274f421436aSArvid Brodin 275f421436aSArvid Brodin 276f421436aSArvid Brodin /* Send reply */ 277f421436aSArvid Brodin 278f421436aSArvid Brodin skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 279f421436aSArvid Brodin if (!skb_out) { 280f421436aSArvid Brodin res = -ENOMEM; 281f421436aSArvid Brodin goto fail; 282f421436aSArvid Brodin } 283f421436aSArvid Brodin 284f421436aSArvid Brodin msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid, 285f421436aSArvid Brodin info->snd_seq, &hsr_genl_family, 0, 286f421436aSArvid Brodin HSR_C_SET_NODE_STATUS); 287f421436aSArvid Brodin if (!msg_head) { 288f421436aSArvid Brodin res = -ENOMEM; 289f421436aSArvid Brodin goto nla_put_failure; 290f421436aSArvid Brodin } 291f421436aSArvid Brodin 292f421436aSArvid Brodin res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); 293f421436aSArvid Brodin if (res < 0) 294f421436aSArvid Brodin goto nla_put_failure; 295f421436aSArvid Brodin 29670ebe4a4SArvid Brodin hsr = netdev_priv(hsr_dev); 29770ebe4a4SArvid Brodin res = hsr_get_node_data(hsr, 298f421436aSArvid Brodin (unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]), 299f421436aSArvid Brodin hsr_node_addr_b, 300f421436aSArvid Brodin &addr_b_ifindex, 301f421436aSArvid Brodin &hsr_node_if1_age, 302f421436aSArvid Brodin &hsr_node_if1_seq, 303f421436aSArvid Brodin &hsr_node_if2_age, 304f421436aSArvid Brodin &hsr_node_if2_seq); 305f421436aSArvid Brodin if (res < 0) 30684a035f6SGeyslan G. Bem goto nla_put_failure; 307f421436aSArvid Brodin 308f421436aSArvid Brodin res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, 309f421436aSArvid Brodin nla_data(info->attrs[HSR_A_NODE_ADDR])); 310f421436aSArvid Brodin if (res < 0) 311f421436aSArvid Brodin goto nla_put_failure; 312f421436aSArvid Brodin 313f421436aSArvid Brodin if (addr_b_ifindex > -1) { 314f421436aSArvid Brodin res = nla_put(skb_out, HSR_A_NODE_ADDR_B, ETH_ALEN, 315f421436aSArvid Brodin hsr_node_addr_b); 316f421436aSArvid Brodin if (res < 0) 317f421436aSArvid Brodin goto nla_put_failure; 318f421436aSArvid Brodin 319f421436aSArvid Brodin res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX, addr_b_ifindex); 320f421436aSArvid Brodin if (res < 0) 321f421436aSArvid Brodin goto nla_put_failure; 322f421436aSArvid Brodin } 323f421436aSArvid Brodin 324f421436aSArvid Brodin res = nla_put_u32(skb_out, HSR_A_IF1_AGE, hsr_node_if1_age); 325f421436aSArvid Brodin if (res < 0) 326f421436aSArvid Brodin goto nla_put_failure; 327f421436aSArvid Brodin res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); 328f421436aSArvid Brodin if (res < 0) 329f421436aSArvid Brodin goto nla_put_failure; 33051f3c605SArvid Brodin rcu_read_lock(); 331c5a75911SArvid Brodin port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); 332c5a75911SArvid Brodin if (port) 333c5a75911SArvid Brodin res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, 334c5a75911SArvid Brodin port->dev->ifindex); 33551f3c605SArvid Brodin rcu_read_unlock(); 336f421436aSArvid Brodin if (res < 0) 337f421436aSArvid Brodin goto nla_put_failure; 338f421436aSArvid Brodin 339f421436aSArvid Brodin res = nla_put_u32(skb_out, HSR_A_IF2_AGE, hsr_node_if2_age); 340f421436aSArvid Brodin if (res < 0) 341f421436aSArvid Brodin goto nla_put_failure; 342f421436aSArvid Brodin res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); 343f421436aSArvid Brodin if (res < 0) 344f421436aSArvid Brodin goto nla_put_failure; 34551f3c605SArvid Brodin rcu_read_lock(); 346c5a75911SArvid Brodin port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); 347c5a75911SArvid Brodin if (port) 348c5a75911SArvid Brodin res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, 349c5a75911SArvid Brodin port->dev->ifindex); 35051f3c605SArvid Brodin rcu_read_unlock(); 35151f3c605SArvid Brodin if (res < 0) 35251f3c605SArvid Brodin goto nla_put_failure; 353f421436aSArvid Brodin 354f421436aSArvid Brodin genlmsg_end(skb_out, msg_head); 355f421436aSArvid Brodin genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); 356f421436aSArvid Brodin 357f421436aSArvid Brodin return 0; 358f421436aSArvid Brodin 359f421436aSArvid Brodin invalid: 360f421436aSArvid Brodin netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL); 361f421436aSArvid Brodin return 0; 362f421436aSArvid Brodin 363f421436aSArvid Brodin nla_put_failure: 364f421436aSArvid Brodin kfree_skb(skb_out); 365f421436aSArvid Brodin /* Fall through */ 366f421436aSArvid Brodin 367f421436aSArvid Brodin fail: 368f421436aSArvid Brodin return res; 369f421436aSArvid Brodin } 370f421436aSArvid Brodin 371f266a683SArvid Brodin /* Get a list of MacAddressA of all nodes known to this node (including self). 372f421436aSArvid Brodin */ 373f421436aSArvid Brodin static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) 374f421436aSArvid Brodin { 375f421436aSArvid Brodin /* For receiving */ 376f421436aSArvid Brodin struct nlattr *na; 377f421436aSArvid Brodin struct net_device *hsr_dev; 378f421436aSArvid Brodin 379f421436aSArvid Brodin /* For sending */ 380f421436aSArvid Brodin struct sk_buff *skb_out; 381f421436aSArvid Brodin void *msg_head; 38270ebe4a4SArvid Brodin struct hsr_priv *hsr; 383f421436aSArvid Brodin void *pos; 384f421436aSArvid Brodin unsigned char addr[ETH_ALEN]; 385f421436aSArvid Brodin int res; 386f421436aSArvid Brodin 387f421436aSArvid Brodin if (!info) 388f421436aSArvid Brodin goto invalid; 389f421436aSArvid Brodin 390f421436aSArvid Brodin na = info->attrs[HSR_A_IFINDEX]; 391f421436aSArvid Brodin if (!na) 392f421436aSArvid Brodin goto invalid; 393f421436aSArvid Brodin 394f421436aSArvid Brodin hsr_dev = __dev_get_by_index(genl_info_net(info), 395f421436aSArvid Brodin nla_get_u32(info->attrs[HSR_A_IFINDEX])); 396f421436aSArvid Brodin if (!hsr_dev) 397f421436aSArvid Brodin goto invalid; 398f421436aSArvid Brodin if (!is_hsr_master(hsr_dev)) 399f421436aSArvid Brodin goto invalid; 400f421436aSArvid Brodin 401f421436aSArvid Brodin 402f421436aSArvid Brodin /* Send reply */ 403f421436aSArvid Brodin 404f421436aSArvid Brodin skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 405f421436aSArvid Brodin if (!skb_out) { 406f421436aSArvid Brodin res = -ENOMEM; 407f421436aSArvid Brodin goto fail; 408f421436aSArvid Brodin } 409f421436aSArvid Brodin 410f421436aSArvid Brodin msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid, 411f421436aSArvid Brodin info->snd_seq, &hsr_genl_family, 0, 412f421436aSArvid Brodin HSR_C_SET_NODE_LIST); 413f421436aSArvid Brodin if (!msg_head) { 414f421436aSArvid Brodin res = -ENOMEM; 415f421436aSArvid Brodin goto nla_put_failure; 416f421436aSArvid Brodin } 417f421436aSArvid Brodin 418f421436aSArvid Brodin res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); 419f421436aSArvid Brodin if (res < 0) 420f421436aSArvid Brodin goto nla_put_failure; 421f421436aSArvid Brodin 42270ebe4a4SArvid Brodin hsr = netdev_priv(hsr_dev); 423f421436aSArvid Brodin 424f421436aSArvid Brodin rcu_read_lock(); 42570ebe4a4SArvid Brodin pos = hsr_get_next_node(hsr, NULL, addr); 426f421436aSArvid Brodin while (pos) { 427f421436aSArvid Brodin res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); 428f421436aSArvid Brodin if (res < 0) { 429f421436aSArvid Brodin rcu_read_unlock(); 430f421436aSArvid Brodin goto nla_put_failure; 431f421436aSArvid Brodin } 43270ebe4a4SArvid Brodin pos = hsr_get_next_node(hsr, pos, addr); 433f421436aSArvid Brodin } 434f421436aSArvid Brodin rcu_read_unlock(); 435f421436aSArvid Brodin 436f421436aSArvid Brodin genlmsg_end(skb_out, msg_head); 437f421436aSArvid Brodin genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); 438f421436aSArvid Brodin 439f421436aSArvid Brodin return 0; 440f421436aSArvid Brodin 441f421436aSArvid Brodin invalid: 442f421436aSArvid Brodin netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL); 443f421436aSArvid Brodin return 0; 444f421436aSArvid Brodin 445f421436aSArvid Brodin nla_put_failure: 446f421436aSArvid Brodin kfree_skb(skb_out); 447f421436aSArvid Brodin /* Fall through */ 448f421436aSArvid Brodin 449f421436aSArvid Brodin fail: 450f421436aSArvid Brodin return res; 451f421436aSArvid Brodin } 452f421436aSArvid Brodin 453f421436aSArvid Brodin 4544534de83SJohannes Berg static const struct genl_ops hsr_ops[] = { 4559504b3eeSJohannes Berg { 4569504b3eeSJohannes Berg .cmd = HSR_C_GET_NODE_STATUS, 4579504b3eeSJohannes Berg .flags = 0, 4589504b3eeSJohannes Berg .policy = hsr_genl_policy, 4599504b3eeSJohannes Berg .doit = hsr_get_node_status, 4609504b3eeSJohannes Berg .dumpit = NULL, 4619504b3eeSJohannes Berg }, 4629504b3eeSJohannes Berg { 463f421436aSArvid Brodin .cmd = HSR_C_GET_NODE_LIST, 464f421436aSArvid Brodin .flags = 0, 465f421436aSArvid Brodin .policy = hsr_genl_policy, 466f421436aSArvid Brodin .doit = hsr_get_node_list, 467f421436aSArvid Brodin .dumpit = NULL, 4689504b3eeSJohannes Berg }, 469f421436aSArvid Brodin }; 470f421436aSArvid Brodin 471f421436aSArvid Brodin int __init hsr_netlink_init(void) 472f421436aSArvid Brodin { 473f421436aSArvid Brodin int rc; 474f421436aSArvid Brodin 475f421436aSArvid Brodin rc = rtnl_link_register(&hsr_link_ops); 476f421436aSArvid Brodin if (rc) 477f421436aSArvid Brodin goto fail_rtnl_link_register; 478f421436aSArvid Brodin 4792a94fe48SJohannes Berg rc = genl_register_family_with_ops_groups(&hsr_genl_family, hsr_ops, 4802a94fe48SJohannes Berg hsr_mcgrps); 481f421436aSArvid Brodin if (rc) 482f421436aSArvid Brodin goto fail_genl_register_family; 483f421436aSArvid Brodin 484f421436aSArvid Brodin return 0; 485f421436aSArvid Brodin 486f421436aSArvid Brodin fail_genl_register_family: 487f421436aSArvid Brodin rtnl_link_unregister(&hsr_link_ops); 488f421436aSArvid Brodin fail_rtnl_link_register: 489f421436aSArvid Brodin 490f421436aSArvid Brodin return rc; 491f421436aSArvid Brodin } 492f421436aSArvid Brodin 493f421436aSArvid Brodin void __exit hsr_netlink_exit(void) 494f421436aSArvid Brodin { 495f421436aSArvid Brodin genl_unregister_family(&hsr_genl_family); 496f421436aSArvid Brodin rtnl_link_unregister(&hsr_link_ops); 497f421436aSArvid Brodin } 498f421436aSArvid Brodin 499f421436aSArvid Brodin MODULE_ALIAS_RTNL_LINK("hsr"); 500