]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
If the IP address is still on the interface when reading a lease,
authorRoy Marples <roy@marples.name>
Wed, 26 Nov 2014 03:35:09 +0000 (03:35 +0000)
committerRoy Marples <roy@marples.name>
Wed, 26 Nov 2014 03:35:09 +0000 (03:35 +0000)
fake add the routes so the lease can be cleaned up if needed.

dhcp.c
ipv4.c
ipv4.h

diff --git a/dhcp.c b/dhcp.c
index ea7c0e1a2010dc4a1a8ee03b994877b66fa96a4f..95b56a89dc4e5506fec036bd2a06c717dd025901 100644 (file)
--- 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 ddb1c973a44dd3aba02b3b1cc4fd60d525346627..23ddb502992477e521c401286e9b00589879512f 100644 (file)
--- 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 5dbfc9cd7e7ad984e529f383b1c17352a1b8ae81..97294ce4fcad42e89e3a4f015dd863799341e248 100644 (file)
--- 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 *);