diff options
Diffstat (limited to 'net/batman-adv/multicast.c')
-rw-r--r-- | net/batman-adv/multicast.c | 126 |
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 | */ | ||
261 | static 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 | */ | ||
298 | static 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 | */ | ||
325 | static struct batadv_orig_node * | ||
326 | batadv_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 | */ | ||
343 | enum batadv_forw_mode | ||
344 | batadv_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 |