diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 38 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 20 |
2 files changed, 51 insertions, 7 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 98e4a63d72bb..783bccfcc060 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2464,6 +2464,23 @@ err_exit: | |||
2464 | return err; | 2464 | return err; |
2465 | } | 2465 | } |
2466 | 2466 | ||
2467 | static int ipv6_mc_config(struct sock *sk, bool join, | ||
2468 | const struct in6_addr *addr, int ifindex) | ||
2469 | { | ||
2470 | int ret; | ||
2471 | |||
2472 | ASSERT_RTNL(); | ||
2473 | |||
2474 | lock_sock(sk); | ||
2475 | if (join) | ||
2476 | ret = __ipv6_sock_mc_join(sk, ifindex, addr); | ||
2477 | else | ||
2478 | ret = __ipv6_sock_mc_drop(sk, ifindex, addr); | ||
2479 | release_sock(sk); | ||
2480 | |||
2481 | return ret; | ||
2482 | } | ||
2483 | |||
2467 | /* | 2484 | /* |
2468 | * Manual configuration of address on an interface | 2485 | * Manual configuration of address on an interface |
2469 | */ | 2486 | */ |
@@ -2476,10 +2493,10 @@ static int inet6_addr_add(struct net *net, int ifindex, | |||
2476 | struct inet6_ifaddr *ifp; | 2493 | struct inet6_ifaddr *ifp; |
2477 | struct inet6_dev *idev; | 2494 | struct inet6_dev *idev; |
2478 | struct net_device *dev; | 2495 | struct net_device *dev; |
2496 | unsigned long timeout; | ||
2497 | clock_t expires; | ||
2479 | int scope; | 2498 | int scope; |
2480 | u32 flags; | 2499 | u32 flags; |
2481 | clock_t expires; | ||
2482 | unsigned long timeout; | ||
2483 | 2500 | ||
2484 | ASSERT_RTNL(); | 2501 | ASSERT_RTNL(); |
2485 | 2502 | ||
@@ -2501,6 +2518,14 @@ static int inet6_addr_add(struct net *net, int ifindex, | |||
2501 | if (IS_ERR(idev)) | 2518 | if (IS_ERR(idev)) |
2502 | return PTR_ERR(idev); | 2519 | return PTR_ERR(idev); |
2503 | 2520 | ||
2521 | if (ifa_flags & IFA_F_MCAUTOJOIN) { | ||
2522 | int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk, | ||
2523 | true, pfx, ifindex); | ||
2524 | |||
2525 | if (ret < 0) | ||
2526 | return ret; | ||
2527 | } | ||
2528 | |||
2504 | scope = ipv6_addr_scope(pfx); | 2529 | scope = ipv6_addr_scope(pfx); |
2505 | 2530 | ||
2506 | timeout = addrconf_timeout_fixup(valid_lft, HZ); | 2531 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
@@ -2542,6 +2567,9 @@ static int inet6_addr_add(struct net *net, int ifindex, | |||
2542 | in6_ifa_put(ifp); | 2567 | in6_ifa_put(ifp); |
2543 | addrconf_verify_rtnl(); | 2568 | addrconf_verify_rtnl(); |
2544 | return 0; | 2569 | return 0; |
2570 | } else if (ifa_flags & IFA_F_MCAUTOJOIN) { | ||
2571 | ipv6_mc_config(net->ipv6.mc_autojoin_sk, | ||
2572 | false, pfx, ifindex); | ||
2545 | } | 2573 | } |
2546 | 2574 | ||
2547 | return PTR_ERR(ifp); | 2575 | return PTR_ERR(ifp); |
@@ -2578,6 +2606,10 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags, | |||
2578 | jiffies); | 2606 | jiffies); |
2579 | ipv6_del_addr(ifp); | 2607 | ipv6_del_addr(ifp); |
2580 | addrconf_verify_rtnl(); | 2608 | addrconf_verify_rtnl(); |
2609 | if (ipv6_addr_is_multicast(pfx)) { | ||
2610 | ipv6_mc_config(net->ipv6.mc_autojoin_sk, | ||
2611 | false, pfx, dev->ifindex); | ||
2612 | } | ||
2581 | return 0; | 2613 | return 0; |
2582 | } | 2614 | } |
2583 | } | 2615 | } |
@@ -3945,7 +3977,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
3945 | 3977 | ||
3946 | /* We ignore other flags so far. */ | 3978 | /* We ignore other flags so far. */ |
3947 | ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | | 3979 | ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | |
3948 | IFA_F_NOPREFIXROUTE; | 3980 | IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN; |
3949 | 3981 | ||
3950 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); | 3982 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); |
3951 | if (ifa == NULL) { | 3983 | if (ifa == NULL) { |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index e4955d019734..1dd1fedff9f4 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -2929,20 +2929,32 @@ static int __net_init igmp6_net_init(struct net *net) | |||
2929 | 2929 | ||
2930 | inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; | 2930 | inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; |
2931 | 2931 | ||
2932 | err = inet_ctl_sock_create(&net->ipv6.mc_autojoin_sk, PF_INET6, | ||
2933 | SOCK_RAW, IPPROTO_ICMPV6, net); | ||
2934 | if (err < 0) { | ||
2935 | pr_err("Failed to initialize the IGMP6 autojoin socket (err %d)\n", | ||
2936 | err); | ||
2937 | goto out_sock_create; | ||
2938 | } | ||
2939 | |||
2932 | err = igmp6_proc_init(net); | 2940 | err = igmp6_proc_init(net); |
2933 | if (err) | 2941 | if (err) |
2934 | goto out_sock_create; | 2942 | goto out_sock_create_autojoin; |
2935 | out: | 2943 | |
2936 | return err; | 2944 | return 0; |
2937 | 2945 | ||
2946 | out_sock_create_autojoin: | ||
2947 | inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk); | ||
2938 | out_sock_create: | 2948 | out_sock_create: |
2939 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2949 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2940 | goto out; | 2950 | out: |
2951 | return err; | ||
2941 | } | 2952 | } |
2942 | 2953 | ||
2943 | static void __net_exit igmp6_net_exit(struct net *net) | 2954 | static void __net_exit igmp6_net_exit(struct net *net) |
2944 | { | 2955 | { |
2945 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2956 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2957 | inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk); | ||
2946 | igmp6_proc_exit(net); | 2958 | igmp6_proc_exit(net); |
2947 | } | 2959 | } |
2948 | 2960 | ||