From: Roy Marples Date: Wed, 26 Nov 2014 03:35:09 +0000 (+0000) Subject: If the IP address is still on the interface when reading a lease, X-Git-Tag: v6.6.3~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e604c2d788293d6abf158b7483f80d1e7af47685;p=thirdparty%2Fdhcpcd.git If the IP address is still on the interface when reading a lease, fake add the routes so the lease can be cleaned up if needed. --- diff --git a/dhcp.c b/dhcp.c index ea7c0e1a..95b56a89 100644 --- a/dhcp.c +++ b/dhcp.c @@ -2182,6 +2182,7 @@ dhcp_drop(struct interface *ifp, const char *reason) dhcp_auth_reset(&state->auth); dhcp_close(ifp); } + if (ifp->options->options & DHCPCD_RELEASE) { unlink(state->leasefile); if (ifp->carrier != LINK_DOWN && @@ -2200,6 +2201,7 @@ dhcp_drop(struct interface *ifp, const char *reason) #endif } } + free(state->old); state->old = state->new; state->new = NULL; @@ -3126,6 +3128,23 @@ dhcp_start1(void *arg) if (state->offer) { get_lease(ifp->ctx, &state->lease, state->offer); state->lease.frominfo = 1; + if (state->new == NULL && + ipv4_iffindaddr(ifp, &state->lease.addr, &state->lease.net)) + { + /* We still have the IP address from the last lease. + * Fake add the address and routes from it so the lease + * can be cleaned up. */ + state->new = malloc(sizeof(*state->new)); + if (state->new) { + memcpy(state->new, state->offer, + sizeof(*state->new)); + state->addr = state->lease.addr; + state->net = state->lease.net; + state->added |= STATE_ADDED | STATE_FAKE; + ipv4_buildroutes(ifp->ctx); + } else + syslog(LOG_ERR, "%s: %m", __func__); + } if (state->offer->cookie == 0) { if (state->offer->yiaddr == state->addr.s_addr) { free(state->offer); @@ -3145,6 +3164,8 @@ dhcp_start1(void *arg) free(state->offer); state->offer = NULL; state->lease.addr.s_addr = 0; + if (state->new) + dhcp_drop(ifp, "EXPIRE"); } else { l = (uint32_t)(now.tv_sec - st.st_mtime); state->lease.leasetime -= l; diff --git a/ipv4.c b/ipv4.c index ddb1c973..23ddb502 100644 --- a/ipv4.c +++ b/ipv4.c @@ -590,7 +590,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx) struct rt_head *nrs, *dnr; struct rt *or, *rt, *rtn; struct interface *ifp; - const struct dhcp_state *state; + const struct dhcp_state *state, *ostate; nrs = malloc(sizeof(*nrs)); if (nrs == NULL) { @@ -623,6 +623,11 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx) rt->src.s_addr = state->addr.s_addr; /* Do we already manage it? */ if ((or = find_route(ctx->ipv4_routes, rt, NULL))) { + if (state->added & STATE_FAKE) + continue; + ostate = D_CSTATE(or->iface); + if (ostate->added & STATE_FAKE) + goto remroute; if (or->iface != ifp || or->src.s_addr != state->addr.s_addr || rt->gate.s_addr != or->gate.s_addr || @@ -631,10 +636,12 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx) if (c_route(or, rt) != 0) continue; } +remroute: TAILQ_REMOVE(ctx->ipv4_routes, or, next); free(or); } else { - if (n_route(rt) != 0) + if (!(state->added & STATE_FAKE) && + n_route(rt) != 0) continue; } TAILQ_REMOVE(dnr, rt, next); @@ -786,7 +793,8 @@ ipv4_applyaddr(void *arg) } else { ipv4_addaddr(ifn, &nstate->lease); - nstate->added = 1; + nstate->added = + STATE_ADDED; } break; } @@ -863,7 +871,7 @@ ipv4_applyaddr(void *arg) state->addr.s_addr != 0) delete_address(ifp); - state->added = 1; + state->added = STATE_ADDED; state->defend = 0; state->addr.s_addr = lease->addr.s_addr; state->net.s_addr = lease->net.s_addr; diff --git a/ipv4.h b/ipv4.h index 5dbfc9cd..97294ce4 100644 --- a/ipv4.h +++ b/ipv4.h @@ -66,6 +66,9 @@ int inet_cidrtoaddr(int, struct in_addr *); uint32_t ipv4_getnetmask(uint32_t); int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *); +#define STATE_ADDED 0x01 +#define STATE_FAKE 0x02 + void ipv4_buildroutes(struct dhcpcd_ctx *); void ipv4_applyaddr(void *); int ipv4_routedeleted(struct dhcpcd_ctx *, const struct rt *);