mirror of
https://github.com/NetworkConfiguration/dhcpcd.git
synced 2026-01-26 14:13:26 +00:00
Protocols will notify when dhcpcd can exit (#536)
* Protocols will notify when dhcpcd can exit DHCPv6 RELEASE requires the addresses to be dropped before a RELEASE message is sent. We now wait for an acknowledgement or a timeout before notifying that DHCPv6 has stopped for the interface. DHCPv4 RELEASE is the other way around, there is no acknowledgement. So we wait for 1 second after sending the message before removing the address and notifying DHCP has stopped for the interface. If we are not releasing then we notify dhcpcd that the protocol has stopped right away when we drop the lease. dhcpcd will exit once there are no running protocols for the interfaces. Fixes #513. Hopefully #535, #519 and #509 as well. Co-authored-by: Sime Zupanovic (EXT) <sime.zupanovic.ext@ericsson.com>
This commit is contained in:
parent
b573b9d87b
commit
665b573d47
@ -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
|
||||
@ -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
|
||||
|
||||
96
src/dhcp.c
96
src/dhcp.c
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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",
|
||||
@ -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;
|
||||
|
||||
24
src/dhcp6.c
24
src/dhcp6.c
@ -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
|
||||
@ -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;
|
||||
@ -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 */
|
||||
|
||||
140
src/dhcpcd.c
140
src/dhcpcd.c
@ -438,27 +438,62 @@ dhcpcd_drop(struct interface *ifp, int stop)
|
||||
dhcpcd_drop_af(ifp, stop, AF_UNSPEC);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_interface(struct interface *ifp, const char *reason)
|
||||
static bool
|
||||
dhcpcd_ifrunning(struct interface *ifp)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx;
|
||||
|
||||
ctx = ifp->ctx;
|
||||
loginfox("%s: removing interface", ifp->name);
|
||||
ifp->options->options |= DHCPCD_STOPPING;
|
||||
#ifdef INET
|
||||
if (D_CSTATE(ifp) != NULL)
|
||||
return true;
|
||||
#ifdef IPV4LL
|
||||
if (IPV4LL_CSTATE(ifp) != NULL)
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
if (D6_CSTATE(ifp) != NULL)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
dhcpcd_drop(ifp, 1);
|
||||
script_runreason(ifp, reason == NULL ? "STOPPED" : reason);
|
||||
void
|
||||
dhcpcd_dropped(struct interface *ifp)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = ifp->ctx;
|
||||
|
||||
/* Delete all timeouts for the interfaces */
|
||||
eloop_q_timeout_delete(ctx->eloop, ELOOP_QUEUE_ALL, NULL, ifp);
|
||||
if (ifp->options == NULL ||
|
||||
!(ifp->options->options & DHCPCD_STOPPING) ||
|
||||
dhcpcd_ifrunning(ifp))
|
||||
return;
|
||||
|
||||
/* De-activate the interface */
|
||||
ifp->active = IF_INACTIVE;
|
||||
ifp->options->options &= ~DHCPCD_STOPPING;
|
||||
if (ifp->active) {
|
||||
ifp->active = IF_INACTIVE;
|
||||
ifp->options->options &= ~DHCPCD_STOPPING;
|
||||
script_runreason(ifp, "STOPPED");
|
||||
}
|
||||
|
||||
if (!(ctx->options & (DHCPCD_MANAGER | DHCPCD_TEST)))
|
||||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
if (!(ctx->options & DHCPCD_EXITING))
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (dhcpcd_ifrunning(ifp))
|
||||
break;
|
||||
}
|
||||
|
||||
/* All interfaces have stopped, we can exit */
|
||||
if (ifp == NULL)
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_interface(struct interface *ifp)
|
||||
{
|
||||
|
||||
loginfox("%s: removing interface", ifp->name);
|
||||
ifp->options->options |= DHCPCD_STOPPING;
|
||||
dhcpcd_drop(ifp, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -744,6 +779,17 @@ dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags)
|
||||
ifp->carrier = carrier;
|
||||
ifp->flags = flags;
|
||||
|
||||
/*
|
||||
* Inactive interfaces may not have options, we so check the
|
||||
* global context if we are stopping or not.
|
||||
* This allows an active interface to stop even if dhcpcd is not.
|
||||
*/
|
||||
if (ifp->options != NULL) {
|
||||
if (ifp->options->options & DHCPCD_STOPPING)
|
||||
return;
|
||||
} else if (ifp->ctx->options & DHCPCD_EXITING)
|
||||
return;
|
||||
|
||||
if (!if_is_link_up(ifp)) {
|
||||
if (!ifp->active || (!was_link_up && !was_roaming))
|
||||
return;
|
||||
@ -1070,13 +1116,16 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
||||
}
|
||||
if (ifp->active) {
|
||||
logdebugx("%s: interface departed", ifp->name);
|
||||
stop_interface(ifp, "DEPARTED");
|
||||
stop_interface(ifp);
|
||||
}
|
||||
TAILQ_REMOVE(ctx->ifaces, ifp, next);
|
||||
if_free(ifp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->options & DHCPCD_EXITING)
|
||||
return 0;
|
||||
|
||||
ifs = if_discover(ctx, &ifaddrs, -1, UNCONST(argv));
|
||||
if (ifs == NULL) {
|
||||
logerr(__func__);
|
||||
@ -1378,14 +1427,15 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
stop_all_interfaces(struct dhcpcd_ctx *ctx, unsigned long long opts)
|
||||
{
|
||||
struct interface *ifp;
|
||||
bool anystopped = false;
|
||||
|
||||
ctx->options |= opts;
|
||||
if (ctx->ifaces == NULL)
|
||||
return;
|
||||
return anystopped;
|
||||
|
||||
if (ctx->options & DHCPCD_RELEASE)
|
||||
ctx->options &= ~DHCPCD_PERSISTENT;
|
||||
@ -1398,8 +1448,10 @@ stop_all_interfaces(struct dhcpcd_ctx *ctx, unsigned long long opts)
|
||||
if (ifp->options->options & DHCPCD_RELEASE)
|
||||
ifp->options->options &= ~DHCPCD_PERSISTENT;
|
||||
ifp->options->options |= DHCPCD_EXITING;
|
||||
stop_interface(ifp, NULL);
|
||||
anystopped = true;
|
||||
stop_interface(ifp);
|
||||
}
|
||||
return anystopped;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1437,7 +1489,6 @@ dhcpcd_renew(struct dhcpcd_ctx *ctx)
|
||||
|
||||
#ifdef USE_SIGNALS
|
||||
#define sigmsg "received %s, %s"
|
||||
static volatile bool dhcpcd_exiting = false;
|
||||
void
|
||||
dhcpcd_signal_cb(int sig, void *arg)
|
||||
{
|
||||
@ -1517,14 +1568,19 @@ dhcpcd_signal_cb(int sig, void *arg)
|
||||
* During teardown we don't want to process SIGTERM or SIGINT again,
|
||||
* as that could trigger memory issues.
|
||||
*/
|
||||
if (dhcpcd_exiting)
|
||||
if (ctx->options & DHCPCD_EXITING)
|
||||
return;
|
||||
|
||||
dhcpcd_exiting = true;
|
||||
if (!(ctx->options & DHCPCD_TEST))
|
||||
stop_all_interfaces(ctx, opts);
|
||||
ctx->options |= DHCPCD_EXITING;
|
||||
if (!(ctx->options & DHCPCD_TEST) &&
|
||||
stop_all_interfaces(ctx, opts))
|
||||
{
|
||||
/* We stopped something, we will exit once that is done. */
|
||||
eloop_exitallinners(exit_code);
|
||||
return;
|
||||
}
|
||||
|
||||
eloop_exitall(exit_code);
|
||||
dhcpcd_exiting = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1664,8 +1720,11 @@ dumperr:
|
||||
|
||||
if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) {
|
||||
if (oifind == argc && af == AF_UNSPEC) {
|
||||
stop_all_interfaces(ctx, opts);
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
ctx->options |= DHCPCD_EXITING;
|
||||
if (stop_all_interfaces(ctx, opts) == false)
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
/* We did stop an interface, it will notify us once
|
||||
* dropped so we can exit. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1695,7 +1754,7 @@ dumperr:
|
||||
if (af != AF_UNSPEC)
|
||||
dhcpcd_drop_af(ifp, 1, af);
|
||||
else
|
||||
stop_interface(ifp, NULL);
|
||||
stop_interface(ifp);
|
||||
ifo->options = orig_opts;
|
||||
}
|
||||
return 0;
|
||||
@ -1897,17 +1956,28 @@ dhcpcd_pidfile_timeout(void *arg)
|
||||
pid_t pid;
|
||||
|
||||
pid = pidfile_read(ctx->pidfile);
|
||||
|
||||
if(pid == -1)
|
||||
if (pid == -1)
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
else if (++ctx->duid_len >= 100) { /* overload duid_len */
|
||||
logerrx("pid %d failed to exit", (int)pid);
|
||||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
} else
|
||||
else
|
||||
eloop_timeout_add_msec(ctx->eloop, 100,
|
||||
dhcpcd_pidfile_timeout, ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcpcd_exit_timeout(void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
pid_t pid;
|
||||
|
||||
pid = pidfile_read(ctx->pidfile);
|
||||
if (pid == -1)
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
else {
|
||||
logwarnx("pid %lld failed to exit", (long long)pid);
|
||||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static int dup_null(int fd)
|
||||
{
|
||||
int fd_null = open(_PATH_DEVNULL, O_WRONLY);
|
||||
@ -2271,6 +2341,8 @@ printpidfile:
|
||||
/* Spin until it exits */
|
||||
loginfox("waiting for pid %d to exit", (int)pid);
|
||||
dhcpcd_pidfile_timeout(&ctx);
|
||||
eloop_timeout_add_sec(ctx.eloop, 50,
|
||||
dhcpcd_exit_timeout, &ctx);
|
||||
goto run_loop;
|
||||
}
|
||||
}
|
||||
@ -2723,7 +2795,7 @@ exit1:
|
||||
if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
|
||||
loginfox(PACKAGE " exited");
|
||||
#ifdef PRIVSEP
|
||||
if (ctx.ps_root != NULL && ps_root_stop(&ctx) == -1)
|
||||
if (ps_root_stop(&ctx) == -1)
|
||||
i = EXIT_FAILURE;
|
||||
eloop_free(ctx.ps_eloop);
|
||||
#endif
|
||||
|
||||
@ -267,6 +267,7 @@ void dhcpcd_handlecarrier(struct interface *, int, unsigned int);
|
||||
int dhcpcd_handleinterface(void *, int, const char *);
|
||||
void dhcpcd_handlehwaddr(struct interface *, uint16_t, const void *, uint8_t);
|
||||
void dhcpcd_dropinterface(struct interface *, const char *);
|
||||
void dhcpcd_dropped(struct interface *);
|
||||
int dhcpcd_selectprofile(struct interface *, const char *);
|
||||
|
||||
void dhcpcd_startinterface(void *);
|
||||
|
||||
71
src/eloop.c
71
src/eloop.c
@ -46,8 +46,13 @@
|
||||
#define KEVENT_N int
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#include <linux/version.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <poll.h>
|
||||
#define USE_EPOLL
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
#define HAVE_EPOLL_PWAIT2
|
||||
#endif
|
||||
#else
|
||||
#include <poll.h>
|
||||
#define USE_PPOLL
|
||||
@ -143,6 +148,9 @@ struct eloop {
|
||||
bool exitnow;
|
||||
bool events_need_setup;
|
||||
bool events_invalid;
|
||||
#ifdef HAVE_EPOLL_PWAIT2
|
||||
bool epoll_pwait2_nosys;
|
||||
#endif
|
||||
};
|
||||
|
||||
TAILQ_HEAD(eloop_head, eloop) eloops = TAILQ_HEAD_INITIALIZER(eloops);
|
||||
@ -617,6 +625,19 @@ eloop_exitall(int code)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
eloop_exitallinners(int code)
|
||||
{
|
||||
struct eloop *eloop;
|
||||
|
||||
TAILQ_FOREACH(eloop, &eloops, next) {
|
||||
if (eloop == TAILQ_FIRST(&eloops))
|
||||
continue;
|
||||
eloop->exitcode = code;
|
||||
eloop->exitnow = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_KQUEUE) || defined(USE_EPOLL)
|
||||
static int
|
||||
eloop_open(struct eloop *eloop)
|
||||
@ -924,24 +945,48 @@ eloop_run_kqueue(struct eloop *eloop, const struct timespec *ts)
|
||||
static int
|
||||
eloop_run_epoll(struct eloop *eloop, const struct timespec *ts)
|
||||
{
|
||||
int timeout, n, nn;
|
||||
int n, nn;
|
||||
struct epoll_event *epe;
|
||||
struct eloop_event *e;
|
||||
unsigned short events;
|
||||
|
||||
if (ts != NULL) {
|
||||
if (ts->tv_sec > INT_MAX / 1000 ||
|
||||
(ts->tv_sec == INT_MAX / 1000 &&
|
||||
((ts->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000)))
|
||||
timeout = INT_MAX;
|
||||
else
|
||||
timeout = (int)(ts->tv_sec * 1000 +
|
||||
(ts->tv_nsec + 999999) / 1000000);
|
||||
} else
|
||||
timeout = -1;
|
||||
/* epoll does not work with zero events */
|
||||
if (eloop->nfds == 0) {
|
||||
n = ppoll(NULL, 0, ts, &eloop->sigset);
|
||||
#ifdef HAVE_EPOLL_PWAIT2
|
||||
} else if (!eloop->epoll_pwait2_nosys) {
|
||||
/* Many linux distros are dumb in shipping newer
|
||||
* kernel headers than the target kernel they are using.
|
||||
* So we jump through this stupid hoop and have to write
|
||||
* more complex code. */
|
||||
n = epoll_pwait2(eloop->fd, eloop->fds, (int)eloop->nfds,
|
||||
ts, &eloop->sigset);
|
||||
if (n == -1 && errno == ENOSYS) {
|
||||
eloop->epoll_pwait2_nosys = true;
|
||||
goto epoll_pwait2_nosys;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
int timeout;
|
||||
|
||||
n = epoll_pwait(eloop->fd, eloop->fds, (int)eloop->nfds, timeout,
|
||||
&eloop->sigset);
|
||||
#ifdef HAVE_EPOLL_PWAIT2
|
||||
epoll_pwait2_nosys:
|
||||
#endif
|
||||
if (ts != NULL) {
|
||||
if (ts->tv_sec > INT_MAX / 1000 ||
|
||||
(ts->tv_sec == INT_MAX / 1000 &&
|
||||
((ts->tv_nsec + 999999) / 1000000 >
|
||||
INT_MAX % 1000000)))
|
||||
timeout = INT_MAX;
|
||||
else
|
||||
timeout = (int)(ts->tv_sec * 1000 +
|
||||
(ts->tv_nsec + 999999) / 1000000);
|
||||
} else
|
||||
timeout = -1;
|
||||
|
||||
n = epoll_pwait(eloop->fd, eloop->fds, (int)eloop->nfds,
|
||||
timeout, &eloop->sigset);
|
||||
}
|
||||
if (n == -1)
|
||||
return -1;
|
||||
|
||||
|
||||
@ -98,6 +98,7 @@ struct eloop *eloop_new_with_signals(struct eloop *);
|
||||
void eloop_free(struct eloop *);
|
||||
void eloop_exit(struct eloop *, int);
|
||||
void eloop_exitall(int);
|
||||
void eloop_exitallinners(int);
|
||||
int eloop_forked(struct eloop *, unsigned short);
|
||||
int eloop_start(struct eloop *);
|
||||
|
||||
|
||||
@ -448,10 +448,11 @@ ipv4ll_drop(struct interface *ifp)
|
||||
|
||||
assert(ifp != NULL);
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
ipv4ll_freearp(ifp);
|
||||
|
||||
if ((ifp->options->options & DHCPCD_NODROP) == DHCPCD_NODROP)
|
||||
return;
|
||||
goto free;
|
||||
|
||||
state = IPV4LL_STATE(ifp);
|
||||
if (state) {
|
||||
@ -481,6 +482,10 @@ ipv4ll_drop(struct interface *ifp)
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
script_runreason(ifp, "IPV4LL");
|
||||
}
|
||||
|
||||
free:
|
||||
ipv4ll_free(ifp);
|
||||
dhcpcd_dropped(ifp);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -1927,6 +1927,7 @@ ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
|
||||
|
||||
/* 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_IPV6))
|
||||
return;
|
||||
|
||||
|
||||
@ -325,6 +325,9 @@ static struct sock_filter ps_seccomp_filter[] = {
|
||||
#ifdef __NR_epoll_pwait
|
||||
SECCOMP_ALLOW(__NR_epoll_pwait),
|
||||
#endif
|
||||
#ifdef __NR_epoll_pwait2
|
||||
SECCOMP_ALLOW(__NR_epoll_pwait2),
|
||||
#endif
|
||||
#ifdef __NR_exit_group
|
||||
SECCOMP_ALLOW(__NR_exit_group),
|
||||
#endif
|
||||
|
||||
@ -760,7 +760,7 @@ ps_stopwait(struct dhcpcd_ctx *ctx)
|
||||
#endif
|
||||
|
||||
error = eloop_start(ctx->ps_eloop);
|
||||
if (error != EXIT_SUCCESS)
|
||||
if (error < 0)
|
||||
logerr("%s: eloop_start", __func__);
|
||||
|
||||
eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx);
|
||||
@ -1136,6 +1136,10 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
|
||||
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 };
|
||||
bool stop = false;
|
||||
|
||||
if (events & ELE_HANGUP) {
|
||||
len = 0;
|
||||
goto stop;
|
||||
}
|
||||
if (!(events & ELE_READ))
|
||||
logerrx("%s: unexpected event 0x%04x", __func__, events);
|
||||
|
||||
@ -1163,12 +1167,13 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
|
||||
}
|
||||
|
||||
if (stop) {
|
||||
stop:
|
||||
ctx->options |= DHCPCD_EXITING;
|
||||
#ifdef PRIVSEP_DEBUG
|
||||
logdebugx("process %d stopping", getpid());
|
||||
#endif
|
||||
ps_free(ctx);
|
||||
eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
eloop_exitall(len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return len;
|
||||
}
|
||||
dlen -= sizeof(psm.psm_hdr);
|
||||
|
||||
@ -824,7 +824,8 @@ rt_build(struct dhcpcd_ctx *ctx, int af)
|
||||
}
|
||||
|
||||
#ifdef BSD
|
||||
if (if_missfilter_apply(ctx) == -1 && errno != ENOTSUP)
|
||||
if (!(ctx->options & DHCPCD_EXITING) &&
|
||||
if_missfilter_apply(ctx) == -1 && errno != ENOTSUP)
|
||||
logerr("if_missfilter_apply");
|
||||
#endif
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user