Blame view

net/bridge/br_multicast.c 59.6 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
eb1d16414   Herbert Xu   bridge: Add core ...
2
3
4
5
  /*
   * Bridge multicast support.
   *
   * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
eb1d16414   Herbert Xu   bridge: Add core ...
6
7
8
   */
  
  #include <linux/err.h>
07f8ac4a1   Linus Lüssing   bridge: add expor...
9
  #include <linux/export.h>
eb1d16414   Herbert Xu   bridge: Add core ...
10
11
  #include <linux/if_ether.h>
  #include <linux/igmp.h>
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
12
  #include <linux/in.h>
eb1d16414   Herbert Xu   bridge: Add core ...
13
14
  #include <linux/jhash.h>
  #include <linux/kernel.h>
b195167fc   Herbert Xu   bridge: Add hash ...
15
  #include <linux/log2.h>
eb1d16414   Herbert Xu   bridge: Add core ...
16
17
18
19
20
21
22
  #include <linux/netdevice.h>
  #include <linux/netfilter_bridge.h>
  #include <linux/random.h>
  #include <linux/rculist.h>
  #include <linux/skbuff.h>
  #include <linux/slab.h>
  #include <linux/timer.h>
1c8ad5bfa   Cong Wang   bridge: use the b...
23
  #include <linux/inetdevice.h>
91b02d3d1   Nikolay Aleksandrov   bridge: mcast: ad...
24
  #include <linux/mroute.h>
eb1d16414   Herbert Xu   bridge: Add core ...
25
  #include <net/ip.h>
147c1e9b9   Nogah Frankel   switchdev: bridge...
26
  #include <net/switchdev.h>
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
27
  #if IS_ENABLED(CONFIG_IPV6)
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
28
  #include <linux/icmpv6.h>
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
29
30
  #include <net/ipv6.h>
  #include <net/mld.h>
d4c4f07df   David S. Miller   bridge: Fix build...
31
  #include <net/ip6_checksum.h>
3c3769e63   Linus Lüssing   bridge: apply mul...
32
  #include <net/addrconf.h>
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
33
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
34
35
  
  #include "br_private.h"
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
36
37
38
39
40
  static const struct rhashtable_params br_mdb_rht_params = {
  	.head_offset = offsetof(struct net_bridge_mdb_entry, rhnode),
  	.key_offset = offsetof(struct net_bridge_mdb_entry, addr),
  	.key_len = sizeof(struct br_ip),
  	.automatic_shrinking = true,
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
41
  };
cc0fdd802   Linus Lüssing   bridge: separate ...
42
  static void br_multicast_start_querier(struct net_bridge *br,
90010b36e   Linus Lüssing   bridge: rename st...
43
  				       struct bridge_mcast_own_query *query);
754bc547f   Satish Ashok   bridge: multicast...
44
45
  static void br_multicast_add_router(struct net_bridge *br,
  				    struct net_bridge_port *port);
bc8c20aca   Satish Ashok   bridge: multicast...
46
47
48
  static void br_ip4_multicast_leave_group(struct net_bridge *br,
  					 struct net_bridge_port *port,
  					 __be32 group,
6db6f0eae   Felix Fietkau   bridge: multicast...
49
50
  					 __u16 vid,
  					 const unsigned char *src);
f12e7d95d   Nogah Frankel   bridge: mcast: Me...
51
  static void __del_port_router(struct net_bridge_port *p);
bc8c20aca   Satish Ashok   bridge: multicast...
52
53
54
55
  #if IS_ENABLED(CONFIG_IPV6)
  static void br_ip6_multicast_leave_group(struct net_bridge *br,
  					 struct net_bridge_port *port,
  					 const struct in6_addr *group,
6db6f0eae   Felix Fietkau   bridge: multicast...
56
  					 __u16 vid, const unsigned char *src);
bc8c20aca   Satish Ashok   bridge: multicast...
57
  #endif
c83b8fab0   Herbert Xu   bridge: Restart q...
58

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
59
60
  static struct net_bridge_mdb_entry *br_mdb_ip_get_rcu(struct net_bridge *br,
  						      struct br_ip *dst)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
61
  {
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
62
  	return rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
63
  }
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
64

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
65
66
  struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge *br,
  					   struct br_ip *dst)
eb1d16414   Herbert Xu   bridge: Add core ...
67
  {
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
68
  	struct net_bridge_mdb_entry *ent;
eb1d16414   Herbert Xu   bridge: Add core ...
69

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
70
  	lockdep_assert_held_once(&br->multicast_lock);
eb1d16414   Herbert Xu   bridge: Add core ...
71

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
72
73
74
  	rcu_read_lock();
  	ent = rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params);
  	rcu_read_unlock();
7f285fa78   Herbert Xu   bridge br_multica...
75

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
76
  	return ent;
7f285fa78   Herbert Xu   bridge br_multica...
77
  }
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
78
79
  static struct net_bridge_mdb_entry *br_mdb_ip4_get(struct net_bridge *br,
  						   __be32 dst, __u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
80
  {
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
81
  	struct br_ip br_dst;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
82
  	memset(&br_dst, 0, sizeof(br_dst));
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
83
84
  	br_dst.u.ip4 = dst;
  	br_dst.proto = htons(ETH_P_IP);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
85
  	br_dst.vid = vid;
0821ec55b   Herbert Xu   bridge: Move NULL...
86

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
87
  	return br_mdb_ip_get(br, &br_dst);
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
88
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
89
  #if IS_ENABLED(CONFIG_IPV6)
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
90
91
92
  static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br,
  						   const struct in6_addr *dst,
  						   __u16 vid)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
93
94
  {
  	struct br_ip br_dst;
0821ec55b   Herbert Xu   bridge: Move NULL...
95

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
96
  	memset(&br_dst, 0, sizeof(br_dst));
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
97
  	br_dst.u.ip6 = *dst;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
98
  	br_dst.proto = htons(ETH_P_IPV6);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
99
  	br_dst.vid = vid;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
100

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
101
  	return br_mdb_ip_get(br, &br_dst);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
102
103
  }
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
104
  struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
fbca58a22   Cong Wang   bridge: add missi...
105
  					struct sk_buff *skb, u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
106
  {
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
107
  	struct br_ip ip;
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
108
  	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
eb1d16414   Herbert Xu   bridge: Add core ...
109
  		return NULL;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
110
  	if (BR_INPUT_SKB_CB(skb)->igmp)
eb1d16414   Herbert Xu   bridge: Add core ...
111
  		return NULL;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
112
  	memset(&ip, 0, sizeof(ip));
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
113
  	ip.proto = skb->protocol;
fbca58a22   Cong Wang   bridge: add missi...
114
  	ip.vid = vid;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
115

eb1d16414   Herbert Xu   bridge: Add core ...
116
117
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
118
119
  		ip.u.ip4 = ip_hdr(skb)->daddr;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
120
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
121
  	case htons(ETH_P_IPV6):
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
122
  		ip.u.ip6 = ipv6_hdr(skb)->daddr;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
123
124
  		break;
  #endif
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
125
126
  	default:
  		return NULL;
eb1d16414   Herbert Xu   bridge: Add core ...
127
  	}
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
128
  	return br_mdb_ip_get_rcu(br, &ip);
eb1d16414   Herbert Xu   bridge: Add core ...
129
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
130
  static void br_multicast_group_expired(struct timer_list *t)
eb1d16414   Herbert Xu   bridge: Add core ...
131
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
132
  	struct net_bridge_mdb_entry *mp = from_timer(mp, t, timer);
eb1d16414   Herbert Xu   bridge: Add core ...
133
  	struct net_bridge *br = mp->br;
eb1d16414   Herbert Xu   bridge: Add core ...
134
135
136
137
  
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) || timer_pending(&mp->timer))
  		goto out;
1bc844ee0   Nikolay Aleksandrov   net: bridge: mdb:...
138
  	br_multicast_host_leave(mp, true);
eb1d16414   Herbert Xu   bridge: Add core ...
139
140
141
  
  	if (mp->ports)
  		goto out;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
142
143
144
  	rhashtable_remove_fast(&br->mdb_hash_tbl, &mp->rhnode,
  			       br_mdb_rht_params);
  	hlist_del_rcu(&mp->mdb_node);
eb1d16414   Herbert Xu   bridge: Add core ...
145

4329596cb   Nikolay Aleksandrov   net: bridge: mult...
146
  	kfree_rcu(mp, rcu);
eb1d16414   Herbert Xu   bridge: Add core ...
147
148
149
150
151
152
153
154
  
  out:
  	spin_unlock(&br->multicast_lock);
  }
  
  static void br_multicast_del_pg(struct net_bridge *br,
  				struct net_bridge_port_group *pg)
  {
eb1d16414   Herbert Xu   bridge: Add core ...
155
156
  	struct net_bridge_mdb_entry *mp;
  	struct net_bridge_port_group *p;
e80516880   Eric Dumazet   bridge: add RCU a...
157
  	struct net_bridge_port_group __rcu **pp;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
158
  	mp = br_mdb_ip_get(br, &pg->addr);
eb1d16414   Herbert Xu   bridge: Add core ...
159
160
  	if (WARN_ON(!mp))
  		return;
e80516880   Eric Dumazet   bridge: add RCU a...
161
162
163
  	for (pp = &mp->ports;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     pp = &p->next) {
eb1d16414   Herbert Xu   bridge: Add core ...
164
165
  		if (p != pg)
  			continue;
83f6a740b   stephen hemminger   bridge: multicast...
166
  		rcu_assign_pointer(*pp, p->next);
eb1d16414   Herbert Xu   bridge: Add core ...
167
168
  		hlist_del_init(&p->mglist);
  		del_timer(&p->timer);
45ebcce56   Elad Raz   bridge: mdb: Mark...
169
170
  		br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB,
  			      p->flags);
4329596cb   Nikolay Aleksandrov   net: bridge: mult...
171
  		kfree_rcu(p, rcu);
eb1d16414   Herbert Xu   bridge: Add core ...
172

ff0fd34ea   Andrew Lunn   net: bridge: Rena...
173
  		if (!mp->ports && !mp->host_joined &&
eb1d16414   Herbert Xu   bridge: Add core ...
174
175
176
177
178
179
180
181
  		    netif_running(br->dev))
  			mod_timer(&mp->timer, jiffies);
  
  		return;
  	}
  
  	WARN_ON(1);
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
182
  static void br_multicast_port_group_expired(struct timer_list *t)
eb1d16414   Herbert Xu   bridge: Add core ...
183
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
184
  	struct net_bridge_port_group *pg = from_timer(pg, t, timer);
eb1d16414   Herbert Xu   bridge: Add core ...
185
186
187
188
  	struct net_bridge *br = pg->port->br;
  
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
9d06b6d8a   Elad Raz   bridge: mdb: Sepa...
189
  	    hlist_unhashed(&pg->mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT)
eb1d16414   Herbert Xu   bridge: Add core ...
190
191
192
193
194
195
196
  		goto out;
  
  	br_multicast_del_pg(br, pg);
  
  out:
  	spin_unlock(&br->multicast_lock);
  }
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
197
  static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
198
199
  						    __be32 group,
  						    u8 *igmp_type)
eb1d16414   Herbert Xu   bridge: Add core ...
200
  {
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
201
202
  	struct igmpv3_query *ihv3;
  	size_t igmp_hdr_size;
eb1d16414   Herbert Xu   bridge: Add core ...
203
204
205
206
  	struct sk_buff *skb;
  	struct igmphdr *ih;
  	struct ethhdr *eth;
  	struct iphdr *iph;
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
207
208
209
  	igmp_hdr_size = sizeof(*ih);
  	if (br->multicast_igmp_version == 3)
  		igmp_hdr_size = sizeof(*ihv3);
eb1d16414   Herbert Xu   bridge: Add core ...
210
  	skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*iph) +
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
211
  						 igmp_hdr_size + 4);
eb1d16414   Herbert Xu   bridge: Add core ...
212
213
214
215
216
217
218
  	if (!skb)
  		goto out;
  
  	skb->protocol = htons(ETH_P_IP);
  
  	skb_reset_mac_header(skb);
  	eth = eth_hdr(skb);
e5a727f66   Joe Perches   bridge: Use ether...
219
  	ether_addr_copy(eth->h_source, br->dev->dev_addr);
eb1d16414   Herbert Xu   bridge: Add core ...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  	eth->h_dest[0] = 1;
  	eth->h_dest[1] = 0;
  	eth->h_dest[2] = 0x5e;
  	eth->h_dest[3] = 0;
  	eth->h_dest[4] = 0;
  	eth->h_dest[5] = 1;
  	eth->h_proto = htons(ETH_P_IP);
  	skb_put(skb, sizeof(*eth));
  
  	skb_set_network_header(skb, skb->len);
  	iph = ip_hdr(skb);
  
  	iph->version = 4;
  	iph->ihl = 6;
  	iph->tos = 0xc0;
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
235
  	iph->tot_len = htons(sizeof(*iph) + igmp_hdr_size + 4);
eb1d16414   Herbert Xu   bridge: Add core ...
236
237
238
239
  	iph->id = 0;
  	iph->frag_off = htons(IP_DF);
  	iph->ttl = 1;
  	iph->protocol = IPPROTO_IGMP;
675779adb   Nikolay Aleksandrov   net: bridge: conv...
240
  	iph->saddr = br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR) ?
1c8ad5bfa   Cong Wang   bridge: use the b...
241
  		     inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0;
eb1d16414   Herbert Xu   bridge: Add core ...
242
243
244
245
246
247
248
249
250
  	iph->daddr = htonl(INADDR_ALLHOSTS_GROUP);
  	((u8 *)&iph[1])[0] = IPOPT_RA;
  	((u8 *)&iph[1])[1] = 4;
  	((u8 *)&iph[1])[2] = 0;
  	((u8 *)&iph[1])[3] = 0;
  	ip_send_check(iph);
  	skb_put(skb, 24);
  
  	skb_set_transport_header(skb, skb->len);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
251
  	*igmp_type = IGMP_HOST_MEMBERSHIP_QUERY;
eb1d16414   Herbert Xu   bridge: Add core ...
252

5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  	switch (br->multicast_igmp_version) {
  	case 2:
  		ih = igmp_hdr(skb);
  		ih->type = IGMP_HOST_MEMBERSHIP_QUERY;
  		ih->code = (group ? br->multicast_last_member_interval :
  				    br->multicast_query_response_interval) /
  			   (HZ / IGMP_TIMER_SCALE);
  		ih->group = group;
  		ih->csum = 0;
  		ih->csum = ip_compute_csum((void *)ih, sizeof(*ih));
  		break;
  	case 3:
  		ihv3 = igmpv3_query_hdr(skb);
  		ihv3->type = IGMP_HOST_MEMBERSHIP_QUERY;
  		ihv3->code = (group ? br->multicast_last_member_interval :
  				      br->multicast_query_response_interval) /
  			     (HZ / IGMP_TIMER_SCALE);
  		ihv3->group = group;
  		ihv3->qqic = br->multicast_query_interval / HZ;
  		ihv3->nsrcs = 0;
  		ihv3->resv = 0;
  		ihv3->suppress = 0;
  		ihv3->qrv = 2;
  		ihv3->csum = 0;
  		ihv3->csum = ip_compute_csum((void *)ihv3, sizeof(*ihv3));
  		break;
  	}
  
  	skb_put(skb, igmp_hdr_size);
eb1d16414   Herbert Xu   bridge: Add core ...
282
283
284
285
286
  	__skb_pull(skb, sizeof(*eth));
  
  out:
  	return skb;
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
287
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
288
  static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
289
290
  						    const struct in6_addr *grp,
  						    u8 *igmp_type)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
291
  {
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
292
293
  	struct mld2_query *mld2q;
  	unsigned long interval;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
294
295
  	struct ipv6hdr *ip6h;
  	struct mld_msg *mldq;
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
296
297
  	size_t mld_hdr_size;
  	struct sk_buff *skb;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
298
299
  	struct ethhdr *eth;
  	u8 *hopopt;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
300

aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
301
302
303
  	mld_hdr_size = sizeof(*mldq);
  	if (br->multicast_mld_version == 2)
  		mld_hdr_size = sizeof(*mld2q);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
304
  	skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*ip6h) +
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
305
  						 8 + mld_hdr_size);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
306
307
308
309
310
311
312
313
  	if (!skb)
  		goto out;
  
  	skb->protocol = htons(ETH_P_IPV6);
  
  	/* Ethernet header */
  	skb_reset_mac_header(skb);
  	eth = eth_hdr(skb);
e5a727f66   Joe Perches   bridge: Use ether...
314
  	ether_addr_copy(eth->h_source, br->dev->dev_addr);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
315
316
317
318
319
320
321
322
  	eth->h_proto = htons(ETH_P_IPV6);
  	skb_put(skb, sizeof(*eth));
  
  	/* IPv6 header + HbH option */
  	skb_set_network_header(skb, skb->len);
  	ip6h = ipv6_hdr(skb);
  
  	*(__force __be32 *)ip6h = htonl(0x60000000);
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
323
  	ip6h->payload_len = htons(8 + mld_hdr_size);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
324
325
  	ip6h->nexthdr = IPPROTO_HOPOPTS;
  	ip6h->hop_limit = 1;
a7bff75b0   Linus Lüssing   bridge: Fix possi...
326
  	ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
d1d81d4c3   Ulrich Weber   bridge: check ret...
327
328
329
  	if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
  			       &ip6h->saddr)) {
  		kfree_skb(skb);
675779adb   Nikolay Aleksandrov   net: bridge: conv...
330
  		br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, false);
d1d81d4c3   Ulrich Weber   bridge: check ret...
331
332
  		return NULL;
  	}
0888d5f3c   Daniel   Bridge: Fix ipv6 ...
333

675779adb   Nikolay Aleksandrov   net: bridge: conv...
334
  	br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true);
36cff5a10   Linus Lüssing   bridge: Fix MLD q...
335
  	ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
336
337
338
339
340
341
342
343
  
  	hopopt = (u8 *)(ip6h + 1);
  	hopopt[0] = IPPROTO_ICMPV6;		/* next hdr */
  	hopopt[1] = 0;				/* length of HbH */
  	hopopt[2] = IPV6_TLV_ROUTERALERT;	/* Router Alert */
  	hopopt[3] = 2;				/* Length of RA Option */
  	hopopt[4] = 0;				/* Type = 0x0000 (MLD) */
  	hopopt[5] = 0;
1de5a71c3   Eldad Zack   ipv6: correct the...
344
345
  	hopopt[6] = IPV6_TLV_PAD1;		/* Pad1 */
  	hopopt[7] = IPV6_TLV_PAD1;		/* Pad1 */
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
346
347
348
349
350
  
  	skb_put(skb, sizeof(*ip6h) + 8);
  
  	/* ICMPv6 */
  	skb_set_transport_header(skb, skb->len);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
351
  	interval = ipv6_addr_any(grp) ?
32de868cb   Linus Lüssing   bridge: fix switc...
352
353
  			br->multicast_query_response_interval :
  			br->multicast_last_member_interval;
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
354
  	*igmp_type = ICMPV6_MGM_QUERY;
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  	switch (br->multicast_mld_version) {
  	case 1:
  		mldq = (struct mld_msg *)icmp6_hdr(skb);
  		mldq->mld_type = ICMPV6_MGM_QUERY;
  		mldq->mld_code = 0;
  		mldq->mld_cksum = 0;
  		mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
  		mldq->mld_reserved = 0;
  		mldq->mld_mca = *grp;
  		mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  						  sizeof(*mldq), IPPROTO_ICMPV6,
  						  csum_partial(mldq,
  							       sizeof(*mldq),
  							       0));
  		break;
  	case 2:
  		mld2q = (struct mld2_query *)icmp6_hdr(skb);
53631a5f9   Lance Richardson   bridge: sparse fi...
372
  		mld2q->mld2q_mrc = htons((u16)jiffies_to_msecs(interval));
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  		mld2q->mld2q_type = ICMPV6_MGM_QUERY;
  		mld2q->mld2q_code = 0;
  		mld2q->mld2q_cksum = 0;
  		mld2q->mld2q_resv1 = 0;
  		mld2q->mld2q_resv2 = 0;
  		mld2q->mld2q_suppress = 0;
  		mld2q->mld2q_qrv = 2;
  		mld2q->mld2q_nsrcs = 0;
  		mld2q->mld2q_qqic = br->multicast_query_interval / HZ;
  		mld2q->mld2q_mca = *grp;
  		mld2q->mld2q_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  						     sizeof(*mld2q),
  						     IPPROTO_ICMPV6,
  						     csum_partial(mld2q,
  								  sizeof(*mld2q),
  								  0));
  		break;
  	}
  	skb_put(skb, mld_hdr_size);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
392
393
394
395
396
397
398
  
  	__skb_pull(skb, sizeof(*eth));
  
  out:
  	return skb;
  }
  #endif
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
399
  static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
400
401
  						struct br_ip *addr,
  						u8 *igmp_type)
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
402
403
404
  {
  	switch (addr->proto) {
  	case htons(ETH_P_IP):
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
405
  		return br_ip4_multicast_alloc_query(br, addr->u.ip4, igmp_type);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
406
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
407
  	case htons(ETH_P_IPV6):
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
408
409
  		return br_ip6_multicast_alloc_query(br, &addr->u.ip6,
  						    igmp_type);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
410
  #endif
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
411
412
413
  	}
  	return NULL;
  }
cfd567543   Cong Wang   bridge: add suppo...
414
  struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
415
  						    struct br_ip *group)
eb1d16414   Herbert Xu   bridge: Add core ...
416
  {
eb1d16414   Herbert Xu   bridge: Add core ...
417
  	struct net_bridge_mdb_entry *mp;
4c0833bcd   Tobias Klauser   bridge: Fix retur...
418
  	int err;
eb1d16414   Herbert Xu   bridge: Add core ...
419

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
420
421
422
  	mp = br_mdb_ip_get(br, group);
  	if (mp)
  		return mp;
eb1d16414   Herbert Xu   bridge: Add core ...
423

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
424
425
426
  	if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) {
  		br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false);
  		return ERR_PTR(-E2BIG);
eb1d16414   Herbert Xu   bridge: Add core ...
427
428
429
430
  	}
  
  	mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
  	if (unlikely(!mp))
4c0833bcd   Tobias Klauser   bridge: Fix retur...
431
  		return ERR_PTR(-ENOMEM);
eb1d16414   Herbert Xu   bridge: Add core ...
432
433
  
  	mp->br = br;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
434
  	mp->addr = *group;
88c1f37f0   Allen Pais   net: bridge: Conv...
435
  	timer_setup(&mp->timer, br_multicast_group_expired, 0);
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
436
437
438
439
440
441
442
443
  	err = rhashtable_lookup_insert_fast(&br->mdb_hash_tbl, &mp->rhnode,
  					    br_mdb_rht_params);
  	if (err) {
  		kfree(mp);
  		mp = ERR_PTR(err);
  	} else {
  		hlist_add_head_rcu(&mp->mdb_node, &br->mdb_list);
  	}
1faabf2aa   Eric Dumazet   bridge: do not ca...
444

eb1d16414   Herbert Xu   bridge: Add core ...
445
446
  	return mp;
  }
cfd567543   Cong Wang   bridge: add suppo...
447
448
449
  struct net_bridge_port_group *br_multicast_new_port_group(
  			struct net_bridge_port *port,
  			struct br_ip *group,
ccb1c31a7   Amerigo Wang   bridge: add flags...
450
  			struct net_bridge_port_group __rcu *next,
6db6f0eae   Felix Fietkau   bridge: multicast...
451
452
  			unsigned char flags,
  			const unsigned char *src)
cfd567543   Cong Wang   bridge: add suppo...
453
454
455
456
457
458
459
460
461
  {
  	struct net_bridge_port_group *p;
  
  	p = kzalloc(sizeof(*p), GFP_ATOMIC);
  	if (unlikely(!p))
  		return NULL;
  
  	p->addr = *group;
  	p->port = port;
9d06b6d8a   Elad Raz   bridge: mdb: Sepa...
462
  	p->flags = flags;
eca2a43bb   stephen hemminger   bridge: fix icmpv...
463
  	rcu_assign_pointer(p->next, next);
cfd567543   Cong Wang   bridge: add suppo...
464
  	hlist_add_head(&p->mglist, &port->mglist);
88c1f37f0   Allen Pais   net: bridge: Conv...
465
  	timer_setup(&p->timer, br_multicast_port_group_expired, 0);
6db6f0eae   Felix Fietkau   bridge: multicast...
466
467
468
469
  
  	if (src)
  		memcpy(p->eth_addr, src, ETH_ALEN);
  	else
1bfe45f4a   Mao Wenan   net: bridge: use ...
470
  		eth_broadcast_addr(p->eth_addr);
6db6f0eae   Felix Fietkau   bridge: multicast...
471

cfd567543   Cong Wang   bridge: add suppo...
472
473
  	return p;
  }
6db6f0eae   Felix Fietkau   bridge: multicast...
474
475
476
477
478
479
480
481
482
483
484
485
  static bool br_port_group_equal(struct net_bridge_port_group *p,
  				struct net_bridge_port *port,
  				const unsigned char *src)
  {
  	if (p->port != port)
  		return false;
  
  	if (!(port->flags & BR_MULTICAST_TO_UNICAST))
  		return true;
  
  	return ether_addr_equal(src, p->eth_addr);
  }
1bc844ee0   Nikolay Aleksandrov   net: bridge: mdb:...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  void br_multicast_host_join(struct net_bridge_mdb_entry *mp, bool notify)
  {
  	if (!mp->host_joined) {
  		mp->host_joined = true;
  		if (notify)
  			br_mdb_notify(mp->br->dev, NULL, &mp->addr,
  				      RTM_NEWMDB, 0);
  	}
  	mod_timer(&mp->timer, jiffies + mp->br->multicast_membership_interval);
  }
  
  void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify)
  {
  	if (!mp->host_joined)
  		return;
  
  	mp->host_joined = false;
  	if (notify)
  		br_mdb_notify(mp->br->dev, NULL, &mp->addr, RTM_DELMDB, 0);
  }
eb1d16414   Herbert Xu   bridge: Add core ...
506
  static int br_multicast_add_group(struct net_bridge *br,
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
507
  				  struct net_bridge_port *port,
6db6f0eae   Felix Fietkau   bridge: multicast...
508
509
  				  struct br_ip *group,
  				  const unsigned char *src)
eb1d16414   Herbert Xu   bridge: Add core ...
510
  {
e80516880   Eric Dumazet   bridge: add RCU a...
511
  	struct net_bridge_port_group __rcu **pp;
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
512
513
  	struct net_bridge_port_group *p;
  	struct net_bridge_mdb_entry *mp;
454594f3b   Linus Lüssing   Revert "bridge: o...
514
  	unsigned long now = jiffies;
eb1d16414   Herbert Xu   bridge: Add core ...
515
  	int err;
eb1d16414   Herbert Xu   bridge: Add core ...
516
517
518
519
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) ||
  	    (port && port->state == BR_STATE_DISABLED))
  		goto out;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
520
  	mp = br_multicast_new_group(br, group);
eb1d16414   Herbert Xu   bridge: Add core ...
521
  	err = PTR_ERR(mp);
4c0833bcd   Tobias Klauser   bridge: Fix retur...
522
  	if (IS_ERR(mp))
eb1d16414   Herbert Xu   bridge: Add core ...
523
524
525
  		goto err;
  
  	if (!port) {
1bc844ee0   Nikolay Aleksandrov   net: bridge: mdb:...
526
  		br_multicast_host_join(mp, true);
eb1d16414   Herbert Xu   bridge: Add core ...
527
528
  		goto out;
  	}
e80516880   Eric Dumazet   bridge: add RCU a...
529
530
531
  	for (pp = &mp->ports;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     pp = &p->next) {
6db6f0eae   Felix Fietkau   bridge: multicast...
532
  		if (br_port_group_equal(p, port, src))
454594f3b   Linus Lüssing   Revert "bridge: o...
533
  			goto found;
eb1d16414   Herbert Xu   bridge: Add core ...
534
535
536
  		if ((unsigned long)p->port < (unsigned long)port)
  			break;
  	}
6db6f0eae   Felix Fietkau   bridge: multicast...
537
  	p = br_multicast_new_port_group(port, group, *pp, 0, src);
eb1d16414   Herbert Xu   bridge: Add core ...
538
539
  	if (unlikely(!p))
  		goto err;
eb1d16414   Herbert Xu   bridge: Add core ...
540
  	rcu_assign_pointer(*pp, p);
45ebcce56   Elad Raz   bridge: mdb: Mark...
541
  	br_mdb_notify(br->dev, port, group, RTM_NEWMDB, 0);
eb1d16414   Herbert Xu   bridge: Add core ...
542

454594f3b   Linus Lüssing   Revert "bridge: o...
543
544
  found:
  	mod_timer(&p->timer, now + br->multicast_membership_interval);
eb1d16414   Herbert Xu   bridge: Add core ...
545
546
547
548
549
550
551
  out:
  	err = 0;
  
  err:
  	spin_unlock(&br->multicast_lock);
  	return err;
  }
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
552
553
  static int br_ip4_multicast_add_group(struct net_bridge *br,
  				      struct net_bridge_port *port,
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
554
  				      __be32 group,
6db6f0eae   Felix Fietkau   bridge: multicast...
555
556
  				      __u16 vid,
  				      const unsigned char *src)
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
557
558
559
560
561
  {
  	struct br_ip br_group;
  
  	if (ipv4_is_local_multicast(group))
  		return 0;
1515a63fc   Nikolay Aleksandrov   net: bridge: alwa...
562
  	memset(&br_group, 0, sizeof(br_group));
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
563
564
  	br_group.u.ip4 = group;
  	br_group.proto = htons(ETH_P_IP);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
565
  	br_group.vid = vid;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
566

6db6f0eae   Felix Fietkau   bridge: multicast...
567
  	return br_multicast_add_group(br, port, &br_group, src);
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
568
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
569
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
570
571
  static int br_ip6_multicast_add_group(struct net_bridge *br,
  				      struct net_bridge_port *port,
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
572
  				      const struct in6_addr *group,
6db6f0eae   Felix Fietkau   bridge: multicast...
573
574
  				      __u16 vid,
  				      const unsigned char *src)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
575
576
  {
  	struct br_ip br_group;
3c3769e63   Linus Lüssing   bridge: apply mul...
577
  	if (ipv6_addr_is_ll_all_nodes(group))
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
578
  		return 0;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
579
  	memset(&br_group, 0, sizeof(br_group));
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
580
  	br_group.u.ip6 = *group;
9cc6e0c4c   Linus Lüssing   bridge: Fix IPv6 ...
581
  	br_group.proto = htons(ETH_P_IPV6);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
582
  	br_group.vid = vid;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
583

6db6f0eae   Felix Fietkau   bridge: multicast...
584
  	return br_multicast_add_group(br, port, &br_group, src);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
585
586
  }
  #endif
88c1f37f0   Allen Pais   net: bridge: Conv...
587
  static void br_multicast_router_expired(struct timer_list *t)
eb1d16414   Herbert Xu   bridge: Add core ...
588
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
589
590
  	struct net_bridge_port *port =
  			from_timer(port, t, multicast_router_timer);
eb1d16414   Herbert Xu   bridge: Add core ...
591
592
593
  	struct net_bridge *br = port->br;
  
  	spin_lock(&br->multicast_lock);
a55d8246a   Nikolay Aleksandrov   bridge: mcast: ad...
594
595
  	if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
  	    port->multicast_router == MDB_RTR_TYPE_PERM ||
f12e7d95d   Nogah Frankel   bridge: mcast: Me...
596
  	    timer_pending(&port->multicast_router_timer))
eb1d16414   Herbert Xu   bridge: Add core ...
597
  		goto out;
f12e7d95d   Nogah Frankel   bridge: mcast: Me...
598
  	__del_port_router(port);
eb1d16414   Herbert Xu   bridge: Add core ...
599
600
601
  out:
  	spin_unlock(&br->multicast_lock);
  }
770414207   Yotam Gigi   net: bridge: Noti...
602
603
604
605
606
607
608
609
610
611
612
613
  static void br_mc_router_state_change(struct net_bridge *p,
  				      bool is_mc_router)
  {
  	struct switchdev_attr attr = {
  		.orig_dev = p->dev,
  		.id = SWITCHDEV_ATTR_ID_BRIDGE_MROUTER,
  		.flags = SWITCHDEV_F_DEFER,
  		.u.mrouter = is_mc_router,
  	};
  
  	switchdev_port_attr_set(p->dev, &attr);
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
614
  static void br_multicast_local_router_expired(struct timer_list *t)
eb1d16414   Herbert Xu   bridge: Add core ...
615
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
616
  	struct net_bridge *br = from_timer(br, t, multicast_router_timer);
770414207   Yotam Gigi   net: bridge: Noti...
617
618
619
620
621
622
623
624
625
626
  
  	spin_lock(&br->multicast_lock);
  	if (br->multicast_router == MDB_RTR_TYPE_DISABLED ||
  	    br->multicast_router == MDB_RTR_TYPE_PERM ||
  	    timer_pending(&br->multicast_router_timer))
  		goto out;
  
  	br_mc_router_state_change(br, false);
  out:
  	spin_unlock(&br->multicast_lock);
eb1d16414   Herbert Xu   bridge: Add core ...
627
  }
cc0fdd802   Linus Lüssing   bridge: separate ...
628
  static void br_multicast_querier_expired(struct net_bridge *br,
90010b36e   Linus Lüssing   bridge: rename st...
629
  					 struct bridge_mcast_own_query *query)
c83b8fab0   Herbert Xu   bridge: Restart q...
630
  {
c83b8fab0   Herbert Xu   bridge: Restart q...
631
  	spin_lock(&br->multicast_lock);
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
632
  	if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED))
c83b8fab0   Herbert Xu   bridge: Restart q...
633
  		goto out;
cc0fdd802   Linus Lüssing   bridge: separate ...
634
  	br_multicast_start_querier(br, query);
c83b8fab0   Herbert Xu   bridge: Restart q...
635
636
637
638
  
  out:
  	spin_unlock(&br->multicast_lock);
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
639
  static void br_ip4_multicast_querier_expired(struct timer_list *t)
cc0fdd802   Linus Lüssing   bridge: separate ...
640
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
641
  	struct net_bridge *br = from_timer(br, t, ip4_other_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
642

90010b36e   Linus Lüssing   bridge: rename st...
643
  	br_multicast_querier_expired(br, &br->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
644
645
646
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
88c1f37f0   Allen Pais   net: bridge: Conv...
647
  static void br_ip6_multicast_querier_expired(struct timer_list *t)
cc0fdd802   Linus Lüssing   bridge: separate ...
648
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
649
  	struct net_bridge *br = from_timer(br, t, ip6_other_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
650

90010b36e   Linus Lüssing   bridge: rename st...
651
  	br_multicast_querier_expired(br, &br->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
652
653
  }
  #endif
dc4eb53a9   Linus Lüssing   bridge: adhere to...
654
655
656
657
658
659
660
661
662
663
664
  static void br_multicast_select_own_querier(struct net_bridge *br,
  					    struct br_ip *ip,
  					    struct sk_buff *skb)
  {
  	if (ip->proto == htons(ETH_P_IP))
  		br->ip4_querier.addr.u.ip4 = ip_hdr(skb)->saddr;
  #if IS_ENABLED(CONFIG_IPV6)
  	else
  		br->ip6_querier.addr.u.ip6 = ipv6_hdr(skb)->saddr;
  #endif
  }
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
665
666
667
  static void __br_multicast_send_query(struct net_bridge *br,
  				      struct net_bridge_port *port,
  				      struct br_ip *ip)
eb1d16414   Herbert Xu   bridge: Add core ...
668
  {
eb1d16414   Herbert Xu   bridge: Add core ...
669
  	struct sk_buff *skb;
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
670
  	u8 igmp_type;
eb1d16414   Herbert Xu   bridge: Add core ...
671

1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
672
  	skb = br_multicast_alloc_query(br, ip, &igmp_type);
eb1d16414   Herbert Xu   bridge: Add core ...
673
  	if (!skb)
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
674
  		return;
eb1d16414   Herbert Xu   bridge: Add core ...
675
676
  
  	if (port) {
eb1d16414   Herbert Xu   bridge: Add core ...
677
  		skb->dev = port->dev;
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
678
  		br_multicast_count(br, port, skb, igmp_type,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
679
  				   BR_MCAST_DIR_TX);
29a26a568   Eric W. Biederman   netfilter: Pass s...
680
681
  		NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
  			dev_net(port->dev), NULL, skb, NULL, skb->dev,
f0b4eeced   Linus Lüssing   bridge: fix netfi...
682
  			br_dev_queue_push_xmit);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
683
684
  	} else {
  		br_multicast_select_own_querier(br, ip, skb);
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
685
  		br_multicast_count(br, port, skb, igmp_type,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
686
  				   BR_MCAST_DIR_RX);
eb1d16414   Herbert Xu   bridge: Add core ...
687
  		netif_rx(skb);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
688
  	}
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
689
690
691
  }
  
  static void br_multicast_send_query(struct net_bridge *br,
cc0fdd802   Linus Lüssing   bridge: separate ...
692
  				    struct net_bridge_port *port,
90010b36e   Linus Lüssing   bridge: rename st...
693
  				    struct bridge_mcast_own_query *own_query)
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
694
  {
90010b36e   Linus Lüssing   bridge: rename st...
695
  	struct bridge_mcast_other_query *other_query = NULL;
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
696
697
  	struct br_ip br_group;
  	unsigned long time;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
698

13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
699
700
  	if (!netif_running(br->dev) ||
  	    !br_opt_get(br, BROPT_MULTICAST_ENABLED) ||
675779adb   Nikolay Aleksandrov   net: bridge: conv...
701
  	    !br_opt_get(br, BROPT_MULTICAST_QUERIER))
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
702
  		return;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
703
  	memset(&br_group.u, 0, sizeof(br_group.u));
90010b36e   Linus Lüssing   bridge: rename st...
704
705
706
  	if (port ? (own_query == &port->ip4_own_query) :
  		   (own_query == &br->ip4_own_query)) {
  		other_query = &br->ip4_other_query;
cc0fdd802   Linus Lüssing   bridge: separate ...
707
  		br_group.proto = htons(ETH_P_IP);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
708
  #if IS_ENABLED(CONFIG_IPV6)
cc0fdd802   Linus Lüssing   bridge: separate ...
709
  	} else {
90010b36e   Linus Lüssing   bridge: rename st...
710
  		other_query = &br->ip6_other_query;
cc0fdd802   Linus Lüssing   bridge: separate ...
711
  		br_group.proto = htons(ETH_P_IPV6);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
712
  #endif
cc0fdd802   Linus Lüssing   bridge: separate ...
713
  	}
90010b36e   Linus Lüssing   bridge: rename st...
714
  	if (!other_query || timer_pending(&other_query->timer))
cc0fdd802   Linus Lüssing   bridge: separate ...
715
716
717
  		return;
  
  	__br_multicast_send_query(br, port, &br_group);
eb1d16414   Herbert Xu   bridge: Add core ...
718

eb1d16414   Herbert Xu   bridge: Add core ...
719
  	time = jiffies;
90010b36e   Linus Lüssing   bridge: rename st...
720
  	time += own_query->startup_sent < br->multicast_startup_query_count ?
eb1d16414   Herbert Xu   bridge: Add core ...
721
722
  		br->multicast_startup_query_interval :
  		br->multicast_query_interval;
90010b36e   Linus Lüssing   bridge: rename st...
723
  	mod_timer(&own_query->timer, time);
eb1d16414   Herbert Xu   bridge: Add core ...
724
  }
90010b36e   Linus Lüssing   bridge: rename st...
725
726
727
  static void
  br_multicast_port_query_expired(struct net_bridge_port *port,
  				struct bridge_mcast_own_query *query)
eb1d16414   Herbert Xu   bridge: Add core ...
728
  {
eb1d16414   Herbert Xu   bridge: Add core ...
729
730
731
  	struct net_bridge *br = port->br;
  
  	spin_lock(&br->multicast_lock);
02a780c01   Dan Carpenter   bridge: cleanup: ...
732
733
  	if (port->state == BR_STATE_DISABLED ||
  	    port->state == BR_STATE_BLOCKING)
eb1d16414   Herbert Xu   bridge: Add core ...
734
  		goto out;
cc0fdd802   Linus Lüssing   bridge: separate ...
735
736
  	if (query->startup_sent < br->multicast_startup_query_count)
  		query->startup_sent++;
eb1d16414   Herbert Xu   bridge: Add core ...
737

cc0fdd802   Linus Lüssing   bridge: separate ...
738
  	br_multicast_send_query(port->br, port, query);
eb1d16414   Herbert Xu   bridge: Add core ...
739
740
741
742
  
  out:
  	spin_unlock(&br->multicast_lock);
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
743
  static void br_ip4_multicast_port_query_expired(struct timer_list *t)
cc0fdd802   Linus Lüssing   bridge: separate ...
744
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
745
  	struct net_bridge_port *port = from_timer(port, t, ip4_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
746

90010b36e   Linus Lüssing   bridge: rename st...
747
  	br_multicast_port_query_expired(port, &port->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
748
749
750
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
88c1f37f0   Allen Pais   net: bridge: Conv...
751
  static void br_ip6_multicast_port_query_expired(struct timer_list *t)
cc0fdd802   Linus Lüssing   bridge: separate ...
752
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
753
  	struct net_bridge_port *port = from_timer(port, t, ip6_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
754

90010b36e   Linus Lüssing   bridge: rename st...
755
  	br_multicast_port_query_expired(port, &port->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
756
757
  }
  #endif
147c1e9b9   Nogah Frankel   switchdev: bridge...
758
759
760
761
762
763
  static void br_mc_disabled_update(struct net_device *dev, bool value)
  {
  	struct switchdev_attr attr = {
  		.orig_dev = dev,
  		.id = SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED,
  		.flags = SWITCHDEV_F_DEFER,
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
764
  		.u.mc_disabled = !value,
147c1e9b9   Nogah Frankel   switchdev: bridge...
765
766
767
768
  	};
  
  	switchdev_port_attr_set(dev, &attr);
  }
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
769
  int br_multicast_add_port(struct net_bridge_port *port)
eb1d16414   Herbert Xu   bridge: Add core ...
770
  {
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
771
  	port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
eb1d16414   Herbert Xu   bridge: Add core ...
772

88c1f37f0   Allen Pais   net: bridge: Conv...
773
774
775
776
  	timer_setup(&port->multicast_router_timer,
  		    br_multicast_router_expired, 0);
  	timer_setup(&port->ip4_own_query.timer,
  		    br_ip4_multicast_port_query_expired, 0);
cc0fdd802   Linus Lüssing   bridge: separate ...
777
  #if IS_ENABLED(CONFIG_IPV6)
88c1f37f0   Allen Pais   net: bridge: Conv...
778
779
  	timer_setup(&port->ip6_own_query.timer,
  		    br_ip6_multicast_port_query_expired, 0);
cc0fdd802   Linus Lüssing   bridge: separate ...
780
  #endif
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
781
782
  	br_mc_disabled_update(port->dev,
  			      br_opt_get(port->br, BROPT_MULTICAST_ENABLED));
147c1e9b9   Nogah Frankel   switchdev: bridge...
783

1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
784
785
786
787
788
  	port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
  	if (!port->mcast_stats)
  		return -ENOMEM;
  
  	return 0;
eb1d16414   Herbert Xu   bridge: Add core ...
789
790
791
792
  }
  
  void br_multicast_del_port(struct net_bridge_port *port)
  {
e10177abf   Satish Ashok   bridge: multicast...
793
794
795
796
797
798
799
800
801
  	struct net_bridge *br = port->br;
  	struct net_bridge_port_group *pg;
  	struct hlist_node *n;
  
  	/* Take care of the remaining groups, only perm ones should be left */
  	spin_lock_bh(&br->multicast_lock);
  	hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
  		br_multicast_del_pg(br, pg);
  	spin_unlock_bh(&br->multicast_lock);
eb1d16414   Herbert Xu   bridge: Add core ...
802
  	del_timer_sync(&port->multicast_router_timer);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
803
  	free_percpu(port->mcast_stats);
eb1d16414   Herbert Xu   bridge: Add core ...
804
  }
90010b36e   Linus Lüssing   bridge: rename st...
805
  static void br_multicast_enable(struct bridge_mcast_own_query *query)
561f1103a   Herbert Xu   bridge: Add multi...
806
  {
cc0fdd802   Linus Lüssing   bridge: separate ...
807
  	query->startup_sent = 0;
561f1103a   Herbert Xu   bridge: Add multi...
808

cc0fdd802   Linus Lüssing   bridge: separate ...
809
810
811
  	if (try_to_del_timer_sync(&query->timer) >= 0 ||
  	    del_timer(&query->timer))
  		mod_timer(&query->timer, jiffies);
561f1103a   Herbert Xu   bridge: Add multi...
812
  }
7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
813
  static void __br_multicast_enable_port(struct net_bridge_port *port)
eb1d16414   Herbert Xu   bridge: Add core ...
814
815
  {
  	struct net_bridge *br = port->br;
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
816
  	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev))
7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
817
  		return;
eb1d16414   Herbert Xu   bridge: Add core ...
818

90010b36e   Linus Lüssing   bridge: rename st...
819
  	br_multicast_enable(&port->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
820
  #if IS_ENABLED(CONFIG_IPV6)
90010b36e   Linus Lüssing   bridge: rename st...
821
  	br_multicast_enable(&port->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
822
  #endif
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
823
824
  	if (port->multicast_router == MDB_RTR_TYPE_PERM &&
  	    hlist_unhashed(&port->rlist))
754bc547f   Satish Ashok   bridge: multicast...
825
  		br_multicast_add_router(br, port);
7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
826
  }
eb1d16414   Herbert Xu   bridge: Add core ...
827

7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
828
829
830
831
832
833
  void br_multicast_enable_port(struct net_bridge_port *port)
  {
  	struct net_bridge *br = port->br;
  
  	spin_lock(&br->multicast_lock);
  	__br_multicast_enable_port(port);
eb1d16414   Herbert Xu   bridge: Add core ...
834
835
836
837
838
839
840
  	spin_unlock(&br->multicast_lock);
  }
  
  void br_multicast_disable_port(struct net_bridge_port *port)
  {
  	struct net_bridge *br = port->br;
  	struct net_bridge_port_group *pg;
b67bfe0d4   Sasha Levin   hlist: drop the n...
841
  	struct hlist_node *n;
eb1d16414   Herbert Xu   bridge: Add core ...
842
843
  
  	spin_lock(&br->multicast_lock);
b67bfe0d4   Sasha Levin   hlist: drop the n...
844
  	hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
9d06b6d8a   Elad Raz   bridge: mdb: Sepa...
845
  		if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
e10177abf   Satish Ashok   bridge: multicast...
846
  			br_multicast_del_pg(br, pg);
eb1d16414   Herbert Xu   bridge: Add core ...
847

f12e7d95d   Nogah Frankel   bridge: mcast: Me...
848
  	__del_port_router(port);
eb1d16414   Herbert Xu   bridge: Add core ...
849
  	del_timer(&port->multicast_router_timer);
90010b36e   Linus Lüssing   bridge: rename st...
850
  	del_timer(&port->ip4_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
851
  #if IS_ENABLED(CONFIG_IPV6)
90010b36e   Linus Lüssing   bridge: rename st...
852
  	del_timer(&port->ip6_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
853
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
854
855
  	spin_unlock(&br->multicast_lock);
  }
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
856
857
  static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
  					 struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
858
859
  					 struct sk_buff *skb,
  					 u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
860
  {
6db6f0eae   Felix Fietkau   bridge: multicast...
861
  	const unsigned char *src;
eb1d16414   Herbert Xu   bridge: Add core ...
862
863
864
865
866
867
868
869
  	struct igmpv3_report *ih;
  	struct igmpv3_grec *grec;
  	int i;
  	int len;
  	int num;
  	int type;
  	int err = 0;
  	__be32 group;
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
870
  	u16 nsrcs;
eb1d16414   Herbert Xu   bridge: Add core ...
871

eb1d16414   Herbert Xu   bridge: Add core ...
872
873
  	ih = igmpv3_report_hdr(skb);
  	num = ntohs(ih->ngrec);
c2d4fbd21   Linus Lüssing   bridge: fix igmpv...
874
  	len = skb_transport_offset(skb) + sizeof(*ih);
eb1d16414   Herbert Xu   bridge: Add core ...
875
876
877
  
  	for (i = 0; i < num; i++) {
  		len += sizeof(*grec);
ba5ea6146   Linus Lüssing   bridge: simplify ...
878
  		if (!ip_mc_may_pull(skb, len))
eb1d16414   Herbert Xu   bridge: Add core ...
879
  			return -EINVAL;
fd218cf95   Herbert Xu   bridge: Fix IGMP3...
880
  		grec = (void *)(skb->data + len - sizeof(*grec));
eb1d16414   Herbert Xu   bridge: Add core ...
881
882
  		group = grec->grec_mca;
  		type = grec->grec_type;
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
883
  		nsrcs = ntohs(grec->grec_nsrcs);
eb1d16414   Herbert Xu   bridge: Add core ...
884

e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
885
  		len += nsrcs * 4;
ba5ea6146   Linus Lüssing   bridge: simplify ...
886
  		if (!ip_mc_may_pull(skb, len))
eb1d16414   Herbert Xu   bridge: Add core ...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
  			return -EINVAL;
  
  		/* We treat this as an IGMPv2 report for now. */
  		switch (type) {
  		case IGMPV3_MODE_IS_INCLUDE:
  		case IGMPV3_MODE_IS_EXCLUDE:
  		case IGMPV3_CHANGE_TO_INCLUDE:
  		case IGMPV3_CHANGE_TO_EXCLUDE:
  		case IGMPV3_ALLOW_NEW_SOURCES:
  		case IGMPV3_BLOCK_OLD_SOURCES:
  			break;
  
  		default:
  			continue;
  		}
6db6f0eae   Felix Fietkau   bridge: multicast...
902
  		src = eth_hdr(skb)->h_source;
bc8c20aca   Satish Ashok   bridge: multicast...
903
904
  		if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
  		     type == IGMPV3_MODE_IS_INCLUDE) &&
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
905
  		    nsrcs == 0) {
6db6f0eae   Felix Fietkau   bridge: multicast...
906
  			br_ip4_multicast_leave_group(br, port, group, vid, src);
bc8c20aca   Satish Ashok   bridge: multicast...
907
  		} else {
6db6f0eae   Felix Fietkau   bridge: multicast...
908
909
  			err = br_ip4_multicast_add_group(br, port, group, vid,
  							 src);
bc8c20aca   Satish Ashok   bridge: multicast...
910
911
912
  			if (err)
  				break;
  		}
eb1d16414   Herbert Xu   bridge: Add core ...
913
914
915
916
  	}
  
  	return err;
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
917
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
918
919
  static int br_ip6_multicast_mld2_report(struct net_bridge *br,
  					struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
920
921
  					struct sk_buff *skb,
  					u16 vid)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
922
  {
ba5ea6146   Linus Lüssing   bridge: simplify ...
923
  	unsigned int nsrcs_offset;
6db6f0eae   Felix Fietkau   bridge: multicast...
924
  	const unsigned char *src;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
925
926
  	struct icmp6hdr *icmp6h;
  	struct mld2_grec *grec;
ba5ea6146   Linus Lüssing   bridge: simplify ...
927
  	unsigned int grec_len;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
928
929
930
931
  	int i;
  	int len;
  	int num;
  	int err = 0;
ba5ea6146   Linus Lüssing   bridge: simplify ...
932
  	if (!ipv6_mc_may_pull(skb, sizeof(*icmp6h)))
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
933
934
935
936
  		return -EINVAL;
  
  	icmp6h = icmp6_hdr(skb);
  	num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
c2d4fbd21   Linus Lüssing   bridge: fix igmpv...
937
  	len = skb_transport_offset(skb) + sizeof(*icmp6h);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
938
939
  
  	for (i = 0; i < num; i++) {
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
940
941
  		__be16 *_nsrcs, __nsrcs;
  		u16 nsrcs;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
942

ba5ea6146   Linus Lüssing   bridge: simplify ...
943
944
945
  		nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
  
  		if (skb_transport_offset(skb) + ipv6_transport_len(skb) <
5fc6266af   Linus Lüssing   bridge: mcast: Fi...
946
  		    nsrcs_offset + sizeof(__nsrcs))
ba5ea6146   Linus Lüssing   bridge: simplify ...
947
  			return -EINVAL;
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
948
949
950
  		_nsrcs = skb_header_pointer(skb, nsrcs_offset,
  					    sizeof(__nsrcs), &__nsrcs);
  		if (!_nsrcs)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
951
  			return -EINVAL;
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
952
953
  		nsrcs = ntohs(*_nsrcs);
  		grec_len = struct_size(grec, grec_src, nsrcs);
ba5ea6146   Linus Lüssing   bridge: simplify ...
954
955
  
  		if (!ipv6_mc_may_pull(skb, len + grec_len))
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
956
957
958
  			return -EINVAL;
  
  		grec = (struct mld2_grec *)(skb->data + len);
ba5ea6146   Linus Lüssing   bridge: simplify ...
959
  		len += grec_len;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  
  		/* We treat these as MLDv1 reports for now. */
  		switch (grec->grec_type) {
  		case MLD2_MODE_IS_INCLUDE:
  		case MLD2_MODE_IS_EXCLUDE:
  		case MLD2_CHANGE_TO_INCLUDE:
  		case MLD2_CHANGE_TO_EXCLUDE:
  		case MLD2_ALLOW_NEW_SOURCES:
  		case MLD2_BLOCK_OLD_SOURCES:
  			break;
  
  		default:
  			continue;
  		}
6db6f0eae   Felix Fietkau   bridge: multicast...
974
  		src = eth_hdr(skb)->h_source;
bc8c20aca   Satish Ashok   bridge: multicast...
975
976
  		if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
  		     grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
e57f61858   Nikolay Aleksandrov   net: bridge: mcas...
977
  		    nsrcs == 0) {
bc8c20aca   Satish Ashok   bridge: multicast...
978
  			br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
6db6f0eae   Felix Fietkau   bridge: multicast...
979
  						     vid, src);
bc8c20aca   Satish Ashok   bridge: multicast...
980
981
  		} else {
  			err = br_ip6_multicast_add_group(br, port,
6db6f0eae   Felix Fietkau   bridge: multicast...
982
983
  							 &grec->grec_mca, vid,
  							 src);
9264251ee   Davide Caratti   bridge: re-introd...
984
  			if (err)
bc8c20aca   Satish Ashok   bridge: multicast...
985
986
  				break;
  		}
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
987
988
989
990
991
  	}
  
  	return err;
  }
  #endif
dc4eb53a9   Linus Lüssing   bridge: adhere to...
992
  static bool br_ip4_multicast_select_querier(struct net_bridge *br,
2cd414319   Linus Lüssing   bridge: memorize ...
993
  					    struct net_bridge_port *port,
dc4eb53a9   Linus Lüssing   bridge: adhere to...
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  					    __be32 saddr)
  {
  	if (!timer_pending(&br->ip4_own_query.timer) &&
  	    !timer_pending(&br->ip4_other_query.timer))
  		goto update;
  
  	if (!br->ip4_querier.addr.u.ip4)
  		goto update;
  
  	if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.u.ip4))
  		goto update;
  
  	return false;
  
  update:
  	br->ip4_querier.addr.u.ip4 = saddr;
2cd414319   Linus Lüssing   bridge: memorize ...
1010
1011
  	/* update protected by general multicast_lock by caller */
  	rcu_assign_pointer(br->ip4_querier.port, port);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1012
1013
1014
1015
1016
  	return true;
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
  static bool br_ip6_multicast_select_querier(struct net_bridge *br,
2cd414319   Linus Lüssing   bridge: memorize ...
1017
  					    struct net_bridge_port *port,
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  					    struct in6_addr *saddr)
  {
  	if (!timer_pending(&br->ip6_own_query.timer) &&
  	    !timer_pending(&br->ip6_other_query.timer))
  		goto update;
  
  	if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.u.ip6) <= 0)
  		goto update;
  
  	return false;
  
  update:
  	br->ip6_querier.addr.u.ip6 = *saddr;
2cd414319   Linus Lüssing   bridge: memorize ...
1031
1032
  	/* update protected by general multicast_lock by caller */
  	rcu_assign_pointer(br->ip6_querier.port, port);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1033
1034
1035
1036
1037
  	return true;
  }
  #endif
  
  static bool br_multicast_select_querier(struct net_bridge *br,
2cd414319   Linus Lüssing   bridge: memorize ...
1038
  					struct net_bridge_port *port,
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1039
1040
1041
1042
  					struct br_ip *saddr)
  {
  	switch (saddr->proto) {
  	case htons(ETH_P_IP):
2cd414319   Linus Lüssing   bridge: memorize ...
1043
  		return br_ip4_multicast_select_querier(br, port, saddr->u.ip4);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1044
1045
  #if IS_ENABLED(CONFIG_IPV6)
  	case htons(ETH_P_IPV6):
2cd414319   Linus Lüssing   bridge: memorize ...
1046
  		return br_ip6_multicast_select_querier(br, port, &saddr->u.ip6);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1047
1048
1049
1050
1051
  #endif
  	}
  
  	return false;
  }
cc0fdd802   Linus Lüssing   bridge: separate ...
1052
  static void
90010b36e   Linus Lüssing   bridge: rename st...
1053
1054
1055
  br_multicast_update_query_timer(struct net_bridge *br,
  				struct bridge_mcast_other_query *query,
  				unsigned long max_delay)
b00589af3   Linus Lüssing   bridge: disable s...
1056
  {
90010b36e   Linus Lüssing   bridge: rename st...
1057
1058
  	if (!timer_pending(&query->timer))
  		query->delay_time = jiffies + max_delay;
b00589af3   Linus Lüssing   bridge: disable s...
1059

90010b36e   Linus Lüssing   bridge: rename st...
1060
  	mod_timer(&query->timer, jiffies + br->multicast_querier_interval);
b00589af3   Linus Lüssing   bridge: disable s...
1061
  }
6d5496483   Nogah Frankel   switchdev: bridge...
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  static void br_port_mc_router_state_change(struct net_bridge_port *p,
  					   bool is_mc_router)
  {
  	struct switchdev_attr attr = {
  		.orig_dev = p->dev,
  		.id = SWITCHDEV_ATTR_ID_PORT_MROUTER,
  		.flags = SWITCHDEV_F_DEFER,
  		.u.mrouter = is_mc_router,
  	};
  
  	switchdev_port_attr_set(p->dev, &attr);
  }
7e80c1244   stephen hemminger   bridge: simplify ...
1074
  /*
7c77602f5   Cong Wang   bridge: fix a typ...
1075
   * Add port to router_list
7e80c1244   stephen hemminger   bridge: simplify ...
1076
1077
1078
   *  list is maintained ordered by pointer value
   *  and locked by br->multicast_lock and RCU
   */
0909e1175   Herbert Xu   bridge: Add multi...
1079
1080
1081
  static void br_multicast_add_router(struct net_bridge *br,
  				    struct net_bridge_port *port)
  {
dcdca2c49   stephen hemminger   bridge: multicast...
1082
  	struct net_bridge_port *p;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1083
  	struct hlist_node *slot = NULL;
dcdca2c49   stephen hemminger   bridge: multicast...
1084

1a040eaca   Nikolay Aleksandrov   bridge: fix multi...
1085
1086
  	if (!hlist_unhashed(&port->rlist))
  		return;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1087
  	hlist_for_each_entry(p, &br->router_list, rlist) {
7e80c1244   stephen hemminger   bridge: simplify ...
1088
1089
  		if ((unsigned long) port >= (unsigned long) p)
  			break;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1090
  		slot = &p->rlist;
dcdca2c49   stephen hemminger   bridge: multicast...
1091
  	}
7e80c1244   stephen hemminger   bridge: simplify ...
1092
  	if (slot)
1d023284c   Ken Helias   list: fix order o...
1093
  		hlist_add_behind_rcu(&port->rlist, slot);
dcdca2c49   stephen hemminger   bridge: multicast...
1094
1095
  	else
  		hlist_add_head_rcu(&port->rlist, &br->router_list);
949f1e39a   Satish Ashok   bridge: mdb: noti...
1096
  	br_rtr_notify(br->dev, port, RTM_NEWMDB);
6d5496483   Nogah Frankel   switchdev: bridge...
1097
  	br_port_mc_router_state_change(port, true);
0909e1175   Herbert Xu   bridge: Add multi...
1098
  }
eb1d16414   Herbert Xu   bridge: Add core ...
1099
1100
1101
1102
  static void br_multicast_mark_router(struct net_bridge *br,
  				     struct net_bridge_port *port)
  {
  	unsigned long now = jiffies;
eb1d16414   Herbert Xu   bridge: Add core ...
1103
1104
  
  	if (!port) {
770414207   Yotam Gigi   net: bridge: Noti...
1105
1106
1107
  		if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) {
  			if (!timer_pending(&br->multicast_router_timer))
  				br_mc_router_state_change(br, true);
eb1d16414   Herbert Xu   bridge: Add core ...
1108
1109
  			mod_timer(&br->multicast_router_timer,
  				  now + br->multicast_querier_interval);
770414207   Yotam Gigi   net: bridge: Noti...
1110
  		}
eb1d16414   Herbert Xu   bridge: Add core ...
1111
1112
  		return;
  	}
a55d8246a   Nikolay Aleksandrov   bridge: mcast: ad...
1113
1114
  	if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
  	    port->multicast_router == MDB_RTR_TYPE_PERM)
eb1d16414   Herbert Xu   bridge: Add core ...
1115
  		return;
0909e1175   Herbert Xu   bridge: Add multi...
1116
  	br_multicast_add_router(br, port);
eb1d16414   Herbert Xu   bridge: Add core ...
1117

eb1d16414   Herbert Xu   bridge: Add core ...
1118
1119
1120
1121
1122
1123
  	mod_timer(&port->multicast_router_timer,
  		  now + br->multicast_querier_interval);
  }
  
  static void br_multicast_query_received(struct net_bridge *br,
  					struct net_bridge_port *port,
90010b36e   Linus Lüssing   bridge: rename st...
1124
  					struct bridge_mcast_other_query *query,
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1125
  					struct br_ip *saddr,
b00589af3   Linus Lüssing   bridge: disable s...
1126
  					unsigned long max_delay)
eb1d16414   Herbert Xu   bridge: Add core ...
1127
  {
2cd414319   Linus Lüssing   bridge: memorize ...
1128
  	if (!br_multicast_select_querier(br, port, saddr))
eb1d16414   Herbert Xu   bridge: Add core ...
1129
  		return;
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1130
  	br_multicast_update_query_timer(br, query, max_delay);
278e2148c   Hangbin Liu   Revert "bridge: d...
1131
  	br_multicast_mark_router(br, port);
eb1d16414   Herbert Xu   bridge: Add core ...
1132
  }
9c2e955c4   zhong jiang   net/bridge/br_mul...
1133
1134
1135
1136
  static void br_ip4_multicast_query(struct net_bridge *br,
  				   struct net_bridge_port *port,
  				   struct sk_buff *skb,
  				   u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
1137
  {
ba5ea6146   Linus Lüssing   bridge: simplify ...
1138
  	unsigned int transport_len = ip_transport_len(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
1139
  	const struct iphdr *iph = ip_hdr(skb);
eb1d16414   Herbert Xu   bridge: Add core ...
1140
1141
1142
1143
  	struct igmphdr *ih = igmp_hdr(skb);
  	struct net_bridge_mdb_entry *mp;
  	struct igmpv3_query *ih3;
  	struct net_bridge_port_group *p;
e80516880   Eric Dumazet   bridge: add RCU a...
1144
  	struct net_bridge_port_group __rcu **pp;
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1145
  	struct br_ip saddr;
eb1d16414   Herbert Xu   bridge: Add core ...
1146
1147
1148
1149
1150
1151
1152
1153
  	unsigned long max_delay;
  	unsigned long now = jiffies;
  	__be32 group;
  
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) ||
  	    (port && port->state == BR_STATE_DISABLED))
  		goto out;
eb1d16414   Herbert Xu   bridge: Add core ...
1154
  	group = ih->group;
ba5ea6146   Linus Lüssing   bridge: simplify ...
1155
  	if (transport_len == sizeof(*ih)) {
eb1d16414   Herbert Xu   bridge: Add core ...
1156
1157
1158
1159
1160
1161
  		max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
  
  		if (!max_delay) {
  			max_delay = 10 * HZ;
  			group = 0;
  		}
ba5ea6146   Linus Lüssing   bridge: simplify ...
1162
  	} else if (transport_len >= sizeof(*ih3)) {
eb1d16414   Herbert Xu   bridge: Add core ...
1163
1164
  		ih3 = igmpv3_query_hdr(skb);
  		if (ih3->nsrcs)
bec68ff16   YOSHIFUJI Hideaki   bridge: ensure to...
1165
  			goto out;
eb1d16414   Herbert Xu   bridge: Add core ...
1166

0ba8c9ec2   YOSHIFUJI Hideaki / 吉藤英明   bridge br_multica...
1167
1168
  		max_delay = ih3->code ?
  			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1169
  	} else {
9ed973cc4   Linus Lüssing   bridge: multicast...
1170
1171
  		goto out;
  	}
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1172
1173
1174
  	if (!group) {
  		saddr.proto = htons(ETH_P_IP);
  		saddr.u.ip4 = iph->saddr;
b00589af3   Linus Lüssing   bridge: disable s...
1175

dc4eb53a9   Linus Lüssing   bridge: adhere to...
1176
1177
  		br_multicast_query_received(br, port, &br->ip4_other_query,
  					    &saddr, max_delay);
eb1d16414   Herbert Xu   bridge: Add core ...
1178
  		goto out;
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1179
  	}
eb1d16414   Herbert Xu   bridge: Add core ...
1180

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1181
  	mp = br_mdb_ip4_get(br, group, vid);
eb1d16414   Herbert Xu   bridge: Add core ...
1182
1183
1184
1185
  	if (!mp)
  		goto out;
  
  	max_delay *= br->multicast_last_member_count;
ff0fd34ea   Andrew Lunn   net: bridge: Rena...
1186
  	if (mp->host_joined &&
eb1d16414   Herbert Xu   bridge: Add core ...
1187
1188
1189
1190
  	    (timer_pending(&mp->timer) ?
  	     time_after(mp->timer.expires, now + max_delay) :
  	     try_to_del_timer_sync(&mp->timer) >= 0))
  		mod_timer(&mp->timer, now + max_delay);
e80516880   Eric Dumazet   bridge: add RCU a...
1191
1192
1193
  	for (pp = &mp->ports;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     pp = &p->next) {
eb1d16414   Herbert Xu   bridge: Add core ...
1194
1195
1196
  		if (timer_pending(&p->timer) ?
  		    time_after(p->timer.expires, now + max_delay) :
  		    try_to_del_timer_sync(&p->timer) >= 0)
24f9cdcbd   Herbert Xu   bridge: Fix timer...
1197
  			mod_timer(&p->timer, now + max_delay);
eb1d16414   Herbert Xu   bridge: Add core ...
1198
1199
1200
1201
  	}
  
  out:
  	spin_unlock(&br->multicast_lock);
eb1d16414   Herbert Xu   bridge: Add core ...
1202
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1203
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1204
1205
  static int br_ip6_multicast_query(struct net_bridge *br,
  				  struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
1206
1207
  				  struct sk_buff *skb,
  				  u16 vid)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1208
  {
ba5ea6146   Linus Lüssing   bridge: simplify ...
1209
  	unsigned int transport_len = ipv6_transport_len(skb);
eca2a43bb   stephen hemminger   bridge: fix icmpv...
1210
  	struct mld_msg *mld;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1211
1212
  	struct net_bridge_mdb_entry *mp;
  	struct mld2_query *mld2q;
e80516880   Eric Dumazet   bridge: add RCU a...
1213
1214
  	struct net_bridge_port_group *p;
  	struct net_bridge_port_group __rcu **pp;
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1215
  	struct br_ip saddr;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1216
1217
  	unsigned long max_delay;
  	unsigned long now = jiffies;
856ce5d08   Linus Lüssing   bridge: fix igmp ...
1218
  	unsigned int offset = skb_transport_offset(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
1219
  	const struct in6_addr *group = NULL;
9ed973cc4   Linus Lüssing   bridge: multicast...
1220
  	bool is_general_query;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1221
1222
1223
1224
1225
1226
  	int err = 0;
  
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) ||
  	    (port && port->state == BR_STATE_DISABLED))
  		goto out;
ba5ea6146   Linus Lüssing   bridge: simplify ...
1227
  	if (transport_len == sizeof(*mld)) {
856ce5d08   Linus Lüssing   bridge: fix igmp ...
1228
  		if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1229
1230
1231
1232
  			err = -EINVAL;
  			goto out;
  		}
  		mld = (struct mld_msg *) icmp6_hdr(skb);
4715213d9   Li RongQing   bridge: fix endian
1233
  		max_delay = msecs_to_jiffies(ntohs(mld->mld_maxdelay));
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1234
1235
  		if (max_delay)
  			group = &mld->mld_mca;
248ba8ec0   Linus Lüssing   bridge: don't try...
1236
  	} else {
856ce5d08   Linus Lüssing   bridge: fix igmp ...
1237
  		if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) {
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1238
1239
1240
1241
1242
1243
  			err = -EINVAL;
  			goto out;
  		}
  		mld2q = (struct mld2_query *)icmp6_hdr(skb);
  		if (!mld2q->mld2q_nsrcs)
  			group = &mld2q->mld2q_mca;
e3f5b1704   Daniel Borkmann   net: ipv6: mld: g...
1244
1245
  
  		max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1246
  	}
9ed973cc4   Linus Lüssing   bridge: multicast...
1247
  	is_general_query = group && ipv6_addr_any(group);
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1248
1249
  	if (is_general_query) {
  		saddr.proto = htons(ETH_P_IPV6);
3b26a5d03   Nikolay Aleksandrov   net: bridge: mcas...
1250
  		saddr.u.ip6 = ipv6_hdr(skb)->saddr;
b00589af3   Linus Lüssing   bridge: disable s...
1251

dc4eb53a9   Linus Lüssing   bridge: adhere to...
1252
1253
  		br_multicast_query_received(br, port, &br->ip6_other_query,
  					    &saddr, max_delay);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1254
  		goto out;
6c03ee8bd   Linus Lüssing   bridge: fix smatc...
1255
1256
  	} else if (!group) {
  		goto out;
dc4eb53a9   Linus Lüssing   bridge: adhere to...
1257
  	}
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1258

19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1259
  	mp = br_mdb_ip6_get(br, group, vid);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1260
1261
1262
1263
  	if (!mp)
  		goto out;
  
  	max_delay *= br->multicast_last_member_count;
ff0fd34ea   Andrew Lunn   net: bridge: Rena...
1264
  	if (mp->host_joined &&
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1265
1266
1267
1268
  	    (timer_pending(&mp->timer) ?
  	     time_after(mp->timer.expires, now + max_delay) :
  	     try_to_del_timer_sync(&mp->timer) >= 0))
  		mod_timer(&mp->timer, now + max_delay);
e80516880   Eric Dumazet   bridge: add RCU a...
1269
1270
1271
  	for (pp = &mp->ports;
  	     (p = mlock_dereference(*pp, br)) != NULL;
  	     pp = &p->next) {
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1272
1273
1274
  		if (timer_pending(&p->timer) ?
  		    time_after(p->timer.expires, now + max_delay) :
  		    try_to_del_timer_sync(&p->timer) >= 0)
24f9cdcbd   Herbert Xu   bridge: Fix timer...
1275
  			mod_timer(&p->timer, now + max_delay);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1276
1277
1278
1279
1280
1281
1282
  	}
  
  out:
  	spin_unlock(&br->multicast_lock);
  	return err;
  }
  #endif
90010b36e   Linus Lüssing   bridge: rename st...
1283
1284
1285
1286
1287
  static void
  br_multicast_leave_group(struct net_bridge *br,
  			 struct net_bridge_port *port,
  			 struct br_ip *group,
  			 struct bridge_mcast_other_query *other_query,
6db6f0eae   Felix Fietkau   bridge: multicast...
1288
1289
  			 struct bridge_mcast_own_query *own_query,
  			 const unsigned char *src)
eb1d16414   Herbert Xu   bridge: Add core ...
1290
  {
eb1d16414   Herbert Xu   bridge: Add core ...
1291
1292
1293
1294
  	struct net_bridge_mdb_entry *mp;
  	struct net_bridge_port_group *p;
  	unsigned long now;
  	unsigned long time;
eb1d16414   Herbert Xu   bridge: Add core ...
1295
1296
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) ||
544586f74   Satish Ashok   bridge: mcast: gi...
1297
  	    (port && port->state == BR_STATE_DISABLED))
eb1d16414   Herbert Xu   bridge: Add core ...
1298
  		goto out;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1299
  	mp = br_mdb_ip_get(br, group);
eb1d16414   Herbert Xu   bridge: Add core ...
1300
1301
  	if (!mp)
  		goto out;
544586f74   Satish Ashok   bridge: mcast: gi...
1302
1303
1304
1305
1306
1307
  	if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
  		struct net_bridge_port_group __rcu **pp;
  
  		for (pp = &mp->ports;
  		     (p = mlock_dereference(*pp, br)) != NULL;
  		     pp = &p->next) {
6db6f0eae   Felix Fietkau   bridge: multicast...
1308
  			if (!br_port_group_equal(p, port, src))
544586f74   Satish Ashok   bridge: mcast: gi...
1309
  				continue;
5c725b6b6   Nikolay Aleksandrov   net: bridge: mcas...
1310
1311
  			if (p->flags & MDB_PG_FLAGS_PERMANENT)
  				break;
544586f74   Satish Ashok   bridge: mcast: gi...
1312
1313
1314
  			rcu_assign_pointer(*pp, p->next);
  			hlist_del_init(&p->mglist);
  			del_timer(&p->timer);
4329596cb   Nikolay Aleksandrov   net: bridge: mult...
1315
  			kfree_rcu(p, rcu);
45ebcce56   Elad Raz   bridge: mdb: Mark...
1316
  			br_mdb_notify(br->dev, port, group, RTM_DELMDB,
3247b2720   Nikolay Aleksandrov   net: bridge: mcas...
1317
  				      p->flags | MDB_PG_FLAGS_FAST_LEAVE);
544586f74   Satish Ashok   bridge: mcast: gi...
1318

ff0fd34ea   Andrew Lunn   net: bridge: Rena...
1319
  			if (!mp->ports && !mp->host_joined &&
544586f74   Satish Ashok   bridge: mcast: gi...
1320
1321
1322
1323
1324
1325
1326
1327
  			    netif_running(br->dev))
  				mod_timer(&mp->timer, jiffies);
  		}
  		goto out;
  	}
  
  	if (timer_pending(&other_query->timer))
  		goto out;
675779adb   Nikolay Aleksandrov   net: bridge: conv...
1328
  	if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) {
6b7df111e   Cong Wang   bridge: send quer...
1329
1330
1331
1332
  		__br_multicast_send_query(br, port, &mp->addr);
  
  		time = jiffies + br->multicast_last_member_count *
  				 br->multicast_last_member_interval;
cc0fdd802   Linus Lüssing   bridge: separate ...
1333

90010b36e   Linus Lüssing   bridge: rename st...
1334
  		mod_timer(&own_query->timer, time);
6b7df111e   Cong Wang   bridge: send quer...
1335
1336
1337
1338
  
  		for (p = mlock_dereference(mp->ports, br);
  		     p != NULL;
  		     p = mlock_dereference(p->next, br)) {
6db6f0eae   Felix Fietkau   bridge: multicast...
1339
  			if (!br_port_group_equal(p, port, src))
6b7df111e   Cong Wang   bridge: send quer...
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  				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;
  		}
  	}
eb1d16414   Herbert Xu   bridge: Add core ...
1352
1353
1354
1355
1356
  	now = jiffies;
  	time = now + br->multicast_last_member_count *
  		     br->multicast_last_member_interval;
  
  	if (!port) {
ff0fd34ea   Andrew Lunn   net: bridge: Rena...
1357
  		if (mp->host_joined &&
eb1d16414   Herbert Xu   bridge: Add core ...
1358
1359
1360
1361
  		    (timer_pending(&mp->timer) ?
  		     time_after(mp->timer.expires, time) :
  		     try_to_del_timer_sync(&mp->timer) >= 0)) {
  			mod_timer(&mp->timer, time);
eb1d16414   Herbert Xu   bridge: Add core ...
1362
  		}
454594f3b   Linus Lüssing   Revert "bridge: o...
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
  
  		goto out;
  	}
  
  	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;
eb1d16414   Herbert Xu   bridge: Add core ...
1381
  	}
eb1d16414   Herbert Xu   bridge: Add core ...
1382
1383
1384
  out:
  	spin_unlock(&br->multicast_lock);
  }
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1385
1386
  static void br_ip4_multicast_leave_group(struct net_bridge *br,
  					 struct net_bridge_port *port,
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
1387
  					 __be32 group,
6db6f0eae   Felix Fietkau   bridge: multicast...
1388
1389
  					 __u16 vid,
  					 const unsigned char *src)
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1390
1391
  {
  	struct br_ip br_group;
90010b36e   Linus Lüssing   bridge: rename st...
1392
  	struct bridge_mcast_own_query *own_query;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1393
1394
1395
  
  	if (ipv4_is_local_multicast(group))
  		return;
90010b36e   Linus Lüssing   bridge: rename st...
1396
  	own_query = port ? &port->ip4_own_query : &br->ip4_own_query;
1515a63fc   Nikolay Aleksandrov   net: bridge: alwa...
1397
  	memset(&br_group, 0, sizeof(br_group));
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1398
1399
  	br_group.u.ip4 = group;
  	br_group.proto = htons(ETH_P_IP);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
1400
  	br_group.vid = vid;
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1401

90010b36e   Linus Lüssing   bridge: rename st...
1402
  	br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
6db6f0eae   Felix Fietkau   bridge: multicast...
1403
  				 own_query, src);
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1404
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1405
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1406
1407
  static void br_ip6_multicast_leave_group(struct net_bridge *br,
  					 struct net_bridge_port *port,
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
1408
  					 const struct in6_addr *group,
6db6f0eae   Felix Fietkau   bridge: multicast...
1409
1410
  					 __u16 vid,
  					 const unsigned char *src)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1411
1412
  {
  	struct br_ip br_group;
90010b36e   Linus Lüssing   bridge: rename st...
1413
  	struct bridge_mcast_own_query *own_query;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1414

3c3769e63   Linus Lüssing   bridge: apply mul...
1415
  	if (ipv6_addr_is_ll_all_nodes(group))
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1416
  		return;
90010b36e   Linus Lüssing   bridge: rename st...
1417
  	own_query = port ? &port->ip6_own_query : &br->ip6_own_query;
1515a63fc   Nikolay Aleksandrov   net: bridge: alwa...
1418
  	memset(&br_group, 0, sizeof(br_group));
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1419
  	br_group.u.ip6 = *group;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1420
  	br_group.proto = htons(ETH_P_IPV6);
b0e9a30dd   Vlad Yasevich   bridge: Add vlan ...
1421
  	br_group.vid = vid;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1422

90010b36e   Linus Lüssing   bridge: rename st...
1423
  	br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
6db6f0eae   Felix Fietkau   bridge: multicast...
1424
  				 own_query, src);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1425
1426
  }
  #endif
8ef2a9a59   YOSHIFUJI Hideaki   bridge br_multica...
1427

1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1428
1429
1430
1431
1432
1433
  static void br_multicast_err_count(const struct net_bridge *br,
  				   const struct net_bridge_port *p,
  				   __be16 proto)
  {
  	struct bridge_mcast_stats __percpu *stats;
  	struct bridge_mcast_stats *pstats;
675779adb   Nikolay Aleksandrov   net: bridge: conv...
1434
  	if (!br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED))
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
  		return;
  
  	if (p)
  		stats = p->mcast_stats;
  	else
  		stats = br->mcast_stats;
  	if (WARN_ON(!stats))
  		return;
  
  	pstats = this_cpu_ptr(stats);
  
  	u64_stats_update_begin(&pstats->syncp);
  	switch (proto) {
  	case htons(ETH_P_IP):
  		pstats->mstats.igmp_parse_errors++;
  		break;
  #if IS_ENABLED(CONFIG_IPV6)
  	case htons(ETH_P_IPV6):
  		pstats->mstats.mld_parse_errors++;
  		break;
  #endif
  	}
  	u64_stats_update_end(&pstats->syncp);
  }
91b02d3d1   Nikolay Aleksandrov   bridge: mcast: ad...
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
  static void br_multicast_pim(struct net_bridge *br,
  			     struct net_bridge_port *port,
  			     const struct sk_buff *skb)
  {
  	unsigned int offset = skb_transport_offset(skb);
  	struct pimhdr *pimhdr, _pimhdr;
  
  	pimhdr = skb_header_pointer(skb, offset, sizeof(_pimhdr), &_pimhdr);
  	if (!pimhdr || pim_hdr_version(pimhdr) != PIM_VERSION ||
  	    pim_hdr_type(pimhdr) != PIM_TYPE_HELLO)
  		return;
  
  	br_multicast_mark_router(br, port);
  }
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
  static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
  				    struct net_bridge_port *port,
  				    struct sk_buff *skb)
  {
  	if (ip_hdr(skb)->protocol != IPPROTO_IGMP ||
  	    igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
  		return -ENOMSG;
  
  	br_multicast_mark_router(br, port);
  
  	return 0;
  }
eb1d16414   Herbert Xu   bridge: Add core ...
1485
1486
  static int br_multicast_ipv4_rcv(struct net_bridge *br,
  				 struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
1487
1488
  				 struct sk_buff *skb,
  				 u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
1489
  {
6db6f0eae   Felix Fietkau   bridge: multicast...
1490
  	const unsigned char *src;
eb1d16414   Herbert Xu   bridge: Add core ...
1491
  	struct igmphdr *ih;
eb1d16414   Herbert Xu   bridge: Add core ...
1492
  	int err;
ba5ea6146   Linus Lüssing   bridge: simplify ...
1493
  	err = ip_mc_check_igmp(skb);
eb1d16414   Herbert Xu   bridge: Add core ...
1494

9afd85c9e   Linus Lüssing   net: Export IGMP/...
1495
  	if (err == -ENOMSG) {
91b02d3d1   Nikolay Aleksandrov   bridge: mcast: ad...
1496
  		if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) {
bd4265fe3   Herbert Xu   bridge: Only floo...
1497
  			BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
91b02d3d1   Nikolay Aleksandrov   bridge: mcast: ad...
1498
1499
1500
  		} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
  			if (ip_hdr(skb)->protocol == IPPROTO_PIM)
  				br_multicast_pim(br, port, skb);
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
1501
  		} else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) {
08e71623c   Li RongQing   bridge: remove re...
1502
  			br_ip4_multicast_mrd_rcv(br, port, skb);
91b02d3d1   Nikolay Aleksandrov   bridge: mcast: ad...
1503
  		}
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
1504

eb1d16414   Herbert Xu   bridge: Add core ...
1505
  		return 0;
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1506
  	} else if (err < 0) {
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1507
  		br_multicast_err_count(br, port, skb->protocol);
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1508
  		return err;
bd4265fe3   Herbert Xu   bridge: Only floo...
1509
  	}
eb1d16414   Herbert Xu   bridge: Add core ...
1510

9afd85c9e   Linus Lüssing   net: Export IGMP/...
1511
  	ih = igmp_hdr(skb);
6db6f0eae   Felix Fietkau   bridge: multicast...
1512
  	src = eth_hdr(skb)->h_source;
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1513
  	BR_INPUT_SKB_CB(skb)->igmp = ih->type;
eb1d16414   Herbert Xu   bridge: Add core ...
1514
1515
1516
1517
  
  	switch (ih->type) {
  	case IGMP_HOST_MEMBERSHIP_REPORT:
  	case IGMPV2_HOST_MEMBERSHIP_REPORT:
62b2bcb49   Fernando Luis Vázquez Cao   IGMP snooping: se...
1518
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
6db6f0eae   Felix Fietkau   bridge: multicast...
1519
  		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
eb1d16414   Herbert Xu   bridge: Add core ...
1520
1521
  		break;
  	case IGMPV3_HOST_MEMBERSHIP_REPORT:
ba5ea6146   Linus Lüssing   bridge: simplify ...
1522
  		err = br_ip4_multicast_igmp3_report(br, port, skb, vid);
eb1d16414   Herbert Xu   bridge: Add core ...
1523
1524
  		break;
  	case IGMP_HOST_MEMBERSHIP_QUERY:
ba5ea6146   Linus Lüssing   bridge: simplify ...
1525
  		br_ip4_multicast_query(br, port, skb, vid);
eb1d16414   Herbert Xu   bridge: Add core ...
1526
1527
  		break;
  	case IGMP_HOST_LEAVE_MESSAGE:
6db6f0eae   Felix Fietkau   bridge: multicast...
1528
  		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
eb1d16414   Herbert Xu   bridge: Add core ...
1529
1530
  		break;
  	}
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
1531
  	br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1532
  			   BR_MCAST_DIR_RX);
eb1d16414   Herbert Xu   bridge: Add core ...
1533
1534
  	return err;
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1535
  #if IS_ENABLED(CONFIG_IPV6)
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
  static int br_ip6_multicast_mrd_rcv(struct net_bridge *br,
  				    struct net_bridge_port *port,
  				    struct sk_buff *skb)
  {
  	int ret;
  
  	if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
  		return -ENOMSG;
  
  	ret = ipv6_mc_check_icmpv6(skb);
  	if (ret < 0)
  		return ret;
  
  	if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV)
  		return -ENOMSG;
  
  	br_multicast_mark_router(br, port);
  
  	return 0;
  }
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1556
1557
  static int br_multicast_ipv6_rcv(struct net_bridge *br,
  				 struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
1558
1559
  				 struct sk_buff *skb,
  				 u16 vid)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1560
  {
6db6f0eae   Felix Fietkau   bridge: multicast...
1561
  	const unsigned char *src;
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1562
  	struct mld_msg *mld;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1563
  	int err;
ba5ea6146   Linus Lüssing   bridge: simplify ...
1564
  	err = ipv6_mc_check_mld(skb);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1565

9afd85c9e   Linus Lüssing   net: Export IGMP/...
1566
1567
1568
  	if (err == -ENOMSG) {
  		if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
  			BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
4b3087c7e   Linus Lüssing   bridge: Snoop Mul...
1569
1570
1571
1572
1573
1574
1575
1576
1577
  
  		if (ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) {
  			err = br_ip6_multicast_mrd_rcv(br, port, skb);
  
  			if (err < 0 && err != -ENOMSG) {
  				br_multicast_err_count(br, port, skb->protocol);
  				return err;
  			}
  		}
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1578
  		return 0;
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1579
  	} else if (err < 0) {
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1580
  		br_multicast_err_count(br, port, skb->protocol);
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1581
  		return err;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1582
  	}
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1583
  	mld = (struct mld_msg *)skb_transport_header(skb);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1584
  	BR_INPUT_SKB_CB(skb)->igmp = mld->mld_type;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1585

9afd85c9e   Linus Lüssing   net: Export IGMP/...
1586
  	switch (mld->mld_type) {
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1587
  	case ICMPV6_MGM_REPORT:
6db6f0eae   Felix Fietkau   bridge: multicast...
1588
  		src = eth_hdr(skb)->h_source;
fc2af6c73   Fernando Luis Vázquez Cao   IGMP snooping: se...
1589
  		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
6db6f0eae   Felix Fietkau   bridge: multicast...
1590
1591
  		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
  						 src);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1592
  		break;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1593
  	case ICMPV6_MLD2_REPORT:
ba5ea6146   Linus Lüssing   bridge: simplify ...
1594
  		err = br_ip6_multicast_mld2_report(br, port, skb, vid);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1595
1596
  		break;
  	case ICMPV6_MGM_QUERY:
ba5ea6146   Linus Lüssing   bridge: simplify ...
1597
  		err = br_ip6_multicast_query(br, port, skb, vid);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1598
1599
  		break;
  	case ICMPV6_MGM_REDUCTION:
6db6f0eae   Felix Fietkau   bridge: multicast...
1600
1601
  		src = eth_hdr(skb)->h_source;
  		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
9afd85c9e   Linus Lüssing   net: Export IGMP/...
1602
  		break;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1603
  	}
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
1604
  	br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1605
  			   BR_MCAST_DIR_RX);
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1606
1607
1608
  	return err;
  }
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
1609
  int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
06499098a   Vlad Yasevich   bridge: pass corr...
1610
  		     struct sk_buff *skb, u16 vid)
eb1d16414   Herbert Xu   bridge: Add core ...
1611
  {
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1612
  	int ret = 0;
1fafc7a93   YOSHIFUJI Hideaki / 吉藤英明   bridge br_multica...
1613
1614
  	BR_INPUT_SKB_CB(skb)->igmp = 0;
  	BR_INPUT_SKB_CB(skb)->mrouters_only = 0;
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
1615
  	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
eb1d16414   Herbert Xu   bridge: Add core ...
1616
1617
1618
1619
  		return 0;
  
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1620
1621
  		ret = br_multicast_ipv4_rcv(br, port, skb, vid);
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1622
  #if IS_ENABLED(CONFIG_IPV6)
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1623
  	case htons(ETH_P_IPV6):
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1624
1625
  		ret = br_multicast_ipv6_rcv(br, port, skb, vid);
  		break;
08b202b67   YOSHIFUJI Hideaki   bridge br_multica...
1626
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
1627
  	}
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
1628
  	return ret;
eb1d16414   Herbert Xu   bridge: Add core ...
1629
  }
cc0fdd802   Linus Lüssing   bridge: separate ...
1630
  static void br_multicast_query_expired(struct net_bridge *br,
2cd414319   Linus Lüssing   bridge: memorize ...
1631
1632
  				       struct bridge_mcast_own_query *query,
  				       struct bridge_mcast_querier *querier)
cc0fdd802   Linus Lüssing   bridge: separate ...
1633
1634
1635
1636
  {
  	spin_lock(&br->multicast_lock);
  	if (query->startup_sent < br->multicast_startup_query_count)
  		query->startup_sent++;
71d9f6149   Eric Dumazet   bridge: fix br_mu...
1637
  	RCU_INIT_POINTER(querier->port, NULL);
cc0fdd802   Linus Lüssing   bridge: separate ...
1638
1639
1640
  	br_multicast_send_query(br, NULL, query);
  	spin_unlock(&br->multicast_lock);
  }
88c1f37f0   Allen Pais   net: bridge: Conv...
1641
  static void br_ip4_multicast_query_expired(struct timer_list *t)
eb1d16414   Herbert Xu   bridge: Add core ...
1642
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
1643
  	struct net_bridge *br = from_timer(br, t, ip4_own_query.timer);
eb1d16414   Herbert Xu   bridge: Add core ...
1644

2cd414319   Linus Lüssing   bridge: memorize ...
1645
  	br_multicast_query_expired(br, &br->ip4_own_query, &br->ip4_querier);
cc0fdd802   Linus Lüssing   bridge: separate ...
1646
  }
eb1d16414   Herbert Xu   bridge: Add core ...
1647

cc0fdd802   Linus Lüssing   bridge: separate ...
1648
  #if IS_ENABLED(CONFIG_IPV6)
88c1f37f0   Allen Pais   net: bridge: Conv...
1649
  static void br_ip6_multicast_query_expired(struct timer_list *t)
cc0fdd802   Linus Lüssing   bridge: separate ...
1650
  {
88c1f37f0   Allen Pais   net: bridge: Conv...
1651
  	struct net_bridge *br = from_timer(br, t, ip6_own_query.timer);
eb1d16414   Herbert Xu   bridge: Add core ...
1652

2cd414319   Linus Lüssing   bridge: memorize ...
1653
  	br_multicast_query_expired(br, &br->ip6_own_query, &br->ip6_querier);
eb1d16414   Herbert Xu   bridge: Add core ...
1654
  }
cc0fdd802   Linus Lüssing   bridge: separate ...
1655
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
1656
1657
1658
  
  void br_multicast_init(struct net_bridge *br)
  {
d08c6bc08   Nikolay Aleksandrov   net: bridge: incr...
1659
  	br->hash_max = BR_MULTICAST_DEFAULT_HASH_MAX;
eb1d16414   Herbert Xu   bridge: Add core ...
1660

7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1661
  	br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
eb1d16414   Herbert Xu   bridge: Add core ...
1662
1663
1664
1665
1666
1667
1668
1669
1670
  	br->multicast_last_member_count = 2;
  	br->multicast_startup_query_count = 2;
  
  	br->multicast_last_member_interval = HZ;
  	br->multicast_query_response_interval = 10 * HZ;
  	br->multicast_startup_query_interval = 125 * HZ / 4;
  	br->multicast_query_interval = 125 * HZ;
  	br->multicast_querier_interval = 255 * HZ;
  	br->multicast_membership_interval = 260 * HZ;
90010b36e   Linus Lüssing   bridge: rename st...
1671
  	br->ip4_other_query.delay_time = 0;
2cd414319   Linus Lüssing   bridge: memorize ...
1672
  	br->ip4_querier.port = NULL;
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
1673
  	br->multicast_igmp_version = 2;
cc0fdd802   Linus Lüssing   bridge: separate ...
1674
  #if IS_ENABLED(CONFIG_IPV6)
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
1675
  	br->multicast_mld_version = 1;
90010b36e   Linus Lüssing   bridge: rename st...
1676
  	br->ip6_other_query.delay_time = 0;
2cd414319   Linus Lüssing   bridge: memorize ...
1677
  	br->ip6_querier.port = NULL;
cc0fdd802   Linus Lüssing   bridge: separate ...
1678
  #endif
6919622af   Ido Schimmel   bridge: mcast: De...
1679
  	br_opt_toggle(br, BROPT_MULTICAST_ENABLED, true);
675779adb   Nikolay Aleksandrov   net: bridge: conv...
1680
  	br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true);
b00589af3   Linus Lüssing   bridge: disable s...
1681

eb1d16414   Herbert Xu   bridge: Add core ...
1682
  	spin_lock_init(&br->multicast_lock);
88c1f37f0   Allen Pais   net: bridge: Conv...
1683
1684
1685
1686
1687
1688
  	timer_setup(&br->multicast_router_timer,
  		    br_multicast_local_router_expired, 0);
  	timer_setup(&br->ip4_other_query.timer,
  		    br_ip4_multicast_querier_expired, 0);
  	timer_setup(&br->ip4_own_query.timer,
  		    br_ip4_multicast_query_expired, 0);
cc0fdd802   Linus Lüssing   bridge: separate ...
1689
  #if IS_ENABLED(CONFIG_IPV6)
88c1f37f0   Allen Pais   net: bridge: Conv...
1690
1691
1692
1693
  	timer_setup(&br->ip6_other_query.timer,
  		    br_ip6_multicast_querier_expired, 0);
  	timer_setup(&br->ip6_own_query.timer,
  		    br_ip6_multicast_query_expired, 0);
cc0fdd802   Linus Lüssing   bridge: separate ...
1694
  #endif
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1695
  	INIT_HLIST_HEAD(&br->mdb_list);
eb1d16414   Herbert Xu   bridge: Add core ...
1696
  }
4effd28c1   Linus Lüssing   bridge: join all-...
1697
1698
1699
1700
1701
1702
  static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
  {
  	struct in_device *in_dev = in_dev_get(br->dev);
  
  	if (!in_dev)
  		return;
9fb20801d   Florian Fainelli   net: Fix ip_mc_{d...
1703
  	__ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
4effd28c1   Linus Lüssing   bridge: join all-...
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
  	in_dev_put(in_dev);
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
  static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
  {
  	struct in6_addr addr;
  
  	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
  	ipv6_dev_mc_inc(br->dev, &addr);
  }
  #else
  static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
  {
  }
  #endif
  
  static void br_multicast_join_snoopers(struct net_bridge *br)
  {
  	br_ip4_multicast_join_snoopers(br);
  	br_ip6_multicast_join_snoopers(br);
  }
  
  static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
  {
  	struct in_device *in_dev = in_dev_get(br->dev);
  
  	if (WARN_ON(!in_dev))
  		return;
9fb20801d   Florian Fainelli   net: Fix ip_mc_{d...
1733
  	__ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
4effd28c1   Linus Lüssing   bridge: join all-...
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
  	in_dev_put(in_dev);
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
  static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
  {
  	struct in6_addr addr;
  
  	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
  	ipv6_dev_mc_dec(br->dev, &addr);
  }
  #else
  static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
  {
  }
  #endif
  
  static void br_multicast_leave_snoopers(struct net_bridge *br)
  {
  	br_ip4_multicast_leave_snoopers(br);
  	br_ip6_multicast_leave_snoopers(br);
  }
cc0fdd802   Linus Lüssing   bridge: separate ...
1756
  static void __br_multicast_open(struct net_bridge *br,
90010b36e   Linus Lüssing   bridge: rename st...
1757
  				struct bridge_mcast_own_query *query)
eb1d16414   Herbert Xu   bridge: Add core ...
1758
  {
cc0fdd802   Linus Lüssing   bridge: separate ...
1759
  	query->startup_sent = 0;
eb1d16414   Herbert Xu   bridge: Add core ...
1760

13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
1761
  	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
eb1d16414   Herbert Xu   bridge: Add core ...
1762
  		return;
cc0fdd802   Linus Lüssing   bridge: separate ...
1763
1764
1765
1766
1767
  	mod_timer(&query->timer, jiffies);
  }
  
  void br_multicast_open(struct net_bridge *br)
  {
4effd28c1   Linus Lüssing   bridge: join all-...
1768
1769
  	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
  		br_multicast_join_snoopers(br);
90010b36e   Linus Lüssing   bridge: rename st...
1770
  	__br_multicast_open(br, &br->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1771
  #if IS_ENABLED(CONFIG_IPV6)
90010b36e   Linus Lüssing   bridge: rename st...
1772
  	__br_multicast_open(br, &br->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1773
  #endif
eb1d16414   Herbert Xu   bridge: Add core ...
1774
1775
1776
1777
  }
  
  void br_multicast_stop(struct net_bridge *br)
  {
eb1d16414   Herbert Xu   bridge: Add core ...
1778
  	del_timer_sync(&br->multicast_router_timer);
90010b36e   Linus Lüssing   bridge: rename st...
1779
1780
  	del_timer_sync(&br->ip4_other_query.timer);
  	del_timer_sync(&br->ip4_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
1781
  #if IS_ENABLED(CONFIG_IPV6)
90010b36e   Linus Lüssing   bridge: rename st...
1782
1783
  	del_timer_sync(&br->ip6_other_query.timer);
  	del_timer_sync(&br->ip6_own_query.timer);
cc0fdd802   Linus Lüssing   bridge: separate ...
1784
  #endif
4effd28c1   Linus Lüssing   bridge: join all-...
1785
1786
1787
  
  	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
  		br_multicast_leave_snoopers(br);
e10177abf   Satish Ashok   bridge: multicast...
1788
1789
1790
1791
  }
  
  void br_multicast_dev_del(struct net_bridge *br)
  {
e10177abf   Satish Ashok   bridge: multicast...
1792
  	struct net_bridge_mdb_entry *mp;
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1793
  	struct hlist_node *tmp;
eb1d16414   Herbert Xu   bridge: Add core ...
1794
1795
  
  	spin_lock_bh(&br->multicast_lock);
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1796
1797
1798
1799
1800
  	hlist_for_each_entry_safe(mp, tmp, &br->mdb_list, mdb_node) {
  		del_timer(&mp->timer);
  		rhashtable_remove_fast(&br->mdb_hash_tbl, &mp->rhnode,
  				       br_mdb_rht_params);
  		hlist_del_rcu(&mp->mdb_node);
4329596cb   Nikolay Aleksandrov   net: bridge: mult...
1801
  		kfree_rcu(mp, rcu);
eb1d16414   Herbert Xu   bridge: Add core ...
1802
  	}
eb1d16414   Herbert Xu   bridge: Add core ...
1803
  	spin_unlock_bh(&br->multicast_lock);
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
1804

4329596cb   Nikolay Aleksandrov   net: bridge: mult...
1805
  	rcu_barrier();
eb1d16414   Herbert Xu   bridge: Add core ...
1806
  }
0909e1175   Herbert Xu   bridge: Add multi...
1807
1808
1809
  
  int br_multicast_set_router(struct net_bridge *br, unsigned long val)
  {
6ae4ae8e5   Linus Lüssing   bridge: allow set...
1810
  	int err = -EINVAL;
0909e1175   Herbert Xu   bridge: Add multi...
1811
1812
  
  	spin_lock_bh(&br->multicast_lock);
0909e1175   Herbert Xu   bridge: Add multi...
1813
1814
  
  	switch (val) {
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1815
1816
  	case MDB_RTR_TYPE_DISABLED:
  	case MDB_RTR_TYPE_PERM:
770414207   Yotam Gigi   net: bridge: Noti...
1817
  		br_mc_router_state_change(br, val == MDB_RTR_TYPE_PERM);
0909e1175   Herbert Xu   bridge: Add multi...
1818
  		del_timer(&br->multicast_router_timer);
770414207   Yotam Gigi   net: bridge: Noti...
1819
1820
1821
  		br->multicast_router = val;
  		err = 0;
  		break;
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1822
  	case MDB_RTR_TYPE_TEMP_QUERY:
770414207   Yotam Gigi   net: bridge: Noti...
1823
1824
  		if (br->multicast_router != MDB_RTR_TYPE_TEMP_QUERY)
  			br_mc_router_state_change(br, false);
0909e1175   Herbert Xu   bridge: Add multi...
1825
1826
1827
  		br->multicast_router = val;
  		err = 0;
  		break;
0909e1175   Herbert Xu   bridge: Add multi...
1828
  	}
0909e1175   Herbert Xu   bridge: Add multi...
1829
1830
1831
1832
  	spin_unlock_bh(&br->multicast_lock);
  
  	return err;
  }
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1833
1834
1835
1836
1837
1838
  static void __del_port_router(struct net_bridge_port *p)
  {
  	if (hlist_unhashed(&p->rlist))
  		return;
  	hlist_del_init_rcu(&p->rlist);
  	br_rtr_notify(p->br->dev, p, RTM_DELMDB);
6d5496483   Nogah Frankel   switchdev: bridge...
1839
  	br_port_mc_router_state_change(p, false);
f12e7d95d   Nogah Frankel   bridge: mcast: Me...
1840
1841
1842
1843
  
  	/* don't allow timer refresh */
  	if (p->multicast_router == MDB_RTR_TYPE_TEMP)
  		p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1844
  }
0909e1175   Herbert Xu   bridge: Add multi...
1845
1846
1847
  int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
  {
  	struct net_bridge *br = p->br;
a55d8246a   Nikolay Aleksandrov   bridge: mcast: ad...
1848
  	unsigned long now = jiffies;
6ae4ae8e5   Linus Lüssing   bridge: allow set...
1849
  	int err = -EINVAL;
0909e1175   Herbert Xu   bridge: Add multi...
1850
1851
  
  	spin_lock(&br->multicast_lock);
4950cfd1e   Nikolay Aleksandrov   bridge: mcast: do...
1852
  	if (p->multicast_router == val) {
a55d8246a   Nikolay Aleksandrov   bridge: mcast: ad...
1853
1854
1855
1856
  		/* Refresh the temp router port timer */
  		if (p->multicast_router == MDB_RTR_TYPE_TEMP)
  			mod_timer(&p->multicast_router_timer,
  				  now + br->multicast_querier_interval);
4950cfd1e   Nikolay Aleksandrov   bridge: mcast: do...
1857
1858
1859
  		err = 0;
  		goto unlock;
  	}
0909e1175   Herbert Xu   bridge: Add multi...
1860
  	switch (val) {
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
  	case MDB_RTR_TYPE_DISABLED:
  		p->multicast_router = MDB_RTR_TYPE_DISABLED;
  		__del_port_router(p);
  		del_timer(&p->multicast_router_timer);
  		break;
  	case MDB_RTR_TYPE_TEMP_QUERY:
  		p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
  		__del_port_router(p);
  		break;
  	case MDB_RTR_TYPE_PERM:
  		p->multicast_router = MDB_RTR_TYPE_PERM;
0909e1175   Herbert Xu   bridge: Add multi...
1872
  		del_timer(&p->multicast_router_timer);
0909e1175   Herbert Xu   bridge: Add multi...
1873
1874
  		br_multicast_add_router(br, p);
  		break;
a55d8246a   Nikolay Aleksandrov   bridge: mcast: ad...
1875
1876
1877
1878
  	case MDB_RTR_TYPE_TEMP:
  		p->multicast_router = MDB_RTR_TYPE_TEMP;
  		br_multicast_mark_router(br, p);
  		break;
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1879
1880
  	default:
  		goto unlock;
0909e1175   Herbert Xu   bridge: Add multi...
1881
  	}
7f0aec7a6   Nikolay Aleksandrov   bridge: mcast: us...
1882
1883
  	err = 0;
  unlock:
0909e1175   Herbert Xu   bridge: Add multi...
1884
1885
1886
1887
  	spin_unlock(&br->multicast_lock);
  
  	return err;
  }
561f1103a   Herbert Xu   bridge: Add multi...
1888

cc0fdd802   Linus Lüssing   bridge: separate ...
1889
  static void br_multicast_start_querier(struct net_bridge *br,
90010b36e   Linus Lüssing   bridge: rename st...
1890
  				       struct bridge_mcast_own_query *query)
561f1103a   Herbert Xu   bridge: Add multi...
1891
1892
  {
  	struct net_bridge_port *port;
748572162   Herbert Xu   bridge: Add br_mu...
1893

cc0fdd802   Linus Lüssing   bridge: separate ...
1894
  	__br_multicast_open(br, query);
748572162   Herbert Xu   bridge: Add br_mu...
1895

c5b493ce1   Nikolay Aleksandrov   net: bridge: mult...
1896
1897
  	rcu_read_lock();
  	list_for_each_entry_rcu(port, &br->port_list, list) {
748572162   Herbert Xu   bridge: Add br_mu...
1898
1899
1900
  		if (port->state == BR_STATE_DISABLED ||
  		    port->state == BR_STATE_BLOCKING)
  			continue;
90010b36e   Linus Lüssing   bridge: rename st...
1901
1902
  		if (query == &br->ip4_own_query)
  			br_multicast_enable(&port->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1903
1904
  #if IS_ENABLED(CONFIG_IPV6)
  		else
90010b36e   Linus Lüssing   bridge: rename st...
1905
  			br_multicast_enable(&port->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1906
  #endif
748572162   Herbert Xu   bridge: Add br_mu...
1907
  	}
c5b493ce1   Nikolay Aleksandrov   net: bridge: mult...
1908
  	rcu_read_unlock();
748572162   Herbert Xu   bridge: Add br_mu...
1909
1910
1911
1912
  }
  
  int br_multicast_toggle(struct net_bridge *br, unsigned long val)
  {
7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
1913
  	struct net_bridge_port *port;
561f1103a   Herbert Xu   bridge: Add multi...
1914

ef5e0d823   Andrey Vagin   bridge: Fix poten...
1915
  	spin_lock_bh(&br->multicast_lock);
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
1916
  	if (!!br_opt_get(br, BROPT_MULTICAST_ENABLED) == !!val)
561f1103a   Herbert Xu   bridge: Add multi...
1917
  		goto unlock;
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
1918
1919
  	br_mc_disabled_update(br->dev, val);
  	br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
4effd28c1   Linus Lüssing   bridge: join all-...
1920
1921
  	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
  		br_multicast_leave_snoopers(br);
561f1103a   Herbert Xu   bridge: Add multi...
1922
  		goto unlock;
4effd28c1   Linus Lüssing   bridge: join all-...
1923
  	}
561f1103a   Herbert Xu   bridge: Add multi...
1924

3a7fda06b   Herbert Xu   bridge: Allow mul...
1925
1926
  	if (!netif_running(br->dev))
  		goto unlock;
7cb3f9214   Nikolay Aleksandrov   bridge: multicast...
1927
1928
1929
  	br_multicast_open(br);
  	list_for_each_entry(port, &br->port_list, list)
  		__br_multicast_enable_port(port);
561f1103a   Herbert Xu   bridge: Add multi...
1930
1931
  
  unlock:
ef5e0d823   Andrey Vagin   bridge: Fix poten...
1932
  	spin_unlock_bh(&br->multicast_lock);
561f1103a   Herbert Xu   bridge: Add multi...
1933

a26d94bff   YueHaibing   net: bridge: remo...
1934
  	return 0;
561f1103a   Herbert Xu   bridge: Add multi...
1935
  }
b195167fc   Herbert Xu   bridge: Add hash ...
1936

9341b988e   Ido Schimmel   bridge: Export mu...
1937
1938
1939
  bool br_multicast_enabled(const struct net_device *dev)
  {
  	struct net_bridge *br = netdev_priv(dev);
13cefad2f   Nikolay Aleksandrov   net: bridge: conv...
1940
  	return !!br_opt_get(br, BROPT_MULTICAST_ENABLED);
9341b988e   Ido Schimmel   bridge: Export mu...
1941
1942
  }
  EXPORT_SYMBOL_GPL(br_multicast_enabled);
0912bda43   Yotam Gigi   net: bridge: Expo...
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
  bool br_multicast_router(const struct net_device *dev)
  {
  	struct net_bridge *br = netdev_priv(dev);
  	bool is_router;
  
  	spin_lock_bh(&br->multicast_lock);
  	is_router = br_multicast_is_router(br);
  	spin_unlock_bh(&br->multicast_lock);
  	return is_router;
  }
  EXPORT_SYMBOL_GPL(br_multicast_router);
c5c232605   Herbert Xu   bridge: Add multi...
1954
1955
  int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
  {
b00589af3   Linus Lüssing   bridge: disable s...
1956
  	unsigned long max_delay;
c5c232605   Herbert Xu   bridge: Add multi...
1957
1958
1959
  	val = !!val;
  
  	spin_lock_bh(&br->multicast_lock);
675779adb   Nikolay Aleksandrov   net: bridge: conv...
1960
  	if (br_opt_get(br, BROPT_MULTICAST_QUERIER) == val)
c5c232605   Herbert Xu   bridge: Add multi...
1961
  		goto unlock;
675779adb   Nikolay Aleksandrov   net: bridge: conv...
1962
  	br_opt_toggle(br, BROPT_MULTICAST_QUERIER, !!val);
b00589af3   Linus Lüssing   bridge: disable s...
1963
1964
1965
1966
  	if (!val)
  		goto unlock;
  
  	max_delay = br->multicast_query_response_interval;
b00589af3   Linus Lüssing   bridge: disable s...
1967

90010b36e   Linus Lüssing   bridge: rename st...
1968
1969
  	if (!timer_pending(&br->ip4_other_query.timer))
  		br->ip4_other_query.delay_time = jiffies + max_delay;
cc0fdd802   Linus Lüssing   bridge: separate ...
1970

90010b36e   Linus Lüssing   bridge: rename st...
1971
  	br_multicast_start_querier(br, &br->ip4_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1972
1973
  
  #if IS_ENABLED(CONFIG_IPV6)
90010b36e   Linus Lüssing   bridge: rename st...
1974
1975
  	if (!timer_pending(&br->ip6_other_query.timer))
  		br->ip6_other_query.delay_time = jiffies + max_delay;
cc0fdd802   Linus Lüssing   bridge: separate ...
1976

90010b36e   Linus Lüssing   bridge: rename st...
1977
  	br_multicast_start_querier(br, &br->ip6_own_query);
cc0fdd802   Linus Lüssing   bridge: separate ...
1978
  #endif
c5c232605   Herbert Xu   bridge: Add multi...
1979
1980
1981
1982
1983
1984
  
  unlock:
  	spin_unlock_bh(&br->multicast_lock);
  
  	return 0;
  }
5e9235853   Nikolay Aleksandrov   bridge: mcast: ad...
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
  int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val)
  {
  	/* Currently we support only version 2 and 3 */
  	switch (val) {
  	case 2:
  	case 3:
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	spin_lock_bh(&br->multicast_lock);
  	br->multicast_igmp_version = val;
  	spin_unlock_bh(&br->multicast_lock);
  
  	return 0;
  }
aa2ae3e71   Nikolay Aleksandrov   bridge: mcast: ad...
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
  #if IS_ENABLED(CONFIG_IPV6)
  int br_multicast_set_mld_version(struct net_bridge *br, unsigned long val)
  {
  	/* Currently we support version 1 and 2 */
  	switch (val) {
  	case 1:
  	case 2:
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	spin_lock_bh(&br->multicast_lock);
  	br->multicast_mld_version = val;
  	spin_unlock_bh(&br->multicast_lock);
  
  	return 0;
  }
  #endif
07f8ac4a1   Linus Lüssing   bridge: add expor...
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
  /**
   * br_multicast_list_adjacent - Returns snooped multicast addresses
   * @dev:	The bridge port adjacent to which to retrieve addresses
   * @br_ip_list:	The list to store found, snooped multicast IP addresses in
   *
   * Creates a list of IP addresses (struct br_ip_list) sensed by the multicast
   * snooping feature on all bridge ports of dev's bridge device, excluding
   * the addresses from dev itself.
   *
   * Returns the number of items added to br_ip_list.
   *
   * Notes:
   * - br_ip_list needs to be initialized by caller
   * - br_ip_list might contain duplicates in the end
   *   (needs to be taken care of by caller)
   * - br_ip_list needs to be freed by caller
   */
  int br_multicast_list_adjacent(struct net_device *dev,
  			       struct list_head *br_ip_list)
  {
  	struct net_bridge *br;
  	struct net_bridge_port *port;
  	struct net_bridge_port_group *group;
  	struct br_ip_list *entry;
  	int count = 0;
  
  	rcu_read_lock();
35f861e3c   Julian Wiedmann   net: bridge: use ...
2048
  	if (!br_ip_list || !netif_is_bridge_port(dev))
07f8ac4a1   Linus Lüssing   bridge: add expor...
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
  		goto unlock;
  
  	port = br_port_get_rcu(dev);
  	if (!port || !port->br)
  		goto unlock;
  
  	br = port->br;
  
  	list_for_each_entry_rcu(port, &br->port_list, list) {
  		if (!port->dev || port->dev == dev)
  			continue;
  
  		hlist_for_each_entry_rcu(group, &port->mglist, mglist) {
  			entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
  			if (!entry)
  				goto unlock;
  
  			entry->addr = group->addr;
  			list_add(&entry->list, br_ip_list);
  			count++;
  		}
  	}
  
  unlock:
  	rcu_read_unlock();
  	return count;
  }
  EXPORT_SYMBOL_GPL(br_multicast_list_adjacent);
2cd414319   Linus Lüssing   bridge: memorize ...
2077
2078
  
  /**
c34963e21   Linus Lüssing   bridge: export kn...
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
   * br_multicast_has_querier_anywhere - Checks for a querier on a bridge
   * @dev: The bridge port providing the bridge on which to check for a querier
   * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
   *
   * Checks whether the given interface has a bridge on top and if so returns
   * true if a valid querier exists anywhere on the bridged link layer.
   * Otherwise returns false.
   */
  bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto)
  {
  	struct net_bridge *br;
  	struct net_bridge_port *port;
  	struct ethhdr eth;
  	bool ret = false;
  
  	rcu_read_lock();
35f861e3c   Julian Wiedmann   net: bridge: use ...
2095
  	if (!netif_is_bridge_port(dev))
c34963e21   Linus Lüssing   bridge: export kn...
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
  		goto unlock;
  
  	port = br_port_get_rcu(dev);
  	if (!port || !port->br)
  		goto unlock;
  
  	br = port->br;
  
  	memset(&eth, 0, sizeof(eth));
  	eth.h_proto = htons(proto);
  
  	ret = br_multicast_querier_exists(br, &eth);
  
  unlock:
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere);
  
  /**
2cd414319   Linus Lüssing   bridge: memorize ...
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
   * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port
   * @dev: The bridge port adjacent to which to check for a querier
   * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
   *
   * Checks whether the given interface has a bridge on top and if so returns
   * true if a selected querier is behind one of the other ports of this
   * bridge. Otherwise returns false.
   */
  bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
  {
  	struct net_bridge *br;
  	struct net_bridge_port *port;
  	bool ret = false;
  
  	rcu_read_lock();
35f861e3c   Julian Wiedmann   net: bridge: use ...
2131
  	if (!netif_is_bridge_port(dev))
2cd414319   Linus Lüssing   bridge: memorize ...
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
  		goto unlock;
  
  	port = br_port_get_rcu(dev);
  	if (!port || !port->br)
  		goto unlock;
  
  	br = port->br;
  
  	switch (proto) {
  	case ETH_P_IP:
  		if (!timer_pending(&br->ip4_other_query.timer) ||
  		    rcu_dereference(br->ip4_querier.port) == port)
  			goto unlock;
  		break;
3993c4e15   Linus Lüssing   bridge: fix compi...
2146
  #if IS_ENABLED(CONFIG_IPV6)
2cd414319   Linus Lüssing   bridge: memorize ...
2147
2148
2149
2150
2151
  	case ETH_P_IPV6:
  		if (!timer_pending(&br->ip6_other_query.timer) ||
  		    rcu_dereference(br->ip6_querier.port) == port)
  			goto unlock;
  		break;
3993c4e15   Linus Lüssing   bridge: fix compi...
2152
  #endif
2cd414319   Linus Lüssing   bridge: memorize ...
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
  	default:
  		goto unlock;
  	}
  
  	ret = true;
  unlock:
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2163
2164
  
  static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2165
  			       const struct sk_buff *skb, u8 type, u8 dir)
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2166
2167
  {
  	struct bridge_mcast_stats *pstats = this_cpu_ptr(stats);
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2168
2169
  	__be16 proto = skb->protocol;
  	unsigned int t_len;
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2170
2171
2172
2173
  
  	u64_stats_update_begin(&pstats->syncp);
  	switch (proto) {
  	case htons(ETH_P_IP):
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2174
  		t_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
  		switch (type) {
  		case IGMP_HOST_MEMBERSHIP_REPORT:
  			pstats->mstats.igmp_v1reports[dir]++;
  			break;
  		case IGMPV2_HOST_MEMBERSHIP_REPORT:
  			pstats->mstats.igmp_v2reports[dir]++;
  			break;
  		case IGMPV3_HOST_MEMBERSHIP_REPORT:
  			pstats->mstats.igmp_v3reports[dir]++;
  			break;
  		case IGMP_HOST_MEMBERSHIP_QUERY:
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
  			if (t_len != sizeof(struct igmphdr)) {
  				pstats->mstats.igmp_v3queries[dir]++;
  			} else {
  				unsigned int offset = skb_transport_offset(skb);
  				struct igmphdr *ih, _ihdr;
  
  				ih = skb_header_pointer(skb, offset,
  							sizeof(_ihdr), &_ihdr);
  				if (!ih)
  					break;
  				if (!ih->code)
  					pstats->mstats.igmp_v1queries[dir]++;
  				else
  					pstats->mstats.igmp_v2queries[dir]++;
  			}
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2201
2202
2203
2204
2205
2206
2207
2208
  			break;
  		case IGMP_HOST_LEAVE_MESSAGE:
  			pstats->mstats.igmp_leaves[dir]++;
  			break;
  		}
  		break;
  #if IS_ENABLED(CONFIG_IPV6)
  	case htons(ETH_P_IPV6):
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2209
2210
2211
  		t_len = ntohs(ipv6_hdr(skb)->payload_len) +
  			sizeof(struct ipv6hdr);
  		t_len -= skb_network_header_len(skb);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2212
2213
2214
2215
2216
2217
2218
2219
  		switch (type) {
  		case ICMPV6_MGM_REPORT:
  			pstats->mstats.mld_v1reports[dir]++;
  			break;
  		case ICMPV6_MLD2_REPORT:
  			pstats->mstats.mld_v2reports[dir]++;
  			break;
  		case ICMPV6_MGM_QUERY:
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2220
2221
2222
2223
  			if (t_len != sizeof(struct mld_msg))
  				pstats->mstats.mld_v2queries[dir]++;
  			else
  				pstats->mstats.mld_v1queries[dir]++;
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
  			break;
  		case ICMPV6_MGM_REDUCTION:
  			pstats->mstats.mld_leaves[dir]++;
  			break;
  		}
  		break;
  #endif /* CONFIG_IPV6 */
  	}
  	u64_stats_update_end(&pstats->syncp);
  }
  
  void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p,
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2236
  			const struct sk_buff *skb, u8 type, u8 dir)
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2237
2238
2239
2240
  {
  	struct bridge_mcast_stats __percpu *stats;
  
  	/* if multicast_disabled is true then igmp type can't be set */
675779adb   Nikolay Aleksandrov   net: bridge: conv...
2241
  	if (!type || !br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED))
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2242
2243
2244
2245
2246
2247
2248
2249
  		return;
  
  	if (p)
  		stats = p->mcast_stats;
  	else
  		stats = br->mcast_stats;
  	if (WARN_ON(!stats))
  		return;
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2250
  	br_mcast_stats_add(stats, skb, type, dir);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
  }
  
  int br_multicast_init_stats(struct net_bridge *br)
  {
  	br->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
  	if (!br->mcast_stats)
  		return -ENOMEM;
  
  	return 0;
  }
b6fe0440c   Ido Schimmel   bridge: implement...
2261
2262
2263
2264
  void br_multicast_uninit_stats(struct net_bridge *br)
  {
  	free_percpu(br->mcast_stats);
  }
b3b6a84c6   Arnd Bergmann   bridge: multicast...
2265
2266
  /* noinline for https://bugs.llvm.org/show_bug.cgi?id=45802#c9 */
  static noinline_for_stack void mcast_stats_add_dir(u64 *dst, u64 *src)
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
  {
  	dst[BR_MCAST_DIR_RX] += src[BR_MCAST_DIR_RX];
  	dst[BR_MCAST_DIR_TX] += src[BR_MCAST_DIR_TX];
  }
  
  void br_multicast_get_stats(const struct net_bridge *br,
  			    const struct net_bridge_port *p,
  			    struct br_mcast_stats *dest)
  {
  	struct bridge_mcast_stats __percpu *stats;
  	struct br_mcast_stats tdst;
  	int i;
  
  	memset(dest, 0, sizeof(*dest));
  	if (p)
  		stats = p->mcast_stats;
  	else
  		stats = br->mcast_stats;
  	if (WARN_ON(!stats))
  		return;
  
  	memset(&tdst, 0, sizeof(tdst));
  	for_each_possible_cpu(i) {
  		struct bridge_mcast_stats *cpu_stats = per_cpu_ptr(stats, i);
  		struct br_mcast_stats temp;
  		unsigned int start;
  
  		do {
  			start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
  			memcpy(&temp, &cpu_stats->mstats, sizeof(temp));
  		} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2298
2299
2300
  		mcast_stats_add_dir(tdst.igmp_v1queries, temp.igmp_v1queries);
  		mcast_stats_add_dir(tdst.igmp_v2queries, temp.igmp_v2queries);
  		mcast_stats_add_dir(tdst.igmp_v3queries, temp.igmp_v3queries);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2301
2302
2303
2304
2305
  		mcast_stats_add_dir(tdst.igmp_leaves, temp.igmp_leaves);
  		mcast_stats_add_dir(tdst.igmp_v1reports, temp.igmp_v1reports);
  		mcast_stats_add_dir(tdst.igmp_v2reports, temp.igmp_v2reports);
  		mcast_stats_add_dir(tdst.igmp_v3reports, temp.igmp_v3reports);
  		tdst.igmp_parse_errors += temp.igmp_parse_errors;
a65056ecf   Nikolay Aleksandrov   net: bridge: exte...
2306
2307
  		mcast_stats_add_dir(tdst.mld_v1queries, temp.mld_v1queries);
  		mcast_stats_add_dir(tdst.mld_v2queries, temp.mld_v2queries);
1080ab95e   Nikolay Aleksandrov   net: bridge: add ...
2308
2309
2310
2311
2312
2313
2314
  		mcast_stats_add_dir(tdst.mld_leaves, temp.mld_leaves);
  		mcast_stats_add_dir(tdst.mld_v1reports, temp.mld_v1reports);
  		mcast_stats_add_dir(tdst.mld_v2reports, temp.mld_v2reports);
  		tdst.mld_parse_errors += temp.mld_parse_errors;
  	}
  	memcpy(dest, &tdst, sizeof(*dest));
  }
19e3a9c90   Nikolay Aleksandrov   net: bridge: conv...
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
  
  int br_mdb_hash_init(struct net_bridge *br)
  {
  	return rhashtable_init(&br->mdb_hash_tbl, &br_mdb_rht_params);
  }
  
  void br_mdb_hash_fini(struct net_bridge *br)
  {
  	rhashtable_destroy(&br->mdb_hash_tbl);
  }