Author: qingli
Date: Mon Oct  3 19:06:55 2011
New Revision: 225946
URL: http://svn.freebsd.org/changeset/base/225946

Log:
  This patch allows ARP to work properly in the presence of
  self-referencing routes. This patch is a rework of r223862.
  
  Reviewed by:  bz, zec
  MFC after:    5 days

Modified:
  head/sys/netinet/in.c

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c       Mon Oct  3 18:05:51 2011        (r225945)
+++ head/sys/netinet/in.c       Mon Oct  3 19:06:55 2011        (r225946)
@@ -1411,6 +1411,8 @@ static int
 in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr 
*l3addr)
 {
        struct rtentry *rt;
+       struct ifnet *xifp;
+       int error = 0;
 
        KASSERT(l3addr->sa_family == AF_INET,
            ("sin_family %d", l3addr->sa_family));
@@ -1418,30 +1420,35 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
        /* XXX rtalloc1 should take a const param */
        rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
 
+       if (rt == NULL)
+               return (EINVAL);
+
        /*
         * If the gateway for an existing host route matches the target L3
-        * address, allow for ARP to proceed.
+        * address, which is a special route inserted by some implementation
+        * such as MANET, and the interface is of the correct type, then
+        * allow for ARP to proceed.
         */
-       if (rt != NULL && (rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) &&
-           rt->rt_gateway->sa_family == AF_INET &&
-           memcmp(rt->rt_gateway->sa_data, l3addr->sa_data, 4) == 0) {
-               RTFREE_LOCKED(rt);
-               return (0);
-       }
-
-       if (rt == NULL || (!(flags & LLE_PUB) &&
-                          ((rt->rt_flags & RTF_GATEWAY) || 
-                           (rt->rt_ifp != ifp)))) {
+       if (rt->rt_flags & (RTF_GATEWAY | RTF_HOST)) {
+               xifp = rt->rt_ifp;
+               
+               if (xifp && (xifp->if_type != IFT_ETHER ||
+                    (xifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0))
+                       error = EINVAL;
+
+               if (memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
+                   sizeof(in_addr_t)) != 0)
+                       error = EINVAL;
+       } else if (!(flags & LLE_PUB) && ((rt->rt_flags & RTF_GATEWAY) ||
+           (rt->rt_ifp != ifp))) {
 #ifdef DIAGNOSTIC
                log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
                    inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
 #endif
-               if (rt != NULL)
-                       RTFREE_LOCKED(rt);
-               return (EINVAL);
+               error = EINVAL;
        }
        RTFREE_LOCKED(rt);
-       return 0;
+       return (error);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to