This allows endless DHCP / ARP to be interuptable.
{
struct interface *ifp = arg;
const struct interface *ifn;
- uint8_t arp_buffer[ARP_LEN];
+ uint8_t buf[ARP_LEN];
struct arphdr ar;
struct arp_msg arm;
ssize_t bytes;
state = ARP_STATE(ifp);
flags = 0;
- while (!(flags & RAW_EOF)) {
- bytes = if_readraw(ifp, state->fd,
- arp_buffer, sizeof(arp_buffer), &flags);
- if (bytes == -1) {
- logger(ifp->ctx, LOG_ERR,
- "%s: arp if_readrawpacket: %m", ifp->name);
- arp_close(ifp);
- return;
- }
- /* We must have a full ARP header */
- if ((size_t)bytes < sizeof(ar))
- continue;
- memcpy(&ar, arp_buffer, sizeof(ar));
- /* Families must match */
- if (ar.ar_hrd != htons(ifp->family))
- continue;
+ bytes = if_readraw(ifp, state->fd, buf, sizeof(buf), &flags);
+ if (bytes == -1) {
+ logger(ifp->ctx, LOG_ERR,
+ "%s: arp if_readrawpacket: %m", ifp->name);
+ arp_close(ifp);
+ return;
+ }
+ /* We must have a full ARP header */
+ if ((size_t)bytes < sizeof(ar))
+ return;
+ memcpy(&ar, buf, sizeof(ar));
+ /* Families must match */
+ if (ar.ar_hrd != htons(ifp->family))
+ return;
#if 0
- /* These checks are enforced in the BPF filter. */
- /* Protocol must be IP. */
- if (ar.ar_pro != htons(ETHERTYPE_IP))
- continue;
- /* Only these types are recognised */
- if (ar.ar_op != htons(ARPOP_REPLY) &&
- ar.ar_op != htons(ARPOP_REQUEST))
- continue;
+ /* These checks are enforced in the BPF filter. */
+ /* Protocol must be IP. */
+ if (ar.ar_pro != htons(ETHERTYPE_IP))
+ continue;
+ /* Only these types are recognised */
+ if (ar.ar_op != htons(ARPOP_REPLY) &&
+ ar.ar_op != htons(ARPOP_REQUEST))
+ continue;
#endif
- if (ar.ar_pln != sizeof(arm.sip.s_addr))
- continue;
-
- /* Get pointers to the hardware addreses */
- hw_s = arp_buffer + sizeof(ar);
- hw_t = hw_s + ar.ar_hln + ar.ar_pln;
- /* Ensure we got all the data */
- if ((hw_t + ar.ar_hln + ar.ar_pln) - arp_buffer > bytes)
- continue;
- /* Ignore messages from ourself */
- TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
- if (ar.ar_hln == ifn->hwlen &&
- memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
- break;
- }
- if (ifn) {
+ if (ar.ar_pln != sizeof(arm.sip.s_addr))
+ return;
+
+ /* Get pointers to the hardware addreses */
+ hw_s = buf + sizeof(ar);
+ hw_t = hw_s + ar.ar_hln + ar.ar_pln;
+ /* Ensure we got all the data */
+ if ((hw_t + ar.ar_hln + ar.ar_pln) - buf > bytes)
+ return;
+ /* Ignore messages from ourself */
+ TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+ if (ar.ar_hln == ifn->hwlen &&
+ memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
+ break;
+ }
+ if (ifn) {
#if 0
- logger(ifp->ctx, LOG_DEBUG,
- "%s: ignoring ARP from self", ifp->name);
+ logger(ifp->ctx, LOG_DEBUG,
+ "%s: ignoring ARP from self", ifp->name);
#endif
- continue;
- }
- /* Copy out the HW and IP addresses */
- memcpy(&arm.sha, hw_s, ar.ar_hln);
- memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
- memcpy(&arm.tha, hw_t, ar.ar_hln);
- memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
-
- /* Run the conflicts */
- TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
- if (astate->conflicted_cb)
- astate->conflicted_cb(astate, &arm);
- }
+ return;
+ }
+ /* Copy out the HW and IP addresses */
+ memcpy(&arm.sha, hw_s, ar.ar_hln);
+ memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
+ memcpy(&arm.tha, hw_t, ar.ar_hln);
+ memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
+
+ /* Run the conflicts */
+ TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
+ if (astate->conflicted_cb)
+ astate->conflicted_cb(astate, &arm);
}
}
/* Need this API due to BPF */
flags = 0;
bootp = NULL;
- while (!(flags & RAW_EOF)) {
- bytes = (size_t)if_readraw(ifp, state->raw_fd,
- buf, sizeof(buf), &flags);
- if ((ssize_t)bytes == -1) {
- logger(ifp->ctx, LOG_ERR,
- "%s: dhcp if_readrawpacket: %m", ifp->name);
- dhcp_close(ifp);
- arp_close(ifp);
- break;
- }
- if (valid_udp_packet(buf, bytes,
- &from, flags & RAW_PARTIALCSUM) == -1)
- {
- logger(ifp->ctx, LOG_ERR,
- "%s: invalid UDP packet from %s",
- ifp->name, inet_ntoa(from));
- continue;
- }
- i = whitelisted_ip(ifp->options, from.s_addr);
- if (i == 0) {
- logger(ifp->ctx, LOG_WARNING,
- "%s: non whitelisted DHCP packet from %s",
- ifp->name, inet_ntoa(from));
- continue;
- } else if (i != 1 &&
- blacklisted_ip(ifp->options, from.s_addr) == 1)
- {
- logger(ifp->ctx, LOG_WARNING,
- "%s: blacklisted DHCP packet from %s",
- ifp->name, inet_ntoa(from));
- continue;
- }
- if (ifp->flags & IFF_POINTOPOINT &&
- state->brd.s_addr != from.s_addr)
- {
- logger(ifp->ctx, LOG_WARNING,
- "%s: server %s is not destination",
- ifp->name, inet_ntoa(from));
- }
- /*
- * DHCP has a variable option area rather than a fixed
- * vendor area.
- * Because DHCP uses the BOOTP protocol it should
- * still send BOOTP sized packets to be RFC compliant.
- * However some servers send a truncated vendor area.
- * dhcpcd can work fine without the vendor area being sent.
- */
- bytes = get_udp_data(&bootp, buf);
- if (bytes < offsetof(struct bootp, vend)) {
- logger(ifp->ctx, LOG_ERR,
- "%s: truncated packet (%zu) from %s",
- ifp->name, bytes, inet_ntoa(from));
- continue;
- }
- /* But to make our IS_DHCP macro easy, ensure the vendor
- * area has at least 4 octets. */
- while (bytes < offsetof(struct bootp, vend) + 4)
- bootp[bytes++] = '\0';
-
- dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from);
- if (state->raw_fd == -1)
- break;
+ bytes = (size_t)if_readraw(ifp, state->raw_fd,buf, sizeof(buf), &flags);
+ if ((ssize_t)bytes == -1) {
+ logger(ifp->ctx, LOG_ERR,
+ "%s: dhcp if_readrawpacket: %m", ifp->name);
+ dhcp_close(ifp);
+ arp_close(ifp);
+ return;
}
+ if (valid_udp_packet(buf, bytes, &from, flags & RAW_PARTIALCSUM) == -1)
+ {
+ logger(ifp->ctx, LOG_ERR, "%s: invalid UDP packet from %s",
+ ifp->name, inet_ntoa(from));
+ return;
+ }
+ i = whitelisted_ip(ifp->options, from.s_addr);
+ if (i == 0) {
+ logger(ifp->ctx, LOG_WARNING,
+ "%s: non whitelisted DHCP packet from %s",
+ ifp->name, inet_ntoa(from));
+ return;
+ } else if (i != 1 && blacklisted_ip(ifp->options, from.s_addr) == 1) {
+ logger(ifp->ctx, LOG_WARNING,
+ "%s: blacklisted DHCP packet from %s",
+ ifp->name, inet_ntoa(from));
+ return;
+ }
+ if (ifp->flags & IFF_POINTOPOINT && state->brd.s_addr != from.s_addr) {
+ logger(ifp->ctx, LOG_WARNING,
+ "%s: server %s is not destination",
+ ifp->name, inet_ntoa(from));
+ }
+ /*
+ * DHCP has a variable option area rather than a fixed vendor area.
+ * Because DHCP uses the BOOTP protocol it should still send BOOTP
+ * sized packets to be RFC compliant.
+ * However some servers send a truncated vendor area.
+ * dhcpcd can work fine without the vendor area being sent.
+ */
+ bytes = get_udp_data(&bootp, buf);
+ if (bytes < offsetof(struct bootp, vend)) {
+ logger(ifp->ctx, LOG_ERR,
+ "%s: truncated packet (%zu) from %s",
+ ifp->name, bytes, inet_ntoa(from));
+ return;
+ }
+ /* But to make our IS_DHCP macro easy, ensure the vendor
+ * area has at least 4 octets. */
+ while (bytes < offsetof(struct bootp, vend) + 4)
+ bootp[bytes++] = '\0';
+
+ dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from);
}
static void
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;
}
bytes = recvmsg(fd, &msg, 0);
if (bytes == -1)
return -1;
- *flags = RAW_EOF; /* We only ever read one packet */
+ *flags = 0;
if (bytes) {
#ifdef PACKET_AUXDATA
for (cmsg = CMSG_FIRSTHDR(&msg);
((addr & IN_CLASSB_NET) == 0xc0a80000))
#endif
-#define RAW_EOF 1 << 0
-#define RAW_PARTIALCSUM 2 << 0
+#define RAW_PARTIALCSUM 1 << 0
#ifdef __sun
/* platform does not supply AF_LINK with getifaddrs. */