aboutsummaryrefslogtreecommitdiffstats
path: root/net/hsr/hsr_slave.c
diff options
context:
space:
mode:
authorArvid Brodin <arvid.brodin@alten.se>2014-07-04 17:37:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-08 14:35:31 -0400
commit51f3c605318b056ac5deb9079bbef2a976558827 (patch)
tree892ae91481ed018ce84f70a9b1c49ee0972d9406 /net/hsr/hsr_slave.c
parente9aae56ea43ef4a32527b9d86c1f6b5eebfbd223 (diff)
net/hsr: Move slave init to hsr_slave.c.
Also try to prevent some possible slave dereference race conditions. This is finalized in the next patch, which abandons the slave array in favour of a list_head list and list RCU. Signed-off-by: Arvid Brodin <arvid.brodin@alten.se> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/hsr/hsr_slave.c')
-rw-r--r--net/hsr/hsr_slave.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index 702814631ee1..d676090f7900 100644
--- a/net/hsr/hsr_slave.c
+++ b/net/hsr/hsr_slave.c
@@ -11,10 +11,45 @@
11 11
12#include "hsr_slave.h" 12#include "hsr_slave.h"
13#include <linux/etherdevice.h> 13#include <linux/etherdevice.h>
14#include <linux/if_arp.h>
14#include "hsr_main.h" 15#include "hsr_main.h"
16#include "hsr_device.h"
15#include "hsr_framereg.h" 17#include "hsr_framereg.h"
16 18
17 19
20static int check_slave_ok(struct net_device *dev)
21{
22 /* Don't allow HSR on non-ethernet like devices */
23 if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) ||
24 (dev->addr_len != ETH_ALEN)) {
25 netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
26 return -EINVAL;
27 }
28
29 /* Don't allow enslaving hsr devices */
30 if (is_hsr_master(dev)) {
31 netdev_info(dev, "Cannot create trees of HSR devices.\n");
32 return -EINVAL;
33 }
34
35 if (is_hsr_slave(dev)) {
36 netdev_info(dev, "This device is already a HSR slave.\n");
37 return -EINVAL;
38 }
39
40 if (dev->priv_flags & IFF_802_1Q_VLAN) {
41 netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n");
42 return -EINVAL;
43 }
44
45 /* HSR over bonded devices has not been tested, but I'm not sure it
46 * won't work...
47 */
48
49 return 0;
50}
51
52
18static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) 53static struct sk_buff *hsr_pull_tag(struct sk_buff *skb)
19{ 54{
20 struct hsr_tag *hsr_tag; 55 struct hsr_tag *hsr_tag;
@@ -241,3 +276,59 @@ forward:
241 276
242 return RX_HANDLER_CONSUMED; 277 return RX_HANDLER_CONSUMED;
243} 278}
279
280int hsr_add_slave(struct hsr_priv *hsr, struct net_device *dev, int idx)
281{
282 int res;
283
284 dev_hold(dev);
285
286 res = check_slave_ok(dev);
287 if (res)
288 goto fail;
289
290 res = dev_set_promiscuity(dev, 1);
291 if (res)
292 goto fail;
293
294 res = netdev_rx_handler_register(dev, hsr_handle_frame, hsr);
295 if (res)
296 goto fail_rx_handler;
297
298
299 hsr->slave[idx] = dev;
300
301 /* Set required header length */
302 if (dev->hard_header_len + HSR_HLEN > hsr->dev->hard_header_len)
303 hsr->dev->hard_header_len = dev->hard_header_len + HSR_HLEN;
304
305 dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr));
306
307 return 0;
308
309fail_rx_handler:
310 dev_set_promiscuity(dev, -1);
311
312fail:
313 dev_put(dev);
314 return res;
315}
316
317void hsr_del_slave(struct hsr_priv *hsr, int idx)
318{
319 struct net_device *slave;
320
321 slave = hsr->slave[idx];
322 hsr->slave[idx] = NULL;
323
324 netdev_update_features(hsr->dev);
325 dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr));
326
327 if (slave) {
328 netdev_rx_handler_unregister(slave);
329 dev_set_promiscuity(slave, -1);
330 }
331
332 synchronize_rcu();
333 dev_put(slave);
334}