diff options
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 4a9f52732655..0b6b1f2ff7ac 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
21 | #include <linux/if_ether.h> | 21 | #include <linux/if_ether.h> |
22 | #include <linux/slab.h> | ||
22 | #include <net/sock.h> | 23 | #include <net/sock.h> |
23 | 24 | ||
24 | #include "br_private.h" | 25 | #include "br_private.h" |
@@ -147,6 +148,8 @@ static void del_nbp(struct net_bridge_port *p) | |||
147 | 148 | ||
148 | rcu_assign_pointer(dev->br_port, NULL); | 149 | rcu_assign_pointer(dev->br_port, NULL); |
149 | 150 | ||
151 | br_multicast_del_port(p); | ||
152 | |||
150 | kobject_uevent(&p->kobj, KOBJ_REMOVE); | 153 | kobject_uevent(&p->kobj, KOBJ_REMOVE); |
151 | kobject_del(&p->kobj); | 154 | kobject_del(&p->kobj); |
152 | 155 | ||
@@ -154,7 +157,7 @@ static void del_nbp(struct net_bridge_port *p) | |||
154 | } | 157 | } |
155 | 158 | ||
156 | /* called with RTNL */ | 159 | /* called with RTNL */ |
157 | static void del_br(struct net_bridge *br) | 160 | static void del_br(struct net_bridge *br, struct list_head *head) |
158 | { | 161 | { |
159 | struct net_bridge_port *p, *n; | 162 | struct net_bridge_port *p, *n; |
160 | 163 | ||
@@ -165,7 +168,7 @@ static void del_br(struct net_bridge *br) | |||
165 | del_timer_sync(&br->gc_timer); | 168 | del_timer_sync(&br->gc_timer); |
166 | 169 | ||
167 | br_sysfs_delbr(br->dev); | 170 | br_sysfs_delbr(br->dev); |
168 | unregister_netdevice(br->dev); | 171 | unregister_netdevice_queue(br->dev, head); |
169 | } | 172 | } |
170 | 173 | ||
171 | static struct net_device *new_bridge_dev(struct net *net, const char *name) | 174 | static struct net_device *new_bridge_dev(struct net *net, const char *name) |
@@ -206,9 +209,8 @@ static struct net_device *new_bridge_dev(struct net *net, const char *name) | |||
206 | 209 | ||
207 | br_netfilter_rtable_init(br); | 210 | br_netfilter_rtable_init(br); |
208 | 211 | ||
209 | INIT_LIST_HEAD(&br->age_list); | ||
210 | |||
211 | br_stp_timer_init(br); | 212 | br_stp_timer_init(br); |
213 | br_multicast_init(br); | ||
212 | 214 | ||
213 | return dev; | 215 | return dev; |
214 | } | 216 | } |
@@ -260,6 +262,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
260 | br_init_port(p); | 262 | br_init_port(p); |
261 | p->state = BR_STATE_DISABLED; | 263 | p->state = BR_STATE_DISABLED; |
262 | br_stp_port_timer_init(p); | 264 | br_stp_port_timer_init(p); |
265 | br_multicast_add_port(p); | ||
263 | 266 | ||
264 | return p; | 267 | return p; |
265 | } | 268 | } |
@@ -323,7 +326,7 @@ int br_del_bridge(struct net *net, const char *name) | |||
323 | } | 326 | } |
324 | 327 | ||
325 | else | 328 | else |
326 | del_br(netdev_priv(dev)); | 329 | del_br(netdev_priv(dev), NULL); |
327 | 330 | ||
328 | rtnl_unlock(); | 331 | rtnl_unlock(); |
329 | return ret; | 332 | return ret; |
@@ -390,6 +393,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
390 | if (dev->br_port != NULL) | 393 | if (dev->br_port != NULL) |
391 | return -EBUSY; | 394 | return -EBUSY; |
392 | 395 | ||
396 | /* No bridging devices that dislike that (e.g. wireless) */ | ||
397 | if (dev->priv_flags & IFF_DONT_BRIDGE) | ||
398 | return -EOPNOTSUPP; | ||
399 | |||
393 | p = new_nbp(br, dev); | 400 | p = new_nbp(br, dev); |
394 | if (IS_ERR(p)) | 401 | if (IS_ERR(p)) |
395 | return PTR_ERR(p); | 402 | return PTR_ERR(p); |
@@ -463,18 +470,17 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) | |||
463 | return 0; | 470 | return 0; |
464 | } | 471 | } |
465 | 472 | ||
466 | void br_net_exit(struct net *net) | 473 | void __net_exit br_net_exit(struct net *net) |
467 | { | 474 | { |
468 | struct net_device *dev; | 475 | struct net_device *dev; |
476 | LIST_HEAD(list); | ||
469 | 477 | ||
470 | rtnl_lock(); | 478 | rtnl_lock(); |
471 | restart: | 479 | for_each_netdev(net, dev) |
472 | for_each_netdev(net, dev) { | 480 | if (dev->priv_flags & IFF_EBRIDGE) |
473 | if (dev->priv_flags & IFF_EBRIDGE) { | 481 | del_br(netdev_priv(dev), &list); |
474 | del_br(netdev_priv(dev)); | 482 | |
475 | goto restart; | 483 | unregister_netdevice_many(&list); |
476 | } | ||
477 | } | ||
478 | rtnl_unlock(); | 484 | rtnl_unlock(); |
479 | 485 | ||
480 | } | 486 | } |