static void
dhcp_handlepacket(void *arg)
{
- struct interface *iface = arg;
+ struct interface *ifp = arg;
struct dhcp_message *dhcp = NULL;
const uint8_t *pp;
size_t bytes;
struct in_addr from;
- int i, partialcsum = 0;
- const struct dhcp_state *state = D_CSTATE(iface);
+ int i, flags;
+ const struct dhcp_state *state = D_CSTATE(ifp);
- /* We loop through until our buffer is empty.
- * The benefit is that if we get >1 DHCP packet in our buffer and
- * the first one fails for any reason, we can use the next. */
- for(;;) {
- bytes = (size_t)if_readrawpacket(iface, ETHERTYPE_IP,
- iface->ctx->packet, udp_dhcp_len, &partialcsum);
- if (bytes == 0 || (ssize_t)bytes == -1)
+ /* Need this API due to BPF */
+ flags = 0;
+ while (!(flags & RAW_EOF)) {
+ bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP,
+ ifp->ctx->packet, udp_dhcp_len, &flags);
+ if (bytes == 0 || (ssize_t)bytes == -1) {
+ syslog(LOG_ERR, "%s: dhcp if_readrawpacket: %m",
+ ifp->name);
+ dhcp_close(ifp);
break;
- if (valid_udp_packet(iface->ctx->packet, bytes,
- &from, partialcsum) == -1)
+ }
+ if (valid_udp_packet(ifp->ctx->packet, bytes,
+ &from, flags & RAW_PARTIALCSUM) == -1)
{
syslog(LOG_ERR, "%s: invalid UDP packet from %s",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
continue;
}
- i = whitelisted_ip(iface->options, from.s_addr);
+ i = whitelisted_ip(ifp->options, from.s_addr);
if (i == 0) {
syslog(LOG_WARNING,
"%s: non whitelisted DHCP packet from %s",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
continue;
} else if (i != 1 &&
- blacklisted_ip(iface->options, from.s_addr) == 1)
+ blacklisted_ip(ifp->options, from.s_addr) == 1)
{
syslog(LOG_WARNING,
"%s: blacklisted DHCP packet from %s",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
continue;
}
- if (iface->flags & IFF_POINTOPOINT &&
+ if (ifp->flags & IFF_POINTOPOINT &&
state->dst.s_addr != from.s_addr)
{
syslog(LOG_WARNING,
"%s: server %s is not destination",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
}
- bytes = get_udp_data(&pp, iface->ctx->packet);
+ bytes = get_udp_data(&pp, ifp->ctx->packet);
if (bytes > sizeof(*dhcp)) {
syslog(LOG_ERR,
"%s: packet greater than DHCP size from %s",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
continue;
}
if (dhcp == NULL) {
memcpy(dhcp, pp, bytes);
if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
syslog(LOG_DEBUG, "%s: bogus cookie from %s",
- iface->name, inet_ntoa(from));
+ ifp->name, inet_ntoa(from));
continue;
}
/* Ensure packet is for us */
- if (iface->hwlen <= sizeof(dhcp->chaddr) &&
- memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
+ if (ifp->hwlen <= sizeof(dhcp->chaddr) &&
+ memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen))
{
char buf[sizeof(dhcp->chaddr) * 3];
syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s",
- iface->name, ntohl(dhcp->xid),
+ ifp->name, ntohl(dhcp->xid),
hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
buf, sizeof(buf)));
continue;
}
- dhcp_handledhcp(iface, &dhcp, &from);
+ dhcp_handledhcp(ifp, &dhcp, &from);
if (state->raw_fd == -1)
break;
}
{
#ifdef SOCK_CLOEXEC
- return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0);
#else
int s, flags;
close(s);
return -1;
}
- if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
- fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
- {
- close(s);
- return -1;
- }
return s;
#endif
}
int flags;
#endif
#ifdef _PATH_BPF
- fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC);
#else
char device[32];
int n = 0;
do {
snprintf(device, sizeof(device), "/dev/bpf%d", n++);
- fd = open(device, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ fd = open(device, O_RDWR | O_CLOEXEC);
} while (fd == -1 && errno == EBUSY);
#endif
if (ioctl(fd, BIOCSETF, &pf) == -1)
goto eexit;
-#ifdef __OpenBSD__
- /* For some reason OpenBSD fails to open the fd as non blocking */
- if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
- fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
- goto eexit;
-#endif
-
return fd;
eexit:
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
- void *data, size_t len, int *partialcsum)
+ void *data, size_t len, int *flags)
{
- int fd = -1;
+ int fd;
struct bpf_hdr packet;
ssize_t bytes;
const unsigned char *payload;
else
fd = state->raw_fd;
- if (partialcsum != NULL)
- *partialcsum = 0; /* Not supported on BSD */
+ if (flags != NULL)
+ *flags = 0; /* Not supported on BSD */
for (;;) {
if (state->buffer_len == 0) {
bytes = read(fd, state->buffer, state->buffer_size);
- if (bytes == -1)
- return errno == EAGAIN ? 0 : -1;
- else if ((size_t)bytes < sizeof(packet))
- return -1;
+ if (bytes == -1 || bytes == 0)
+ return bytes;
state->buffer_len = (size_t)bytes;
state->buffer_pos = 0;
}
next:
state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
packet.bh_caplen);
- if (state->buffer_pos >= state->buffer_len)
+ if (state->buffer_pos >= state->buffer_len) {
state->buffer_len = state->buffer_pos = 0;
+ *flags |= RAW_EOF;
+ }
if (bytes != -1)
return bytes;
}
int ifa_flags;
#endif
- for (;;) {
- bytes = read(ctx->link_fd, msg, sizeof(msg));
- if (bytes == -1) {
- if (errno == EAGAIN)
- return 0;
- if (errno == EINTR)
- continue;
- return -1;
- }
- e = msg + bytes;
- for (p = msg; p < e; p += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)(void *)p;
- // Ignore messages generated by us
- if (rtm->rtm_pid == getpid())
- break;
- switch(rtm->rtm_type) {
+ bytes = read(ctx->link_fd, msg, sizeof(msg));
+ if (bytes == -1 || bytes == 0)
+ return bytes;
+ e = msg + bytes;
+ for (p = msg; p < e; p += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)p;
+ // Ignore messages generated by us
+ if (rtm->rtm_pid == getpid())
+ break;
+ switch(rtm->rtm_type) {
#ifdef RTM_IFANNOUNCE
- case RTM_IFANNOUNCE:
- ifan = (struct if_announcemsghdr *)(void *)p;
- switch(ifan->ifan_what) {
- case IFAN_ARRIVAL:
- dhcpcd_handleinterface(ctx, 1,
- ifan->ifan_name);
- break;
- case IFAN_DEPARTURE:
- dhcpcd_handleinterface(ctx, -1,
- ifan->ifan_name);
- break;
- }
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *)(void *)p;
+ switch(ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ dhcpcd_handleinterface(ctx, 1,
+ ifan->ifan_name);
break;
+ case IFAN_DEPARTURE:
+ dhcpcd_handleinterface(ctx, -1,
+ ifan->ifan_name);
+ break;
+ }
+ break;
#endif
- case RTM_IFINFO:
- ifm = (struct if_msghdr *)(void *)p;
- memset(ifname, 0, sizeof(ifname));
- if (!(if_indextoname(ifm->ifm_index, ifname)))
- break;
- switch (ifm->ifm_data.ifi_link_state) {
- case LINK_STATE_DOWN:
- len = LINK_DOWN;
- break;
- case LINK_STATE_UP:
- len = LINK_UP;
- break;
- default:
- /* handle_carrier will re-load
- * the interface flags and check for
- * IFF_RUNNING as some drivers that
- * don't handle link state also don't
- * set IFF_RUNNING when this routing
- * message is generated.
- * As such, it is a race ...*/
- len = LINK_UNKNOWN;
- break;
- }
- dhcpcd_handlecarrier(ctx, len,
- (unsigned int)ifm->ifm_flags, ifname);
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)(void *)p;
+ memset(ifname, 0, sizeof(ifname));
+ if (!(if_indextoname(ifm->ifm_index, ifname)))
+ break;
+ switch (ifm->ifm_data.ifi_link_state) {
+ case LINK_STATE_DOWN:
+ len = LINK_DOWN;
+ break;
+ case LINK_STATE_UP:
+ len = LINK_UP;
+ break;
+ default:
+ /* handle_carrier will re-load
+ * the interface flags and check for
+ * IFF_RUNNING as some drivers that
+ * don't handle link state also don't
+ * set IFF_RUNNING when this routing
+ * message is generated.
+ * As such, it is a race ...*/
+ len = LINK_UNKNOWN;
+ break;
+ }
+ dhcpcd_handlecarrier(ctx, len,
+ (unsigned int)ifm->ifm_flags, ifname);
+ break;
+ case RTM_DELETE:
+ if (~rtm->rtm_addrs &
+ (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
+ break;
+ cp = (char *)(void *)(rtm + 1);
+ sa = (struct sockaddr *)(void *)cp;
+ if (sa->sa_family != AF_INET)
break;
- case RTM_DELETE:
- if (~rtm->rtm_addrs &
- (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
- break;
- cp = (char *)(void *)(rtm + 1);
- sa = (struct sockaddr *)(void *)cp;
- if (sa->sa_family != AF_INET)
- break;
#ifdef INET
- get_addrs(rtm->rtm_addrs, cp, rti_info);
- memset(&rt, 0, sizeof(rt));
- rt.iface = NULL;
- COPYOUT(rt.dest, rti_info[RTAX_DST]);
- COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
- COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
- ipv4_routedeleted(ctx, &rt);
+ get_addrs(rtm->rtm_addrs, cp, rti_info);
+ memset(&rt, 0, sizeof(rt));
+ rt.iface = NULL;
+ COPYOUT(rt.dest, rti_info[RTAX_DST]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
+ ipv4_routedeleted(ctx, &rt);
#endif
- break;
+ break;
#ifdef RTM_CHGADDR
- case RTM_CHGADDR: /* FALLTHROUGH */
+ case RTM_CHGADDR: /* FALLTHROUGH */
#endif
- case RTM_DELADDR: /* FALLTHROUGH */
- case RTM_NEWADDR:
- ifam = (struct ifa_msghdr *)(void *)p;
- if (!if_indextoname(ifam->ifam_index, ifname))
- break;
- cp = (char *)(void *)(ifam + 1);
- get_addrs(ifam->ifam_addrs, cp, rti_info);
- if (rti_info[RTAX_IFA] == NULL)
- break;
- switch (rti_info[RTAX_IFA]->sa_family) {
- case AF_LINK:
+ case RTM_DELADDR: /* FALLTHROUGH */
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)(void *)p;
+ if (!if_indextoname(ifam->ifam_index, ifname))
+ break;
+ cp = (char *)(void *)(ifam + 1);
+ get_addrs(ifam->ifam_addrs, cp, rti_info);
+ if (rti_info[RTAX_IFA] == NULL)
+ break;
+ switch (rti_info[RTAX_IFA]->sa_family) {
+ case AF_LINK:
#ifdef RTM_CHGADDR
- if (rtm->rtm_type != RTM_CHGADDR)
- break;
+ if (rtm->rtm_type != RTM_CHGADDR)
+ break;
#else
- if (rtm->rtm_type != RTM_NEWADDR)
- break;
-#endif
- memcpy(&sdl, rti_info[RTAX_IFA],
- rti_info[RTAX_IFA]->sa_len);
- dhcpcd_handlehwaddr(ctx, ifname,
- (const unsigned char*)CLLADDR(&sdl),
- sdl.sdl_alen);
+ if (rtm->rtm_type != RTM_NEWADDR)
break;
+#endif
+ memcpy(&sdl, rti_info[RTAX_IFA],
+ rti_info[RTAX_IFA]->sa_len);
+ dhcpcd_handlehwaddr(ctx, ifname,
+ (const unsigned char*)CLLADDR(&sdl),
+ sdl.sdl_alen);
+ break;
#ifdef INET
- case AF_INET:
- case 255: /* FIXME: Why 255? */
- COPYOUT(rt.dest, rti_info[RTAX_IFA]);
- COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
- COPYOUT(rt.gate, rti_info[RTAX_BRD]);
- ipv4_handleifa(ctx, rtm->rtm_type,
- NULL, ifname,
- &rt.dest, &rt.net, &rt.gate);
- break;
+ case AF_INET:
+ case 255: /* FIXME: Why 255? */
+ COPYOUT(rt.dest, rti_info[RTAX_IFA]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_BRD]);
+ ipv4_handleifa(ctx, rtm->rtm_type,
+ NULL, ifname,
+ &rt.dest, &rt.net, &rt.gate);
+ break;
#endif
#ifdef INET6
- case AF_INET6:
- sin6 = (struct sockaddr_in6*)(void *)
- rti_info[RTAX_IFA];
- memcpy(ia6.s6_addr,
- sin6->sin6_addr.s6_addr,
- sizeof(ia6.s6_addr));
- if (rtm->rtm_type == RTM_NEWADDR) {
- ifa_flags = if_addrflags6(
- ifname,
- &ia6);
- if (ifa_flags == -1)
- break;
- } else
- ifa_flags = 0;
- ipv6_handleifa(ctx, rtm->rtm_type, NULL,
- ifname, &ia6, ifa_flags);
- break;
-#endif
- }
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6*)(void *)
+ rti_info[RTAX_IFA];
+ memcpy(ia6.s6_addr,
+ sin6->sin6_addr.s6_addr,
+ sizeof(ia6.s6_addr));
+ if (rtm->rtm_type == RTM_NEWADDR) {
+ ifa_flags = if_addrflags6(ifname, &ia6);
+ if (ifa_flags == -1)
+ break;
+ } else
+ ifa_flags = 0;
+ ipv6_handleifa(ctx, rtm->rtm_type, NULL,
+ ifname, &ia6, ifa_flags);
break;
+#endif
}
+ break;
}
}
+
+ return 0;
}
#ifndef SYS_NMLN /* OSX */
for (;;) {
bytes = recv(fd, NULL, 0,
flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
- if (bytes == -1) {
- if (errno == EAGAIN) {
- r = 0;
- goto eexit;
- }
- if (errno == EINTR)
- continue;
+ if (bytes == -1 || bytes == 0)
goto eexit;
- } else if ((size_t)bytes == buflen) {
+ if ((size_t)bytes == buflen) {
/* Support kernels older than 2.6.22 */
if (bytes == 0)
bytes = 512;
}
bytes = recvfrom(fd, buf, buflen, flags,
(struct sockaddr *)&nladdr, &nladdr_len);
- if (bytes == -1) {
- if (errno == EAGAIN) {
- r = 0;
- goto eexit;
- }
- if (errno == EINTR)
- continue;
+ if (bytes == -1 || bytes == 0)
goto eexit;
- }
/* Check sender */
if (nladdr_len != sizeof(nladdr)) {
#endif
#ifdef SOCK_CLOEXEC
- if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC,
htons(protocol))) == -1)
return -1;
#else
close(s);
return -1;
}
- if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
- fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
- {
- close(s);
- return -1;
- }
#endif
/* Install the DHCP filter */
memset(&pf, 0, sizeof(pf));
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
- void *data, size_t len, int *partialcsum)
+ void *data, size_t len, int *flags)
{
struct iovec iov = {
.iov_base = data,
fd = state->raw_fd;
bytes = recvmsg(fd, &msg, 0);
if (bytes == -1)
- return errno == EAGAIN ? 0 : -1;
- if (partialcsum != NULL) {
- *partialcsum = 0;
+ return -1;
+ if (bytes) {
+ *flags &= ~RAW_PARTIALCSUM;
#ifdef PACKET_AUXDATA
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg;
if (cmsg->cmsg_level == SOL_PACKET &&
cmsg->cmsg_type == PACKET_AUXDATA) {
aux = (void *)CMSG_DATA(cmsg);
- *partialcsum = aux->tp_status &
- TP_STATUS_CSUMNOTREADY;
+ if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
+ *flags |= RAW_PARTIALCSUM;
}
}
#endif