on stack as and when required.
Rather than peaking and checking for truncation for receiving,
just allocate a large enough buffer upfront.
fclose(fp);
return len;
}
-
-ssize_t
-recvmsg_realloc(int fd, struct msghdr *msg, int flags)
-{
- struct iovec *iov;
- ssize_t slen;
- size_t len;
- void *n;
-
- assert(msg != NULL);
- assert(msg->msg_iov != NULL && msg->msg_iovlen > 0);
- assert((flags & (MSG_PEEK | MSG_TRUNC)) == 0);
-
- /* Assume we are reallocing the last iovec. */
- iov = &msg->msg_iov[msg->msg_iovlen - 1];
-
- for (;;) {
- /* Passing MSG_TRUNC should return the actual size needed. */
- slen = recvmsg(fd, msg, flags | MSG_PEEK | MSG_TRUNC);
- if (slen == -1)
- return -1;
- if (!(msg->msg_flags & MSG_TRUNC))
- break;
-
- len = (size_t)slen;
-
- /* Some kernels return the size of the receive buffer
- * on truncation, not the actual size needed.
- * So grow the buffer and try again. */
- if (iov->iov_len == len)
- len++;
- else if (iov->iov_len > len)
- break;
- len = roundup(len, IOVEC_BUFSIZ);
- if ((n = realloc(iov->iov_base, len)) == NULL)
- return -1;
- iov->iov_base = n;
- iov->iov_len = len;
- }
-
- slen = recvmsg(fd, msg, flags);
- if (slen != -1 && msg->msg_flags & MSG_TRUNC) {
- /* This should not be possible ... */
- errno = ENOBUFS;
- return -1;
- }
- return slen;
-}
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *);
size_t read_hwaddr_aton(uint8_t **, const char *);
-
-ssize_t recvmsg_realloc(int, struct msghdr *, int);
#endif
"No Prefix Available"
};
-static void dhcp6_bind(struct interface *, const char *);
+static void dhcp6_bind(struct interface *, const char *, const char *);
static void dhcp6_failinform(void *);
static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *);
static void dhcp6_recvaddr(void *);
static int
dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
{
- struct dhcp6_state *state;
- struct dhcpcd_ctx *ctx;
- struct sockaddr_in6 dst;
+ struct dhcp6_state *state = D6_STATE(ifp);
+ struct dhcpcd_ctx *ctx = ifp->ctx;
+ struct sockaddr_in6 dst = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(DHCP6_SERVER_PORT),
+ };
struct timespec RTprev;
double rnd;
time_t ms;
const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
struct ipv6_addr *lla;
int s;
+ struct iovec iov = {
+ .iov_base = state->send, .iov_len = state->send_len,
+ };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &dst, .msg_namelen = sizeof(dst),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ };
if (!callback && ifp->carrier <= LINK_DOWN)
return 0;
- memset(&dst, 0, sizeof(dst));
- dst.sin6_family = AF_INET6;
- dst.sin6_port = htons(DHCP6_SERVER_PORT);
#ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst);
#endif
- state = D6_STATE(ifp);
lla = ipv6_linklocal(ifp);
/* We need to ensure we have sufficient scope to unicast the address */
/* XXX FIXME: We should check any added addresses we have like from
/* Wait the initial delay */
if (state->IMD != 0) {
state->IMD = 0;
- eloop_timeout_add_tv(ifp->ctx->eloop,
+ eloop_timeout_add_tv(ctx->eloop,
&state->RT, callback, ifp);
return 0;
}
}
#endif
- ctx = ifp->ctx;
- ctx->sndhdr.msg_name = (void *)&dst;
- ctx->sndhdr.msg_iov[0].iov_base = state->send;
- ctx->sndhdr.msg_iov[0].iov_len = state->send_len;
-
/* Set the outbound interface */
if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
struct cmsghdr *cm;
- struct in6_pktinfo pi;
+ struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
dst.sin6_scope_id = ifp->index;
- cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+ msg.msg_control = ctl;
+ msg.msg_controllen = sizeof(ctl);
+ cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */
return -1;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memset(&pi, 0, sizeof(pi));
- pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
- } else {
- /* Remove the control buffer as we're not dictating
- * which interface to use for outgoing messages. */
- ctx->sndhdr.msg_control = NULL;
- ctx->sndhdr.msg_controllen = 0;
}
if (ctx->dhcp6_fd != -1)
return -1;
}
- if (sendmsg(s, &ctx->sndhdr, 0) == -1) {
+ if (sendmsg(s, &msg, 0) == -1) {
logerr("%s: %s: sendmsg", __func__, ifp->name);
/* Allow DHCPv6 to continue .... the errors
* would be rate limited by the protocol.
* associate with an access point. */
}
- /* Restore the control buffer assignment. */
- if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
- ctx->sndhdr.msg_control = ctx->sndbuf;
- ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
- }
-
state->RTC++;
if (callback) {
if (state->MRC == 0 || state->RTC < state->MRC)
- eloop_timeout_add_tv(ifp->ctx->eloop,
+ eloop_timeout_add_tv(ctx->eloop,
&state->RT, callback, ifp);
else if (state->MRC != 0 && state->MRCcallback)
- eloop_timeout_add_tv(ifp->ctx->eloop,
+ eloop_timeout_add_tv(ctx->eloop,
&state->RT, state->MRCcallback, ifp);
else
logwarnx("%s: sent %d times with no reply",
break;
}
- dhcp6_bind(ifp, NULL);
+ dhcp6_bind(ifp, NULL, NULL);
switch (state->state) {
case DH6S_BOUND:
#endif
static void
-dhcp6_bind(struct interface *ifp, const char *op)
+dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
{
struct dhcp6_state *state = D6_STATE(ifp);
bool has_new = false;
}
lognewinfo = has_new ? loginfox : logdebugx;
if (op != NULL)
- lognewinfo("%s: %s received from %s",
- ifp->name, op, ifp->ctx->sfrom);
+ lognewinfo("%s: %s received from %s", ifp->name, op, sfrom);
state->reason = NULL;
if (state->state != DH6S_ITIMEDOUT)
}
static void
-dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
+dhcp6_recvif(struct interface *ifp, const char *sfrom,
+ struct dhcp6_message *r, size_t len)
{
struct dhcpcd_ctx *ctx;
size_t i;
}
if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
- logdebugx("%s: no DHCPv6 server ID from %s",
- ifp->name, ctx->sfrom);
+ logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom);
return;
}
!dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
{
logwarnx("%s: reject DHCPv6 (no option %s) from %s",
- ifp->name, opt->var, ctx->sfrom);
+ ifp->name, opt->var, sfrom);
return;
}
if (has_option_mask(ifo->rejectmask6, opt->option) &&
dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
{
logwarnx("%s: reject DHCPv6 (option %s) from %s",
- ifp->name, opt->var, ctx->sfrom);
+ ifp->name, opt->var, sfrom);
return;
}
}
(uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL)
{
logerr("%s: authentication failed from %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
if (state->auth.token)
} else if (ifo->auth.options & DHCPCD_AUTH_SEND) {
if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
logerr("%s: no authentication from %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
- logwarnx("%s: no authentication from %s",
- ifp->name, ctx->sfrom);
+ logwarnx("%s: no authentication from %s", ifp->name, sfrom);
}
#endif
return;
break;
case DH6S_CONFIRM:
- if (dhcp6_validatelease(ifp, r, len,
- ctx->sfrom, NULL) == -1)
+ if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
{
dhcp6_startdiscover(ifp);
return;
case DH6S_REQUEST: /* FALLTHROUGH */
case DH6S_RENEW: /* FALLTHROUGH */
case DH6S_REBIND:
- if (dhcp6_validatelease(ifp, r, len,
- ctx->sfrom, NULL) == -1)
+ if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
{
/*
* If we can't use the lease, fallback to
logerrx("%s: invalid INF_MAX_RT %u",
ifp->name, max_rt);
}
- if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1)
+ if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
return;
break;
case DHCP6_RECONFIGURE:
if (auth == NULL) {
#endif
logerrx("%s: unauthenticated %s from %s",
- ifp->name, op, ctx->sfrom);
+ ifp->name, op, sfrom);
if (ifo->auth.options & DHCPCD_AUTH_REQUIRE)
return;
#ifdef AUTH
}
- loginfox("%s: %s from %s", ifp->name, op, ctx->sfrom);
+ loginfox("%s: %s from %s", ifp->name, op, sfrom);
o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol);
if (o == NULL) {
logerrx("%s: missing Reconfigure Message option",
ia = TAILQ_FIRST(&state->addrs);
if (ia == NULL)
loginfox("%s: ADV (no address) from %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
else
loginfox("%s: ADV %s from %s",
- ifp->name, ia->saddr, ctx->sfrom);
+ ifp->name, ia->saddr, sfrom);
if (ifp->ctx->options & DHCPCD_TEST)
break;
dhcp6_startrequest(ifp);
}
}
- dhcp6_bind(ifp, op);
+ dhcp6_bind(ifp, op, sfrom);
}
static void
dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
{
+ struct sockaddr_in6 from;
+ unsigned char buf[64 * 1024]; /* Maximum UDP message size */
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &from, .msg_namelen = sizeof(from),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
int s;
size_t len;
ssize_t bytes;
+ char sfrom[INET6_ADDRSTRLEN];
struct interface *ifp;
struct dhcp6_message *r;
const struct dhcp6_state *state;
uint8_t *o;
uint16_t ol;
- ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
- bytes = recvmsg_realloc(s, &ctx->rcvhdr, 0);
+ bytes = recvmsg(s, &msg, 0);
if (bytes == -1) {
- logerr("%s: recvmsg_realloc", __func__);
+ logerr(__func__);
return;
}
len = (size_t)bytes;
- ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
- ctx->ntopbuf, sizeof(ctx->ntopbuf));
+ inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
if (len < sizeof(struct dhcp6_message)) {
- logerrx("DHCPv6 packet too short from %s", ctx->sfrom);
+ logerrx("DHCPv6 packet too short from %s", sfrom);
return;
}
struct in6_pktinfo pi;
pi.ipi6_ifindex = 0;
- for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&msg);
cm;
- cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&msg, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
}
if (pi.ipi6_ifindex == 0) {
logerrx("DHCPv6 reply did not contain index from %s",
- ctx->sfrom);
+ sfrom);
return;
}
}
if (ifp == NULL) {
logerrx("DHCPv6 reply for unexpected interface from %s",
- ctx->sfrom);
+ sfrom);
return;
}
}
- r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
+ r = (struct dhcp6_message *)buf;
o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
if (o == NULL || ol != ctx->duid_len ||
memcmp(o, ctx->duid, ol) != 0)
{
logdebugx("%s: incorrect client ID from %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
logdebugx("%s: no DHCPv6 server ID from %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
if (r->type == DHCP6_RECONFIGURE) {
logdebugx("%s: RECONFIGURE6 recv from %s,"
" sending to all interfaces",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = D6_CSTATE(ifp);
if (state != NULL && state->send != NULL)
- dhcp6_recvif(ifp, r, len);
+ dhcp6_recvif(ifp, sfrom, r, len);
}
return;
}
state->send->xid[0],
state->send->xid[1],
state->send->xid[2],
- ctx->sfrom);
+ sfrom);
return;
}
logdebugx("%s: redirecting DHCP6 message to %s",
ifp = ifp1;
}
- dhcp6_recvif(ifp, r, len);
+ dhcp6_recvif(ifp, sfrom, r, len);
}
static void
#endif
dev_stop(&ctx);
eloop_free(ctx.eloop);
- free(ctx.iov[0].iov_base);
if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
loginfox(PACKAGE " exited");
int link_fd;
int seq; /* route message sequence no */
int sseq; /* successful seq no sent */
- struct iovec iov[1]; /* generic iovec buffer */
#ifdef USE_SIGNALS
sigset_t sigset;
uint8_t *secret;
size_t secret_len;
- unsigned char ctlbuf[IP6BUFLEN];
- struct sockaddr_in6 from;
- struct msghdr sndhdr;
- struct iovec sndiov[1];
- unsigned char sndbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- struct msghdr rcvhdr;
- char ntopbuf[INET6_ADDRSTRLEN];
- const char *sfrom;
-
int nd_fd;
struct ra_head *ra_routers;
int
if_handlelink(struct dhcpcd_ctx *ctx)
{
- struct msghdr msg;
+ union {
+ struct rt_msghdr rtmsg;
+ unsigned char buf[2048];
+ } u;
+ struct iovec iov = { .iov_base = u.buf, .iov_len = sizeof(u) };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
ssize_t len;
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = ctx->iov;
- msg.msg_iovlen = 1;
-
- len = recvmsg_realloc(ctx->link_fd, &msg, 0);
+ len = recvmsg(ctx->link_fd, &msg, 0);
if (len == -1)
return -1;
if (len != 0)
- if_dispatch(ctx, ctx->iov[0].iov_base);
+ if_dispatch(ctx, &u.rtmsg);
return 0;
}
struct priv {
int route_fd;
uint32_t route_pid;
- struct iovec sndrcv_iov[1];
};
/* We need this to send a broadcast for InfiniBand.
if (ctx->priv != NULL) {
priv = (struct priv *)ctx->priv;
- free(priv->sndrcv_iov[0].iov_base);
close(priv->route_fd);
}
}
struct interface *ifp, int fd, int flags,
int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
{
- struct msghdr msg;
- struct sockaddr_nl nladdr;
+ struct sockaddr_nl nladdr = { .nl_pid = 0 };
+ struct msghdr msg = {
+ .msg_name = &nladdr, .msg_namelen = sizeof(nladdr),
+ .msg_iov = iov, .msg_iovlen = 1,
+ };
ssize_t len;
struct nlmsghdr *nlm;
int r;
unsigned int again;
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &nladdr;
- msg.msg_namelen = sizeof(nladdr);
- memset(&nladdr, 0, sizeof(nladdr));
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
recv_again:
- if ((len = recvmsg_realloc(fd, &msg, flags)) == -1)
+ if ((len = recvmsg(fd, &msg, flags)) == -1)
return -1;
if (len == 0)
return 0;
int
if_handlelink(struct dhcpcd_ctx *ctx)
{
+ unsigned char buf[16 * 1024];
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
- return get_netlink(ctx, ctx->iov, NULL,
+ return get_netlink(ctx, &iov, NULL,
ctx->link_fd, MSG_DONTWAIT, &link_netlink);
}
int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
{
int s, r;
- struct sockaddr_nl snl;
- struct iovec iov[1];
- struct msghdr msg;
-
- memset(&snl, 0, sizeof(snl));
- snl.nl_family = AF_NETLINK;
+ struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
+ struct iovec iov = { .iov_base = hdr, .iov_len = hdr->nlmsg_len };
+ struct msghdr msg = {
+ .msg_name = &snl, .msg_namelen = sizeof(snl),
+ .msg_iov = &iov, .msg_iovlen = 1
+ };
if (protocol == NETLINK_ROUTE) {
struct priv *priv;
return -1;
}
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &snl;
- msg.msg_namelen = sizeof(snl);
- memset(&iov, 0, sizeof(iov));
- iov[0].iov_base = hdr;
- iov[0].iov_len = hdr->nlmsg_len;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
/* Request a reply */
hdr->nlmsg_flags |= NLM_F_ACK;
hdr->nlmsg_seq = (uint32_t)++ctx->seq;
if (sendmsg(s, &msg, 0) != -1) {
- struct priv *priv;
+ unsigned char buf[16 * 1024];
+ struct iovec riov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
- priv = (struct priv *)ctx->priv;
- r = get_netlink(ctx, priv->sndrcv_iov, ifp, s, 0, callback);
+ r = get_netlink(ctx, &riov, ifp, s, 0, callback);
} else
r = -1;
if (protocol != NETLINK_ROUTE)
int
if_initrt(struct dhcpcd_ctx *ctx, int af)
{
- struct nlmr nlm;
+ struct nlmr nlm = {
+ .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+ .hdr.nlmsg_type = RTM_GETROUTE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH,
+ .rt.rtm_table = RT_TABLE_MAIN,
+ .rt.rtm_family = (unsigned char)af,
+ };
rt_headclear(&ctx->kroutes, af);
-
- memset(&nlm, 0, sizeof(nlm));
- nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- nlm.hdr.nlmsg_type = RTM_GETROUTE;
- nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
- nlm.rt.rtm_table = RT_TABLE_MAIN;
- nlm.rt.rtm_family = (unsigned char)af;
-
return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, &_if_initrt);
}
};
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
#ifdef PACKET_AUXDATA
- unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+ unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))] = { 0 };
struct cmsghdr *cmsg;
struct tpacket_auxdata *aux;
#endif
int
if_handlelink(struct dhcpcd_ctx *ctx)
{
- struct msghdr msg;
+ union {
+ struct rt_msghdr rtmsg;
+ unsigned char buf[2048];
+ } u;
+ struct iovec iov = { .iov_base = u.buf, .iov_len = sizeof(u) };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
ssize_t len;
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = ctx->iov;
- msg.msg_iovlen = 1;
-
- if ((len = recvmsg_realloc(ctx->link_fd, &msg, 0)) == -1)
+ if ((len = recvmsg(ctx->link_fd, &msg, 0)) == -1)
return -1;
if (len != 0)
- if_dispatch(ctx, ctx->iov[0].iov_base);
+ if_dispatch(ctx, &u.rtmsg);
return 0;
}
ipv6_init(struct dhcpcd_ctx *ctx)
{
- if (ctx->sndhdr.msg_iovlen == 1)
+ if (ctx->ra_routers != NULL)
return 0;
- if (ctx->ra_routers == NULL) {
- ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
- if (ctx->ra_routers == NULL)
- return -1;
- }
+ ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
+ if (ctx->ra_routers == NULL)
+ return -1;
TAILQ_INIT(ctx->ra_routers);
- ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
- ctx->sndhdr.msg_iov = ctx->sndiov;
- ctx->sndhdr.msg_iovlen = 1;
- ctx->sndhdr.msg_control = ctx->sndbuf;
- ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
- ctx->rcvhdr.msg_name = &ctx->from;
- ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
- ctx->rcvhdr.msg_iov = ctx->iov;
- ctx->rcvhdr.msg_iovlen = 1;
- ctx->rcvhdr.msg_control = ctx->ctlbuf;
- // controllen is set at recieve
- //ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
-
ctx->nd_fd = -1;
ctx->dhcp6_fd = -1;
return 0;
{
struct interface *ifp = arg;
struct dhcpcd_ctx *ctx;
- struct rs_state *state;
- struct sockaddr_in6 dst;
+ struct rs_state *state = RS_STATE(ifp);
+ struct sockaddr_in6 dst = { .sin6_family = AF_INET6 };
+ struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &dst, .msg_namelen = sizeof(dst),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
struct cmsghdr *cm;
- struct in6_pktinfo pi;
+ struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address",
return;
}
- memset(&dst, 0, sizeof(dst));
- dst.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst);
#endif
return;
}
- state = RS_STATE(ifp);
ctx = ifp->ctx;
- ctx->sndhdr.msg_name = (void *)&dst;
- ctx->sndhdr.msg_iov[0].iov_base = state->rs;
- ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
/* Set the outbound interface */
- cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+ cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */
return;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memset(&pi, 0, sizeof(pi));
- pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name);
- if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
+ if (sendmsg(ctx->nd_fd, &msg, 0) == -1) {
logerr(__func__);
/* Allow IPv6ND to continue .... at most a few errors
* would be logged.
struct ipv6_addr *ia = arg;
struct interface *ifp = ia->iface;
struct dhcpcd_ctx *ctx = ifp->ctx;
- struct sockaddr_in6 dst;
+ struct sockaddr_in6 dst = {
+ .sin6_family = AF_INET6,
+ .sin6_scope_id = ifp->index,
+ };
+ struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &dst, .msg_namelen = sizeof(dst),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
struct cmsghdr *cm;
- struct in6_pktinfo pi;
+ struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
const struct rs_state *state = RS_CSTATE(ifp);
if (state == NULL || ifp->carrier <= LINK_DOWN)
goto freeit;
- memset(&dst, 0, sizeof(dst));
- dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
- dst.sin6_scope_id = ifp->index;
if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
logerr(__func__);
return;
}
- ctx->sndhdr.msg_name = (void *)&dst;
- ctx->sndhdr.msg_iov[0].iov_base = ia->na;
- ctx->sndhdr.msg_iov[0].iov_len = ia->na_len;
-
/* Set the outbound interface. */
- cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+ cm = CMSG_FIRSTHDR(&msg);
assert(cm != NULL);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memset(&pi, 0, sizeof(pi));
- pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
- if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1)
+ if (sendmsg(ctx->nd_fd, &msg, 0) == -1)
logerr(__func__);
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
#endif
static void
-ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
- struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlera(struct dhcpcd_ctx *ctx,
+ const struct sockaddr_in6 *from, const char *sfrom,
+ struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{
size_t i, olen;
struct nd_router_advert *nd_ra;
if (ifp == NULL) {
#ifdef DEBUG_RS
- logdebugx("RA for unexpected interface from %s",
- ctx->sfrom);
+ logdebugx("RA for unexpected interface from %s", sfrom);
#endif
return;
}
if (len < sizeof(struct nd_router_advert)) {
- logerrx("IPv6 RA packet too short from %s", ctx->sfrom);
+ logerrx("IPv6 RA packet too short from %s", sfrom);
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
- logerrx("invalid hoplimit(%d) in RA from %s",
- hoplimit, ctx->sfrom);
+ logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom);
return;
}
-
- if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
- logerrx("RA from non local address %s", ctx->sfrom);
+ if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
+ logerrx("RA from non local address %s", sfrom);
return;
}
if (!(ifp->options->options & DHCPCD_IPV6RS)) {
#ifdef DEBUG_RS
- logerrx("%s: unexpected RA from %s",
- ifp->name, ctx->sfrom);
+ logerrx("%s: unexpected RA from %s", ifp->name, sfrom);
#endif
return;
}
if (ipv6_linklocal(ifp) == NULL) {
#ifdef DEBUG_RS
logdebugx("%s: received RA from %s (no link-local)",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
#endif
return;
}
- if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) {
+ if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) {
logdebugx("%s: ignoring RA from ourself %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (ifp == rap->iface &&
- IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
+ IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
break;
}
return;
}
rap->iface = ifp;
- rap->from = ctx->from.sin6_addr;
- strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
+ rap->from = from->sin6_addr;
+ strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs);
new_rap = true;
} else
* in accordance with the own prefix times which would result in too
* much needless log spam. */
logfunc = new_rap ? loginfox : logdebugx,
- logfunc("%s: Router Advertisement from %s",
- ifp->name, ctx->sfrom);
+ logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->flags = nd_ra->nd_ra_flags_reserved;
}
if (dho != NULL)
logwarnx("%s: reject RA (option %s) from %s",
- ifp->name, dho->var, ctx->sfrom);
+ ifp->name, dho->var, rap->sfrom);
else
logwarnx("%s: reject RA (option %d) from %s",
- ifp->name, ndo.nd_opt_type, ctx->sfrom);
+ ifp->name, ndo.nd_opt_type, rap->sfrom);
if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0);
else
dho->option))
{
logwarnx("%s: reject RA (no option %s) from %s",
- ifp->name, dho->var, ctx->sfrom);
+ ifp->name, dho->var, rap->sfrom);
if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0);
else
}
static void
-ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
- struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
+ struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{
struct nd_neighbor_advert *nd_na;
struct in6_addr nd_na_target;
if (ifp == NULL) {
#ifdef DEBUG_NS
- logdebugx("NA for unexpected interface from %s",
- ctx->sfrom);
+ logdebugx("NA for unexpected interface from %s", sfrom);
#endif
return;
}
if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
- logerrx("%s: IPv6 NA too short from %s",
- ifp->name, ctx->sfrom);
+ logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
logerrx("invalid hoplimit(%d) in NA from %s",
- hoplimit, ctx->sfrom);
+ hoplimit, sfrom);
return;
}
memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
logerrx("%s: NA multicast address %s (%s)",
- ifp->name, taddr, ctx->sfrom);
+ ifp->name, taddr, sfrom);
return;
}
if (rap == NULL) {
#ifdef DEBUG_NS
logdebugx("%s: unexpected NA from %s for %s",
- ifp->name, ctx->sfrom, taddr);
+ ifp->name, sfrom, taddr);
#endif
return;
}
#ifdef DEBUG_NS
logdebugx("%s: %sNA for %s from %s",
- ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
+ ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
#endif
/* Node is no longer a router, so remove it from consideration */
if (!is_router && !rap->expired) {
loginfox("%s: %s not a router (%s)",
- ifp->name, taddr, ctx->sfrom);
+ ifp->name, taddr, sfrom);
rap->expired = 1;
rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT");
ipv6nd_handledata(void *arg)
{
struct dhcpcd_ctx *ctx;
+ struct sockaddr_in6 from;
+ unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &from, .msg_namelen = sizeof(from),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
ssize_t len;
struct cmsghdr *cm;
+ char sfrom[INET6_ADDRSTRLEN];
int hoplimit;
struct in6_pktinfo pkt;
struct icmp6_hdr *icp;
struct interface *ifp;
ctx = arg;
- ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
- len = recvmsg_realloc(ctx->nd_fd, &ctx->rcvhdr, 0);
+ len = recvmsg(ctx->nd_fd, &msg, 0);
if (len == -1) {
logerr(__func__);
return;
}
- ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
- ctx->ntopbuf, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
if ((size_t)len < sizeof(struct icmp6_hdr)) {
- logerrx("IPv6 ICMP packet too short from %s", ctx->sfrom);
+ logerrx("IPv6 ICMP packet too short from %s", sfrom);
return;
}
pkt.ipi6_ifindex = 0;
hoplimit = 0;
- for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&msg);
cm;
- cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&msg, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
}
if (pkt.ipi6_ifindex == 0) {
- logerrx("IPv6 RA/NA did not contain index from %s", ctx->sfrom);
+ logerrx("IPv6 RA/NA did not contain index from %s", sfrom);
return;
}
!(ifp->options->options & DHCPCD_IPV6)))
return;
- icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
+ icp = (struct icmp6_hdr *)buf;
if (icp->icmp6_code == 0) {
switch(icp->icmp6_type) {
case ND_NEIGHBOR_ADVERT:
- ipv6nd_handlena(ctx, ifp, icp, (size_t)len,
- hoplimit);
+ ipv6nd_handlena(ctx, sfrom,
+ ifp, icp, (size_t)len, hoplimit);
return;
case ND_ROUTER_ADVERT:
- ipv6nd_handlera(ctx, ifp, icp, (size_t)len,
- hoplimit);
+ ipv6nd_handlera(ctx, &from, sfrom,
+ ifp, icp, (size_t)len, hoplimit);
return;
}
}
logerrx("invalid IPv6 type %d or code %d from %s",
- icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
+ icp->icmp6_type, icp->icmp6_code, sfrom);
}
static void