.. | .. |
---|
| 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 |
---|
| 6 | + * |
---|
| 7 | + * Event handling for HSR and PRP devices. |
---|
10 | 8 | */ |
---|
11 | 9 | |
---|
12 | 10 | #include <linux/netdevice.h> |
---|
| 11 | +#include <net/rtnetlink.h> |
---|
13 | 12 | #include <linux/rculist.h> |
---|
14 | 13 | #include <linux/timer.h> |
---|
15 | 14 | #include <linux/etherdevice.h> |
---|
.. | .. |
---|
19 | 18 | #include "hsr_framereg.h" |
---|
20 | 19 | #include "hsr_slave.h" |
---|
21 | 20 | |
---|
| 21 | +static bool hsr_slave_empty(struct hsr_priv *hsr) |
---|
| 22 | +{ |
---|
| 23 | + struct hsr_port *port; |
---|
| 24 | + |
---|
| 25 | + hsr_for_each_port(hsr, port) |
---|
| 26 | + if (port->type != HSR_PT_MASTER) |
---|
| 27 | + return false; |
---|
| 28 | + return true; |
---|
| 29 | +} |
---|
22 | 30 | |
---|
23 | 31 | static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, |
---|
24 | 32 | void *ptr) |
---|
25 | 33 | { |
---|
26 | | - struct net_device *dev; |
---|
27 | 34 | struct hsr_port *port, *master; |
---|
| 35 | + struct net_device *dev; |
---|
28 | 36 | struct hsr_priv *hsr; |
---|
| 37 | + LIST_HEAD(list_kill); |
---|
29 | 38 | int mtu_max; |
---|
30 | 39 | int res; |
---|
31 | 40 | |
---|
32 | 41 | dev = netdev_notifier_info_to_dev(ptr); |
---|
33 | 42 | port = hsr_port_get_rtnl(dev); |
---|
34 | | - if (port == NULL) { |
---|
| 43 | + if (!port) { |
---|
35 | 44 | if (!is_hsr_master(dev)) |
---|
36 | 45 | return NOTIFY_DONE; /* Not an HSR device */ |
---|
37 | 46 | hsr = netdev_priv(dev); |
---|
38 | 47 | port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
---|
39 | | - if (port == NULL) { |
---|
| 48 | + if (!port) { |
---|
40 | 49 | /* Resend of notification concerning removed device? */ |
---|
41 | 50 | return NOTIFY_DONE; |
---|
42 | 51 | } |
---|
.. | .. |
---|
49 | 58 | case NETDEV_DOWN: /* Administrative state UP */ |
---|
50 | 59 | case NETDEV_CHANGE: /* Link (carrier) state changes */ |
---|
51 | 60 | hsr_check_carrier_and_operstate(hsr); |
---|
| 61 | + break; |
---|
| 62 | + case NETDEV_CHANGENAME: |
---|
| 63 | + if (is_hsr_master(dev)) |
---|
| 64 | + hsr_debugfs_rename(dev); |
---|
52 | 65 | break; |
---|
53 | 66 | case NETDEV_CHANGEADDR: |
---|
54 | 67 | if (port->type == HSR_PT_MASTER) { |
---|
.. | .. |
---|
63 | 76 | |
---|
64 | 77 | if (port->type == HSR_PT_SLAVE_A) { |
---|
65 | 78 | ether_addr_copy(master->dev->dev_addr, dev->dev_addr); |
---|
66 | | - call_netdevice_notifiers(NETDEV_CHANGEADDR, master->dev); |
---|
| 79 | + call_netdevice_notifiers(NETDEV_CHANGEADDR, |
---|
| 80 | + master->dev); |
---|
67 | 81 | } |
---|
68 | 82 | |
---|
69 | 83 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ |
---|
70 | 84 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
---|
71 | | - res = hsr_create_self_node(&hsr->self_node_db, |
---|
| 85 | + res = hsr_create_self_node(hsr, |
---|
72 | 86 | master->dev->dev_addr, |
---|
73 | 87 | port ? |
---|
74 | 88 | port->dev->dev_addr : |
---|
.. | .. |
---|
85 | 99 | master->dev->mtu = mtu_max; |
---|
86 | 100 | break; |
---|
87 | 101 | case NETDEV_UNREGISTER: |
---|
88 | | - hsr_del_port(port); |
---|
| 102 | + if (!is_hsr_master(dev)) { |
---|
| 103 | + master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); |
---|
| 104 | + hsr_del_port(port); |
---|
| 105 | + if (hsr_slave_empty(master->hsr)) { |
---|
| 106 | + const struct rtnl_link_ops *ops; |
---|
| 107 | + |
---|
| 108 | + ops = master->dev->rtnl_link_ops; |
---|
| 109 | + ops->dellink(master->dev, &list_kill); |
---|
| 110 | + unregister_netdevice_many(&list_kill); |
---|
| 111 | + } |
---|
| 112 | + } |
---|
89 | 113 | break; |
---|
90 | 114 | case NETDEV_PRE_TYPE_CHANGE: |
---|
91 | 115 | /* HSR works only on Ethernet devices. Refuse slave to change |
---|
.. | .. |
---|
96 | 120 | |
---|
97 | 121 | return NOTIFY_DONE; |
---|
98 | 122 | } |
---|
99 | | - |
---|
100 | 123 | |
---|
101 | 124 | struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) |
---|
102 | 125 | { |
---|
.. | .. |
---|
112 | 135 | .notifier_call = hsr_netdev_notify, /* Slave event notifications */ |
---|
113 | 136 | }; |
---|
114 | 137 | |
---|
115 | | - |
---|
116 | 138 | static int __init hsr_init(void) |
---|
117 | 139 | { |
---|
118 | 140 | int res; |
---|
.. | .. |
---|
127 | 149 | |
---|
128 | 150 | static void __exit hsr_exit(void) |
---|
129 | 151 | { |
---|
130 | | - unregister_netdevice_notifier(&hsr_nb); |
---|
131 | 152 | hsr_netlink_exit(); |
---|
| 153 | + hsr_debugfs_remove_root(); |
---|
| 154 | + unregister_netdevice_notifier(&hsr_nb); |
---|
132 | 155 | } |
---|
133 | 156 | |
---|
134 | 157 | module_init(hsr_init); |
---|