.. | .. |
---|
| 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 | + * Frame handler other utility functions for HSR and PRP. |
---|
10 | 8 | */ |
---|
11 | 9 | |
---|
12 | 10 | #include "hsr_slave.h" |
---|
.. | .. |
---|
18 | 16 | #include "hsr_forward.h" |
---|
19 | 17 | #include "hsr_framereg.h" |
---|
20 | 18 | |
---|
| 19 | +bool hsr_invalid_dan_ingress_frame(__be16 protocol) |
---|
| 20 | +{ |
---|
| 21 | + return (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR)); |
---|
| 22 | +} |
---|
21 | 23 | |
---|
22 | 24 | static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) |
---|
23 | 25 | { |
---|
24 | 26 | struct sk_buff *skb = *pskb; |
---|
25 | 27 | struct hsr_port *port; |
---|
26 | | - u16 protocol; |
---|
| 28 | + struct hsr_priv *hsr; |
---|
| 29 | + __be16 protocol; |
---|
| 30 | + |
---|
| 31 | + /* Packets from dev_loopback_xmit() do not have L2 header, bail out */ |
---|
| 32 | + if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) |
---|
| 33 | + return RX_HANDLER_PASS; |
---|
27 | 34 | |
---|
28 | 35 | if (!skb_mac_header_was_set(skb)) { |
---|
29 | 36 | WARN_ONCE(1, "%s: skb invalid", __func__); |
---|
30 | 37 | return RX_HANDLER_PASS; |
---|
31 | 38 | } |
---|
32 | 39 | |
---|
33 | | - rcu_read_lock(); /* hsr->node_db, hsr->ports */ |
---|
34 | 40 | port = hsr_port_get_rcu(skb->dev); |
---|
35 | 41 | if (!port) |
---|
36 | 42 | goto finish_pass; |
---|
| 43 | + hsr = port->hsr; |
---|
37 | 44 | |
---|
38 | 45 | if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) { |
---|
39 | 46 | /* Directly kill frames sent by ourselves */ |
---|
.. | .. |
---|
41 | 48 | goto finish_consume; |
---|
42 | 49 | } |
---|
43 | 50 | |
---|
| 51 | + /* For HSR, only tagged frames are expected, but for PRP |
---|
| 52 | + * there could be non tagged frames as well from Single |
---|
| 53 | + * attached nodes (SANs). |
---|
| 54 | + */ |
---|
44 | 55 | protocol = eth_hdr(skb)->h_proto; |
---|
45 | | - if (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR)) |
---|
| 56 | + if (hsr->proto_ops->invalid_dan_ingress_frame && |
---|
| 57 | + hsr->proto_ops->invalid_dan_ingress_frame(protocol)) |
---|
46 | 58 | goto finish_pass; |
---|
47 | 59 | |
---|
48 | 60 | skb_push(skb, ETH_HLEN); |
---|
| 61 | + skb_reset_mac_header(skb); |
---|
| 62 | + if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) || |
---|
| 63 | + protocol == htons(ETH_P_HSR)) |
---|
| 64 | + skb_set_network_header(skb, ETH_HLEN + HSR_HLEN); |
---|
| 65 | + skb_reset_mac_len(skb); |
---|
49 | 66 | |
---|
50 | 67 | hsr_forward_skb(skb, port); |
---|
51 | 68 | |
---|
52 | 69 | finish_consume: |
---|
53 | | - rcu_read_unlock(); /* hsr->node_db, hsr->ports */ |
---|
54 | 70 | return RX_HANDLER_CONSUMED; |
---|
55 | 71 | |
---|
56 | 72 | finish_pass: |
---|
57 | | - rcu_read_unlock(); /* hsr->node_db, hsr->ports */ |
---|
58 | 73 | return RX_HANDLER_PASS; |
---|
59 | 74 | } |
---|
60 | 75 | |
---|
.. | .. |
---|
63 | 78 | return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame; |
---|
64 | 79 | } |
---|
65 | 80 | |
---|
66 | | - |
---|
67 | | -static int hsr_check_dev_ok(struct net_device *dev) |
---|
| 81 | +static int hsr_check_dev_ok(struct net_device *dev, |
---|
| 82 | + struct netlink_ext_ack *extack) |
---|
68 | 83 | { |
---|
69 | 84 | /* Don't allow HSR on non-ethernet like devices */ |
---|
70 | | - if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || |
---|
71 | | - (dev->addr_len != ETH_ALEN)) { |
---|
72 | | - netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n"); |
---|
| 85 | + if ((dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || |
---|
| 86 | + dev->addr_len != ETH_ALEN) { |
---|
| 87 | + NL_SET_ERR_MSG_MOD(extack, "Cannot use loopback or non-ethernet device as HSR slave."); |
---|
73 | 88 | return -EINVAL; |
---|
74 | 89 | } |
---|
75 | 90 | |
---|
76 | 91 | /* Don't allow enslaving hsr devices */ |
---|
77 | 92 | if (is_hsr_master(dev)) { |
---|
78 | | - netdev_info(dev, "Cannot create trees of HSR devices.\n"); |
---|
| 93 | + NL_SET_ERR_MSG_MOD(extack, |
---|
| 94 | + "Cannot create trees of HSR devices."); |
---|
79 | 95 | return -EINVAL; |
---|
80 | 96 | } |
---|
81 | 97 | |
---|
82 | 98 | if (hsr_port_exists(dev)) { |
---|
83 | | - netdev_info(dev, "This device is already a HSR slave.\n"); |
---|
| 99 | + NL_SET_ERR_MSG_MOD(extack, |
---|
| 100 | + "This device is already a HSR slave."); |
---|
84 | 101 | return -EINVAL; |
---|
85 | 102 | } |
---|
86 | 103 | |
---|
87 | 104 | if (is_vlan_dev(dev)) { |
---|
88 | | - netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n"); |
---|
| 105 | + NL_SET_ERR_MSG_MOD(extack, "HSR on top of VLAN is not yet supported in this driver."); |
---|
89 | 106 | return -EINVAL; |
---|
90 | 107 | } |
---|
91 | 108 | |
---|
92 | 109 | if (dev->priv_flags & IFF_DONT_BRIDGE) { |
---|
93 | | - netdev_info(dev, "This device does not support bridging.\n"); |
---|
| 110 | + NL_SET_ERR_MSG_MOD(extack, |
---|
| 111 | + "This device does not support bridging."); |
---|
94 | 112 | return -EOPNOTSUPP; |
---|
95 | 113 | } |
---|
96 | 114 | |
---|
.. | .. |
---|
101 | 119 | return 0; |
---|
102 | 120 | } |
---|
103 | 121 | |
---|
104 | | - |
---|
105 | 122 | /* Setup device to be added to the HSR bridge. */ |
---|
106 | | -static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) |
---|
| 123 | +static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, |
---|
| 124 | + struct hsr_port *port, |
---|
| 125 | + struct netlink_ext_ack *extack) |
---|
| 126 | + |
---|
107 | 127 | { |
---|
| 128 | + struct net_device *hsr_dev; |
---|
| 129 | + struct hsr_port *master; |
---|
108 | 130 | int res; |
---|
109 | 131 | |
---|
110 | | - dev_hold(dev); |
---|
111 | 132 | res = dev_set_promiscuity(dev, 1); |
---|
112 | 133 | if (res) |
---|
113 | | - goto fail_promiscuity; |
---|
| 134 | + return res; |
---|
114 | 135 | |
---|
115 | | - /* FIXME: |
---|
116 | | - * What does net device "adjacency" mean? Should we do |
---|
117 | | - * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ? |
---|
118 | | - */ |
---|
| 136 | + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
---|
| 137 | + hsr_dev = master->dev; |
---|
| 138 | + |
---|
| 139 | + res = netdev_upper_dev_link(dev, hsr_dev, extack); |
---|
| 140 | + if (res) |
---|
| 141 | + goto fail_upper_dev_link; |
---|
119 | 142 | |
---|
120 | 143 | res = netdev_rx_handler_register(dev, hsr_handle_frame, port); |
---|
121 | 144 | if (res) |
---|
.. | .. |
---|
125 | 148 | return 0; |
---|
126 | 149 | |
---|
127 | 150 | fail_rx_handler: |
---|
| 151 | + netdev_upper_dev_unlink(dev, hsr_dev); |
---|
| 152 | +fail_upper_dev_link: |
---|
128 | 153 | dev_set_promiscuity(dev, -1); |
---|
129 | | -fail_promiscuity: |
---|
130 | | - dev_put(dev); |
---|
131 | | - |
---|
132 | 154 | return res; |
---|
133 | 155 | } |
---|
134 | 156 | |
---|
135 | 157 | int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, |
---|
136 | | - enum hsr_port_type type) |
---|
| 158 | + enum hsr_port_type type, struct netlink_ext_ack *extack) |
---|
137 | 159 | { |
---|
138 | 160 | struct hsr_port *port, *master; |
---|
139 | 161 | int res; |
---|
140 | 162 | |
---|
141 | 163 | if (type != HSR_PT_MASTER) { |
---|
142 | | - res = hsr_check_dev_ok(dev); |
---|
| 164 | + res = hsr_check_dev_ok(dev, extack); |
---|
143 | 165 | if (res) |
---|
144 | 166 | return res; |
---|
145 | 167 | } |
---|
146 | 168 | |
---|
147 | 169 | port = hsr_port_get_hsr(hsr, type); |
---|
148 | | - if (port != NULL) |
---|
| 170 | + if (port) |
---|
149 | 171 | return -EBUSY; /* This port already exists */ |
---|
150 | 172 | |
---|
151 | 173 | port = kzalloc(sizeof(*port), GFP_KERNEL); |
---|
152 | | - if (port == NULL) |
---|
| 174 | + if (!port) |
---|
153 | 175 | return -ENOMEM; |
---|
154 | 176 | |
---|
155 | 177 | port->hsr = hsr; |
---|
.. | .. |
---|
157 | 179 | port->type = type; |
---|
158 | 180 | |
---|
159 | 181 | if (type != HSR_PT_MASTER) { |
---|
160 | | - res = hsr_portdev_setup(dev, port); |
---|
| 182 | + res = hsr_portdev_setup(hsr, dev, port, extack); |
---|
161 | 183 | if (res) |
---|
162 | 184 | goto fail_dev_setup; |
---|
163 | 185 | } |
---|
.. | .. |
---|
186 | 208 | list_del_rcu(&port->port_list); |
---|
187 | 209 | |
---|
188 | 210 | if (port != master) { |
---|
189 | | - if (master != NULL) { |
---|
190 | | - netdev_update_features(master->dev); |
---|
191 | | - dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); |
---|
192 | | - } |
---|
| 211 | + netdev_update_features(master->dev); |
---|
| 212 | + dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); |
---|
193 | 213 | netdev_rx_handler_unregister(port->dev); |
---|
194 | 214 | dev_set_promiscuity(port->dev, -1); |
---|
| 215 | + netdev_upper_dev_unlink(port->dev, master->dev); |
---|
195 | 216 | } |
---|
196 | | - |
---|
197 | | - /* FIXME? |
---|
198 | | - * netdev_upper_dev_unlink(port->dev, port->hsr->dev); |
---|
199 | | - */ |
---|
200 | 217 | |
---|
201 | 218 | synchronize_rcu(); |
---|
202 | 219 | |
---|
203 | | - if (port != master) |
---|
204 | | - dev_put(port->dev); |
---|
| 220 | + kfree(port); |
---|
205 | 221 | } |
---|