Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion hooks/dhcpcd-run-hooks.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd October 11, 2024
.Dd October 6, 2025
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
Expand Down Expand Up @@ -105,6 +105,8 @@ dhcpcd renewed its lease.
dhcpcd has rebound to a new DHCP server.
.It Dv REBOOT | Dv REBOOT6
dhcpcd successfully requested a lease from a DHCP server.
.It Dv RELEASE | Dv RELEASE6
dhcpcd has released the lease.
.It Dv DELEGATED6
dhcpcd assigned a delegated prefix to the interface.
.It Dv IPV4LL
Expand Down
96 changes: 66 additions & 30 deletions src/dhcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2866,6 +2866,51 @@ dhcp_reboot(struct interface *ifp)
send_request(ifp);
}

static void
dhcp_deconfigure(void *arg)
{
struct interface *ifp = arg;
struct dhcp_state *state = D_STATE(ifp);
struct if_options *ifo = ifp->options;
const char *reason;

#ifdef AUTH
dhcp_auth_reset(&state->auth);
#endif

if (state->state == DHS_RELEASE)
reason = "RELEASE";
else
reason = state->reason;
state->state = DHS_NONE;
free(state->offer);
state->offer = NULL;
state->offer_len = 0;
free(state->old);
state->old = state->new;
state->old_len = state->new_len;
state->new = NULL;
state->new_len = 0;
if (ifo->options & DHCPCD_CONFIGURE)
ipv4_applyaddr(ifp);
else {
state->addr = NULL;
state->added = 0;
}
script_runreason(ifp, reason);
free(state->old);
state->old = NULL;
state->old_len = 0;
state->lease.addr.s_addr = 0;
ifo->options &= ~(DHCPCD_CSR_WARNED | DHCPCD_ROUTER_HOST_ROUTE_WARNED);

if (ifo->options & DHCPCD_STOPPING) {
dhcp_free(ifp);
dhcpcd_dropped(ifp);
} else
dhcp_close(ifp);
}

void
dhcp_drop(struct interface *ifp, const char *reason)
{
Expand All @@ -2876,6 +2921,7 @@ dhcp_drop(struct interface *ifp, const char *reason)
* but we do have a timeout, so punt it. */
if (state == NULL || state->state == DHS_NONE) {
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcpcd_dropped(ifp);
return;
}

Expand All @@ -2886,6 +2932,7 @@ dhcp_drop(struct interface *ifp, const char *reason)
#ifdef ARPING
state->arping_index = -1;
#endif
state->reason = reason;

if (ifo->options & DHCPCD_RELEASE && !(ifo->options & DHCPCD_INFORM)) {
/* Failure to send the release may cause this function to
Expand All @@ -2899,10 +2946,21 @@ dhcp_drop(struct interface *ifp, const char *reason)
state->new != NULL &&
state->lease.server.s_addr != INADDR_ANY)
{
/* We need to delay removal of the IP address so the
* message can be sent.
* Unlike DHCPv6, there is no acknowledgement. */
const struct timespec delay = {
.tv_sec = 1,
};

loginfox("%s: releasing lease of %s",
ifp->name, inet_ntoa(state->lease.addr));
dhcp_new_xid(ifp);
send_message(ifp, DHCP_RELEASE, NULL);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_tv(ifp->ctx->eloop,
&delay, dhcp_deconfigure, ifp);
return;
}
}
#ifdef AUTH
Expand All @@ -2919,36 +2977,7 @@ dhcp_drop(struct interface *ifp, const char *reason)
#endif

eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
#ifdef AUTH
dhcp_auth_reset(&state->auth);
#endif

state->state = DHS_NONE;
free(state->offer);
state->offer = NULL;
state->offer_len = 0;
free(state->old);
state->old = state->new;
state->old_len = state->new_len;
state->new = NULL;
state->new_len = 0;
state->reason = reason;
if (ifo->options & DHCPCD_CONFIGURE)
ipv4_applyaddr(ifp);
else {
state->addr = NULL;
state->added = 0;
script_runreason(ifp, state->reason);
}
free(state->old);
state->old = NULL;
state->old_len = 0;
state->lease.addr.s_addr = 0;
ifo->options &= ~(DHCPCD_CSR_WARNED | DHCPCD_ROUTER_HOST_ROUTE_WARNED);

/* Close DHCP ports so a changed interface family is picked
* up by a new BPF state. */
dhcp_close(ifp);
dhcp_deconfigure(ifp);
}

static int
Expand Down Expand Up @@ -3108,6 +3137,12 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
#define IS_STATE_ACTIVE(s) ((s)-state != DHS_NONE && \
(s)->state != DHS_INIT && (s)->state != DHS_BOUND)

/* Don't do anything if the user hasn't configured it. */
if (ifp->active != IF_ACTIVE_USER ||
ifp->options->options & DHCPCD_STOPPING ||
!(ifp->options->options & DHCPCD_DHCP))
return;

if (bootp->op != BOOTREPLY) {
if (IS_STATE_ACTIVE(state))
logdebugx("%s: op (%d) is not BOOTREPLY",
Expand Down Expand Up @@ -3932,6 +3967,7 @@ dhcp_free(struct interface *ifp)
free(state->offer);
free(state->clientid);
free(state);
ifp->if_data[IF_DATA_DHCP] = NULL;
}

ctx = ifp->ctx;
Expand Down
24 changes: 13 additions & 11 deletions src/dhcp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -2110,29 +2110,25 @@ dhcp6_startrelease(struct interface *ifp)
struct dhcp6_state *state;

state = D6_STATE(ifp);
if (state->state != DH6S_BOUND)
if (state->state != DH6S_BOUND) {
dhcp6_finishrelease(ifp);
return;
}

state->state = DH6S_RELEASE;
state->RTC = 0;
state->IMD = REL_MAX_DELAY;
state->IRT = REL_TIMEOUT;
state->MRT = REL_MAX_RT;
/* MRC of REL_MAX_RC is optional in RFC 3315 18.1.6 */
#if 0
state->MRC = REL_MAX_RC;
state->MRCcallback = dhcp6_finishrelease;
#else
state->MRC = 0;
state->MRCcallback = NULL;
#endif

if (dhcp6_makemessage(ifp) == -1)
if (dhcp6_makemessage(ifp) == -1) {
logerr("%s: %s", __func__, ifp->name);
else {
dhcp6_sendrelease(ifp);
/* not much we can do apart from finish now */
dhcp6_finishrelease(ifp);
}
} else
dhcp6_sendrelease(ifp);
}

static int
Expand Down Expand Up @@ -3610,6 +3606,11 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
ifp->name, sfrom);
dhcp6_fail(ifp, true);
return;
case DH6S_RELEASE:
loginfox("%s: %s acknowledged RELEASE6",
ifp->name, sfrom);
dhcp6_finishrelease(ifp);
return;
default:
valid_op = false;
break;
Expand Down Expand Up @@ -4293,6 +4294,7 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
free(state);
ifp->if_data[IF_DATA_DHCP6] = NULL;
}
dhcpcd_dropped(ifp);

/* If we don't have any more DHCP6 enabled interfaces,
* close the global socket and release resources */
Expand Down
Loading
Loading