dhcp6: Add function for DHCPv6 Status option
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 4 Jan 2018 13:11:42 +0000 (15:11 +0200)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 4 Jan 2018 13:22:43 +0000 (15:22 +0200)
Factor out code to parse a DHCPv6 Status option using a common
function.

src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/sd-dhcp6-client.c

index 9e7d3976aa38a342d78b467ceee9d59607b7c548..982ce3608a53305569d6ec9641f674f179d2604d 100644 (file)
@@ -83,6 +83,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
 int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
                        size_t *optlen, uint8_t **optvalue);
+int dhcp6_option_parse_status(DHCP6Option *option);
 int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia);
 int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
                                 struct in6_addr **addrs, size_t count,
index 80925b3948ca1e5544c5d239fab138484ecdee27..b18a996d8661c0a49978faeaa3b78a83923c5a2a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "alloc-util.h"
 #include "dhcp6-internal.h"
+#include "dhcp6-lease-internal.h"
 #include "dhcp6-protocol.h"
 #include "dns-domain.h"
 #include "sparse-endian.h"
 #include "unaligned.h"
 #include "util.h"
 
+typedef struct DHCP6StatusOption {
+        struct DHCP6Option option;
+        be16_t status;
+        char msg[];
+} _packed_ DHCP6StatusOption;
+
 #define DHCP6_OPTION_IA_NA_LEN                  12
 #define DHCP6_OPTION_IA_TA_LEN                  4
 
@@ -207,6 +214,15 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
         return 0;
 }
 
+int dhcp6_option_parse_status(DHCP6Option *option) {
+        DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option;
+
+        if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*statusopt))
+                return -ENOBUFS;
+
+        return be16toh(statusopt->status);
+}
+
 int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) {
         uint16_t iatype, optlen;
         size_t i, len;
@@ -302,15 +318,14 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) {
                         break;
 
                 case SD_DHCP6_OPTION_STATUS_CODE:
-                        if (optlen < sizeof(status)) {
-                                r = -ENOMSG;
-                                goto error;
-                        }
 
-                        status = option->data[0] << 8 | option->data[1];
+                        status = dhcp6_option_parse_status(option);
                         if (status) {
                                 log_dhcp6_client(client, "IA status %d",
                                                  status);
+
+                                dhcp6_lease_free_ia(ia);
+
                                 r = -EINVAL;
                                 goto error;
                         }
index 9c758a4d0bc00d797d347d2ce95ac578f9df4550..3659356b56988f5f52248d99c5fc1af58f54659a 100644 (file)
@@ -740,7 +740,8 @@ static int client_parse_message(
 
         while (pos < len) {
                 DHCP6Option *option = (DHCP6Option *)&message->options[pos];
-                uint16_t optcode, optlen, status;
+                uint16_t optcode, optlen;
+                int status;
                 uint8_t *optval;
                 be32_t iaid_lease;
 
@@ -795,14 +796,13 @@ static int client_parse_message(
                         break;
 
                 case SD_DHCP6_OPTION_STATUS_CODE:
-                        if (optlen < 2)
-                                return -EINVAL;
-
-                        status = optval[0] << 8 | optval[1];
+                        status = dhcp6_option_parse_status(option);
                         if (status) {
                                 log_dhcp6_client(client, "%s Status %s",
                                                  dhcp6_message_type_to_string(message->type),
                                                  dhcp6_message_status_to_string(status));
+                                dhcp6_lease_free_ia(&lease->ia);
+
                                 return -EINVAL;
                         }