]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Ensure host routes and subnet routes are added correctly. v4.0.7
authorRoy Marples <roy@marples.name>
Mon, 1 Dec 2008 16:58:17 +0000 (16:58 +0000)
committerRoy Marples <roy@marples.name>
Mon, 1 Dec 2008 16:58:17 +0000 (16:58 +0000)
if-bsd.c

index e90b36c652a57781136c175d1ac0ba6925abcf38..d0ff24641c7c9765c14957dcff80f38ccc9fdb4a 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -98,12 +98,11 @@ if_address(const char *ifname, const struct in_addr *address,
 }
 
 int
-if_route(const struct interface *iface, const struct in_addr *destination,
-        const struct in_addr *netmask, const struct in_addr *gateway,
+if_route(const struct interface *iface, const struct in_addr *dest,
+        const struct in_addr *net, const struct in_addr *gate,
         _unused int metric, int action)
 {
        int s;
-       static int seq;
        union sockunion {
                struct sockaddr sa;
                struct sockaddr_in sin;
@@ -122,58 +121,77 @@ if_route(const struct interface *iface, const struct in_addr *destination,
        size_t l;
        int retval = 0;
 
-#define ADDSU(_su) \
+#define ADDSU(_su) \
        l = SA_SIZE(&(_su.sa)); \
        memcpy(bp, &(_su), l); \
-       bp += l;
-#define ADDADDR(_addr) \
+       bp += l; \
+}
+#define ADDADDR(_addr) { \
        memset (&su, 0, sizeof(su)); \
        su.sin.sin_family = AF_INET; \
        su.sin.sin_len = sizeof(su.sin); \
        memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
-       ADDSU(su);
+       ADDSU(su); \
+}
 
        if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
                return -1;
 
        memset(&rtm, 0, sizeof(rtm));
        rtm.hdr.rtm_version = RTM_VERSION;
-       rtm.hdr.rtm_seq = ++seq;
+       rtm.hdr.rtm_seq = 1;
        if (action == 0)
                rtm.hdr.rtm_type = RTM_CHANGE;
        else if (action > 0)
                rtm.hdr.rtm_type = RTM_ADD;
        else
                rtm.hdr.rtm_type = RTM_DELETE;
-       rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
-       if (netmask->s_addr == INADDR_BROADCAST)
+       rtm.hdr.rtm_flags = RTF_UP;
+       /* None interface subnet routes are static. */
+       if (gate->s_addr != INADDR_ANY ||
+           net->s_addr != iface->net.s_addr ||
+           dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
+               rtm.hdr.rtm_flags |= RTF_STATIC;
+       rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+       if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
                rtm.hdr.rtm_flags |= RTF_HOST;
-       if (gateway->s_addr != INADDR_ANY)      
-               rtm.hdr.rtm_flags |= RTF_GATEWAY;
-       rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
-
-       ADDADDR(destination);
-       ADDADDR(gateway);
-
-       /* Ensure that netmask is set correctly */
-       memset(&su, 0, sizeof(su));
-       su.sin.sin_family = AF_INET;
-       su.sin.sin_len = sizeof(su.sin);
-       memcpy(&su.sin.sin_addr, &netmask->s_addr, sizeof(su.sin.sin_addr));
-       p = su.sa.sa_len + (char *)&su;
-       for (su.sa.sa_len = 0; p > (char *)&su; )
-               if (*--p != 0) {
-                       su.sa.sa_len = 1 + p - (char *)&su;
-                       break;
-               }
-       ADDSU(su);
-
-       /* Make us a link layer socket for IFP */
-       memset(&su, 0, sizeof(su));
-       su.sdl.sdl_family = AF_LINK;
-       su.sdl.sdl_len = sizeof(su.sdl);
-       link_addr(iface->name, &su.sdl);
-       ADDSU(su);
+       else {
+               rtm.hdr.rtm_addrs |= RTA_NETMASK;
+               if (rtm.hdr.rtm_flags & RTF_STATIC)
+                       rtm.hdr.rtm_flags |= RTF_GATEWAY;
+               if (action >= 0)
+                       rtm.hdr.rtm_addrs |= RTA_IFA;
+       }
+
+       ADDADDR(dest);
+       if (rtm.hdr.rtm_flags & RTF_HOST ||
+           !(rtm.hdr.rtm_flags & RTF_STATIC))
+       {
+               /* Make us a link layer socket for the host gateway */
+               memset(&su, 0, sizeof(su));
+               su.sdl.sdl_len = sizeof(struct sockaddr_dl);
+               link_addr(iface->name, &su.sdl);
+               ADDSU(su);
+       } else
+               ADDADDR(gate);
+
+       if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
+               /* Ensure that netmask is set correctly */
+               memset(&su, 0, sizeof(su));
+               su.sin.sin_family = AF_INET;
+               su.sin.sin_len = sizeof(su.sin);
+               memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
+               p = su.sa.sa_len + (char *)&su;
+               for (su.sa.sa_len = 0; p > (char *)&su;)
+                       if (*--p != 0) {
+                               su.sa.sa_len = 1 + p - (char *)&su;
+                               break;
+                       }
+               ADDSU(su);
+       }
+
+       if (rtm.hdr.rtm_addrs & RTA_IFA)
+               ADDADDR(&iface->addr);
 
        rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
        if (write(s, &rtm, l) == -1)