diff options
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 33 |
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; |
461 | err3: | ||
462 | sysfs_remove_link(br->ifobj, p->dev->name); | ||
454 | err2: | 463 | err2: |
455 | br_fdb_delete_by_port(br, p, 1); | 464 | br_fdb_delete_by_port(br, p, 1); |
456 | err1: | 465 | err1: |
@@ -467,9 +476,13 @@ put_back: | |||
467 | /* called with RTNL */ | 476 | /* called with RTNL */ |
468 | int br_del_if(struct net_bridge *br, struct net_device *dev) | 477 | int 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); |