aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-06-10 12:12:50 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-15 14:00:40 -0400
commit91d2c34a4eed32876ca333b0ca44f3bc56645805 (patch)
tree26799e5cb1dff486a0695e1be8618064d12fe0bd /net/bridge/br_if.c
parentc18370f5b2949d9cca519355f33690b75e1e7c8b (diff)
bridge: Fix netpoll support
There are multiple problems with the newly added netpoll support: 1) Use-after-free on each netpoll packet. 2) Invoking unsafe code on netpoll/IRQ path. 3) Breaks when netpoll is enabled on the underlying device. This patch fixes all of these problems. In particular, we now allocate proper netpoll structures for each underlying device. We only allow netpoll to be enabled on the bridge when all the devices underneath it support netpoll. Once it is enabled, we do not allow non-netpoll devices to join the bridge (until netpoll is disabled again). This allows us to do away with the npinfo juggling that caused problem number 1. Incidentally this patch fixes number 2 by bypassing unsafe code such as multicast snooping and netfilter. Reported-by: Qianfeng Zhang <frzhang@redhat.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r--net/bridge/br_if.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index d9242342837e..97ac9da4d76c 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -155,7 +155,8 @@ static void del_nbp(struct net_bridge_port *p)
155 kobject_uevent(&p->kobj, KOBJ_REMOVE); 155 kobject_uevent(&p->kobj, KOBJ_REMOVE);
156 kobject_del(&p->kobj); 156 kobject_del(&p->kobj);
157 157
158 br_netpoll_disable(br, dev); 158 br_netpoll_disable(p);
159
159 call_rcu(&p->rcu, destroy_nbp_rcu); 160 call_rcu(&p->rcu, destroy_nbp_rcu);
160} 161}
161 162
@@ -168,8 +169,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
168 del_nbp(p); 169 del_nbp(p);
169 } 170 }
170 171
171 br_netpoll_cleanup(br->dev);
172
173 del_timer_sync(&br->gc_timer); 172 del_timer_sync(&br->gc_timer);
174 173
175 br_sysfs_delbr(br->dev); 174 br_sysfs_delbr(br->dev);
@@ -429,11 +428,14 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
429 if (err) 428 if (err)
430 goto err2; 429 goto err2;
431 430
431 if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
432 goto err3;
433
432 rcu_assign_pointer(dev->br_port, p); 434 rcu_assign_pointer(dev->br_port, p);
433 435
434 err = netdev_rx_handler_register(dev, br_handle_frame); 436 err = netdev_rx_handler_register(dev, br_handle_frame);
435 if (err) 437 if (err)
436 goto err3; 438 goto err4;
437 439
438 dev_disable_lro(dev); 440 dev_disable_lro(dev);
439 441
@@ -454,11 +456,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
454 456
455 kobject_uevent(&p->kobj, KOBJ_ADD); 457 kobject_uevent(&p->kobj, KOBJ_ADD);
456 458
457 br_netpoll_enable(br, dev);
458
459 return 0; 459 return 0;
460err3: 460err4:
461 rcu_assign_pointer(dev->br_port, NULL); 461 rcu_assign_pointer(dev->br_port, NULL);
462err3:
463 sysfs_remove_link(br->ifobj, p->dev->name);
462err2: 464err2:
463 br_fdb_delete_by_port(br, p, 1); 465 br_fdb_delete_by_port(br, p, 1);
464err1: 466err1: