~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/hsr/hsr_slave.c

Version: ~ [ linux-5.11 ] ~ [ linux-5.10.17 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.99 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.176 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.221 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.257 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.257 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* 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  *
  8  * Author(s):
  9  *      2011-2014 Arvid Brodin, arvid.brodin@alten.se
 10  */
 11 
 12 #include "hsr_slave.h"
 13 #include <linux/etherdevice.h>
 14 #include <linux/if_arp.h>
 15 #include "hsr_main.h"
 16 #include "hsr_device.h"
 17 #include "hsr_forward.h"
 18 #include "hsr_framereg.h"
 19 
 20 
 21 static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
 22 {
 23         struct sk_buff *skb = *pskb;
 24         struct hsr_port *port;
 25         u16 protocol;
 26 
 27         if (!skb_mac_header_was_set(skb)) {
 28                 WARN_ONCE(1, "%s: skb invalid", __func__);
 29                 return RX_HANDLER_PASS;
 30         }
 31 
 32         rcu_read_lock(); /* hsr->node_db, hsr->ports */
 33         port = hsr_port_get_rcu(skb->dev);
 34 
 35         if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) {
 36                 /* Directly kill frames sent by ourselves */
 37                 kfree_skb(skb);
 38                 goto finish_consume;
 39         }
 40 
 41         protocol = eth_hdr(skb)->h_proto;
 42         if (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR))
 43                 goto finish_pass;
 44 
 45         skb_push(skb, ETH_HLEN);
 46 
 47         hsr_forward_skb(skb, port);
 48 
 49 finish_consume:
 50         rcu_read_unlock(); /* hsr->node_db, hsr->ports */
 51         return RX_HANDLER_CONSUMED;
 52 
 53 finish_pass:
 54         rcu_read_unlock(); /* hsr->node_db, hsr->ports */
 55         return RX_HANDLER_PASS;
 56 }
 57 
 58 bool hsr_port_exists(const struct net_device *dev)
 59 {
 60         return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame;
 61 }
 62 
 63 
 64 static int hsr_check_dev_ok(struct net_device *dev)
 65 {
 66         /* Don't allow HSR on non-ethernet like devices */
 67         if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) ||
 68             (dev->addr_len != ETH_ALEN)) {
 69                 netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
 70                 return -EINVAL;
 71         }
 72 
 73         /* Don't allow enslaving hsr devices */
 74         if (is_hsr_master(dev)) {
 75                 netdev_info(dev, "Cannot create trees of HSR devices.\n");
 76                 return -EINVAL;
 77         }
 78 
 79         if (hsr_port_exists(dev)) {
 80                 netdev_info(dev, "This device is already a HSR slave.\n");
 81                 return -EINVAL;
 82         }
 83 
 84         if (dev->priv_flags & IFF_802_1Q_VLAN) {
 85                 netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n");
 86                 return -EINVAL;
 87         }
 88 
 89         if (dev->priv_flags & IFF_DONT_BRIDGE) {
 90                 netdev_info(dev, "This device does not support bridging.\n");
 91                 return -EOPNOTSUPP;
 92         }
 93 
 94         /* HSR over bonded devices has not been tested, but I'm not sure it
 95          * won't work...
 96          */
 97 
 98         return 0;
 99 }
100 
101 
102 /* Setup device to be added to the HSR bridge. */
103 static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port)
104 {
105         int res;
106 
107         dev_hold(dev);
108         res = dev_set_promiscuity(dev, 1);
109         if (res)
110                 goto fail_promiscuity;
111 
112         /* FIXME:
113          * What does net device "adjacency" mean? Should we do
114          * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ?
115          */
116 
117         res = netdev_rx_handler_register(dev, hsr_handle_frame, port);
118         if (res)
119                 goto fail_rx_handler;
120         dev_disable_lro(dev);
121 
122         return 0;
123 
124 fail_rx_handler:
125         dev_set_promiscuity(dev, -1);
126 fail_promiscuity:
127         dev_put(dev);
128 
129         return res;
130 }
131 
132 int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
133                  enum hsr_port_type type)
134 {
135         struct hsr_port *port, *master;
136         int res;
137 
138         if (type != HSR_PT_MASTER) {
139                 res = hsr_check_dev_ok(dev);
140                 if (res)
141                         return res;
142         }
143 
144         port = hsr_port_get_hsr(hsr, type);
145         if (port != NULL)
146                 return -EBUSY;  /* This port already exists */
147 
148         port = kzalloc(sizeof(*port), GFP_KERNEL);
149         if (port == NULL)
150                 return -ENOMEM;
151 
152         if (type != HSR_PT_MASTER) {
153                 res = hsr_portdev_setup(dev, port);
154                 if (res)
155                         goto fail_dev_setup;
156         }
157 
158         port->hsr = hsr;
159         port->dev = dev;
160         port->type = type;
161 
162         list_add_tail_rcu(&port->port_list, &hsr->ports);
163         synchronize_rcu();
164 
165         master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
166         netdev_update_features(master->dev);
167         dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
168 
169         return 0;
170 
171 fail_dev_setup:
172         kfree(port);
173         return res;
174 }
175 
176 void hsr_del_port(struct hsr_port *port)
177 {
178         struct hsr_priv *hsr;
179         struct hsr_port *master;
180 
181         hsr = port->hsr;
182         master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
183         list_del_rcu(&port->port_list);
184 
185         if (port != master) {
186                 if (master != NULL) {
187                         netdev_update_features(master->dev);
188                         dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
189                 }
190                 netdev_rx_handler_unregister(port->dev);
191                 dev_set_promiscuity(port->dev, -1);
192         }
193 
194         /* FIXME?
195          * netdev_upper_dev_unlink(port->dev, port->hsr->dev);
196          */
197 
198         synchronize_rcu();
199 
200         if (port != master)
201                 dev_put(port->dev);
202 }
203 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp