Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Refactor the multicast membership code so that we can ha...
details: https://anonhg.NetBSD.org/src/rev/f1eacc75ede7
branches: trunk
changeset: 803103:f1eacc75ede7
user: christos <christos%NetBSD.org@localhost>
date: Sun Oct 12 19:00:21 2014 +0000
description:
Refactor the multicast membership code so that we can handle v4 mapped
addresses using the v6 membership ioctls.
diffstat:
sys/netinet/ip_output.c | 293 +++++++++++++++++++++++++--------------------
sys/netinet6/ip6_output.c | 167 +++++++++++++++----------
sys/netinet6/ip6_var.h | 7 +-
3 files changed, 265 insertions(+), 202 deletions(-)
diffs (truncated from 653 to 300 lines):
diff -r b1f916ae3224 -r f1eacc75ede7 sys/netinet/ip_output.c
--- a/sys/netinet/ip_output.c Sun Oct 12 18:59:35 2014 +0000
+++ b/sys/netinet/ip_output.c Sun Oct 12 19:00:21 2014 +0000
@@ -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 @@
#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 @@
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 @@
{
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 @@
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))
Home |
Main Index |
Thread Index |
Old Index