]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-network: DHCPv6 - add support to send userclass option
authorSusant Sahani <ssahani@vmware.com>
Mon, 18 May 2020 12:46:50 +0000 (14:46 +0200)
committerSusant Sahani <ssahani@vmware.com>
Tue, 19 May 2020 09:44:51 +0000 (11:44 +0200)
sd-network: DHCPv6 - add support to send userclass option

21.15.  User Class Option

   The User Class option is used by a client to identify the type or
   category of users or applications it represents.

   The format of the User 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_USER_CLASS       |          option-len           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                          user-class-data                      .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                    Figure 26: User Class Option Format

      option-code          OPTION_USER_CLASS (15).

      option-len           Length of user-class-data field.

      user-class-data      The user classes carried by the client.  The
                           length, in octets, is specified by
                           option-len.

The information contained in the data area of this option is
   contained in one or more opaque fields that represent the user class
   or classes of which the client is a member.  A server selects
   configuration information for the client based on the classes
   identified in this option.  For example, the User Class option can be
   used to configure all clients of people in the accounting department
   with a different printer than clients of people in the marketing
   department.  The user class information carried in this option MUST
   be configurable on the client.

   The data area of the User Class option MUST contain one or more
   instances of user-class-data information.  Each instance of
   user-class-data is formatted as follows:

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

                Figure 27: Format of user-class-data Field

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 db80585a22c310c12da72a428df5bd641873ee79..8b651636caf6dc9153898b06256ac360e4cadc09 100644 (file)
@@ -97,6 +97,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
 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_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 3b7c89edd7b2eeab719d78cdedf49bb79a427833..d1a02da35fd26a25451c9aef37c9ed7b9f9ae4c0 100644 (file)
@@ -167,6 +167,36 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         return r;
 }
 
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
+        _cleanup_free_ uint8_t *p = NULL;
+        size_t total = 0, offset = 0;
+        char **s;
+
+        assert_return(buf && *buf && buflen && user_class, -EINVAL);
+
+        STRV_FOREACH(s, user_class) {
+                size_t len = strlen(*s);
+                uint8_t *q;
+
+                if (len > 0xffff)
+                        return -ENAMETOOLONG;
+
+                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_USER_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 51716c28bb604edd4f4e25513cc839a15e7f48d9..0240f1b7c7d2da40d6dd83e42e1a5aab1c197aca 100644 (file)
@@ -67,6 +67,7 @@ struct sd_dhcp6_client {
         size_t req_opts_len;
         char *fqdn;
         char *mudurl;
+        char **user_class;
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
@@ -385,6 +386,27 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
         return free_and_strdup(&client->mudurl, mudurl);
 }
 
+int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
+        _cleanup_strv_free_ char **s = NULL;
+        char **p;
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+        assert_return(user_class, -EINVAL);
+
+        STRV_FOREACH(p, user_class)
+                if (strlen(*p) > UINT16_MAX)
+                        return -ENAMETOOLONG;
+
+        s = strv_copy((char **) user_class);
+        if (!s)
+                return -ENOMEM;
+
+        client->user_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);
@@ -565,6 +587,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_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)
@@ -611,6 +639,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_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)
@@ -645,6 +679,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_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)
@@ -1602,7 +1642,10 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
         free(client->req_opts);
         free(client->fqdn);
         free(client->mudurl);
+
         ordered_hashmap_free(client->extra_options);
+        strv_free(client->user_class);
+
         return mfree(client);
 }
 
index d365fc763805c6d7803a8e1a4535ffc9984fce2e..8011457b76179359376f9ebf773c9e0ecad4bb71 100644 (file)
@@ -125,6 +125,10 @@ 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_prefix_delegation_hint(
                 sd_dhcp6_client *client,
                 uint8_t prefixlen,