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.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 18b245e2c00e..c03d2c3ff03e 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -147,14 +147,17 @@ static void del_nbp(struct net_bridge_port *p)
147 147
148 list_del_rcu(&p->list); 148 list_del_rcu(&p->list);
149 149
150 rcu_assign_pointer(dev->br_port, NULL); 150 dev->priv_flags &= ~IFF_BRIDGE_PORT;
151
152 netdev_rx_handler_unregister(dev);
151 153
152 br_multicast_del_port(p); 154 br_multicast_del_port(p);
153 155
154 kobject_uevent(&p->kobj, KOBJ_REMOVE); 156 kobject_uevent(&p->kobj, KOBJ_REMOVE);
155 kobject_del(&p->kobj); 157 kobject_del(&p->kobj);
156 158
157 br_netpoll_disable(br, dev); 159 br_netpoll_disable(p);
160
158 call_rcu(&p->rcu, destroy_nbp_rcu); 161 call_rcu(&p->rcu, destroy_nbp_rcu);
159} 162}
160 163
@@ -167,8 +170,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
167 del_nbp(p); 170 del_nbp(p);
168 } 171 }
169 172
170 br_netpoll_cleanup(br->dev);
171
172 del_timer_sync(&br->gc_timer); 173 del_timer_sync(&br->gc_timer);
173 174
174 br_sysfs_delbr(br->dev); 175 br_sysfs_delbr(br->dev);
@@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
400 return -ELOOP; 401 return -ELOOP;
401 402
402 /* Device is already being bridged */ 403 /* Device is already being bridged */
403 if (dev->br_port != NULL) 404 if (br_port_exists(dev))
404 return -EBUSY; 405 return -EBUSY;
405 406
406 /* No bridging devices that dislike that (e.g. wireless) */ 407 /* No bridging devices that dislike that (e.g. wireless) */
@@ -428,7 +429,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
428 if (err) 429 if (err)
429 goto err2; 430 goto err2;
430 431
431 rcu_assign_pointer(dev->br_port, p); 432 if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
433 goto err3;
434
435 err = netdev_rx_handler_register(dev, br_handle_frame, p);
436 if (err)
437 goto err3;
438
439 dev->priv_flags |= IFF_BRIDGE_PORT;
440
432 dev_disable_lro(dev); 441 dev_disable_lro(dev);
433 442
434 list_add_rcu(&p->list, &br->port_list); 443 list_add_rcu(&p->list, &br->port_list);
@@ -448,9 +457,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
448 457
449 kobject_uevent(&p->kobj, KOBJ_ADD); 458 kobject_uevent(&p->kobj, KOBJ_ADD);
450 459
451 br_netpoll_enable(br, dev);
452
453 return 0; 460 return 0;
461err3:
462 sysfs_remove_link(br->ifobj, p->dev->name);
454err2: 463err2:
455 br_fdb_delete_by_port(br, p, 1); 464 br_fdb_delete_by_port(br, p, 1);
456err1: 465err1:
@@ -467,9 +476,13 @@ put_back:
467/* called with RTNL */ 476/* called with RTNL */
468int br_del_if(struct net_bridge *br, struct net_device *dev) 477int br_del_if(struct net_bridge *br, struct net_device *dev)
469{ 478{
470 struct net_bridge_port *p = dev->br_port; 479 struct net_bridge_port *p;
480
481 if (!br_port_exists(dev))
482 return -EINVAL;
471 483
472 if (!p || p->br != br) 484 p = br_port_get(dev);
485 if (p->br != br)
473 return -EINVAL; 486 return -EINVAL;
474 487
475 del_nbp(p); 488 del_nbp(p);