summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2016-05-14 12:57:32 +0000
committerRoy Marples <roy@marples.name>2016-05-14 12:57:32 +0000
commit55314f9874ea04ab2b0603fccb4b2f329b06724e (patch)
tree1cfd31391161f962819c460f61ebe2da26f80048
parent6079f415e7ad06983eb2ad2b34e94d84e475ac7e (diff)
downloaddhcpcd-55314f9874ea04ab2b0603fccb4b2f329b06724e.tar.xz
No point in looping on the raw socket anymore thanks to eloop.
This allows endless DHCP / ARP to be interuptable.
-rw-r--r--arp.c109
-rw-r--r--dhcp.c112
-rw-r--r--if-bsd.c4
-rw-r--r--if-linux.c2
-rw-r--r--if.h3
5 files changed, 106 insertions, 124 deletions
diff --git a/arp.c b/arp.c
index ab313673..64f12371 100644
--- a/arp.c
+++ b/arp.c
@@ -123,7 +123,7 @@ arp_packet(void *arg)
{
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;
@@ -134,65 +134,62 @@ arp_packet(void *arg)
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);
}
}
diff --git a/dhcp.c b/dhcp.c
index 2cd1ac62..fc0a0b2f 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -3100,69 +3100,57 @@ dhcp_handlepacket(void *arg)
/* 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
diff --git a/if-bsd.c b/if-bsd.c
index 86215c78..0f35ce2a 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -522,10 +522,8 @@ if_readraw(struct interface *ifp, int fd, void *data, size_t len, int *flags)
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;
}
diff --git a/if-linux.c b/if-linux.c
index d3d1ec0c..404b2c96 100644
--- a/if-linux.c
+++ b/if-linux.c
@@ -1334,7 +1334,7 @@ if_readraw(__unused struct interface *ifp, int fd,
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);
diff --git a/if.h b/if.h
index 33f05cab..b4a9f983 100644
--- a/if.h
+++ b/if.h
@@ -80,8 +80,7 @@
((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. */