@@ -1204,6 +1204,7 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
newsk->sk_v6_rcv_saddr = treq->ir_v6_loc_addr;
inet6_sk(newsk)->saddr = treq->ir_v6_loc_addr;
newnp->ipv6_fl_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->pktoptions = NULL;
newsk->sk_bound_dev_if = treq->ir_iif;
newinet->inet_opt = NULL;
@@ -282,7 +282,7 @@ struct ipv6_pinfo {
__u32 dst_cookie;
__u32 rx_dst_cookie;
- struct ipv6_mc_socklist __rcu *ipv6_mc_list;
+ struct list_head ipv6_mc_list;
struct ipv6_ac_socklist *ipv6_ac_list;
struct ipv6_fl_socklist __rcu *ipv6_fl_list;
@@ -90,7 +90,7 @@ struct ipv6_mc_socklist {
struct in6_addr addr;
int ifindex;
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
- struct ipv6_mc_socklist __rcu *next;
+ struct list_head list;
rwlock_t sflock;
struct ip6_sf_socklist *sflist;
struct rcu_head rcu;
@@ -430,7 +430,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
newsk->sk_backlog_rcv = dccp_v4_do_rcv;
newnp->pktoptions = NULL;
newnp->opt = NULL;
- newnp->ipv6_mc_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
newnp->mcast_oif = inet_iif(skb);
@@ -497,7 +497,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
/* Clone RX bits */
newnp->rxopt.all = np->rxopt.all;
- newnp->ipv6_mc_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
newnp->pktoptions = NULL;
@@ -207,6 +207,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk);
np->hop_limit = -1;
+ INIT_LIST_HEAD(&np->ipv6_mc_list);
np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
np->mc_loop = 1;
np->mc_all = 1;
@@ -85,7 +85,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *mca,
static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *mca,
int sfmode, int sfcount, const struct in6_addr *psfsrc,
int delta);
-static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
+static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *mc_lst,
struct inet6_dev *idev);
static int __ipv6_dev_mc_inc(struct net_device *dev,
const struct in6_addr *addr, unsigned int mode);
@@ -109,11 +109,6 @@ int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
* socket join on multicast group
*/
-#define for_each_mc_rcu(np, mc) \
- for (mc = rcu_dereference((np)->ipv6_mc_list); \
- mc; \
- mc = rcu_dereference(mc->next))
-
static void mca_get(struct ifmcaddr6 *mc)
{
refcount_inc(&mc->mca_refcnt);
@@ -142,10 +137,10 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
const struct in6_addr *addr, unsigned int mode)
{
- struct net_device *dev = NULL;
- struct ipv6_mc_socklist *mc_lst;
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6_mc_socklist *mc_lst;
struct net *net = sock_net(sk);
+ struct net_device *dev = NULL;
int err;
ASSERT_RTNL();
@@ -153,22 +148,17 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
- rcu_read_lock();
- for_each_mc_rcu(np, mc_lst) {
+ list_for_each_entry(mc_lst, &np->ipv6_mc_list, list) {
if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
- ipv6_addr_equal(&mc_lst->addr, addr)) {
- rcu_read_unlock();
+ ipv6_addr_equal(&mc_lst->addr, addr))
return -EADDRINUSE;
- }
}
- rcu_read_unlock();
mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
-
if (!mc_lst)
return -ENOMEM;
- mc_lst->next = NULL;
+ INIT_LIST_HEAD(&mc_lst->list);
mc_lst->addr = *addr;
if (ifindex == 0) {
@@ -202,8 +192,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
return err;
}
- mc_lst->next = np->ipv6_mc_list;
- rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
+ list_add_rcu(&mc_lst->list, &np->ipv6_mc_list);
return 0;
}
@@ -227,7 +216,6 @@ 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();
@@ -235,25 +223,22 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
- for (lnk = &np->ipv6_mc_list;
- (mc_lst = rtnl_dereference(*lnk)) != NULL;
- lnk = &mc_lst->next) {
+ list_for_each_entry(mc_lst, &np->ipv6_mc_list, list) {
if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
ipv6_addr_equal(&mc_lst->addr, addr)) {
struct net_device *dev;
- *lnk = mc_lst->next;
-
dev = __dev_get_by_index(net, mc_lst->ifindex);
if (dev) {
struct inet6_dev *idev = __in6_dev_get(dev);
- (void) ip6_mc_leave_src(sk, mc_lst, idev);
+ ip6_mc_leave_src(sk, mc_lst, idev);
if (idev)
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
} else
- (void) ip6_mc_leave_src(sk, mc_lst, NULL);
+ ip6_mc_leave_src(sk, mc_lst, NULL);
+ list_del_rcu(&mc_lst->list);
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
kfree_rcu(mc_lst, rcu);
return 0;
@@ -297,27 +282,27 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
void __ipv6_sock_mc_close(struct sock *sk)
{
+ struct ipv6_mc_socklist *mc_lst, *tmp;
struct ipv6_pinfo *np = inet6_sk(sk);
- struct ipv6_mc_socklist *mc_lst;
struct net *net = sock_net(sk);
ASSERT_RTNL();
- while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) {
+ list_for_each_entry_safe(mc_lst, tmp, &np->ipv6_mc_list, list) {
struct net_device *dev;
- np->ipv6_mc_list = mc_lst->next;
-
dev = __dev_get_by_index(net, mc_lst->ifindex);
if (dev) {
struct inet6_dev *idev = __in6_dev_get(dev);
- (void) ip6_mc_leave_src(sk, mc_lst, idev);
+ ip6_mc_leave_src(sk, mc_lst, idev);
if (idev)
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
- } else
- (void) ip6_mc_leave_src(sk, mc_lst, NULL);
+ } else {
+ ip6_mc_leave_src(sk, mc_lst, NULL);
+ }
+ list_del_rcu(&mc_lst->list);
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
kfree_rcu(mc_lst, rcu);
}
@@ -327,23 +312,27 @@ void ipv6_sock_mc_close(struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
- if (!rcu_access_pointer(np->ipv6_mc_list))
- return;
rtnl_lock();
+ if (list_empty(&np->ipv6_mc_list)) {
+ rtnl_unlock();
+ return;
+ }
+
__ipv6_sock_mc_close(sk);
rtnl_unlock();
}
int ip6_mc_source(int add, int omode, struct sock *sk,
- struct group_source_req *pgsr)
+ struct group_source_req *pgsr)
{
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct in6_addr *source, *group;
+ struct ipv6_mc_socklist *mc_lst;
struct net *net = sock_net(sk);
- struct ipv6_mc_socklist *mc;
struct ip6_sf_socklist *psl;
struct inet6_dev *idev;
int leavegroup = 0;
+ bool found = false;
int mclocked = 0;
int i, j, rv;
int err;
@@ -363,33 +352,35 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
err = -EADDRNOTAVAIL;
- for_each_mc_rcu(inet6, mc) {
- if (pgsr->gsr_interface && mc->ifindex != pgsr->gsr_interface)
+ list_for_each_entry_rcu(mc_lst, &inet6->ipv6_mc_list, list) {
+ if (pgsr->gsr_interface && mc_lst->ifindex != pgsr->gsr_interface)
continue;
- if (ipv6_addr_equal(&mc->addr, group))
+ if (ipv6_addr_equal(&mc_lst->addr, group)) {
+ found = true;
break;
+ }
}
- if (!mc) { /* must have a prior join */
+ if (!found) { /* must have a prior join */
err = -EINVAL;
goto done;
}
/* if a source filter was set, must be the same mode as before */
- if (mc->sflist) {
- if (mc->sfmode != omode) {
+ if (mc_lst->sflist) {
+ if (mc_lst->sfmode != omode) {
err = -EINVAL;
goto done;
}
- } else if (mc->sfmode != omode) {
+ } else if (mc_lst->sfmode != omode) {
/* allow mode switches for empty-set filters */
ip6_mc_add_src(idev, group, omode, 0, NULL, 0);
- ip6_mc_del_src(idev, group, mc->sfmode, 0, NULL, 0);
- mc->sfmode = omode;
+ ip6_mc_del_src(idev, group, mc_lst->sfmode, 0, NULL, 0);
+ mc_lst->sfmode = omode;
}
- write_lock(&mc->sflock);
+ write_lock(&mc_lst->sflock);
mclocked = 1;
- psl = mc->sflist;
+ psl = mc_lst->sflist;
if (!add) {
if (!psl)
goto done; /* err = -EADDRNOTAVAIL */
@@ -442,7 +433,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
}
psl = newpsl;
- mc->sflist = psl;
+ mc_lst->sflist = psl;
}
rv = 1; /* > 0 for insert logic below if sl_count is 0 */
for (i = 0; i < psl->sl_count; i++) {
@@ -459,7 +450,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
ip6_mc_add_src(idev, group, omode, 1, source, 1);
done:
if (mclocked)
- write_unlock(&mc->sflock);
+ write_unlock(&mc_lst->sflock);
read_unlock_bh(&idev->lock);
rcu_read_unlock();
if (leavegroup)
@@ -472,11 +463,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
{
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *newpsl, *psl;
+ struct ipv6_mc_socklist *mc_lst;
struct net *net = sock_net(sk);
const struct in6_addr *group;
- struct ipv6_mc_socklist *mc;
struct inet6_dev *idev;
int leavegroup = 0;
+ bool found = false;
int i, err;
group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
@@ -502,13 +494,15 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
goto done;
}
- for_each_mc_rcu(inet6, mc) {
- if (mc->ifindex != gsf->gf_interface)
+ list_for_each_entry_rcu(mc_lst, &inet6->ipv6_mc_list, list) {
+ if (mc_lst->ifindex != gsf->gf_interface)
continue;
- if (ipv6_addr_equal(&mc->addr, group))
+ if (ipv6_addr_equal(&mc_lst->addr, group)) {
+ found = true;
break;
+ }
}
- if (!mc) { /* must have a prior join */
+ if (!found) { /* must have a prior join */
err = -EINVAL;
goto done;
}
@@ -537,17 +531,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
}
- write_lock(&mc->sflock);
- psl = mc->sflist;
+ write_lock(&mc_lst->sflock);
+ psl = mc_lst->sflist;
if (psl) {
- ip6_mc_del_src(idev, group, mc->sfmode,
+ ip6_mc_del_src(idev, group, mc_lst->sfmode,
psl->sl_count, psl->sl_addr, 0);
sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
} else
- ip6_mc_del_src(idev, group, mc->sfmode, 0, NULL, 0);
- mc->sflist = newpsl;
- mc->sfmode = gsf->gf_fmode;
- write_unlock(&mc->sflock);
+ ip6_mc_del_src(idev, group, mc_lst->sfmode, 0, NULL, 0);
+ mc_lst->sflist = newpsl;
+ mc_lst->sfmode = gsf->gf_fmode;
+ write_unlock(&mc_lst->sflock);
err = 0;
done:
read_unlock_bh(&idev->lock);
@@ -560,13 +554,14 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
struct sockaddr_storage __user *p)
{
+ struct ipv6_pinfo *inet6 = inet6_sk(sk);
+ struct ipv6_mc_socklist *mc_lst;
+ struct net *net = sock_net(sk);
int err, i, count, copycount;
const struct in6_addr *group;
- struct ipv6_mc_socklist *mc;
- struct inet6_dev *idev;
- struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *psl;
- struct net *net = sock_net(sk);
+ struct inet6_dev *idev;
+ bool found = false;
group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
@@ -587,16 +582,18 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
* so reading the list is safe.
*/
- for_each_mc_rcu(inet6, mc) {
- if (mc->ifindex != gsf->gf_interface)
+ list_for_each_entry_rcu(mc_lst, &inet6->ipv6_mc_list, list) {
+ if (mc_lst->ifindex != gsf->gf_interface)
continue;
- if (ipv6_addr_equal(group, &mc->addr))
+ if (ipv6_addr_equal(group, &mc_lst->addr)) {
+ found = true;
break;
+ }
}
- if (!mc) /* must have a prior join */
+ if (!found) /* must have a prior join */
goto done;
- gsf->gf_fmode = mc->sfmode;
- psl = mc->sflist;
+ gsf->gf_fmode = mc_lst->sfmode;
+ psl = mc_lst->sflist;
count = psl ? psl->sl_count : 0;
read_unlock_bh(&idev->lock);
rcu_read_unlock();
@@ -604,7 +601,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
gsf->gf_numsrc = count;
/* changes to psl require the socket lock, and a write lock
- * on mc->sflock. We have the socket lock so reading here is safe.
+ * on mc_lst->sflock. We have the socket lock so reading here is safe.
*/
for (i = 0; i < copycount; i++, p++) {
struct sockaddr_in6 *psin6;
@@ -628,23 +625,25 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
const struct in6_addr *src_addr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
- struct ipv6_mc_socklist *mc;
+ struct ipv6_mc_socklist *mc_lst;
+ bool rv = true, found = false;
struct ip6_sf_socklist *psl;
- bool rv = true;
rcu_read_lock();
- for_each_mc_rcu(np, mc) {
- if (ipv6_addr_equal(&mc->addr, mc_addr))
+ list_for_each_entry_rcu(mc_lst, &np->ipv6_mc_list, list) {
+ if (ipv6_addr_equal(&mc_lst->addr, mc_addr)) {
+ found = true;
break;
+ }
}
- if (!mc) {
+ if (!found) {
rcu_read_unlock();
return np->mc_all;
}
- read_lock(&mc->sflock);
- psl = mc->sflist;
+ read_lock(&mc_lst->sflock);
+ psl = mc_lst->sflist;
if (!psl) {
- rv = mc->sfmode == MCAST_EXCLUDE;
+ rv = mc_lst->sfmode == MCAST_EXCLUDE;
} else {
int i;
@@ -652,12 +651,12 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
if (ipv6_addr_equal(&psl->sl_addr[i], src_addr))
break;
}
- if (mc->sfmode == MCAST_INCLUDE && i >= psl->sl_count)
+ if (mc_lst->sfmode == MCAST_INCLUDE && i >= psl->sl_count)
rv = false;
- if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
+ if (mc_lst->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
rv = false;
}
- read_unlock(&mc->sflock);
+ read_unlock(&mc_lst->sflock);
rcu_read_unlock();
return rv;
@@ -2463,22 +2462,25 @@ static void mld_join_group(struct ifmcaddr6 *mc)
spin_unlock_bh(&mc->mca_lock);
}
-static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
+static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *mc_lst,
struct inet6_dev *idev)
{
int err;
- write_lock_bh(&iml->sflock);
- if (!iml->sflist) {
+ write_lock_bh(&mc_lst->sflock);
+ if (!mc_lst->sflist) {
/* any-source empty exclude case */
- err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0);
+ err = ip6_mc_del_src(idev, &mc_lst->addr, mc_lst->sfmode,
+ 0, NULL, 0);
} else {
- err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode,
- iml->sflist->sl_count, iml->sflist->sl_addr, 0);
- sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max));
- iml->sflist = NULL;
- }
- write_unlock_bh(&iml->sflock);
+ err = ip6_mc_del_src(idev, &mc_lst->addr, mc_lst->sfmode,
+ mc_lst->sflist->sl_count,
+ mc_lst->sflist->sl_addr, 0);
+ sock_kfree_s(sk, mc_lst->sflist,
+ IP6_SFLSIZE(mc_lst->sflist->sl_max));
+ mc_lst->sflist = NULL;
+ }
+ write_unlock_bh(&mc_lst->sflock);
return err;
}
@@ -1242,7 +1242,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif
- newnp->ipv6_mc_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
newnp->pktoptions = NULL;
@@ -1311,7 +1311,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
First: no IPv4 options.
*/
newinet->inet_opt = NULL;
- newnp->ipv6_mc_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
@@ -754,7 +754,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
newnp = inet6_sk(newsk);
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
- newnp->ipv6_mc_list = NULL;
+ INIT_LIST_HEAD(&newnp->ipv6_mc_list);
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
Currently, struct ipv6_mc_socklist doesn't use list API so that code shape is a little bit different from others. So it converts ipv6_mc_socklist to use list API so it would improve readability. Signed-off-by: Taehee Yoo <ap420073@gmail.com> --- .../chelsio/inline_crypto/chtls/chtls_cm.c | 1 + include/linux/ipv6.h | 2 +- include/net/if_inet6.h | 2 +- net/dccp/ipv6.c | 4 +- net/ipv6/af_inet6.c | 1 + net/ipv6/mcast.c | 190 +++++++++--------- net/ipv6/tcp_ipv6.c | 4 +- net/sctp/ipv6.c | 2 +- 8 files changed, 105 insertions(+), 101 deletions(-)