]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-network: DHCPv6 - Add support to send vendor class data
authorSusant Sahani <ssahani@vmware.com>
Mon, 20 Apr 2020 07:04:58 +0000 (09:04 +0200)
committerSusant Sahani <ssahani@vmware.com>
Wed, 20 May 2020 05:52:19 +0000 (07:52 +0200)
```
21.16.  Vendor Class Option

   This option is used by a client to identify the vendor that
   manufactured the hardware on which the client is running.  The
   information contained in the data area of this option is contained in
   one or more opaque fields that identify details of the hardware
   configuration.  The format of the Vendor Class option is:

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |      OPTION_VENDOR_CLASS      |           option-len          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                       enterprise-number                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                       vendor-class-data                       .
      .                             . . .                             .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                   Figure 28: Vendor Class Option Format

      option-code          OPTION_VENDOR_CLASS (16).

      option-len           4 + length of vendor-class-data field.

      enterprise-number    The vendor's registered Enterprise Number as
                           maintained by IANA [IANA-PEN].  A 4-octet
                           field containing an unsigned integer.

      vendor-class-data    The hardware configuration of the node on
                           which the client is running.  A
                           variable-length field (4 octets less than the
                           value in the option-len field).

   The vendor-class-data field is composed of a series of separate
   items, each of which describes some characteristic of the client's
   hardware configuration.  Examples of vendor-class-data instances
   might include the version of the operating system the client is
   running or the amount of memory installed on the client.

   Each instance of vendor-class-data is formatted as follows:

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
      |       vendor-class-len        |          opaque-data          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+

               Figure 29: Format of vendor-class-data Field

   The vendor-class-len field is 2 octets long and specifies the length
   of the opaque vendor-class-data in network byte order.

   Servers and clients MUST NOT include more than one instance of
   OPTION_VENDOR_CLASS with the same Enterprise Number.  Each instance
   of OPTION_VENDOR_CLASS can carry multiple vendor-class-data
   instances.
   ```

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

index c01c1cf6d6f50b5177ccfe65b175896075e8c020..d0610a32e23d5defcca83889ea716bfb2a4e491e 100644 (file)
@@ -15,7 +15,6 @@
 #include "udev-util.h"
 #include "virt.h"
 
-#define SYSTEMD_PEN    43793
 #define HASH_KEY       SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
 #define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
 #define USEC_2000       ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
index b3115125d9ab1ae59043388e9355ab32763afc54..76abd6583e3a3905ed2cd3349a6040f56e96d5b2 100644 (file)
@@ -8,6 +8,8 @@
 #include "time-util.h"
 #include "unaligned.h"
 
+#define SYSTEMD_PEN    43793
+
 typedef enum DUIDType {
         DUID_TYPE_LLT       = 1,
         DUID_TYPE_EN        = 2,
index 8b651636caf6dc9153898b06256ac360e4cadc09..ced85fd3afe7a0a26b3baeb68a81654cc4774eb3 100644 (file)
@@ -98,6 +98,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
 int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
 int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
 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, size_t len);
index d1a02da35fd26a25451c9aef37c9ed7b9f9ae4c0..0ec36507cd46cae97004c42c83e56bb86613f6e9 100644 (file)
@@ -9,6 +9,7 @@
 #include "sd-dhcp6-client.h"
 
 #include "alloc-util.h"
+#include "dhcp-identifier.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-lease-internal.h"
 #include "dhcp6-protocol.h"
@@ -180,7 +181,6 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
 
                 if (len > 0xffff)
                         return -ENAMETOOLONG;
-
                 q = realloc(p, total + len + 2);
                 if (!q)
                         return -ENOMEM;
@@ -197,6 +197,46 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
         return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
 }
 
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
+        _cleanup_free_ uint8_t *p = NULL;
+        uint32_t enterprise_identifier;
+        size_t total, offset;
+        char **s;
+
+        assert(buf);
+        assert(*buf);
+        assert(buflen);
+        assert(vendor_class);
+
+        enterprise_identifier = htobe32(SYSTEMD_PEN);
+
+        p = memdup(&enterprise_identifier, sizeof(enterprise_identifier));
+        if (!p)
+                return -ENOMEM;
+
+        total = sizeof(enterprise_identifier);
+        offset = total;
+
+        STRV_FOREACH(s, vendor_class) {
+                size_t len = strlen(*s);
+                uint8_t *q;
+
+                q = realloc(p, total + len + 2);
+                if (!q)
+                        return -ENOMEM;
+
+                p = q;
+
+                unaligned_write_be16(&p[offset], len);
+                memcpy(&p[offset + 2], *s, len);
+
+                offset += 2 + len;
+                total += 2 + len;
+        }
+
+        return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
+}
+
 int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
         DHCP6Option *option = (DHCP6Option *)buf;
         size_t i = sizeof(*option) + sizeof(pd->ia_pd);
index 0240f1b7c7d2da40d6dd83e42e1a5aab1c197aca..ce9e6cae7e6a68533b5006261a1567bd2487fcc3 100644 (file)
@@ -68,6 +68,7 @@ struct sd_dhcp6_client {
         char *fqdn;
         char *mudurl;
         char **user_class;
+        char **vendor_class;
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
@@ -380,7 +381,7 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
         assert_return(mudurl, -EINVAL);
-        assert_return(strlen(mudurl) <= 255, -EINVAL);
+        assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL);
         assert_return(http_url_is_valid(mudurl), -EINVAL);
 
         return free_and_strdup(&client->mudurl, mudurl);
@@ -392,6 +393,7 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_
 
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+
         assert_return(user_class, -EINVAL);
 
         STRV_FOREACH(p, user_class)
@@ -407,6 +409,27 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_
         return 0;
 }
 
+int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
+        _cleanup_strv_free_ char **s = NULL;
+        char **p;
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+        assert_return(vendor_class, -EINVAL);
+
+        STRV_FOREACH(p, vendor_class)
+                if (strlen(*p) > UINT8_MAX)
+                        return -ENAMETOOLONG;
+
+        s = strv_copy(vendor_class);
+        if (!s)
+                return -ENOMEM;
+
+        client->vendor_class = TAKE_PTR(s);
+
+        return 0;
+}
+
 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
         assert_return(client, -EINVAL);
         assert_return(delegation, -EINVAL);
@@ -593,6 +616,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
@@ -645,6 +674,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -685,6 +720,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -1645,6 +1686,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
 
         ordered_hashmap_free(client->extra_options);
         strv_free(client->user_class);
+        strv_free(client->vendor_class);
 
         return mfree(client);
 }
index 8011457b76179359376f9ebf773c9e0ecad4bb71..c342be4b294b7ef972908c64e5fff5e8a21e764c 100644 (file)
@@ -125,10 +125,12 @@ int sd_dhcp6_client_set_request_option(
 int sd_dhcp6_client_set_request_mud_url(
                 sd_dhcp6_client *client,
                 const char *mudurl);
-
 int sd_dhcp6_client_set_request_user_class(
                 sd_dhcp6_client *client,
                 char** user_class);
+int sd_dhcp6_client_set_request_vendor_class(
+                sd_dhcp6_client *client,
+                char** vendor_class);
 int sd_dhcp6_client_set_prefix_delegation_hint(
                 sd_dhcp6_client *client,
                 uint8_t prefixlen,