Module Name: src
Committed By: ozaki-r
Date: Thu Mar 2 05:24:23 UTC 2017
Modified Files:
src/sys/netinet: ip_output.c
src/sys/netinet6: ip6_output.c ip6_var.h
Log Message:
Make usages of ifp MP-safe in some functions of IP multicast
To generate a diff of this commit:
cvs rdiff -u -r1.272 -r1.273 src/sys/netinet/ip_output.c
cvs rdiff -u -r1.188 -r1.189 src/sys/netinet6/ip6_output.c
cvs rdiff -u -r1.72 -r1.73 src/sys/netinet6/ip6_var.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netinet/ip_output.c
diff -u src/sys/netinet/ip_output.c:1.272 src/sys/netinet/ip_output.c:1.273
--- src/sys/netinet/ip_output.c:1.272 Wed Feb 22 07:05:04 2017
+++ src/sys/netinet/ip_output.c Thu Mar 2 05:24:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_output.c,v 1.272 2017/02/22 07:05:04 ozaki-r Exp $ */
+/* $NetBSD: ip_output.c,v 1.273 2017/03/02 05:24:23 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.272 2017/02/22 07:05:04 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.273 2017/03/02 05:24:23 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -1444,6 +1444,7 @@ bad:
/*
* following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
+ * Must be called in a pserialize critical section.
*/
static struct ifnet *
ip_multicast_if(struct in_addr *a, int *ifindexp)
@@ -1462,10 +1463,12 @@ ip_multicast_if(struct in_addr *a, int *
if (ifindexp)
*ifindexp = ifindex;
} else {
- LIST_FOREACH(ia, &IN_IFADDR_HASH(a->s_addr), ia_hash) {
+ IN_ADDRHASH_READER_FOREACH(ia, a->s_addr) {
if (in_hosteq(ia->ia_addr.sin_addr, *a) &&
(ia->ia_ifp->if_flags & IFF_MULTICAST) != 0) {
ifp = ia->ia_ifp;
+ if (if_is_deactivated(ifp))
+ ifp = NULL;
break;
}
}
@@ -1509,7 +1512,7 @@ ip_getoptval(const struct sockopt *sopt,
static int
ip_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
- struct in_addr *ia, bool add)
+ struct psref *psref, struct in_addr *ia, bool add)
{
int error;
struct ip_mreq mreq;
@@ -1546,12 +1549,28 @@ ip_get_membership(const struct sockopt *
if (error != 0)
return error;
*ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp : NULL;
+ if (*ifp != NULL) {
+ if (if_is_deactivated(*ifp))
+ *ifp = NULL;
+ else
+ if_acquire(*ifp, psref);
+ }
rtcache_unref(rt, &ro);
rtcache_free(&ro);
} else {
+ int s = pserialize_read_enter();
*ifp = ip_multicast_if(&mreq.imr_interface, NULL);
- if (!add && *ifp == NULL)
+ if (!add && *ifp == NULL) {
+ pserialize_read_exit(s);
return EADDRNOTAVAIL;
+ }
+ if (*ifp != NULL) {
+ if (if_is_deactivated(*ifp))
+ *ifp = NULL;
+ else
+ if_acquire(*ifp, psref);
+ }
+ pserialize_read_exit(s);
}
return 0;
}
@@ -1565,26 +1584,31 @@ ip_add_membership(struct ip_moptions *im
{
struct ifnet *ifp = NULL; // XXX: gcc [ppc]
struct in_addr ia;
- int i, error;
+ int i, error, bound;
+ struct psref psref;
+ bound = curlwp_bind();
if (sopt->sopt_size == sizeof(struct ip_mreq))
- error = ip_get_membership(sopt, &ifp, &ia, true);
+ error = ip_get_membership(sopt, &ifp, &psref, &ia, true);
else
#ifdef INET6
- error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+ error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
#else
- return EINVAL;
+ error = EINVAL;
+ goto out;
#endif
if (error)
- return error;
+ goto out;
/*
* See if we found an interface, and confirm that it
* supports multicast.
*/
- if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
- return EADDRNOTAVAIL;
+ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+ error = EADDRNOTAVAIL;
+ goto out;
+ }
/*
* See if the membership already exists or if all the
@@ -1595,21 +1619,31 @@ ip_add_membership(struct ip_moptions *im
in_hosteq(imo->imo_membership[i]->inm_addr, ia))
break;
}
- if (i < imo->imo_num_memberships)
- return EADDRINUSE;
+ if (i < imo->imo_num_memberships) {
+ error = EADDRINUSE;
+ goto out;
+ }
- if (i == IP_MAX_MEMBERSHIPS)
- return ETOOMANYREFS;
+ if (i == IP_MAX_MEMBERSHIPS) {
+ error = ETOOMANYREFS;
+ goto out;
+ }
/*
* Everything looks good; add a new record to the multicast
* address list for the given interface.
*/
- if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL)
- return ENOBUFS;
+ if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL) {
+ error = ENOBUFS;
+ goto out;
+ }
++imo->imo_num_memberships;
- return 0;
+ error = 0;
+out:
+ if_put(ifp, &psref);
+ curlwp_bindx(bound);
+ return error;
}
/*
@@ -1621,19 +1655,24 @@ ip_drop_membership(struct ip_moptions *i
{
struct in_addr ia = { .s_addr = 0 }; // XXX: gcc [ppc]
struct ifnet *ifp = NULL; // XXX: gcc [ppc]
- int i, error;
+ int i, error, bound;
+ struct psref psref;
+ /* imo is protected by solock or referenced only by the caller */
+
+ bound = curlwp_bind();
if (sopt->sopt_size == sizeof(struct ip_mreq))
- error = ip_get_membership(sopt, &ifp, &ia, false);
+ error = ip_get_membership(sopt, &ifp, &psref, &ia, false);
else
#ifdef INET6
- error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+ error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
#else
- return EINVAL;
+ error = EINVAL;
+ goto out;
#endif
if (error)
- return error;
+ goto out;
/*
* Find the membership in the membership array.
@@ -1644,8 +1683,10 @@ ip_drop_membership(struct ip_moptions *i
in_hosteq(imo->imo_membership[i]->inm_addr, ia))
break;
}
- if (i == imo->imo_num_memberships)
- return EADDRNOTAVAIL;
+ if (i == imo->imo_num_memberships) {
+ error = EADDRNOTAVAIL;
+ goto out;
+ }
/*
* Give up the multicast address record to which the
@@ -1659,7 +1700,11 @@ ip_drop_membership(struct ip_moptions *i
for (++i; i < imo->imo_num_memberships; ++i)
imo->imo_membership[i-1] = imo->imo_membership[i];
--imo->imo_num_memberships;
- return 0;
+ error = 0;
+out:
+ curlwp_bindx(bound);
+ if_put(ifp, &psref);
+ return error;
}
/*
@@ -1691,7 +1736,8 @@ ip_setmoptions(struct ip_moptions **pimo
}
switch (sopt->sopt_name) {
- case IP_MULTICAST_IF:
+ case IP_MULTICAST_IF: {
+ int s;
/*
* Select the interface for outgoing multicast packets.
*/
@@ -1713,17 +1759,21 @@ ip_setmoptions(struct ip_moptions **pimo
* IP address. Find the interface and confirm that
* it supports multicasting.
*/
+ s = pserialize_read_enter();
ifp = ip_multicast_if(&addr, &ifindex);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+ pserialize_read_exit(s);
error = EADDRNOTAVAIL;
break;
}
imo->imo_multicast_if_index = ifp->if_index;
+ pserialize_read_exit(s);
if (ifindex)
imo->imo_multicast_addr = addr;
else
imo->imo_multicast_addr.s_addr = INADDR_ANY;
break;
+ }
case IP_MULTICAST_TTL:
/*
Index: src/sys/netinet6/ip6_output.c
diff -u src/sys/netinet6/ip6_output.c:1.188 src/sys/netinet6/ip6_output.c:1.189
--- src/sys/netinet6/ip6_output.c:1.188 Thu Mar 2 01:05:02 2017
+++ src/sys/netinet6/ip6_output.c Thu Mar 2 05:24:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ip6_output.c,v 1.188 2017/03/02 01:05:02 ozaki-r Exp $ */
+/* $NetBSD: ip6_output.c,v 1.189 2017/03/02 05:24:23 ozaki-r Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.188 2017/03/02 01:05:02 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.189 2017/03/02 05:24:23 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -2380,13 +2380,14 @@ ip6_freepcbopts(struct ip6_pktopts *pkto
}
int
-ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp, void *v,
- size_t l)
+ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
+ struct psref *psref, void *v, size_t l)
{
struct ipv6_mreq mreq;
int error;
struct in6_addr *ia = &mreq.ipv6mr_multiaddr;
struct in_addr *ia4 = (void *)&ia->s6_addr32[3];
+
error = sockopt_get(sopt, &mreq, sizeof(mreq));
if (error != 0)
return error;
@@ -2437,15 +2438,16 @@ ip6_get_membership(const struct sockopt
if (error != 0)
return error;
rt = rtcache_init(&ro);
- *ifp = rt != NULL ? rt->rt_ifp : NULL;
- /* FIXME *ifp is NOMPSAFE */
+ *ifp = rt != NULL ?
+ if_get_byindex(rt->rt_ifp->if_index, psref) : NULL;
rtcache_unref(rt, &ro);
rtcache_free(&ro);
} else {
/*
* If the interface is specified, validate it.
*/
- if ((*ifp = if_byindex(mreq.ipv6mr_interface)) == NULL)
+ *ifp = if_get_byindex(mreq.ipv6mr_interface, psref);
+ if (*ifp == NULL)
return ENXIO; /* XXX EINVAL? */
}
if (sizeof(*ia) == l)
@@ -2488,7 +2490,8 @@ ip6_setmoptions(const struct sockopt *so
switch (sopt->sopt_name) {
- case IPV6_MULTICAST_IF:
+ case IPV6_MULTICAST_IF: {
+ int s;
/*
* Select the interface for outgoing multicast packets.
*/
@@ -2496,19 +2499,24 @@ ip6_setmoptions(const struct sockopt *so
if (error != 0)
break;
+ s = pserialize_read_enter();
if (ifindex != 0) {
if ((ifp = if_byindex(ifindex)) == NULL) {
+ pserialize_read_exit(s);
error = ENXIO; /* XXX EINVAL? */
break;
}
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ pserialize_read_exit(s);
error = EADDRNOTAVAIL;
break;
}
} else
ifp = NULL;
im6o->im6o_multicast_if_index = if_get_index(ifp);
+ pserialize_read_exit(s);
break;
+ }
case IPV6_MULTICAST_HOPS:
{
@@ -2545,17 +2553,23 @@ ip6_setmoptions(const struct sockopt *so
im6o->im6o_multicast_loop = loop;
break;
- case IPV6_JOIN_GROUP:
+ case IPV6_JOIN_GROUP: {
+ int bound;
+ struct psref psref;
/*
* Add a multicast group membership.
* Group must be a valid IP6 multicast address.
*/
- if ((error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia))))
+ bound = curlwp_bind();
+ error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
+ if (error != 0) {
+ curlwp_bindx(bound);
return error;
+ }
if (IN6_IS_ADDR_V4MAPPED(&ia)) {
error = ip_setmoptions(&in6p->in6p_v4moptions, sopt);
- break;
+ goto put_break;
}
/*
* See if we found an interface, and confirm that it
@@ -2563,12 +2577,12 @@ ip6_setmoptions(const struct sockopt *so
*/
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
- break;
+ goto put_break;
}
if (in6_setscope(&ia, ifp, NULL)) {
error = EADDRNOTAVAIL; /* XXX: should not happen */
- break;
+ goto put_break;
}
/*
@@ -2578,11 +2592,11 @@ ip6_setmoptions(const struct sockopt *so
if (imm->i6mm_maddr->in6m_ifp == ifp &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
&ia))
- break;
+ goto put_break;
}
if (imm != NULL) {
error = EADDRINUSE;
- break;
+ goto put_break;
}
/*
* Everything looks good; add a new record to the multicast
@@ -2590,9 +2604,13 @@ ip6_setmoptions(const struct sockopt *so
*/
imm = in6_joingroup(ifp, &ia, &error, 0);
if (imm == NULL)
- break;
+ goto put_break;
LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
+ put_break:
+ if_put(ifp, &psref);
+ curlwp_bindx(bound);
break;
+ }
case IPV6_LEAVE_GROUP:
/*
Index: src/sys/netinet6/ip6_var.h
diff -u src/sys/netinet6/ip6_var.h:1.72 src/sys/netinet6/ip6_var.h:1.73
--- src/sys/netinet6/ip6_var.h:1.72 Tue Feb 14 03:05:06 2017
+++ src/sys/netinet6/ip6_var.h Thu Mar 2 05:24:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ip6_var.h,v 1.72 2017/02/14 03:05:06 ozaki-r Exp $ */
+/* $NetBSD: ip6_var.h,v 1.73 2017/03/02 05:24:23 ozaki-r Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@@ -404,8 +404,8 @@ int in6_selectsrc(struct sockaddr_in6 *,
struct ifnet **, struct psref *, struct in6_addr *);
int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
struct route **, struct rtentry **, bool);
-int ip6_get_membership(const struct sockopt *, struct ifnet **, void *,
- size_t);
+int ip6_get_membership(const struct sockopt *, struct ifnet **,
+ struct psref *, void *, size_t);
u_int32_t ip6_randomid(void);
u_int32_t ip6_randomflowlabel(void);