Переглянути джерело

kernel: backport upstream bridge multicast snooping fixes

Signed-off-by: Felix Fietkau <[email protected]>

SVN-Revision: 41817
Felix Fietkau 11 роки тому
батько
коміт
dd7650f67c

+ 848 - 0
target/linux/generic/patches-3.10/070-net_bridge_backports.patch

@@ -0,0 +1,848 @@
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -67,7 +67,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
+ 		}
+ 
+ 		mdst = br_mdb_get(br, skb, vid);
+-		if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
++		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
++		    br_multicast_querier_exists(br, eth_hdr(skb)))
+ 			br_multicast_deliver(mdst, skb);
+ 		else
+ 			br_flood_deliver(br, skb);
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -98,7 +98,8 @@ int br_handle_frame_finish(struct sk_buf
+ 		skb2 = skb;
+ 	else if (is_multicast_ether_addr(dest)) {
+ 		mdst = br_mdb_get(br, skb, vid);
+-		if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
++		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
++		    br_multicast_querier_exists(br, eth_hdr(skb))) {
+ 			if ((mdst && mdst->mglist) ||
+ 			    br_multicast_is_router(br))
+ 				skb2 = skb;
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -23,16 +23,19 @@
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+ #include <linux/timer.h>
++#include <linux/inetdevice.h>
+ #include <net/ip.h>
+ #if IS_ENABLED(CONFIG_IPV6)
+ #include <net/ipv6.h>
+ #include <net/mld.h>
+ #include <net/ip6_checksum.h>
++#include <net/addrconf.h>
+ #endif
+ 
+ #include "br_private.h"
+ 
+-static void br_multicast_start_querier(struct net_bridge *br);
++static void br_multicast_start_querier(struct net_bridge *br,
++				       struct bridge_mcast_query *query);
+ unsigned int br_mdb_rehash_seq;
+ 
+ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
+@@ -381,7 +384,8 @@ static struct sk_buff *br_ip4_multicast_
+ 	iph->frag_off = htons(IP_DF);
+ 	iph->ttl = 1;
+ 	iph->protocol = IPPROTO_IGMP;
+-	iph->saddr = 0;
++	iph->saddr = br->multicast_query_use_ifaddr ?
++		     inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0;
+ 	iph->daddr = htonl(INADDR_ALLHOSTS_GROUP);
+ 	((u8 *)&iph[1])[0] = IPOPT_RA;
+ 	((u8 *)&iph[1])[1] = 4;
+@@ -724,7 +728,7 @@ static int br_ip6_multicast_add_group(st
+ {
+ 	struct br_ip br_group;
+ 
+-	if (!ipv6_is_transient_multicast(group))
++	if (ipv6_addr_is_ll_all_nodes(group))
+ 		return 0;
+ 
+ 	br_group.u.ip6 = *group;
+@@ -756,20 +760,35 @@ static void br_multicast_local_router_ex
+ {
+ }
+ 
+-static void br_multicast_querier_expired(unsigned long data)
++static void br_multicast_querier_expired(struct net_bridge *br,
++					 struct bridge_mcast_query *query)
+ {
+-	struct net_bridge *br = (void *)data;
+-
+ 	spin_lock(&br->multicast_lock);
+ 	if (!netif_running(br->dev) || br->multicast_disabled)
+ 		goto out;
+ 
+-	br_multicast_start_querier(br);
++	br_multicast_start_querier(br, query);
+ 
+ out:
+ 	spin_unlock(&br->multicast_lock);
+ }
+ 
++static void br_ip4_multicast_querier_expired(unsigned long data)
++{
++	struct net_bridge *br = (void *)data;
++
++	br_multicast_querier_expired(br, &br->ip4_query);
++}
++
++#if IS_ENABLED(CONFIG_IPV6)
++static void br_ip6_multicast_querier_expired(unsigned long data)
++{
++	struct net_bridge *br = (void *)data;
++
++	br_multicast_querier_expired(br, &br->ip6_query);
++}
++#endif
++
+ static void __br_multicast_send_query(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      struct br_ip *ip)
+@@ -790,37 +809,45 @@ static void __br_multicast_send_query(st
+ }
+ 
+ static void br_multicast_send_query(struct net_bridge *br,
+-				    struct net_bridge_port *port, u32 sent)
++				    struct net_bridge_port *port,
++				    struct bridge_mcast_query *query)
+ {
+ 	unsigned long time;
+ 	struct br_ip br_group;
++	struct bridge_mcast_querier *querier = NULL;
+ 
+ 	if (!netif_running(br->dev) || br->multicast_disabled ||
+-	    !br->multicast_querier ||
+-	    timer_pending(&br->multicast_querier_timer))
++	    !br->multicast_querier)
+ 		return;
+ 
+ 	memset(&br_group.u, 0, sizeof(br_group.u));
+ 
+-	br_group.proto = htons(ETH_P_IP);
+-	__br_multicast_send_query(br, port, &br_group);
+-
++	if (port ? (query == &port->ip4_query) :
++		   (query == &br->ip4_query)) {
++		querier = &br->ip4_querier;
++		br_group.proto = htons(ETH_P_IP);
+ #if IS_ENABLED(CONFIG_IPV6)
+-	br_group.proto = htons(ETH_P_IPV6);
+-	__br_multicast_send_query(br, port, &br_group);
++	} else {
++		querier = &br->ip6_querier;
++		br_group.proto = htons(ETH_P_IPV6);
+ #endif
++	}
++
++	if (!querier || timer_pending(&querier->timer))
++		return;
++
++	__br_multicast_send_query(br, port, &br_group);
+ 
+ 	time = jiffies;
+-	time += sent < br->multicast_startup_query_count ?
++	time += query->startup_sent < br->multicast_startup_query_count ?
+ 		br->multicast_startup_query_interval :
+ 		br->multicast_query_interval;
+-	mod_timer(port ? &port->multicast_query_timer :
+-			 &br->multicast_query_timer, time);
++	mod_timer(&query->timer, time);
+ }
+ 
+-static void br_multicast_port_query_expired(unsigned long data)
++static void br_multicast_port_query_expired(struct net_bridge_port *port,
++					    struct bridge_mcast_query *query)
+ {
+-	struct net_bridge_port *port = (void *)data;
+ 	struct net_bridge *br = port->br;
+ 
+ 	spin_lock(&br->multicast_lock);
+@@ -828,25 +855,43 @@ static void br_multicast_port_query_expi
+ 	    port->state == BR_STATE_BLOCKING)
+ 		goto out;
+ 
+-	if (port->multicast_startup_queries_sent <
+-	    br->multicast_startup_query_count)
+-		port->multicast_startup_queries_sent++;
++	if (query->startup_sent < br->multicast_startup_query_count)
++		query->startup_sent++;
+ 
+-	br_multicast_send_query(port->br, port,
+-				port->multicast_startup_queries_sent);
++	br_multicast_send_query(port->br, port, query);
+ 
+ out:
+ 	spin_unlock(&br->multicast_lock);
+ }
+ 
++static void br_ip4_multicast_port_query_expired(unsigned long data)
++{
++	struct net_bridge_port *port = (void *)data;
++
++	br_multicast_port_query_expired(port, &port->ip4_query);
++}
++
++#if IS_ENABLED(CONFIG_IPV6)
++static void br_ip6_multicast_port_query_expired(unsigned long data)
++{
++	struct net_bridge_port *port = (void *)data;
++
++	br_multicast_port_query_expired(port, &port->ip6_query);
++}
++#endif
++
+ void br_multicast_add_port(struct net_bridge_port *port)
+ {
+ 	port->multicast_router = 1;
+ 
+ 	setup_timer(&port->multicast_router_timer, br_multicast_router_expired,
+ 		    (unsigned long)port);
+-	setup_timer(&port->multicast_query_timer,
+-		    br_multicast_port_query_expired, (unsigned long)port);
++	setup_timer(&port->ip4_query.timer, br_ip4_multicast_port_query_expired,
++		    (unsigned long)port);
++#if IS_ENABLED(CONFIG_IPV6)
++	setup_timer(&port->ip6_query.timer, br_ip6_multicast_port_query_expired,
++		    (unsigned long)port);
++#endif
+ }
+ 
+ void br_multicast_del_port(struct net_bridge_port *port)
+@@ -854,13 +899,13 @@ void br_multicast_del_port(struct net_br
+ 	del_timer_sync(&port->multicast_router_timer);
+ }
+ 
+-static void __br_multicast_enable_port(struct net_bridge_port *port)
++static void br_multicast_enable(struct bridge_mcast_query *query)
+ {
+-	port->multicast_startup_queries_sent = 0;
++	query->startup_sent = 0;
+ 
+-	if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 ||
+-	    del_timer(&port->multicast_query_timer))
+-		mod_timer(&port->multicast_query_timer, jiffies);
++	if (try_to_del_timer_sync(&query->timer) >= 0 ||
++	    del_timer(&query->timer))
++		mod_timer(&query->timer, jiffies);
+ }
+ 
+ void br_multicast_enable_port(struct net_bridge_port *port)
+@@ -871,7 +916,10 @@ void br_multicast_enable_port(struct net
+ 	if (br->multicast_disabled || !netif_running(br->dev))
+ 		goto out;
+ 
+-	__br_multicast_enable_port(port);
++	br_multicast_enable(&port->ip4_query);
++#if IS_ENABLED(CONFIG_IPV6)
++	br_multicast_enable(&port->ip6_query);
++#endif
+ 
+ out:
+ 	spin_unlock(&br->multicast_lock);
+@@ -890,7 +938,10 @@ void br_multicast_disable_port(struct ne
+ 	if (!hlist_unhashed(&port->rlist))
+ 		hlist_del_init_rcu(&port->rlist);
+ 	del_timer(&port->multicast_router_timer);
+-	del_timer(&port->multicast_query_timer);
++	del_timer(&port->ip4_query.timer);
++#if IS_ENABLED(CONFIG_IPV6)
++	del_timer(&port->ip6_query.timer);
++#endif
+ 	spin_unlock(&br->multicast_lock);
+ }
+ 
+@@ -1015,6 +1066,17 @@ static int br_ip6_multicast_mld2_report(
+ }
+ #endif
+ 
++static void
++br_multicast_update_querier_timer(struct net_bridge *br,
++				  struct bridge_mcast_querier *querier,
++				  unsigned long max_delay)
++{
++	if (!timer_pending(&querier->timer))
++		querier->delay_time = jiffies + max_delay;
++
++	mod_timer(&querier->timer, jiffies + br->multicast_querier_interval);
++}
++
+ /*
+  * Add port to rotuer_list
+  *  list is maintained ordered by pointer value
+@@ -1065,12 +1127,13 @@ timer:
+ 
+ static void br_multicast_query_received(struct net_bridge *br,
+ 					struct net_bridge_port *port,
+-					int saddr)
++					struct bridge_mcast_querier *querier,
++					int saddr,
++					unsigned long max_delay)
+ {
+ 	if (saddr)
+-		mod_timer(&br->multicast_querier_timer,
+-			  jiffies + br->multicast_querier_interval);
+-	else if (timer_pending(&br->multicast_querier_timer))
++		br_multicast_update_querier_timer(br, querier, max_delay);
++	else if (timer_pending(&querier->timer))
+ 		return;
+ 
+ 	br_multicast_mark_router(br, port);
+@@ -1097,8 +1160,6 @@ static int br_ip4_multicast_query(struct
+ 	    (port && port->state == BR_STATE_DISABLED))
+ 		goto out;
+ 
+-	br_multicast_query_received(br, port, !!iph->saddr);
+-
+ 	group = ih->group;
+ 
+ 	if (skb->len == sizeof(*ih)) {
+@@ -1122,6 +1183,9 @@ static int br_ip4_multicast_query(struct
+ 			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
+ 	}
+ 
++	br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
++				    max_delay);
++
+ 	if (!group)
+ 		goto out;
+ 
+@@ -1174,8 +1238,6 @@ static int br_ip6_multicast_query(struct
+ 	    (port && port->state == BR_STATE_DISABLED))
+ 		goto out;
+ 
+-	br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
+-
+ 	/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+ 	if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+ 		err = -EINVAL;
+@@ -1203,6 +1265,9 @@ static int br_ip6_multicast_query(struct
+ 		max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
+ 	}
+ 
++	br_multicast_query_received(br, port, &br->ip6_querier,
++				    !ipv6_addr_any(&ip6h->saddr), max_delay);
++
+ 	if (!group)
+ 		goto out;
+ 
+@@ -1235,7 +1300,9 @@ out:
+ 
+ static void br_multicast_leave_group(struct net_bridge *br,
+ 				     struct net_bridge_port *port,
+-				     struct br_ip *group)
++				     struct br_ip *group,
++				     struct bridge_mcast_querier *querier,
++				     struct bridge_mcast_query *query)
+ {
+ 	struct net_bridge_mdb_htable *mdb;
+ 	struct net_bridge_mdb_entry *mp;
+@@ -1246,7 +1313,7 @@ static void br_multicast_leave_group(str
+ 	spin_lock(&br->multicast_lock);
+ 	if (!netif_running(br->dev) ||
+ 	    (port && port->state == BR_STATE_DISABLED) ||
+-	    timer_pending(&br->multicast_querier_timer))
++	    timer_pending(&querier->timer))
+ 		goto out;
+ 
+ 	mdb = mlock_dereference(br->mdb, br);
+@@ -1254,6 +1321,31 @@ static void br_multicast_leave_group(str
+ 	if (!mp)
+ 		goto out;
+ 
++	if (br->multicast_querier) {
++		__br_multicast_send_query(br, port, &mp->addr);
++
++		time = jiffies + br->multicast_last_member_count *
++				 br->multicast_last_member_interval;
++
++		mod_timer(&query->timer, time);
++
++		for (p = mlock_dereference(mp->ports, br);
++		     p != NULL;
++		     p = mlock_dereference(p->next, br)) {
++			if (p->port != port)
++				continue;
++
++			if (!hlist_unhashed(&p->mglist) &&
++			    (timer_pending(&p->timer) ?
++			     time_after(p->timer.expires, time) :
++			     try_to_del_timer_sync(&p->timer) >= 0)) {
++				mod_timer(&p->timer, time);
++			}
++
++			break;
++		}
++	}
++
+ 	if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
+ 		struct net_bridge_port_group __rcu **pp;
+ 
+@@ -1306,7 +1398,6 @@ static void br_multicast_leave_group(str
+ 
+ 		break;
+ 	}
+-
+ out:
+ 	spin_unlock(&br->multicast_lock);
+ }
+@@ -1317,6 +1408,8 @@ static void br_ip4_multicast_leave_group
+ 					 __u16 vid)
+ {
+ 	struct br_ip br_group;
++	struct bridge_mcast_query *query = port ? &port->ip4_query :
++						  &br->ip4_query;
+ 
+ 	if (ipv4_is_local_multicast(group))
+ 		return;
+@@ -1325,7 +1418,7 @@ static void br_ip4_multicast_leave_group
+ 	br_group.proto = htons(ETH_P_IP);
+ 	br_group.vid = vid;
+ 
+-	br_multicast_leave_group(br, port, &br_group);
++	br_multicast_leave_group(br, port, &br_group, &br->ip4_querier, query);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -1335,15 +1428,18 @@ static void br_ip6_multicast_leave_group
+ 					 __u16 vid)
+ {
+ 	struct br_ip br_group;
++	struct bridge_mcast_query *query = port ? &port->ip6_query :
++						  &br->ip6_query;
+ 
+-	if (!ipv6_is_transient_multicast(group))
++
++	if (ipv6_addr_is_ll_all_nodes(group))
+ 		return;
+ 
+ 	br_group.u.ip6 = *group;
+ 	br_group.proto = htons(ETH_P_IPV6);
+ 	br_group.vid = vid;
+ 
+-	br_multicast_leave_group(br, port, &br_group);
++	br_multicast_leave_group(br, port, &br_group, &br->ip6_querier, query);
+ }
+ #endif
+ 
+@@ -1473,8 +1569,14 @@ static int br_multicast_ipv6_rcv(struct 
+ 	 *  - MLD has always Router Alert hop-by-hop option
+ 	 *  - But we do not support jumbrograms.
+ 	 */
+-	if (ip6h->version != 6 ||
+-	    ip6h->nexthdr != IPPROTO_HOPOPTS ||
++	if (ip6h->version != 6)
++		return 0;
++
++	/* Prevent flooding this packet if there is no listener present */
++	if (!ipv6_addr_is_ll_all_nodes(&ip6h->daddr))
++		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
++
++	if (ip6h->nexthdr != IPPROTO_HOPOPTS ||
+ 	    ip6h->payload_len == 0)
+ 		return 0;
+ 
+@@ -1605,19 +1707,32 @@ int br_multicast_rcv(struct net_bridge *
+ 	return 0;
+ }
+ 
+-static void br_multicast_query_expired(unsigned long data)
++static void br_multicast_query_expired(struct net_bridge *br,
++				       struct bridge_mcast_query *query)
++{
++	spin_lock(&br->multicast_lock);
++	if (query->startup_sent < br->multicast_startup_query_count)
++		query->startup_sent++;
++
++	br_multicast_send_query(br, NULL, query);
++	spin_unlock(&br->multicast_lock);
++}
++
++static void br_ip4_multicast_query_expired(unsigned long data)
+ {
+ 	struct net_bridge *br = (void *)data;
+ 
+-	spin_lock(&br->multicast_lock);
+-	if (br->multicast_startup_queries_sent <
+-	    br->multicast_startup_query_count)
+-		br->multicast_startup_queries_sent++;
++	br_multicast_query_expired(br, &br->ip4_query);
++}
+ 
+-	br_multicast_send_query(br, NULL, br->multicast_startup_queries_sent);
++#if IS_ENABLED(CONFIG_IPV6)
++static void br_ip6_multicast_query_expired(unsigned long data)
++{
++	struct net_bridge *br = (void *)data;
+ 
+-	spin_unlock(&br->multicast_lock);
++	br_multicast_query_expired(br, &br->ip6_query);
+ }
++#endif
+ 
+ void br_multicast_init(struct net_bridge *br)
+ {
+@@ -1626,6 +1741,7 @@ void br_multicast_init(struct net_bridge
+ 
+ 	br->multicast_router = 1;
+ 	br->multicast_querier = 0;
++	br->multicast_query_use_ifaddr = 0;
+ 	br->multicast_last_member_count = 2;
+ 	br->multicast_startup_query_count = 2;
+ 
+@@ -1636,23 +1752,43 @@ void br_multicast_init(struct net_bridge
+ 	br->multicast_querier_interval = 255 * HZ;
+ 	br->multicast_membership_interval = 260 * HZ;
+ 
++	br->ip4_querier.delay_time = 0;
++#if IS_ENABLED(CONFIG_IPV6)
++	br->ip6_querier.delay_time = 0;
++#endif
++
+ 	spin_lock_init(&br->multicast_lock);
+ 	setup_timer(&br->multicast_router_timer,
+ 		    br_multicast_local_router_expired, 0);
+-	setup_timer(&br->multicast_querier_timer,
+-		    br_multicast_querier_expired, (unsigned long)br);
+-	setup_timer(&br->multicast_query_timer, br_multicast_query_expired,
++	setup_timer(&br->ip4_querier.timer, br_ip4_multicast_querier_expired,
+ 		    (unsigned long)br);
++	setup_timer(&br->ip4_query.timer, br_ip4_multicast_query_expired,
++		    (unsigned long)br);
++#if IS_ENABLED(CONFIG_IPV6)
++	setup_timer(&br->ip6_querier.timer, br_ip6_multicast_querier_expired,
++		    (unsigned long)br);
++	setup_timer(&br->ip6_query.timer, br_ip6_multicast_query_expired,
++		    (unsigned long)br);
++#endif
+ }
+ 
+-void br_multicast_open(struct net_bridge *br)
++static void __br_multicast_open(struct net_bridge *br,
++				struct bridge_mcast_query *query)
+ {
+-	br->multicast_startup_queries_sent = 0;
++	query->startup_sent = 0;
+ 
+ 	if (br->multicast_disabled)
+ 		return;
+ 
+-	mod_timer(&br->multicast_query_timer, jiffies);
++	mod_timer(&query->timer, jiffies);
++}
++
++void br_multicast_open(struct net_bridge *br)
++{
++	__br_multicast_open(br, &br->ip4_query);
++#if IS_ENABLED(CONFIG_IPV6)
++	__br_multicast_open(br, &br->ip6_query);
++#endif
+ }
+ 
+ void br_multicast_stop(struct net_bridge *br)
+@@ -1664,8 +1800,12 @@ void br_multicast_stop(struct net_bridge
+ 	int i;
+ 
+ 	del_timer_sync(&br->multicast_router_timer);
+-	del_timer_sync(&br->multicast_querier_timer);
+-	del_timer_sync(&br->multicast_query_timer);
++	del_timer_sync(&br->ip4_querier.timer);
++	del_timer_sync(&br->ip4_query.timer);
++#if IS_ENABLED(CONFIG_IPV6)
++	del_timer_sync(&br->ip6_querier.timer);
++	del_timer_sync(&br->ip6_query.timer);
++#endif
+ 
+ 	spin_lock_bh(&br->multicast_lock);
+ 	mdb = mlock_dereference(br->mdb, br);
+@@ -1767,18 +1907,24 @@ unlock:
+ 	return err;
+ }
+ 
+-static void br_multicast_start_querier(struct net_bridge *br)
++static void br_multicast_start_querier(struct net_bridge *br,
++				       struct bridge_mcast_query *query)
+ {
+ 	struct net_bridge_port *port;
+ 
+-	br_multicast_open(br);
++	__br_multicast_open(br, query);
+ 
+ 	list_for_each_entry(port, &br->port_list, list) {
+ 		if (port->state == BR_STATE_DISABLED ||
+ 		    port->state == BR_STATE_BLOCKING)
+ 			continue;
+ 
+-		__br_multicast_enable_port(port);
++		if (query == &br->ip4_query)
++			br_multicast_enable(&port->ip4_query);
++#if IS_ENABLED(CONFIG_IPV6)
++		else
++			br_multicast_enable(&port->ip6_query);
++#endif
+ 	}
+ }
+ 
+@@ -1813,7 +1959,10 @@ rollback:
+ 			goto rollback;
+ 	}
+ 
+-	br_multicast_start_querier(br);
++	br_multicast_start_querier(br, &br->ip4_query);
++#if IS_ENABLED(CONFIG_IPV6)
++	br_multicast_start_querier(br, &br->ip6_query);
++#endif
+ 
+ unlock:
+ 	spin_unlock_bh(&br->multicast_lock);
+@@ -1823,6 +1972,8 @@ unlock:
+ 
+ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
+ {
++	unsigned long max_delay;
++
+ 	val = !!val;
+ 
+ 	spin_lock_bh(&br->multicast_lock);
+@@ -1830,8 +1981,22 @@ int br_multicast_set_querier(struct net_
+ 		goto unlock;
+ 
+ 	br->multicast_querier = val;
+-	if (val)
+-		br_multicast_start_querier(br);
++	if (!val)
++		goto unlock;
++
++	max_delay = br->multicast_query_response_interval;
++
++	if (!timer_pending(&br->ip4_querier.timer))
++		br->ip4_querier.delay_time = jiffies + max_delay;
++
++	br_multicast_start_querier(br, &br->ip4_query);
++
++#if IS_ENABLED(CONFIG_IPV6)
++	if (!timer_pending(&br->ip6_querier.timer))
++		br->ip6_querier.delay_time = jiffies + max_delay;
++
++	br_multicast_start_querier(br, &br->ip6_query);
++#endif
+ 
+ unlock:
+ 	spin_unlock_bh(&br->multicast_lock);
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -66,6 +66,20 @@ struct br_ip
+ 	__u16		vid;
+ };
+ 
++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
++/* our own querier */
++struct bridge_mcast_query {
++	struct timer_list	timer;
++	u32			startup_sent;
++};
++
++/* other querier */
++struct bridge_mcast_querier {
++	struct timer_list		timer;
++	unsigned long			delay_time;
++};
++#endif
++
+ struct net_port_vlans {
+ 	u16				port_idx;
+ 	u16				pvid;
+@@ -159,10 +173,12 @@ struct net_bridge_port
+ #define BR_ADMIN_COST		0x00000010
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+-	u32				multicast_startup_queries_sent;
++	struct bridge_mcast_query	ip4_query;
++#if IS_ENABLED(CONFIG_IPV6)
++	struct bridge_mcast_query	ip6_query;
++#endif /* IS_ENABLED(CONFIG_IPV6) */
+ 	unsigned char			multicast_router;
+ 	struct timer_list		multicast_router_timer;
+-	struct timer_list		multicast_query_timer;
+ 	struct hlist_head		mglist;
+ 	struct hlist_node		rlist;
+ #endif
+@@ -246,12 +262,12 @@ struct net_bridge
+ 
+ 	u8				multicast_disabled:1;
+ 	u8				multicast_querier:1;
++	u8				multicast_query_use_ifaddr:1;
+ 
+ 	u32				hash_elasticity;
+ 	u32				hash_max;
+ 
+ 	u32				multicast_last_member_count;
+-	u32				multicast_startup_queries_sent;
+ 	u32				multicast_startup_query_count;
+ 
+ 	unsigned long			multicast_last_member_interval;
+@@ -266,8 +282,12 @@ struct net_bridge
+ 	struct hlist_head		router_list;
+ 
+ 	struct timer_list		multicast_router_timer;
+-	struct timer_list		multicast_querier_timer;
+-	struct timer_list		multicast_query_timer;
++	struct bridge_mcast_querier	ip4_querier;
++	struct bridge_mcast_query	ip4_query;
++#if IS_ENABLED(CONFIG_IPV6)
++	struct bridge_mcast_querier	ip6_querier;
++	struct bridge_mcast_query	ip6_query;
++#endif /* IS_ENABLED(CONFIG_IPV6) */
+ #endif
+ 
+ 	struct timer_list		hello_timer;
+@@ -477,22 +497,35 @@ extern void br_mdb_notify(struct net_dev
+ #define mlock_dereference(X, br) \
+ 	rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
+ 
+-#if IS_ENABLED(CONFIG_IPV6)
+-#include <net/addrconf.h>
+-static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
+-{
+-	if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr))
+-		return 1;
+-	return 0;
+-}
+-#endif
+-
+ static inline bool br_multicast_is_router(struct net_bridge *br)
+ {
+ 	return br->multicast_router == 2 ||
+ 	       (br->multicast_router == 1 &&
+ 		timer_pending(&br->multicast_router_timer));
+ }
++
++static inline bool
++__br_multicast_querier_exists(struct net_bridge *br,
++			      struct bridge_mcast_querier *querier)
++{
++	return time_is_before_jiffies(querier->delay_time) &&
++	       (br->multicast_querier || timer_pending(&querier->timer));
++}
++
++static inline bool br_multicast_querier_exists(struct net_bridge *br,
++					       struct ethhdr *eth)
++{
++	switch (eth->h_proto) {
++	case (htons(ETH_P_IP)):
++		return __br_multicast_querier_exists(br, &br->ip4_querier);
++#if IS_ENABLED(CONFIG_IPV6)
++	case (htons(ETH_P_IPV6)):
++		return __br_multicast_querier_exists(br, &br->ip6_querier);
++#endif
++	default:
++		return false;
++	}
++}
+ #else
+ static inline int br_multicast_rcv(struct net_bridge *br,
+ 				   struct net_bridge_port *port,
+@@ -549,6 +582,11 @@ static inline bool br_multicast_is_route
+ {
+ 	return 0;
+ }
++static inline bool br_multicast_querier_exists(struct net_bridge *br,
++					       struct ethhdr *eth)
++{
++	return false;
++}
+ static inline void br_mdb_init(void)
+ {
+ }
+--- a/net/bridge/br_sysfs_br.c
++++ b/net/bridge/br_sysfs_br.c
+@@ -375,6 +375,31 @@ static ssize_t store_multicast_snooping(
+ static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
+ 		   show_multicast_snooping, store_multicast_snooping);
+ 
++static ssize_t show_multicast_query_use_ifaddr(struct device *d,
++				      struct device_attribute *attr,
++				      char *buf)
++{
++	struct net_bridge *br = to_bridge(d);
++	return sprintf(buf, "%d\n", br->multicast_query_use_ifaddr);
++}
++
++static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val)
++{
++	br->multicast_query_use_ifaddr = !!val;
++	return 0;
++}
++
++static ssize_t
++store_multicast_query_use_ifaddr(struct device *d,
++				 struct device_attribute *attr,
++				 const char *buf, size_t len)
++{
++	return store_bridge_parm(d, buf, len, set_query_use_ifaddr);
++}
++static DEVICE_ATTR(multicast_query_use_ifaddr, S_IRUGO | S_IWUSR,
++		   show_multicast_query_use_ifaddr,
++		   store_multicast_query_use_ifaddr);
++
+ static ssize_t show_multicast_querier(struct device *d,
+ 				      struct device_attribute *attr,
+ 				      char *buf)
+@@ -734,6 +759,7 @@ static struct attribute *bridge_attrs[] 
+ 	&dev_attr_multicast_router.attr,
+ 	&dev_attr_multicast_snooping.attr,
+ 	&dev_attr_multicast_querier.attr,
++	&dev_attr_multicast_query_use_ifaddr.attr,
+ 	&dev_attr_hash_elasticity.attr,
+ 	&dev_attr_hash_max.attr,
+ 	&dev_attr_multicast_last_member_count.attr,
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -9,6 +9,7 @@
+ #include <net/netlink.h>
+ #if IS_ENABLED(CONFIG_IPV6)
+ #include <net/ipv6.h>
++#include <net/addrconf.h>
+ #endif
+ 
+ #include "br_private.h"
+@@ -253,7 +254,7 @@ static bool is_valid_mdb_entry(struct br
+ 			return false;
+ #if IS_ENABLED(CONFIG_IPV6)
+ 	} else if (entry->addr.proto == htons(ETH_P_IPV6)) {
+-		if (!ipv6_is_transient_multicast(&entry->addr.u.ip6))
++		if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6))
+ 			return false;
+ #endif
+ 	} else
+@@ -414,16 +415,20 @@ static int __br_mdb_del(struct net_bridg
+ 	if (!netif_running(br->dev) || br->multicast_disabled)
+ 		return -EINVAL;
+ 
+-	if (timer_pending(&br->multicast_querier_timer))
+-		return -EBUSY;
+-
+ 	ip.proto = entry->addr.proto;
+-	if (ip.proto == htons(ETH_P_IP))
++	if (ip.proto == htons(ETH_P_IP)) {
++		if (timer_pending(&br->ip4_querier.timer))
++			return -EBUSY;
++
+ 		ip.u.ip4 = entry->addr.u.ip4;
+ #if IS_ENABLED(CONFIG_IPV6)
+-	else
++	} else {
++		if (timer_pending(&br->ip6_querier.timer))
++			return -EBUSY;
++
+ 		ip.u.ip6 = entry->addr.u.ip6;
+ #endif
++	}
+ 
+ 	spin_lock_bh(&br->multicast_lock);
+ 	mdb = mlock_dereference(br->mdb, br);

+ 2 - 2
target/linux/generic/patches-3.10/120-bridge_allow_receiption_on_disabled_port.patch

@@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <[email protected]>
 
 
 --- a/net/bridge/br_input.c
 --- a/net/bridge/br_input.c
 +++ b/net/bridge/br_input.c
 +++ b/net/bridge/br_input.c
-@@ -139,10 +139,14 @@ drop:
+@@ -140,10 +140,14 @@ drop:
  static int br_handle_local_finish(struct sk_buff *skb)
  static int br_handle_local_finish(struct sk_buff *skb)
  {
  {
  	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
  	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
@@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <[email protected]>
  	return 0;	 /* process further */
  	return 0;	 /* process further */
  }
  }
  
  
-@@ -212,6 +216,18 @@ rx_handler_result_t br_handle_frame(stru
+@@ -213,6 +217,18 @@ rx_handler_result_t br_handle_frame(stru
  
  
  forward:
  forward:
  	switch (p->state) {
  	switch (p->state) {

+ 3 - 3
target/linux/generic/patches-3.10/642-bridge_port_isolate.patch

@@ -1,13 +1,13 @@
 --- a/net/bridge/br_private.h
 --- a/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
-@@ -157,6 +157,7 @@ struct net_bridge_port
+@@ -171,6 +171,7 @@ struct net_bridge_port
  #define BR_ROOT_BLOCK		0x00000004
  #define BR_ROOT_BLOCK		0x00000004
  #define BR_MULTICAST_FAST_LEAVE	0x00000008
  #define BR_MULTICAST_FAST_LEAVE	0x00000008
  #define BR_ADMIN_COST		0x00000010
  #define BR_ADMIN_COST		0x00000010
 +#define BR_ISOLATE_MODE		0x00000020
 +#define BR_ISOLATE_MODE		0x00000020
  
  
  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
- 	u32				multicast_startup_queries_sent;
+ 	struct bridge_mcast_query	ip4_query;
 --- a/net/bridge/br_sysfs_if.c
 --- a/net/bridge/br_sysfs_if.c
 +++ b/net/bridge/br_sysfs_if.c
 +++ b/net/bridge/br_sysfs_if.c
 @@ -159,6 +159,22 @@ BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPI
 @@ -159,6 +159,22 @@ BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPI
@@ -43,7 +43,7 @@
  
  
 --- a/net/bridge/br_input.c
 --- a/net/bridge/br_input.c
 +++ b/net/bridge/br_input.c
 +++ b/net/bridge/br_input.c
-@@ -114,8 +114,8 @@ int br_handle_frame_finish(struct sk_buf
+@@ -115,8 +115,8 @@ int br_handle_frame_finish(struct sk_buf
  			skb2 = skb;
  			skb2 = skb;
  
  
  		br->dev->stats.multicast++;
  		br->dev->stats.multicast++;

+ 1 - 1
target/linux/generic/patches-3.10/643-bridge_remove_ipv6_dependency.patch

@@ -25,7 +25,7 @@
  	  Ethernet bridge, which means that the different Ethernet segments it
  	  Ethernet bridge, which means that the different Ethernet segments it
 --- a/net/ipv6/Makefile
 --- a/net/ipv6/Makefile
 +++ b/net/ipv6/Makefile
 +++ b/net/ipv6/Makefile
-@@ -44,3 +44,4 @@ obj-y += addrconf_core.o exthdrs_core.o
+@@ -44,3 +44,4 @@ obj-y += addrconf_core.o exthdrs_core.o 
  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
  
  
  obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
  obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o

+ 5 - 5
target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch

@@ -38,7 +38,7 @@
  		       netif_receive_skb);
  		       netif_receive_skb);
  }
  }
  
  
-@@ -209,7 +209,7 @@ rx_handler_result_t br_handle_frame(stru
+@@ -210,7 +210,7 @@ rx_handler_result_t br_handle_frame(stru
  		}
  		}
  
  
  		/* Deliver packet to local host only */
  		/* Deliver packet to local host only */
@@ -47,7 +47,7 @@
  			    NULL, br_handle_local_finish)) {
  			    NULL, br_handle_local_finish)) {
  			return RX_HANDLER_CONSUMED; /* consumed by filter */
  			return RX_HANDLER_CONSUMED; /* consumed by filter */
  		} else {
  		} else {
-@@ -224,7 +224,7 @@ forward:
+@@ -225,7 +225,7 @@ forward:
  		if (ether_addr_equal(p->br->dev->dev_addr, dest))
  		if (ether_addr_equal(p->br->dev->dev_addr, dest))
  			skb->pkt_type = PACKET_HOST;
  			skb->pkt_type = PACKET_HOST;
  
  
@@ -56,7 +56,7 @@
  			br_handle_local_finish))
  			br_handle_local_finish))
  			break;
  			break;
  
  
-@@ -246,7 +246,7 @@ forward:
+@@ -247,7 +247,7 @@ forward:
  		if (ether_addr_equal(p->br->dev->dev_addr, dest))
  		if (ether_addr_equal(p->br->dev->dev_addr, dest))
  			skb->pkt_type = PACKET_HOST;
  			skb->pkt_type = PACKET_HOST;
  
  
@@ -67,7 +67,7 @@
  	default:
  	default:
 --- a/net/bridge/br_multicast.c
 --- a/net/bridge/br_multicast.c
 +++ b/net/bridge/br_multicast.c
 +++ b/net/bridge/br_multicast.c
-@@ -783,7 +783,7 @@ static void __br_multicast_send_query(st
+@@ -802,7 +802,7 @@ static void __br_multicast_send_query(st
  	if (port) {
  	if (port) {
  		__skb_push(skb, sizeof(struct ethhdr));
  		__skb_push(skb, sizeof(struct ethhdr));
  		skb->dev = port->dev;
  		skb->dev = port->dev;
@@ -96,7 +96,7 @@
  	if (vlan_tx_tag_present(skb))
  	if (vlan_tx_tag_present(skb))
 --- a/net/bridge/br_private.h
 --- a/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
-@@ -696,15 +696,29 @@ static inline u16 br_get_pvid(const stru
+@@ -734,15 +734,29 @@ static inline u16 br_get_pvid(const stru
  
  
  /* br_netfilter.c */
  /* br_netfilter.c */
  #ifdef CONFIG_BRIDGE_NETFILTER
  #ifdef CONFIG_BRIDGE_NETFILTER

+ 39 - 37
target/linux/generic/patches-3.10/645-bridge_multicast_to_unicast.patch

@@ -1,6 +1,6 @@
 --- a/net/bridge/br_multicast.c
 --- a/net/bridge/br_multicast.c
 +++ b/net/bridge/br_multicast.c
 +++ b/net/bridge/br_multicast.c
-@@ -630,7 +630,8 @@ struct net_bridge_port_group *br_multica
+@@ -634,7 +634,8 @@ struct net_bridge_port_group *br_multica
  			struct net_bridge_port *port,
  			struct net_bridge_port *port,
  			struct br_ip *group,
  			struct br_ip *group,
  			struct net_bridge_port_group __rcu *next,
  			struct net_bridge_port_group __rcu *next,
@@ -10,7 +10,7 @@
  {
  {
  	struct net_bridge_port_group *p;
  	struct net_bridge_port_group *p;
  
  
-@@ -645,12 +646,33 @@ struct net_bridge_port_group *br_multica
+@@ -649,12 +650,33 @@ struct net_bridge_port_group *br_multica
  	hlist_add_head(&p->mglist, &port->mglist);
  	hlist_add_head(&p->mglist, &port->mglist);
  	setup_timer(&p->timer, br_multicast_port_group_expired,
  	setup_timer(&p->timer, br_multicast_port_group_expired,
  		    (unsigned long)p);
  		    (unsigned long)p);
@@ -45,7 +45,7 @@
  {
  {
  	struct net_bridge_mdb_entry *mp;
  	struct net_bridge_mdb_entry *mp;
  	struct net_bridge_port_group *p;
  	struct net_bridge_port_group *p;
-@@ -677,13 +699,13 @@ static int br_multicast_add_group(struct
+@@ -681,13 +703,13 @@ static int br_multicast_add_group(struct
  	for (pp = &mp->ports;
  	for (pp = &mp->ports;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     pp = &p->next) {
  	     pp = &p->next) {
@@ -61,7 +61,7 @@
  	if (unlikely(!p))
  	if (unlikely(!p))
  		goto err;
  		goto err;
  	rcu_assign_pointer(*pp, p);
  	rcu_assign_pointer(*pp, p);
-@@ -702,7 +724,7 @@ err:
+@@ -706,7 +728,7 @@ err:
  static int br_ip4_multicast_add_group(struct net_bridge *br,
  static int br_ip4_multicast_add_group(struct net_bridge *br,
  				      struct net_bridge_port *port,
  				      struct net_bridge_port *port,
  				      __be32 group,
  				      __be32 group,
@@ -70,7 +70,7 @@
  {
  {
  	struct br_ip br_group;
  	struct br_ip br_group;
  
  
-@@ -713,14 +735,14 @@ static int br_ip4_multicast_add_group(st
+@@ -717,14 +739,14 @@ static int br_ip4_multicast_add_group(st
  	br_group.proto = htons(ETH_P_IP);
  	br_group.proto = htons(ETH_P_IP);
  	br_group.vid = vid;
  	br_group.vid = vid;
  
  
@@ -87,7 +87,7 @@
  {
  {
  	struct br_ip br_group;
  	struct br_ip br_group;
  
  
-@@ -731,7 +753,7 @@ static int br_ip6_multicast_add_group(st
+@@ -735,7 +757,7 @@ static int br_ip6_multicast_add_group(st
  	br_group.proto = htons(ETH_P_IPV6);
  	br_group.proto = htons(ETH_P_IPV6);
  	br_group.vid = vid;
  	br_group.vid = vid;
  
  
@@ -96,7 +96,7 @@
  }
  }
  #endif
  #endif
  
  
-@@ -898,6 +920,7 @@ static int br_ip4_multicast_igmp3_report
+@@ -949,6 +971,7 @@ static int br_ip4_multicast_igmp3_report
  					 struct net_bridge_port *port,
  					 struct net_bridge_port *port,
  					 struct sk_buff *skb)
  					 struct sk_buff *skb)
  {
  {
@@ -104,7 +104,7 @@
  	struct igmpv3_report *ih;
  	struct igmpv3_report *ih;
  	struct igmpv3_grec *grec;
  	struct igmpv3_grec *grec;
  	int i;
  	int i;
-@@ -943,7 +966,7 @@ static int br_ip4_multicast_igmp3_report
+@@ -994,7 +1017,7 @@ static int br_ip4_multicast_igmp3_report
  			continue;
  			continue;
  		}
  		}
  
  
@@ -113,7 +113,7 @@
  		if (err)
  		if (err)
  			break;
  			break;
  	}
  	}
-@@ -956,6 +979,7 @@ static int br_ip6_multicast_mld2_report(
+@@ -1007,6 +1030,7 @@ static int br_ip6_multicast_mld2_report(
  					struct net_bridge_port *port,
  					struct net_bridge_port *port,
  					struct sk_buff *skb)
  					struct sk_buff *skb)
  {
  {
@@ -121,7 +121,7 @@
  	struct icmp6hdr *icmp6h;
  	struct icmp6hdr *icmp6h;
  	struct mld2_grec *grec;
  	struct mld2_grec *grec;
  	int i;
  	int i;
-@@ -1006,7 +1030,7 @@ static int br_ip6_multicast_mld2_report(
+@@ -1057,7 +1081,7 @@ static int br_ip6_multicast_mld2_report(
  		}
  		}
  
  
  		err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
  		err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
@@ -130,17 +130,17 @@
  		if (!err)
  		if (!err)
  			break;
  			break;
  	}
  	}
-@@ -1235,7 +1259,8 @@ out:
- 
- static void br_multicast_leave_group(struct net_bridge *br,
+@@ -1302,7 +1326,8 @@ static void br_multicast_leave_group(str
  				     struct net_bridge_port *port,
  				     struct net_bridge_port *port,
--				     struct br_ip *group)
-+				     struct br_ip *group,
+ 				     struct br_ip *group,
+ 				     struct bridge_mcast_querier *querier,
+-				     struct bridge_mcast_query *query)
++				     struct bridge_mcast_query *query,
 +				     const unsigned char *src)
 +				     const unsigned char *src)
  {
  {
  	struct net_bridge_mdb_htable *mdb;
  	struct net_bridge_mdb_htable *mdb;
  	struct net_bridge_mdb_entry *mp;
  	struct net_bridge_mdb_entry *mp;
-@@ -1260,7 +1285,7 @@ static void br_multicast_leave_group(str
+@@ -1352,7 +1377,7 @@ static void br_multicast_leave_group(str
  		for (pp = &mp->ports;
  		for (pp = &mp->ports;
  		     (p = mlock_dereference(*pp, br)) != NULL;
  		     (p = mlock_dereference(*pp, br)) != NULL;
  		     pp = &p->next) {
  		     pp = &p->next) {
@@ -149,7 +149,7 @@
  				continue;
  				continue;
  
  
  			rcu_assign_pointer(*pp, p->next);
  			rcu_assign_pointer(*pp, p->next);
-@@ -1294,7 +1319,7 @@ static void br_multicast_leave_group(str
+@@ -1386,7 +1411,7 @@ static void br_multicast_leave_group(str
  	for (p = mlock_dereference(mp->ports, br);
  	for (p = mlock_dereference(mp->ports, br);
  	     p != NULL;
  	     p != NULL;
  	     p = mlock_dereference(p->next, br)) {
  	     p = mlock_dereference(p->next, br)) {
@@ -158,7 +158,7 @@
  			continue;
  			continue;
  
  
  		if (!hlist_unhashed(&p->mglist) &&
  		if (!hlist_unhashed(&p->mglist) &&
-@@ -1313,8 +1338,8 @@ out:
+@@ -1404,8 +1429,8 @@ out:
  
  
  static void br_ip4_multicast_leave_group(struct net_bridge *br,
  static void br_ip4_multicast_leave_group(struct net_bridge *br,
  					 struct net_bridge_port *port,
  					 struct net_bridge_port *port,
@@ -168,13 +168,14 @@
 +					 const unsigned char *src)
 +					 const unsigned char *src)
  {
  {
  	struct br_ip br_group;
  	struct br_ip br_group;
- 
-@@ -1325,14 +1350,14 @@ static void br_ip4_multicast_leave_group
+ 	struct bridge_mcast_query *query = port ? &port->ip4_query :
+@@ -1418,14 +1443,15 @@ static void br_ip4_multicast_leave_group
  	br_group.proto = htons(ETH_P_IP);
  	br_group.proto = htons(ETH_P_IP);
  	br_group.vid = vid;
  	br_group.vid = vid;
  
  
--	br_multicast_leave_group(br, port, &br_group);
-+	br_multicast_leave_group(br, port, &br_group, src);
+-	br_multicast_leave_group(br, port, &br_group, &br->ip4_querier, query);
++	br_multicast_leave_group(br, port, &br_group, &br->ip4_querier, query,
++				 src);
  }
  }
  
  
  #if IS_ENABLED(CONFIG_IPV6)
  #if IS_ENABLED(CONFIG_IPV6)
@@ -185,17 +186,18 @@
 +					 __u16 vid, const unsigned char *src)
 +					 __u16 vid, const unsigned char *src)
  {
  {
  	struct br_ip br_group;
  	struct br_ip br_group;
- 
-@@ -1343,7 +1368,7 @@ static void br_ip6_multicast_leave_group
+ 	struct bridge_mcast_query *query = port ? &port->ip6_query :
+@@ -1439,7 +1465,8 @@ static void br_ip6_multicast_leave_group
  	br_group.proto = htons(ETH_P_IPV6);
  	br_group.proto = htons(ETH_P_IPV6);
  	br_group.vid = vid;
  	br_group.vid = vid;
  
  
--	br_multicast_leave_group(br, port, &br_group);
-+	br_multicast_leave_group(br, port, &br_group, src);
+-	br_multicast_leave_group(br, port, &br_group, &br->ip6_querier, query);
++	br_multicast_leave_group(br, port, &br_group, &br->ip6_querier, query,
++				 src);
  }
  }
  #endif
  #endif
  
  
-@@ -1351,6 +1376,7 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1447,6 +1474,7 @@ static int br_multicast_ipv4_rcv(struct 
  				 struct net_bridge_port *port,
  				 struct net_bridge_port *port,
  				 struct sk_buff *skb)
  				 struct sk_buff *skb)
  {
  {
@@ -203,7 +205,7 @@
  	struct sk_buff *skb2 = skb;
  	struct sk_buff *skb2 = skb;
  	const struct iphdr *iph;
  	const struct iphdr *iph;
  	struct igmphdr *ih;
  	struct igmphdr *ih;
-@@ -1426,7 +1452,7 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1522,7 +1550,7 @@ static int br_multicast_ipv4_rcv(struct 
  	case IGMP_HOST_MEMBERSHIP_REPORT:
  	case IGMP_HOST_MEMBERSHIP_REPORT:
  	case IGMPV2_HOST_MEMBERSHIP_REPORT:
  	case IGMPV2_HOST_MEMBERSHIP_REPORT:
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
@@ -212,7 +214,7 @@
  		break;
  		break;
  	case IGMPV3_HOST_MEMBERSHIP_REPORT:
  	case IGMPV3_HOST_MEMBERSHIP_REPORT:
  		err = br_ip4_multicast_igmp3_report(br, port, skb2);
  		err = br_ip4_multicast_igmp3_report(br, port, skb2);
-@@ -1435,7 +1461,7 @@ static int br_multicast_ipv4_rcv(struct
+@@ -1531,7 +1559,7 @@ static int br_multicast_ipv4_rcv(struct 
  		err = br_ip4_multicast_query(br, port, skb2);
  		err = br_ip4_multicast_query(br, port, skb2);
  		break;
  		break;
  	case IGMP_HOST_LEAVE_MESSAGE:
  	case IGMP_HOST_LEAVE_MESSAGE:
@@ -221,7 +223,7 @@
  		break;
  		break;
  	}
  	}
  
  
-@@ -1452,6 +1478,7 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1548,6 +1576,7 @@ static int br_multicast_ipv6_rcv(struct 
  				 struct net_bridge_port *port,
  				 struct net_bridge_port *port,
  				 struct sk_buff *skb)
  				 struct sk_buff *skb)
  {
  {
@@ -229,7 +231,7 @@
  	struct sk_buff *skb2;
  	struct sk_buff *skb2;
  	const struct ipv6hdr *ip6h;
  	const struct ipv6hdr *ip6h;
  	u8 icmp6_type;
  	u8 icmp6_type;
-@@ -1557,7 +1584,8 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1659,7 +1688,8 @@ static int br_multicast_ipv6_rcv(struct 
  		}
  		}
  		mld = (struct mld_msg *)skb_transport_header(skb2);
  		mld = (struct mld_msg *)skb_transport_header(skb2);
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
@@ -239,7 +241,7 @@
  		break;
  		break;
  	    }
  	    }
  	case ICMPV6_MLD2_REPORT:
  	case ICMPV6_MLD2_REPORT:
-@@ -1574,7 +1602,7 @@ static int br_multicast_ipv6_rcv(struct
+@@ -1676,7 +1706,7 @@ static int br_multicast_ipv6_rcv(struct 
  			goto out;
  			goto out;
  		}
  		}
  		mld = (struct mld_msg *)skb_transport_header(skb2);
  		mld = (struct mld_msg *)skb_transport_header(skb2);
@@ -250,7 +252,7 @@
  
  
 --- a/net/bridge/br_private.h
 --- a/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
 +++ b/net/bridge/br_private.h
-@@ -101,6 +101,9 @@ struct net_bridge_port_group {
+@@ -115,6 +115,9 @@ struct net_bridge_port_group {
  	struct timer_list		timer;
  	struct timer_list		timer;
  	struct br_ip			addr;
  	struct br_ip			addr;
  	unsigned char			state;
  	unsigned char			state;
@@ -260,15 +262,15 @@
  };
  };
  
  
  struct net_bridge_mdb_entry
  struct net_bridge_mdb_entry
-@@ -158,6 +161,7 @@ struct net_bridge_port
+@@ -172,6 +175,7 @@ struct net_bridge_port
  #define BR_MULTICAST_FAST_LEAVE	0x00000008
  #define BR_MULTICAST_FAST_LEAVE	0x00000008
  #define BR_ADMIN_COST		0x00000010
  #define BR_ADMIN_COST		0x00000010
  #define BR_ISOLATE_MODE		0x00000020
  #define BR_ISOLATE_MODE		0x00000020
 +#define BR_MULTICAST_TO_UCAST	0x00000040
 +#define BR_MULTICAST_TO_UCAST	0x00000040
  
  
  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
- 	u32				multicast_startup_queries_sent;
-@@ -469,7 +473,8 @@ extern struct net_bridge_port_group *br_
+ 	struct bridge_mcast_query	ip4_query;
+@@ -489,7 +493,8 @@ extern struct net_bridge_port_group *br_
  				struct net_bridge_port *port,
  				struct net_bridge_port *port,
  				struct br_ip *group,
  				struct br_ip *group,
  				struct net_bridge_port_group *next,
  				struct net_bridge_port_group *next,
@@ -280,7 +282,7 @@
  extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
  extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
 --- a/net/bridge/br_mdb.c
 --- a/net/bridge/br_mdb.c
 +++ b/net/bridge/br_mdb.c
 +++ b/net/bridge/br_mdb.c
-@@ -340,7 +340,7 @@ static int br_mdb_add_group(struct net_b
+@@ -341,7 +341,7 @@ static int br_mdb_add_group(struct net_b
  			break;
  			break;
  	}
  	}
  
  

+ 1 - 1
target/linux/generic/patches-3.10/657-qdisc_reduce_truesize.patch

@@ -24,7 +24,7 @@ commont qdiscs.
  	}
  	}
 --- a/net/sched/sch_fifo.c
 --- a/net/sched/sch_fifo.c
 +++ b/net/sched/sch_fifo.c
 +++ b/net/sched/sch_fifo.c
-@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff
+@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff 
  
  
  static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch)
  static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch)
  {
  {