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);

Reply via email to