aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c38
-rw-r--r--net/ipv6/mcast.c20
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
2467static 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;
2935out: 2943
2936 return err; 2944 return 0;
2937 2945
2946out_sock_create_autojoin:
2947 inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
2938out_sock_create: 2948out_sock_create:
2939 inet_ctl_sock_destroy(net->ipv6.igmp_sk); 2949 inet_ctl_sock_destroy(net->ipv6.igmp_sk);
2940 goto out; 2950out:
2951 return err;
2941} 2952}
2942 2953
2943static void __net_exit igmp6_net_exit(struct net *net) 2954static 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