aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r--net/bridge/br_if.c32
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 */
157static void del_br(struct net_bridge *br) 160static 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
171static struct net_device *new_bridge_dev(struct net *net, const char *name) 174static 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
466void br_net_exit(struct net *net) 473void __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();
471restart: 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}