diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index c01c1cf6d6..d0610a32e2 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -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 */ diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index b3115125d9..76abd6583e 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -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, diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 8b651636ca..ced85fd3af 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -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); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index d1a02da35f..0ec36507cd 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -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); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 0240f1b7c7..ce9e6cae7e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -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); } diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 8011457b76..c342be4b29 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -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,