]>
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, arvid.brodin@alten.se |
f421436a AB |
6 | */ |
7 | ||
8 | #include <linux/netdevice.h> | |
9 | #include <linux/rculist.h> | |
10 | #include <linux/timer.h> | |
11 | #include <linux/etherdevice.h> | |
12 | #include "hsr_main.h" | |
13 | #include "hsr_device.h" | |
14 | #include "hsr_netlink.h" | |
15 | #include "hsr_framereg.h" | |
51f3c605 | 16 | #include "hsr_slave.h" |
f421436a | 17 | |
f421436a AB |
18 | static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, |
19 | void *ptr) | |
20 | { | |
c5a75911 AB |
21 | struct net_device *dev; |
22 | struct hsr_port *port, *master; | |
70ebe4a4 | 23 | struct hsr_priv *hsr; |
f421436a AB |
24 | int mtu_max; |
25 | int res; | |
f421436a AB |
26 | |
27 | dev = netdev_notifier_info_to_dev(ptr); | |
c5a75911 | 28 | port = hsr_port_get_rtnl(dev); |
05ca6e64 | 29 | if (!port) { |
f421436a | 30 | if (!is_hsr_master(dev)) |
c5a75911 | 31 | return NOTIFY_DONE; /* Not an HSR device */ |
70ebe4a4 | 32 | hsr = netdev_priv(dev); |
c5a75911 | 33 | port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
05ca6e64 | 34 | if (!port) { |
56b08fdc AB |
35 | /* Resend of notification concerning removed device? */ |
36 | return NOTIFY_DONE; | |
37 | } | |
c5a75911 AB |
38 | } else { |
39 | hsr = port->hsr; | |
f421436a AB |
40 | } |
41 | ||
42 | switch (event) { | |
43 | case NETDEV_UP: /* Administrative state DOWN */ | |
44 | case NETDEV_DOWN: /* Administrative state UP */ | |
45 | case NETDEV_CHANGE: /* Link (carrier) state changes */ | |
e9aae56e | 46 | hsr_check_carrier_and_operstate(hsr); |
f421436a | 47 | break; |
4c2d5e33 | 48 | case NETDEV_CHANGENAME: |
04b69426 TY |
49 | if (is_hsr_master(dev)) |
50 | hsr_debugfs_rename(dev); | |
4c2d5e33 | 51 | break; |
f421436a | 52 | case NETDEV_CHANGEADDR: |
c5a75911 AB |
53 | if (port->type == HSR_PT_MASTER) { |
54 | /* This should not happen since there's no | |
55 | * ndo_set_mac_address() for HSR devices - i.e. not | |
56 | * supported. | |
57 | */ | |
f421436a | 58 | break; |
c5a75911 | 59 | } |
f421436a | 60 | |
c5a75911 AB |
61 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
62 | ||
63 | if (port->type == HSR_PT_SLAVE_A) { | |
64 | ether_addr_copy(master->dev->dev_addr, dev->dev_addr); | |
d595b85a MK |
65 | call_netdevice_notifiers(NETDEV_CHANGEADDR, |
66 | master->dev); | |
51f3c605 | 67 | } |
f421436a AB |
68 | |
69 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ | |
c5a75911 | 70 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
92a35678 | 71 | res = hsr_create_self_node(hsr, |
c5a75911 AB |
72 | master->dev->dev_addr, |
73 | port ? | |
74 | port->dev->dev_addr : | |
75 | master->dev->dev_addr); | |
f421436a | 76 | if (res) |
c5a75911 | 77 | netdev_warn(master->dev, |
f421436a | 78 | "Could not update HSR node address.\n"); |
f421436a AB |
79 | break; |
80 | case NETDEV_CHANGEMTU: | |
c5a75911 | 81 | if (port->type == HSR_PT_MASTER) |
f421436a | 82 | break; /* Handled in ndo_change_mtu() */ |
c5a75911 AB |
83 | mtu_max = hsr_get_max_mtu(port->hsr); |
84 | master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); | |
85 | master->dev->mtu = mtu_max; | |
f421436a AB |
86 | break; |
87 | case NETDEV_UNREGISTER: | |
e0a4b997 TY |
88 | if (!is_hsr_master(dev)) |
89 | hsr_del_port(port); | |
f421436a AB |
90 | break; |
91 | case NETDEV_PRE_TYPE_CHANGE: | |
92 | /* HSR works only on Ethernet devices. Refuse slave to change | |
93 | * its type. | |
94 | */ | |
95 | return NOTIFY_BAD; | |
96 | } | |
97 | ||
98 | return NOTIFY_DONE; | |
99 | } | |
100 | ||
c5a75911 AB |
101 | struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) |
102 | { | |
103 | struct hsr_port *port; | |
104 | ||
105 | hsr_for_each_port(hsr, port) | |
106 | if (port->type == pt) | |
107 | return port; | |
108 | return NULL; | |
109 | } | |
110 | ||
f421436a AB |
111 | static struct notifier_block hsr_nb = { |
112 | .notifier_call = hsr_netdev_notify, /* Slave event notifications */ | |
113 | }; | |
114 | ||
f421436a AB |
115 | static int __init hsr_init(void) |
116 | { | |
117 | int res; | |
118 | ||
70ebe4a4 | 119 | BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); |
f421436a | 120 | |
f421436a | 121 | register_netdevice_notifier(&hsr_nb); |
f421436a AB |
122 | res = hsr_netlink_init(); |
123 | ||
124 | return res; | |
125 | } | |
126 | ||
127 | static void __exit hsr_exit(void) | |
128 | { | |
129 | unregister_netdevice_notifier(&hsr_nb); | |
f421436a | 130 | hsr_netlink_exit(); |
c6c4ccd7 | 131 | hsr_debugfs_remove_root(); |
f421436a AB |
132 | } |
133 | ||
134 | module_init(hsr_init); | |
135 | module_exit(hsr_exit); | |
136 | MODULE_LICENSE("GPL"); |