]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add IPv4LL subnet routes like the kernel does.
authorRoy Marples <roy@marples.name>
Fri, 7 Aug 2015 08:49:07 +0000 (08:49 +0000)
committerRoy Marples <roy@marples.name>
Fri, 7 Aug 2015 08:49:07 +0000 (08:49 +0000)
Build the routing table before applying routes, fixes [a3de5dcae1].

if-bsd.c
if-linux.c
ipv4.c
ipv4ll.c
ipv4ll.h

index f5ffe74024990c9dcf9477a1f13512cbc3fc704b..4a6a918f6243dc6f584aac94946b8e9512424cb5 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -81,6 +81,7 @@
 #include "if.h"
 #include "if-options.h"
 #include "ipv4.h"
+#include "ipv4ll.h"
 #include "ipv6.h"
 #include "ipv6nd.h"
 
@@ -508,6 +509,7 @@ int
 if_route(unsigned char cmd, const struct rt *rt)
 {
        const struct dhcp_state *state;
+       const struct ipv4ll_state *istate;
        union sockunion {
                struct sockaddr sa;
                struct sockaddr_in sin;
@@ -534,10 +536,14 @@ if_route(unsigned char cmd, const struct rt *rt)
                ADDSU;                                                        \
        }
 
-       if (cmd != RTM_DELETE)
+       if (cmd != RTM_DELETE) {
                state = D_CSTATE(rt->iface);
-       else    /* appease GCC */
+               istate = IPV4LL_DSTATE(rt->iface);
+       } else {
+               /* appease GCC */
                state = NULL;
+               istate = NULL;
+       }
        memset(&rtm, 0, sizeof(rtm));
        rtm.hdr.rtm_version = RTM_VERSION;
        rtm.hdr.rtm_seq = 1;
@@ -554,9 +560,14 @@ if_route(unsigned char cmd, const struct rt *rt)
        if (cmd != RTM_DELETE) {
                rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
                /* None interface subnet routes are static. */
-               if (rt->gate.s_addr != INADDR_ANY ||
+               if ((rt->gate.s_addr != INADDR_ANY ||
                    rt->net.s_addr != state->net.s_addr ||
-                   rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
+                   rt->dest.s_addr !=
+                   (state->addr.s_addr & state->net.s_addr)) &&
+                   (istate == NULL ||
+                   rt->dest.s_addr !=
+                   (istate->addr.s_addr & inaddr_llmask.s_addr) ||
+                   rt->net.s_addr != inaddr_llmask.s_addr))
                        rtm.hdr.rtm_flags |= RTF_STATIC;
                else {
 #ifdef RTF_CLONING
@@ -627,7 +638,7 @@ if_route(unsigned char cmd, const struct rt *rt)
                }
 
                if (rtm.hdr.rtm_addrs & RTA_IFA)
-                       ADDADDR(&state->addr);
+                       ADDADDR(istate == NULL ? &state->addr : &istate->addr);
 
                if (rt->mtu) {
                        rtm.hdr.rtm_inits |= RTV_MTU;
index 59d8f134b90f140ea812d078a39b15f44409e9e0..3829dfcc144a57ad7d221617bb0bf1cbf5764413 100644 (file)
@@ -80,6 +80,7 @@
 #include "dhcp.h"
 #include "if.h"
 #include "ipv4.h"
+#include "ipv4ll.h"
 #include "ipv6.h"
 #include "ipv6nd.h"
 
@@ -1335,7 +1336,8 @@ if_route(unsigned char cmd, const struct rt *rt)
 {
        struct nlmr nlm;
        int retval = 0;
-       struct dhcp_state *state;
+       const struct dhcp_state *state;
+       const struct ipv4ll_state *istate;
 
        memset(&nlm, 0, sizeof(nlm));
        nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
@@ -1356,14 +1358,18 @@ if_route(unsigned char cmd, const struct rt *rt)
        nlm.rt.rtm_family = AF_INET;
        nlm.rt.rtm_table = RT_TABLE_MAIN;
 
-       state = D_STATE(rt->iface);
+       state = D_CSTATE(rt->iface);
+       istate = IPV4LL_CSTATE(rt->iface);
        if (cmd == RTM_DELETE)
                nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
        else {
                /* We only change route metrics for kernel routes */
-               if (rt->dest.s_addr ==
+               if ((rt->dest.s_addr ==
                    (state->addr.s_addr & state->net.s_addr) &&
-                   rt->net.s_addr == state->net.s_addr)
+                   rt->net.s_addr == state->net.s_addr) ||
+                   (istate && rt->dest.s_addr ==
+                   (istate->addr.s_addr & inaddr_llmask.s_addr) &&
+                   rt->net.s_addr == inaddr_llmask.s_addr))
                        nlm.rt.rtm_protocol = RTPROT_KERNEL;
                else
                        nlm.rt.rtm_protocol = RTPROT_BOOT;
@@ -1383,7 +1389,8 @@ if_route(unsigned char cmd, const struct rt *rt)
            &rt->dest.s_addr, sizeof(rt->dest.s_addr));
        if (nlm.rt.rtm_protocol == RTPROT_KERNEL) {
                add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
-                   &state->addr.s_addr, sizeof(state->addr.s_addr));
+                   istate == NULL ? &state->addr.s_addr : &istate->addr.s_addr,
+                   sizeof(state->addr.s_addr));
        }
        /* If a host route then don't add the gateway */
        if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
diff --git a/ipv4.c b/ipv4.c
index 022c0e7845a84717333d84544fe48d264e2ad9c2..e0b29761454cfa36a4f1819765c8997bf4b8b5fb 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -443,7 +443,7 @@ nc_route(struct rt *ort, struct rt *nrt)
 #ifdef HAVE_ROUTE_METRIC
        /* With route metrics, we can safely add the new route before
         * deleting the old route. */
-       if (if_route(RTM_ADD, nrt)  == 0) {
+       if (if_route(RTM_ADD, nrt) == 0) {
                if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
                        logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m");
                return 0;
index 4815df4bb6ebc059f21939026872e38a9601c698..9952360ed896e22ba2496852b5dd9befea7307f2 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -45,8 +45,8 @@
 #include "ipv4ll.h"
 #include "script.h"
 
-static const struct in_addr inaddr_llmask = { HTONL(LINKLOCAL_MASK) };
-static const struct in_addr inaddr_llbcast = { HTONL(LINKLOCAL_BRDC) };
+const struct in_addr inaddr_llmask = { HTONL(LINKLOCAL_MASK) };
+const struct in_addr inaddr_llbcast = { HTONL(LINKLOCAL_BRDC) };
 
 static in_addr_t
 ipv4ll_pick_addr(const struct arp_state *astate)
@@ -189,6 +189,7 @@ ipv4ll_probed(struct arp_state *astate)
 #endif
        state->addr = astate->addr;
        timespecclear(&state->defend);
+       if_initrt(ifp);
        ipv4_buildroutes(ifp->ctx);
        arp_announce(astate);
        script_runreason(ifp, "IPV4LL");
index 4820c1437848464adb7375970836f0d250b40769..8fdf10b43c08ea38cf90f466a77bf37a38abce29 100644 (file)
--- a/ipv4ll.h
+++ b/ipv4ll.h
@@ -30,6 +30,9 @@
 
 #include "arp.h"
 
+extern const struct in_addr inaddr_llmask;
+extern const struct in_addr inaddr_llbcast;
+
 #define LINKLOCAL_ADDR 0xa9fe0000
 #define LINKLOCAL_MASK IN_CLASSB_NET
 #define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)