For libsystemd's headers, the changes made depend on whether the header is installed or not. For installed headers, the only change made is that commonly included headers were moved to _sd-common.h. For these headers, there should be no noticeable change in behavior when including them. For non-installed headers, includes were replaced with forward declarations where possible as usual. Split out of #37344.
201 lines
6.5 KiB
C
201 lines
6.5 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include "alloc-util.h"
|
|
#include "dhcp-client-id-internal.h"
|
|
#include "iovec-util.h"
|
|
#include "json-util.h"
|
|
#include "log.h"
|
|
#include "siphash24.h"
|
|
#include "string-util.h"
|
|
#include "unaligned.h"
|
|
#include "utf8.h"
|
|
|
|
int sd_dhcp_client_id_clear(sd_dhcp_client_id *client_id) {
|
|
assert_return(client_id, -EINVAL);
|
|
|
|
*client_id = (sd_dhcp_client_id) {};
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_is_set(const sd_dhcp_client_id *client_id) {
|
|
if (!client_id)
|
|
return false;
|
|
|
|
return client_id_size_is_valid(client_id->size);
|
|
}
|
|
|
|
int sd_dhcp_client_id_get(const sd_dhcp_client_id *client_id, uint8_t *ret_type, const void **ret_data, size_t *ret_size) {
|
|
assert_return(sd_dhcp_client_id_is_set(client_id), -EINVAL);
|
|
assert_return(ret_type, -EINVAL);
|
|
assert_return(ret_data, -EINVAL);
|
|
assert_return(ret_size, -EINVAL);
|
|
|
|
*ret_type = client_id->id.type;
|
|
*ret_data = client_id->id.data;
|
|
*ret_size = client_id->size - offsetof(typeof(client_id->id), data);
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_get_raw(const sd_dhcp_client_id *client_id, const void **ret_data, size_t *ret_size) {
|
|
assert_return(sd_dhcp_client_id_is_set(client_id), -EINVAL);
|
|
assert_return(ret_data, -EINVAL);
|
|
assert_return(ret_size, -EINVAL);
|
|
|
|
/* Unlike sd_dhcp_client_id_get(), this returns whole client ID including its type. */
|
|
|
|
*ret_data = client_id->raw;
|
|
*ret_size = client_id->size;
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_set(
|
|
sd_dhcp_client_id *client_id,
|
|
uint8_t type,
|
|
const void *data,
|
|
size_t data_size) {
|
|
|
|
assert_return(client_id, -EINVAL);
|
|
assert_return(data, -EINVAL);
|
|
|
|
if (!client_id_data_size_is_valid(data_size))
|
|
return -EINVAL;
|
|
|
|
client_id->id.type = type;
|
|
memcpy(client_id->id.data, data, data_size);
|
|
|
|
client_id->size = offsetof(typeof(client_id->id), data) + data_size;
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_set_raw(
|
|
sd_dhcp_client_id *client_id,
|
|
const void *data,
|
|
size_t data_size) {
|
|
|
|
assert_return(client_id, -EINVAL);
|
|
assert_return(data, -EINVAL);
|
|
|
|
/* Unlike sd_dhcp_client_id_set(), this takes whole client ID including its type. */
|
|
|
|
if (!client_id_size_is_valid(data_size))
|
|
return -EINVAL;
|
|
|
|
memcpy(client_id->raw, data, data_size);
|
|
|
|
client_id->size = data_size;
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_set_iaid_duid(
|
|
sd_dhcp_client_id *client_id,
|
|
uint32_t iaid,
|
|
sd_dhcp_duid *duid) {
|
|
|
|
assert_return(client_id, -EINVAL);
|
|
assert_return(duid, -EINVAL);
|
|
assert_return(sd_dhcp_duid_is_set(duid), -ESTALE);
|
|
|
|
client_id->id.type = 255;
|
|
unaligned_write_be32(&client_id->id.ns.iaid, iaid);
|
|
memcpy(&client_id->id.ns.duid, &duid->duid, duid->size);
|
|
|
|
client_id->size = offsetof(typeof(client_id->id), ns.duid) + duid->size;
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_to_string(const sd_dhcp_client_id *client_id, char **ret) {
|
|
_cleanup_free_ char *t = NULL;
|
|
size_t len;
|
|
int r;
|
|
|
|
assert_return(sd_dhcp_client_id_is_set(client_id), -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
len = client_id->size - offsetof(typeof(client_id->id), data);
|
|
|
|
switch (client_id->id.type) {
|
|
case 0:
|
|
if (utf8_is_printable((char *) client_id->id.gen.data, len))
|
|
r = asprintf(&t, "%.*s", (int) len, client_id->id.gen.data);
|
|
else
|
|
r = asprintf(&t, "DATA");
|
|
break;
|
|
case 1:
|
|
if (len == sizeof_field(sd_dhcp_client_id, id.eth))
|
|
r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
client_id->id.eth.haddr[0],
|
|
client_id->id.eth.haddr[1],
|
|
client_id->id.eth.haddr[2],
|
|
client_id->id.eth.haddr[3],
|
|
client_id->id.eth.haddr[4],
|
|
client_id->id.eth.haddr[5]);
|
|
else
|
|
r = asprintf(&t, "ETHER");
|
|
break;
|
|
case 2 ... 254:
|
|
r = asprintf(&t, "ARP/LL");
|
|
break;
|
|
case 255:
|
|
if (len < sizeof(uint32_t))
|
|
r = asprintf(&t, "IAID/DUID");
|
|
else {
|
|
uint32_t iaid = be32toh(client_id->id.ns.iaid);
|
|
/* TODO: check and stringify DUID */
|
|
r = asprintf(&t, "IAID:0x%x/DUID", iaid);
|
|
}
|
|
break;
|
|
default:
|
|
assert_not_reached();
|
|
}
|
|
if (r < 0)
|
|
return -ENOMEM;
|
|
|
|
*ret = TAKE_PTR(t);
|
|
return 0;
|
|
}
|
|
|
|
int sd_dhcp_client_id_to_string_from_raw(const void *data, size_t data_size, char **ret) {
|
|
sd_dhcp_client_id client_id;
|
|
int r;
|
|
|
|
assert_return(data, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
r = sd_dhcp_client_id_set_raw(&client_id, data, data_size);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return sd_dhcp_client_id_to_string(&client_id, ret);
|
|
}
|
|
|
|
void client_id_hash_func(const sd_dhcp_client_id *client_id, struct siphash *state) {
|
|
assert(sd_dhcp_client_id_is_set(client_id));
|
|
assert(state);
|
|
|
|
siphash24_compress_typesafe(client_id->size, state);
|
|
siphash24_compress(client_id->raw, client_id->size, state);
|
|
}
|
|
|
|
int client_id_compare_func(const sd_dhcp_client_id *a, const sd_dhcp_client_id *b) {
|
|
assert(sd_dhcp_client_id_is_set(a));
|
|
assert(sd_dhcp_client_id_is_set(b));
|
|
|
|
return memcmp_nn(a->raw, a->size, b->raw, b->size);
|
|
}
|
|
|
|
int json_dispatch_client_id(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
|
sd_dhcp_client_id *client_id = ASSERT_PTR(userdata);
|
|
_cleanup_(iovec_done) struct iovec iov = {};
|
|
int r;
|
|
|
|
r = json_dispatch_byte_array_iovec(name, variant, flags, &iov);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = sd_dhcp_client_id_set_raw(client_id, iov.iov_base, iov.iov_len);
|
|
if (r < 0)
|
|
return json_log(variant, flags, r, "Failed to set DHCP client ID from JSON field '%s': %m", strna(name));
|
|
|
|
return 0;
|
|
}
|