aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/multicast.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/multicast.c')
-rw-r--r--net/batman-adv/multicast.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 3ba9a18a906c..1d1627fe0de0 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -20,6 +20,7 @@
20#include "originator.h" 20#include "originator.h"
21#include "hard-interface.h" 21#include "hard-interface.h"
22#include "translation-table.h" 22#include "translation-table.h"
23#include "multicast.h"
23 24
24/** 25/**
25 * batadv_mcast_mla_softif_get - get softif multicast listeners 26 * batadv_mcast_mla_softif_get - get softif multicast listeners
@@ -247,6 +248,131 @@ out:
247} 248}
248 249
249/** 250/**
251 * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
252 * @bat_priv: the bat priv with all the soft interface information
253 * @skb: the IPv6 packet to check
254 *
255 * Checks whether the given IPv6 packet has the potential to be forwarded with a
256 * mode more optimal than classic flooding.
257 *
258 * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
259 * of memory.
260 */
261static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
262 struct sk_buff *skb)
263{
264 struct ipv6hdr *ip6hdr;
265
266 /* We might fail due to out-of-memory -> drop it */
267 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
268 return -ENOMEM;
269
270 ip6hdr = ipv6_hdr(skb);
271
272 /* TODO: Implement Multicast Router Discovery (RFC4286),
273 * then allow scope > link local, too
274 */
275 if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL)
276 return -EINVAL;
277
278 /* link-local-all-nodes multicast listeners behind a bridge are
279 * not snoopable (see RFC4541, section 3, paragraph 3)
280 */
281 if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
282 return -EINVAL;
283
284 return 0;
285}
286
287/**
288 * batadv_mcast_forw_mode_check - check for optimized forwarding potential
289 * @bat_priv: the bat priv with all the soft interface information
290 * @skb: the multicast frame to check
291 *
292 * Checks whether the given multicast ethernet frame has the potential to be
293 * forwarded with a mode more optimal than classic flooding.
294 *
295 * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
296 * of memory.
297 */
298static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
299 struct sk_buff *skb)
300{
301 struct ethhdr *ethhdr = eth_hdr(skb);
302
303 if (!atomic_read(&bat_priv->multicast_mode))
304 return -EINVAL;
305
306 if (atomic_read(&bat_priv->mcast.num_disabled))
307 return -EINVAL;
308
309 switch (ntohs(ethhdr->h_proto)) {
310 case ETH_P_IPV6:
311 return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb);
312 default:
313 return -EINVAL;
314 }
315}
316
317/**
318 * batadv_mcast_forw_tt_node_get - get a multicast tt node
319 * @bat_priv: the bat priv with all the soft interface information
320 * @ethhdr: the ether header containing the multicast destination
321 *
322 * Returns an orig_node matching the multicast address provided by ethhdr
323 * via a translation table lookup. This increases the returned nodes refcount.
324 */
325static struct batadv_orig_node *
326batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
327 struct ethhdr *ethhdr)
328{
329 return batadv_transtable_search(bat_priv, ethhdr->h_source,
330 ethhdr->h_dest, BATADV_NO_FLAGS);
331}
332
333/**
334 * batadv_mcast_forw_mode - check on how to forward a multicast packet
335 * @bat_priv: the bat priv with all the soft interface information
336 * @skb: The multicast packet to check
337 * @orig: an originator to be set to forward the skb to
338 *
339 * Returns the forwarding mode as enum batadv_forw_mode and in case of
340 * BATADV_FORW_SINGLE set the orig to the single originator the skb
341 * should be forwarded to.
342 */
343enum batadv_forw_mode
344batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
345 struct batadv_orig_node **orig)
346{
347 struct ethhdr *ethhdr;
348 int ret, tt_count;
349
350 ret = batadv_mcast_forw_mode_check(bat_priv, skb);
351 if (ret == -ENOMEM)
352 return BATADV_FORW_NONE;
353 else if (ret < 0)
354 return BATADV_FORW_ALL;
355
356 ethhdr = eth_hdr(skb);
357
358 tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
359 BATADV_NO_FLAGS);
360
361 switch (tt_count) {
362 case 1:
363 *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr);
364 if (*orig)
365 return BATADV_FORW_SINGLE;
366
367 /* fall through */
368 case 0:
369 return BATADV_FORW_NONE;
370 default:
371 return BATADV_FORW_ALL;
372 }
373}
374
375/**
250 * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container 376 * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
251 * @bat_priv: the bat priv with all the soft interface information 377 * @bat_priv: the bat priv with all the soft interface information
252 * @orig: the orig_node of the ogm 378 * @orig: the orig_node of the ogm