diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br.c | 4 | ||||
-rw-r--r-- | net/bridge/br_device.c | 2 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 15 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 4 | ||||
-rw-r--r-- | net/bridge/br_if.c | 7 | ||||
-rw-r--r-- | net/bridge/br_input.c | 10 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 88 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 49 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 10 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 6 | ||||
-rw-r--r-- | net/bridge/br_private.h | 21 | ||||
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 8 | ||||
-rw-r--r-- | net/bridge/br_stp_if.c | 2 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtable_broute.c | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 13 |
15 files changed, 134 insertions, 108 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c index c8436fa31344..84bbb82599b2 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -22,8 +22,6 @@ | |||
22 | 22 | ||
23 | #include "br_private.h" | 23 | #include "br_private.h" |
24 | 24 | ||
25 | int (*br_should_route_hook)(struct sk_buff *skb); | ||
26 | |||
27 | static const struct stp_proto br_stp_proto = { | 25 | static const struct stp_proto br_stp_proto = { |
28 | .rcv = br_stp_rcv, | 26 | .rcv = br_stp_rcv, |
29 | }; | 27 | }; |
@@ -102,8 +100,6 @@ static void __exit br_deinit(void) | |||
102 | br_fdb_fini(); | 100 | br_fdb_fini(); |
103 | } | 101 | } |
104 | 102 | ||
105 | EXPORT_SYMBOL(br_should_route_hook); | ||
106 | |||
107 | module_init(br_init) | 103 | module_init(br_init) |
108 | module_exit(br_deinit) | 104 | module_exit(br_deinit) |
109 | MODULE_LICENSE("GPL"); | 105 | MODULE_LICENSE("GPL"); |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 17cb0b633576..556443566e9c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -141,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
141 | 141 | ||
142 | #ifdef CONFIG_BRIDGE_NETFILTER | 142 | #ifdef CONFIG_BRIDGE_NETFILTER |
143 | /* remember the MTU in the rtable for PMTU */ | 143 | /* remember the MTU in the rtable for PMTU */ |
144 | br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu; | 144 | dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | return 0; | 147 | return 0; |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 90512ccfd3e9..2872393b2939 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -238,15 +238,18 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | |||
238 | int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) | 238 | int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) |
239 | { | 239 | { |
240 | struct net_bridge_fdb_entry *fdb; | 240 | struct net_bridge_fdb_entry *fdb; |
241 | struct net_bridge_port *port; | ||
241 | int ret; | 242 | int ret; |
242 | 243 | ||
243 | if (!br_port_exists(dev)) | ||
244 | return 0; | ||
245 | |||
246 | rcu_read_lock(); | 244 | rcu_read_lock(); |
247 | fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr); | 245 | port = br_port_get_rcu(dev); |
248 | ret = fdb && fdb->dst->dev != dev && | 246 | if (!port) |
249 | fdb->dst->state == BR_STATE_FORWARDING; | 247 | ret = 0; |
248 | else { | ||
249 | fdb = __br_fdb_get(port->br, addr); | ||
250 | ret = fdb && fdb->dst->dev != dev && | ||
251 | fdb->dst->state == BR_STATE_FORWARDING; | ||
252 | } | ||
250 | rcu_read_unlock(); | 253 | rcu_read_unlock(); |
251 | 254 | ||
252 | return ret; | 255 | return ret; |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index cbfe87f0f34a..2bd11ec6d166 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -223,7 +223,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
223 | struct net_bridge_port_group *p; | 223 | struct net_bridge_port_group *p; |
224 | struct hlist_node *rp; | 224 | struct hlist_node *rp; |
225 | 225 | ||
226 | rp = rcu_dereference(br->router_list.first); | 226 | rp = rcu_dereference(hlist_first_rcu(&br->router_list)); |
227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; | 227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; |
228 | while (p || rp) { | 228 | while (p || rp) { |
229 | struct net_bridge_port *port, *lport, *rport; | 229 | struct net_bridge_port *port, *lport, *rport; |
@@ -242,7 +242,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
242 | if ((unsigned long)lport >= (unsigned long)port) | 242 | if ((unsigned long)lport >= (unsigned long)port) |
243 | p = rcu_dereference(p->next); | 243 | p = rcu_dereference(p->next); |
244 | if ((unsigned long)rport >= (unsigned long)port) | 244 | if ((unsigned long)rport >= (unsigned long)port) |
245 | rp = rcu_dereference(rp->next); | 245 | rp = rcu_dereference(hlist_next_rcu(rp)); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (!prev) | 248 | if (!prev) |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 89ad25a76202..d9d1e2bac1d6 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -475,11 +475,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) | |||
475 | { | 475 | { |
476 | struct net_bridge_port *p; | 476 | struct net_bridge_port *p; |
477 | 477 | ||
478 | if (!br_port_exists(dev)) | 478 | p = br_port_get_rtnl(dev); |
479 | return -EINVAL; | 479 | if (!p || p->br != br) |
480 | |||
481 | p = br_port_get(dev); | ||
482 | if (p->br != br) | ||
483 | return -EINVAL; | 480 | return -EINVAL; |
484 | 481 | ||
485 | del_nbp(p); | 482 | del_nbp(p); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 25207a1f182b..6f6d8e1b776f 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -21,6 +21,10 @@ | |||
21 | /* Bridge group multicast address 802.1d (pg 51). */ | 21 | /* Bridge group multicast address 802.1d (pg 51). */ |
22 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | 22 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; |
23 | 23 | ||
24 | /* Hook for brouter */ | ||
25 | br_should_route_hook_t __rcu *br_should_route_hook __read_mostly; | ||
26 | EXPORT_SYMBOL(br_should_route_hook); | ||
27 | |||
24 | static int br_pass_frame_up(struct sk_buff *skb) | 28 | static int br_pass_frame_up(struct sk_buff *skb) |
25 | { | 29 | { |
26 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; | 30 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; |
@@ -139,7 +143,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb) | |||
139 | { | 143 | { |
140 | struct net_bridge_port *p; | 144 | struct net_bridge_port *p; |
141 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 145 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
142 | int (*rhook)(struct sk_buff *skb); | 146 | br_should_route_hook_t *rhook; |
143 | 147 | ||
144 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) | 148 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) |
145 | return skb; | 149 | return skb; |
@@ -173,8 +177,8 @@ forward: | |||
173 | switch (p->state) { | 177 | switch (p->state) { |
174 | case BR_STATE_FORWARDING: | 178 | case BR_STATE_FORWARDING: |
175 | rhook = rcu_dereference(br_should_route_hook); | 179 | rhook = rcu_dereference(br_should_route_hook); |
176 | if (rhook != NULL) { | 180 | if (rhook) { |
177 | if (rhook(skb)) | 181 | if ((*rhook)(skb)) |
178 | return skb; | 182 | return skb; |
179 | dest = eth_hdr(skb)->h_dest; | 183 | dest = eth_hdr(skb)->h_dest; |
180 | } | 184 | } |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 543b3262d002..f701a21acb34 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -33,6 +33,9 @@ | |||
33 | 33 | ||
34 | #include "br_private.h" | 34 | #include "br_private.h" |
35 | 35 | ||
36 | #define mlock_dereference(X, br) \ | ||
37 | rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) | ||
38 | |||
36 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 39 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
37 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) | 40 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) |
38 | { | 41 | { |
@@ -135,7 +138,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get( | |||
135 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, | 138 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, |
136 | struct sk_buff *skb) | 139 | struct sk_buff *skb) |
137 | { | 140 | { |
138 | struct net_bridge_mdb_htable *mdb = br->mdb; | 141 | struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb); |
139 | struct br_ip ip; | 142 | struct br_ip ip; |
140 | 143 | ||
141 | if (br->multicast_disabled) | 144 | if (br->multicast_disabled) |
@@ -235,7 +238,8 @@ static void br_multicast_group_expired(unsigned long data) | |||
235 | if (mp->ports) | 238 | if (mp->ports) |
236 | goto out; | 239 | goto out; |
237 | 240 | ||
238 | mdb = br->mdb; | 241 | mdb = mlock_dereference(br->mdb, br); |
242 | |||
239 | hlist_del_rcu(&mp->hlist[mdb->ver]); | 243 | hlist_del_rcu(&mp->hlist[mdb->ver]); |
240 | mdb->size--; | 244 | mdb->size--; |
241 | 245 | ||
@@ -249,16 +253,20 @@ out: | |||
249 | static void br_multicast_del_pg(struct net_bridge *br, | 253 | static void br_multicast_del_pg(struct net_bridge *br, |
250 | struct net_bridge_port_group *pg) | 254 | struct net_bridge_port_group *pg) |
251 | { | 255 | { |
252 | struct net_bridge_mdb_htable *mdb = br->mdb; | 256 | struct net_bridge_mdb_htable *mdb; |
253 | struct net_bridge_mdb_entry *mp; | 257 | struct net_bridge_mdb_entry *mp; |
254 | struct net_bridge_port_group *p; | 258 | struct net_bridge_port_group *p; |
255 | struct net_bridge_port_group **pp; | 259 | struct net_bridge_port_group __rcu **pp; |
260 | |||
261 | mdb = mlock_dereference(br->mdb, br); | ||
256 | 262 | ||
257 | mp = br_mdb_ip_get(mdb, &pg->addr); | 263 | mp = br_mdb_ip_get(mdb, &pg->addr); |
258 | if (WARN_ON(!mp)) | 264 | if (WARN_ON(!mp)) |
259 | return; | 265 | return; |
260 | 266 | ||
261 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 267 | for (pp = &mp->ports; |
268 | (p = mlock_dereference(*pp, br)) != NULL; | ||
269 | pp = &p->next) { | ||
262 | if (p != pg) | 270 | if (p != pg) |
263 | continue; | 271 | continue; |
264 | 272 | ||
@@ -294,10 +302,10 @@ out: | |||
294 | spin_unlock(&br->multicast_lock); | 302 | spin_unlock(&br->multicast_lock); |
295 | } | 303 | } |
296 | 304 | ||
297 | static int br_mdb_rehash(struct net_bridge_mdb_htable **mdbp, int max, | 305 | static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max, |
298 | int elasticity) | 306 | int elasticity) |
299 | { | 307 | { |
300 | struct net_bridge_mdb_htable *old = *mdbp; | 308 | struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1); |
301 | struct net_bridge_mdb_htable *mdb; | 309 | struct net_bridge_mdb_htable *mdb; |
302 | int err; | 310 | int err; |
303 | 311 | ||
@@ -569,7 +577,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
569 | struct net_bridge *br, struct net_bridge_port *port, | 577 | struct net_bridge *br, struct net_bridge_port *port, |
570 | struct br_ip *group, int hash) | 578 | struct br_ip *group, int hash) |
571 | { | 579 | { |
572 | struct net_bridge_mdb_htable *mdb = br->mdb; | 580 | struct net_bridge_mdb_htable *mdb; |
573 | struct net_bridge_mdb_entry *mp; | 581 | struct net_bridge_mdb_entry *mp; |
574 | struct hlist_node *p; | 582 | struct hlist_node *p; |
575 | unsigned count = 0; | 583 | unsigned count = 0; |
@@ -577,6 +585,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
577 | int elasticity; | 585 | int elasticity; |
578 | int err; | 586 | int err; |
579 | 587 | ||
588 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
580 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { | 589 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { |
581 | count++; | 590 | count++; |
582 | if (unlikely(br_ip_equal(group, &mp->addr))) | 591 | if (unlikely(br_ip_equal(group, &mp->addr))) |
@@ -642,13 +651,16 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
642 | struct net_bridge *br, struct net_bridge_port *port, | 651 | struct net_bridge *br, struct net_bridge_port *port, |
643 | struct br_ip *group) | 652 | struct br_ip *group) |
644 | { | 653 | { |
645 | struct net_bridge_mdb_htable *mdb = br->mdb; | 654 | struct net_bridge_mdb_htable *mdb; |
646 | struct net_bridge_mdb_entry *mp; | 655 | struct net_bridge_mdb_entry *mp; |
647 | int hash; | 656 | int hash; |
657 | int err; | ||
648 | 658 | ||
659 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
649 | if (!mdb) { | 660 | if (!mdb) { |
650 | if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0)) | 661 | err = br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0); |
651 | return NULL; | 662 | if (err) |
663 | return ERR_PTR(err); | ||
652 | goto rehash; | 664 | goto rehash; |
653 | } | 665 | } |
654 | 666 | ||
@@ -660,7 +672,7 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
660 | 672 | ||
661 | case -EAGAIN: | 673 | case -EAGAIN: |
662 | rehash: | 674 | rehash: |
663 | mdb = br->mdb; | 675 | mdb = rcu_dereference_protected(br->mdb, 1); |
664 | hash = br_ip_hash(mdb, group); | 676 | hash = br_ip_hash(mdb, group); |
665 | break; | 677 | break; |
666 | 678 | ||
@@ -670,7 +682,7 @@ rehash: | |||
670 | 682 | ||
671 | mp = kzalloc(sizeof(*mp), GFP_ATOMIC); | 683 | mp = kzalloc(sizeof(*mp), GFP_ATOMIC); |
672 | if (unlikely(!mp)) | 684 | if (unlikely(!mp)) |
673 | goto out; | 685 | return ERR_PTR(-ENOMEM); |
674 | 686 | ||
675 | mp->br = br; | 687 | mp->br = br; |
676 | mp->addr = *group; | 688 | mp->addr = *group; |
@@ -692,7 +704,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
692 | { | 704 | { |
693 | struct net_bridge_mdb_entry *mp; | 705 | struct net_bridge_mdb_entry *mp; |
694 | struct net_bridge_port_group *p; | 706 | struct net_bridge_port_group *p; |
695 | struct net_bridge_port_group **pp; | 707 | struct net_bridge_port_group __rcu **pp; |
696 | unsigned long now = jiffies; | 708 | unsigned long now = jiffies; |
697 | int err; | 709 | int err; |
698 | 710 | ||
@@ -703,7 +715,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
703 | 715 | ||
704 | mp = br_multicast_new_group(br, port, group); | 716 | mp = br_multicast_new_group(br, port, group); |
705 | err = PTR_ERR(mp); | 717 | err = PTR_ERR(mp); |
706 | if (unlikely(IS_ERR(mp) || !mp)) | 718 | if (IS_ERR(mp)) |
707 | goto err; | 719 | goto err; |
708 | 720 | ||
709 | if (!port) { | 721 | if (!port) { |
@@ -712,7 +724,9 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
712 | goto out; | 724 | goto out; |
713 | } | 725 | } |
714 | 726 | ||
715 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 727 | for (pp = &mp->ports; |
728 | (p = mlock_dereference(*pp, br)) != NULL; | ||
729 | pp = &p->next) { | ||
716 | if (p->port == port) | 730 | if (p->port == port) |
717 | goto found; | 731 | goto found; |
718 | if ((unsigned long)p->port < (unsigned long)port) | 732 | if ((unsigned long)p->port < (unsigned long)port) |
@@ -1106,7 +1120,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1106 | struct net_bridge_mdb_entry *mp; | 1120 | struct net_bridge_mdb_entry *mp; |
1107 | struct igmpv3_query *ih3; | 1121 | struct igmpv3_query *ih3; |
1108 | struct net_bridge_port_group *p; | 1122 | struct net_bridge_port_group *p; |
1109 | struct net_bridge_port_group **pp; | 1123 | struct net_bridge_port_group __rcu **pp; |
1110 | unsigned long max_delay; | 1124 | unsigned long max_delay; |
1111 | unsigned long now = jiffies; | 1125 | unsigned long now = jiffies; |
1112 | __be32 group; | 1126 | __be32 group; |
@@ -1145,7 +1159,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1145 | if (!group) | 1159 | if (!group) |
1146 | goto out; | 1160 | goto out; |
1147 | 1161 | ||
1148 | mp = br_mdb_ip4_get(br->mdb, group); | 1162 | mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group); |
1149 | if (!mp) | 1163 | if (!mp) |
1150 | goto out; | 1164 | goto out; |
1151 | 1165 | ||
@@ -1157,7 +1171,9 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1157 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1171 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1158 | mod_timer(&mp->timer, now + max_delay); | 1172 | mod_timer(&mp->timer, now + max_delay); |
1159 | 1173 | ||
1160 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1174 | for (pp = &mp->ports; |
1175 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1176 | pp = &p->next) { | ||
1161 | if (timer_pending(&p->timer) ? | 1177 | if (timer_pending(&p->timer) ? |
1162 | time_after(p->timer.expires, now + max_delay) : | 1178 | time_after(p->timer.expires, now + max_delay) : |
1163 | try_to_del_timer_sync(&p->timer) >= 0) | 1179 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1178,7 +1194,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1178 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); | 1194 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); |
1179 | struct net_bridge_mdb_entry *mp; | 1195 | struct net_bridge_mdb_entry *mp; |
1180 | struct mld2_query *mld2q; | 1196 | struct mld2_query *mld2q; |
1181 | struct net_bridge_port_group *p, **pp; | 1197 | struct net_bridge_port_group *p; |
1198 | struct net_bridge_port_group __rcu **pp; | ||
1182 | unsigned long max_delay; | 1199 | unsigned long max_delay; |
1183 | unsigned long now = jiffies; | 1200 | unsigned long now = jiffies; |
1184 | struct in6_addr *group = NULL; | 1201 | struct in6_addr *group = NULL; |
@@ -1214,7 +1231,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1214 | if (!group) | 1231 | if (!group) |
1215 | goto out; | 1232 | goto out; |
1216 | 1233 | ||
1217 | mp = br_mdb_ip6_get(br->mdb, group); | 1234 | mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group); |
1218 | if (!mp) | 1235 | if (!mp) |
1219 | goto out; | 1236 | goto out; |
1220 | 1237 | ||
@@ -1225,7 +1242,9 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1225 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1242 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1226 | mod_timer(&mp->timer, now + max_delay); | 1243 | mod_timer(&mp->timer, now + max_delay); |
1227 | 1244 | ||
1228 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1245 | for (pp = &mp->ports; |
1246 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1247 | pp = &p->next) { | ||
1229 | if (timer_pending(&p->timer) ? | 1248 | if (timer_pending(&p->timer) ? |
1230 | time_after(p->timer.expires, now + max_delay) : | 1249 | time_after(p->timer.expires, now + max_delay) : |
1231 | try_to_del_timer_sync(&p->timer) >= 0) | 1250 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1254,7 +1273,7 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1254 | timer_pending(&br->multicast_querier_timer)) | 1273 | timer_pending(&br->multicast_querier_timer)) |
1255 | goto out; | 1274 | goto out; |
1256 | 1275 | ||
1257 | mdb = br->mdb; | 1276 | mdb = mlock_dereference(br->mdb, br); |
1258 | mp = br_mdb_ip_get(mdb, group); | 1277 | mp = br_mdb_ip_get(mdb, group); |
1259 | if (!mp) | 1278 | if (!mp) |
1260 | goto out; | 1279 | goto out; |
@@ -1277,7 +1296,9 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1277 | goto out; | 1296 | goto out; |
1278 | } | 1297 | } |
1279 | 1298 | ||
1280 | for (p = mp->ports; p; p = p->next) { | 1299 | for (p = mlock_dereference(mp->ports, br); |
1300 | p != NULL; | ||
1301 | p = mlock_dereference(p->next, br)) { | ||
1281 | if (p->port != port) | 1302 | if (p->port != port) |
1282 | continue; | 1303 | continue; |
1283 | 1304 | ||
@@ -1633,7 +1654,7 @@ void br_multicast_stop(struct net_bridge *br) | |||
1633 | del_timer_sync(&br->multicast_query_timer); | 1654 | del_timer_sync(&br->multicast_query_timer); |
1634 | 1655 | ||
1635 | spin_lock_bh(&br->multicast_lock); | 1656 | spin_lock_bh(&br->multicast_lock); |
1636 | mdb = br->mdb; | 1657 | mdb = mlock_dereference(br->mdb, br); |
1637 | if (!mdb) | 1658 | if (!mdb) |
1638 | goto out; | 1659 | goto out; |
1639 | 1660 | ||
@@ -1737,6 +1758,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1737 | { | 1758 | { |
1738 | struct net_bridge_port *port; | 1759 | struct net_bridge_port *port; |
1739 | int err = 0; | 1760 | int err = 0; |
1761 | struct net_bridge_mdb_htable *mdb; | ||
1740 | 1762 | ||
1741 | spin_lock(&br->multicast_lock); | 1763 | spin_lock(&br->multicast_lock); |
1742 | if (br->multicast_disabled == !val) | 1764 | if (br->multicast_disabled == !val) |
@@ -1749,15 +1771,16 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1749 | if (!netif_running(br->dev)) | 1771 | if (!netif_running(br->dev)) |
1750 | goto unlock; | 1772 | goto unlock; |
1751 | 1773 | ||
1752 | if (br->mdb) { | 1774 | mdb = mlock_dereference(br->mdb, br); |
1753 | if (br->mdb->old) { | 1775 | if (mdb) { |
1776 | if (mdb->old) { | ||
1754 | err = -EEXIST; | 1777 | err = -EEXIST; |
1755 | rollback: | 1778 | rollback: |
1756 | br->multicast_disabled = !!val; | 1779 | br->multicast_disabled = !!val; |
1757 | goto unlock; | 1780 | goto unlock; |
1758 | } | 1781 | } |
1759 | 1782 | ||
1760 | err = br_mdb_rehash(&br->mdb, br->mdb->max, | 1783 | err = br_mdb_rehash(&br->mdb, mdb->max, |
1761 | br->hash_elasticity); | 1784 | br->hash_elasticity); |
1762 | if (err) | 1785 | if (err) |
1763 | goto rollback; | 1786 | goto rollback; |
@@ -1782,6 +1805,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1782 | { | 1805 | { |
1783 | int err = -ENOENT; | 1806 | int err = -ENOENT; |
1784 | u32 old; | 1807 | u32 old; |
1808 | struct net_bridge_mdb_htable *mdb; | ||
1785 | 1809 | ||
1786 | spin_lock(&br->multicast_lock); | 1810 | spin_lock(&br->multicast_lock); |
1787 | if (!netif_running(br->dev)) | 1811 | if (!netif_running(br->dev)) |
@@ -1790,7 +1814,9 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1790 | err = -EINVAL; | 1814 | err = -EINVAL; |
1791 | if (!is_power_of_2(val)) | 1815 | if (!is_power_of_2(val)) |
1792 | goto unlock; | 1816 | goto unlock; |
1793 | if (br->mdb && val < br->mdb->size) | 1817 | |
1818 | mdb = mlock_dereference(br->mdb, br); | ||
1819 | if (mdb && val < mdb->size) | ||
1794 | goto unlock; | 1820 | goto unlock; |
1795 | 1821 | ||
1796 | err = 0; | 1822 | err = 0; |
@@ -1798,8 +1824,8 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1798 | old = br->hash_max; | 1824 | old = br->hash_max; |
1799 | br->hash_max = val; | 1825 | br->hash_max = val; |
1800 | 1826 | ||
1801 | if (br->mdb) { | 1827 | if (mdb) { |
1802 | if (br->mdb->old) { | 1828 | if (mdb->old) { |
1803 | err = -EEXIST; | 1829 | err = -EEXIST; |
1804 | rollback: | 1830 | rollback: |
1805 | br->hash_max = old; | 1831 | br->hash_max = old; |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 865fd7634b67..4b5b66d07bba 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -124,24 +124,25 @@ void br_netfilter_rtable_init(struct net_bridge *br) | |||
124 | atomic_set(&rt->dst.__refcnt, 1); | 124 | atomic_set(&rt->dst.__refcnt, 1); |
125 | rt->dst.dev = br->dev; | 125 | rt->dst.dev = br->dev; |
126 | rt->dst.path = &rt->dst; | 126 | rt->dst.path = &rt->dst; |
127 | rt->dst.metrics[RTAX_MTU - 1] = 1500; | 127 | dst_metric_set(&rt->dst, RTAX_MTU, 1500); |
128 | rt->dst.flags = DST_NOXFRM; | 128 | rt->dst.flags = DST_NOXFRM; |
129 | rt->dst.ops = &fake_dst_ops; | 129 | rt->dst.ops = &fake_dst_ops; |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) | 132 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
133 | { | 133 | { |
134 | if (!br_port_exists(dev)) | 134 | struct net_bridge_port *port; |
135 | return NULL; | 135 | |
136 | return &br_port_get_rcu(dev)->br->fake_rtable; | 136 | port = br_port_get_rcu(dev); |
137 | return port ? &port->br->fake_rtable : NULL; | ||
137 | } | 138 | } |
138 | 139 | ||
139 | static inline struct net_device *bridge_parent(const struct net_device *dev) | 140 | static inline struct net_device *bridge_parent(const struct net_device *dev) |
140 | { | 141 | { |
141 | if (!br_port_exists(dev)) | 142 | struct net_bridge_port *port; |
142 | return NULL; | ||
143 | 143 | ||
144 | return br_port_get_rcu(dev)->br->dev; | 144 | port = br_port_get_rcu(dev); |
145 | return port ? port->br->dev : NULL; | ||
145 | } | 146 | } |
146 | 147 | ||
147 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | 148 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) |
@@ -412,13 +413,8 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | |||
412 | if (dnat_took_place(skb)) { | 413 | if (dnat_took_place(skb)) { |
413 | if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { | 414 | if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { |
414 | struct flowi fl = { | 415 | struct flowi fl = { |
415 | .nl_u = { | 416 | .fl4_dst = iph->daddr, |
416 | .ip4_u = { | 417 | .fl4_tos = RT_TOS(iph->tos), |
417 | .daddr = iph->daddr, | ||
418 | .saddr = 0, | ||
419 | .tos = RT_TOS(iph->tos) }, | ||
420 | }, | ||
421 | .proto = 0, | ||
422 | }; | 418 | }; |
423 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 419 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
424 | 420 | ||
@@ -566,26 +562,26 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
566 | u32 pkt_len; | 562 | u32 pkt_len; |
567 | 563 | ||
568 | if (skb->len < sizeof(struct ipv6hdr)) | 564 | if (skb->len < sizeof(struct ipv6hdr)) |
569 | goto inhdr_error; | 565 | return NF_DROP; |
570 | 566 | ||
571 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 567 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
572 | goto inhdr_error; | 568 | return NF_DROP; |
573 | 569 | ||
574 | hdr = ipv6_hdr(skb); | 570 | hdr = ipv6_hdr(skb); |
575 | 571 | ||
576 | if (hdr->version != 6) | 572 | if (hdr->version != 6) |
577 | goto inhdr_error; | 573 | return NF_DROP; |
578 | 574 | ||
579 | pkt_len = ntohs(hdr->payload_len); | 575 | pkt_len = ntohs(hdr->payload_len); |
580 | 576 | ||
581 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { | 577 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { |
582 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) | 578 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) |
583 | goto inhdr_error; | 579 | return NF_DROP; |
584 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) | 580 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) |
585 | goto inhdr_error; | 581 | return NF_DROP; |
586 | } | 582 | } |
587 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) | 583 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) |
588 | goto inhdr_error; | 584 | return NF_DROP; |
589 | 585 | ||
590 | nf_bridge_put(skb->nf_bridge); | 586 | nf_bridge_put(skb->nf_bridge); |
591 | if (!nf_bridge_alloc(skb)) | 587 | if (!nf_bridge_alloc(skb)) |
@@ -598,9 +594,6 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
598 | br_nf_pre_routing_finish_ipv6); | 594 | br_nf_pre_routing_finish_ipv6); |
599 | 595 | ||
600 | return NF_STOLEN; | 596 | return NF_STOLEN; |
601 | |||
602 | inhdr_error: | ||
603 | return NF_DROP; | ||
604 | } | 597 | } |
605 | 598 | ||
606 | /* Direct IPv6 traffic to br_nf_pre_routing_ipv6. | 599 | /* Direct IPv6 traffic to br_nf_pre_routing_ipv6. |
@@ -619,11 +612,11 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
619 | __u32 len = nf_bridge_encap_header_len(skb); | 612 | __u32 len = nf_bridge_encap_header_len(skb); |
620 | 613 | ||
621 | if (unlikely(!pskb_may_pull(skb, len))) | 614 | if (unlikely(!pskb_may_pull(skb, len))) |
622 | goto out; | 615 | return NF_DROP; |
623 | 616 | ||
624 | p = br_port_get_rcu(in); | 617 | p = br_port_get_rcu(in); |
625 | if (p == NULL) | 618 | if (p == NULL) |
626 | goto out; | 619 | return NF_DROP; |
627 | br = p->br; | 620 | br = p->br; |
628 | 621 | ||
629 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || | 622 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || |
@@ -645,8 +638,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
645 | nf_bridge_pull_encap_header_rcsum(skb); | 638 | nf_bridge_pull_encap_header_rcsum(skb); |
646 | 639 | ||
647 | if (br_parse_ip_options(skb)) | 640 | if (br_parse_ip_options(skb)) |
648 | /* Drop invalid packet */ | 641 | return NF_DROP; |
649 | goto out; | ||
650 | 642 | ||
651 | nf_bridge_put(skb->nf_bridge); | 643 | nf_bridge_put(skb->nf_bridge); |
652 | if (!nf_bridge_alloc(skb)) | 644 | if (!nf_bridge_alloc(skb)) |
@@ -660,9 +652,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
660 | br_nf_pre_routing_finish); | 652 | br_nf_pre_routing_finish); |
661 | 653 | ||
662 | return NF_STOLEN; | 654 | return NF_STOLEN; |
663 | |||
664 | out: | ||
665 | return NF_DROP; | ||
666 | } | 655 | } |
667 | 656 | ||
668 | 657 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 4a6a378c84e3..f8bf4c7f842c 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -119,11 +119,13 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
119 | 119 | ||
120 | idx = 0; | 120 | idx = 0; |
121 | for_each_netdev(net, dev) { | 121 | for_each_netdev(net, dev) { |
122 | struct net_bridge_port *port = br_port_get_rtnl(dev); | ||
123 | |||
122 | /* not a bridge port */ | 124 | /* not a bridge port */ |
123 | if (!br_port_exists(dev) || idx < cb->args[0]) | 125 | if (!port || idx < cb->args[0]) |
124 | goto skip; | 126 | goto skip; |
125 | 127 | ||
126 | if (br_fill_ifinfo(skb, br_port_get(dev), | 128 | if (br_fill_ifinfo(skb, port, |
127 | NETLINK_CB(cb->skb).pid, | 129 | NETLINK_CB(cb->skb).pid, |
128 | cb->nlh->nlmsg_seq, RTM_NEWLINK, | 130 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
129 | NLM_F_MULTI) < 0) | 131 | NLM_F_MULTI) < 0) |
@@ -169,9 +171,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
169 | if (!dev) | 171 | if (!dev) |
170 | return -ENODEV; | 172 | return -ENODEV; |
171 | 173 | ||
172 | if (!br_port_exists(dev)) | 174 | p = br_port_get_rtnl(dev); |
175 | if (!p) | ||
173 | return -EINVAL; | 176 | return -EINVAL; |
174 | p = br_port_get(dev); | ||
175 | 177 | ||
176 | /* if kernel STP is running, don't allow changes */ | 178 | /* if kernel STP is running, don't allow changes */ |
177 | if (p->br->stp_enabled == BR_KERNEL_STP) | 179 | if (p->br->stp_enabled == BR_KERNEL_STP) |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 404d4e14c6a7..7d337c9b6082 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -32,15 +32,15 @@ struct notifier_block br_device_notifier = { | |||
32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
33 | { | 33 | { |
34 | struct net_device *dev = ptr; | 34 | struct net_device *dev = ptr; |
35 | struct net_bridge_port *p = br_port_get(dev); | 35 | struct net_bridge_port *p; |
36 | struct net_bridge *br; | 36 | struct net_bridge *br; |
37 | int err; | 37 | int err; |
38 | 38 | ||
39 | /* not a port of a bridge */ | 39 | /* not a port of a bridge */ |
40 | if (!br_port_exists(dev)) | 40 | p = br_port_get_rtnl(dev); |
41 | if (!p) | ||
41 | return NOTIFY_DONE; | 42 | return NOTIFY_DONE; |
42 | 43 | ||
43 | p = br_port_get(dev); | ||
44 | br = p->br; | 44 | br = p->br; |
45 | 45 | ||
46 | switch (event) { | 46 | switch (event) { |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 75c90edaf7db..84aac7734bfc 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -72,7 +72,7 @@ struct net_bridge_fdb_entry | |||
72 | 72 | ||
73 | struct net_bridge_port_group { | 73 | struct net_bridge_port_group { |
74 | struct net_bridge_port *port; | 74 | struct net_bridge_port *port; |
75 | struct net_bridge_port_group *next; | 75 | struct net_bridge_port_group __rcu *next; |
76 | struct hlist_node mglist; | 76 | struct hlist_node mglist; |
77 | struct rcu_head rcu; | 77 | struct rcu_head rcu; |
78 | struct timer_list timer; | 78 | struct timer_list timer; |
@@ -86,7 +86,7 @@ struct net_bridge_mdb_entry | |||
86 | struct hlist_node hlist[2]; | 86 | struct hlist_node hlist[2]; |
87 | struct hlist_node mglist; | 87 | struct hlist_node mglist; |
88 | struct net_bridge *br; | 88 | struct net_bridge *br; |
89 | struct net_bridge_port_group *ports; | 89 | struct net_bridge_port_group __rcu *ports; |
90 | struct rcu_head rcu; | 90 | struct rcu_head rcu; |
91 | struct timer_list timer; | 91 | struct timer_list timer; |
92 | struct timer_list query_timer; | 92 | struct timer_list query_timer; |
@@ -151,11 +151,20 @@ struct net_bridge_port | |||
151 | #endif | 151 | #endif |
152 | }; | 152 | }; |
153 | 153 | ||
154 | #define br_port_get_rcu(dev) \ | ||
155 | ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data)) | ||
156 | #define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data) | ||
157 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) | 154 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) |
158 | 155 | ||
156 | static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev) | ||
157 | { | ||
158 | struct net_bridge_port *port = rcu_dereference(dev->rx_handler_data); | ||
159 | return br_port_exists(dev) ? port : NULL; | ||
160 | } | ||
161 | |||
162 | static inline struct net_bridge_port *br_port_get_rtnl(struct net_device *dev) | ||
163 | { | ||
164 | return br_port_exists(dev) ? | ||
165 | rtnl_dereference(dev->rx_handler_data) : NULL; | ||
166 | } | ||
167 | |||
159 | struct br_cpu_netstats { | 168 | struct br_cpu_netstats { |
160 | u64 rx_packets; | 169 | u64 rx_packets; |
161 | u64 rx_bytes; | 170 | u64 rx_bytes; |
@@ -227,7 +236,7 @@ struct net_bridge | |||
227 | unsigned long multicast_startup_query_interval; | 236 | unsigned long multicast_startup_query_interval; |
228 | 237 | ||
229 | spinlock_t multicast_lock; | 238 | spinlock_t multicast_lock; |
230 | struct net_bridge_mdb_htable *mdb; | 239 | struct net_bridge_mdb_htable __rcu *mdb; |
231 | struct hlist_head router_list; | 240 | struct hlist_head router_list; |
232 | struct hlist_head mglist; | 241 | struct hlist_head mglist; |
233 | 242 | ||
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index e3d7aefa9181..289646ec9b7b 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -143,10 +143,6 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | |||
143 | struct net_bridge *br; | 143 | struct net_bridge *br; |
144 | const unsigned char *buf; | 144 | const unsigned char *buf; |
145 | 145 | ||
146 | if (!br_port_exists(dev)) | ||
147 | goto err; | ||
148 | p = br_port_get_rcu(dev); | ||
149 | |||
150 | if (!pskb_may_pull(skb, 4)) | 146 | if (!pskb_may_pull(skb, 4)) |
151 | goto err; | 147 | goto err; |
152 | 148 | ||
@@ -155,6 +151,10 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | |||
155 | if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) | 151 | if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) |
156 | goto err; | 152 | goto err; |
157 | 153 | ||
154 | p = br_port_get_rcu(dev); | ||
155 | if (!p) | ||
156 | goto err; | ||
157 | |||
158 | br = p->br; | 158 | br = p->br; |
159 | spin_lock(&br->lock); | 159 | spin_lock(&br->lock); |
160 | 160 | ||
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 1d8826914cbf..79372d4a4055 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -145,7 +145,7 @@ static void br_stp_stop(struct net_bridge *br) | |||
145 | char *envp[] = { NULL }; | 145 | char *envp[] = { NULL }; |
146 | 146 | ||
147 | if (br->stp_enabled == BR_USER_STP) { | 147 | if (br->stp_enabled == BR_USER_STP) { |
148 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | 148 | r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); |
149 | br_info(br, "userspace STP stopped, return code %d\n", r); | 149 | br_info(br, "userspace STP stopped, return code %d\n", r); |
150 | 150 | ||
151 | /* To start timers on any ports left in blocking */ | 151 | /* To start timers on any ports left in blocking */ |
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index ae3f106c3908..1bcaf36ad612 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
@@ -87,7 +87,8 @@ static int __init ebtable_broute_init(void) | |||
87 | if (ret < 0) | 87 | if (ret < 0) |
88 | return ret; | 88 | return ret; |
89 | /* see br_input.c */ | 89 | /* see br_input.c */ |
90 | rcu_assign_pointer(br_should_route_hook, ebt_broute); | 90 | rcu_assign_pointer(br_should_route_hook, |
91 | (br_should_route_hook_t *)ebt_broute); | ||
91 | return 0; | 92 | return 0; |
92 | } | 93 | } |
93 | 94 | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index a1dcf83f0d58..16df0532d4b9 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -128,6 +128,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, | |||
128 | const struct net_device *in, const struct net_device *out) | 128 | const struct net_device *in, const struct net_device *out) |
129 | { | 129 | { |
130 | const struct ethhdr *h = eth_hdr(skb); | 130 | const struct ethhdr *h = eth_hdr(skb); |
131 | const struct net_bridge_port *p; | ||
131 | __be16 ethproto; | 132 | __be16 ethproto; |
132 | int verdict, i; | 133 | int verdict, i; |
133 | 134 | ||
@@ -148,13 +149,11 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, | |||
148 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) | 149 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
149 | return 1; | 150 | return 1; |
150 | /* rcu_read_lock()ed by nf_hook_slow */ | 151 | /* rcu_read_lock()ed by nf_hook_slow */ |
151 | if (in && br_port_exists(in) && | 152 | if (in && (p = br_port_get_rcu(in)) != NULL && |
152 | FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev), | 153 | FWINV2(ebt_dev_check(e->logical_in, p->br->dev), EBT_ILOGICALIN)) |
153 | EBT_ILOGICALIN)) | ||
154 | return 1; | 154 | return 1; |
155 | if (out && br_port_exists(out) && | 155 | if (out && (p = br_port_get_rcu(out)) != NULL && |
156 | FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev), | 156 | FWINV2(ebt_dev_check(e->logical_out, p->br->dev), EBT_ILOGICALOUT)) |
157 | EBT_ILOGICALOUT)) | ||
158 | return 1; | 157 | return 1; |
159 | 158 | ||
160 | if (e->bitmask & EBT_SOURCEMAC) { | 159 | if (e->bitmask & EBT_SOURCEMAC) { |
@@ -1148,7 +1147,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table) | |||
1148 | void *p; | 1147 | void *p; |
1149 | 1148 | ||
1150 | if (input_table == NULL || (repl = input_table->table) == NULL || | 1149 | if (input_table == NULL || (repl = input_table->table) == NULL || |
1151 | repl->entries == 0 || repl->entries_size == 0 || | 1150 | repl->entries == NULL || repl->entries_size == 0 || |
1152 | repl->counters != NULL || input_table->private != NULL) { | 1151 | repl->counters != NULL || input_table->private != NULL) { |
1153 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); | 1152 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); |
1154 | return ERR_PTR(-EINVAL); | 1153 | return ERR_PTR(-EINVAL); |