void ipv6_sysctl_unregister(void);
#endif
+int ipv6_sock_mc_join(struct sock *sk, int ifindex,
+ const struct in6_addr *addr);
+int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
+ const struct in6_addr *addr);
+int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
+ const struct in6_addr *addr);
+int __ipv6_sock_mc_drop(struct sock *sk, int ifindex,
+ const struct in6_addr *addr);
#endif /* _NET_IPV6_H */
return iv > 0 ? iv : 1;
}
-int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
+int __ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
struct net_device *dev = NULL;
struct ipv6_mc_socklist *mc_lst;
struct net *net = sock_net(sk);
int err;
+ ASSERT_RTNL();
+
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
mc_lst->next = NULL;
mc_lst->addr = *addr;
- rtnl_lock();
if (ifindex == 0) {
struct rt6_info *rt;
rt = rt6_lookup(net, addr, NULL, 0, 0);
dev = __dev_get_by_index(net, ifindex);
if (dev == NULL) {
- rtnl_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return -ENODEV;
}
err = ipv6_dev_mc_inc(dev, addr);
if (err) {
- rtnl_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return err;
}
mc_lst->next = np->ipv6_mc_list;
rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
+ return 0;
+}
+EXPORT_SYMBOL(__ipv6_sock_mc_join);
+
+int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
+{
+ int ret;
+
+ rtnl_lock();
+ ret = __ipv6_sock_mc_join(sk, ifindex, addr);
rtnl_unlock();
- return 0;
+ return ret;
}
+EXPORT_SYMBOL(ipv6_sock_mc_join);
/*
* socket leave on multicast group
*/
-int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
+int __ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_mc_socklist *mc_lst;
struct ipv6_mc_socklist __rcu **lnk;
struct net *net = sock_net(sk);
+ ASSERT_RTNL();
+
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
- rtnl_lock();
for (lnk = &np->ipv6_mc_list;
(mc_lst = rtnl_dereference(*lnk)) != NULL;
lnk = &mc_lst->next) {
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
} else
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
- rtnl_unlock();
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
kfree_rcu(mc_lst, rcu);
return 0;
}
}
- rtnl_unlock();
return -EADDRNOTAVAIL;
}
+EXPORT_SYMBOL(__ipv6_sock_mc_drop);
+
+int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
+{
+ int ret;
+
+ rtnl_lock();
+ ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
+ rtnl_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL(ipv6_sock_mc_drop);
/* called with rcu_read_lock() */
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,