In order to keep if_get()/if_put() dances in the same function, I need
to change in6_selectroute() to no longer return an ``ifp''.

This is a first step towards this goal.  It moves the multicast code out
of in6_selectroute().  I could simplify things further but I'd prefer to
do that in small diffs.

ok?

Index: netinet6/in6_src.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.58
diff -u -p -r1.58 in6_src.c
--- netinet6/in6_src.c  11 Sep 2015 09:58:33 -0000      1.58
+++ netinet6/in6_src.c  11 Sep 2015 10:33:18 -0000
@@ -295,43 +295,17 @@ in6_selectsrc(struct in6_addr **in6src, 
 
 int
 in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
-    struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
-    struct rtentry **retrt, int norouteok, u_int rtableid)
+    struct route_in6 *ro, struct ifnet **retifp,
+    struct rtentry **retrt, unsigned int rtableid)
 {
        int error = 0;
        struct ifnet *ifp = NULL;
        struct rtentry *rt = NULL;
        struct sockaddr_in6 *sin6_next;
-       struct in6_pktinfo *pi = NULL;
        struct in6_addr *dst;
 
        dst = &dstsock->sin6_addr;
 
-       /* If the caller specify the outgoing interface explicitly, use it. */
-       if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
-               ifp = if_get(pi->ipi6_ifindex);
-               if (ifp != NULL &&
-                   (norouteok || retrt == NULL ||
-                    IN6_IS_ADDR_MULTICAST(dst))) {
-                       /*
-                        * we do not have to check or get the route for
-                        * multicast.
-                        */
-                       goto done;
-               } else
-                       goto getroute;
-       }
-
-       /*
-        * If the destination address is a multicast address and the outgoing
-        * interface for the address is specified by the caller, use it.
-        */
-       if (IN6_IS_ADDR_MULTICAST(dst) &&
-           mopts != NULL && (ifp = if_get(mopts->im6o_ifidx)) != NULL) {
-               goto done; /* we do not need a route for multicast. */
-       }
-
-  getroute:
        /*
         * If the next hop address for the packet is specified by the caller,
         * use it as the gateway.
@@ -467,8 +441,6 @@ in6_selectroute(struct sockaddr_in6 *dst
                 */
                error = EHOSTUNREACH;
        }
-       if (error == EHOSTUNREACH)
-               ip6stat.ip6s_noroute++;
 
        if (retifp != NULL)
                *retifp = ifp;
@@ -484,10 +456,26 @@ in6_selectif(struct sockaddr_in6 *dstsoc
     u_int rtableid)
 {
        struct rtentry *rt = NULL;
+       struct in6_pktinfo *pi = NULL;
        int error;
 
-       if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp,
-           &rt, 1, rtableid)) != 0)
+       /* If the caller specify the outgoing interface explicitly, use it. */
+       if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
+               *retifp = if_get(pi->ipi6_ifindex);
+               if (*retifp != NULL)
+                       return (0);
+       }
+
+       /*
+        * If the destination address is a multicast address and the outgoing
+        * interface for the address is specified by the caller, use it.
+        */
+       if (IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) &&
+           mopts != NULL && (*retifp = if_get(mopts->im6o_ifidx)) != NULL)
+               return (0);
+
+       if ((error = in6_selectroute(dstsock, opts, ro, retifp,
+           &rt, rtableid)) != 0)
                return (error);
 
        /*
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.182
diff -u -p -r1.182 ip6_output.c
--- netinet6/ip6_output.c       11 Sep 2015 09:58:33 -0000      1.182
+++ netinet6/ip6_output.c       11 Sep 2015 12:09:42 -0000
@@ -155,7 +155,7 @@ ip6_output(struct mbuf *m0, struct ip6_p
     int flags, struct ip6_moptions *im6o, struct inpcb *inp)
 {
        struct ip6_hdr *ip6;
-       struct ifnet *ifp;
+       struct ifnet *ifp = NULL;
        struct mbuf *m = m0;
        int hlen, tlen;
        struct route_in6 ip6route;
@@ -528,17 +528,27 @@ reroute:
        dstsock.sin6_addr = ip6->ip6_dst;
        dstsock.sin6_len = sizeof(dstsock);
        ro->ro_tableid = m->m_pkthdr.ph_rtableid;
-       if ((error = in6_selectroute(&dstsock, opt, im6o, ro, &ifp,
-           &rt, 0, m->m_pkthdr.ph_rtableid)) != 0) {
-               switch (error) {
-               case EHOSTUNREACH:
+
+       if (IN6_IS_ADDR_MULTICAST(&dstsock.sin6_addr)) {
+               struct in6_pktinfo *pi = NULL;
+
+               /*
+                * If the caller specify the outgoing interface
+                * explicitly, use it.
+                */
+               if (opt != NULL && (pi = opt->ip6po_pktinfo) != NULL)
+                       ifp = if_get(pi->ipi6_ifindex);
+
+               if (ifp == NULL && im6o != NULL)
+                       ifp = if_get(im6o->im6o_ifidx);
+       }
+
+       if (ifp == NULL) {
+               if ((error = in6_selectroute(&dstsock, opt, ro, &ifp,
+                   &rt, m->m_pkthdr.ph_rtableid)) != 0) {
                        ip6stat.ip6s_noroute++;
-                       break;
-               case EADDRNOTAVAIL:
-               default:
-                       break;  /* XXX statistics? */
+                       goto bad;
                }
-               goto bad;
        }
        if (rt == NULL) {
                /*
Index: netinet6/ip6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_var.h,v
retrieving revision 1.53
diff -u -p -r1.53 ip6_var.h
--- netinet6/ip6_var.h  11 Sep 2015 09:58:33 -0000      1.53
+++ netinet6/ip6_var.h  11 Sep 2015 10:29:26 -0000
@@ -311,8 +311,8 @@ int in6_selectsrc(struct in6_addr **, st
            struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *,
            struct in6_addr *, u_int);
 int    in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
-           struct ip6_moptions *, struct route_in6 *, struct ifnet **,
-           struct rtentry **, int, u_int rtableid);
+           struct route_in6 *, struct ifnet **,
+           struct rtentry **, unsigned int rtableid);
 
 u_int32_t ip6_randomflowlabel(void);
 #endif /* _KERNEL */

Reply via email to