aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/Kconfig2
-rw-r--r--net/batman-adv/multicast.c87
2 files changed, 75 insertions, 14 deletions
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index f66930ee3c0b..b7ba97dbf4a9 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -66,7 +66,7 @@ config BATMAN_ADV_NC
66 66
67config BATMAN_ADV_MCAST 67config BATMAN_ADV_MCAST
68 bool "Multicast optimisation" 68 bool "Multicast optimisation"
69 depends on BATMAN_ADV 69 depends on BATMAN_ADV && INET
70 default n 70 default n
71 help 71 help
72 This option enables the multicast optimisation which aims to 72 This option enables the multicast optimisation which aims to
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index c32f24fafe67..4673328def29 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -25,9 +25,11 @@
25#include <linux/errno.h> 25#include <linux/errno.h>
26#include <linux/etherdevice.h> 26#include <linux/etherdevice.h>
27#include <linux/fs.h> 27#include <linux/fs.h>
28#include <linux/icmpv6.h>
28#include <linux/if_ether.h> 29#include <linux/if_ether.h>
29#include <linux/in6.h> 30#include <linux/igmp.h>
30#include <linux/in.h> 31#include <linux/in.h>
32#include <linux/in6.h>
31#include <linux/ip.h> 33#include <linux/ip.h>
32#include <linux/ipv6.h> 34#include <linux/ipv6.h>
33#include <linux/kref.h> 35#include <linux/kref.h>
@@ -236,7 +238,7 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
236 if (batadv_mcast_has_bridge(bat_priv)) { 238 if (batadv_mcast_has_bridge(bat_priv)) {
237 if (bat_priv->mcast.enabled) { 239 if (bat_priv->mcast.enabled) {
238 batadv_tvlv_container_unregister(bat_priv, 240 batadv_tvlv_container_unregister(bat_priv,
239 BATADV_TVLV_MCAST, 1); 241 BATADV_TVLV_MCAST, 2);
240 bat_priv->mcast.enabled = false; 242 bat_priv->mcast.enabled = false;
241 } 243 }
242 244
@@ -245,7 +247,7 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
245 247
246 if (!bat_priv->mcast.enabled || 248 if (!bat_priv->mcast.enabled ||
247 mcast_data.flags != bat_priv->mcast.flags) { 249 mcast_data.flags != bat_priv->mcast.flags) {
248 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1, 250 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
249 &mcast_data, sizeof(mcast_data)); 251 &mcast_data, sizeof(mcast_data));
250 bat_priv->mcast.flags = mcast_data.flags; 252 bat_priv->mcast.flags = mcast_data.flags;
251 bat_priv->mcast.enabled = true; 253 bat_priv->mcast.enabled = true;
@@ -283,6 +285,31 @@ out:
283} 285}
284 286
285/** 287/**
288 * batadv_mcast_is_report_ipv4 - check for IGMP reports
289 * @skb: the ethernet frame destined for the mesh
290 *
291 * This call might reallocate skb data.
292 *
293 * Checks whether the given frame is a valid IGMP report.
294 *
295 * Return: If so then true, otherwise false.
296 */
297static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
298{
299 if (ip_mc_check_igmp(skb, NULL) < 0)
300 return false;
301
302 switch (igmp_hdr(skb)->type) {
303 case IGMP_HOST_MEMBERSHIP_REPORT:
304 case IGMPV2_HOST_MEMBERSHIP_REPORT:
305 case IGMPV3_HOST_MEMBERSHIP_REPORT:
306 return true;
307 }
308
309 return false;
310}
311
312/**
286 * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential 313 * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential
287 * @bat_priv: the bat priv with all the soft interface information 314 * @bat_priv: the bat priv with all the soft interface information
288 * @skb: the IPv4 packet to check 315 * @skb: the IPv4 packet to check
@@ -304,6 +331,9 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
304 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr))) 331 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
305 return -ENOMEM; 332 return -ENOMEM;
306 333
334 if (batadv_mcast_is_report_ipv4(skb))
335 return -EINVAL;
336
307 iphdr = ip_hdr(skb); 337 iphdr = ip_hdr(skb);
308 338
309 /* TODO: Implement Multicast Router Discovery (RFC4286), 339 /* TODO: Implement Multicast Router Discovery (RFC4286),
@@ -320,6 +350,31 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
320 return 0; 350 return 0;
321} 351}
322 352
353#if IS_ENABLED(CONFIG_IPV6)
354/**
355 * batadv_mcast_is_report_ipv6 - check for MLD reports
356 * @skb: the ethernet frame destined for the mesh
357 *
358 * This call might reallocate skb data.
359 *
360 * Checks whether the given frame is a valid MLD report.
361 *
362 * Return: If so then true, otherwise false.
363 */
364static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
365{
366 if (ipv6_mc_check_mld(skb, NULL) < 0)
367 return false;
368
369 switch (icmp6_hdr(skb)->icmp6_type) {
370 case ICMPV6_MGM_REPORT:
371 case ICMPV6_MLD2_REPORT:
372 return true;
373 }
374
375 return false;
376}
377
323/** 378/**
324 * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential 379 * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
325 * @bat_priv: the bat priv with all the soft interface information 380 * @bat_priv: the bat priv with all the soft interface information
@@ -341,6 +396,9 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
341 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr))) 396 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
342 return -ENOMEM; 397 return -ENOMEM;
343 398
399 if (batadv_mcast_is_report_ipv6(skb))
400 return -EINVAL;
401
344 ip6hdr = ipv6_hdr(skb); 402 ip6hdr = ipv6_hdr(skb);
345 403
346 /* TODO: Implement Multicast Router Discovery (RFC4286), 404 /* TODO: Implement Multicast Router Discovery (RFC4286),
@@ -357,6 +415,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
357 415
358 return 0; 416 return 0;
359} 417}
418#endif
360 419
361/** 420/**
362 * batadv_mcast_forw_mode_check - check for optimized forwarding potential 421 * batadv_mcast_forw_mode_check - check for optimized forwarding potential
@@ -385,9 +444,11 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
385 case ETH_P_IP: 444 case ETH_P_IP:
386 return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb, 445 return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
387 is_unsnoopable); 446 is_unsnoopable);
447#if IS_ENABLED(CONFIG_IPV6)
388 case ETH_P_IPV6: 448 case ETH_P_IPV6:
389 return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb, 449 return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
390 is_unsnoopable); 450 is_unsnoopable);
451#endif
391 default: 452 default:
392 return -EINVAL; 453 return -EINVAL;
393 } 454 }
@@ -728,18 +789,18 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
728} 789}
729 790
730/** 791/**
731 * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container 792 * batadv_mcast_tvlv_ogm_handler - process incoming multicast tvlv container
732 * @bat_priv: the bat priv with all the soft interface information 793 * @bat_priv: the bat priv with all the soft interface information
733 * @orig: the orig_node of the ogm 794 * @orig: the orig_node of the ogm
734 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 795 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
735 * @tvlv_value: tvlv buffer containing the multicast data 796 * @tvlv_value: tvlv buffer containing the multicast data
736 * @tvlv_value_len: tvlv buffer length 797 * @tvlv_value_len: tvlv buffer length
737 */ 798 */
738static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 799static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
739 struct batadv_orig_node *orig, 800 struct batadv_orig_node *orig,
740 u8 flags, 801 u8 flags,
741 void *tvlv_value, 802 void *tvlv_value,
742 u16 tvlv_value_len) 803 u16 tvlv_value_len)
743{ 804{
744 bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 805 bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
745 u8 mcast_flags = BATADV_NO_FLAGS; 806 u8 mcast_flags = BATADV_NO_FLAGS;
@@ -789,8 +850,8 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
789 */ 850 */
790void batadv_mcast_init(struct batadv_priv *bat_priv) 851void batadv_mcast_init(struct batadv_priv *bat_priv)
791{ 852{
792 batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1, 853 batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
793 NULL, BATADV_TVLV_MCAST, 1, 854 NULL, BATADV_TVLV_MCAST, 2,
794 BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 855 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
795} 856}
796 857
@@ -800,8 +861,8 @@ void batadv_mcast_init(struct batadv_priv *bat_priv)
800 */ 861 */
801void batadv_mcast_free(struct batadv_priv *bat_priv) 862void batadv_mcast_free(struct batadv_priv *bat_priv)
802{ 863{
803 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1); 864 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
804 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1); 865 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
805 866
806 spin_lock_bh(&bat_priv->tt.commit_lock); 867 spin_lock_bh(&bat_priv->tt.commit_lock);
807 batadv_mcast_mla_tt_retract(bat_priv, NULL); 868 batadv_mcast_mla_tt_retract(bat_priv, NULL);