|
@@ -2464,6 +2464,23 @@ err_exit:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int ipv6_mc_config(struct sock *sk, bool join,
|
|
|
+ const struct in6_addr *addr, int ifindex)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ASSERT_RTNL();
|
|
|
+
|
|
|
+ lock_sock(sk);
|
|
|
+ if (join)
|
|
|
+ ret = __ipv6_sock_mc_join(sk, ifindex, addr);
|
|
|
+ else
|
|
|
+ ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
|
|
|
+ release_sock(sk);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Manual configuration of address on an interface
|
|
|
*/
|
|
@@ -2476,10 +2493,10 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
|
|
struct inet6_ifaddr *ifp;
|
|
|
struct inet6_dev *idev;
|
|
|
struct net_device *dev;
|
|
|
+ unsigned long timeout;
|
|
|
+ clock_t expires;
|
|
|
int scope;
|
|
|
u32 flags;
|
|
|
- clock_t expires;
|
|
|
- unsigned long timeout;
|
|
|
|
|
|
ASSERT_RTNL();
|
|
|
|
|
@@ -2501,6 +2518,14 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
|
|
if (IS_ERR(idev))
|
|
|
return PTR_ERR(idev);
|
|
|
|
|
|
+ if (ifa_flags & IFA_F_MCAUTOJOIN) {
|
|
|
+ int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk,
|
|
|
+ true, pfx, ifindex);
|
|
|
+
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
scope = ipv6_addr_scope(pfx);
|
|
|
|
|
|
timeout = addrconf_timeout_fixup(valid_lft, HZ);
|
|
@@ -2542,6 +2567,9 @@ static int inet6_addr_add(struct net *net, int ifindex,
|
|
|
in6_ifa_put(ifp);
|
|
|
addrconf_verify_rtnl();
|
|
|
return 0;
|
|
|
+ } else if (ifa_flags & IFA_F_MCAUTOJOIN) {
|
|
|
+ ipv6_mc_config(net->ipv6.mc_autojoin_sk,
|
|
|
+ false, pfx, ifindex);
|
|
|
}
|
|
|
|
|
|
return PTR_ERR(ifp);
|
|
@@ -2578,6 +2606,10 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
|
|
|
jiffies);
|
|
|
ipv6_del_addr(ifp);
|
|
|
addrconf_verify_rtnl();
|
|
|
+ if (ipv6_addr_is_multicast(pfx)) {
|
|
|
+ ipv6_mc_config(net->ipv6.mc_autojoin_sk,
|
|
|
+ false, pfx, dev->ifindex);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
@@ -3945,7 +3977,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
|
|
|
|
/* We ignore other flags so far. */
|
|
|
ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
|
|
|
- IFA_F_NOPREFIXROUTE;
|
|
|
+ IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN;
|
|
|
|
|
|
ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
|
|
|
if (ifa == NULL) {
|