summaryrefslogtreecommitdiff
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br.c10
-rw-r--r--net/bridge/br_fdb.c45
-rw-r--r--net/bridge/br_input.c5
-rw-r--r--net/bridge/br_netfilter.c33
-rw-r--r--net/bridge/br_private.h12
-rw-r--r--net/bridge/br_stp.c3
-rw-r--r--net/bridge/br_sysfs_br.c3
-rw-r--r--net/bridge/br_sysfs_if.c3
-rw-r--r--net/bridge/netfilter/ebtables.c18
9 files changed, 73 insertions, 59 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 4d2c1f1cb524..9aac5213105a 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -65,8 +65,9 @@ static int __init br_init(void)
brioctl_set(br_ioctl_deviceless_stub);
br_handle_frame_hook = br_handle_frame;
- br_fdb_get_hook = br_fdb_get;
- br_fdb_put_hook = br_fdb_put;
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ br_fdb_test_addr_hook = br_fdb_test_addr;
+#endif
return 0;
err_out4:
@@ -95,8 +96,9 @@ static void __exit br_deinit(void)
synchronize_net();
br_netfilter_fini();
- br_fdb_get_hook = NULL;
- br_fdb_put_hook = NULL;
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ br_fdb_test_addr_hook = NULL;
+#endif
br_handle_frame_hook = NULL;
br_fdb_fini();
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index a48f5efdb6bf..57bf05c353bc 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -71,10 +71,17 @@ static inline int br_mac_hash(const unsigned char *mac)
return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
}
+static void fdb_rcu_free(struct rcu_head *head)
+{
+ struct net_bridge_fdb_entry *ent
+ = container_of(head, struct net_bridge_fdb_entry, rcu);
+ kmem_cache_free(br_fdb_cache, ent);
+}
+
static inline void fdb_delete(struct net_bridge_fdb_entry *f)
{
hlist_del_rcu(&f->hlist);
- br_fdb_put(f);
+ call_rcu(&f->rcu, fdb_rcu_free);
}
void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
@@ -226,33 +233,26 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
return NULL;
}
-/* Interface used by ATM hook that keeps a ref count */
-struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
- unsigned char *addr)
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+/* Interface used by ATM LANE hook to test
+ * if an addr is on some other bridge port */
+int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
{
struct net_bridge_fdb_entry *fdb;
+ int ret;
+
+ if (!dev->br_port)
+ return 0;
rcu_read_lock();
- fdb = __br_fdb_get(br, addr);
- if (fdb && !atomic_inc_not_zero(&fdb->use_count))
- fdb = NULL;
+ fdb = __br_fdb_get(dev->br_port->br, addr);
+ ret = fdb && fdb->dst->dev != dev &&
+ fdb->dst->state == BR_STATE_FORWARDING;
rcu_read_unlock();
- return fdb;
-}
-
-static void fdb_rcu_free(struct rcu_head *head)
-{
- struct net_bridge_fdb_entry *ent
- = container_of(head, struct net_bridge_fdb_entry, rcu);
- kmem_cache_free(br_fdb_cache, ent);
-}
-/* Set entry up for deletion with RCU */
-void br_fdb_put(struct net_bridge_fdb_entry *ent)
-{
- if (atomic_dec_and_test(&ent->use_count))
- call_rcu(&ent->rcu, fdb_rcu_free);
+ return ret;
}
+#endif /* CONFIG_ATM_LANE */
/*
* Fill buffer with forwarding table records in
@@ -326,7 +326,6 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
if (fdb) {
memcpy(fdb->addr.addr, addr, ETH_ALEN);
- atomic_set(&fdb->use_count, 1);
hlist_add_head_rcu(&fdb->hlist, head);
fdb->dst = source;
@@ -398,7 +397,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
if (unlikely(fdb->is_local)) {
if (net_ratelimit())
printk(KERN_WARNING "%s: received packet with "
- " own address as source address\n",
+ "own address as source address\n",
source->dev->name);
} else {
/* fastpath: update of existing entry */
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 30b88777c3df..5ee1a3682bf2 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -134,6 +134,10 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
if (skb->protocol == htons(ETH_P_PAUSE))
goto drop;
+ /* If STP is turned off, then forward */
+ if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
+ goto forward;
+
if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
NULL, br_handle_local_finish))
return NULL; /* frame consumed by filter */
@@ -141,6 +145,7 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
return skb; /* continue processing */
}
+forward:
switch (p->state) {
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index e4a418fcb35b..d22f611e4004 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -228,6 +228,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
{
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+ struct rtable *rt;
if (nf_bridge->mask & BRNF_PKT_TYPE) {
skb->pkt_type = PACKET_OTHERHOST;
@@ -235,12 +236,13 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
}
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
- skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
- if (!skb->rtable) {
+ rt = bridge_parent_rtable(nf_bridge->physindev);
+ if (!rt) {
kfree_skb(skb);
return 0;
}
- dst_hold(&skb->rtable->u.dst);
+ dst_hold(&rt->u.dst);
+ skb_dst_set(skb, &rt->u.dst);
skb->dev = nf_bridge->physindev;
nf_bridge_push_encap_header(skb);
@@ -320,7 +322,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
skb->dev = bridge_parent(skb->dev);
if (skb->dev) {
- struct dst_entry *dst = skb->dst;
+ struct dst_entry *dst = skb_dst(skb);
nf_bridge_pull_encap_header(skb);
@@ -338,6 +340,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
struct net_device *dev = skb->dev;
struct iphdr *iph = ip_hdr(skb);
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+ struct rtable *rt;
int err;
if (nf_bridge->mask & BRNF_PKT_TYPE) {
@@ -347,7 +350,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
if (dnat_took_place(skb)) {
if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
- struct rtable *rt;
struct flowi fl = {
.nl_u = {
.ip4_u = {
@@ -373,7 +375,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
/* - Bridged-and-DNAT'ed traffic doesn't
* require ip_forwarding. */
if (((struct dst_entry *)rt)->dev == dev) {
- skb->dst = (struct dst_entry *)rt;
+ skb_dst_set(skb, (struct dst_entry *)rt);
goto bridged_dnat;
}
/* we are sure that forwarding is disabled, so printing
@@ -387,7 +389,7 @@ free_skb:
kfree_skb(skb);
return 0;
} else {
- if (skb->dst->dev == dev) {
+ if (skb_dst(skb)->dev == dev) {
bridged_dnat:
/* Tell br_nf_local_out this is a
* bridged frame */
@@ -404,12 +406,13 @@ bridged_dnat:
skb->pkt_type = PACKET_HOST;
}
} else {
- skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
- if (!skb->rtable) {
+ rt = bridge_parent_rtable(nf_bridge->physindev);
+ if (!rt) {
kfree_skb(skb);
return 0;
}
- dst_hold(&skb->rtable->u.dst);
+ dst_hold(&rt->u.dst);
+ skb_dst_set(skb, &rt->u.dst);
}
skb->dev = nf_bridge->physindev;
@@ -628,10 +631,10 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) {
- dst_release(&skb->rtable->u.dst);
- skb->rtable = NULL;
- }
+ struct rtable *rt = skb_rtable(skb);
+
+ if (rt && rt == bridge_parent_rtable(in))
+ skb_dst_drop(skb);
return NF_ACCEPT;
}
@@ -846,7 +849,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
return NF_ACCEPT;
#ifdef CONFIG_NETFILTER_DEBUG
- if (skb->dst == NULL) {
+ if (skb_dst(skb) == NULL) {
printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n");
goto print_error;
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index b6c3b71974dc..d5b5537272b4 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -51,7 +51,6 @@ struct net_bridge_fdb_entry
struct net_bridge_port *dst;
struct rcu_head rcu;
- atomic_t use_count;
unsigned long ageing_timer;
mac_addr addr;
unsigned char is_local;
@@ -154,9 +153,7 @@ extern void br_fdb_delete_by_port(struct net_bridge *br,
const struct net_bridge_port *p, int do_all);
extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
const unsigned char *addr);
-extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
- unsigned char *addr);
-extern void br_fdb_put(struct net_bridge_fdb_entry *ent);
+extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long count, unsigned long off);
extern int br_fdb_insert(struct net_bridge *br,
@@ -242,10 +239,9 @@ extern void br_stp_port_timer_init(struct net_bridge_port *p);
extern unsigned long br_timer_value(const struct timer_list *timer);
/* br.c */
-extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
- unsigned char *addr);
-extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
-
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
+#endif
/* br_netlink.c */
extern int br_netlink_init(void);
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 6e63ec3f1fcf..0660515f3992 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -297,6 +297,9 @@ void br_topology_change_detection(struct net_bridge *br)
{
int isroot = br_is_root_bridge(br);
+ if (br->stp_enabled != BR_KERNEL_STP)
+ return;
+
pr_info("%s: topology change detected, %s\n", br->dev->name,
isroot ? "propagating" : "sending tcn bpdu");
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 603d89248e71..ee4820aa1843 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -172,7 +172,8 @@ static ssize_t store_stp_state(struct device *d,
if (endp == buf)
return -EINVAL;
- rtnl_lock();
+ if (!rtnl_trylock())
+ return restart_syscall();
br_stp_set_enabled(br, val);
rtnl_unlock();
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 02b2d50cce4d..4a3cdf8f3813 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -189,7 +189,8 @@ static ssize_t brport_store(struct kobject * kobj,
val = simple_strtoul(buf, &endp, 0);
if (endp != buf) {
- rtnl_lock();
+ if (!rtnl_trylock())
+ return restart_syscall();
if (p->dev && p->br && brport_attr->store) {
spin_lock_bh(&p->br->lock);
ret = brport_attr->store(p, val);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 820252aee81f..37928d5f2840 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -142,6 +142,12 @@ static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
return 0;
}
+static inline __pure
+struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
+{
+ return (void *)entry + entry->next_offset;
+}
+
/* Do some firewalling */
unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
@@ -164,7 +170,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
mtpar.in = tgpar.in = in;
mtpar.out = tgpar.out = out;
mtpar.hotdrop = &hotdrop;
- tgpar.hooknum = hook;
+ mtpar.hooknum = tgpar.hooknum = hook;
read_lock_bh(&table->lock);
private = table->private;
@@ -249,8 +255,7 @@ letsreturn:
/* jump to a udc */
cs[sp].n = i + 1;
cs[sp].chaininfo = chaininfo;
- cs[sp].e = (struct ebt_entry *)
- (((char *)point) + point->next_offset);
+ cs[sp].e = ebt_next_entry(point);
i = 0;
chaininfo = (struct ebt_entries *) (base + verdict);
#ifdef CONFIG_NETFILTER_DEBUG
@@ -266,8 +271,7 @@ letsreturn:
sp++;
continue;
letscontinue:
- point = (struct ebt_entry *)
- (((char *)point) + point->next_offset);
+ point = ebt_next_entry(point);
i++;
}
@@ -787,7 +791,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
/* this can't be 0, so the loop test is correct */
cl_s[i].cs.n = pos + 1;
pos = 0;
- cl_s[i].cs.e = ((void *)e + e->next_offset);
+ cl_s[i].cs.e = ebt_next_entry(e);
e = (struct ebt_entry *)(hlp2->data);
nentries = hlp2->nentries;
cl_s[i].from = chain_nr;
@@ -797,7 +801,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
continue;
}
letscontinue:
- e = (void *)e + e->next_offset;
+ e = ebt_next_entry(e);
pos++;
}
return 0;