summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2018-01-04 15:11:42 +0200
committerPatrik Flykt <patrik.flykt@linux.intel.com>2018-01-04 15:22:43 +0200
commitc6b4f32a507c5ad885265309b2ecb56e618564d5 (patch)
treed32cb199b81a63d999e8b6aba1cb63e71daa48c3 /src
parent3bc424a3cc0bacc688ec2f4f93a5560fb4ca393b (diff)
downloadsystemd-c6b4f32a507c5ad885265309b2ecb56e618564d5.tar.gz
dhcp6: Add function for DHCPv6 Status option
Factor out code to parse a DHCPv6 Status option using a common function.
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd-network/dhcp6-internal.h1
-rw-r--r--src/libsystemd-network/dhcp6-option.c25
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c10
3 files changed, 26 insertions, 10 deletions
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 9e7d3976aa..982ce3608a 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -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,
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index 80925b3948..b18a996d86 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -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"
@@ -33,6 +34,12 @@
#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;
}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 9c758a4d0b..3659356b56 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -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;
}