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); |
