]>
Commit | Line | Data |
---|---|---|
0e7623bd | 1 | // SPDX-License-Identifier: GPL-2.0 |
70ebe4a4 | 2 | /* Copyright 2011-2014 Autronica Fire and Security AS |
f421436a AB |
3 | * |
4 | * Author(s): | |
70ebe4a4 | 5 | * 2011-2014 Arvid Brodin, [email protected] |
8f4c0e01 MK |
6 | * |
7 | * Event handling for HSR and PRP devices. | |
f421436a AB |
8 | */ |
9 | ||
10 | #include <linux/netdevice.h> | |
de0083c7 | 11 | #include <net/rtnetlink.h> |
f421436a AB |
12 | #include <linux/rculist.h> |
13 | #include <linux/timer.h> | |
14 | #include <linux/etherdevice.h> | |
15 | #include "hsr_main.h" | |
16 | #include "hsr_device.h" | |
17 | #include "hsr_netlink.h" | |
18 | #include "hsr_framereg.h" | |
51f3c605 | 19 | #include "hsr_slave.h" |
f421436a | 20 | |
34a9c361 TY |
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 | } | |
30 | ||
f421436a AB |
31 | static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, |
32 | void *ptr) | |
33 | { | |
c5a75911 | 34 | struct hsr_port *port, *master; |
34a9c361 | 35 | struct net_device *dev; |
70ebe4a4 | 36 | struct hsr_priv *hsr; |
34a9c361 | 37 | LIST_HEAD(list_kill); |
f421436a AB |
38 | int mtu_max; |
39 | int res; | |
f421436a AB |
40 | |
41 | dev = netdev_notifier_info_to_dev(ptr); | |
c5a75911 | 42 | port = hsr_port_get_rtnl(dev); |
05ca6e64 | 43 | if (!port) { |
f421436a | 44 | if (!is_hsr_master(dev)) |
c5a75911 | 45 | return NOTIFY_DONE; /* Not an HSR device */ |
70ebe4a4 | 46 | hsr = netdev_priv(dev); |
c5a75911 | 47 | port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
05ca6e64 | 48 | if (!port) { |
56b08fdc AB |
49 | /* Resend of notification concerning removed device? */ |
50 | return NOTIFY_DONE; | |
51 | } | |
c5a75911 AB |
52 | } else { |
53 | hsr = port->hsr; | |
f421436a AB |
54 | } |
55 | ||
56 | switch (event) { | |
57 | case NETDEV_UP: /* Administrative state DOWN */ | |
58 | case NETDEV_DOWN: /* Administrative state UP */ | |
59 | case NETDEV_CHANGE: /* Link (carrier) state changes */ | |
e9aae56e | 60 | hsr_check_carrier_and_operstate(hsr); |
f421436a | 61 | break; |
4c2d5e33 | 62 | case NETDEV_CHANGENAME: |
04b69426 TY |
63 | if (is_hsr_master(dev)) |
64 | hsr_debugfs_rename(dev); | |
4c2d5e33 | 65 | break; |
f421436a | 66 | case NETDEV_CHANGEADDR: |
c5a75911 AB |
67 | if (port->type == HSR_PT_MASTER) { |
68 | /* This should not happen since there's no | |
69 | * ndo_set_mac_address() for HSR devices - i.e. not | |
70 | * supported. | |
71 | */ | |
f421436a | 72 | break; |
c5a75911 | 73 | } |
f421436a | 74 | |
c5a75911 AB |
75 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
76 | ||
77 | if (port->type == HSR_PT_SLAVE_A) { | |
78 | ether_addr_copy(master->dev->dev_addr, dev->dev_addr); | |
d595b85a MK |
79 | call_netdevice_notifiers(NETDEV_CHANGEADDR, |
80 | master->dev); | |
51f3c605 | 81 | } |
f421436a AB |
82 | |
83 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ | |
c5a75911 | 84 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
92a35678 | 85 | res = hsr_create_self_node(hsr, |
c5a75911 AB |
86 | master->dev->dev_addr, |
87 | port ? | |
88 | port->dev->dev_addr : | |
89 | master->dev->dev_addr); | |
f421436a | 90 | if (res) |
c5a75911 | 91 | netdev_warn(master->dev, |
f421436a | 92 | "Could not update HSR node address.\n"); |
f421436a AB |
93 | break; |
94 | case NETDEV_CHANGEMTU: | |
c5a75911 | 95 | if (port->type == HSR_PT_MASTER) |
f421436a | 96 | break; /* Handled in ndo_change_mtu() */ |
c5a75911 AB |
97 | mtu_max = hsr_get_max_mtu(port->hsr); |
98 | master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); | |
99 | master->dev->mtu = mtu_max; | |
f421436a AB |
100 | break; |
101 | case NETDEV_UNREGISTER: | |
34a9c361 TY |
102 | if (!is_hsr_master(dev)) { |
103 | master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); | |
e0a4b997 | 104 | hsr_del_port(port); |
34a9c361 | 105 | if (hsr_slave_empty(master->hsr)) { |
de0083c7 TY |
106 | const struct rtnl_link_ops *ops; |
107 | ||
108 | ops = master->dev->rtnl_link_ops; | |
109 | ops->dellink(master->dev, &list_kill); | |
34a9c361 TY |
110 | unregister_netdevice_many(&list_kill); |
111 | } | |
112 | } | |
f421436a AB |
113 | break; |
114 | case NETDEV_PRE_TYPE_CHANGE: | |
115 | /* HSR works only on Ethernet devices. Refuse slave to change | |
116 | * its type. | |
117 | */ | |
118 | return NOTIFY_BAD; | |
119 | } | |
120 | ||
121 | return NOTIFY_DONE; | |
122 | } | |
123 | ||
c5a75911 AB |
124 | struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) |
125 | { | |
126 | struct hsr_port *port; | |
127 | ||
128 | hsr_for_each_port(hsr, port) | |
129 | if (port->type == pt) | |
130 | return port; | |
131 | return NULL; | |
132 | } | |
133 | ||
dcf0cd1c GM |
134 | int hsr_get_version(struct net_device *dev, enum hsr_version *ver) |
135 | { | |
136 | struct hsr_priv *hsr; | |
137 | ||
138 | hsr = netdev_priv(dev); | |
139 | *ver = hsr->prot_version; | |
140 | ||
141 | return 0; | |
142 | } | |
143 | EXPORT_SYMBOL(hsr_get_version); | |
144 | ||
f421436a AB |
145 | static struct notifier_block hsr_nb = { |
146 | .notifier_call = hsr_netdev_notify, /* Slave event notifications */ | |
147 | }; | |
148 | ||
f421436a AB |
149 | static int __init hsr_init(void) |
150 | { | |
151 | int res; | |
152 | ||
70ebe4a4 | 153 | BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); |
f421436a | 154 | |
f421436a | 155 | register_netdevice_notifier(&hsr_nb); |
f421436a AB |
156 | res = hsr_netlink_init(); |
157 | ||
158 | return res; | |
159 | } | |
160 | ||
161 | static void __exit hsr_exit(void) | |
162 | { | |
f421436a | 163 | hsr_netlink_exit(); |
c6c4ccd7 | 164 | hsr_debugfs_remove_root(); |
de0083c7 | 165 | unregister_netdevice_notifier(&hsr_nb); |
f421436a AB |
166 | } |
167 | ||
168 | module_init(hsr_init); | |
169 | module_exit(hsr_exit); | |
170 | MODULE_LICENSE("GPL"); |