diff options
| -rw-r--r-- | net/batman-adv/Kconfig | 2 | ||||
| -rw-r--r-- | net/batman-adv/multicast.c | 87 |
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 | ||
| 67 | config BATMAN_ADV_MCAST | 67 | config 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 | */ | ||
| 297 | static 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 | */ | ||
| 364 | static 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 | */ |
| 738 | static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | 799 | static 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 | */ |
| 790 | void batadv_mcast_init(struct batadv_priv *bat_priv) | 851 | void 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 | */ |
| 801 | void batadv_mcast_free(struct batadv_priv *bat_priv) | 862 | void 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); |
