From: Roy Marples Date: Fri, 7 Aug 2015 08:49:07 +0000 (+0000) Subject: Add IPv4LL subnet routes like the kernel does. X-Git-Tag: v6.9.2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f3dae6c2057278ff9bdb1b4eec1afb386856385;p=thirdparty%2Fdhcpcd.git Add IPv4LL subnet routes like the kernel does. Build the routing table before applying routes, fixes [a3de5dcae1]. --- diff --git a/if-bsd.c b/if-bsd.c index f5ffe740..4a6a918f 100644 --- 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; diff --git a/if-linux.c b/if-linux.c index 59d8f134..3829dfcc 100644 --- a/if-linux.c +++ b/if-linux.c @@ -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 022c0e78..e0b29761 100644 --- 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; diff --git a/ipv4ll.c b/ipv4ll.c index 4815df4b..9952360e 100644 --- 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"); diff --git a/ipv4ll.h b/ipv4ll.h index 4820c143..8fdf10b4 100644 --- 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)