From: Yu Watanabe Date: Sun, 19 Apr 2026 06:47:45 +0000 (+0900) Subject: dhcp-message: introduce dhcp_message_{append,get}_option_parameter_request_list() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa9584a0371a4e90b12869e7e7a945d46e4218b6;p=thirdparty%2Fsystemd.git dhcp-message: introduce dhcp_message_{append,get}_option_parameter_request_list() These are for DHCP option 55 (parameter request list). --- diff --git a/src/libsystemd-network/dhcp-message.c b/src/libsystemd-network/dhcp-message.c index 0882422d115..a2d0cb8c677 100644 --- a/src/libsystemd-network/dhcp-message.c +++ b/src/libsystemd-network/dhcp-message.c @@ -11,6 +11,8 @@ #include "iovec-wrapper.h" #include "ip-util.h" #include "network-common.h" +#include "set.h" +#include "sort-util.h" #include "string-util.h" static sd_dhcp_message* dhcp_message_free(sd_dhcp_message *message) { @@ -216,6 +218,35 @@ int dhcp_message_append_option_client_id(sd_dhcp_message *message, const sd_dhcp return dhcp_message_append_option(message, SD_DHCP_OPTION_CLIENT_IDENTIFIER, id->size, id->raw); } +static int cmp_uint8(const uint8_t *a, const uint8_t *b) { + assert(a); + assert(b); + + return CMP(*a, *b); +} + +int dhcp_message_append_option_parameter_request_list(sd_dhcp_message *message, Set *prl) { + assert(message); + + size_t len = set_size(prl); + if (len == 0) + return 0; + + _cleanup_free_ uint8_t *buf = new(uint8_t, len); + if (!buf) + return -ENOMEM; + + uint8_t *p = buf; + void *q; + SET_FOREACH(q, prl) + *p++ = PTR_TO_UINT8(q); + + /* Sort the options to make the message reproducible. */ + typesafe_qsort(buf, len, cmp_uint8); + + return dhcp_message_append_option(message, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, len, buf); +} + int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret) { int r; @@ -357,6 +388,33 @@ int dhcp_message_get_option_client_id(sd_dhcp_message *message, sd_dhcp_client_i return sd_dhcp_client_id_set_raw(ret, iov.iov_base, iov.iov_len); } +int dhcp_message_get_option_parameter_request_list(sd_dhcp_message *message, Set **ret) { + int r; + + assert(message); + + _cleanup_(iovec_done) struct iovec iov = {}; + r = dhcp_message_get_option_alloc(message, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, &iov); + if (r < 0) + return r; + + if (!iovec_is_set(&iov)) + return -ENODATA; + + if (!ret) + return 0; + + _cleanup_set_free_ Set *prl = NULL; + for (struct iovec i = iov; iovec_is_set(&i); iovec_inc(&i, 1)) { + r = set_ensure_put(&prl, /* hash_ops= */ NULL, UINT8_TO_PTR(*(uint8_t*) i.iov_base)); + if (r < 0) + return r; + } + + *ret = TAKE_PTR(prl); + return 0; +} + static int dhcp_message_verify_header( const struct iovec *iov, uint8_t op, diff --git a/src/libsystemd-network/dhcp-message.h b/src/libsystemd-network/dhcp-message.h index 50c1810c7d6..4ceba1eec13 100644 --- a/src/libsystemd-network/dhcp-message.h +++ b/src/libsystemd-network/dhcp-message.h @@ -40,6 +40,7 @@ int dhcp_message_append_option_address(sd_dhcp_message *message, uint8_t code, c int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code, size_t n_addr, const struct in_addr *addr); int dhcp_message_append_option_string(sd_dhcp_message *message, uint8_t code, const char *data); int dhcp_message_append_option_client_id(sd_dhcp_message *message, const sd_dhcp_client_id *id); +int dhcp_message_append_option_parameter_request_list(sd_dhcp_message *message, Set *prl); int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret); int dhcp_message_get_option_alloc(sd_dhcp_message *message, uint8_t code, struct iovec *ret); @@ -52,6 +53,7 @@ int dhcp_message_get_option_address(sd_dhcp_message *message, uint8_t code, stru int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, size_t *ret_n_addr, struct in_addr **ret_addr); int dhcp_message_get_option_string(sd_dhcp_message *message, uint8_t code, char **ret); int dhcp_message_get_option_client_id(sd_dhcp_message *message, sd_dhcp_client_id *ret); +int dhcp_message_get_option_parameter_request_list(sd_dhcp_message *message, Set **ret); int dhcp_message_parse( const struct iovec *iov, diff --git a/src/libsystemd-network/test-dhcp-message.c b/src/libsystemd-network/test-dhcp-message.c index cca5c0603b7..bdb3ef921a2 100644 --- a/src/libsystemd-network/test-dhcp-message.c +++ b/src/libsystemd-network/test-dhcp-message.c @@ -10,6 +10,7 @@ #include "iovec-util.h" #include "iovec-wrapper.h" #include "random-util.h" +#include "set.h" #include "strv.h" #include "tests.h" @@ -101,6 +102,12 @@ static void verify_client_id(sd_dhcp_message *m, const sd_dhcp_client_id *expect ASSERT_EQ(client_id_compare_func(&id, expected), 0); } +static void verify_prl(sd_dhcp_message *m, Set *expected) { + _cleanup_set_free_ Set *set = NULL; + ASSERT_OK(dhcp_message_get_option_parameter_request_list(m, &set)); + ASSERT_TRUE(set_equal(set, expected)); +} + TEST(dhcp_message) { _cleanup_(sd_dhcp_message_unrefp) sd_dhcp_message *m = NULL; @@ -132,6 +139,10 @@ TEST(dhcp_message) { .size = 7, }; + _cleanup_set_free_ Set *prl = NULL; + for (uint8_t i = SD_DHCP_OPTION_PRIVATE_BASE; i <= SD_DHCP_OPTION_PRIVATE_LAST; i++) + ASSERT_OK(set_ensure_put(&prl, /* hash_ops= */ NULL, UINT_TO_PTR(i))); + const char *vendor_class = "hogehoge"; char **root_path = STRV_MAKE("/path/to/root", "/hogehoge/foofoo"); @@ -206,6 +217,11 @@ TEST(dhcp_message) { ASSERT_OK(dhcp_message_append_option_client_id(m, &id)); verify_client_id(m, &id); + /* parameter request list */ + ASSERT_OK(dhcp_message_append_option_parameter_request_list(m, prl)); + ASSERT_OK(dhcp_message_append_option_parameter_request_list(m, prl)); + verify_prl(m, prl); + /* build and parse */ _cleanup_(iovw_done_free) struct iovec_wrapper iovw = {}; ASSERT_OK(dhcp_message_build(m, &iovw)); @@ -235,6 +251,7 @@ TEST(dhcp_message) { verify_addresses(m2, ELEMENTSOF(ntp), ntp); verify_string(m2, vendor_class); verify_client_id(m2, &id); + verify_prl(m2, prl); /* build again, and verify the packet */ _cleanup_(iovw_done_free) struct iovec_wrapper iovw2 = {};