diff options
-rw-r--r-- | src/libsystemd-network/dhcp6-option.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index e6a31778f4..a46b6e3096 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -24,31 +24,37 @@ #include <string.h> #include "sparse-endian.h" +#include "unaligned.h" #include "util.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" -#define DHCP6_OPTION_HDR_LEN 4 #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 +typedef struct DHCP6Option { + be16_t code; + be16_t len; + uint8_t data[]; +} DHCP6Option; + static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; /* unaligned! */ + assert_return(buf, -EINVAL); assert_return(*buf, -EINVAL); assert_return(buflen, -EINVAL); - if (optlen > 0xffff || *buflen < optlen + DHCP6_OPTION_HDR_LEN) + if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option)) return -ENOBUFS; - (*buf)[0] = optcode >> 8; - (*buf)[1] = optcode & 0xff; - (*buf)[2] = optlen >> 8; - (*buf)[3] = optlen & 0xff; + unaligned_write_be16(&option->code, optcode); + unaligned_write_be16(&option->len, (uint16_t) optlen); - *buf += DHCP6_OPTION_HDR_LEN; - *buflen -= DHCP6_OPTION_HDR_LEN; + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); return 0; } @@ -100,8 +106,8 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { ia_hdr = *buf; ia_buflen = *buflen; - *buf += DHCP6_OPTION_HDR_LEN; - *buflen -= DHCP6_OPTION_HDR_LEN; + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); memcpy(*buf, &ia->id, len); @@ -119,7 +125,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { *buf += sizeof(addr->iaaddr); *buflen -= sizeof(addr->iaaddr); - ia_addrlen += DHCP6_OPTION_HDR_LEN + sizeof(addr->iaaddr); + ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr); } r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); @@ -130,23 +136,24 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { } -static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *opt, +static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; /* unaligned! */ uint16_t len; assert_return(buf, -EINVAL); - assert_return(opt, -EINVAL); + assert_return(optcode, -EINVAL); assert_return(optlen, -EINVAL); - if (*buflen < 4) + if (*buflen < sizeof(DHCP6Option)) return -ENOMSG; - len = (*buf)[2] << 8 | (*buf)[3]; + len = unaligned_read_be16(&option->len); if (len > *buflen) return -ENOMSG; - *opt = (*buf)[0] << 8 | (*buf)[1]; + *optcode = unaligned_read_be16(&option->code); *optlen = len; *buf += 4; @@ -190,7 +197,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, switch (iatype) { case DHCP6_OPTION_IA_NA: - if (*buflen < DHCP6_OPTION_IA_NA_LEN + DHCP6_OPTION_HDR_LEN + + if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; @@ -212,7 +219,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, break; case DHCP6_OPTION_IA_TA: - if (*buflen < DHCP6_OPTION_IA_TA_LEN + DHCP6_OPTION_HDR_LEN + + if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; |