.. | .. |
---|
| 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: |
---|