chiark / gitweb /
man/tmpfiles.d: fix typo
[elogind.git] / src / libsystemd-network / dhcp6-option.c
index f488832cf919ca4406c3a192ee124b9b05cb8323..a46b6e3096c8b96ff19b80bc442f5b1a4359f1ab 100644 (file)
 #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
-#define DHCP6_OPTION_IAADDR_LEN                 24
+
+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;
 }
@@ -58,13 +63,14 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                         size_t optlen, const void *optval) {
         int r;
 
-        assert_return(optval, -EINVAL);
+        assert_return(optval || optlen == 0, -EINVAL);
 
         r = option_append_hdr(buf, buflen, code, optlen);
         if (r < 0)
                 return r;
 
-        memcpy(*buf, optval, optlen);
+        if (optval)
+                memcpy(*buf, optval, optlen);
 
         *buf += optlen;
         *buflen -= optlen;
@@ -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);
 
@@ -110,16 +116,16 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
 
         LIST_FOREACH(addresses, addr, ia->addresses) {
                 r = option_append_hdr(buf, buflen, DHCP6_OPTION_IAADDR,
-                                      DHCP6_OPTION_IAADDR_LEN);
+                                      sizeof(addr->iaaddr));
                 if (r < 0)
                         return r;
 
-                memcpy(*buf, &addr->address, DHCP6_OPTION_IAADDR_LEN);
+                memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr));
 
-                *buf += DHCP6_OPTION_IAADDR_LEN;
-                *buflen -= DHCP6_OPTION_IAADDR_LEN;
+                *buf += sizeof(addr->iaaddr);
+                *buflen -= sizeof(addr->iaaddr);
 
-                ia_addrlen += DHCP6_OPTION_HDR_LEN + DHCP6_OPTION_IAADDR_LEN;
+                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,8 +197,8 @@ 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 +
-                    DHCP6_OPTION_IAADDR_LEN) {
+                if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) +
+                    sizeof(addr->iaaddr)) {
                         r = -ENOBUFS;
                         goto error;
                 }
@@ -212,8 +219,8 @@ 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 +
-                    DHCP6_OPTION_IAADDR_LEN) {
+                if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) +
+                    sizeof(addr->iaaddr)) {
                         r = -ENOBUFS;
                         goto error;
                 }
@@ -249,10 +256,10 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
 
                         LIST_INIT(addresses, addr);
 
-                        memcpy(&addr->address, *buf, DHCP6_OPTION_IAADDR_LEN);
+                        memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr));
 
-                        lt_valid = be32toh(addr->lifetime_valid);
-                        lt_pref = be32toh(addr->lifetime_valid);
+                        lt_valid = be32toh(addr->iaaddr.lifetime_valid);
+                        lt_pref = be32toh(addr->iaaddr.lifetime_valid);
 
                         if (!lt_valid || lt_pref > lt_valid) {
                                 log_dhcp6_client(client, "IA preferred %ds > valid %ds",