aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_if.c21
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/netfilter/ebt_ulog.c10
-rw-r--r--net/bridge/netfilter/ebtables.c7
4 files changed, 29 insertions, 10 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ba442883e877..da687c8dc6ff 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p)
104{ 104{
105 struct net_device *dev = p->dev; 105 struct net_device *dev = p->dev;
106 106
107 dev->br_port = NULL;
107 p->br = NULL; 108 p->br = NULL;
108 p->dev = NULL; 109 p->dev = NULL;
109 dev_put(dev); 110 dev_put(dev);
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head)
118 destroy_nbp(p); 119 destroy_nbp(p);
119} 120}
120 121
121/* called with RTNL */ 122/* Delete port(interface) from bridge is done in two steps.
123 * via RCU. First step, marks device as down. That deletes
124 * all the timers and stops new packets from flowing through.
125 *
126 * Final cleanup doesn't occur until after all CPU's finished
127 * processing packets.
128 *
129 * Protected from multiple admin operations by RTNL mutex
130 */
122static void del_nbp(struct net_bridge_port *p) 131static void del_nbp(struct net_bridge_port *p)
123{ 132{
124 struct net_bridge *br = p->br; 133 struct net_bridge *br = p->br;
125 struct net_device *dev = p->dev; 134 struct net_device *dev = p->dev;
126 135
127 dev->br_port = NULL; 136 /* Race between RTNL notify and RCU callback */
137 if (p->deleted)
138 return;
139
128 dev_set_promiscuity(dev, -1); 140 dev_set_promiscuity(dev, -1);
129 141
130 cancel_delayed_work(&p->carrier_check); 142 cancel_delayed_work(&p->carrier_check);
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p)
132 144
133 spin_lock_bh(&br->lock); 145 spin_lock_bh(&br->lock);
134 br_stp_disable_port(p); 146 br_stp_disable_port(p);
147 p->deleted = 1;
135 spin_unlock_bh(&br->lock); 148 spin_unlock_bh(&br->lock);
136 149
137 br_fdb_delete_by_port(br, p); 150 br_fdb_delete_by_port(br, p);
138 151
139 list_del_rcu(&p->list); 152 list_del_rcu(&p->list);
140 153
141 del_timer_sync(&p->message_age_timer);
142 del_timer_sync(&p->forward_delay_timer);
143 del_timer_sync(&p->hold_timer);
144
145 call_rcu(&p->rcu, destroy_nbp_rcu); 154 call_rcu(&p->rcu, destroy_nbp_rcu);
146} 155}
147 156
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c5bd631ffcd5..e330b17b6d81 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -68,6 +68,7 @@ struct net_bridge_port
68 /* STP */ 68 /* STP */
69 u8 priority; 69 u8 priority;
70 u8 state; 70 u8 state;
71 u8 deleted;
71 u16 port_no; 72 u16 port_no;
72 unsigned char topology_change_ack; 73 unsigned char topology_change_ack;
73 unsigned char config_pending; 74 unsigned char config_pending;
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ce617b3dbbb8..802baf755ef4 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -46,7 +46,7 @@
46#define PRINTR(format, args...) do { if (net_ratelimit()) \ 46#define PRINTR(format, args...) do { if (net_ratelimit()) \
47 printk(format , ## args); } while (0) 47 printk(format , ## args); } while (0)
48 48
49static unsigned int nlbufsiz = 4096; 49static unsigned int nlbufsiz = NLMSG_GOODSIZE;
50module_param(nlbufsiz, uint, 0600); 50module_param(nlbufsiz, uint, 0600);
51MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " 51MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
52 "(defaults to 4096)"); 52 "(defaults to 4096)");
@@ -98,12 +98,14 @@ static void ulog_timer(unsigned long data)
98static struct sk_buff *ulog_alloc_skb(unsigned int size) 98static struct sk_buff *ulog_alloc_skb(unsigned int size)
99{ 99{
100 struct sk_buff *skb; 100 struct sk_buff *skb;
101 unsigned int n;
101 102
102 skb = alloc_skb(nlbufsiz, GFP_ATOMIC); 103 n = max(size, nlbufsiz);
104 skb = alloc_skb(n, GFP_ATOMIC);
103 if (!skb) { 105 if (!skb) {
104 PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " 106 PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
105 "of size %ub!\n", nlbufsiz); 107 "of size %ub!\n", n);
106 if (size < nlbufsiz) { 108 if (n > size) {
107 /* try to allocate only as much as we need for 109 /* try to allocate only as much as we need for
108 * current packet */ 110 * current packet */
109 skb = alloc_skb(size, GFP_ATOMIC); 111 skb = alloc_skb(size, GFP_ATOMIC);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 00729b3604f8..cbd4020cc84d 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -934,6 +934,13 @@ static int do_replace(void __user *user, unsigned int len)
934 BUGPRINT("Entries_size never zero\n"); 934 BUGPRINT("Entries_size never zero\n");
935 return -EINVAL; 935 return -EINVAL;
936 } 936 }
937 /* overflow check */
938 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
939 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
940 return -ENOMEM;
941 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
942 return -ENOMEM;
943
937 countersize = COUNTER_OFFSET(tmp.nentries) * 944 countersize = COUNTER_OFFSET(tmp.nentries) *
938 (highest_possible_processor_id()+1); 945 (highest_possible_processor_id()+1);
939 newinfo = (struct ebt_table_info *) 946 newinfo = (struct ebt_table_info *)