]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
DHCP messages are really BOOTP so lets name the structure accordingly.
authorRoy Marples <roy@marples.name>
Fri, 6 May 2016 13:26:41 +0000 (13:26 +0000)
committerRoy Marples <roy@marples.name>
Fri, 6 May 2016 13:26:41 +0000 (13:26 +0000)
While here, stop making assumptions about the size of a DHCP packet based
on a fixed structure from a default MTU of 1500.
Instead, make it flexable and set the DHCP packet size to the interface MTU
less UDP and IP headers.
As a result, we need to know the size of the DHCP packet received
rather than just walking the old fixed DHCP message structure.

This makes Coverity happy about tainted scalar values when parsing DHCP
messages.

auth.c
dhcp.c
dhcp.h
dhcpcd.c
dhcpcd.h
if-bsd.c
ipv4.c
script.c

diff --git a/auth.c b/auth.c
index b24f75723c9db6724a757a4ae33cad925adfc7ee..4a6d7ea60b1bf37e58c9c9bbbdb712079bc04c01 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -320,8 +320,8 @@ gottoken:
 
        /* RFC3318, section 5.2 - zero giaddr and hops */
        if (mp == 4) {
-               *(mm + offsetof(struct dhcp_message, hwopcount)) = '\0';
-               memset(mm + offsetof(struct dhcp_message, giaddr), 0, 4);
+               *(mm + offsetof(struct bootp, hops)) = '\0';
+               memset(mm + offsetof(struct bootp, giaddr), 0, 4);
        }
 
        memset(hmac, 0, sizeof(hmac));
@@ -638,10 +638,10 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
 
        /* RFC3318, section 5.2 - zero giaddr and hops */
        if (mp == 4) {
-               p = m + offsetof(struct dhcp_message, hwopcount);
+               p = m + offsetof(struct bootp, hops);
                hops = *p;
                *p = '\0';
-               p = m + offsetof(struct dhcp_message, giaddr);
+               p = m + offsetof(struct bootp, giaddr);
                memcpy(&giaddr, p, sizeof(giaddr));
                memset(p, 0, sizeof(giaddr));
        } else {
@@ -660,9 +660,9 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
 
        /* RFC3318, section 5.2 - restore giaddr and hops */
        if (mp == 4) {
-               p = m + offsetof(struct dhcp_message, hwopcount);
+               p = m + offsetof(struct bootp, hops);
                *p = hops;
-               p = m + offsetof(struct dhcp_message, giaddr);
+               p = m + offsetof(struct bootp, giaddr);
                memcpy(p, &giaddr, sizeof(giaddr));
        }
 
diff --git a/dhcp.c b/dhcp.c
index 99c878c7ca041f6cc03f3b496e3d0f02d45f69d3..089502f2a69df354910599643b7cbc8eaeb7cc3f 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -110,14 +110,12 @@ static const char * const dhcp_params[] = {
        NULL
 };
 
-struct udp_dhcp_packet
+struct udp_bootp_packet
 {
        struct ip ip;
        struct udphdr udp;
-       struct dhcp_message dhcp;
-};
-
-static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
+       uint8_t bootp[];
+} __packed;
 
 static int dhcp_open(struct interface *);
 static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *);
@@ -149,26 +147,30 @@ dhcp_printoptions(const struct dhcpcd_ctx *ctx,
        }
 }
 
-#define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL)
+#define get_option_raw(ctx, bootp, bootp_len, opt)     \
+       get_option((ctx), (bootp), (bootp_len), NULL)
 static const uint8_t *
 get_option(struct dhcpcd_ctx *ctx,
-    const struct dhcp_message *dhcp, unsigned int opt, size_t *len)
+    const struct bootp *bootp, size_t bootp_len,
+    unsigned int opt, size_t *opt_len)
 {
-       const uint8_t *p = dhcp->options;
-       const uint8_t *e = p + sizeof(dhcp->options);
-       uint8_t l, ol = 0;
-       uint8_t o = 0;
-       uint8_t overl = 0;
-       uint8_t *bp = NULL;
-       const uint8_t *op = NULL;
-       size_t bl = 0;
+       const uint8_t *p, *e;
+       uint8_t l, o, ol, overl, *bp;
+       const uint8_t *op;
+       size_t bl;
 
        /* Check we have the magic cookie */
-       if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
+       if (!IS_DHCP(bootp)) {
                errno = ENOTSUP;
                return NULL;
        }
 
+       p = bootp->vend + 4; /* options after the 4 byte cookie */
+       e = (const uint8_t *)bootp + bootp_len;
+       ol = o = overl = 0;
+       bp = NULL;
+       op = NULL;
+       bl = 0;
        while (p < e) {
                o = *p++;
                switch (o) {
@@ -179,13 +181,13 @@ get_option(struct dhcpcd_ctx *ctx,
                        if (overl & 1) {
                                /* bit 1 set means parse boot file */
                                overl = (uint8_t)(overl & ~1);
-                               p = dhcp->bootfile;
-                               e = p + sizeof(dhcp->bootfile);
+                               p = bootp->file;
+                               e = p + sizeof(bootp->file);
                        } else if (overl & 2) {
                                /* bit 2 set means parse server name */
                                overl = (uint8_t)(overl & ~2);
-                               p = dhcp->servername;
-                               e = p + sizeof(dhcp->servername);
+                               p = bootp->sname;
+                               e = p + sizeof(bootp->sname);
                        } else
                                goto exit;
                        /* No length to read */
@@ -210,14 +212,29 @@ get_option(struct dhcpcd_ctx *ctx,
 
                if (o == opt) {
                        if (op) {
-                               if (!ctx->opt_buffer) {
-                                       ctx->opt_buffer =
-                                           malloc(DHCP_OPTION_LEN +
-                                           BOOTFILE_LEN + SERVERNAME_LEN);
-                                       if (ctx->opt_buffer == NULL)
+                               /* We must concatonate the options. */
+                               if ((bp && ctx->opt_buffer &&
+                                   (size_t)(bp - ctx->opt_buffer) + ol >
+                                   ctx->opt_buffer_len) ||
+                                   ol > ctx->opt_buffer_len)
+                               {
+                                       size_t pos;
+                                       uint8_t *nb;
+
+                                       if (bp)
+                                               pos = (size_t)
+                                                   (bp - ctx->opt_buffer);
+                                       else
+                                               pos = 0;
+                                       nb = realloc(ctx->opt_buffer,
+                                           ctx->opt_buffer_len + ol);
+                                       if (nb == NULL)
                                                return NULL;
+                                       ctx->opt_buffer = nb;
+                                       ctx->opt_buffer_len += ol;
+                                       bp = ctx->opt_buffer + pos;
                                }
-                               if (!bp)
+                               if (bp == NULL)
                                        bp = ctx->opt_buffer;
                                memcpy(bp, op, ol);
                                bp += ol;
@@ -234,8 +251,8 @@ get_option(struct dhcpcd_ctx *ctx,
        }
 
 exit:
-       if (len)
-               *len = bl;
+       if (opt_len)
+               *opt_len = bl;
        if (bp) {
                memcpy(bp, op, ol);
                return (const uint8_t *)ctx->opt_buffer;
@@ -246,15 +263,15 @@ exit:
        return NULL;
 }
 
-int
+static int
 get_option_addr(struct dhcpcd_ctx *ctx,
-    struct in_addr *a, const struct dhcp_message *dhcp,
+    struct in_addr *a, const struct bootp *bootp, size_t bootp_len,
     uint8_t option)
 {
        const uint8_t *p;
        size_t len;
 
-       p = get_option(ctx, dhcp, option, &len);
+       p = get_option(ctx, bootp, bootp_len, option, &len);
        if (!p || len < (ssize_t)sizeof(a->s_addr))
                return -1;
        memcpy(&a->s_addr, p, sizeof(a->s_addr));
@@ -263,13 +280,13 @@ get_option_addr(struct dhcpcd_ctx *ctx,
 
 static int
 get_option_uint32(struct dhcpcd_ctx *ctx,
-    uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
+    uint32_t *i, const struct bootp *bootp, size_t bootp_len, uint8_t option)
 {
        const uint8_t *p;
        size_t len;
        uint32_t d;
 
-       p = get_option(ctx, dhcp, option, &len);
+       p = get_option(ctx, bootp, bootp_len, option, &len);
        if (!p || len < (ssize_t)sizeof(d))
                return -1;
        memcpy(&d, p, sizeof(d));
@@ -280,13 +297,13 @@ get_option_uint32(struct dhcpcd_ctx *ctx,
 
 static int
 get_option_uint16(struct dhcpcd_ctx *ctx,
-    uint16_t *i, const struct dhcp_message *dhcp, uint8_t option)
+    uint16_t *i, const struct bootp *bootp, size_t bootp_len, uint8_t option)
 {
        const uint8_t *p;
        size_t len;
        uint16_t d;
 
-       p = get_option(ctx, dhcp, option, &len);
+       p = get_option(ctx, bootp, bootp_len, option, &len);
        if (!p || len < (ssize_t)sizeof(d))
                return -1;
        memcpy(&d, p, sizeof(d));
@@ -297,12 +314,12 @@ get_option_uint16(struct dhcpcd_ctx *ctx,
 
 static int
 get_option_uint8(struct dhcpcd_ctx *ctx,
-    uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
+    uint8_t *i, const struct bootp *bootp, size_t bootp_len, uint8_t option)
 {
        const uint8_t *p;
        size_t len;
 
-       p = get_option(ctx, dhcp, option, &len);
+       p = get_option(ctx, bootp, bootp_len, option, &len);
        if (!p || len < (ssize_t)sizeof(*p))
                return -1;
        if (i)
@@ -485,13 +502,13 @@ decode_rfc3361(const uint8_t *data, size_t dl)
 
 static char *
 get_option_string(struct dhcpcd_ctx *ctx,
-    const struct dhcp_message *dhcp, uint8_t option)
+    const struct bootp *bootp, size_t bootp_len, uint8_t option)
 {
        size_t len;
        const uint8_t *p;
        char *s;
 
-       p = get_option(ctx, dhcp, option, &len);
+       p = get_option(ctx, bootp, bootp_len, option, &len);
        if (!p || len == 0 || *p == '\0')
                return NULL;
 
@@ -536,7 +553,8 @@ route_netmask(uint32_t ip_in)
  * If we have a CSR then we only use that.
  * Otherwise we add static routes and then routers. */
 static struct rt_head *
-get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
+get_option_routes(struct interface *ifp,
+    const struct bootp *bootp, size_t bootp_len)
 {
        struct if_options *ifo = ifp->options;
        const uint8_t *p;
@@ -548,12 +566,12 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 
        /* If we have CSR's then we MUST use these only */
        if (!has_option_mask(ifo->nomask, DHO_CSR))
-               p = get_option(ifp->ctx, dhcp, DHO_CSR, &len);
+               p = get_option(ifp->ctx, bootp, bootp_len, DHO_CSR, &len);
        else
                p = NULL;
        /* Check for crappy MS option */
        if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) {
-               p = get_option(ifp->ctx, dhcp, DHO_MSCSR, &len);
+               p = get_option(ifp->ctx, bootp, bootp_len, DHO_MSCSR, &len);
                if (p)
                        csr = "MS ";
        }
@@ -583,7 +601,8 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
        }
        TAILQ_INIT(routes);
        if (!has_option_mask(ifo->nomask, DHO_STATICROUTE))
-               p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len);
+               p = get_option(ifp->ctx, bootp, bootp_len,
+                   DHO_STATICROUTE, &len);
        else
                p = NULL;
        /* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */
@@ -609,7 +628,7 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
                        /* A host route is normally set by having the
                         * gateway match the destination or assigned address */
                        if (route->gate.s_addr == route->dest.s_addr ||
-                           route->gate.s_addr == dhcp->yiaddr)
+                           route->gate.s_addr == bootp->yiaddr)
                        {
                                route->gate.s_addr = htonl(INADDR_ANY);
                                route->net.s_addr = htonl(INADDR_BROADCAST);
@@ -622,7 +641,7 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 
        /* Now grab our routers */
        if (!has_option_mask(ifo->nomask, DHO_ROUTER))
-               p = get_option(ifp->ctx, dhcp, DHO_ROUTER, &len);
+               p = get_option(ifp->ctx, bootp, bootp_len, DHO_ROUTER, &len);
        else
                p = NULL;
        if (p) {
@@ -645,15 +664,16 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 uint16_t
 dhcp_get_mtu(const struct interface *ifp)
 {
-       const struct dhcp_message *dhcp;
+       const struct dhcp_state *state;
        uint16_t mtu;
 
        if (ifp->options->mtu)
                return (uint16_t)ifp->options->mtu;
        mtu = 0; /* bogus gcc warning */
-       if ((dhcp = D_CSTATE(ifp)->new) == NULL ||
+       if ((state = D_CSTATE(ifp)) == NULL ||
            has_option_mask(ifp->options->nomask, DHO_MTU) ||
-           get_option_uint16(ifp->ctx, &mtu, dhcp, DHO_MTU) == -1)
+           get_option_uint16(ifp->ctx, &mtu,
+                             state->new, state->new_len, DHO_MTU) == -1)
                return 0;
        return mtu;
 }
@@ -665,10 +685,10 @@ dhcp_get_routes(struct interface *ifp)
 {
        struct rt_head *routes;
        uint16_t mtu;
-       const struct dhcp_message *dhcp;
+       const struct dhcp_state *state;
 
-       dhcp = D_CSTATE(ifp)->new;
-       routes = get_option_routes(ifp, dhcp);
+       state = D_CSTATE(ifp);
+       routes = get_option_routes(ifp, state->new, state->new_len);
        if ((mtu = dhcp_get_mtu(ifp)) != 0) {
                struct rt *rt;
 
@@ -679,45 +699,39 @@ dhcp_get_routes(struct interface *ifp)
        return routes;
 }
 
-#define PUTADDR(_type, _val)                                                 \
-       {                                                                     \
-               *p++ = _type;                                                 \
-               *p++ = 4;                                                     \
-               memcpy(p, &_val.s_addr, 4);                                   \
-               p += 4;                                                       \
-       }
-
-int
-dhcp_message_add_addr(struct dhcp_message *dhcp,
+/* Assumes DHCP options */
+static int
+dhcp_message_add_addr(struct bootp *bootp,
     uint8_t type, struct in_addr addr)
 {
        uint8_t *p;
        size_t len;
 
-       p = dhcp->options;
+       p = bootp->vend;
        while (*p != DHO_END) {
                p++;
                p += *p + 1;
        }
 
-       len = (size_t)(p - (uint8_t *)dhcp);
-       if (len + 6 > sizeof(*dhcp)) {
+       len = (size_t)(p - bootp->vend);
+       if (len + 6 > sizeof(bootp->vend)) {
                errno = ENOMEM;
                return -1;
        }
 
-       PUTADDR(type, addr);
+       *p++ = type;
+       *p++ = 4;
+       memcpy(p, &addr.s_addr, 4);
+       p += 4;
        *p = DHO_END;
        return 0;
 }
 
-ssize_t
-make_message(struct dhcp_message **message,
-    const struct interface *ifp,
-    uint8_t type)
+static ssize_t
+make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
 {
-       struct dhcp_message *dhcp;
-       uint8_t *m, *lp, *p, *auth;
+       struct bootp *bootp;
+       uint8_t *lp, *p, *e, *auth;
        uint8_t *n_params = NULL, auth_len;
        uint32_t ul;
        uint16_t sz;
@@ -729,61 +743,95 @@ make_message(struct dhcp_message **message,
        char hbuf[HOSTNAME_MAX_LEN + 1];
        const char *hostname;
        const struct vivco *vivco;
+       int mtu;
 
-       dhcp = calloc(1, sizeof (*dhcp));
-       if (dhcp == NULL)
+       if ((mtu = if_getmtu(ifp)) == -1)
+               logger(ifp->ctx, LOG_ERR,
+                   "%s: if_getmtu: %m", ifp->name);
+       else if (mtu < MTU_MIN) {
+               if (if_setmtu(ifp, MTU_MIN) == -1)
+                       logger(ifp->ctx, LOG_ERR,
+                           "%s: if_setmtu: %m", ifp->name);
+               mtu = MTU_MIN;
+       }
+
+       if (ifo->options & DHCPCD_BOOTP)
+               bootp = calloc(1, sizeof (*bootp));
+       else
+               /* Make the maximal message we could send */
+               bootp = calloc(1, (size_t)(mtu - IP_UDP_SIZE));
+
+       if (bootp == NULL)
                return -1;
-       m = (uint8_t *)dhcp;
-       p = dhcp->options;
+       *bootpm = bootp;
 
        if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
-               (type == DHCP_REQUEST &&
-                   state->net.s_addr == lease->net.s_addr &&
-                   (state->new == NULL ||
-                       state->new->cookie == htonl(MAGIC_COOKIE)))))
+           (type == DHCP_REQUEST && state->net.s_addr == lease->net.s_addr &&
+           (state->new == NULL || IS_DHCP(state->new)))))
        {
-               dhcp->ciaddr = state->addr.s_addr;
                /* In-case we haven't actually configured the address yet */
                if (type == DHCP_INFORM && state->addr.s_addr == 0)
-                       dhcp->ciaddr = lease->addr.s_addr;
+                       bootp->ciaddr = lease->addr.s_addr;
+               else
+                       bootp->ciaddr = state->addr.s_addr;
        }
 
-       dhcp->op = DHCP_BOOTREQUEST;
-       dhcp->hwtype = (uint8_t)ifp->family;
+       bootp->op = DHCP_BOOTREQUEST;
+       bootp->htype = (uint8_t)ifp->family;
        switch (ifp->family) {
        case ARPHRD_ETHER:
        case ARPHRD_IEEE802:
-               dhcp->hwlen = (uint8_t)ifp->hwlen;
-               memcpy(&dhcp->chaddr, &ifp->hwaddr, ifp->hwlen);
+               bootp->hlen = (uint8_t)ifp->hwlen;
+               memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen);
                break;
        }
 
        if (ifo->options & DHCPCD_BROADCAST &&
-           dhcp->ciaddr == 0 &&
+           bootp->ciaddr == 0 &&
            type != DHCP_DECLINE &&
            type != DHCP_RELEASE)
-               dhcp->flags = htons(BROADCAST_FLAG);
-
+               bootp->flags = htons(BROADCAST_FLAG);
+#if 0
        if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
                struct timespec tv;
 
                clock_gettime(CLOCK_MONOTONIC, &tv);
                timespecsub(&tv, &state->started, &tv);
                if (tv.tv_sec < 0 || tv.tv_sec > (time_t)UINT16_MAX)
-                       dhcp->secs = htons((uint16_t)UINT16_MAX);
+                       bootp->secs = htons((uint16_t)UINT16_MAX);
                else
-                       dhcp->secs = htons((uint16_t)tv.tv_sec);
+                       bootp->secs = htons((uint16_t)tv.tv_sec);
        }
-       dhcp->xid = htonl(state->xid);
-       dhcp->cookie = htonl(MAGIC_COOKIE);
+#endif
+       bootp->xid = htonl(state->xid);
 
-       if (!(ifo->options & DHCPCD_BOOTP)) {
-               *p++ = DHO_MESSAGETYPE;
-               *p++ = 1;
-               *p++ = type;
-       }
+       if (ifo->options & DHCPCD_BOOTP)
+               return sizeof(*bootp);
+
+       p = bootp->vend;
+       e = (uint8_t *)bootp + (mtu - IP_UDP_SIZE) - 1; /* -1 for DHO_END */
+
+       ul = htonl(MAGIC_COOKIE);
+       memcpy(p, &ul, sizeof(ul));
+       p += sizeof(ul);
+
+       *p++ = DHO_MESSAGETYPE;
+       *p++ = 1;
+       *p++ = type;
+
+#define AREA_LEFT      (size_t)(e - p)
+#define AREA_FIT(s)    if ((s) > AREA_LEFT) goto toobig;
+#define AREA_CHECK(s)  if ((s) + 2UL > AREA_LEFT) goto toobig;
+#define PUT_ADDR(o, a) do {            \
+       AREA_CHECK(4);                  \
+       *p++ = (o);                     \
+       *p++ = 4;                       \
+       memcpy(p, &(a)->s_addr, 4);     \
+       p += 4;                         \
+} while (0 /* CONSTCOND */)
 
        if (state->clientid) {
+               AREA_CHECK(state->clientid[0]);
                *p++ = DHO_CLIENTID;
                memcpy(p, state->clientid, (size_t)state->clientid[0] + 1);
                p += state->clientid[0] + 1;
@@ -794,23 +842,25 @@ make_message(struct dhcp_message **message,
                    (type == DHCP_REQUEST &&
                        lease->addr.s_addr != state->addr.s_addr))
                {
-                       PUTADDR(DHO_IPADDRESS, lease->addr);
+                       PUT_ADDR(DHO_IPADDRESS, &lease->addr);
                        if (lease->server.s_addr)
-                               PUTADDR(DHO_SERVERID, lease->server);
+                               PUT_ADDR(DHO_SERVERID, &lease->server);
                }
 
                if (type == DHCP_RELEASE) {
                        if (lease->server.s_addr)
-                               PUTADDR(DHO_SERVERID, lease->server);
+                               PUT_ADDR(DHO_SERVERID, &lease->server);
                }
        }
 
        if (type == DHCP_DECLINE) {
-               *p++ = DHO_MESSAGE;
                len = strlen(DAD);
-               *p++ = (uint8_t)len;
-               memcpy(p, DAD, len);
-               p += len;
+               if (len > AREA_LEFT) {
+                       *p++ = DHO_MESSAGE;
+                       *p++ = (uint8_t)len;
+                       memcpy(p, DAD, len);
+                       p += len;
+               }
        }
 
        if (type == DHCP_DISCOVER &&
@@ -818,15 +868,17 @@ make_message(struct dhcp_message **message,
            has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
        {
                /* RFC 4039 Section 3 */
+               AREA_CHECK(0);
                *p++ = DHO_RAPIDCOMMIT;
                *p++ = 0;
        }
 
        if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
-               PUTADDR(DHO_IPADDRESS, ifo->req_addr);
+               PUT_ADDR(DHO_IPADDRESS, &ifo->req_addr);
 
        /* RFC 2563 Auto Configure */
        if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL) {
+               AREA_CHECK(1);
                *p++ = DHO_AUTOCONFIGURE;
                *p++ = 1;
                *p++ = 1;
@@ -836,33 +888,17 @@ make_message(struct dhcp_message **message,
            type == DHCP_INFORM ||
            type == DHCP_REQUEST)
        {
-               if (!(ifo->options & DHCPCD_BOOTP)) {
-                       int mtu;
-
-                       if ((mtu = if_getmtu(ifp)) == -1)
-                               logger(ifp->ctx, LOG_ERR,
-                                   "%s: if_getmtu: %m", ifp->name);
-                       else if (mtu < MTU_MIN) {
-                               if (if_setmtu(ifp, MTU_MIN) == -1)
-                                       logger(ifp->ctx, LOG_ERR,
-                                           "%s: if_setmtu: %m", ifp->name);
-                               mtu = MTU_MIN;
-                       } else if (mtu > MTU_MAX) {
-                               /* Even though our MTU could be greater than
-                                * MTU_MAX (1500) dhcpcd does not presently
-                                * handle DHCP packets any bigger. */
-                               mtu = MTU_MAX;
-                       }
-                       if (mtu != -1) {
-                               *p++ = DHO_MAXMESSAGESIZE;
-                               *p++ = 2;
-                               sz = htons((uint16_t)mtu);
-                               memcpy(p, &sz, 2);
-                               p += 2;
-                       }
+               if (mtu != -1) {
+                       AREA_CHECK(2);
+                       *p++ = DHO_MAXMESSAGESIZE;
+                       *p++ = 2;
+                       sz = htons((uint16_t)mtu - IP_UDP_SIZE);
+                       memcpy(p, &sz, 2);
+                       p += 2;
                }
 
                if (ifo->userclass[0]) {
+                       AREA_CHECK(ifo->userclass[0]);
                        *p++ = DHO_USERCLASS;
                        memcpy(p, ifo->userclass,
                            (size_t)ifo->userclass[0] + 1);
@@ -870,6 +906,7 @@ make_message(struct dhcp_message **message,
                }
 
                if (ifo->vendorclassid[0]) {
+                       AREA_CHECK(ifo->vendorclassid[0]);
                        *p++ = DHO_VENDORCLASSID;
                        memcpy(p, ifo->vendorclassid,
                            (size_t)ifo->vendorclassid[0] + 1);
@@ -878,6 +915,7 @@ make_message(struct dhcp_message **message,
 
                if (type != DHCP_INFORM) {
                        if (ifo->leasetime != 0) {
+                               AREA_CHECK(4);
                                *p++ = DHO_LEASETIME;
                                *p++ = 4;
                                ul = htonl(ifo->leasetime);
@@ -898,9 +936,12 @@ make_message(struct dhcp_message **message,
                 */
                if (ifo->fqdn != FQDN_DISABLE) {
                        /* IETF DHC-FQDN option (81), RFC4702 */
+                       i = 3;
+                       if (hostname)
+                               i += encode_rfc1035(hostname, NULL);
+                       AREA_CHECK(i);
                        *p++ = DHO_FQDN;
-                       lp = p;
-                       *p++ = 3;
+                       *p++ = (uint8_t)i;
                        /*
                         * Flags: 0000NEOS
                         * S: 1 => Client requests Server to update
@@ -919,12 +960,12 @@ make_message(struct dhcp_message **message,
                        *p++ = 0; /* from server for A RR if S=1 */
                        if (hostname) {
                                i = encode_rfc1035(hostname, p);
-                               *lp = (uint8_t)(*lp + i);
                                p += i;
                        }
                } else if (ifo->options & DHCPCD_HOSTNAME && hostname) {
-                       *p++ = DHO_HOSTNAME;
                        len = strlen(hostname);
+                       AREA_CHECK(len);
+                       *p++ = DHO_HOSTNAME;
                        *p++ = (uint8_t)len;
                        memcpy(p, hostname, len);
                        p += len;
@@ -932,6 +973,7 @@ make_message(struct dhcp_message **message,
 
                /* vendor is already encoded correctly, so just add it */
                if (ifo->vendor[0]) {
+                       AREA_CHECK(ifo->vendor[0]);
                        *p++ = DHO_VENDOR;
                        memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1);
                        p += ifo->vendor[0] + 1;
@@ -941,12 +983,14 @@ make_message(struct dhcp_message **message,
                    DHCPCD_AUTH_SENDREQUIRE)
                {
                        /* We support HMAC-MD5 */
+                       AREA_CHECK(1);
                        *p++ = DHO_FORCERENEW_NONCE;
                        *p++ = 1;
                        *p++ = AUTH_ALG_HMAC_MD5;
                }
 
                if (ifo->vivco_len) {
+                       AREA_CHECK(sizeof(ul));
                        *p++ = DHO_VIVCO;
                        lp = p++;
                        *lp = sizeof(ul);
@@ -957,14 +1001,12 @@ make_message(struct dhcp_message **message,
                            i < ifo->vivco_len;
                            i++, vivco++)
                        {
-                               len = (size_t)(p - m) + vivco->len + 1;
-                               if (len > sizeof(*dhcp))
-                                       goto toobig;
+                               AREA_FIT(vivco->len);
                                if (vivco->len + 2 + *lp > 255) {
                                        logger(ifp->ctx, LOG_ERR,
                                            "%s: VIVCO option too big",
                                            ifp->name);
-                                       free(dhcp);
+                                       free(bootp);
                                        return -1;
                                }
                                *p++ = (uint8_t)vivco->len;
@@ -974,9 +1016,7 @@ make_message(struct dhcp_message **message,
                        }
                }
 
-               len = (size_t)((p - m) + 3);
-               if (len > sizeof(*dhcp))
-                       goto toobig;
+               AREA_CHECK(0);
                *p++ = DHO_PARAMETERREQUESTLIST;
                n_params = p;
                *p++ = 0;
@@ -993,9 +1033,7 @@ make_message(struct dhcp_message **message,
                            (opt->option == DHO_RENEWALTIME ||
                                opt->option == DHO_REBINDTIME))
                                continue;
-                       len = (size_t)((p - m) + 2);
-                       if (len > sizeof(*dhcp))
-                               goto toobig;
+                       AREA_FIT(1);
                        *p++ = (uint8_t)opt->option;
                }
                for (i = 0, opt = ifo->dhcp_override;
@@ -1017,9 +1055,7 @@ make_message(struct dhcp_message **message,
                            (opt->option == DHO_RENEWALTIME ||
                                opt->option == DHO_REBINDTIME))
                                continue;
-                       len = (size_t)((p - m) + 2);
-                       if (len > sizeof(*dhcp))
-                               goto toobig;
+                       AREA_FIT(1);
                        *p++ = (uint8_t)opt->option;
                }
                *n_params = (uint8_t)(p - n_params - 1);
@@ -1042,9 +1078,7 @@ make_message(struct dhcp_message **message,
                            "%s: dhcp_auth_encode: %m", ifp->name);
                else if (alen != 0) {
                        auth_len = (uint8_t)alen;
-                       len = (size_t)((p + alen) - m);
-                       if (len > sizeof(*dhcp))
-                               goto toobig;
+                       AREA_CHECK(auth_len);
                        *p++ = DHO_AUTHENTICATION;
                        *p++ = auth_len;
                        auth = p;
@@ -1053,35 +1087,32 @@ make_message(struct dhcp_message **message,
        }
 
        *p++ = DHO_END;
+       len = (size_t)(p - (uint8_t *)bootp);
 
        /* Pad out to the BOOTP minimum message length.
         * Some DHCP servers incorrectly require this. */
-       while (p - m < BOOTP_MESSAGE_LENTH_MIN)
+       while (len < BOOTP_MESSAGE_LENTH_MIN) {
                *p++ = DHO_PAD;
+               len++;
+       }
 
-       len = (size_t)(p - m);
        if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0)
                dhcp_auth_encode(&ifo->auth, state->auth.token,
-                   m, len, 4, type, auth, auth_len);
+                   (uint8_t *)bootp, len, 4, type, auth, auth_len);
 
-       *message = dhcp;
        return (ssize_t)len;
 
 toobig:
        logger(ifp->ctx, LOG_ERR, "%s: DHCP messge too big", ifp->name);
-       free(dhcp);
+       free(bootp);
        return -1;
 }
 
 static ssize_t
-write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
+write_lease(const struct interface *ifp, const struct bootp *bootp, size_t len)
 {
        int fd;
-       size_t len;
        ssize_t bytes;
-       const uint8_t *e, *p;
-       uint8_t l;
-       uint8_t o = 0;
        const struct dhcp_state *state = D_CSTATE(ifp);
 
        logger(ifp->ctx, LOG_DEBUG, "%s: writing lease `%s'",
@@ -1090,40 +1121,26 @@ write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
        fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd == -1)
                return -1;
-
-       /* Only write as much as we need */
-       p = dhcp->options;
-       e = p + sizeof(dhcp->options);
-       len = sizeof(*dhcp);
-       while (p < e) {
-               o = *p;
-               if (o == DHO_END) {
-                       len = (size_t)(p - (const uint8_t *)dhcp);
-                       break;
-               }
-               p++;
-               if (o != DHO_PAD) {
-                       l = *p++;
-                       p += l;
-               }
-       }
-       bytes = write(fd, dhcp, len);
+       bytes = write(fd, bootp, len);
        close(fd);
        return bytes;
 }
 
-static struct dhcp_message *
-read_lease(struct interface *ifp)
+static size_t
+read_lease(struct interface *ifp, struct bootp **bootp)
 {
        int fd;
        bool fd_opened;
-       void *dhcp;
        struct dhcp_state *state = D_STATE(ifp);
-       ssize_t bytes;
+       uint8_t *lease;
+       size_t bytes;
        const uint8_t *auth;
        uint8_t type;
        size_t auth_len;
 
+       /* Safety */
+       *bootp = NULL;
+
        if (state->leasefile[0] == '\0') {
                fd = fileno(stdin);
                fd_opened = false;
@@ -1135,50 +1152,49 @@ read_lease(struct interface *ifp)
                if (errno != ENOENT)
                        logger(ifp->ctx, LOG_ERR, "%s: open `%s': %m",
                            ifp->name, state->leasefile);
-               return NULL;
+               return 0;
        }
        if (state->leasefile[0] == '\0')
                logger(ifp->ctx, LOG_DEBUG, "reading standard input");
        else
                logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'",
                    ifp->name, state->leasefile);
-       dhcp = calloc(1, sizeof(struct dhcp_message));
-       if (dhcp == NULL) {
-               if (fd_opened)
-                       close(fd);
-               return NULL;
-       }
-       bytes = read(fd, dhcp, sizeof(struct dhcp_message));
+
+       bytes = dhcp_read_lease_fd(fd, &lease);
        if (fd_opened)
                close(fd);
-       if (bytes == -1) {
-               free(dhcp);
-               return NULL;
+       if (bytes == 0) {
+               free(lease);
+               logger(ifp->ctx, LOG_ERR,
+                   "%s: dhcp_read_lease_fd: %m", __func__);
+               return 0;
        }
-       if ((size_t)bytes < offsetof(struct dhcp_message, cookie)) {
-               free(dhcp);
-               errno = EINVAL;
-               return NULL;
+
+       if (bytes < sizeof(**bootp)) {
+               free(lease);
+               logger(ifp->ctx, LOG_ERR, "%s: truncated lease", __func__);
+               return 0;
        }
 
        if (ifp->ctx->options & DHCPCD_DUMPLEASE)
-               return dhcp;
+               goto out;
 
        /* We may have found a BOOTP server */
-       if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
+       if (get_option_uint8(ifp->ctx, &type, (struct bootp *)lease, bytes,
+           DHO_MESSAGETYPE) == -1)
                type = 0;
 
        /* Authenticate the message */
-       auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
+       auth = get_option(ifp->ctx, (struct bootp *)lease, bytes,
+           DHO_AUTHENTICATION, &auth_len);
        if (auth) {
                if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
-                   dhcp, sizeof(struct dhcp_message), 4, type,
-                   auth, auth_len) == NULL)
+                   lease, bytes, 4, type, auth, auth_len) == NULL)
                {
                        logger(ifp->ctx, LOG_DEBUG,
                            "%s: dhcp_auth_validate: %m", ifp->name);
-                       free(dhcp);
-                       return NULL;
+                       free(lease);
+                       return 0;
                }
                if (state->auth.token)
                        logger(ifp->ctx, LOG_DEBUG,
@@ -1192,11 +1208,13 @@ read_lease(struct interface *ifp)
        {
                logger(ifp->ctx, LOG_ERR,
                    "%s: authentication now required", ifp->name);
-               free(dhcp);
-               return NULL;
+               free(lease);
+               return 0;
        }
 
-       return dhcp;
+out:
+       *bootp = (struct bootp *)lease;
+       return bytes;
 }
 
 static const struct dhcp_opt *
@@ -1249,7 +1267,8 @@ dhcp_getoption(struct dhcpcd_ctx *ctx,
 }
 
 ssize_t
-dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
+dhcp_env(char **env, const char *prefix,
+    const struct bootp *bootp, size_t bootp_len,
     const struct interface *ifp)
 {
        const struct if_options *ifo;
@@ -1260,21 +1279,22 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        struct dhcp_opt *opt, *vo;
        size_t e, i, pl;
        char **ep;
-       char cidr[4], safe[(BOOTFILE_LEN * 4) + 1];
+       char cidr[4], safe[(BOOTP_FILE_LEN * 4) + 1];
        uint8_t overl = 0;
        uint32_t en;
 
        e = 0;
        ifo = ifp->options;
-       if (get_option_uint8(ifp->ctx, &overl, dhcp, DHO_OPTSOVERLOADED) == -1)
+       if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len,
+           DHO_OPTSOVERLOADED) == -1)
                overl = 0;
 
        if (env == NULL) {
-               if (dhcp->yiaddr || dhcp->ciaddr)
+               if (bootp->yiaddr || bootp->ciaddr)
                        e += 5;
-               if (*dhcp->bootfile && !(overl & 1))
+               if (*bootp->file && !(overl & 1))
                        e++;
-               if (*dhcp->servername && !(overl & 2))
+               if (*bootp->sname && !(overl & 2))
                        e++;
                for (i = 0, opt = ifp->ctx->dhcp_opts;
                    i < ifp->ctx->dhcp_opts_len;
@@ -1284,7 +1304,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                                continue;
                        if (dhcp_getoverride(ifo, opt->option))
                                continue;
-                       p = get_option(ifp->ctx, dhcp, opt->option, &pl);
+                       p = get_option(ifp->ctx, bootp, bootp_len,
+                           opt->option, &pl);
                        if (!p)
                                continue;
                        e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
@@ -1296,7 +1317,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                {
                        if (has_option_mask(ifo->nomask, opt->option))
                                continue;
-                       p = get_option(ifp->ctx, dhcp, opt->option, &pl);
+                       p = get_option(ifp->ctx, bootp, bootp_len,
+                           opt->option, &pl);
                        if (!p)
                                continue;
                        e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
@@ -1306,13 +1328,13 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        }
 
        ep = env;
-       if (dhcp->yiaddr || dhcp->ciaddr) {
+       if (bootp->yiaddr || bootp->ciaddr) {
                /* Set some useful variables that we derive from the DHCP
                 * message but are not necessarily in the options */
-               addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
+               addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr;
                addvar(ifp->ctx, &ep, prefix, "ip_address", inet_ntoa(addr));
                if (get_option_addr(ifp->ctx, &net,
-                   dhcp, DHO_SUBNETMASK) == -1)
+                   bootp, bootp_len, DHO_SUBNETMASK) == -1)
                {
                        net.s_addr = ipv4_getnetmask(addr.s_addr);
                        addvar(ifp->ctx, &ep, prefix,
@@ -1321,25 +1343,25 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
                addvar(ifp->ctx, &ep, prefix, "subnet_cidr", cidr);
                if (get_option_addr(ifp->ctx, &brd,
-                   dhcp, DHO_BROADCAST) == -1)
+                   bootp, bootp_len, DHO_BROADCAST) == -1)
                {
                        brd.s_addr = addr.s_addr | ~net.s_addr;
                        addvar(ifp->ctx, &ep, prefix,
                            "broadcast_address", inet_ntoa(brd));
                }
-               addr.s_addr = dhcp->yiaddr & net.s_addr;
+               addr.s_addr = bootp->yiaddr & net.s_addr;
                addvar(ifp->ctx, &ep, prefix,
                    "network_number", inet_ntoa(addr));
        }
 
-       if (*dhcp->bootfile && !(overl & 1)) {
+       if (*bootp->file && !(overl & 1)) {
                print_string(safe, sizeof(safe), OT_STRING,
-                   dhcp->bootfile, sizeof(dhcp->bootfile));
+                   bootp->file, sizeof(bootp->file));
                addvar(ifp->ctx, &ep, prefix, "filename", safe);
        }
-       if (*dhcp->servername && !(overl & 2)) {
+       if (*bootp->sname && !(overl & 2)) {
                print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN,
-                   dhcp->servername, sizeof(dhcp->servername));
+                   bootp->sname, sizeof(bootp->sname));
                addvar(ifp->ctx, &ep, prefix, "server_name", safe);
        }
 
@@ -1367,7 +1389,9 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                        continue;
                if (dhcp_getoverride(ifo, opt->option))
                        continue;
-               if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) {
+               if ((p = get_option(ifp->ctx, bootp, bootp_len,
+                   opt->option, &pl)))
+               {
                        ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
                            opt, dhcp_getoption, p, pl);
                        if (opt->option == DHO_VIVSO &&
@@ -1394,7 +1418,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        {
                if (has_option_mask(ifo->nomask, opt->option))
                        continue;
-               if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl)))
+               if ((p = get_option(ifp->ctx, bootp, bootp_len,
+                   opt->option, &pl)))
                        ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
                            opt, dhcp_getoption, p, pl);
        }
@@ -1404,30 +1429,28 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
 
 static void
 get_lease(struct dhcpcd_ctx *ctx,
-    struct dhcp_lease *lease, const struct dhcp_message *dhcp)
+    struct dhcp_lease *lease, const struct bootp *bootp, size_t len)
 {
 
-       assert(dhcp != NULL);
+       assert(bootp != NULL);
 
-       lease->cookie = dhcp->cookie;
+       memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie));
        /* BOOTP does not set yiaddr for replies when ciaddr is set. */
-       if (dhcp->yiaddr)
-               lease->addr.s_addr = dhcp->yiaddr;
-       else
-               lease->addr.s_addr = dhcp->ciaddr;
-       if (get_option_addr(ctx, &lease->net, dhcp, DHO_SUBNETMASK) == -1)
+       lease->addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr;
+       if (get_option_addr(ctx, &lease->net, bootp, len, DHO_SUBNETMASK) == -1)
                lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr);
-       if (get_option_addr(ctx, &lease->brd, dhcp, DHO_BROADCAST) == -1)
+       if (get_option_addr(ctx, &lease->brd, bootp, len, DHO_BROADCAST) == -1)
                lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
-       if (get_option_uint32(ctx, &lease->leasetime, dhcp, DHO_LEASETIME) != 0)
+       if (get_option_uint32(ctx, &lease->leasetime,
+           bootp, len, DHO_LEASETIME) != 0)
                lease->leasetime = ~0U; /* Default to infinite lease */
        if (get_option_uint32(ctx, &lease->renewaltime,
-           dhcp, DHO_RENEWALTIME) != 0)
+           bootp, len, DHO_RENEWALTIME) != 0)
                lease->renewaltime = 0;
        if (get_option_uint32(ctx, &lease->rebindtime,
-           dhcp, DHO_REBINDTIME) != 0)
+           bootp, len, DHO_REBINDTIME) != 0)
                lease->rebindtime = 0;
-       if (get_option_addr(ctx, &lease->server, dhcp, DHO_SERVERID) != 0)
+       if (get_option_addr(ctx, &lease->server, bootp, len, DHO_SERVERID) != 0)
                lease->server.s_addr = INADDR_ANY;
 }
 
@@ -1452,7 +1475,7 @@ dhcp_fallback(void *arg)
        dhcpcd_startinterface(iface);
 }
 
-uint32_t
+static uint32_t
 dhcp_xid(const struct interface *ifp)
 {
        uint32_t xid;
@@ -1535,7 +1558,7 @@ eexit:
 }
 
 static uint16_t
-checksum(const void *data, unsigned int len)
+checksum(const void *data, size_t len)
 {
        const uint8_t *addr = data;
        uint32_t sum = 0;
@@ -1555,16 +1578,15 @@ checksum(const void *data, unsigned int len)
        return (uint16_t)~htons((uint16_t)sum);
 }
 
-static struct udp_dhcp_packet *
+static struct udp_bootp_packet *
 dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
        struct in_addr source, struct in_addr dest)
 {
-       struct udp_dhcp_packet *udpp;
+       struct udp_bootp_packet *udpp;
        struct ip *ip;
        struct udphdr *udp;
 
-       udpp = calloc(1, sizeof(*udpp));
-       if (udpp == NULL)
+       if ((udpp = calloc(1, sizeof(*ip) + sizeof(*udp) + length)) == NULL)
                return NULL;
        ip = &udpp->ip;
        udp = &udpp->udp;
@@ -1578,7 +1600,7 @@ dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
         * If we don't do the ordering like so then the udp checksum will be
         * broken, so find another way of doing it! */
 
-       memcpy(&udpp->dhcp, data, length);
+       memcpy(&udpp->bootp, data, length);
 
        ip->ip_p = IPPROTO_UDP;
        ip->ip_src.s_addr = source.s_addr;
@@ -1591,7 +1613,7 @@ dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
        udp->uh_dport = htons(DHCP_SERVER_PORT);
        udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length));
        ip->ip_len = udp->uh_ulen;
-       udp->uh_sum = checksum(udpp, sizeof(*udpp));
+       udp->uh_sum = checksum(udpp, sizeof(*ip) +  sizeof(*udp) + length);
 
        ip->ip_v = IPVERSION;
        ip->ip_hl = sizeof(*ip) >> 2;
@@ -1610,8 +1632,8 @@ send_message(struct interface *ifp, uint8_t type,
 {
        struct dhcp_state *state = D_STATE(ifp);
        struct if_options *ifo = ifp->options;
-       struct dhcp_message *dhcp;
-       struct udp_dhcp_packet *udp;
+       struct bootp *bootp;
+       struct udp_bootp_packet *udp;
        size_t len;
        ssize_t r;
        struct in_addr from, to;
@@ -1667,7 +1689,7 @@ send_message(struct interface *ifp, uint8_t type,
 #endif
            (state->lease.server.s_addr ||
            ifp->options->options & DHCPCD_INFORM) &&
-           !IS_BOOTP(ifp, state->new))
+           IS_DHCP(state->new))
        {
                s = dhcp_openudp(ifp);
                if (s == -1) {
@@ -1680,13 +1702,13 @@ send_message(struct interface *ifp, uint8_t type,
                }
        }
 
-       r = make_message(&dhcp, ifp, type);
+       r = make_message(&bootp, ifp, type);
        if (a != INADDR_ANY)
                state->addr.s_addr = a;
        if (r == -1)
                goto fail;
        len = (size_t)r;
-       from.s_addr = dhcp->ciaddr;
+       from.s_addr = bootp->ciaddr;
        if (s != -1 && from.s_addr != INADDR_ANY)
                to.s_addr = state->lease.server.s_addr;
        else
@@ -1698,7 +1720,7 @@ send_message(struct interface *ifp, uint8_t type,
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = to.s_addr;
                sin.sin_port = htons(DHCP_SERVER_PORT);
-               r = sendto(s, (uint8_t *)dhcp, len, 0,
+               r = sendto(s, (uint8_t *)bootp, len, 0,
                    (struct sockaddr *)&sin, sizeof(sin));
                if (r == -1)
                        logger(ifp->ctx, LOG_ERR,
@@ -1707,7 +1729,7 @@ send_message(struct interface *ifp, uint8_t type,
                size_t ulen;
 
                r = 0;
-               udp = dhcp_makeudppacket(&ulen, (uint8_t *)dhcp, len, from, to);
+               udp = dhcp_makeudppacket(&ulen, (uint8_t *)bootp, len, from, to);
                if (udp == NULL) {
                        logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m");
                } else {
@@ -1738,7 +1760,7 @@ send_message(struct interface *ifp, uint8_t type,
                        }
                }
        }
-       free(dhcp);
+       free(bootp);
 
 fail:
        if (s != -1)
@@ -1964,13 +1986,18 @@ dhcp_arp_probed(struct arp_state *astate)
                dhcp_bind(astate->iface);
 #ifndef IN_IFF_TENTATIVE
        else {
-               struct dhcp_message *oldnew;
+               struct bootp *bootp;
+               size_t len;
 
-               oldnew = state->new;
+               bootp = state->new;
+               len = state->new_len;
                state->new = state->offer;
-               get_lease(astate->iface->ctx, &state->lease, state->new);
+               state->new_len = state->offer_len;
+               get_lease(astate->iface->ctx, &state->lease,
+                   state->new, state->new_len);
                ipv4_applyaddr(astate->iface);
-               state->new = oldnew;
+               state->new = bootp;
+               state->new_len = len;
        }
 #endif
 
@@ -2086,10 +2113,13 @@ dhcp_bind(struct interface *ifp)
        if (state->offer) {
                free(state->old);
                state->old = state->new;
+               state->old_len = state->new_len;
                state->new = state->offer;
+               state->new_len = state->offer_len;
                state->offer = NULL;
+               state->offer_len = 0;
        }
-       get_lease(ifp->ctx, lease, state->new);
+       get_lease(ifp->ctx, lease, state->new, state->new_len);
        if (ifo->options & DHCPCD_STATIC) {
                logger(ifp->ctx, LOG_INFO, "%s: using static address %s/%d",
                    ifp->name, inet_ntoa(lease->addr),
@@ -2183,7 +2213,7 @@ dhcp_bind(struct interface *ifp)
        state->state = DHS_BOUND;
        if (!state->lease.frominfo &&
            !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
-               if (write_lease(ifp, state->new) == -1)
+               if (write_lease(ifp, state->new, state->new_len) == -1)
                        logger(ifp->ctx, LOG_ERR,
                            "%s: write_lease: %m", __func__);
 
@@ -2211,26 +2241,32 @@ dhcp_lastlease(void *arg)
        dhcp_discover(ifp);
 }
 
-struct dhcp_message *
-dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
+static size_t
+dhcp_message_new(struct bootp **bootp,
+    const struct in_addr *addr, const struct in_addr *mask)
 {
-       struct dhcp_message *dhcp;
        uint8_t *p;
+       uint32_t cookie;
+
+       if ((*bootp = calloc(1, sizeof(**bootp))) == NULL)
+               return 0;
+
+       (*bootp)->yiaddr = addr->s_addr;
+       p = (*bootp)->vend;
+
+       cookie = htonl(MAGIC_COOKIE);
+       memcpy(&cookie, p, sizeof(cookie));
+       p += sizeof(cookie);
 
-       dhcp = calloc(1, sizeof(*dhcp));
-       if (dhcp == NULL)
-               return NULL;
-       dhcp->yiaddr = addr->s_addr;
-       dhcp->cookie = htonl(MAGIC_COOKIE);
-       p = dhcp->options;
        if (mask && mask->s_addr != INADDR_ANY) {
                *p++ = DHO_SUBNETMASK;
                *p++ = sizeof(mask->s_addr);
                memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
                p+= sizeof(mask->s_addr);
        }
-       *p++ = DHO_END;
-       return dhcp;
+
+       *p = DHO_END;
+       return sizeof(**bootp);
 }
 
 static int
@@ -2260,7 +2296,7 @@ dhcp_arp_address(struct interface *ifp)
                if (ia == NULL) {
                        struct dhcp_lease l;
 
-                       get_lease(ifp->ctx, &l, state->offer);
+                       get_lease(ifp->ctx, &l, state->offer, state->offer_len);
                        /* Add the address now, let the kernel handle DAD. */
                        ipv4_addaddr(ifp, &l.addr, &l.net, &l.brd);
                } else
@@ -2272,7 +2308,7 @@ dhcp_arp_address(struct interface *ifp)
        if (ifp->options->options & DHCPCD_ARP && ia == NULL) {
                struct dhcp_lease l;
 
-               get_lease(ifp->ctx, &l, state->offer);
+               get_lease(ifp->ctx, &l, state->offer, state->offer_len);
                logger(ifp->ctx, LOG_INFO, "%s: probing address %s/%d",
                    ifp->name, inet_ntoa(l.addr), inet_ntocidr(l.net));
                if ((astate = arp_new(ifp, &addr)) != NULL) {
@@ -2319,9 +2355,10 @@ dhcp_static(struct interface *ifp)
                return;
        }
 
-       state->offer = dhcp_message_new(ia ? &ia->addr : &ifo->req_addr,
+       state->offer_len = dhcp_message_new(&state->offer,
+           ia ? &ia->addr : &ifo->req_addr,
            ia ? &ia->net : &ifo->req_mask);
-       if (state->offer)
+       if (state->offer_len)
                dhcp_arp_bind(ifp);
 }
 
@@ -2360,8 +2397,8 @@ dhcp_inform(struct interface *ifp)
                                    ifp->name);
                                return;
                        }
-                       state->offer = dhcp_message_new(&ifo->req_addr,
-                           &ifo->req_mask);
+                       state->offer_len = dhcp_message_new(&state->offer,
+                           &ifo->req_addr, &ifo->req_mask);
                        if (dhcp_arp_address(ifp) == 0)
                                return;
                        ia = ipv4_iffindaddr(ifp,
@@ -2370,10 +2407,11 @@ dhcp_inform(struct interface *ifp)
                }
        }
 
-       state->offer = dhcp_message_new(&ia->addr, &ia->net);
-       if (state->offer) {
+       state->offer_len = dhcp_message_new(&state->offer, &ia->addr, &ia->net);
+       if (state->offer_len) {
                state->xid = dhcp_xid(ifp);
-               get_lease(ifp->ctx, &state->lease, state->offer);
+               get_lease(ifp->ctx, &state->lease,
+                   state->offer, state->offer_len);
                send_inform(ifp);
        }
 }
@@ -2427,7 +2465,7 @@ dhcp_reboot(struct interface *ifp)
                dhcp_discover(ifp);
                return;
        }
-       if (state->offer->cookie == 0)
+       if (!IS_DHCP(state->offer))
                return;
 
        logger(ifp->ctx, LOG_INFO, "%s: rebinding lease of %s",
@@ -2502,30 +2540,59 @@ dhcp_drop(struct interface *ifp, const char *reason)
 
        free(state->offer);
        state->offer = NULL;
+       state->offer_len = 0;
        free(state->old);
        state->old = state->new;
+       state->old_len = state->new_len;
        state->new = NULL;
+       state->new_len = 0;
        state->reason = reason;
        ipv4_applyaddr(ifp);
        free(state->old);
        state->old = NULL;
+       state->old_len = 0;
        state->lease.addr.s_addr = 0;
        ifp->options->options &= ~(DHCPCD_CSR_WARNED |
            DHCPCD_ROUTER_HOST_ROUTE_WARNED);
 }
 
+static int
+blacklisted_ip(const struct if_options *ifo, in_addr_t addr)
+{
+       size_t i;
+
+       for (i = 0; i < ifo->blacklist_len; i += 2)
+               if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1]))
+                       return 1;
+       return 0;
+}
+
+static int
+whitelisted_ip(const struct if_options *ifo, in_addr_t addr)
+{
+       size_t i;
+
+       if (ifo->whitelist_len == 0)
+               return -1;
+       for (i = 0; i < ifo->whitelist_len; i += 2)
+               if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1]))
+                       return 1;
+       return 0;
+}
+
 static void
-log_dhcp1(int lvl, const char *msg,
-    const struct interface *ifp, const struct dhcp_message *dhcp,
+log_dhcp(int lvl, const char *msg,
+    const struct interface *ifp, const struct bootp *bootp, size_t bootp_len,
     const struct in_addr *from, int ad)
 {
        const char *tfrom;
-       char *a,  sname[sizeof(dhcp->servername) * 4];
+       char *a,  sname[sizeof(bootp->sname) * 4];
        struct in_addr addr;
        int r;
+       uint8_t overl;
 
        if (strcmp(msg, "NAK:") == 0) {
-               a = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE);
+               a = get_option_string(ifp->ctx, bootp, bootp_len, DHO_MESSAGE);
                if (a) {
                        char *tmp;
                        size_t al, tmpl;
@@ -2542,8 +2609,8 @@ log_dhcp1(int lvl, const char *msg,
                        free(a);
                        a = tmp;
                }
-       } else if (ad && dhcp->yiaddr != 0) {
-               addr.s_addr = dhcp->yiaddr;
+       } else if (ad && bootp->yiaddr != 0) {
+               addr.s_addr = bootp->yiaddr;
                a = strdup(inet_ntoa(addr));
                if (a == NULL) {
                        logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
@@ -2553,10 +2620,13 @@ log_dhcp1(int lvl, const char *msg,
                a = NULL;
 
        tfrom = "from";
-       r = get_option_addr(ifp->ctx, &addr, dhcp, DHO_SERVERID);
-       if (dhcp->servername[0] && r == 0) {
+       r = get_option_addr(ifp->ctx, &addr, bootp, bootp_len, DHO_SERVERID);
+       if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len,
+           DHO_OPTSOVERLOADED) == -1)
+               overl = 0;
+       if (bootp->sname[0] && r == 0 && !(overl & 2)) {
                print_string(sname, sizeof(sname), OT_STRING,
-                   dhcp->servername, strlen((const char *)dhcp->servername));
+                   bootp->sname, strlen((const char *)bootp->sname));
                if (a == NULL)
                        logger(ifp->ctx, lvl, "%s: %s %s %s `%s'",
                            ifp->name, msg, tfrom, inet_ntoa(addr), sname);
@@ -2579,45 +2649,11 @@ log_dhcp1(int lvl, const char *msg,
 }
 
 static void
-log_dhcp(int lvl, const char *msg,
-    const struct interface *ifp, const struct dhcp_message *dhcp,
-    const struct in_addr *from)
-{
-
-       log_dhcp1(lvl, msg, ifp, dhcp, from, 1);
-}
-
-static int
-blacklisted_ip(const struct if_options *ifo, in_addr_t addr)
-{
-       size_t i;
-
-       for (i = 0; i < ifo->blacklist_len; i += 2)
-               if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1]))
-                       return 1;
-       return 0;
-}
-
-static int
-whitelisted_ip(const struct if_options *ifo, in_addr_t addr)
-{
-       size_t i;
-
-       if (ifo->whitelist_len == 0)
-               return -1;
-       for (i = 0; i < ifo->whitelist_len; i += 2)
-               if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1]))
-                       return 1;
-       return 0;
-}
-
-static void
-dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
+dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
     const struct in_addr *from)
 {
        struct dhcp_state *state = D_STATE(ifp);
        struct if_options *ifo = ifp->options;
-       struct dhcp_message *dhcp = *dhcpp;
        struct dhcp_lease *lease = &state->lease;
        uint8_t type, tmp;
        const uint8_t *auth;
@@ -2625,12 +2661,32 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        unsigned int i;
        size_t auth_len;
        char *msg;
+       bool bootp_copied;
 #ifdef IN_IFF_DUPLICATED
        struct ipv4_addr *ia;
 #endif
 
+#define LOGDHCP0(l, m) \
+       log_dhcp((l), (m), ifp, bootp, bootp_len, from, 0)
+#define LOGDHCP(l, m) \
+       log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1)
+
+       /* Ensure packet is for us */
+       if (ifp->hwlen <= sizeof(bootp->chaddr) &&
+           memcmp(bootp->chaddr, ifp->hwaddr, ifp->hwlen))
+       {
+               char buf[sizeof(bootp->chaddr) * 3];
+
+               logger(ifp->ctx, LOG_DEBUG, "%s: xid 0x%x is for hwaddr %s",
+                   ifp->name, ntohl(bootp->xid),
+                   hwaddr_ntoa(bootp->chaddr, sizeof(bootp->chaddr),
+                   buf, sizeof(buf)));
+               return;
+       }
+
        /* We may have found a BOOTP server */
-       if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
+       if (get_option_uint8(ifp->ctx, &type,
+           bootp, bootp_len, DHO_MESSAGETYPE) == -1)
                type = 0;
        else if (ifo->options & DHCPCD_BOOTP) {
                logger(ifp->ctx, LOG_DEBUG,
@@ -2640,16 +2696,16 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        }
 
        /* Authenticate the message */
-       auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
+       auth = get_option(ifp->ctx, bootp, bootp_len,
+           DHO_AUTHENTICATION, &auth_len);
        if (auth) {
                if (dhcp_auth_validate(&state->auth, &ifo->auth,
-                   (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type,
+                   (uint8_t *)bootp, bootp_len, 4, type,
                    auth, auth_len) == NULL)
                {
                        logger(ifp->ctx, LOG_DEBUG,
                            "%s: dhcp_auth_validate: %m", ifp->name);
-                       log_dhcp1(LOG_ERR, "authentication failed",
-                           ifp, dhcp, from, 0);
+                       LOGDHCP0(LOG_ERR, "authentication failed");
                        return;
                }
                if (state->auth.token)
@@ -2661,12 +2717,10 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                            "%s: accepted reconfigure key", ifp->name);
        } else if (ifo->auth.options & DHCPCD_AUTH_SEND) {
                if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
-                       log_dhcp1(LOG_ERR, "no authentication",
-                           ifp, dhcp, from, 0);
+                       LOGDHCP0(LOG_ERR, "no authentication");
                        return;
                }
-               log_dhcp1(LOG_WARNING, "no authentication",
-                   ifp, dhcp, from, 0);
+               LOGDHCP0(LOG_WARNING, "no authentication");
        }
 
        /* RFC 3203 */
@@ -2674,22 +2728,19 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                if (from->s_addr == INADDR_ANY ||
                    from->s_addr == INADDR_BROADCAST)
                {
-                       log_dhcp(LOG_ERR, "discarding Force Renew",
-                           ifp, dhcp, from);
+                       LOGDHCP(LOG_ERR, "discarding Force Renew");
                        return;
                }
                if (auth == NULL) {
-                       log_dhcp(LOG_ERR, "unauthenticated Force Renew",
-                           ifp, dhcp, from);
+                       LOGDHCP(LOG_ERR, "unauthenticated Force Renew");
                        if (ifo->auth.options & DHCPCD_AUTH_REQUIRE)
                                return;
                }
                if (state->state != DHS_BOUND && state->state != DHS_INFORM) {
-                       log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew",
-                           ifp, dhcp, from);
+                       LOGDHCP(LOG_DEBUG, "not bound, ignoring Force Renew");
                        return;
                }
-               log_dhcp(LOG_ERR, "Force Renew from", ifp, dhcp, from);
+               LOGDHCP(LOG_INFO, "Force Renew from");
                /* The rebind and expire timings are still the same, we just
                 * enter the renew state early */
                if (state->state == DHS_BOUND)
@@ -2706,22 +2757,22 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                /* Before we supported FORCERENEW we closed off the raw
                 * port so we effectively ignored all messages.
                 * As such we'll not log by default here. */
-               //log_dhcp(LOG_DEBUG, "bound, ignoring", ifp, dhcp, from);
+               //LOGDHCP(LOG_DEBUG, "bound, ignoring");
                return;
        }
 
        /* Ensure it's the right transaction */
-       if (state->xid != ntohl(dhcp->xid)) {
+       if (state->xid != ntohl(bootp->xid)) {
                logger(ifp->ctx, LOG_DEBUG,
                    "%s: wrong xid 0x%x (expecting 0x%x) from %s",
-                   ifp->name, ntohl(dhcp->xid), state->xid,
+                   ifp->name, ntohl(bootp->xid), state->xid,
                    inet_ntoa(*from));
                return;
        }
 
        if (state->state == DHS_PROBE) {
                /* Ignore any DHCP messages whilst probing a lease to bind. */
-               log_dhcp(LOG_DEBUG, "probing, ignoring", ifp, dhcp, from);
+               LOGDHCP(LOG_DEBUG, "probing, ignoring");
                return;
        }
 
@@ -2731,9 +2782,10 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        /* Ensure that no reject options are present */
        for (i = 1; i < 255; i++) {
                if (has_option_mask(ifo->rejectmask, i) &&
-                   get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) == 0)
+                   get_option_uint8(ifp->ctx, &tmp,
+                   bootp, bootp_len, (uint8_t)i) == 0)
                {
-                       log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
+                       LOGDHCP(LOG_WARNING, "reject DHCP");
                        return;
                }
        }
@@ -2741,15 +2793,18 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        if (type == DHCP_NAK) {
                /* For NAK, only check if we require the ServerID */
                if (has_option_mask(ifo->requiremask, DHO_SERVERID) &&
-                   get_option_addr(ifp->ctx, &addr, dhcp, DHO_SERVERID) == -1)
+                   get_option_addr(ifp->ctx, &addr,
+                   bootp, bootp_len, DHO_SERVERID) == -1)
                {
-                       log_dhcp(LOG_WARNING, "reject NAK", ifp, dhcp, from);
+                       LOGDHCP(LOG_WARNING, "reject NAK");
                        return;
                }
 
                /* We should restart on a NAK */
-               log_dhcp(LOG_WARNING, "NAK:", ifp, dhcp, from);
-               if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
+               LOGDHCP(LOG_WARNING, "NAK:");
+               if ((msg = get_option_string(ifp->ctx,
+                   bootp, bootp_len, DHO_MESSAGE)))
+               {
                        logger(ifp->ctx, LOG_WARNING, "%s: message: %s",
                            ifp->name, msg);
                        free(msg);
@@ -2777,7 +2832,8 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        /* Ensure that all required options are present */
        for (i = 1; i < 255; i++) {
                if (has_option_mask(ifo->requiremask, i) &&
-                   get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) != 0)
+                   get_option_uint8(ifp->ctx, &tmp,
+                   bootp, bootp_len, (uint8_t)i) != 0)
                {
                        /* If we are BOOTP, then ignore the need for serverid.
                         * To ignore BOOTP, require dhcp_message_type.
@@ -2786,33 +2842,33 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                         * always true. */
                        if (type == 0 && i == DHO_SERVERID)
                                continue;
-                       log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
+                       LOGDHCP(LOG_WARNING, "reject DHCP");
                        return;
                }
        }
 
        /* DHCP Auto-Configure, RFC 2563 */
-       if (type == DHCP_OFFER && dhcp->yiaddr == 0) {
-               log_dhcp(LOG_WARNING, "no address given", ifp, dhcp, from);
-               if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
+       if (type == DHCP_OFFER && bootp->yiaddr == 0) {
+               LOGDHCP(LOG_WARNING, "no address given");
+               if ((msg = get_option_string(ifp->ctx,
+                   bootp, bootp_len, DHO_MESSAGE)))
+               {
                        logger(ifp->ctx, LOG_WARNING,
                            "%s: message: %s", ifp->name, msg);
                        free(msg);
                }
                if (state->state == DHS_DISCOVER &&
-                   get_option_uint8(ifp->ctx, &tmp, dhcp,
+                   get_option_uint8(ifp->ctx, &tmp, bootp, bootp_len,
                    DHO_AUTOCONFIGURE) == 0)
                {
                        switch (tmp) {
                        case 0:
-                               log_dhcp(LOG_WARNING, "IPv4LL disabled from",
-                                   ifp, dhcp, from);
+                               LOGDHCP(LOG_WARNING, "IPv4LL disabled from");
                                ipv4ll_drop(ifp);
                                arp_close(ifp);
                                break;
                        case 1:
-                               log_dhcp(LOG_WARNING, "IPv4LL enabled from",
-                                   ifp, dhcp, from);
+                               LOGDHCP(LOG_WARNING, "IPv4LL enabled from");
                                ipv4ll_start(ifp);
                                break;
                        default:
@@ -2830,19 +2886,18 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
 
        /* Ensure that the address offered is valid */
        if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
-           (dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) &&
-           (dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST))
+           (bootp->ciaddr == INADDR_ANY || bootp->ciaddr == INADDR_BROADCAST)
+           &&
+           (bootp->yiaddr == INADDR_ANY || bootp->yiaddr == INADDR_BROADCAST))
        {
-               log_dhcp(LOG_WARNING, "reject invalid address",
-                   ifp, dhcp, from);
+               LOGDHCP(LOG_WARNING, "reject invalid address");
                return;
        }
 
 #ifdef IN_IFF_DUPLICATED
        ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
        if (ia && ia->addr_flags & IN_IFF_DUPLICATED) {
-               log_dhcp(LOG_WARNING, "declined duplicate address",
-                   ifp, dhcp, from);
+               LOGDHCP(LOG_WARNING, "declined duplicate address");
                if (type)
                        dhcp_decline(ifp);
                ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
@@ -2853,33 +2908,47 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
        }
 #endif
 
+       bootp_copied = false;
        if ((type == 0 || type == DHCP_OFFER) && state->state == DHS_DISCOVER) {
                lease->frominfo = 0;
-               lease->addr.s_addr = dhcp->yiaddr;
-               lease->cookie = dhcp->cookie;
+               lease->addr.s_addr = bootp->yiaddr;
+               memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie));
                if (type == 0 ||
                    get_option_addr(ifp->ctx,
-                   &lease->server, dhcp, DHO_SERVERID) != 0)
+                   &lease->server, bootp, bootp_len, DHO_SERVERID) != 0)
                        lease->server.s_addr = INADDR_ANY;
 
                /* Test for rapid commit in the OFFER */
                if (!(ifp->ctx->options & DHCPCD_TEST) &&
                    has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT) &&
-                   get_option(ifp->ctx, dhcp, DHO_RAPIDCOMMIT, NULL))
+                   get_option(ifp->ctx, bootp, bootp_len,
+                   DHO_RAPIDCOMMIT, NULL))
                {
                        state->state = DHS_REQUEST;
                        goto rapidcommit;
                }
 
-               log_dhcp(LOG_INFO, "offered", ifp, dhcp, from);
-               free(state->offer);
-               state->offer = dhcp;
-               *dhcpp = NULL;
+               LOGDHCP(LOG_INFO, "offered");
+               if (state->offer_len < bootp_len) {
+                       free(state->offer);
+                       if ((state->offer = malloc(bootp_len)) == NULL) {
+                               logger(ifp->ctx, LOG_ERR, "%s: malloc: %m",
+                                   __func__);
+                               state->offer_len = 0;
+                               return;
+                       }
+               }
+               memcpy(state->offer, bootp, bootp_len);
+               state->offer_len = bootp_len;
+               bootp_copied = true;
                if (ifp->ctx->options & DHCPCD_TEST) {
                        free(state->old);
                        state->old = state->new;
+                       state->old_len = state->new_len;
                        state->new = state->offer;
+                       state->new_len = state->offer_len;
                        state->offer = NULL;
+                       state->offer_len = 0;
                        state->reason = "TEST";
                        script_runreason(ifp, state->reason);
                        eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
@@ -2901,15 +2970,13 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
 
        if (type) {
                if (type == DHCP_OFFER) {
-                       log_dhcp(LOG_WARNING, "ignoring offer of",
-                           ifp, dhcp, from);
+                       LOGDHCP(LOG_WARNING, "ignoring offer of");
                        return;
                }
 
                /* We should only be dealing with acks */
                if (type != DHCP_ACK) {
-                       log_dhcp(LOG_ERR, "not ACK or OFFER",
-                           ifp, dhcp, from);
+                       LOGDHCP(LOG_ERR, "not ACK or OFFER");
                        return;
                }
 
@@ -2917,18 +2984,18 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                        /* We only allow ACK of rapid commit DISCOVER. */
                        if (has_option_mask(ifo->requestmask,
                            DHO_RAPIDCOMMIT) &&
-                           get_option(ifp->ctx, dhcp, DHO_RAPIDCOMMIT, NULL))
+                           get_option(ifp->ctx, bootp, bootp_len,
+                           DHO_RAPIDCOMMIT, NULL))
                                state->state = DHS_REQUEST;
                        else {
-                               log_dhcp(LOG_DEBUG, "ignoring ack of",
-                                   ifp, dhcp, from);
+                               LOGDHCP(LOG_DEBUG, "ignoring ack of");
                                return;
                        }
                }
 
 rapidcommit:
                if (!(ifo->options & DHCPCD_INFORM))
-                       log_dhcp(LOG_DEBUG, "acknowledged", ifp, dhcp, from);
+                       LOGDHCP(LOG_DEBUG, "acknowledged");
                else
                    ifo->options &= ~DHCPCD_STATIC;
        }
@@ -2938,12 +3005,19 @@ rapidcommit:
         * potentially NAK the REQUEST. */
        state->nakoff = 0;
 
-       /* BOOTP could have already assigned this above, so check we still
-        * have a pointer. */
-       if (*dhcpp) {
-               free(state->offer);
-               state->offer = dhcp;
-               *dhcpp = NULL;
+       /* BOOTP could have already assigned this above. */
+       if (!bootp_copied) {
+               if (state->offer_len < bootp_len) {
+                       free(state->offer);
+                       if ((state->offer = malloc(bootp_len)) == NULL) {
+                               logger(ifp->ctx, LOG_ERR, "%s: malloc: %m",
+                                   __func__);
+                               state->offer_len = 0;
+                               return;
+                       }
+               }
+               memcpy(state->offer, bootp, bootp_len);
+               state->offer_len = bootp_len;
        }
 
        lease->frominfo = 0;
@@ -2953,61 +3027,63 @@ rapidcommit:
 }
 
 static size_t
-get_udp_data(const uint8_t **data, const uint8_t *udp)
+get_udp_data(uint8_t **data, uint8_t *udp)
 {
-       struct udp_dhcp_packet p;
+       struct udp_bootp_packet *p;
 
-       memcpy(&p, udp, sizeof(p));
-       *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
-       return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp);
+       p = (struct udp_bootp_packet *)udp;
+       *data = udp + offsetof(struct udp_bootp_packet, bootp);
+       return ntohs(p->ip.ip_len) - sizeof(p->ip) - sizeof(p->udp);
 }
 
 static int
-valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+valid_udp_packet(uint8_t *data, size_t data_len, struct in_addr *from,
     int noudpcsum)
 {
-       struct udp_dhcp_packet p;
-       uint16_t bytes, udpsum;
+       struct udp_bootp_packet *p;
+       uint16_t bytes;
 
-       if (data_len < sizeof(p.ip)) {
+       if (data_len < sizeof(p->ip) + sizeof(p->udp)) {
                if (from)
                        from->s_addr = INADDR_ANY;
                errno = EINVAL;
                return -1;
        }
-       memcpy(&p, data, MIN(data_len, sizeof(p)));
+       p = (struct udp_bootp_packet *)data;
        if (from)
-               from->s_addr = p.ip.ip_src.s_addr;
-       if (data_len > sizeof(p)) {
-               errno = EINVAL;
-               return -1;
-       }
-       if (checksum(&p.ip, sizeof(p.ip)) != 0) {
+               from->s_addr = p->ip.ip_src.s_addr;
+       if (checksum(&p->ip, sizeof(p->ip)) != 0) {
                errno = EINVAL;
                return -1;
        }
 
-       bytes = ntohs(p.ip.ip_len);
+       bytes = ntohs(p->ip.ip_len);
        if (data_len < bytes) {
                errno = EINVAL;
                return -1;
        }
 
        if (noudpcsum == 0) {
-               udpsum = p.udp.uh_sum;
-               p.udp.uh_sum = 0;
-               p.ip.ip_hl = 0;
-               p.ip.ip_v = 0;
-               p.ip.ip_tos = 0;
-               p.ip.ip_len = p.udp.uh_ulen;
-               p.ip.ip_id = 0;
-               p.ip.ip_off = 0;
-               p.ip.ip_ttl = 0;
-               p.ip.ip_sum = 0;
-               if (udpsum && checksum(&p, bytes) != udpsum) {
+               uint16_t udpsum, iplen;
+
+               /* This does scribble on the packet, but at this point
+                * we don't care to keep it. */
+               iplen = p->ip.ip_len;
+               udpsum = p->udp.uh_sum;
+               p->udp.uh_sum = 0;
+               p->ip.ip_hl = 0;
+               p->ip.ip_v = 0;
+               p->ip.ip_tos = 0;
+               p->ip.ip_len = p->udp.uh_ulen;
+               p->ip.ip_id = 0;
+               p->ip.ip_off = 0;
+               p->ip.ip_ttl = 0;
+               p->ip.ip_sum = 0;
+               if (udpsum && checksum(p, bytes) != udpsum) {
                        errno = EINVAL;
                        return -1;
                }
+               p->ip.ip_len = iplen;
        }
 
        return 0;
@@ -3017,8 +3093,7 @@ static void
 dhcp_handlepacket(void *arg)
 {
        struct interface *ifp = arg;
-       struct dhcp_message *dhcp = NULL;
-       const uint8_t *pp;
+       uint8_t *bootp;
        size_t bytes;
        struct in_addr from;
        int i, flags;
@@ -3026,9 +3101,10 @@ dhcp_handlepacket(void *arg)
 
        /* Need this API due to BPF */
        flags = 0;
+       bootp = NULL;
        while (!(flags & RAW_EOF)) {
                bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP,
-                   ifp->ctx->packet, udp_dhcp_len, &flags);
+                   ifp->ctx->packet, sizeof(ifp->ctx->packet), &flags);
                if ((ssize_t)bytes == -1) {
                        logger(ifp->ctx, LOG_ERR,
                            "%s: dhcp if_readrawpacket: %m", ifp->name);
@@ -3065,55 +3141,25 @@ dhcp_handlepacket(void *arg)
                            "%s: server %s is not destination",
                            ifp->name, inet_ntoa(from));
                }
-               bytes = get_udp_data(&pp, ifp->ctx->packet);
-               if (bytes > sizeof(*dhcp)) {
-                       logger(ifp->ctx, LOG_ERR,
-                           "%s: packet greater than DHCP size from %s",
-                           ifp->name, inet_ntoa(from));
-                       continue;
-               }
-               if (bytes < offsetof(struct dhcp_message, cookie)) {
-                       logger(ifp->ctx, LOG_ERR,
-                           "%s: truncated packet from %s",
-                           ifp->name, inet_ntoa(from));
-                       continue;
-               }
-               if (dhcp == NULL) {
-                       dhcp = calloc(1, sizeof(*dhcp));
-                       if (dhcp == NULL) {
-                               logger(ifp->ctx, LOG_ERR,
-                                   "%s: calloc: %m", __func__);
-                               break;
-                       }
-               }
-               memcpy(dhcp, pp, bytes);
-               if (bytes < (ssize_t)sizeof(*dhcp))
-                       memset((char *)dhcp + bytes, 0, sizeof(*dhcp) - bytes);
-               /* Ensure packet is for us */
-               if (ifp->hwlen <= sizeof(dhcp->chaddr) &&
-                   memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen))
-               {
-                       char buf[sizeof(dhcp->chaddr) * 3];
 
-                       logger(ifp->ctx, LOG_DEBUG,
-                           "%s: xid 0x%x is for hwaddr %s",
-                           ifp->name, ntohl(dhcp->xid),
-                           hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
-                               buf, sizeof(buf)));
+               bytes = get_udp_data(&bootp, ifp->ctx->packet);
+               if (bytes < sizeof(struct bootp)) {
+                       logger(ifp->ctx, LOG_ERR,
+                           "%s: truncated packet (%zu) from %s",
+                           ifp->name, bytes, inet_ntoa(from));
                        continue;
                }
-               dhcp_handledhcp(ifp, &dhcp, &from);
+               dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from);
                if (state->raw_fd == -1)
                        break;
        }
-       free(dhcp);
 }
 
 static void
 dhcp_handleudp(void *arg)
 {
        struct dhcpcd_ctx *ctx;
-       uint8_t buffer[sizeof(struct dhcp_message)];
+       uint8_t buffer[MTU_MAX];
 
        ctx = arg;
 
@@ -3132,14 +3178,6 @@ dhcp_open(struct interface *ifp)
 {
        struct dhcp_state *state;
 
-       if (ifp->ctx->packet == NULL) {
-               ifp->ctx->packet = malloc(udp_dhcp_len);
-               if (ifp->ctx->packet == NULL) {
-                       logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
-                       return -1;
-               }
-       }
-
        state = D_STATE(ifp);
        if (state->raw_fd == -1) {
                state->raw_fd = if_openrawsocket(ifp, ETHERTYPE_IP);
@@ -3172,7 +3210,7 @@ dhcp_dump(struct interface *ifp)
        state->raw_fd = -1;
        dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
            AF_INET, ifp);
-       state->new = read_lease(ifp);
+       state->new_len = read_lease(ifp, &state->new);
        if (state->new == NULL) {
                logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
                    *ifp->name ? ifp->name : state->leasefile, __func__);
@@ -3219,9 +3257,7 @@ dhcp_free(struct interface *ifp)
                        ctx->udp_fd = -1;
                }
 
-               free(ctx->packet);
                free(ctx->opt_buffer);
-               ctx->packet = NULL;
                ctx->opt_buffer = NULL;
        }
 }
@@ -3381,7 +3417,7 @@ dhcp_start1(void *arg)
        /* We don't want to read the old lease if we NAK an old test */
        nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
        if (!nolease && ifo->options & DHCPCD_DHCP) {
-               state->offer = read_lease(ifp);
+               state->offer_len = read_lease(ifp, &state->offer);
                /* Check the saved lease matches the type we want */
                if (state->offer) {
 #ifdef IN_IFF_DUPLICATED
@@ -3392,12 +3428,12 @@ dhcp_start1(void *arg)
                        ia = ipv4_iffindaddr(ifp, &addr, NULL);
 #endif
 
-                       if ((IS_BOOTP(ifp, state->offer) &&
+                       if ((!IS_DHCP(state->offer) &&
                            !(ifo->options & DHCPCD_BOOTP)) ||
 #ifdef IN_IFF_DUPLICATED
                            (ia && ia->addr_flags & IN_IFF_DUPLICATED) ||
 #endif
-                           (!IS_BOOTP(ifp, state->offer) &&
+                           (IS_DHCP(state->offer) &&
                            ifo->options & DHCPCD_BOOTP))
                        {
                                free(state->offer);
@@ -3406,7 +3442,8 @@ dhcp_start1(void *arg)
                }
        }
        if (state->offer) {
-               get_lease(ifp->ctx, &state->lease, state->offer);
+               get_lease(ifp->ctx, &state->lease,
+                   state->offer, state->offer_len);
                state->lease.frominfo = 1;
                if (state->new == NULL &&
                    ipv4_iffindaddr(ifp, &state->lease.addr, &state->lease.net))
@@ -3414,10 +3451,10 @@ dhcp_start1(void *arg)
                        /* We still have the IP address from the last lease.
                         * Fake add the address and routes from it so the lease
                         * can be cleaned up. */
-                       state->new = malloc(sizeof(*state->new));
+                       state->new = malloc(state->offer_len);
                        if (state->new) {
-                               memcpy(state->new, state->offer,
-                                   sizeof(*state->new));
+                               memcpy(state->new,
+                                   state->offer, state->offer_len);
                                state->addr = state->lease.addr;
                                state->net = state->lease.net;
                                state->added |= STATE_ADDED | STATE_FAKE;
@@ -3425,10 +3462,11 @@ dhcp_start1(void *arg)
                        } else
                                logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
                }
-               if (state->offer->cookie == 0) {
+               if (!IS_DHCP(state->offer)) {
                        if (state->offer->yiaddr == state->addr.s_addr) {
                                free(state->offer);
                                state->offer = NULL;
+                               state->offer_len = 0;
                        }
                } else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) &&
                    state->lease.leasetime != ~0U &&
@@ -3445,6 +3483,7 @@ dhcp_start1(void *arg)
                                    "%s: discarding expired lease", ifp->name);
                                free(state->offer);
                                state->offer = NULL;
+                               state->offer_len = 0;
                                state->lease.addr.s_addr = 0;
                                /* Technically we should discard the lease
                                 * as it's expired, just as DHCPv6 addresses
@@ -3477,7 +3516,7 @@ dhcp_start1(void *arg)
                return;
        }
 
-       if (state->offer == NULL || state->offer->cookie == 0)
+       if (state->offer == NULL || !IS_DHCP(state->offer))
                dhcp_discover(ifp);
        else
                dhcp_reboot(ifp);
@@ -3491,6 +3530,25 @@ dhcp_start(struct interface *ifp)
        if (!(ifp->options->options & DHCPCD_IPV4))
                return;
 
+       /* If we haven't specified a ClientID and our hardware address
+        * length is greater than BOOTP CHADDR then we enforce a ClientID
+        * of the hardware address family and the hardware address.
+        * If there is no hardware address and no ClientID set,
+        * force a DUID based ClientID. */
+       if (ifp->hwlen > 16)
+               ifp->options->options |= DHCPCD_CLIENTID;
+       else if (ifp->hwlen == 0 && !(ifp->options->options & DHCPCD_CLIENTID))
+               ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
+
+       /* Firewire and InfiniBand interfaces require ClientID and
+        * the broadcast option being set. */
+       switch (ifp->family) {
+       case ARPHRD_IEEE1394:   /* FALLTHROUGH */
+       case ARPHRD_INFINIBAND:
+               ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
+               break;
+       }
+
        /* If we violate RFC2131 section 3.7 then require ARP
         * to detect if any other client wants our address. */
        if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND)
@@ -3575,7 +3633,7 @@ dhcp_handleifa(int cmd, struct interface *ifp,
 
        free(state->old);
        state->old = state->new;
-       state->new = dhcp_message_new(addr, net);
+       state->new_len = dhcp_message_new(&state->new, addr, net);
        if (state->new == NULL)
                return;
        state->brd = *brd;
diff --git a/dhcp.h b/dhcp.h
index a400d07d8094f44bfef8a07d50ede1fe0c1c379c..feec2e3cb3f56120560b0bcd7847fbca7a5f6aae 100644 (file)
--- a/dhcp.h
+++ b/dhcp.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2016 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -131,14 +131,6 @@ enum FQDN {
        FQDN_BOTH       = 0x31
 };
 
-/* Sizes for DHCP options */
-#define DHCP_CHADDR_LEN         16
-#define SERVERNAME_LEN          64
-#define BOOTFILE_LEN            128
-#define DHCP_UDP_LEN            (14 + 20 + 8)
-#define DHCP_FIXED_LEN          (DHCP_UDP_LEN + 226)
-#define DHCP_OPTION_LEN         (MTU_MAX - DHCP_FIXED_LEN)
-
 /* Some crappy DHCP servers require the BOOTP minimum length */
 #define BOOTP_MESSAGE_LENTH_MIN 300
 
@@ -154,23 +146,30 @@ enum FQDN {
 # endif
 #endif
 
-struct dhcp_message {
-       uint8_t op;           /* message type */
-       uint8_t hwtype;       /* hardware address type */
-       uint8_t hwlen;        /* hardware address length */
-       uint8_t hwopcount;    /* should be zero in client message */
-       uint32_t xid;            /* transaction id */
-       uint16_t secs;           /* elapsed time in sec. from boot */
-       uint16_t flags;
-       uint32_t ciaddr;         /* (previously allocated) client IP */
-       uint32_t yiaddr;         /* 'your' client IP address */
-       uint32_t siaddr;         /* should be zero in client's messages */
-       uint32_t giaddr;         /* should be zero in client's messages */
-       uint8_t chaddr[DHCP_CHADDR_LEN];  /* client's hardware address */
-       uint8_t servername[SERVERNAME_LEN];    /* server host name */
-       uint8_t bootfile[BOOTFILE_LEN];    /* boot file name */
-       uint32_t cookie;
-       uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */
+/* Sizes for BOOTP options */
+#define        BOOTP_CHADDR_LEN         16
+#define        BOOTP_SNAME_LEN          64
+#define        BOOTP_FILE_LEN          128
+#define        BOOTP_VEND_LEN           64
+
+/* DHCP is basically an extension to BOOTP */
+struct bootp {
+       uint8_t op;             /* message type */
+       uint8_t htype;          /* hardware address type */
+       uint8_t hlen;           /* hardware address length */
+       uint8_t hops;           /* should be zero in client message */
+       uint32_t xid;           /* transaction id */
+       uint16_t secs;          /* elapsed time in sec. from boot */
+       uint16_t flags;         /* such as broadcast flag */
+       uint32_t ciaddr;        /* (previously allocated) client IP */
+       uint32_t yiaddr;        /* 'your' client IP address */
+       uint32_t siaddr;        /* should be zero in client's messages */
+       uint32_t giaddr;        /* should be zero in client's messages */
+       uint8_t chaddr[BOOTP_CHADDR_LEN];       /* client's hardware address */
+       uint8_t sname[BOOTP_SNAME_LEN];         /* server host name */
+       uint8_t file[BOOTP_FILE_LEN];           /* boot file name */
+       uint8_t vend[BOOTP_VEND_LEN];           /* vendor specific area */
+       /* DHCP allows a variable length vendor area */
 } __packed;
 
 struct dhcp_lease {
@@ -201,10 +200,14 @@ enum DHS {
 
 struct dhcp_state {
        enum DHS state;
-       struct dhcp_message *sent;
-       struct dhcp_message *offer;
-       struct dhcp_message *new;
-       struct dhcp_message *old;
+       struct bootp *sent;
+       size_t sent_len;
+       struct bootp *offer;
+       size_t offer_len;
+       struct bootp *new;
+       size_t new_len;
+       struct bootp *old;
+       size_t old_len;
        struct dhcp_lease lease;
        const char *reason;
        time_t interval;
@@ -232,6 +235,12 @@ struct dhcp_state {
 #define D_STATE_RUNNING(ifp)                                                  \
        (D_CSTATE((ifp)) && D_CSTATE((ifp))->new && D_CSTATE((ifp))->reason)
 
+#define IS_DHCP(b)     ((b) != NULL &&                 \
+                           (b)->vend[0] == 0x63 &&     \
+                           (b)->vend[1] == 0x82 &&     \
+                           (b)->vend[2] == 0x53 &&     \
+                           (b)->vend[3] == 0x63)
+
 #include "dhcpcd.h"
 #include "if-options.h"
 
@@ -241,23 +250,11 @@ ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
 
 void dhcp_printoptions(const struct dhcpcd_ctx *,
     const struct dhcp_opt *, size_t);
-int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
-    const struct dhcp_message *, uint8_t);
-#define IS_BOOTP(i, m) ((m) != NULL &&                                             \
-           get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
 uint16_t dhcp_get_mtu(const struct interface *);
 struct rt_head *dhcp_get_routes(struct interface *);
-ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
+ssize_t dhcp_env(char **, const char *, const struct bootp *, size_t,
     const struct interface *);
 
-uint32_t dhcp_xid(const struct interface *);
-struct dhcp_message *dhcp_message_new(const struct in_addr *addr,
-    const struct in_addr *mask);
-int dhcp_message_add_addr(struct dhcp_message *, uint8_t, struct in_addr);
-ssize_t make_message(struct dhcp_message **, const struct interface *,
-    uint8_t);
-int valid_dhcp_packet(unsigned char *);
-
 void dhcp_handleifa(int, struct interface *,
     const struct in_addr *, const struct in_addr *, const struct in_addr *,
     int);
index 3cf67a0c41de644bbf514b4e3fcd1dc3e4a19310..2c38bc765194d296512c3939c6f671d244f7d2ff 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -461,25 +461,6 @@ configure_interface1(struct interface *ifp)
                        ifo->options |= DHCPCD_IPV6RA_OWN;
        }
 
-       /* If we haven't specified a ClientID and our hardware address
-        * length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
-        * of the hardware address family and the hardware address.
-        * If there is no hardware address and no ClientID set,
-        * force a DUID based ClientID. */
-       if (ifp->hwlen > DHCP_CHADDR_LEN)
-               ifo->options |= DHCPCD_CLIENTID;
-       else if (ifp->hwlen == 0 && !(ifo->options & DHCPCD_CLIENTID))
-               ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
-
-       /* Firewire and InfiniBand interfaces require ClientID and
-        * the broadcast option being set. */
-       switch (ifp->family) {
-       case ARPHRD_IEEE1394:   /* FALLTHROUGH */
-       case ARPHRD_INFINIBAND:
-               ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
-               break;
-       }
-
        if (!(ifo->options & DHCPCD_IAID)) {
                /*
                 * An IAID is for identifying a unqiue interface within
index 08c7723b5c292ed435826ecd58ac4629bf4b435c..9047e1c17efac688276a07a4aabdf1f7a6e50f77 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -156,12 +156,13 @@ struct dhcpcd_ctx {
        struct rt_head *ipv4_kroutes;
 
        int udp_fd;
-       uint8_t *packet;
+       uint8_t packet[1500];   /* maximum packet we deal with */
 
        /* Our aggregate option buffer.
         * We ONLY use this when options are split, which for most purposes is
         * practically never. See RFC3396 for details. */
        uint8_t *opt_buffer;
+       size_t opt_buffer_len;
 #endif
 #ifdef INET6
        unsigned char secret[SECRET_LEN];
index cc40dbe6ca069a78b8fc12feca94d68b40a50f01..249fa4e36e25aac373f466ded5af1db11cd9f028 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -498,11 +498,7 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol,
        *flags = 0;
        for (;;) {
                if (state->buffer_len == 0) {
-                       /* alias a void pointer to our buffer
-                        * so that Coverity does not treat this as tainted. */
-                       void *bufp = state->buffer;
-
-                       bytes = read(fd, bufp, state->buffer_size);
+                       bytes = read(fd, state->buffer, state->buffer_size);
                        if (bytes == -1 || bytes == 0)
                                return bytes;
                        state->buffer_len = (size_t)bytes;
diff --git a/ipv4.c b/ipv4.c
index 07c5a053fb11a050fb72a3f7d90199602a35c16b..600e41f91164af8ddc2d0b06d79c7d8f7aa2c7d5 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -324,11 +324,9 @@ ipv4_ifcmp(const struct interface *si, const struct interface *ti)
        /* If we are either, they neither have a lease, or they both have.
         * We need to check for IPv4LL and make it non-preferred. */
        if (sis->new && tis->new) {
-               int sill = (sis->new->cookie == htonl(MAGIC_COOKIE));
-               int till = (tis->new->cookie == htonl(MAGIC_COOKIE));
-               if (sill && !till)
+               if (IS_DHCP(sis->new) && !IS_DHCP(tis->new))
                        return -1;
-               if (!sill && till)
+               if (!IS_DHCP(sis->new) && IS_DHCP(tis->new))
                        return 1;
        }
        return 0;
@@ -1098,7 +1096,6 @@ ipv4_applyaddr(void *arg)
 {
        struct interface *ifp = arg, *ifn;
        struct dhcp_state *state = D_STATE(ifp), *nstate;
-       struct dhcp_message *dhcp;
        struct dhcp_lease *lease;
        struct if_options *ifo = ifp->options;
        struct ipv4_addr *ap;
@@ -1106,11 +1103,11 @@ ipv4_applyaddr(void *arg)
 
        if (state == NULL)
                return;
-       dhcp = state->new;
-       lease = &state->lease;
 
+       lease = &state->lease;
        if_sortinterfaces(ifp->ctx);
-       if (dhcp == NULL) {
+
+       if (state->new == NULL) {
                if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
                {
index e20eca9cef94aef47a660caa0447e50056ec9fc9..81d95cbce27bf866331cda1938c1fe23f55f325e 100644 (file)
--- a/script.c
+++ b/script.c
@@ -421,7 +421,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        }
 #ifdef INET
        if (dhcp && state && state->old) {
-               n = dhcp_env(NULL, NULL, state->old, ifp);
+               n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp);
                if (n == -1)
                        goto eexit;
                if (n > 0) {
@@ -430,7 +430,8 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
                        if (nenv == NULL)
                                goto eexit;
                        env = nenv;
-                       n = dhcp_env(env + elen, "old", state->old, ifp);
+                       n = dhcp_env(env + elen, "old",
+                           state->old, state->old_len, ifp);
                        if (n == -1)
                                goto eexit;
                        elen += (size_t)n;
@@ -476,7 +477,7 @@ dumplease:
                }
        }
        if (dhcp && state && state->new) {
-               n = dhcp_env(NULL, NULL, state->new, ifp);
+               n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp);
                if (n > 0) {
                        nenv = realloc(env, sizeof(char *) *
                            (elen + (size_t)n + 1));
@@ -484,7 +485,7 @@ dumplease:
                                goto eexit;
                        env = nenv;
                        n = dhcp_env(env + elen, "new",
-                           state->new, ifp);
+                           state->new, state->new_len, ifp);
                        if (n == -1)
                                goto eexit;
                        elen += (size_t)n;