[systemd-commits] 4 commits - src/libsystemd-network

Tom Gundersen tomegun at kemper.freedesktop.org
Tue May 20 14:31:40 PDT 2014


 src/libsystemd-network/dhcp-internal.h       |    6 
 src/libsystemd-network/dhcp-lease-internal.h |   12 +
 src/libsystemd-network/dhcp-option.c         |  113 ++++++------
 src/libsystemd-network/dhcp-packet.c         |   15 -
 src/libsystemd-network/dhcp-protocol.h       |   11 +
 src/libsystemd-network/sd-dhcp-client.c      |   57 +++---
 src/libsystemd-network/sd-dhcp-lease.c       |  240 +++++++++++++++++++++------
 src/libsystemd-network/test-dhcp-option.c    |   58 ++----
 8 files changed, 323 insertions(+), 189 deletions(-)

New commits:
commit f5c0c00f400e6f1fa58c5faf8bc93ca9057d4463
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue May 20 22:02:49 2014 +0200

    dhcp-lease: add support for parsing a few more dhcp options

diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index 297bacb..ff09583 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -35,19 +35,31 @@
 struct sd_dhcp_lease {
         RefCount n_ref;
 
+        int32_t time_offset;
         uint32_t t1;
         uint32_t t2;
         uint32_t lifetime;
+        uint32_t mtu_aging_timeout;
         be32_t address;
         be32_t server_address;
         be32_t subnet_mask;
         be32_t router;
         be32_t next_server;
+        be32_t broadcast;
         struct in_addr *dns;
         size_t dns_size;
         struct in_addr *ntp;
         size_t ntp_size;
+        struct in_addr *policy_filter;
+        size_t policy_filter_size;
+        struct in_addr *static_route;
+        size_t static_route_size;
+        uint16_t boot_file_size;
+        uint16_t mdr;
         uint16_t mtu;
+        uint8_t ttl;
+        bool ip_forward;
+        bool ip_forward_non_local;
         char *domainname;
         char *hostname;
         char *root_path;
diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h
index 11de186..260508f 100644
--- a/src/libsystemd-network/dhcp-protocol.h
+++ b/src/libsystemd-network/dhcp-protocol.h
@@ -105,12 +105,22 @@ enum {
 enum {
         DHCP_OPTION_PAD                         = 0,
         DHCP_OPTION_SUBNET_MASK                 = 1,
+        DHCP_OPTION_TIME_OFFSET                 = 2,
         DHCP_OPTION_ROUTER                      = 3,
         DHCP_OPTION_DOMAIN_NAME_SERVER          = 6,
         DHCP_OPTION_HOST_NAME                   = 12,
+        DHCP_OPTION_BOOT_FILE_SIZE              = 13,
         DHCP_OPTION_DOMAIN_NAME                 = 15,
         DHCP_OPTION_ROOT_PATH                   = 17,
+        DHCP_OPTION_ENABLE_IP_FORWARDING        = 19,
+        DHCP_OPTION_ENABLE_IP_FORWARDING_NL     = 20,
+        DHCP_OPTION_POLICY_FILTER               = 21,
+        DHCP_OPTION_INTERFACE_MDR               = 22,
+        DHCP_OPTION_INTERFACE_TTL               = 23,
+        DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
         DHCP_OPTION_INTERFACE_MTU               = 26,
+        DHCP_OPTION_BROADCAST                   = 28,
+        DHCP_OPTION_STATIC_ROUTE                = 33,
         DHCP_OPTION_NTP_SERVER                  = 42,
         DHCP_OPTION_REQUESTED_IP_ADDRESS        = 50,
         DHCP_OPTION_IP_ADDRESS_LEASE_TIME       = 51,
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 2ec45ca..3203b7a 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -196,6 +196,10 @@ static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, ui
         }
 }
 
+static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
+        lease_parse_u32(option, len, (uint32_t *)ret, 0);
+}
+
 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
         be16_t val;
 
@@ -219,6 +223,26 @@ static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
                 memcpy(ret, option, 4);
 }
 
+static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
+        assert(option);
+        assert(ret);
+
+        if (len == 1)
+                *ret = !!(*option);
+}
+
+static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
+        assert(option);
+        assert(ret);
+
+        if (len == 1) {
+                *ret = *option;
+
+                if (*ret < min)
+                        *ret = min;
+        }
+}
+
 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
         assert(option);
         assert(ret);
@@ -237,12 +261,12 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
         return 0;
 }
 
-static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
+static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
         assert(option);
         assert(ret);
         assert(ret_size);
 
-        if (len && !(len % 4)) {
+        if (len && !(len % (4 * mult))) {
                 size_t size;
                 struct in_addr *addresses;
 
@@ -260,6 +284,14 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
         return 0;
 }
 
+static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
+        return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
+}
+
+static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
+        return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
+}
+
 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                               void *user_data) {
         sd_dhcp_lease *lease = user_data;
@@ -269,6 +301,16 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 
         switch(code) {
 
+        case DHCP_OPTION_TIME_OFFSET:
+                lease_parse_s32(option, len, &lease->time_offset);
+
+                break;
+
+        case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
+                lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
+
+                break;
+
         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
                 lease_parse_u32(option, len, &lease->lifetime, 1);
 
@@ -284,6 +326,11 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 
                 break;
 
+        case DHCP_OPTION_BROADCAST:
+                lease_parse_be32(option, len, &lease->broadcast);
+
+                break;
+
         case DHCP_OPTION_ROUTER:
                 lease_parse_be32(option, len, &lease->router);
 
@@ -303,11 +350,40 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 
                 break;
 
+        case DHCP_OPTION_POLICY_FILTER:
+                r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
+                if (r < 0)
+                        return r;
+
+                break;
+
+        case DHCP_OPTION_STATIC_ROUTE:
+                r = lease_parse_in_addrs_pairs(option, len, &lease->static_route, &lease->static_route_size);
+                if (r < 0)
+                        return r;
+
+                break;
+
         case DHCP_OPTION_INTERFACE_MTU:
                 lease_parse_u16(option, len, &lease->mtu, 68);
 
                 break;
 
+        case DHCP_OPTION_INTERFACE_MDR:
+                lease_parse_u16(option, len, &lease->mdr, 576);
+
+                break;
+
+        case DHCP_OPTION_INTERFACE_TTL:
+                lease_parse_u8(option, len, &lease->ttl, 1);
+
+                break;
+
+        case DHCP_OPTION_BOOT_FILE_SIZE:
+                lease_parse_u16(option, len, &lease->boot_file_size, 0);
+
+                break;
+
         case DHCP_OPTION_DOMAIN_NAME:
                 r = lease_parse_string(option, len, &lease->domainname);
                 if (r < 0)
@@ -338,6 +414,16 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                 lease_parse_u32(option, len, &lease->t2, 1);
 
                 break;
+
+        case DHCP_OPTION_ENABLE_IP_FORWARDING:
+                lease_parse_bool(option, len, &lease->ip_forward);
+
+                break;
+
+        case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
+                lease_parse_bool(option, len, &lease->ip_forward_non_local);
+
+                break;
         }
 
         return 0;

commit e140ae58f1c10bbd75ef94afc07d07b82323b506
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue May 20 16:40:59 2014 +0200

    dhcp-lease: refactor lease parsing
    
    Use helper functions, and add some more sanity checking/asserts.

diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index cf71f11..2ec45ca 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -181,113 +181,161 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
         return NULL;
 }
 
+static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
+        be32_t val;
+
+        assert(option);
+        assert(ret);
+
+        if (len == 4) {
+                memcpy(&val, option, 4);
+                *ret = be32toh(val);
+
+                if (*ret < min)
+                        *ret = min;
+        }
+}
+
+static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
+        be16_t val;
+
+        assert(option);
+        assert(ret);
+
+        if (len == 2) {
+                memcpy(&val, option, 2);
+                *ret = be16toh(val);
+
+                if (*ret < min)
+                        *ret = min;
+        }
+}
+
+static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
+        assert(option);
+        assert(ret);
+
+        if (len == 4)
+                memcpy(ret, option, 4);
+}
+
+static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
+        assert(option);
+        assert(ret);
+
+        if (len >= 1) {
+                char *string;
+
+                string = strndup((const char *)option, len);
+                if (!string)
+                        return -errno;
+
+                free(*ret);
+                *ret = string;
+        }
+
+        return 0;
+}
+
+static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
+        assert(option);
+        assert(ret);
+        assert(ret_size);
+
+        if (len && !(len % 4)) {
+                size_t size;
+                struct in_addr *addresses;
+
+                size = len / 4;
+
+                addresses = newdup(struct in_addr, option, size);
+                if (!addresses)
+                        return -ENOMEM;
+
+                free(*ret);
+                *ret = addresses;
+                *ret_size = size;
+        }
+
+        return 0;
+}
+
 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                               void *user_data) {
         sd_dhcp_lease *lease = user_data;
-        be32_t val;
+        int r;
+
+        assert(lease);
 
         switch(code) {
 
         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
-                if (len == 4) {
-                        memcpy(&val, option, 4);
-                        lease->lifetime = be32toh(val);
-                }
+                lease_parse_u32(option, len, &lease->lifetime, 1);
 
                 break;
 
         case DHCP_OPTION_SERVER_IDENTIFIER:
-                if (len >= 4)
-                        memcpy(&lease->server_address, option, 4);
+                lease_parse_be32(option, len, &lease->server_address);
 
                 break;
 
         case DHCP_OPTION_SUBNET_MASK:
-                if (len >= 4)
-                        memcpy(&lease->subnet_mask, option, 4);
+                lease_parse_be32(option, len, &lease->subnet_mask);
 
                 break;
 
         case DHCP_OPTION_ROUTER:
-                if (len >= 4)
-                        memcpy(&lease->router, option, 4);
+                lease_parse_be32(option, len, &lease->router);
 
                 break;
 
         case DHCP_OPTION_DOMAIN_NAME_SERVER:
-                if (len && !(len % 4)) {
-                        lease->dns_size = len / 4;
-
-                        free(lease->dns);
-                        lease->dns = newdup(struct in_addr, option, lease->dns_size);
-                        if (!lease->dns)
-                                return -ENOMEM;
-                }
+                r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
+                if (r < 0)
+                        return r;
 
                 break;
 
         case DHCP_OPTION_NTP_SERVER:
-                if (len && !(len % 4)) {
-                        lease->ntp_size = len / 4;
-
-                        free(lease->ntp);
-                        lease->ntp = newdup(struct in_addr, option, lease->ntp_size);
-                        if (!lease->ntp)
-                                return -ENOMEM;
-                }
+                r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
+                if (r < 0)
+                        return r;
 
                 break;
 
         case DHCP_OPTION_INTERFACE_MTU:
-                if (len >= 2) {
-                        be16_t mtu;
-
-                        memcpy(&mtu, option, 2);
-                        lease->mtu = be16toh(mtu);
-
-                        if (lease->mtu < 68)
-                                lease->mtu = 0;
-                }
+                lease_parse_u16(option, len, &lease->mtu, 68);
 
                 break;
 
         case DHCP_OPTION_DOMAIN_NAME:
-                if (len >= 1) {
-                        free(lease->domainname);
-                        lease->domainname = strndup((const char *)option, len);
-                }
+                r = lease_parse_string(option, len, &lease->domainname);
+                if (r < 0)
+                        return r;
 
                 break;
 
         case DHCP_OPTION_HOST_NAME:
-                if (len >= 1) {
-                        free(lease->hostname);
-                        lease->hostname = strndup((const char *)option, len);
-                }
+                r = lease_parse_string(option, len, &lease->hostname);
+                if (r < 0)
+                        return r;
 
                 break;
 
         case DHCP_OPTION_ROOT_PATH:
-                if (len >= 1) {
-                        free(lease->root_path);
-                        lease->root_path = strndup((const char *)option, len);
-                }
+                r = lease_parse_string(option, len, &lease->root_path);
+                if (r < 0)
+                        return r;
 
                 break;
 
         case DHCP_OPTION_RENEWAL_T1_TIME:
-                if (len == 4) {
-                        memcpy(&val, option, 4);
-                        lease->t1 = be32toh(val);
-                }
+                lease_parse_u32(option, len, &lease->t1, 1);
 
                 break;
 
         case DHCP_OPTION_REBINDING_T2_TIME:
-                if (len == 4) {
-                        memcpy(&val, option, 4);
-                        lease->t2 = be32toh(val);
-                }
+                lease_parse_u32(option, len, &lease->t2, 1);
 
                 break;
         }

commit 32008a9636b3781112d349e77ee9e3279104b01c
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue May 20 13:07:19 2014 +0200

    sd-dhcp: refactor parse_options
    
    Similar to the previous patch, exchange a length and a pointer with only one offset variable.
    Also fix the type of the options to be uint8_t[], rather than uint8_t*.

diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index 7bf8812..6895092 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -60,86 +60,86 @@ int dhcp_option_append(uint8_t options[], size_t size, size_t *offset,
         return 0;
 }
 
-static int parse_options(const uint8_t *buf, size_t buflen, uint8_t *overload,
+static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
                          uint8_t *message_type, dhcp_option_cb_t cb,
-                         void *user_data)
-{
-        const uint8_t *code = buf;
-        const uint8_t *len;
+                         void *user_data) {
+        uint8_t code, len;
+        size_t offset = 0;
 
-        while (buflen > 0) {
-                switch (*code) {
+        while (offset < buflen) {
+                switch (options[offset]) {
                 case DHCP_OPTION_PAD:
-                        buflen -= 1;
-                        code++;
+                        offset++;
+
                         break;
 
                 case DHCP_OPTION_END:
                         return 0;
 
                 case DHCP_OPTION_MESSAGE_TYPE:
-                        if (buflen < 3)
+                        if (buflen < offset + 3)
                                 return -ENOBUFS;
-                        buflen -= 3;
 
-                        len = code + 1;
-                        if (*len != 1)
+                        len = options[++offset];
+                        if (len != 1)
                                 return -EINVAL;
 
                         if (message_type)
-                                *message_type = *(len + 1);
+                                *message_type = options[++offset];
+                        else
+                                offset++;
 
-                        code += 3;
+                        offset++;
 
                         break;
 
                 case DHCP_OPTION_OVERLOAD:
-                        if (buflen < 3)
+                        if (buflen < offset + 3)
                                 return -ENOBUFS;
-                        buflen -= 3;
 
-                        len = code + 1;
-                        if (*len != 1)
+                        len = options[++offset];
+                        if (len != 1)
                                 return -EINVAL;
 
                         if (overload)
-                                *overload = *(len + 1);
+                                *overload = options[++offset];
+                        else
+                                offset++;
 
-                        code += 3;
+                        offset++;
 
                         break;
 
                 default:
-                        if (buflen < 3)
+                        if (buflen < offset + 3)
                                 return -ENOBUFS;
 
-                        len = code + 1;
+                        code = options[offset];
+                        len = options[++offset];
 
-                        if (buflen < (size_t)*len + 2)
+                        if (buflen < ++offset + len)
                                 return -EINVAL;
-                        buflen -= *len + 2;
 
                         if (cb)
-                                cb(*code, *len, len + 1, user_data);
+                                cb(code, len, &options[offset], user_data);
 
-                        code += *len + 2;
+                        offset += len;
 
                         break;
                 }
         }
 
-        if (buflen)
+        if (offset < buflen)
                 return -EINVAL;
 
         return 0;
 }
 
 int dhcp_option_parse(DHCPMessage *message, size_t len,
-                      dhcp_option_cb_t cb, void *user_data)
-{
+                      dhcp_option_cb_t cb, void *user_data) {
         uint8_t overload = 0;
         uint8_t message_type = 0;
-        int res;
+        int r;
 
         if (!message)
                 return -EINVAL;
@@ -149,23 +149,23 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
 
         len -= sizeof(DHCPMessage);
 
-        res = parse_options(message->options, len, &overload, &message_type,
-                            cb, user_data);
-        if (res < 0)
-                return res;
+        r = parse_options(message->options, len, &overload, &message_type,
+                          cb, user_data);
+        if (r < 0)
+                return r;
 
         if (overload & DHCP_OVERLOAD_FILE) {
-                res = parse_options(message->file, sizeof(message->file),
+                r = parse_options(message->file, sizeof(message->file),
                                 NULL, &message_type, cb, user_data);
-                if (res < 0)
-                        return res;
+                if (r < 0)
+                        return r;
         }
 
         if (overload & DHCP_OVERLOAD_SNAME) {
-                res = parse_options(message->sname, sizeof(message->sname),
+                r = parse_options(message->sname, sizeof(message->sname),
                                 NULL, &message_type, cb, user_data);
-                if (res < 0)
-                        return res;
+                if (r < 0)
+                        return r;
         }
 
         if (message_type)

commit 20b958bf157dfb2f521b191ef7158035bcaa3003
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue May 20 11:04:50 2014 +0200

    sd-dhcp: refactor dhcp_option_append
    
    Store a pointer to the options in the DHCPMessage struct, and pass
    this together with an offset around, rather than a uint8_t**.
    
    This avoids us having to (re)compute the pointer; and changes
    dhcp_option_append from adjusting both the pointer to the next
    option and the remaining size of the options, to just adjusting
    the current offset.
    
    This makes the code a bit simpler to follow IMHO, but there should
    be no functional change.

diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index eb4a6cd..56423a2 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -36,8 +36,8 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
                                  const void *packet, size_t len);
 
-int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
-                       size_t optlen, const void *optval);
+int dhcp_option_append(uint8_t options[], size_t size, size_t *offset,
+                       uint8_t code, size_t optlen, const void *optval);
 
 typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
                                 const uint8_t *option, void *user_data);
@@ -46,7 +46,7 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
                       dhcp_option_cb_t cb, void *user_data);
 
 int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type,
-                      uint8_t **opt, size_t *optlen);
+                      uint8_t options[], size_t optlen, size_t *optoffset);
 
 uint16_t dhcp_packet_checksum(void *buf, size_t len);
 
diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index 1b92e86..7bf8812 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -26,37 +26,33 @@
 
 #include "dhcp-internal.h"
 
-int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
-                       size_t optlen, const void *optval)
-{
-        if (!buf || !buflen)
-                return -EINVAL;
+int dhcp_option_append(uint8_t options[], size_t size, size_t *offset,
+                       uint8_t code, size_t optlen, const void *optval) {
+        assert(options);
+        assert(offset);
 
         switch (code) {
 
         case DHCP_OPTION_PAD:
         case DHCP_OPTION_END:
-                if (*buflen < 1)
+                if (size - *offset < 1)
                         return -ENOBUFS;
 
-                (*buf)[0] = code;
-                *buf += 1;
-                *buflen -= 1;
+                options[*offset] = code;
+                *offset += 1;
                 break;
 
         default:
-                if (*buflen < optlen + 2)
+                if (size - *offset < optlen + 2)
                         return -ENOBUFS;
 
-                if (!optval)
-                        return -EINVAL;
+                assert(optval);
 
-                (*buf)[0] = code;
-                (*buf)[1] = optlen;
-                memcpy(&(*buf)[2], optval, optlen);
+                options[*offset] = code;
+                options[*offset + 1] = optlen;
+                memcpy(&options[*offset + 2], optval, optlen);
 
-                *buf += optlen + 2;
-                *buflen -= (optlen + 2);
+                *offset += optlen + 2;
 
                 break;
         }
@@ -143,7 +139,6 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
 {
         uint8_t overload = 0;
         uint8_t message_type = 0;
-        uint8_t *opt = (uint8_t *)(message + 1);
         int res;
 
         if (!message)
@@ -154,7 +149,7 @@ int dhcp_option_parse(DHCPMessage *message, size_t len,
 
         len -= sizeof(DHCPMessage);
 
-        res = parse_options(opt, len, &overload, &message_type,
+        res = parse_options(message->options, len, &overload, &message_type,
                             cb, user_data);
         if (res < 0)
                 return res;
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index d72d7a6..10b6457 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -38,8 +38,9 @@
 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
 
 int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
-                      uint8_t type, uint8_t **opt, size_t *optlen) {
-        int err;
+                      uint8_t type, uint8_t options[], size_t optlen, size_t *optoffset) {
+        size_t offset = 0;
+        int r;
 
         assert(op == BOOTREQUEST || op == BOOTREPLY);
 
@@ -49,12 +50,12 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
         message->xid = htobe32(xid);
         message->magic = htobe32(DHCP_MAGIC_COOKIE);
 
-        *opt = (uint8_t *)(message + 1);
+        r = dhcp_option_append(message->options, optlen, &offset,
+                                 DHCP_OPTION_MESSAGE_TYPE, 1, &type);
+        if (r < 0)
+                return r;
 
-        err = dhcp_option_append(opt, optlen, DHCP_OPTION_MESSAGE_TYPE, 1,
-                                 &type);
-        if (err < 0)
-                return err;
+        *optoffset = offset;
 
         return 0;
 }
diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h
index 539606c..11de186 100644
--- a/src/libsystemd-network/dhcp-protocol.h
+++ b/src/libsystemd-network/dhcp-protocol.h
@@ -44,6 +44,7 @@ struct DHCPMessage {
         uint8_t sname[64];
         uint8_t file[128];
         be32_t magic;
+        uint8_t options[0];
 } _packed_;
 
 typedef struct DHCPMessage DHCPMessage;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 94235cf..cee4ccf 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -257,19 +257,18 @@ static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
 }
 
 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
-                               uint8_t type, uint8_t **opt, size_t *optlen) {
+                               uint8_t type, size_t optlen, size_t *optoffset) {
         be16_t max_size;
         int r;
 
         assert(client);
         assert(client->secs);
         assert(message);
-        assert(opt);
-        assert(optlen);
+        assert(optoffset);
         assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
 
-        r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
-                              optlen);
+        r = dhcp_message_init(message, BOOTREQUEST, client->xid, type,
+                              message->options, optlen, optoffset);
         if (r < 0)
                 return r;
 
@@ -285,7 +284,8 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
 
         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
            Identifier option is not set */
-        r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
+        r = dhcp_option_append(message->options, optlen, optoffset,
+                               DHCP_OPTION_CLIENT_IDENTIFIER,
                                sizeof(client->client_id), &client->client_id);
         if (r < 0)
                 return r;
@@ -299,10 +299,9 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
            it MUST include that list in any subsequent DHCPREQUEST
            messages.
          */
-        r = dhcp_option_append(opt, optlen,
+        r = dhcp_option_append(message->options, optlen, optoffset,
                                DHCP_OPTION_PARAMETER_REQUEST_LIST,
-                               client->req_opts_size,
-                               client->req_opts);
+                               client->req_opts_size, client->req_opts);
         if (r < 0)
                 return r;
 
@@ -316,7 +315,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
          */
         max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
                            DHCP_MIN_OPTIONS_SIZE);
-        r = dhcp_option_append(opt, optlen,
+        r = dhcp_option_append(message->options, optlen, optoffset,
                                DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
                                2, &max_size);
         if (r < 0)
@@ -336,8 +335,7 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
 
 static int client_send_discover(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *discover = NULL;
-        size_t optlen, len;
-        uint8_t *opt;
+        size_t optoffset, optlen, len;
         usec_t time_now;
         int r;
 
@@ -364,7 +362,7 @@ static int client_send_discover(sd_dhcp_client *client) {
                 return -ENOMEM;
 
         r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
-                                &opt, &optlen);
+                                optlen, &optoffset);
         if (r < 0)
                 return r;
 
@@ -375,22 +373,21 @@ static int client_send_discover(sd_dhcp_client *client) {
            option to suggest the lease time it would like.
          */
         if (client->last_addr != INADDR_ANY) {
-                r = dhcp_option_append(&opt, &optlen,
-                                         DHCP_OPTION_REQUESTED_IP_ADDRESS,
-                                         4, &client->last_addr);
+                r = dhcp_option_append(discover->dhcp.options, optlen, &optoffset,
+                                       DHCP_OPTION_REQUESTED_IP_ADDRESS,
+                                       4, &client->last_addr);
                 if (r < 0)
                         return r;
         }
 
-        r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
-        if (r < 0)
-                return r;
+        r = dhcp_option_append(discover->dhcp.options, optlen, &optoffset,
+                               DHCP_OPTION_END, 0, NULL);
 
         /* We currently ignore:
            The client SHOULD wait a random time between one and ten seconds to
            desynchronize the use of DHCP at startup.
          */
-        r = dhcp_client_send_raw(client, discover, len - optlen);
+        r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
         if (r < 0)
                 return r;
 
@@ -401,8 +398,7 @@ static int client_send_discover(sd_dhcp_client *client) {
 
 static int client_send_request(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *request;
-        size_t optlen, len;
-        uint8_t *opt;
+        size_t optoffset, optlen, len;
         int r;
 
         optlen = DHCP_MIN_OPTIONS_SIZE;
@@ -412,8 +408,8 @@ static int client_send_request(sd_dhcp_client *client) {
         if (!request)
                 return -ENOMEM;
 
-        r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
-                                &optlen);
+        r = client_message_init(client, &request->dhcp, DHCP_REQUEST,
+                                optlen, &optoffset);
         if (r < 0)
                 return r;
 
@@ -428,13 +424,13 @@ static int client_send_request(sd_dhcp_client *client) {
                    filled in with the yiaddr value from the chosen DHCPOFFER.
                  */
 
-                r = dhcp_option_append(&opt, &optlen,
+                r = dhcp_option_append(request->dhcp.options, optlen, &optoffset,
                                        DHCP_OPTION_SERVER_IDENTIFIER,
                                        4, &client->lease->server_address);
                 if (r < 0)
                         return r;
 
-                r = dhcp_option_append(&opt, &optlen,
+                r = dhcp_option_append(request->dhcp.options, optlen, &optoffset,
                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                        4, &client->lease->address);
                 if (r < 0)
@@ -447,7 +443,7 @@ static int client_send_request(sd_dhcp_client *client) {
                    option MUST be filled in with client’s notion of its previously
                    assigned address. ’ciaddr’ MUST be zero.
                  */
-                r = dhcp_option_append(&opt, &optlen,
+                r = dhcp_option_append(request->dhcp.options, optlen, &optoffset,
                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                        4, &client->last_addr);
                 if (r < 0)
@@ -480,7 +476,8 @@ static int client_send_request(sd_dhcp_client *client) {
                 return -EINVAL;
         }
 
-        r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
+        r = dhcp_option_append(request->dhcp.options, optlen, &optoffset,
+                               DHCP_OPTION_END, 0, NULL);
         if (r < 0)
                 return r;
 
@@ -489,9 +486,9 @@ static int client_send_request(sd_dhcp_client *client) {
                                                  client->lease->server_address,
                                                  DHCP_PORT_SERVER,
                                                  &request->dhcp,
-                                                 len - optlen - DHCP_IP_UDP_SIZE);
+                                                 sizeof(DHCPMessage) + optoffset);
         } else {
-                r = dhcp_client_send_raw(client, request, len - optlen);
+                r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
         }
         if (r < 0)
                 return r;
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 35db8c1..eaf6a53 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -85,16 +85,14 @@ static void test_invalid_buffer_length(void)
 static void test_message_init(void)
 {
         _cleanup_free_ DHCPMessage *message = NULL;
-        size_t optlen = 3;
+        size_t optlen = 3, optoffset;
         size_t len = sizeof(DHCPMessage) + optlen;
-        uint8_t *opt, *magic;
+        uint8_t *magic;
 
         message = malloc0(len);
 
-        opt = (uint8_t *)(message + 1);
-
         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
-                  DHCP_DISCOVER, &opt, &optlen) >= 0);
+                  DHCP_DISCOVER, message->options, optlen, &optoffset) >= 0);
 
         assert_se(message->xid == htobe32(0x12345678));
         assert_se(message->op == BOOTREQUEST);
@@ -115,13 +113,11 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
 {
         DHCPMessage *message;
         size_t len = sizeof(DHCPMessage) + optlen;
-        uint8_t *opt;
 
         message = malloc0(len);
-        opt = (uint8_t *)(message + 1);
 
         if (options && optlen)
-                memcpy(opt, options, optlen);
+                memcpy(&message->options, options, optlen);
 
         if (file && filelen <= 128)
                 memcpy(&message->file, file, filelen);
@@ -308,46 +304,34 @@ static uint8_t options[64] = {
 
 static void test_option_set(void)
 {
-        size_t len, oldlen;
-        int pos, i;
-        uint8_t *opt;
-
-        assert_se(dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL);
-
-        len = 0;
-        opt = &result[0];
-        assert_se(dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL);
-        assert_se(opt == &result[0] && len == 0);
+        size_t offset = 0, len, pos;
+        unsigned i;
 
-        assert_se(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
+        assert_se(dhcp_option_append(result, 0, &offset, DHCP_OPTION_PAD,
                                   0, NULL) == -ENOBUFS);
-        assert_se(opt == &result[0] && len == 0);
+        assert_se(offset == 0);
 
-        opt = &result[4];
-        len = 1;
-        assert_se(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
+        offset = 4;
+        assert_se(dhcp_option_append(result, 1, &offset, DHCP_OPTION_PAD,
                                     0, NULL) >= 0);
-        assert_se(opt == &result[5] && len == 0);
+        assert_se(offset == 5);
 
-        pos = 4;
+        offset = pos = 4;
         len = 60;
         while (pos < 64 && options[pos] != DHCP_OPTION_END) {
-                opt = &result[pos];
-                oldlen = len;
+                offset = pos;
 
-                assert_se(dhcp_option_append(&opt, &len, options[pos],
-                                          options[pos + 1],
-                                          &options[pos + 2]) >= 0);
+                assert_se(dhcp_option_append(result, len, &offset,
+                                             options[pos],
+                                             options[pos + 1],
+                                             &options[pos + 2]) >= 0);
 
-                if (options[pos] == DHCP_OPTION_PAD) {
-                        assert_se(opt == &result[pos + 1]);
-                        assert_se(len == oldlen - 1);
+                if (options[pos] == DHCP_OPTION_PAD)
                         pos++;
-                } else {
-                        assert_se(opt == &result[pos + 2 + options[pos + 1]]);
-                        assert_se(len == oldlen - 2 - options[pos + 1]);
+                else
                         pos += 2 + options[pos + 1];
-                }
+
+                assert_se(offset == pos);
         }
 
         for (i = 0; i < pos; i++) {



More information about the systemd-commits mailing list