diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
| -rw-r--r-- | net/bridge/br_multicast.c | 47 | 
1 files changed, 26 insertions, 21 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 2559fb53983..eaa0e1bae49 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -38,7 +38,7 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(  	struct net_bridge_mdb_entry *mp;  	struct hlist_node *p; -	hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { +	hlist_for_each_entry_rcu(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {  		if (dst == mp->addr)  			return mp;  	} @@ -49,22 +49,23 @@ static struct net_bridge_mdb_entry *__br_mdb_ip_get(  static struct net_bridge_mdb_entry *br_mdb_ip_get(  	struct net_bridge_mdb_htable *mdb, __be32 dst)  { +	if (!mdb) +		return NULL; +  	return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));  }  struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,  					struct sk_buff *skb)  { -	struct net_bridge_mdb_htable *mdb = br->mdb; - -	if (!mdb || br->multicast_disabled) +	if (br->multicast_disabled)  		return NULL;  	switch (skb->protocol) {  	case htons(ETH_P_IP):  		if (BR_INPUT_SKB_CB(skb)->igmp)  			break; -		return br_mdb_ip_get(mdb, ip_hdr(skb)->daddr); +		return br_mdb_ip_get(br->mdb, ip_hdr(skb)->daddr);  	}  	return NULL; @@ -627,8 +628,8 @@ static void br_multicast_port_query_expired(unsigned long data)  	struct net_bridge *br = port->br;  	spin_lock(&br->multicast_lock); -	if (port && (port->state == BR_STATE_DISABLED || -		     port->state == BR_STATE_BLOCKING)) +	if (port->state == BR_STATE_DISABLED || +	    port->state == BR_STATE_BLOCKING)  		goto out;  	if (port->multicast_startup_queries_sent < @@ -722,11 +723,11 @@ static int br_multicast_igmp3_report(struct net_bridge *br,  		if (!pskb_may_pull(skb, len))  			return -EINVAL; -		grec = (void *)(skb->data + len); +		grec = (void *)(skb->data + len - sizeof(*grec));  		group = grec->grec_mca;  		type = grec->grec_type; -		len += grec->grec_nsrcs * 4; +		len += ntohs(grec->grec_nsrcs) * 4;  		if (!pskb_may_pull(skb, len))  			return -EINVAL; @@ -823,6 +824,7 @@ static int br_multicast_query(struct net_bridge *br,  	unsigned long max_delay;  	unsigned long now = jiffies;  	__be32 group; +	int err = 0;  	spin_lock(&br->multicast_lock);  	if (!netif_running(br->dev) || @@ -841,15 +843,17 @@ static int br_multicast_query(struct net_bridge *br,  			group = 0;  		}  	} else { -		if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) -			return -EINVAL; +		if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) { +			err = -EINVAL; +			goto out; +		}  		ih3 = igmpv3_query_hdr(skb);  		if (ih3->nsrcs) -			return 0; +			goto out; -		max_delay = ih3->code ? 1 : -			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE); +		max_delay = ih3->code ? +			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;  	}  	if (!group) @@ -876,7 +880,7 @@ static int br_multicast_query(struct net_bridge *br,  out:  	spin_unlock(&br->multicast_lock); -	return 0; +	return err;  }  static void br_multicast_leave_group(struct net_bridge *br, @@ -953,9 +957,6 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,  	unsigned offset;  	int err; -	BR_INPUT_SKB_CB(skb)->igmp = 0; -	BR_INPUT_SKB_CB(skb)->mrouters_only = 0; -  	/* We treat OOM as packet loss for now. */  	if (!pskb_may_pull(skb, sizeof(*iph)))  		return -EINVAL; @@ -987,7 +988,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,  		err = pskb_trim_rcsum(skb2, len);  		if (err) -			return err; +			goto err_out;  	}  	len -= ip_hdrlen(skb2); @@ -1009,7 +1010,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,  	case CHECKSUM_NONE:  		skb2->csum = 0;  		if (skb_checksum_complete(skb2)) -			return -EINVAL; +			goto out;  	}  	err = 0; @@ -1036,6 +1037,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,  out:  	__skb_push(skb2, offset); +err_out:  	if (skb2 != skb)  		kfree_skb(skb2);  	return err; @@ -1044,6 +1046,9 @@ out:  int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,  		     struct sk_buff *skb)  { +	BR_INPUT_SKB_CB(skb)->igmp = 0; +	BR_INPUT_SKB_CB(skb)->mrouters_only = 0; +  	if (br->multicast_disabled)  		return 0; @@ -1135,7 +1140,7 @@ void br_multicast_stop(struct net_bridge *br)  	if (mdb->old) {  		spin_unlock_bh(&br->multicast_lock); -		synchronize_rcu_bh(); +		rcu_barrier_bh();  		spin_lock_bh(&br->multicast_lock);  		WARN_ON(mdb->old);  	}  |