]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.6.4/bridge-fix-ipv6-mc-snooping-if-bridge-has-no-ipv6-address.patch
5.0-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.6.4 / bridge-fix-ipv6-mc-snooping-if-bridge-has-no-ipv6-address.patch
1 From foo@baz Wed Jul 6 16:50:56 PDT 2016
2 From: daniel <daniel@dd-wrt.com>
3 Date: Fri, 24 Jun 2016 12:35:18 +0200
4 Subject: Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: daniel <daniel@dd-wrt.com>
10
11 [ Upstream commit 0888d5f3c0f183ea6177355752ada433d370ac89 ]
12
13 The bridge is falsly dropping ipv6 mulitcast packets if there is:
14 1. No ipv6 address assigned on the brigde.
15 2. No external mld querier present.
16 3. The internal querier enabled.
17
18 When the bridge fails to build mld queries, because it has no
19 ipv6 address, it slilently returns, but keeps the local querier enabled.
20 This specific case causes confusing packet loss.
21
22 Ipv6 multicast snooping can only work if:
23 a) An external querier is present
24 OR
25 b) The bridge has an ipv6 address an is capable of sending own queries
26
27 Otherwise it has to forward/flood the ipv6 multicast traffic,
28 because snooping cannot work.
29
30 This patch fixes the issue by adding a flag to the bridge struct that
31 indicates that there is currently no ipv6 address assinged to the bridge
32 and returns a false state for the local querier in
33 __br_multicast_querier_exists().
34
35 Special thanks to Linus Lüssing.
36
37 Fixes: d1d81d4c3dd8 ("bridge: check return value of ipv6_dev_get_saddr()")
38 Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
39 Acked-by: Linus Lüssing <linus.luessing@c0d3.blue>
40 Signed-off-by: David S. Miller <davem@davemloft.net>
41 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
42 ---
43 net/bridge/br_multicast.c | 4 ++++
44 net/bridge/br_private.h | 23 +++++++++++++++++++----
45 2 files changed, 23 insertions(+), 4 deletions(-)
46
47 --- a/net/bridge/br_multicast.c
48 +++ b/net/bridge/br_multicast.c
49 @@ -464,8 +464,11 @@ static struct sk_buff *br_ip6_multicast_
50 if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
51 &ip6h->saddr)) {
52 kfree_skb(skb);
53 + br->has_ipv6_addr = 0;
54 return NULL;
55 }
56 +
57 + br->has_ipv6_addr = 1;
58 ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
59
60 hopopt = (u8 *)(ip6h + 1);
61 @@ -1745,6 +1748,7 @@ void br_multicast_init(struct net_bridge
62 br->ip6_other_query.delay_time = 0;
63 br->ip6_querier.port = NULL;
64 #endif
65 + br->has_ipv6_addr = 1;
66
67 spin_lock_init(&br->multicast_lock);
68 setup_timer(&br->multicast_router_timer,
69 --- a/net/bridge/br_private.h
70 +++ b/net/bridge/br_private.h
71 @@ -304,6 +304,7 @@ struct net_bridge
72 u8 multicast_disabled:1;
73 u8 multicast_querier:1;
74 u8 multicast_query_use_ifaddr:1;
75 + u8 has_ipv6_addr:1;
76
77 u32 hash_elasticity;
78 u32 hash_max;
79 @@ -577,10 +578,22 @@ static inline bool br_multicast_is_route
80
81 static inline bool
82 __br_multicast_querier_exists(struct net_bridge *br,
83 - struct bridge_mcast_other_query *querier)
84 + struct bridge_mcast_other_query *querier,
85 + const bool is_ipv6)
86 {
87 + bool own_querier_enabled;
88 +
89 + if (br->multicast_querier) {
90 + if (is_ipv6 && !br->has_ipv6_addr)
91 + own_querier_enabled = false;
92 + else
93 + own_querier_enabled = true;
94 + } else {
95 + own_querier_enabled = false;
96 + }
97 +
98 return time_is_before_jiffies(querier->delay_time) &&
99 - (br->multicast_querier || timer_pending(&querier->timer));
100 + (own_querier_enabled || timer_pending(&querier->timer));
101 }
102
103 static inline bool br_multicast_querier_exists(struct net_bridge *br,
104 @@ -588,10 +601,12 @@ static inline bool br_multicast_querier_
105 {
106 switch (eth->h_proto) {
107 case (htons(ETH_P_IP)):
108 - return __br_multicast_querier_exists(br, &br->ip4_other_query);
109 + return __br_multicast_querier_exists(br,
110 + &br->ip4_other_query, false);
111 #if IS_ENABLED(CONFIG_IPV6)
112 case (htons(ETH_P_IPV6)):
113 - return __br_multicast_querier_exists(br, &br->ip6_other_query);
114 + return __br_multicast_querier_exists(br,
115 + &br->ip6_other_query, true);
116 #endif
117 default:
118 return false;