| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* Copyright 2011-2014 Autronica Fire and Security AS |
|---|
| 2 | | - * |
|---|
| 3 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 4 | | - * under the terms of the GNU General Public License as published by the Free |
|---|
| 5 | | - * Software Foundation; either version 2 of the License, or (at your option) |
|---|
| 6 | | - * any later version. |
|---|
| 7 | 3 | * |
|---|
| 8 | 4 | * Author(s): |
|---|
| 9 | 5 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
|---|
| 10 | 6 | * |
|---|
| 11 | | - * Routines for handling Netlink messages for HSR. |
|---|
| 7 | + * Routines for handling Netlink messages for HSR and PRP. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 14 | 10 | #include "hsr_netlink.h" |
|---|
| .. | .. |
|---|
| 26 | 22 | [IFLA_HSR_VERSION] = { .type = NLA_U8 }, |
|---|
| 27 | 23 | [IFLA_HSR_SUPERVISION_ADDR] = { .len = ETH_ALEN }, |
|---|
| 28 | 24 | [IFLA_HSR_SEQ_NR] = { .type = NLA_U16 }, |
|---|
| 25 | + [IFLA_HSR_PROTOCOL] = { .type = NLA_U8 }, |
|---|
| 29 | 26 | }; |
|---|
| 30 | | - |
|---|
| 31 | 27 | |
|---|
| 32 | 28 | /* Here, it seems a netdevice has already been allocated for us, and the |
|---|
| 33 | 29 | * hsr_dev_setup routine has been executed. Nice! |
|---|
| .. | .. |
|---|
| 36 | 32 | struct nlattr *tb[], struct nlattr *data[], |
|---|
| 37 | 33 | struct netlink_ext_ack *extack) |
|---|
| 38 | 34 | { |
|---|
| 35 | + enum hsr_version proto_version; |
|---|
| 36 | + unsigned char multicast_spec; |
|---|
| 37 | + u8 proto = HSR_PROTOCOL_HSR; |
|---|
| 39 | 38 | struct net_device *link[2]; |
|---|
| 40 | | - unsigned char multicast_spec, hsr_version; |
|---|
| 41 | 39 | |
|---|
| 42 | 40 | if (!data) { |
|---|
| 43 | | - netdev_info(dev, "HSR: No slave devices specified\n"); |
|---|
| 41 | + NL_SET_ERR_MSG_MOD(extack, "No slave devices specified"); |
|---|
| 44 | 42 | return -EINVAL; |
|---|
| 45 | 43 | } |
|---|
| 46 | 44 | if (!data[IFLA_HSR_SLAVE1]) { |
|---|
| 47 | | - netdev_info(dev, "HSR: Slave1 device not specified\n"); |
|---|
| 45 | + NL_SET_ERR_MSG_MOD(extack, "Slave1 device not specified"); |
|---|
| 48 | 46 | return -EINVAL; |
|---|
| 49 | 47 | } |
|---|
| 50 | | - link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1])); |
|---|
| 48 | + link[0] = __dev_get_by_index(src_net, |
|---|
| 49 | + nla_get_u32(data[IFLA_HSR_SLAVE1])); |
|---|
| 50 | + if (!link[0]) { |
|---|
| 51 | + NL_SET_ERR_MSG_MOD(extack, "Slave1 does not exist"); |
|---|
| 52 | + return -EINVAL; |
|---|
| 53 | + } |
|---|
| 51 | 54 | if (!data[IFLA_HSR_SLAVE2]) { |
|---|
| 52 | | - netdev_info(dev, "HSR: Slave2 device not specified\n"); |
|---|
| 55 | + NL_SET_ERR_MSG_MOD(extack, "Slave2 device not specified"); |
|---|
| 53 | 56 | return -EINVAL; |
|---|
| 54 | 57 | } |
|---|
| 55 | | - link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2])); |
|---|
| 56 | | - |
|---|
| 57 | | - if (!link[0] || !link[1]) |
|---|
| 58 | | - return -ENODEV; |
|---|
| 59 | | - if (link[0] == link[1]) |
|---|
| 58 | + link[1] = __dev_get_by_index(src_net, |
|---|
| 59 | + nla_get_u32(data[IFLA_HSR_SLAVE2])); |
|---|
| 60 | + if (!link[1]) { |
|---|
| 61 | + NL_SET_ERR_MSG_MOD(extack, "Slave2 does not exist"); |
|---|
| 60 | 62 | return -EINVAL; |
|---|
| 63 | + } |
|---|
| 64 | + |
|---|
| 65 | + if (link[0] == link[1]) { |
|---|
| 66 | + NL_SET_ERR_MSG_MOD(extack, "Slave1 and Slave2 are same"); |
|---|
| 67 | + return -EINVAL; |
|---|
| 68 | + } |
|---|
| 61 | 69 | |
|---|
| 62 | 70 | if (!data[IFLA_HSR_MULTICAST_SPEC]) |
|---|
| 63 | 71 | multicast_spec = 0; |
|---|
| 64 | 72 | else |
|---|
| 65 | 73 | multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]); |
|---|
| 66 | 74 | |
|---|
| 75 | + if (data[IFLA_HSR_PROTOCOL]) |
|---|
| 76 | + proto = nla_get_u8(data[IFLA_HSR_PROTOCOL]); |
|---|
| 77 | + |
|---|
| 78 | + if (proto >= HSR_PROTOCOL_MAX) { |
|---|
| 79 | + NL_SET_ERR_MSG_MOD(extack, "Unsupported protocol"); |
|---|
| 80 | + return -EINVAL; |
|---|
| 81 | + } |
|---|
| 82 | + |
|---|
| 67 | 83 | if (!data[IFLA_HSR_VERSION]) { |
|---|
| 68 | | - hsr_version = 0; |
|---|
| 84 | + proto_version = HSR_V0; |
|---|
| 69 | 85 | } else { |
|---|
| 70 | | - hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]); |
|---|
| 71 | | - if (hsr_version > 1) { |
|---|
| 86 | + if (proto == HSR_PROTOCOL_PRP) { |
|---|
| 87 | + NL_SET_ERR_MSG_MOD(extack, "PRP version unsupported"); |
|---|
| 88 | + return -EINVAL; |
|---|
| 89 | + } |
|---|
| 90 | + |
|---|
| 91 | + proto_version = nla_get_u8(data[IFLA_HSR_VERSION]); |
|---|
| 92 | + if (proto_version > HSR_V1) { |
|---|
| 72 | 93 | NL_SET_ERR_MSG_MOD(extack, |
|---|
| 73 | | - "Only versions 0..1 are supported"); |
|---|
| 94 | + "Only HSR version 0/1 supported"); |
|---|
| 74 | 95 | return -EINVAL; |
|---|
| 75 | 96 | } |
|---|
| 76 | 97 | } |
|---|
| 77 | 98 | |
|---|
| 78 | | - return hsr_dev_finalize(dev, link, multicast_spec, hsr_version); |
|---|
| 99 | + if (proto == HSR_PROTOCOL_PRP) |
|---|
| 100 | + proto_version = PRP_V1; |
|---|
| 101 | + |
|---|
| 102 | + return hsr_dev_finalize(dev, link, multicast_spec, proto_version, extack); |
|---|
| 103 | +} |
|---|
| 104 | + |
|---|
| 105 | +static void hsr_dellink(struct net_device *dev, struct list_head *head) |
|---|
| 106 | +{ |
|---|
| 107 | + struct hsr_priv *hsr = netdev_priv(dev); |
|---|
| 108 | + |
|---|
| 109 | + del_timer_sync(&hsr->prune_timer); |
|---|
| 110 | + del_timer_sync(&hsr->announce_timer); |
|---|
| 111 | + |
|---|
| 112 | + hsr_debugfs_term(hsr); |
|---|
| 113 | + hsr_del_ports(hsr); |
|---|
| 114 | + |
|---|
| 115 | + hsr_del_self_node(hsr); |
|---|
| 116 | + hsr_del_nodes(&hsr->node_db); |
|---|
| 117 | + |
|---|
| 118 | + unregister_netdevice_queue(dev, head); |
|---|
| 79 | 119 | } |
|---|
| 80 | 120 | |
|---|
| 81 | 121 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) |
|---|
| 82 | 122 | { |
|---|
| 83 | | - struct hsr_priv *hsr; |
|---|
| 123 | + struct hsr_priv *hsr = netdev_priv(dev); |
|---|
| 124 | + u8 proto = HSR_PROTOCOL_HSR; |
|---|
| 84 | 125 | struct hsr_port *port; |
|---|
| 85 | | - int res; |
|---|
| 86 | 126 | |
|---|
| 87 | | - hsr = netdev_priv(dev); |
|---|
| 88 | | - |
|---|
| 89 | | - res = 0; |
|---|
| 90 | | - |
|---|
| 91 | | - rcu_read_lock(); |
|---|
| 92 | 127 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); |
|---|
| 93 | | - if (port) |
|---|
| 94 | | - res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex); |
|---|
| 95 | | - rcu_read_unlock(); |
|---|
| 96 | | - if (res) |
|---|
| 97 | | - goto nla_put_failure; |
|---|
| 128 | + if (port) { |
|---|
| 129 | + if (nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex)) |
|---|
| 130 | + goto nla_put_failure; |
|---|
| 131 | + } |
|---|
| 98 | 132 | |
|---|
| 99 | | - rcu_read_lock(); |
|---|
| 100 | 133 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
|---|
| 101 | | - if (port) |
|---|
| 102 | | - res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex); |
|---|
| 103 | | - rcu_read_unlock(); |
|---|
| 104 | | - if (res) |
|---|
| 105 | | - goto nla_put_failure; |
|---|
| 134 | + if (port) { |
|---|
| 135 | + if (nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex)) |
|---|
| 136 | + goto nla_put_failure; |
|---|
| 137 | + } |
|---|
| 106 | 138 | |
|---|
| 107 | 139 | if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, |
|---|
| 108 | 140 | hsr->sup_multicast_addr) || |
|---|
| 109 | 141 | nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr)) |
|---|
| 142 | + goto nla_put_failure; |
|---|
| 143 | + if (hsr->prot_version == PRP_V1) |
|---|
| 144 | + proto = HSR_PROTOCOL_PRP; |
|---|
| 145 | + if (nla_put_u8(skb, IFLA_HSR_PROTOCOL, proto)) |
|---|
| 110 | 146 | goto nla_put_failure; |
|---|
| 111 | 147 | |
|---|
| 112 | 148 | return 0; |
|---|
| .. | .. |
|---|
| 122 | 158 | .priv_size = sizeof(struct hsr_priv), |
|---|
| 123 | 159 | .setup = hsr_dev_setup, |
|---|
| 124 | 160 | .newlink = hsr_newlink, |
|---|
| 161 | + .dellink = hsr_dellink, |
|---|
| 125 | 162 | .fill_info = hsr_fill_info, |
|---|
| 126 | 163 | }; |
|---|
| 127 | | - |
|---|
| 128 | | - |
|---|
| 129 | 164 | |
|---|
| 130 | 165 | /* attribute policy */ |
|---|
| 131 | 166 | static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = { |
|---|
| .. | .. |
|---|
| 144 | 179 | { .name = "hsr-network", }, |
|---|
| 145 | 180 | }; |
|---|
| 146 | 181 | |
|---|
| 147 | | - |
|---|
| 148 | | - |
|---|
| 149 | 182 | /* This is called if for some node with MAC address addr, we only get frames |
|---|
| 150 | 183 | * over one of the slave interfaces. This would indicate an open network ring |
|---|
| 151 | 184 | * (i.e. a link has failed somewhere). |
|---|
| .. | .. |
|---|
| 162 | 195 | if (!skb) |
|---|
| 163 | 196 | goto fail; |
|---|
| 164 | 197 | |
|---|
| 165 | | - msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_RING_ERROR); |
|---|
| 198 | + msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, |
|---|
| 199 | + HSR_C_RING_ERROR); |
|---|
| 166 | 200 | if (!msg_head) |
|---|
| 167 | 201 | goto nla_put_failure; |
|---|
| 168 | 202 | |
|---|
| .. | .. |
|---|
| 207 | 241 | if (!msg_head) |
|---|
| 208 | 242 | goto nla_put_failure; |
|---|
| 209 | 243 | |
|---|
| 210 | | - |
|---|
| 211 | 244 | res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr); |
|---|
| 212 | 245 | if (res < 0) |
|---|
| 213 | 246 | goto nla_put_failure; |
|---|
| .. | .. |
|---|
| 226 | 259 | netdev_warn(master->dev, "Could not send HSR node down\n"); |
|---|
| 227 | 260 | rcu_read_unlock(); |
|---|
| 228 | 261 | } |
|---|
| 229 | | - |
|---|
| 230 | 262 | |
|---|
| 231 | 263 | /* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table |
|---|
| 232 | 264 | * about the status of a specific node in the network, defined by its MAC |
|---|
| .. | .. |
|---|
| 281 | 313 | } |
|---|
| 282 | 314 | |
|---|
| 283 | 315 | msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid, |
|---|
| 284 | | - info->snd_seq, &hsr_genl_family, 0, |
|---|
| 285 | | - HSR_C_SET_NODE_STATUS); |
|---|
| 316 | + info->snd_seq, &hsr_genl_family, 0, |
|---|
| 317 | + HSR_C_SET_NODE_STATUS); |
|---|
| 286 | 318 | if (!msg_head) { |
|---|
| 287 | 319 | res = -ENOMEM; |
|---|
| 288 | 320 | goto nla_put_failure; |
|---|
| .. | .. |
|---|
| 294 | 326 | |
|---|
| 295 | 327 | hsr = netdev_priv(hsr_dev); |
|---|
| 296 | 328 | res = hsr_get_node_data(hsr, |
|---|
| 297 | | - (unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]), |
|---|
| 298 | | - hsr_node_addr_b, |
|---|
| 299 | | - &addr_b_ifindex, |
|---|
| 300 | | - &hsr_node_if1_age, |
|---|
| 301 | | - &hsr_node_if1_seq, |
|---|
| 302 | | - &hsr_node_if2_age, |
|---|
| 303 | | - &hsr_node_if2_seq); |
|---|
| 329 | + (unsigned char *) |
|---|
| 330 | + nla_data(info->attrs[HSR_A_NODE_ADDR]), |
|---|
| 331 | + hsr_node_addr_b, |
|---|
| 332 | + &addr_b_ifindex, |
|---|
| 333 | + &hsr_node_if1_age, |
|---|
| 334 | + &hsr_node_if1_seq, |
|---|
| 335 | + &hsr_node_if2_age, |
|---|
| 336 | + &hsr_node_if2_seq); |
|---|
| 304 | 337 | if (res < 0) |
|---|
| 305 | 338 | goto nla_put_failure; |
|---|
| 306 | 339 | |
|---|
| 307 | 340 | res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, |
|---|
| 308 | | - nla_data(info->attrs[HSR_A_NODE_ADDR])); |
|---|
| 341 | + nla_data(info->attrs[HSR_A_NODE_ADDR])); |
|---|
| 309 | 342 | if (res < 0) |
|---|
| 310 | 343 | goto nla_put_failure; |
|---|
| 311 | 344 | |
|---|
| 312 | 345 | if (addr_b_ifindex > -1) { |
|---|
| 313 | 346 | res = nla_put(skb_out, HSR_A_NODE_ADDR_B, ETH_ALEN, |
|---|
| 314 | | - hsr_node_addr_b); |
|---|
| 347 | + hsr_node_addr_b); |
|---|
| 315 | 348 | if (res < 0) |
|---|
| 316 | 349 | goto nla_put_failure; |
|---|
| 317 | 350 | |
|---|
| 318 | | - res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX, addr_b_ifindex); |
|---|
| 351 | + res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX, |
|---|
| 352 | + addr_b_ifindex); |
|---|
| 319 | 353 | if (res < 0) |
|---|
| 320 | 354 | goto nla_put_failure; |
|---|
| 321 | 355 | } |
|---|
| .. | .. |
|---|
| 406 | 440 | } |
|---|
| 407 | 441 | |
|---|
| 408 | 442 | msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid, |
|---|
| 409 | | - info->snd_seq, &hsr_genl_family, 0, |
|---|
| 410 | | - HSR_C_SET_NODE_LIST); |
|---|
| 443 | + info->snd_seq, &hsr_genl_family, 0, |
|---|
| 444 | + HSR_C_SET_NODE_LIST); |
|---|
| 411 | 445 | if (!msg_head) { |
|---|
| 412 | 446 | res = -ENOMEM; |
|---|
| 413 | 447 | goto nla_put_failure; |
|---|
| .. | .. |
|---|
| 459 | 493 | return res; |
|---|
| 460 | 494 | } |
|---|
| 461 | 495 | |
|---|
| 462 | | - |
|---|
| 463 | | -static const struct genl_ops hsr_ops[] = { |
|---|
| 496 | +static const struct genl_small_ops hsr_ops[] = { |
|---|
| 464 | 497 | { |
|---|
| 465 | 498 | .cmd = HSR_C_GET_NODE_STATUS, |
|---|
| 499 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 466 | 500 | .flags = 0, |
|---|
| 467 | | - .policy = hsr_genl_policy, |
|---|
| 468 | 501 | .doit = hsr_get_node_status, |
|---|
| 469 | 502 | .dumpit = NULL, |
|---|
| 470 | 503 | }, |
|---|
| 471 | 504 | { |
|---|
| 472 | 505 | .cmd = HSR_C_GET_NODE_LIST, |
|---|
| 506 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 473 | 507 | .flags = 0, |
|---|
| 474 | | - .policy = hsr_genl_policy, |
|---|
| 475 | 508 | .doit = hsr_get_node_list, |
|---|
| 476 | 509 | .dumpit = NULL, |
|---|
| 477 | 510 | }, |
|---|
| .. | .. |
|---|
| 482 | 515 | .name = "HSR", |
|---|
| 483 | 516 | .version = 1, |
|---|
| 484 | 517 | .maxattr = HSR_A_MAX, |
|---|
| 518 | + .policy = hsr_genl_policy, |
|---|
| 485 | 519 | .netnsok = true, |
|---|
| 486 | 520 | .module = THIS_MODULE, |
|---|
| 487 | | - .ops = hsr_ops, |
|---|
| 488 | | - .n_ops = ARRAY_SIZE(hsr_ops), |
|---|
| 521 | + .small_ops = hsr_ops, |
|---|
| 522 | + .n_small_ops = ARRAY_SIZE(hsr_ops), |
|---|
| 489 | 523 | .mcgrps = hsr_mcgrps, |
|---|
| 490 | 524 | .n_mcgrps = ARRAY_SIZE(hsr_mcgrps), |
|---|
| 491 | 525 | }; |
|---|
| .. | .. |
|---|
| 502 | 536 | if (rc) |
|---|
| 503 | 537 | goto fail_genl_register_family; |
|---|
| 504 | 538 | |
|---|
| 539 | + hsr_debugfs_create_root(); |
|---|
| 505 | 540 | return 0; |
|---|
| 506 | 541 | |
|---|
| 507 | 542 | fail_genl_register_family: |
|---|