#include "io-util.h"
#include "memory-util.h"
#include "random-util.h"
+#include "set.h"
+#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
union sockaddr_union link;
sd_event_source *receive_message;
bool request_broadcast;
- uint8_t *req_opts;
- size_t req_opts_allocated;
- size_t req_opts_size;
+ Set *req_opts;
bool anonymize;
be32_t last_addr;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
}
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
- size_t i;
-
assert_return(client, -EINVAL);
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
break;
}
- for (i = 0; i < client->req_opts_size; i++)
- if (client->req_opts[i] == option)
- return -EEXIST;
-
- if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
- client->req_opts_size + 1))
- return -ENOMEM;
-
- client->req_opts[client->req_opts_size++] = option;
-
- return 0;
+ return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
}
int sd_dhcp_client_set_request_address(
client_initialize(client);
}
+static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
+ return CMP(*a, *b);
+}
+
static int client_message_init(
sd_dhcp_client *client,
DHCPPacket **ret,
MAY contain the Parameter Request List option. */
/* NOTE: in case that there would be an option to do not send
* any PRL at all, the size should be checked before sending */
- if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
+ if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) {
+ _cleanup_free_ uint8_t *opts = NULL;
+ size_t n_opts, i = 0;
+ void *val;
+
+ n_opts = set_size(client->req_opts);
+ opts = new(uint8_t, n_opts);
+ if (!opts)
+ return -ENOMEM;
+
+ SET_FOREACH(val, client->req_opts)
+ opts[i++] = PTR_TO_UINT8(val);
+ assert(i == n_opts);
+
+ /* For anonymizing the request, let's sort the options. */
+ typesafe_qsort(opts, n_opts, cmp_uint8);
+
r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
- client->req_opts_size, client->req_opts);
+ n_opts, opts);
if (r < 0)
return r;
}
sd_dhcp_lease_unref(client->lease);
- free(client->req_opts);
+ set_free(client->req_opts);
free(client->hostname);
free(client->vendor_class_identifier);
free(client->mudurl);
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
+ const uint8_t *opts;
+ size_t n_opts;
+ int r;
+
assert_return(ret, -EINVAL);
_cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
};
/* NOTE: this could be moved to a function. */
if (anonymize) {
- client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
- client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
+ n_opts = ELEMENTSOF(default_req_opts_anonymize);
+ opts = default_req_opts_anonymize;
} else {
- client->req_opts_size = ELEMENTSOF(default_req_opts);
- client->req_opts = memdup(default_req_opts, client->req_opts_size);
+ n_opts = ELEMENTSOF(default_req_opts);
+ opts = default_req_opts;
+ }
+
+ for (size_t i = 0; i < n_opts; i++) {
+ r = sd_dhcp_client_set_request_option(client, opts[i]);
+ if (r < 0)
+ return r;
}
- if (!client->req_opts)
- return -ENOMEM;
*ret = TAKE_PTR(client);
assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_ROUTER) == -EEXIST);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_ROUTER) == 0);
/* This PRL option is not set when using Anonymize, but in this test
* Anonymize settings are not being used. */
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_HOST_NAME) == -EEXIST);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST);
-
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_PAD) == -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_END) == -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
- == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == 0);
+
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PAD) == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_END) == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
/* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
* default PRL when using Anonymize, so it is changed to other option
* that is not set by default, to check that it was set successfully.
* Options not set by default (using or not anonymize) are option 17
* (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
+ assert_se(sd_dhcp_client_set_request_option(client, 17) == 1);
+ assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, 42) == 1);
assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
- assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
- assert_se(sd_dhcp_client_set_request_option(client, 42) == 0);
- assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
sd_dhcp_client_unref(client);
}
r = sd_dhcp_client_attach_event(client, e, 0);
assert_se(r >= 0);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_NETBIOS_NAMESERVER) == -EEXIST);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_NETBIOS_NAMESERVER) == 0);
/* This PRL option is not set when using Anonymize */
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_HOST_NAME) == 0);
- assert_se(sd_dhcp_client_set_request_option(client,
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
- == -EINVAL);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 1);
+ assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
/* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
* default PRL when using Anonymize, */
+ assert_se(sd_dhcp_client_set_request_option(client, 101) == 1);
assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
- assert_se(sd_dhcp_client_set_request_option(client, 101) == -EEXIST);
sd_dhcp_client_unref(client);
}