26
26
#include <linux/etherdevice.h>
27
27
#include <linux/fs.h>
28
28
#include <linux/icmpv6.h>
29
+ #include <linux/if_bridge.h>
29
30
#include <linux/if_ether.h>
30
31
#include <linux/igmp.h>
31
32
#include <linux/in.h>
36
37
#include <linux/list.h>
37
38
#include <linux/lockdep.h>
38
39
#include <linux/netdevice.h>
40
+ #include <linux/printk.h>
39
41
#include <linux/rculist.h>
40
42
#include <linux/rcupdate.h>
41
43
#include <linux/skbuff.h>
45
47
#include <linux/string.h>
46
48
#include <linux/types.h>
47
49
#include <net/addrconf.h>
50
+ #include <net/if_inet6.h>
51
+ #include <net/ip.h>
48
52
#include <net/ipv6.h>
49
53
50
54
#include "packet.h"
51
55
#include "translation-table.h"
52
56
57
+ /**
58
+ * batadv_mcast_get_bridge - get the bridge on top of the softif if it exists
59
+ * @soft_iface: netdev struct of the mesh interface
60
+ *
61
+ * If the given soft interface has a bridge on top then the refcount
62
+ * of the according net device is increased.
63
+ *
64
+ * Return: NULL if no such bridge exists. Otherwise the net device of the
65
+ * bridge.
66
+ */
67
+ static struct net_device * batadv_mcast_get_bridge (struct net_device * soft_iface )
68
+ {
69
+ struct net_device * upper = soft_iface ;
70
+
71
+ rcu_read_lock ();
72
+ do {
73
+ upper = netdev_master_upper_dev_get_rcu (upper );
74
+ } while (upper && !(upper -> priv_flags & IFF_EBRIDGE ));
75
+
76
+ if (upper )
77
+ dev_hold (upper );
78
+ rcu_read_unlock ();
79
+
80
+ return upper ;
81
+ }
82
+
53
83
/**
54
84
* batadv_mcast_mla_softif_get - get softif multicast listeners
55
85
* @dev: the device to collect multicast addresses from
56
86
* @mcast_list: a list to put found addresses into
57
87
*
58
- * Collect multicast addresses of the local multicast listeners
59
- * on the given soft interface, dev, in the given mcast_list.
88
+ * Collects multicast addresses of multicast listeners residing
89
+ * on this kernel on the given soft interface, dev, in
90
+ * the given mcast_list. In general, multicast listeners provided by
91
+ * your multicast receiving applications run directly on this node.
92
+ *
93
+ * If there is a bridge interface on top of dev, collects from that one
94
+ * instead. Just like with IP addresses and routes, multicast listeners
95
+ * will(/should) register to the bridge interface instead of an
96
+ * enslaved bat0.
60
97
*
61
98
* Return: -ENOMEM on memory allocation error or the number of
62
99
* items added to the mcast_list otherwise.
63
100
*/
64
101
static int batadv_mcast_mla_softif_get (struct net_device * dev ,
65
102
struct hlist_head * mcast_list )
66
103
{
104
+ struct net_device * bridge = batadv_mcast_get_bridge (dev );
67
105
struct netdev_hw_addr * mc_list_entry ;
68
106
struct batadv_hw_addr * new ;
69
107
int ret = 0 ;
70
108
71
- netif_addr_lock_bh (dev );
72
- netdev_for_each_mc_addr (mc_list_entry , dev ) {
109
+ netif_addr_lock_bh (bridge ? bridge : dev );
110
+ netdev_for_each_mc_addr (mc_list_entry , bridge ? bridge : dev ) {
73
111
new = kmalloc (sizeof (* new ), GFP_ATOMIC );
74
112
if (!new ) {
75
113
ret = - ENOMEM ;
@@ -80,7 +118,10 @@ static int batadv_mcast_mla_softif_get(struct net_device *dev,
80
118
hlist_add_head (& new -> list , mcast_list );
81
119
ret ++ ;
82
120
}
83
- netif_addr_unlock_bh (dev );
121
+ netif_addr_unlock_bh (bridge ? bridge : dev );
122
+
123
+ if (bridge )
124
+ dev_put (bridge );
84
125
85
126
return ret ;
86
127
}
@@ -105,6 +146,83 @@ static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
105
146
return false;
106
147
}
107
148
149
+ /**
150
+ * batadv_mcast_mla_br_addr_cpy - copy a bridge multicast address
151
+ * @dst: destination to write to - a multicast MAC address
152
+ * @src: source to read from - a multicast IP address
153
+ *
154
+ * Converts a given multicast IPv4/IPv6 address from a bridge
155
+ * to its matching multicast MAC address and copies it into the given
156
+ * destination buffer.
157
+ *
158
+ * Caller needs to make sure the destination buffer can hold
159
+ * at least ETH_ALEN bytes.
160
+ */
161
+ static void batadv_mcast_mla_br_addr_cpy (char * dst , const struct br_ip * src )
162
+ {
163
+ if (src -> proto == htons (ETH_P_IP ))
164
+ ip_eth_mc_map (src -> u .ip4 , dst );
165
+ #if IS_ENABLED (CONFIG_IPV6 )
166
+ else if (src -> proto == htons (ETH_P_IPV6 ))
167
+ ipv6_eth_mc_map (& src - > u .ip6 , dst );
168
+ #endif
169
+ else
170
+ eth_zero_addr (dst );
171
+ }
172
+
173
+ /**
174
+ * batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
175
+ * @dev: a bridge slave whose bridge to collect multicast addresses from
176
+ * @mcast_list: a list to put found addresses into
177
+ *
178
+ * Collects multicast addresses of multicast listeners residing
179
+ * on foreign, non-mesh devices which we gave access to our mesh via
180
+ * a bridge on top of the given soft interface, dev, in the given
181
+ * mcast_list.
182
+ *
183
+ * Return: -ENOMEM on memory allocation error or the number of
184
+ * items added to the mcast_list otherwise.
185
+ */
186
+ static int batadv_mcast_mla_bridge_get (struct net_device * dev ,
187
+ struct hlist_head * mcast_list )
188
+ {
189
+ struct list_head bridge_mcast_list = LIST_HEAD_INIT (bridge_mcast_list );
190
+ struct br_ip_list * br_ip_entry , * tmp ;
191
+ struct batadv_hw_addr * new ;
192
+ u8 mcast_addr [ETH_ALEN ];
193
+ int ret ;
194
+
195
+ /* we don't need to detect these devices/listeners, the IGMP/MLD
196
+ * snooping code of the Linux bridge already does that for us
197
+ */
198
+ ret = br_multicast_list_adjacent (dev , & bridge_mcast_list );
199
+ if (ret < 0 )
200
+ goto out ;
201
+
202
+ list_for_each_entry (br_ip_entry , & bridge_mcast_list , list ) {
203
+ batadv_mcast_mla_br_addr_cpy (mcast_addr , & br_ip_entry -> addr );
204
+ if (batadv_mcast_mla_is_duplicate (mcast_addr , mcast_list ))
205
+ continue ;
206
+
207
+ new = kmalloc (sizeof (* new ), GFP_ATOMIC );
208
+ if (!new ) {
209
+ ret = - ENOMEM ;
210
+ break ;
211
+ }
212
+
213
+ ether_addr_copy (new -> addr , mcast_addr );
214
+ hlist_add_head (& new -> list , mcast_list );
215
+ }
216
+
217
+ out :
218
+ list_for_each_entry_safe (br_ip_entry , tmp , & bridge_mcast_list , list ) {
219
+ list_del (& br_ip_entry -> list );
220
+ kfree (br_ip_entry );
221
+ }
222
+
223
+ return ret ;
224
+ }
225
+
108
226
/**
109
227
* batadv_mcast_mla_list_free - free a list of multicast addresses
110
228
* @bat_priv: the bat priv with all the soft interface information
@@ -222,29 +340,51 @@ static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
222
340
* Updates the own multicast tvlv with our current multicast related settings,
223
341
* capabilities and inabilities.
224
342
*
225
- * Return: true if the tvlv container is registered afterwards. Otherwise
226
- * returns false .
343
+ * Return: false if we want all IPv4 && IPv6 multicast traffic and true
344
+ * otherwise .
227
345
*/
228
346
static bool batadv_mcast_mla_tvlv_update (struct batadv_priv * bat_priv )
229
347
{
230
348
struct batadv_tvlv_mcast_data mcast_data ;
349
+ struct batadv_mcast_querier_state querier4 = {false, false};
350
+ struct batadv_mcast_querier_state querier6 = {false, false};
351
+ struct net_device * dev = bat_priv -> soft_iface ;
231
352
232
353
mcast_data .flags = BATADV_NO_FLAGS ;
233
354
memset (mcast_data .reserved , 0 , sizeof (mcast_data .reserved ));
234
355
235
- /* Avoid attaching MLAs, if there is a bridge on top of our soft
236
- * interface, we don't support that yet (TODO)
356
+ bat_priv -> mcast .bridged = batadv_mcast_has_bridge (bat_priv );
357
+ if (!bat_priv -> mcast .bridged )
358
+ goto update ;
359
+
360
+ #if !IS_ENABLED (CONFIG_BRIDGE_IGMP_SNOOPING )
361
+ pr_warn_once ("No bridge IGMP snooping compiled - multicast optimizations disabled\n" );
362
+ #endif
363
+
364
+ querier4 .exists = br_multicast_has_querier_anywhere (dev , ETH_P_IP );
365
+ querier4 .shadowing = br_multicast_has_querier_adjacent (dev , ETH_P_IP );
366
+
367
+ querier6 .exists = br_multicast_has_querier_anywhere (dev , ETH_P_IPV6 );
368
+ querier6 .shadowing = br_multicast_has_querier_adjacent (dev , ETH_P_IPV6 );
369
+
370
+ mcast_data .flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES ;
371
+
372
+ /* 1) If no querier exists at all, then multicast listeners on
373
+ * our local TT clients behind the bridge will keep silent.
374
+ * 2) If the selected querier is on one of our local TT clients,
375
+ * behind the bridge, then this querier might shadow multicast
376
+ * listeners on our local TT clients, behind this bridge.
377
+ *
378
+ * In both cases, we will signalize other batman nodes that
379
+ * we need all multicast traffic of the according protocol.
237
380
*/
238
- if (batadv_mcast_has_bridge (bat_priv )) {
239
- if (bat_priv -> mcast .enabled ) {
240
- batadv_tvlv_container_unregister (bat_priv ,
241
- BATADV_TVLV_MCAST , 2 );
242
- bat_priv -> mcast .enabled = false;
243
- }
381
+ if (!querier4 .exists || querier4 .shadowing )
382
+ mcast_data .flags |= BATADV_MCAST_WANT_ALL_IPV4 ;
244
383
245
- return false;
246
- }
384
+ if (! querier6 . exists || querier6 . shadowing )
385
+ mcast_data . flags |= BATADV_MCAST_WANT_ALL_IPV6 ;
247
386
387
+ update :
248
388
if (!bat_priv -> mcast .enabled ||
249
389
mcast_data .flags != bat_priv -> mcast .flags ) {
250
390
batadv_tvlv_container_register (bat_priv , BATADV_TVLV_MCAST , 2 ,
@@ -253,7 +393,8 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
253
393
bat_priv -> mcast .enabled = true;
254
394
}
255
395
256
- return true;
396
+ return !(mcast_data .flags &
397
+ (BATADV_MCAST_WANT_ALL_IPV4 + BATADV_MCAST_WANT_ALL_IPV6 ));
257
398
}
258
399
259
400
/**
@@ -276,6 +417,10 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
276
417
if (ret < 0 )
277
418
goto out ;
278
419
420
+ ret = batadv_mcast_mla_bridge_get (soft_iface , & mcast_list );
421
+ if (ret < 0 )
422
+ goto out ;
423
+
279
424
update :
280
425
batadv_mcast_mla_tt_retract (bat_priv , & mcast_list );
281
426
batadv_mcast_mla_tt_add (bat_priv , & mcast_list );
0 commit comments