From 5d619328bf07da0b6b209ce12f22381a4fe435e0 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Tue, 2 Feb 2021 14:41:54 +0000 Subject: [PATCH] eloop: Make the API more like native poll/kqueue/epoll Just have the one callback, but return an abstracted event mask to work out if we can read/write have something else. Log diagnostics if the event mask is unexpected. While here add more logging if we fail to register an event to monitor. --- src/arp.c | 12 +- src/control.c | 171 ++++++++++++-------- src/dhcp.c | 34 ++-- src/dhcp6.c | 42 ++--- src/dhcpcd.c | 66 +++++--- src/eloop.c | 359 +++++++++++++++++++----------------------- src/eloop.h | 25 ++- src/ipv6nd.c | 22 ++- src/privsep-bpf.c | 13 +- src/privsep-control.c | 24 ++- src/privsep-inet.c | 49 +++--- src/privsep-root.c | 31 ++-- src/privsep.c | 22 ++- src/privsep.h | 7 +- 14 files changed, 485 insertions(+), 392 deletions(-) diff --git a/src/arp.c b/src/arp.c index e8a27f42..5445e757 100644 --- a/src/arp.c +++ b/src/arp.c @@ -299,7 +299,7 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len, } static void -arp_read(void *arg) +arp_read(void *arg, unsigned short events) { struct arp_state *astate = arg; struct bpf *bpf = astate->bpf; @@ -308,6 +308,9 @@ arp_read(void *arg) ssize_t bytes; struct in_addr addr = astate->addr; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + /* Some RAW mechanisms are generic file descriptors, not sockets. * This means we have no kernel call to just get one packet, * so we have to process the entire buffer. */ @@ -532,7 +535,7 @@ arp_new(struct interface *ifp, const struct in_addr *addr) struct arp_state *astate; if ((state = ARP_STATE(ifp)) == NULL) { - ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state)); + ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state)); state = ARP_STATE(ifp); if (state == NULL) { logerr(__func__); @@ -567,8 +570,9 @@ arp_new(struct interface *ifp, const struct in_addr *addr) free(astate); return NULL; } - eloop_event_add(ifp->ctx->eloop, astate->bpf->bpf_fd, - arp_read, astate); + if (eloop_event_add(ifp->ctx->eloop, astate->bpf->bpf_fd, ELE_READ, + arp_read, astate) == -1) + logerr("%s: eloop_event_add", __func__); } diff --git a/src/control.c b/src/control.c index 92846511..ab75fe48 100644 --- a/src/control.c +++ b/src/control.c @@ -53,6 +53,8 @@ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #endif +static void control_handle_data(void *, unsigned short); + static void control_queue_free(struct fd_list *fd) { @@ -84,9 +86,10 @@ control_free(struct fd_list *fd) fd->ctx->ps_control_client = NULL; #endif - if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1 && - errno != ENOENT) - logerr(__func__); + /* Remove ELE_WRITE */ + if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ, + control_handle_data, fd) == -1) + logerr("%s: eloop_event_add", __func__); TAILQ_REMOVE(&fd->ctx->control_fds, fd, next); control_queue_free(fd); free(fd); @@ -107,9 +110,8 @@ control_delete(struct fd_list *fd) } static void -control_handle_data(void *arg) +control_handle_read(struct fd_list *fd) { - struct fd_list *fd = arg; char buffer[1024]; ssize_t bytes; @@ -145,6 +147,78 @@ control_handle_data(void *arg) control_recvdata(fd, buffer, (size_t)bytes); } +static void +control_handle_write(struct fd_list *fd) +{ + struct iovec iov[2]; + int iov_len; + struct fd_data *data; + + data = TAILQ_FIRST(&fd->queue); + + if (data->data_flags & FD_SENDLEN) { + iov[0].iov_base = &data->data_len; + iov[0].iov_len = sizeof(size_t); + iov[1].iov_base = data->data; + iov[1].iov_len = data->data_len; + iov_len = 2; + } else { + iov[0].iov_base = data->data; + iov[0].iov_len = data->data_len; + iov_len = 1; + } + + if (writev(fd->fd, iov, iov_len) == -1) { + logerr("%s: write", __func__); + control_delete(fd); + return; + } + + TAILQ_REMOVE(&fd->queue, data, next); +#ifdef CTL_FREE_LIST + TAILQ_INSERT_TAIL(&fd->free_queue, data, next); +#else + if (data->data_size != 0) + free(data->data); + free(data); +#endif + + if (TAILQ_FIRST(&fd->queue) != NULL) + return; + + /* Remove ELE_WRITE */ + if (fd->flags & FD_LISTEN) { + if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ, + control_handle_data, fd) == -1) + logerr("%s: eloop_event_add", __func__); + } else { + if (eloop_event_delete(fd->ctx->eloop, fd->fd) == -1) + logerr("%s: eloop_event_add", __func__); + } +#ifdef PRIVSEP + if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) { + if (ps_ctl_sendeof(fd) == -1) + logerr(__func__); + control_free(fd); + } +#endif +} + + +static void +control_handle_data(void *arg, unsigned short events) +{ + struct fd_list *fd = arg; + + if (events != ELE_READ && events != ELE_WRITE) + logerrx("%s: unexpected event 0x%04x", __func__, events); + + if (events & ELE_WRITE) + control_handle_write(fd); + if (events & ELE_READ) + control_handle_read(fd); +} + void control_recvdata(struct fd_list *fd, char *data, size_t len) { @@ -221,13 +295,17 @@ control_new(struct dhcpcd_ctx *ctx, int fd, unsigned int flags) } static void -control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags) +control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags, + unsigned short events) { struct sockaddr_un run; socklen_t len; struct fd_list *l; int fd, flags; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = sizeof(run); if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1) goto error; @@ -249,8 +327,9 @@ control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags) if (l == NULL) goto error; - if (eloop_event_add(ctx->eloop, l->fd, control_handle_data, l) == -1) - logerr(__func__); + if (eloop_event_add(ctx->eloop, l->fd, ELE_READ, + control_handle_data, l) == -1) + logerr("%s: eloop_event_add", __func__); return; error: @@ -260,19 +339,19 @@ error: } static void -control_handle(void *arg) +control_handle(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - control_handle1(ctx, ctx->control_fd, 0); + control_handle1(ctx, ctx->control_fd, 0, events); } static void -control_handle_unpriv(void *arg) +control_handle_unpriv(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV); + control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV, events); } static int @@ -381,11 +460,15 @@ control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family) return -1; ctx->control_fd = fd; - eloop_event_add(ctx->eloop, fd, control_handle, ctx); + if (eloop_event_add(ctx->eloop, fd, ELE_READ, + control_handle, ctx) == -1) + logerr("%s: eloop_event_add", __func__); if ((fd = control_start1(ctx, ifname, family, S_UNPRIV)) != -1) { ctx->control_unpriv_fd = fd; - eloop_event_add(ctx->eloop, fd, control_handle_unpriv, ctx); + if (eloop_event_add(ctx->eloop, fd, ELE_READ, + control_handle_unpriv, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } return ctx->control_fd; } @@ -490,62 +573,11 @@ control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv) return write(ctx->control_fd, buffer, len); } -static void -control_writeone(void *arg) -{ - struct fd_list *fd; - struct iovec iov[2]; - int iov_len; - struct fd_data *data; - - fd = arg; - data = TAILQ_FIRST(&fd->queue); - - if (data->data_flags & FD_SENDLEN) { - iov[0].iov_base = &data->data_len; - iov[0].iov_len = sizeof(size_t); - iov[1].iov_base = data->data; - iov[1].iov_len = data->data_len; - iov_len = 2; - } else { - iov[0].iov_base = data->data; - iov[0].iov_len = data->data_len; - iov_len = 1; - } - - if (writev(fd->fd, iov, iov_len) == -1) { - logerr("%s: write", __func__); - control_delete(fd); - return; - } - - TAILQ_REMOVE(&fd->queue, data, next); -#ifdef CTL_FREE_LIST - TAILQ_INSERT_TAIL(&fd->free_queue, data, next); -#else - if (data->data_size != 0) - free(data->data); - free(data); -#endif - - if (TAILQ_FIRST(&fd->queue) != NULL) - return; - - if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1) - logerr(__func__); -#ifdef PRIVSEP - if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) { - if (ps_ctl_sendeof(fd) == -1) - logerr(__func__); - control_free(fd); - } -#endif -} - int control_queue(struct fd_list *fd, void *data, size_t data_len) { struct fd_data *d; + unsigned short events; if (data_len == 0) { errno = EINVAL; @@ -590,6 +622,9 @@ control_queue(struct fd_list *fd, void *data, size_t data_len) d->data_flags = fd->flags & FD_SENDLEN; TAILQ_INSERT_TAIL(&fd->queue, d, next); - eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd); - return 0; + events = ELE_WRITE; + if (fd->flags & FD_LISTEN) + events |= ELE_READ; + return eloop_event_add(fd->ctx->eloop, fd->fd, events, + control_handle_data, fd); } diff --git a/src/dhcp.c b/src/dhcp.c index fdd926b7..5b1eb269 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -137,7 +137,7 @@ static void dhcp_arp_found(struct arp_state *, const struct arp_msg *); #endif static void dhcp_handledhcp(struct interface *, struct bootp *, size_t, const struct in_addr *); -static void dhcp_handleifudp(void *); +static void dhcp_handleifudp(void *, unsigned short); static int dhcp_initstate(struct interface *); void @@ -2406,7 +2406,9 @@ openudp: dhcp_openbpf(ifp); return; } - eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp); + if (eloop_event_add(ctx->eloop, state->udp_rfd, ELE_READ, + dhcp_handleifudp, ifp) == -1) + logerr("%s: eloop_event_add", __func__); } static size_t @@ -3622,7 +3624,7 @@ dhcp_packet(struct interface *ifp, uint8_t *data, size_t len, } static void -dhcp_readbpf(void *arg) +dhcp_readbpf(void *arg, unsigned short events) { struct interface *ifp = arg; uint8_t buf[FRAMELEN_MAX]; @@ -3630,6 +3632,9 @@ dhcp_readbpf(void *arg) struct dhcp_state *state = D_STATE(ifp); struct bpf *bpf = state->bpf; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + bpf->bpf_flags &= ~BPF_EOF; while (!(bpf->bpf_flags & BPF_EOF)) { bytes = bpf_read(bpf, buf, sizeof(buf)); @@ -3693,7 +3698,8 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) } static void -dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) +dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp, + unsigned short events) { const struct dhcp_state *state; struct sockaddr_in from; @@ -3721,6 +3727,9 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) int s; ssize_t bytes; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + if (ifp != NULL) { state = D_CSTATE(ifp); s = state->udp_rfd; @@ -3738,19 +3747,19 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) } static void -dhcp_handleudp(void *arg) +dhcp_handleudp(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - dhcp_readudp(ctx, NULL); + dhcp_readudp(ctx, NULL, events); } static void -dhcp_handleifudp(void *arg) +dhcp_handleifudp(void *arg, unsigned short events) { struct interface *ifp = arg; - dhcp_readudp(ifp->ctx, ifp); + dhcp_readudp(ifp->ctx, ifp, events); } static int @@ -3785,8 +3794,9 @@ dhcp_openbpf(struct interface *ifp) return -1; } - eloop_event_add(ifp->ctx->eloop, - state->bpf->bpf_fd, dhcp_readbpf, ifp); + if (eloop_event_add(ifp->ctx->eloop, state->bpf->bpf_fd, ELE_READ, + dhcp_readbpf, ifp) == -1) + logerr("%s: eloop_event_add", __func__); return 0; } @@ -3962,7 +3972,9 @@ dhcp_start1(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx); + if (eloop_event_add(ctx->eloop, ctx->udp_rfd, ELE_READ, + dhcp_handleudp, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) { ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP); diff --git a/src/dhcp6.c b/src/dhcp6.c index a7722f23..4fd119c5 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -173,7 +173,7 @@ static const char * const dhcp6_statuses[] = { static void dhcp6_bind(struct interface *, const char *, const char *); static void dhcp6_failinform(void *); -static void dhcp6_recvaddr(void *); +static void dhcp6_recvaddr(void *, unsigned short); static void dhcp6_startdecline(struct interface *); #ifdef SMALL @@ -2243,8 +2243,8 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, if (!(a->flags & IPV6_AF_DELEGATEDPFX)) a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX; a->flags &= ~(IPV6_AF_STALE | - IPV6_AF_EXTENDED | - IPV6_AF_REQUEST); + IPV6_AF_EXTENDED | + IPV6_AF_REQUEST); if (a->prefix_vltime != pdp.vltime) a->flags |= IPV6_AF_NEW; } @@ -2396,7 +2396,7 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l, logwarnx("%s: IAID %s T1(%d) > T2(%d) from %s", ifp->name, hwaddr_ntoa(iaid, sizeof(iaid), buf, - sizeof(buf)), + sizeof(buf)), ia.t1, ia.t2, sfrom); continue; } @@ -2829,7 +2829,7 @@ dhcp6_script_try_run(struct interface *ifp, int delegated) if (ap->flags & IPV6_AF_ONLINK) { if (!(ap->flags & IPV6_AF_DADCOMPLETED) && ipv6_iffindaddr(ap->iface, &ap->addr, - IN6_IFF_TENTATIVE)) + IN6_IFF_TENTATIVE)) ap->flags |= IPV6_AF_DADCOMPLETED; if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 #ifndef SMALL @@ -3073,7 +3073,7 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) if (state->reason == NULL) state->reason = "INFORM6"; o = dhcp6_findmoption(state->new, state->new_len, - D6_OPTION_INFO_REFRESH_TIME, &ol); + D6_OPTION_INFO_REFRESH_TIME, &ol); if (o == NULL || ol != sizeof(uint32_t)) state->renew = IRT_DEFAULT; else { @@ -3693,7 +3693,7 @@ recvif: } static void -dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) +dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia, unsigned short events) { struct sockaddr_in6 from; union { @@ -3715,6 +3715,9 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) int s; ssize_t bytes; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_rfd; bytes = recvmsg(s, &msg, 0); if (bytes == -1) { @@ -3727,19 +3730,20 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) } static void -dhcp6_recvaddr(void *arg) + +dhcp6_recvaddr(void *arg, unsigned short events) { struct ipv6_addr *ia = arg; - dhcp6_recv(ia->iface->ctx, ia); + dhcp6_recv(ia->iface->ctx, ia, events); } static void -dhcp6_recvctx(void *arg) +dhcp6_recvctx(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - dhcp6_recv(ctx, NULL); + dhcp6_recv(ctx, NULL, events); } int @@ -3860,7 +3864,9 @@ dhcp6_start1(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, dhcp6_recvctx, ctx); + if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ, + dhcp6_recvctx, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } if (!IN_PRIVSEP(ctx) && ctx->dhcp6_wfd == -1) { @@ -4172,13 +4178,13 @@ dhcp6_handleifa(int cmd, struct ipv6_addr *ia, pid_t pid) if (ia->dhcp6_fd == -1) ia->dhcp6_fd = dhcp6_openudp(ia->iface->index, &ia->addr); - if (ia->dhcp6_fd != -1) - eloop_event_add(ia->iface->ctx->eloop, - ia->dhcp6_fd, dhcp6_recvaddr, ia); + if (ia->dhcp6_fd != -1 && + eloop_event_add(ia->iface->ctx->eloop, + ia->dhcp6_fd, ELE_READ, dhcp6_recvaddr, ia) == -1) + logerr("%s: eloop_event_add", __func__); } } - if ((state = D6_STATE(ifp)) != NULL) ipv6_handleifa_addrs(cmd, &state->addrs, ia, pid); } @@ -4289,7 +4295,7 @@ dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp, delegated: #ifndef SMALL - /* Needed for Delegated Prefixes */ + /* Needed for Delegated Prefixes */ state = D6_CSTATE(ifp); TAILQ_FOREACH(ap, &state->addrs, next) { if (ap->delegating_prefix) @@ -4308,7 +4314,7 @@ delegated: } if (fprintf(fp, "%s", ap->saddr) == -1) return -1; - } + } if (fputc('\0', fp) == EOF) return -1; #endif diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 8b0e5e63..d23ce3fd 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -1110,10 +1110,13 @@ out: } static void -dhcpcd_handlelink(void *arg) +dhcpcd_handlelink(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + if (if_handlelink(ctx) == -1) { if (errno == ENOBUFS || errno == ENOMEM) { dhcpcd_linkoverflow(ctx); @@ -1648,15 +1651,18 @@ dumperr: return 0; } -static void dhcpcd_readdump1(void *); +static void dhcpcd_readdump1(void *, unsigned short); static void -dhcpcd_readdump2(void *arg) +dhcpcd_readdump2(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; int exit_code = EXIT_FAILURE; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, ctx->ctl_buf + ctx->ctl_bufpos, ctx->ctl_buflen - ctx->ctl_bufpos); if (len == -1) { @@ -1675,8 +1681,9 @@ dhcpcd_readdump2(void *arg) fflush(stdout); if (--ctx->ctl_extra != 0) { putchar('\n'); - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump1, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump1, ctx) == -1) + logerr("%s: eloop_event_add", __func__); return; } exit_code = EXIT_SUCCESS; @@ -1687,11 +1694,14 @@ finished: } static void -dhcpcd_readdump1(void *arg) +dhcpcd_readdump1(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, &ctx->ctl_buflen, sizeof(ctx->ctl_buflen)); if (len != sizeof(ctx->ctl_buflen)) { if (len != -1) @@ -1709,8 +1719,9 @@ dhcpcd_readdump1(void *arg) goto err; ctx->ctl_bufpos = 0; - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump2, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump2, ctx) == -1) + logerr("%s: eloop_event_add", __func__); return; err: @@ -1719,11 +1730,14 @@ err: } static void -dhcpcd_readdump0(void *arg) +dhcpcd_readdump0(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, &ctx->ctl_extra, sizeof(ctx->ctl_extra)); if (len != sizeof(ctx->ctl_extra)) { if (len != -1) @@ -1738,8 +1752,9 @@ dhcpcd_readdump0(void *arg) return; } - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump1, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump1, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } static void @@ -1759,17 +1774,20 @@ dhcpcd_readdump(struct dhcpcd_ctx *ctx) if (eloop_timeout_add_sec(ctx->eloop, 5, dhcpcd_readdumptimeout, ctx) == -1) return -1; - return eloop_event_add(ctx->eloop, ctx->control_fd, + return eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, dhcpcd_readdump0, ctx); } static void -dhcpcd_fork_cb(void *arg) +dhcpcd_fork_cb(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; int exit_code; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); if (len == -1) { logerr(__func__); @@ -1786,12 +1804,15 @@ dhcpcd_fork_cb(void *arg) } static void -dhcpcd_stderr_cb(void *arg) +dhcpcd_stderr_cb(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; char log[BUFSIZ]; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->stderr_fd, log, sizeof(log)); if (len == -1) { if (errno != ECONNRESET) @@ -2306,7 +2327,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ, + dhcpcd_fork_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); /* * Redirect stderr to the stderr socketpair. @@ -2354,7 +2377,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ, + dhcpcd_fork_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); if (ctx.stderr_valid) { ctx.stderr_fd = stderr_fd[0]; @@ -2365,8 +2390,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.stderr_fd, - dhcpcd_stderr_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.stderr_fd, ELE_READ, + dhcpcd_stderr_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); } #ifdef PRIVSEP if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) @@ -2448,7 +2474,9 @@ start_master: /* Start handling kernel messages for interfaces, addresses and * routes. */ - eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); + if (eloop_event_add(ctx.eloop, ctx.link_fd, ELE_READ, + dhcpcd_handlelink, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); #ifdef PRIVSEP if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1) diff --git a/src/eloop.c b/src/eloop.c index 16f1b05d..ab8d289c 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -30,10 +30,12 @@ * Basically for a small number of fd's (total, not max fd) * of say a few hundred, ppoll(2) performs just fine, if not faster than others. * It also has the smallest memory and binary size footprint. - * ppoll(2) is available on all modern OS my software runs on. + * ppoll(2) is available on all modern OS my software runs on and should be + * an up and coming POSIX standard interface. * If ppoll is not available, then pselect(2) can be used instead which has * even smaller memory and binary size footprint. * However, this difference is quite tiny and the ppoll API is superior. + * pselect cannot return error conditions such as EOF for example. * * Both epoll(7) and kqueue(2) require an extra fd per process to manage * their respective list of interest AND syscalls to manage it. @@ -175,10 +177,9 @@ struct eloop_event { TAILQ_ENTRY(eloop_event) next; int fd; - void (*read_cb)(void *); - void *read_cb_arg; - void (*write_cb)(void *); - void *write_cb_arg; + void (*cb)(void *, unsigned short); + void *cb_arg; + unsigned short events; #ifdef HAVE_PPOLL struct pollfd *pollfd; #endif @@ -245,73 +246,6 @@ eloop_realloca(void *ptr, size_t n, size_t size) } #endif -unsigned long long -eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp, - unsigned int *nsp) -{ - unsigned long long tsecs, usecs, secs; - long nsecs; - - if (tsp->tv_sec < 0) /* time wreapped */ - tsecs = UTIME_MAX - (unsigned long long)(-tsp->tv_sec); - else - tsecs = (unsigned long long)tsp->tv_sec; - if (usp->tv_sec < 0) /* time wrapped */ - usecs = UTIME_MAX - (unsigned long long)(-usp->tv_sec); - else - usecs = (unsigned long long)usp->tv_sec; - - if (usecs > tsecs) /* time wrapped */ - secs = (UTIME_MAX - usecs) + tsecs; - else - secs = tsecs - usecs; - - nsecs = tsp->tv_nsec - usp->tv_nsec; - if (nsecs < 0) { - if (secs == 0) - nsecs = 0; - else { - secs--; - nsecs += NSEC_PER_SEC; - } - } - if (nsp != NULL) - *nsp = (unsigned int)nsecs; - return secs; -} - -static void -eloop_reduce_timers(struct eloop *eloop) -{ - struct timespec now; - unsigned long long secs; - unsigned int nsecs; - struct eloop_timeout *t; - - clock_gettime(CLOCK_MONOTONIC, &now); - secs = eloop_timespec_diff(&now, &eloop->now, &nsecs); - - TAILQ_FOREACH(t, &eloop->timeouts, next) { - if (secs > t->seconds) { - t->seconds = 0; - t->nseconds = 0; - } else { - t->seconds -= (unsigned int)secs; - if (nsecs > t->nseconds) { - if (t->seconds == 0) - t->nseconds = 0; - else { - t->seconds--; - t->nseconds = NSEC_PER_SEC - - (nsecs - t->nseconds); - } - } else - t->nseconds -= nsecs; - } - } - - eloop->now = now; -} static int eloop_event_setup_fds(struct eloop *eloop) @@ -348,17 +282,13 @@ eloop_event_setup_fds(struct eloop *eloop) TAILQ_INSERT_TAIL(&eloop->free_events, e, next); continue; } -#ifdef ELOOP_DEBUG - fprintf(stderr, "%s(%d) fd=%d, rcb=%p, wcb=%p\n", - __func__, getpid(), e->fd, e->read_cb, e->write_cb); -#endif #ifdef HAVE_PPOLL e->pollfd = pfd; pfd->fd = e->fd; pfd->events = 0; - if (e->read_cb != NULL) + if (e->events & ELE_READ) pfd->events |= POLLIN; - if (e->write_cb != NULL) + if (e->events & ELE_WRITE) pfd->events |= POLLOUT; pfd->revents = 0; pfd++; @@ -377,14 +307,13 @@ eloop_event_count(const struct eloop *eloop) } int -eloop_event_add_rw(struct eloop *eloop, int fd, - void (*read_cb)(void *), void *read_cb_arg, - void (*write_cb)(void *), void *write_cb_arg) +eloop_event_add(struct eloop *eloop, int fd, unsigned short events, + void (*cb)(void *, unsigned short), void *cb_arg) { struct eloop_event *e; bool added; #if defined(HAVE_KQUEUE) - struct kevent ke[2]; + struct kevent ke[2], *kep = &ke[0]; size_t n; #elif defined(HAVE_EPOLL) struct epoll_event epe; @@ -392,8 +321,8 @@ eloop_event_add_rw(struct eloop *eloop, int fd, #endif assert(eloop != NULL); - assert(read_cb != NULL || write_cb != NULL); - if (fd == -1) { + assert(cb != NULL && cb_arg != NULL); + if (fd == -1 || !(events & (ELE_READ | ELE_WRITE))) { errno = EINVAL; return -1; } @@ -417,32 +346,28 @@ eloop_event_add_rw(struct eloop *eloop, int fd, TAILQ_INSERT_HEAD(&eloop->events, e, next); eloop->nevents++; e->fd = fd; - e->read_cb = read_cb; - e->read_cb_arg = read_cb_arg; - e->write_cb = write_cb; - e->write_cb_arg = write_cb_arg; - goto setup; + e->events = 0; } else added = false; - if (read_cb != NULL) { - e->read_cb = read_cb; - e->read_cb_arg = read_cb_arg; - } - if (write_cb != NULL) { - e->write_cb = write_cb; - e->write_cb_arg = write_cb_arg; - } + e->cb = cb; + e->cb_arg = cb_arg; -setup: #if defined(HAVE_KQUEUE) - EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, e); - if (e->write_cb != NULL) { - EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE, EV_ADD, 0, 0, e); - n = 2; - } else - n = 1; - if (_kevent(eloop->fd, ke, n, NULL, 0, NULL) == -1) { + n = 2; + if (events & ELE_READ && !(e->events & ELE_READ)) + EV_SET(kep++, (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, e); + else if (!(events & ELE_READ) && e->events & ELE_READ) + EV_SET(kep++, (uintptr_t)fd, EVFILT_READ, EV_DELETE, 0, 0, e); + else + n--; + if (events & ELE_WRITE && !(e->events & ELE_WRITE)) + EV_SET(kep++, (uintptr_t)fd, EVFILT_WRITE, EV_ADD, 0, 0, e); + else if (!(events & ELE_WRITE) && e->events & ELE_WRITE) + EV_SET(kep++, (uintptr_t)fd, EVFILT_WRITE, EV_DELETE, 0, 0, e); + else + n--; + if (n != 0 && _kevent(eloop->fd, ke, n, NULL, 0, NULL) == -1) { if (added) { TAILQ_REMOVE(&eloop->events, e, next); TAILQ_INSERT_TAIL(&eloop->free_events, e, next); @@ -452,9 +377,9 @@ setup: #elif defined(HAVE_EPOLL) memset(&epe, 0, sizeof(epe)); epe.data.ptr = e; - if (e->read_cb != NULL) + if (e->events & ELE_READ) epe.events |= EPOLLIN; - if (e->write_cb != NULL) + if (e->events & ELE_WRITE) epe.events |= EPOLLOUT; op = added ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; @@ -471,32 +396,15 @@ setup: #else UNUSED(added); #endif + e->events = events; eloop->events_need_setup = true; return 0; } int -eloop_event_add(struct eloop *eloop, int fd, - void (*read_cb)(void *), void *read_cb_arg) -{ - - return eloop_event_add_rw(eloop, fd, read_cb, read_cb_arg, NULL, NULL); -} - -int -eloop_event_add_w(struct eloop *eloop, int fd, - void (*write_cb)(void *), void *write_cb_arg) -{ - - return eloop_event_add_rw(eloop, fd, NULL,NULL, write_cb, write_cb_arg); -} - -int -eloop_event_delete_write(struct eloop *eloop, int fd, int write_only) +eloop_event_delete(struct eloop *eloop, int fd) { struct eloop_event *e; -#ifdef HAVE_KQUEUE -#endif assert(eloop != NULL); if (fd == -1) { @@ -513,44 +421,78 @@ eloop_event_delete_write(struct eloop *eloop, int fd, int write_only) return -1; } - if (write_only) { -#if defined(HAVE_KQUEUE) - if (e->write_cb != NULL) { - struct kevent ke; + e->fd = -1; + eloop->nevents--; + eloop->events_need_setup = true; + return 1; +} - EV_SET(&ke, (uintptr_t)e->fd, - EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (_kevent(eloop->fd, &ke, 1, NULL, 0, NULL) == -1) - return -1; - } -#elif defined(HAVE_EPOLL) - if (e->write_cb != NULL) { - struct epoll_event epe; - - memset(&epe, 0, sizeof(epe)); - epe.data.ptr = e; - if (e->read_cb != NULL) - epe.events |= EPOLLIN; - if (epoll_ctl(eloop->fd, - e->read_cb != NULL ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, - e->fd, &epe) == -1) - return -1; +unsigned long long +eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp, + unsigned int *nsp) +{ + unsigned long long tsecs, usecs, secs; + long nsecs; + + if (tsp->tv_sec < 0) /* time wreapped */ + tsecs = UTIME_MAX - (unsigned long long)(-tsp->tv_sec); + else + tsecs = (unsigned long long)tsp->tv_sec; + if (usp->tv_sec < 0) /* time wrapped */ + usecs = UTIME_MAX - (unsigned long long)(-usp->tv_sec); + else + usecs = (unsigned long long)usp->tv_sec; + + if (usecs > tsecs) /* time wrapped */ + secs = (UTIME_MAX - usecs) + tsecs; + else + secs = tsecs - usecs; + + nsecs = tsp->tv_nsec - usp->tv_nsec; + if (nsecs < 0) { + if (secs == 0) + nsecs = 0; + else { + secs--; + nsecs += NSEC_PER_SEC; } -#elif defined(HAVE_PPOLL) - if (e->pollfd != NULL) { - e->pollfd->events &= ~POLLOUT; - e->pollfd->revents &= ~POLLOUT; + } + if (nsp != NULL) + *nsp = (unsigned int)nsecs; + return secs; +} + +static void +eloop_reduce_timers(struct eloop *eloop) +{ + struct timespec now; + unsigned long long secs; + unsigned int nsecs; + struct eloop_timeout *t; + + clock_gettime(CLOCK_MONOTONIC, &now); + secs = eloop_timespec_diff(&now, &eloop->now, &nsecs); + + TAILQ_FOREACH(t, &eloop->timeouts, next) { + if (secs > t->seconds) { + t->seconds = 0; + t->nseconds = 0; + } else { + t->seconds -= (unsigned int)secs; + if (nsecs > t->nseconds) { + if (t->seconds == 0) + t->nseconds = 0; + else { + t->seconds--; + t->nseconds = NSEC_PER_SEC + - (nsecs - t->nseconds); + } + } else + t->nseconds -= nsecs; } -#endif - e->write_cb = NULL; - e->write_cb_arg = NULL; - return 0; } - e->fd = -1; - eloop->nevents--; - eloop->events_need_setup = true; - return 1; + eloop->now = now; } /* @@ -734,12 +676,12 @@ eloop_forked(struct eloop *eloop) if (e->fd == -1) continue; #if defined(HAVE_KQUEUE) - if (e->read_cb != NULL) { + if (e->events & ELE_READ) { EV_SET(pfd++, (uintptr_t)e->fd, EVFILT_READ, EV_ADD, 0, 0, e); i++; } - if (e->write_cb != NULL) { + if (e->events & ELE_WRITE) { EV_SET(pfd++, (uintptr_t)e->fd, EVFILT_WRITE, EV_ADD, 0, 0, e); i++; @@ -1006,6 +948,7 @@ eloop_run_kqueue(struct eloop *eloop, const struct timespec *ts) int n, nn; struct kevent *ke; struct eloop_event *e; + unsigned short events; n = _kevent(eloop->fd, NULL, 0, eloop->fds, eloop->nevents, ts); if (n == -1) @@ -1015,25 +958,22 @@ eloop_run_kqueue(struct eloop *eloop, const struct timespec *ts) if (eloop->cleared) break; e = (struct eloop_event *)ke->udata; -#if 0 - /* What to do with this? - * Currently we behave like ppoll and just try the - * socket and get the error there. */ - if (ke->flags & EV_ERROR) - errno = (int)ke->data; -#endif - switch (ke->filter) { - case EVFILT_SIGNAL: + if (ke->filter == EVFILT_SIGNAL) { eloop->signal_cb((int)ke->ident, eloop->signal_cb_ctx); - break; - case EVFILT_WRITE: - e->write_cb(e->write_cb_arg); - break; - case EVFILT_READ: - e->read_cb(e->read_cb_arg); - break; + continue; } + if (ke->filter == EVFILT_READ) + events = ELE_READ; + else if (ke->filter == EVFILT_WRITE) + events = ELE_WRITE; + else + continue; /* assert? */ + if (ke->flags & EV_EOF) + events |= ELE_HANGUP; + if (ke->flags & EV_ERROR) + events |= ELE_ERROR; + e->cb(e->cb_arg, events); } return n; } @@ -1047,6 +987,7 @@ eloop_run_epoll(struct eloop *eloop, int timeout, n, nn; struct epoll_event *epe; struct eloop_event *e; + unsigned short events; if (ts != NULL) { if (ts->tv_sec > INT_MAX / 1000 || @@ -1072,12 +1013,18 @@ eloop_run_epoll(struct eloop *eloop, if (eloop->cleared) break; e = (struct eloop_event *)epe->data.ptr; - if (epe->events & EPOLLOUT && - e->fd != -1 && e->write_cb != NULL) - e->write_cb(e->write_cb_arg); - if (epe->events & (EPOLLIN | EPOLLERR | EPOLLHUP) && - e->fd != -1 && e->read_cb != NULL) - e->read_cb(e->read_cb_arg); + if (e->fd == -1) + continue; + events = 0; + if (epe->events & EPOLLIN) + events |= ELE_READ; + if (epe->events & EPOLLOUT) + events |= ELE_WRITE; + if (epe->events & EPOLLHUP) + events |= ELE_HANGUP; + if (epe->events & EPOLLERR) + events |= ELE_ERROR; + e->cb(e->cb_arg, events); } return n; } @@ -1090,6 +1037,8 @@ eloop_run_ppoll(struct eloop *eloop, { int n, nn; struct eloop_event *e; + struct pollfd *pfd; + unsigned short events; n = ppoll(eloop->fds, (nfds_t)eloop->nevents, ts, signals); if (n == -1 || n == 0) @@ -1100,17 +1049,24 @@ eloop_run_ppoll(struct eloop *eloop, if (eloop->cleared) break; /* Skip freshly added events */ - if (e->pollfd == NULL) + if ((pfd = e->pollfd) == NULL) continue; - if (e->pollfd->revents) + if (e->pollfd->revents) { nn--; - if (e->fd != -1 && e->pollfd->revents & POLLOUT && - e->write_cb != NULL) - e->write_cb(e->write_cb_arg); - if (e->fd != -1 && - e->pollfd != NULL && e->pollfd->revents && - e->read_cb != NULL) - e->read_cb(e->read_cb_arg); + events = 0; + if (pfd->revents & POLLIN) + events |= ELE_READ; + if (pfd->revents & POLLOUT) + events |= ELE_WRITE; + if (pfd->revents & POLLHUP) + events |= ELE_HANGUP; + if (pfd->revents & POLLERR) + events |= ELE_ERROR; + if (pfd->revents & POLLNVAL) + events |= ELE_NVAL; + if (events) + e->cb(e->cb_arg, events); + } if (nn == 0) break; } @@ -1126,6 +1082,7 @@ eloop_run_pselect(struct eloop *eloop, fd_set read_fds, write_fds; int maxfd, n; struct eloop_event *e; + unsigned short events; FD_ZERO(&read_fds); FD_ZERO(&write_fds); @@ -1133,18 +1090,19 @@ eloop_run_pselect(struct eloop *eloop, TAILQ_FOREACH(e, &eloop->events, next) { if (e->fd == -1) continue; - if (e->read_cb != NULL) { + if (e->events & ELE_READ) { FD_SET(e->fd, &read_fds); if (e->fd > maxfd) maxfd = e->fd; } - if (e->write_cb != NULL) { + if (e->events & ELE_WRITE) { FD_SET(e->fd, &write_fds); if (e->fd > maxfd) maxfd = e->fd; } } + /* except_fd's is for STREAMS devices which we don't use. */ n = pselect(maxfd + 1, &read_fds, &write_fds, NULL, ts, sigmask); if (n == -1 || n == 0) return n; @@ -1154,10 +1112,13 @@ eloop_run_pselect(struct eloop *eloop, break; if (e->fd == -1) continue; - if (e->write_cb != NULL && FD_ISSET(e->fd, &write_fds)) - e->write_cb(e->write_cb_arg); - if (e->read_cb != NULL && FD_ISSET(e->fd, &read_fds)) - e->read_cb(e->read_cb_arg); + events = 0; + if (FD_ISSET(e->fd, &read_fds)) + events |= ELE_READ; + if (FD_ISSET(e->fd, &write_fds)) + events |= ELE_WRITE; + if (events) + e->cb(e->cb_arg, events); } return n; @@ -1172,7 +1133,7 @@ eloop_start(struct eloop *eloop, sigset_t *signals) struct timespec ts, *tsp; assert(eloop != NULL); -#if defined(HAVE_KQUEUE) +#ifdef HAVE_KQUEUE UNUSED(signals); #endif diff --git a/src/eloop.h b/src/eloop.h index a86d825c..27f95bae 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -52,22 +52,19 @@ /* Forward declare eloop - the content should be invisible to the outside */ struct eloop; -unsigned long long eloop_timespec_diff(const struct timespec *tsp, - const struct timespec *usp, unsigned int *nsp); +#define ELE_READ 0x0001 +#define ELE_WRITE 0x0002 +#define ELE_ERROR 0x0100 +#define ELE_HANGUP 0x0200 +#define ELE_NVAL 0x0400 + size_t eloop_event_count(const struct eloop *); -int eloop_event_add_rw(struct eloop *, int, - void (*)(void *), void *, - void (*)(void *), void *); -int eloop_event_add(struct eloop *, int, - void (*)(void *), void *); -int eloop_event_add_w(struct eloop *, int, - void (*)(void *), void *); -#define eloop_event_delete(eloop, fd) \ - eloop_event_delete_write((eloop), (fd), 0) -#define eloop_event_remove_writecb(eloop, fd) \ - eloop_event_delete_write((eloop), (fd), 1) -int eloop_event_delete_write(struct eloop *, int, int); +int eloop_event_add(struct eloop *, int, unsigned short, + void (*)(void *, unsigned short), void *); +int eloop_event_delete(struct eloop *, int); +unsigned long long eloop_timespec_diff(const struct timespec *tsp, + const struct timespec *usp, unsigned int *nsp); #define eloop_timeout_add_tv(eloop, tv, cb, ctx) \ eloop_q_timeout_add_tv((eloop), ELOOP_QUEUE, (tv), (cb), (ctx)) #define eloop_timeout_add_sec(eloop, tv, cb, ctx) \ diff --git a/src/ipv6nd.c b/src/ipv6nd.c index b0174a77..4b9c735d 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -78,7 +78,7 @@ struct nd_opt_rdnss { /* RDNSS option RFC 6106 */ uint8_t nd_opt_rdnss_len; uint16_t nd_opt_rdnss_reserved; uint32_t nd_opt_rdnss_lifetime; - /* followed by list of IP prefixes */ + /* followed by list of IP prefixes */ }; __CTASSERT(sizeof(struct nd_opt_rdnss) == 8); #endif @@ -131,7 +131,7 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) == 8); //#define DEBUG_NS // -static void ipv6nd_handledata(void *); +static void ipv6nd_handledata(void *, unsigned short); /* * Android ships buggy ICMP6 filter headers. @@ -281,8 +281,14 @@ ipv6nd_openif(struct interface *ifp) return -1; } + if (eloop_event_add(ifp->ctx->eloop, fd, ELE_READ, + ipv6nd_handledata, ifp) == -1) + { + close(fd); + return -1; + } + state->nd_fd = fd; - eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp); return fd; } #endif @@ -388,7 +394,9 @@ ipv6nd_sendrsprobe(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx); + if (eloop_event_add(ctx->eloop, ctx->nd_fd, ELE_READ, + ipv6nd_handledata, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } s = ifp->ctx->nd_fd; #endif @@ -1977,7 +1985,7 @@ ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) } static void -ipv6nd_handledata(void *arg) +ipv6nd_handledata(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx; int fd; @@ -2013,6 +2021,10 @@ ipv6nd_handledata(void *arg) ctx = arg; fd = ctx->nd_fd; #endif + + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = recvmsg(fd, &msg, 0); if (len == -1) { logerr(__func__); diff --git a/src/privsep-bpf.c b/src/privsep-bpf.c index f402ea18..f0088568 100644 --- a/src/privsep-bpf.c +++ b/src/privsep-bpf.c @@ -54,7 +54,7 @@ #include "privsep.h" static void -ps_bpf_recvbpf(void *arg) +ps_bpf_recvbpf(void *arg, unsigned short events) { struct ps_process *psp = arg; struct bpf *bpf = psp->psp_bpf; @@ -65,6 +65,9 @@ ps_bpf_recvbpf(void *arg) .ps_cmd = psp->psp_id.psi_cmd, }; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + bpf->bpf_flags &= ~BPF_EOF; /* A BPF read can read more than one filtered packet at time. * This mechanism allows us to read each packet from the buffer. */ @@ -131,11 +134,11 @@ ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) } static void -ps_bpf_recvmsg(void *arg) +ps_bpf_recvmsg(void *arg, unsigned short events) { struct ps_process *psp = arg; - if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, + if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, ps_bpf_recvmsgcb, arg) == -1) logerr(__func__); } @@ -164,8 +167,8 @@ ps_bpf_start_bpf(void *arg) else if (ps_rights_limit_fd(psp->psp_bpf->bpf_fd) == -1) logerr("%s: ps_rights_limit_fd", __func__); #endif - else if (eloop_event_add(ctx->eloop, - psp->psp_bpf->bpf_fd, ps_bpf_recvbpf, psp) == -1) + else if (eloop_event_add(ctx->eloop, psp->psp_bpf->bpf_fd, ELE_READ, + ps_bpf_recvbpf, psp) == -1) logerr("%s: eloop_event_add", __func__); else { psp->psp_work_fd = psp->psp_bpf->bpf_fd; diff --git a/src/privsep-control.c b/src/privsep-control.c index f5f8cfdd..389c5ad2 100644 --- a/src/privsep-control.c +++ b/src/privsep-control.c @@ -82,11 +82,12 @@ ps_ctl_recvmsgcb(void *arg, struct ps_msghdr *psm, __unused struct msghdr *msg) } static void -ps_ctl_recvmsg(void *arg) +ps_ctl_recvmsg(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvpsmsg(ctx, ctx->ps_control_fd, ps_ctl_recvmsgcb, ctx) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_control_fd, events, + ps_ctl_recvmsgcb, ctx) == -1) logerr(__func__); } @@ -161,21 +162,25 @@ ps_ctl_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg) } static void -ps_ctl_dodispatch(void *arg) +ps_ctl_dodispatch(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvpsmsg(ctx, ctx->ps_control_fd, ps_ctl_dispatch, ctx) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_control_fd, events, + ps_ctl_dispatch, ctx) == -1) logerr(__func__); } static void -ps_ctl_recv(void *arg) +ps_ctl_recv(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; char buf[BUFSIZ]; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + errno = 0; len = read(ctx->ps_control_data_fd, buf, sizeof(buf)); if (len == -1 || len == 0) { @@ -191,13 +196,16 @@ ps_ctl_recv(void *arg) } static void -ps_ctl_listen(void *arg) +ps_ctl_listen(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; char buf[BUFSIZ]; ssize_t len; struct fd_list *fd; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + errno = 0; len = read(ctx->ps_control->fd, buf, sizeof(buf)); if (len == -1 || len == 0) { @@ -250,7 +258,7 @@ ps_ctl_start(struct dhcpcd_ctx *ctx) ctx->ps_control_data_fd = data_fd[0]; close(data_fd[1]); - if (eloop_event_add(ctx->eloop, ctx->ps_control_data_fd, + if (eloop_event_add(ctx->eloop, ctx->ps_control_data_fd, ELE_READ, ps_ctl_recv, ctx) == -1) return -1; @@ -259,7 +267,7 @@ ps_ctl_start(struct dhcpcd_ctx *ctx) close(listen_fd[1]); if (ctx->ps_control == NULL) return -1; - if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, + if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, ELE_READ, ps_ctl_listen, ctx) == -1) return -1; diff --git a/src/privsep-inet.c b/src/privsep-inet.c index b98e19ad..bad4ea10 100644 --- a/src/privsep-inet.c +++ b/src/privsep-inet.c @@ -49,30 +49,33 @@ #ifdef INET static void -ps_inet_recvbootp(void *arg) +ps_inet_recvbootp(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvmsg(ctx, ctx->udp_rfd, PS_BOOTP, ctx->ps_inet_fd) == -1) + if (ps_recvmsg(ctx, ctx->udp_rfd, events, + PS_BOOTP, ctx->ps_inet_fd) == -1) logerr(__func__); } #endif #ifdef INET6 static void -ps_inet_recvra(void *arg) +ps_inet_recvra(void *arg, unsigned short events) { #ifdef __sun struct interface *ifp = arg; struct rs_state *state = RS_STATE(ifp); struct dhcpcd_ctx *ctx = ifp->ctx; - if (ps_recvmsg(ctx, state->nd_fd, PS_ND, ctx->ps_inet_fd) == -1) + if (ps_recvmsg(ctx, state->nd_fd, events, + PS_ND, ctx->ps_inet_fd) == -1) logerr(__func__); #else struct dhcpcd_ctx *ctx = arg; - if (ps_recvmsg(ctx, ctx->nd_fd, PS_ND, ctx->ps_inet_fd) == -1) + if (ps_recvmsg(ctx, ctx->nd_fd, events, + PS_ND, ctx->ps_inet_fd) == -1) logerr(__func__); #endif } @@ -80,11 +83,12 @@ ps_inet_recvra(void *arg) #ifdef DHCP6 static void -ps_inet_recvdhcp6(void *arg) +ps_inet_recvdhcp6(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvmsg(ctx, ctx->dhcp6_rfd, PS_DHCP6, ctx->ps_inet_fd) == -1) + if (ps_recvmsg(ctx, ctx->dhcp6_rfd, events, + PS_DHCP6, ctx->ps_inet_fd) == -1) logerr(__func__); } #endif @@ -145,7 +149,7 @@ ps_inet_startcb(void *arg) ctx->udp_rfd = -1; } #endif - else if (eloop_event_add(ctx->eloop, ctx->udp_rfd, + else if (eloop_event_add(ctx->eloop, ctx->udp_rfd, ELE_READ, ps_inet_recvbootp, ctx) == -1) { logerr("%s: eloop_event_add DHCP", __func__); @@ -167,7 +171,7 @@ ps_inet_startcb(void *arg) ctx->nd_fd = -1; } #endif - else if (eloop_event_add(ctx->eloop, ctx->nd_fd, + else if (eloop_event_add(ctx->eloop, ctx->nd_fd, ELE_READ, ps_inet_recvra, ctx) == -1) { logerr("%s: eloop_event_add RA", __func__); @@ -191,7 +195,7 @@ ps_inet_startcb(void *arg) ctx->dhcp6_rfd = -1; } #endif - else if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, + else if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ, ps_inet_recvdhcp6, ctx) == -1) { logerr("%s: eloop_event_add DHCP6", __func__); @@ -299,12 +303,12 @@ dosend: } static void -ps_inet_recvmsg(void *arg) +ps_inet_recvmsg(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; /* Receive shutdown */ - if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, NULL, NULL) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, events, NULL, NULL) == -1) logerr(__func__); } @@ -337,11 +341,12 @@ ps_inet_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg) } static void -ps_inet_dodispatch(void *arg) +ps_inet_dodispatch(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, ps_inet_dispatch, ctx) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, events, + ps_inet_dispatch, ctx) == -1) logerr(__func__); } @@ -370,11 +375,11 @@ ps_inet_stop(struct dhcpcd_ctx *ctx) #ifdef INET static void -ps_inet_recvinbootp(void *arg) +ps_inet_recvinbootp(void *arg, unsigned short events) { struct ps_process *psp = arg; - if (ps_recvmsg(psp->psp_ctx, psp->psp_work_fd, + if (ps_recvmsg(psp->psp_ctx, psp->psp_work_fd, events, PS_BOOTP, psp->psp_ctx->ps_data_fd) == -1) logerr(__func__); } @@ -402,7 +407,7 @@ ps_inet_listenin(void *arg) } #endif - if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, + if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, ELE_READ, ps_inet_recvinbootp, psp) == -1) { logerr("%s: eloop_event_add DHCP", __func__); @@ -459,11 +464,11 @@ ps_inet_listennd(void *arg) #ifdef DHCP6 static void -ps_inet_recvin6dhcp6(void *arg) +ps_inet_recvin6dhcp6(void *arg, unsigned short events) { struct ps_process *psp = arg; - if (ps_recvmsg(psp->psp_ctx, psp->psp_work_fd, + if (ps_recvmsg(psp->psp_ctx, psp->psp_work_fd, events, PS_DHCP6, psp->psp_ctx->ps_data_fd) == -1) logerr(__func__); } @@ -491,7 +496,7 @@ ps_inet_listenin6(void *arg) } #endif - if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, + if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, ELE_READ, ps_inet_recvin6dhcp6, psp) == -1) { logerr("%s: eloop_event_add DHCP", __func__); @@ -504,12 +509,12 @@ ps_inet_listenin6(void *arg) #endif static void -ps_inet_recvmsgpsp(void *arg) +ps_inet_recvmsgpsp(void *arg, unsigned short events) { struct ps_process *psp = arg; /* Receive shutdown. */ - if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, NULL, NULL) == -1) + if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1) logerr(__func__); } diff --git a/src/privsep-root.c b/src/privsep-root.c index adcbd640..03f68266 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -74,7 +74,7 @@ struct psr_ctx { }; static void -ps_root_readerrorcb(void *arg) +ps_root_readerrorcb(void *arg, unsigned short events) { struct psr_ctx *psr_ctx = arg; struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; @@ -87,6 +87,9 @@ ps_root_readerrorcb(void *arg) ssize_t len; int exit_code = EXIT_FAILURE; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + #define PSR_ERROR(e) \ do { \ psr_error->psr_result = -1; \ @@ -113,7 +116,7 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len) .psr_data = data, .psr_datalen = len, }; - if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd, + if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd, ELE_READ, ps_root_readerrorcb, &psr_ctx) == -1) return -1; @@ -126,7 +129,7 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len) #ifdef PRIVSEP_GETIFADDRS static void -ps_root_mreaderrorcb(void *arg) +ps_root_mreaderrorcb(void *arg, unsigned short events) { struct psr_ctx *psr_ctx = arg; struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; @@ -138,6 +141,9 @@ ps_root_mreaderrorcb(void *arg) ssize_t len; int exit_code = EXIT_FAILURE; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = recv(ctx->ps_root_fd, psr_error, sizeof(*psr_error), MSG_PEEK); if (len == -1) PSR_ERROR(errno); @@ -605,11 +611,12 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) /* Receive from state engine, do an action. */ static void -ps_root_recvmsg(void *arg) +ps_root_recvmsg(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvpsmsg(ctx, ctx->ps_root_fd, ps_root_recvmsgcb, ctx) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_root_fd, events, + ps_root_recvmsgcb, ctx) == -1) logerr(__func__); } @@ -775,19 +782,23 @@ ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) } static void -ps_root_dispatch(void *arg) +ps_root_dispatch(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - if (ps_recvpsmsg(ctx, ctx->ps_data_fd, ps_root_dispatchcb, ctx) == -1) + if (ps_recvpsmsg(ctx, ctx->ps_data_fd, events, + ps_root_dispatchcb, ctx) == -1) logerr(__func__); } static void -ps_root_log(void *arg) +ps_root_log(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + /* OpenBSD reports connection reset when dhcpcd exits ... */ if (logreadfd(ctx->ps_log_fd) == -1 && errno != ECONNRESET) logerr(__func__); @@ -821,7 +832,7 @@ ps_root_start(struct dhcpcd_ctx *ctx) if (pid == 0) { ctx->ps_log_fd = logfd[1]; - if (eloop_event_add(ctx->eloop, ctx->ps_log_fd, + if (eloop_event_add(ctx->eloop, ctx->ps_log_fd, ELE_READ, ps_root_log, ctx) == -1) return -1; close(logfd[0]); @@ -836,7 +847,7 @@ ps_root_start(struct dhcpcd_ctx *ctx) ctx->ps_data_fd = datafd[0]; close(datafd[1]); - if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, + if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, ELE_READ, ps_root_dispatch, ctx) == -1) return -1; diff --git a/src/privsep.c b/src/privsep.c index 01a5d308..52599df1 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -320,7 +320,8 @@ ps_rights_limit_stdio(struct dhcpcd_ctx *ctx) pid_t ps_dostart(struct dhcpcd_ctx *ctx, pid_t *priv_pid, int *priv_fd, - void (*recv_msg)(void *), void (*recv_unpriv_msg), + void (*recv_msg)(void *, unsigned short), + void (*recv_unpriv_msg)(void *, unsigned short), void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *), unsigned int flags) { @@ -356,7 +357,7 @@ ps_dostart(struct dhcpcd_ctx *ctx, close(fd[1]); if (recv_unpriv_msg == NULL) ; - else if (eloop_event_add(ctx->eloop, *priv_fd, + else if (eloop_event_add(ctx->eloop, *priv_fd, ELE_READ, recv_unpriv_msg, recv_ctx) == -1) { logerr("%s: eloop_event_add", __func__); @@ -404,7 +405,8 @@ ps_dostart(struct dhcpcd_ctx *ctx, ctx->ps_inet_fd = -1; } - if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1) + if (eloop_event_add(ctx->eloop, *priv_fd, ELE_READ, + recv_msg, recv_ctx) == -1) { logerr("%s: eloop_event_add", __func__); goto errexit; @@ -865,7 +867,8 @@ nobufs: } ssize_t -ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) +ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, unsigned short events, + uint16_t cmd, int wfd) { struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; @@ -878,8 +881,12 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), .msg_iov = iov, .msg_iovlen = 1, }; + ssize_t len; + + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); - ssize_t len = recvmsg(rfd, &msg, 0); + len = recvmsg(rfd, &msg, 0); if (len == -1) logerr("%s: recvmsg", __func__); @@ -903,7 +910,7 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) } ssize_t -ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, +ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events, ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *cbctx) { @@ -914,6 +921,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; bool stop = false; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(fd, &psm, sizeof(psm)); #ifdef PRIVSEP_DEBUG logdebugx("%s: %zd", __func__, len); diff --git a/src/privsep.h b/src/privsep.h index c74bf25c..33916274 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -187,8 +187,8 @@ ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint16_t, unsigned long, const struct msghdr *); ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long, const void *data, size_t len); -ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, uint16_t, int); -ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, +ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, unsigned short, uint16_t, int); +ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, unsigned short, ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *); /* Internal privsep functions. */ @@ -209,7 +209,8 @@ int ps_seccomp_enter(void); pid_t ps_dostart(struct dhcpcd_ctx * ctx, pid_t *priv_pid, int *priv_fd, - void (*recv_msg)(void *), void (*recv_unpriv_msg), + void (*recv_msg)(void *, unsigned short), + void (*recv_unpriv_msg)(void *, unsigned short), void *recv_ctx, int (*callback)(void *), void (*)(int, void *), unsigned int); int ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd); -- 2.47.2