Module Name: src
Committed By: christos
Date: Sun Oct 12 19:00:21 UTC 2014
Modified Files:
src/sys/netinet: ip_output.c
src/sys/netinet6: ip6_output.c ip6_var.h
Log Message:
Refactor the multicast membership code so that we can handle v4 mapped
addresses using the v6 membership ioctls.
To generate a diff of this commit:
cvs rdiff -u -r1.231 -r1.232 src/sys/netinet/ip_output.c
cvs rdiff -u -r1.159 -r1.160 src/sys/netinet6/ip6_output.c
cvs rdiff -u -r1.62 -r1.63 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.231 src/sys/netinet/ip_output.c:1.232
--- src/sys/netinet/ip_output.c:1.231 Sat Oct 11 17:12:51 2014
+++ src/sys/netinet/ip_output.c Sun Oct 12 15:00:21 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_output.c,v 1.231 2014/10/11 21:12:51 christos Exp $ */
+/* $NetBSD: ip_output.c,v 1.232 2014/10/12 19:00:21 christos 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.231 2014/10/11 21:12:51 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.232 2014/10/12 19:00:21 christos Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@@ -124,6 +124,10 @@ __KERNEL_RCSID(0, "$NetBSD: ip_output.c,
#include <netinet/portalgo.h>
#include <netinet/udp.h>
+#ifdef INET6
+#include <netinet6/ip6_var.h>
+#endif
+
#ifdef MROUTING
#include <netinet/ip_mroute.h>
#endif
@@ -1359,6 +1363,158 @@ ip_getoptval(const struct sockopt *sopt,
return 0;
}
+static int
+ip_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
+ struct in_addr *ia, bool add)
+{
+ int error;
+ struct ip_mreq mreq;
+
+ error = sockopt_get(sopt, &mreq, sizeof(mreq));
+ if (error)
+ return error;
+
+ if (!IN_MULTICAST(mreq.imr_multiaddr.s_addr))
+ return EINVAL;
+
+ memcpy(ia, &mreq.imr_multiaddr, sizeof(*ia));
+
+ if (in_nullhost(mreq.imr_interface)) {
+ union {
+ struct sockaddr dst;
+ struct sockaddr_in dst4;
+ } u;
+ struct route ro;
+
+ if (!add) {
+ *ifp = NULL;
+ return 0;
+ }
+ /*
+ * If no interface address was provided, use the interface of
+ * the route to the given multicast address.
+ */
+ struct rtentry *rt;
+ memset(&ro, 0, sizeof(ro));
+
+ sockaddr_in_init(&u.dst4, ia, 0);
+ rtcache_setdst(&ro, &u.dst);
+ *ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp : NULL;
+ rtcache_free(&ro);
+ } else {
+ *ifp = ip_multicast_if(&mreq.imr_interface, NULL);
+ if (!add && *ifp == NULL)
+ return EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+/*
+ * Add a multicast group membership.
+ * Group must be a valid IP multicast address.
+ */
+static int
+ip_add_membership(struct ip_moptions *imo, const struct sockopt *sopt)
+{
+ struct ifnet *ifp;
+ struct in_addr ia;
+ int i, error;
+
+ if (sopt->sopt_size == sizeof(struct ip_mreq))
+ error = ip_get_membership(sopt, &ifp, &ia, true);
+ else
+#ifdef INET6
+ error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+#else
+ return EINVAL;
+#endif
+
+ if (error)
+ return error;
+
+ /*
+ * See if we found an interface, and confirm that it
+ * supports multicast.
+ */
+ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
+ return EADDRNOTAVAIL;
+
+ /*
+ * See if the membership already exists or if all the
+ * membership slots are full.
+ */
+ for (i = 0; i < imo->imo_num_memberships; ++i) {
+ if (imo->imo_membership[i]->inm_ifp == ifp &&
+ in_hosteq(imo->imo_membership[i]->inm_addr, ia))
+ break;
+ }
+ if (i < imo->imo_num_memberships)
+ return EADDRINUSE;
+
+ if (i == IP_MAX_MEMBERSHIPS)
+ return ETOOMANYREFS;
+
+ /*
+ * 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;
+
+ ++imo->imo_num_memberships;
+ return 0;
+}
+
+/*
+ * Drop a multicast group membership.
+ * Group must be a valid IP multicast address.
+ */
+static int
+ip_drop_membership(struct ip_moptions *imo, const struct sockopt *sopt)
+{
+ struct in_addr ia;
+ struct ifnet *ifp;
+ int i, error;
+
+ if (sopt->sopt_size == sizeof(struct ip_mreq))
+ error = ip_get_membership(sopt, &ifp, &ia, false);
+ else
+#ifdef INET6
+ error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+#else
+ return EINVAL;
+#endif
+
+ if (error)
+ return error;
+
+ /*
+ * Find the membership in the membership array.
+ */
+ for (i = 0; i < imo->imo_num_memberships; ++i) {
+ if ((ifp == NULL ||
+ imo->imo_membership[i]->inm_ifp == ifp) &&
+ in_hosteq(imo->imo_membership[i]->inm_addr, ia))
+ break;
+ }
+ if (i == imo->imo_num_memberships)
+ return EADDRNOTAVAIL;
+
+ /*
+ * Give up the multicast address record to which the
+ * membership points.
+ */
+ in_delmulti(imo->imo_membership[i]);
+
+ /*
+ * Remove the gap in the membership array.
+ */
+ for (++i; i < imo->imo_num_memberships; ++i)
+ imo->imo_membership[i-1] = imo->imo_membership[i];
+ --imo->imo_num_memberships;
+ return 0;
+}
+
/*
* Set the IP multicast options in response to user setsockopt().
*/
@@ -1367,9 +1523,8 @@ ip_setmoptions(struct ip_moptions **pimo
{
struct ip_moptions *imo = *pimo;
struct in_addr addr;
- struct ip_mreq lmreq, *mreq;
struct ifnet *ifp;
- int i, ifindex, error = 0;
+ int ifindex, error = 0;
if (!imo) {
/*
@@ -1438,134 +1593,12 @@ ip_setmoptions(struct ip_moptions **pimo
error = ip_getoptval(sopt, &imo->imo_multicast_loop, 1);
break;
- case IP_ADD_MEMBERSHIP:
- /*
- * Add a multicast group membership.
- * Group must be a valid IP multicast address.
- */
- error = sockopt_get(sopt, &lmreq, sizeof(lmreq));
- if (error)
- break;
-
- mreq = &lmreq;
-
- if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
- error = EINVAL;
- break;
- }
- /*
- * If no interface address was provided, use the interface of
- * the route to the given multicast address.
- */
- if (in_nullhost(mreq->imr_interface)) {
- struct rtentry *rt;
- union {
- struct sockaddr dst;
- struct sockaddr_in dst4;
- } u;
- struct route ro;
-
- memset(&ro, 0, sizeof(ro));
-
- sockaddr_in_init(&u.dst4, &mreq->imr_multiaddr, 0);
- rtcache_setdst(&ro, &u.dst);
- ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp
- : NULL;
- rtcache_free(&ro);
- } else {
- ifp = ip_multicast_if(&mreq->imr_interface, NULL);
- }
- /*
- * See if we found an interface, and confirm that it
- * supports multicast.
- */
- if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
- error = EADDRNOTAVAIL;
- break;
- }
- /*
- * See if the membership already exists or if all the
- * membership slots are full.
- */
- for (i = 0; i < imo->imo_num_memberships; ++i) {
- if (imo->imo_membership[i]->inm_ifp == ifp &&
- in_hosteq(imo->imo_membership[i]->inm_addr,
- mreq->imr_multiaddr))
- break;
- }
- if (i < imo->imo_num_memberships) {
- error = EADDRINUSE;
- break;
- }
- if (i == IP_MAX_MEMBERSHIPS) {
- error = ETOOMANYREFS;
- break;
- }
- /*
- * Everything looks good; add a new record to the multicast
- * address list for the given interface.
- */
- if ((imo->imo_membership[i] =
- in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
- error = ENOBUFS;
- break;
- }
- ++imo->imo_num_memberships;
+ case IP_ADD_MEMBERSHIP: /* IPV6_JOIN_GROUP */
+ error = ip_add_membership(imo, sopt);
break;
- case IP_DROP_MEMBERSHIP:
- /*
- * Drop a multicast group membership.
- * Group must be a valid IP multicast address.
- */
- error = sockopt_get(sopt, &lmreq, sizeof(lmreq));
- if (error)
- break;
-
- mreq = &lmreq;
-
- if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
- error = EINVAL;
- break;
- }
- /*
- * If an interface address was specified, get a pointer
- * to its ifnet structure.
- */
- if (in_nullhost(mreq->imr_interface))
- ifp = NULL;
- else {
- ifp = ip_multicast_if(&mreq->imr_interface, NULL);
- if (ifp == NULL) {
- error = EADDRNOTAVAIL;
- break;
- }
- }
- /*
- * Find the membership in the membership array.
- */
- for (i = 0; i < imo->imo_num_memberships; ++i) {
- if ((ifp == NULL ||
- imo->imo_membership[i]->inm_ifp == ifp) &&
- in_hosteq(imo->imo_membership[i]->inm_addr,
- mreq->imr_multiaddr))
- break;
- }
- if (i == imo->imo_num_memberships) {
- error = EADDRNOTAVAIL;
- break;
- }
- /*
- * Give up the multicast address record to which the
- * membership points.
- */
- in_delmulti(imo->imo_membership[i]);
- /*
- * Remove the gap in the membership array.
- */
- for (++i; i < imo->imo_num_memberships; ++i)
- imo->imo_membership[i-1] = imo->imo_membership[i];
- --imo->imo_num_memberships;
+ case IP_DROP_MEMBERSHIP: /* IPV6_LEAVE_GROUP */
+ error = ip_drop_membership(imo, sopt);
break;
default:
Index: src/sys/netinet6/ip6_output.c
diff -u src/sys/netinet6/ip6_output.c:1.159 src/sys/netinet6/ip6_output.c:1.160
--- src/sys/netinet6/ip6_output.c:1.159 Sat Oct 11 16:53:16 2014
+++ src/sys/netinet6/ip6_output.c Sun Oct 12 15:00:21 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ip6_output.c,v 1.159 2014/10/11 20:53:16 christos Exp $ */
+/* $NetBSD: ip6_output.c,v 1.160 2014/10/12 19:00:21 christos 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.159 2014/10/11 20:53:16 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.160 2014/10/12 19:00:21 christos Exp $");
#include "opt_inet.h"
#include "opt_inet6.h"
@@ -123,8 +123,8 @@ static int ip6_pcbopt(int, u_char *, int
static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, kauth_cred_t,
int, int, int);
-static int ip6_setmoptions(const struct sockopt *, struct ip6_moptions **);
-static int ip6_getmoptions(struct sockopt *, struct ip6_moptions *);
+static int ip6_setmoptions(const struct sockopt *, struct in6pcb *);
+static int ip6_getmoptions(struct sockopt *, struct in6pcb *);
static int ip6_copyexthdr(struct mbuf **, void *, int);
static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
struct ip6_frag **);
@@ -1636,7 +1636,7 @@ else \
case IPV6_MULTICAST_LOOP:
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
- error = ip6_setmoptions(sopt, &in6p->in6p_moptions);
+ error = ip6_setmoptions(sopt, in6p);
break;
case IPV6_PORTRANGE:
@@ -1860,7 +1860,7 @@ else \
case IPV6_MULTICAST_LOOP:
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
- error = ip6_getmoptions(sopt, in6p->in6p_moptions);
+ error = ip6_getmoptions(sopt, in6p);
break;
case IPV6_PORTALGO:
@@ -2267,20 +2267,90 @@ ip6_freepcbopts(struct ip6_pktopts *pkto
free(pktopt, M_IP6OPT);
}
+int
+ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp, 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;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(ia)) {
+ /*
+ * We use the unspecified address to specify to accept
+ * all multicast addresses. Only super user is allowed
+ * to do this.
+ */
+ if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_IPV6,
+ KAUTH_REQ_NETWORK_IPV6_JOIN_MULTICAST, NULL, NULL, NULL))
+ return EACCES;
+ } else if (IN6_IS_ADDR_V4MAPPED(ia)) {
+ // Don't bother if we are not going to use ifp.
+ if (l == sizeof(*ia)) {
+ memcpy(v, ia, l);
+ return 0;
+ }
+ } else if (!IN6_IS_ADDR_MULTICAST(ia)) {
+ return EINVAL;
+ }
+
+ /*
+ * If no interface was explicitly specified, choose an
+ * appropriate one according to the given multicast address.
+ */
+ if (mreq.ipv6mr_interface == 0) {
+ struct rtentry *rt;
+ union {
+ struct sockaddr dst;
+ struct sockaddr_in dst4;
+ struct sockaddr_in6 dst6;
+ } u;
+ struct route ro;
+
+ /*
+ * Look up the routing table for the
+ * address, and choose the outgoing interface.
+ * XXX: is it a good approach?
+ */
+ memset(&ro, 0, sizeof(ro));
+ if (IN6_IS_ADDR_V4MAPPED(ia))
+ sockaddr_in_init(&u.dst4, ia4, 0);
+ else
+ sockaddr_in6_init(&u.dst6, ia, 0, 0, 0);
+ rtcache_setdst(&ro, &u.dst);
+ *ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp : NULL;
+ rtcache_free(&ro);
+ } else {
+ /*
+ * If the interface is specified, validate it.
+ */
+ if ((*ifp = if_byindex(mreq.ipv6mr_interface)) == NULL)
+ return ENXIO; /* XXX EINVAL? */
+ }
+ if (sizeof(*ia) == l)
+ memcpy(v, ia, l);
+ else
+ memcpy(v, ia4, l);
+ return 0;
+}
+
/*
* Set the IP6 multicast options in response to user setsockopt().
*/
static int
-ip6_setmoptions(const struct sockopt *sopt, struct ip6_moptions **im6op)
+ip6_setmoptions(const struct sockopt *sopt, struct in6pcb *in6p)
{
int error = 0;
u_int loop, ifindex;
struct ipv6_mreq mreq;
+ struct in6_addr ia;
struct ifnet *ifp;
- struct ip6_moptions *im6o = *im6op;
- struct route ro;
+ struct ip6_moptions *im6o = in6p->in6p_moptions;
struct in6_multi_mship *imm;
- struct lwp *l = curlwp; /* XXX */
if (im6o == NULL) {
/*
@@ -2290,8 +2360,7 @@ ip6_setmoptions(const struct sockopt *so
im6o = malloc(sizeof(*im6o), M_IPMOPTS, M_NOWAIT);
if (im6o == NULL)
return (ENOBUFS);
-
- *im6op = im6o;
+ in6p->in6p_moptions = im6o;
im6o->im6o_multicast_ifp = NULL;
im6o->im6o_multicast_hlim = ip6_defmcasthlim;
im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
@@ -2362,60 +2431,13 @@ ip6_setmoptions(const struct sockopt *so
* Add a multicast group membership.
* Group must be a valid IP6 multicast address.
*/
- error = sockopt_get(sopt, &mreq, sizeof(mreq));
- if (error != 0)
- break;
+ if ((error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia))))
+ return error;
- if (IN6_IS_ADDR_UNSPECIFIED(&mreq.ipv6mr_multiaddr)) {
- /*
- * We use the unspecified address to specify to accept
- * all multicast addresses. Only super user is allowed
- * to do this.
- */
- if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_IPV6,
- KAUTH_REQ_NETWORK_IPV6_JOIN_MULTICAST, NULL, NULL, NULL))
- {
- error = EACCES;
- break;
- }
- } else if (!IN6_IS_ADDR_MULTICAST(&mreq.ipv6mr_multiaddr)) {
- error = EINVAL;
+ if (IN6_IS_ADDR_V4MAPPED(&ia)) {
+ error = ip_setmoptions(&in6p->in6p_v4moptions, sopt);
break;
}
-
- /*
- * If no interface was explicitly specified, choose an
- * appropriate one according to the given multicast address.
- */
- if (mreq.ipv6mr_interface == 0) {
- struct rtentry *rt;
- union {
- struct sockaddr dst;
- struct sockaddr_in6 dst6;
- } u;
-
- /*
- * Look up the routing table for the
- * address, and choose the outgoing interface.
- * XXX: is it a good approach?
- */
- memset(&ro, 0, sizeof(ro));
- sockaddr_in6_init(&u.dst6, &mreq.ipv6mr_multiaddr, 0,
- 0, 0);
- rtcache_setdst(&ro, &u.dst);
- ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp
- : NULL;
- rtcache_free(&ro);
- } else {
- /*
- * If the interface is specified, validate it.
- */
- if ((ifp = if_byindex(mreq.ipv6mr_interface)) == NULL) {
- error = ENXIO; /* XXX EINVAL? */
- break;
- }
- }
-
/*
* See if we found an interface, and confirm that it
* supports multicast
@@ -2425,7 +2447,7 @@ ip6_setmoptions(const struct sockopt *so
break;
}
- if (in6_setscope(&mreq.ipv6mr_multiaddr, ifp, NULL)) {
+ if (in6_setscope(&ia, ifp, NULL)) {
error = EADDRNOTAVAIL; /* XXX: should not happen */
break;
}
@@ -2437,7 +2459,7 @@ ip6_setmoptions(const struct sockopt *so
imm != NULL; imm = imm->i6mm_chain.le_next)
if (imm->i6mm_maddr->in6m_ifp == ifp &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
- &mreq.ipv6mr_multiaddr))
+ &ia))
break;
if (imm != NULL) {
error = EADDRINUSE;
@@ -2447,7 +2469,7 @@ ip6_setmoptions(const struct sockopt *so
* Everything looks good; add a new record to the multicast
* address list for the given interface.
*/
- imm = in6_joingroup(ifp, &mreq.ipv6mr_multiaddr, &error, 0);
+ imm = in6_joingroup(ifp, &ia, &error, 0);
if (imm == NULL)
break;
LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
@@ -2462,6 +2484,10 @@ ip6_setmoptions(const struct sockopt *so
if (error != 0)
break;
+ if (IN6_IS_ADDR_V4MAPPED(&mreq.ipv6mr_multiaddr)) {
+ error = ip_setmoptions(&in6p->in6p_v4moptions, sopt);
+ break;
+ }
/*
* If an interface address was specified, get a pointer
* to its ifnet structure.
@@ -2547,8 +2573,8 @@ ip6_setmoptions(const struct sockopt *so
im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
im6o->im6o_memberships.lh_first == NULL) {
- free(*im6op, M_IPMOPTS);
- *im6op = NULL;
+ free(in6p->in6p_moptions, M_IPMOPTS);
+ in6p->in6p_moptions = NULL;
}
return (error);
@@ -2558,10 +2584,11 @@ ip6_setmoptions(const struct sockopt *so
* Return the IP6 multicast options in response to user getsockopt().
*/
static int
-ip6_getmoptions(struct sockopt *sopt, struct ip6_moptions *im6o)
+ip6_getmoptions(struct sockopt *sopt, struct in6pcb *in6p)
{
u_int optval;
int error;
+ struct ip6_moptions *im6o = in6p->in6p_moptions;
switch (sopt->sopt_name) {
case IPV6_MULTICAST_IF:
Index: src/sys/netinet6/ip6_var.h
diff -u src/sys/netinet6/ip6_var.h:1.62 src/sys/netinet6/ip6_var.h:1.63
--- src/sys/netinet6/ip6_var.h:1.62 Thu Jun 5 19:48:16 2014
+++ src/sys/netinet6/ip6_var.h Sun Oct 12 15:00:21 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ip6_var.h,v 1.62 2014/06/05 23:48:16 rmind Exp $ */
+/* $NetBSD: ip6_var.h,v 1.63 2014/10/12 19:00:21 christos Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@@ -316,6 +316,7 @@ extern const struct pr_usrreqs rip6_usrr
int icmp6_ctloutput(int, struct socket *, struct sockopt *);
+struct mbuf;
void ip6_init(void);
void ip6_input(struct mbuf *);
const struct ip6aux *ip6_getdstifaddr(struct mbuf *);
@@ -329,7 +330,7 @@ int ip6_lasthdr(struct mbuf *, int, int,
struct m_tag *ip6_addaux(struct mbuf *);
struct m_tag *ip6_findaux(struct mbuf *);
void ip6_delaux(struct mbuf *);
-
+struct ip6_hdr;
int ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
void ip6_savecontrol(struct in6pcb *, struct mbuf **, struct ip6_hdr *,
@@ -395,6 +396,8 @@ struct in6_addr *in6_selectsrc(struct s
int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route *, struct ifnet **,
struct rtentry **, int);
+int ip6_get_membership(const struct sockopt *, struct ifnet **, void *,
+ size_t);
u_int32_t ip6_randomid(void);
u_int32_t ip6_randomflowlabel(void);