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/48b88de543a1
branches:  trunk
changeset: 332961:48b88de543a1
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 a3e37dc59a17 -r 48b88de543a1 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