mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
dhcp: introduce sd_dhcp_duid and move relevant functions to sd_dhcp_duid.[ch]
This commit is contained in:
@@ -2,30 +2,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-dhcp-duid.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define SYSTEMD_PEN 43793
|
||||
|
||||
typedef enum DUIDType {
|
||||
DUID_TYPE_LLT = 1,
|
||||
DUID_TYPE_EN = 2,
|
||||
DUID_TYPE_LL = 3,
|
||||
DUID_TYPE_UUID = 4,
|
||||
DUID_TYPE_LLT = SD_DUID_TYPE_LLT,
|
||||
DUID_TYPE_EN = SD_DUID_TYPE_EN,
|
||||
DUID_TYPE_LL = SD_DUID_TYPE_LL,
|
||||
DUID_TYPE_UUID = SD_DUID_TYPE_UUID,
|
||||
_DUID_TYPE_MAX,
|
||||
_DUID_TYPE_INVALID = -EINVAL,
|
||||
_DUID_TYPE_FORCE_U16 = UINT16_MAX,
|
||||
_DUID_TYPE_INVALID = -EINVAL,
|
||||
} DUIDType;
|
||||
|
||||
/* RFC 8415 section 11.1:
|
||||
* A DUID consists of a 2-octet type code represented in network byte order, followed by a variable number of
|
||||
* octets that make up the actual identifier. The length of the DUID (not including the type code) is at
|
||||
* least 1 octet and at most 128 octets. */
|
||||
#define MIN_DUID_DATA_LEN 1
|
||||
#define MAX_DUID_DATA_LEN 128
|
||||
#define MIN_DUID_LEN (sizeof(be16_t) + MIN_DUID_DATA_LEN)
|
||||
#define MAX_DUID_LEN (sizeof(be16_t) + MAX_DUID_DATA_LEN)
|
||||
|
||||
/* https://tools.ietf.org/html/rfc3315#section-9.1 */
|
||||
@@ -52,35 +53,30 @@ struct duid {
|
||||
/* DUID_TYPE_UUID */
|
||||
sd_id128_t uuid;
|
||||
} _packed_ uuid;
|
||||
struct {
|
||||
uint8_t data[MAX_DUID_DATA_LEN];
|
||||
} _packed_ raw;
|
||||
uint8_t data[MAX_DUID_DATA_LEN];
|
||||
};
|
||||
} _packed_;
|
||||
|
||||
int dhcp_identifier_set_duid_llt(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
usec_t t,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len);
|
||||
int dhcp_identifier_set_duid_ll(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len);
|
||||
int dhcp_identifier_set_duid_en(struct duid *ret_duid, size_t *ret_len);
|
||||
int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len);
|
||||
int dhcp_identifier_set_duid_raw(
|
||||
DUIDType duid_type,
|
||||
const uint8_t *buf,
|
||||
size_t buf_len,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len);
|
||||
typedef struct sd_dhcp_duid {
|
||||
size_t size;
|
||||
union {
|
||||
struct duid duid;
|
||||
uint8_t raw[MAX_DUID_LEN];
|
||||
};
|
||||
} sd_dhcp_duid;
|
||||
|
||||
static inline bool duid_size_is_valid(size_t size) {
|
||||
return size >= MIN_DUID_LEN && size <= MAX_DUID_LEN;
|
||||
}
|
||||
|
||||
static inline bool duid_data_size_is_valid(size_t size) {
|
||||
return size >= MIN_DUID_DATA_LEN && size <= MAX_DUID_DATA_LEN;
|
||||
}
|
||||
|
||||
const char *duid_type_to_string(DUIDType t) _const_;
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret);
|
||||
|
||||
const char *duid_type_to_string(DUIDType t) _const_;
|
||||
@@ -1,209 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "netif-util.h"
|
||||
#include "network-common.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-table.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#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 */
|
||||
|
||||
static const char * const duid_type_table[_DUID_TYPE_MAX] = {
|
||||
[DUID_TYPE_LLT] = "DUID-LLT",
|
||||
[DUID_TYPE_EN] = "DUID-EN/Vendor",
|
||||
[DUID_TYPE_LL] = "DUID-LL",
|
||||
[DUID_TYPE_UUID] = "UUID",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
|
||||
|
||||
int dhcp_identifier_set_duid_llt(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
usec_t t,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
uint16_t time_from_2000y;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (hw_addr->length == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (t < USEC_2000)
|
||||
time_from_2000y = 0;
|
||||
else
|
||||
time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff);
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT);
|
||||
unaligned_write_be16(&ret_duid->llt.htype, arp_type);
|
||||
unaligned_write_be32(&ret_duid->llt.time, time_from_2000y);
|
||||
memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length);
|
||||
|
||||
*ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_duid_ll(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (hw_addr->length == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL);
|
||||
unaligned_write_be16(&ret_duid->ll.htype, arp_type);
|
||||
memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length);
|
||||
|
||||
*ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_duid_en(struct duid *ret_duid, size_t *ret_len) {
|
||||
sd_id128_t machine_id;
|
||||
bool test_mode;
|
||||
uint64_t hash;
|
||||
int r;
|
||||
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
test_mode = network_test_mode_enabled();
|
||||
|
||||
if (!test_mode) {
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* For tests, especially for fuzzers, reproducibility is important.
|
||||
* Hence, use a static and constant machine ID.
|
||||
* See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
|
||||
machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_EN);
|
||||
unaligned_write_be32(&ret_duid->en.pen, SYSTEMD_PEN);
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
* directly; duid->en.id might not be aligned, so we need to copy */
|
||||
hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
|
||||
memcpy(ret_duid->en.id, &hash, sizeof(hash));
|
||||
|
||||
*ret_len = offsetof(struct duid, en.id) + sizeof(hash);
|
||||
|
||||
if (test_mode)
|
||||
assert_se(memcmp(ret_duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, *ret_len) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) {
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_UUID);
|
||||
memcpy(&ret_duid->uuid.uuid, &machine_id, sizeof(machine_id));
|
||||
|
||||
*ret_len = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_duid_raw(
|
||||
DUIDType duid_type,
|
||||
const uint8_t *buf,
|
||||
size_t buf_len,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
assert(buf || buf_len == 0);
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (duid_type < 0 || duid_type > UINT16_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (buf_len > MAX_DUID_DATA_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, duid_type);
|
||||
memcpy_safe(ret_duid->raw.data, buf, buf_len);
|
||||
|
||||
*ret_len = offsetof(struct duid, raw.data) + buf_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret) {
|
||||
|
||||
const char *name = NULL;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret);
|
||||
|
||||
if (dev)
|
||||
name = net_get_persistent_name(dev);
|
||||
if (name)
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* fall back to MAC address if no predictable name available */
|
||||
id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
|
||||
|
||||
id32 = (id & 0xffffffff) ^ (id >> 32);
|
||||
|
||||
if (legacy_unstable_byteorder)
|
||||
/* for historical reasons (a bug), the bits were swapped and thus
|
||||
* the result was endianness dependent. Preserve that behavior. */
|
||||
id32 = bswap_32(id32);
|
||||
else
|
||||
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||
* to be more common, swap the bytes on LE to give the same as legacy
|
||||
* behavior. */
|
||||
id32 = be32toh(id32);
|
||||
|
||||
unaligned_write_ne32(ret, id32);
|
||||
return 0;
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "sd-event.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp6-client-internal.h"
|
||||
#include "dhcp6-option.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
@@ -64,8 +64,7 @@ struct sd_dhcp6_client {
|
||||
DHCP6IA ia_na;
|
||||
DHCP6IA ia_pd;
|
||||
DHCP6RequestIA request_ia;
|
||||
struct duid duid;
|
||||
size_t duid_len;
|
||||
sd_dhcp_duid duid;
|
||||
be16_t *req_opts;
|
||||
size_t n_req_opts;
|
||||
char *fqdn;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
sources = files(
|
||||
'arp-util.c',
|
||||
'dhcp-identifier.c',
|
||||
'dhcp-network.c',
|
||||
'dhcp-option.c',
|
||||
'dhcp-packet.c',
|
||||
@@ -17,6 +16,7 @@ sources = files(
|
||||
'network-common.c',
|
||||
'network-internal.c',
|
||||
'sd-dhcp-client.c',
|
||||
'sd-dhcp-duid.c',
|
||||
'sd-dhcp-lease.c',
|
||||
'sd-dhcp-server.c',
|
||||
'sd-dhcp6-client.c',
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-client-internal.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-network.h"
|
||||
#include "dhcp-option.h"
|
||||
@@ -451,29 +451,45 @@ static int dhcp_client_set_iaid(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_client_set_iaid_duid(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
sd_dhcp_duid *duid) {
|
||||
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -ESTALE);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memcpy(&client->client_id.ns.duid, &duid->duid, duid->size);
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_iaid_duid_llt(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
usec_t llt_time) {
|
||||
|
||||
size_t len;
|
||||
sd_dhcp_duid duid;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
r = sd_dhcp_duid_set_llt(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->client_id.ns.duid, &len);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m");
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
|
||||
|
||||
return 0;
|
||||
return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_iaid_duid_ll(
|
||||
@@ -481,23 +497,17 @@ int sd_dhcp_client_set_iaid_duid_ll(
|
||||
bool iaid_set,
|
||||
uint32_t iaid) {
|
||||
|
||||
size_t len;
|
||||
sd_dhcp_duid duid;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
r = sd_dhcp_duid_set_ll(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->client_id.ns.duid, &len);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m");
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
|
||||
|
||||
return 0;
|
||||
return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_iaid_duid_en(
|
||||
@@ -505,23 +515,17 @@ int sd_dhcp_client_set_iaid_duid_en(
|
||||
bool iaid_set,
|
||||
uint32_t iaid) {
|
||||
|
||||
size_t len;
|
||||
sd_dhcp_duid duid;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
r = sd_dhcp_duid_set_en(&duid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m");
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
|
||||
|
||||
return 0;
|
||||
return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_iaid_duid_uuid(
|
||||
@@ -529,23 +533,17 @@ int sd_dhcp_client_set_iaid_duid_uuid(
|
||||
bool iaid_set,
|
||||
uint32_t iaid) {
|
||||
|
||||
size_t len;
|
||||
sd_dhcp_duid duid;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
r = sd_dhcp_duid_set_uuid(&duid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m");
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
|
||||
|
||||
return 0;
|
||||
return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_iaid_duid_raw(
|
||||
@@ -553,27 +551,21 @@ int sd_dhcp_client_set_iaid_duid_raw(
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
uint16_t duid_type,
|
||||
const uint8_t *duid,
|
||||
size_t duid_len) {
|
||||
const uint8_t *duid_data,
|
||||
size_t duid_data_len) {
|
||||
|
||||
size_t len;
|
||||
sd_dhcp_duid duid;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
|
||||
assert_return(duid || duid_len == 0, -EINVAL);
|
||||
assert_return(duid_data || duid_data_len == 0, -EINVAL);
|
||||
|
||||
r = dhcp_client_set_iaid(client, iaid_set, iaid);
|
||||
r = sd_dhcp_duid_set(&duid, duid_type, duid_data, duid_data_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->client_id.ns.duid, &len);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set DUID: %m");
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
|
||||
|
||||
return 0;
|
||||
return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) {
|
||||
|
||||
241
src/libsystemd-network/sd-dhcp-duid.c
Normal file
241
src/libsystemd-network/sd-dhcp-duid.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "netif-util.h"
|
||||
#include "network-common.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-table.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#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 */
|
||||
|
||||
static const char * const duid_type_table[_DUID_TYPE_MAX] = {
|
||||
[DUID_TYPE_LLT] = "DUID-LLT",
|
||||
[DUID_TYPE_EN] = "DUID-EN/Vendor",
|
||||
[DUID_TYPE_LL] = "DUID-LL",
|
||||
[DUID_TYPE_UUID] = "UUID",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
|
||||
|
||||
int sd_dhcp_duid_clear(sd_dhcp_duid *duid) {
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
*duid = (sd_dhcp_duid) {};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid) {
|
||||
if (!duid)
|
||||
return false;
|
||||
|
||||
return duid_size_is_valid(duid->size);
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size) {
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
assert_return(ret_type, -EINVAL);
|
||||
assert_return(ret_data, -EINVAL);
|
||||
assert_return(ret_size, -EINVAL);
|
||||
|
||||
*ret_type = be16toh(duid->duid.type);
|
||||
*ret_data = duid->duid.data;
|
||||
*ret_size = duid->size - offsetof(struct duid, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size) {
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
assert_return(ret_data, -EINVAL);
|
||||
assert_return(ret_size, -EINVAL);
|
||||
|
||||
/* Unlike sd_dhcp_duid_get(), this returns whole DUID including its type. */
|
||||
|
||||
*ret_data = duid->raw;
|
||||
*ret_size = duid->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set(
|
||||
sd_dhcp_duid *duid,
|
||||
uint16_t duid_type,
|
||||
const void *data,
|
||||
size_t data_size) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
assert_return(duid_data_size_is_valid(data_size), -EINVAL);
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, duid_type);
|
||||
memcpy(duid->duid.data, data, data_size);
|
||||
|
||||
duid->size = offsetof(struct duid, data) + data_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_raw(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *data,
|
||||
size_t data_size) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
assert_return(duid_size_is_valid(data_size), -EINVAL);
|
||||
|
||||
/* Unlike sd_dhcp_duid_set(), this takes whole DUID including its type. */
|
||||
|
||||
memcpy(duid->raw, data, data_size);
|
||||
|
||||
duid->size = data_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_llt(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type,
|
||||
uint64_t usec) {
|
||||
|
||||
uint16_t time_from_2000y;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(hw_addr, -EINVAL);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
time_from_2000y = (uint16_t) ((usec_sub_unsigned(usec, USEC_2000) / USEC_PER_SEC) & 0xffffffff);
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LLT);
|
||||
unaligned_write_be16(&duid->duid.llt.htype, arp_type);
|
||||
unaligned_write_be32(&duid->duid.llt.time, time_from_2000y);
|
||||
memcpy(duid->duid.llt.haddr, hw_addr, hw_addr_size);
|
||||
|
||||
duid->size = offsetof(struct duid, llt.haddr) + hw_addr_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_ll(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(hw_addr, -EINVAL);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LL);
|
||||
unaligned_write_be16(&duid->duid.ll.htype, arp_type);
|
||||
memcpy(duid->duid.ll.haddr, hw_addr, hw_addr_size);
|
||||
|
||||
duid->size = offsetof(struct duid, ll.haddr) + hw_addr_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_en(sd_dhcp_duid *duid) {
|
||||
sd_id128_t machine_id;
|
||||
bool test_mode;
|
||||
uint64_t hash;
|
||||
int r;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
test_mode = network_test_mode_enabled();
|
||||
|
||||
if (!test_mode) {
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* For tests, especially for fuzzers, reproducibility is important.
|
||||
* Hence, use a static and constant machine ID.
|
||||
* See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
|
||||
machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_EN);
|
||||
unaligned_write_be32(&duid->duid.en.pen, SYSTEMD_PEN);
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
* directly; duid->en.id might not be aligned, so we need to copy */
|
||||
hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
|
||||
memcpy(duid->duid.en.id, &hash, sizeof(hash));
|
||||
|
||||
duid->size = offsetof(struct duid, en.id) + sizeof(hash);
|
||||
|
||||
if (test_mode)
|
||||
assert_se(memcmp(&duid->duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, duid->size) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid) {
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_UUID);
|
||||
memcpy(&duid->duid.uuid.uuid, &machine_id, sizeof(machine_id));
|
||||
|
||||
duid->size = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret) {
|
||||
|
||||
const char *name = NULL;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret);
|
||||
|
||||
if (dev)
|
||||
name = net_get_persistent_name(dev);
|
||||
if (name)
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* fall back to MAC address if no predictable name available */
|
||||
id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
|
||||
|
||||
id32 = (id & 0xffffffff) ^ (id >> 32);
|
||||
|
||||
if (legacy_unstable_byteorder)
|
||||
/* for historical reasons (a bug), the bits were swapped and thus
|
||||
* the result was endianness dependent. Preserve that behavior. */
|
||||
id32 = bswap_32(id32);
|
||||
else
|
||||
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||
* to be more common, swap the bytes on LE to give the same as legacy
|
||||
* behavior. */
|
||||
id32 = be32toh(id32);
|
||||
|
||||
unaligned_write_ne32(ret, id32);
|
||||
return 0;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dns-domain.h"
|
||||
@@ -191,10 +191,10 @@ int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *
|
||||
static int client_ensure_duid(sd_dhcp6_client *client) {
|
||||
assert(client);
|
||||
|
||||
if (client->duid_len != 0)
|
||||
if (sd_dhcp_duid_is_set(&client->duid))
|
||||
return 0;
|
||||
|
||||
return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
|
||||
return sd_dhcp6_client_set_duid_en(client);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +208,7 @@ int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->duid, &client->duid_len);
|
||||
r = sd_dhcp_duid_set_llt(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m");
|
||||
|
||||
@@ -221,7 +221,7 @@ int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->duid, &client->duid_len);
|
||||
r = sd_dhcp_duid_set_ll(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m");
|
||||
|
||||
@@ -234,7 +234,7 @@ int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
|
||||
r = sd_dhcp_duid_set_en(&client->duid);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m");
|
||||
|
||||
@@ -247,7 +247,7 @@ int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len);
|
||||
r = sd_dhcp_duid_set_uuid(&client->duid);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m");
|
||||
|
||||
@@ -261,7 +261,7 @@ int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, co
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
assert_return(duid || duid_len == 0, -EINVAL);
|
||||
|
||||
r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->duid, &client->duid_len);
|
||||
r = sd_dhcp_duid_set(&client->duid, duid_type, duid, duid_len);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID: %m");
|
||||
|
||||
@@ -276,21 +276,21 @@ int sd_dhcp6_client_duid_as_string(
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->duid_len > offsetof(struct duid, raw.data), -ENODATA);
|
||||
assert_return(sd_dhcp_duid_is_set(&client->duid), -ENODATA);
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
v = duid_type_to_string(be16toh(client->duid.type));
|
||||
v = duid_type_to_string(be16toh(client->duid.duid.type));
|
||||
if (v) {
|
||||
s = strdup(v);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = asprintf(&s, "%0x", client->duid.type);
|
||||
r = asprintf(&s, "%0x", client->duid.duid.type);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
t = hexmem(client->duid.raw.data, client->duid_len - offsetof(struct duid, raw.data));
|
||||
t = hexmem(client->duid.duid.data, client->duid.size - offsetof(struct duid, data));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -825,9 +825,9 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(client->duid_len > 0);
|
||||
assert(sd_dhcp_duid_is_set(&client->duid));
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_CLIENTID,
|
||||
client->duid_len, &client->duid);
|
||||
client->duid.size, &client->duid.duid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -867,7 +867,7 @@ static int dhcp6_lease_parse_message(
|
||||
"%s message does not contain client ID. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
if (memcmp_nn(clientid, clientid_len, &client->duid, client->duid_len) != 0)
|
||||
if (memcmp_nn(clientid, clientid_len, &client->duid.duid, client->duid.size) != 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"The client ID in %s message does not match. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp-network.h"
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-packet.h"
|
||||
@@ -165,19 +165,18 @@ static int check_options(uint8_t code, uint8_t len, const void *option, void *us
|
||||
switch (code) {
|
||||
case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
|
||||
{
|
||||
sd_dhcp_duid duid;
|
||||
uint32_t iaid;
|
||||
struct duid duid;
|
||||
size_t duid_len;
|
||||
|
||||
assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
|
||||
assert_se(sd_dhcp_duid_set_en(&duid) >= 0);
|
||||
assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid) >= 0);
|
||||
|
||||
assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
|
||||
assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid.size);
|
||||
assert_se(len == 19);
|
||||
assert_se(((uint8_t*) option)[0] == 0xff);
|
||||
|
||||
assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
|
||||
assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
|
||||
assert_se(memcmp((uint8_t*) option + 5, &duid.duid, duid.size) == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "sd-dhcp6-client.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "escape.h"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "set.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "bus-util.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "env-file.h"
|
||||
#include "ethtool-util.h"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "sd-netlink.h"
|
||||
#include "sd-resolve.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "firewall-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "networkd-link.h"
|
||||
|
||||
@@ -21,6 +21,7 @@ systemd_headers = files(_systemd_headers)
|
||||
|
||||
_not_installed_headers = [
|
||||
'sd-dhcp-client.h',
|
||||
'sd-dhcp-duid.h',
|
||||
'sd-dhcp-lease.h',
|
||||
'sd-dhcp-option.h',
|
||||
'sd-dhcp-protocol.h',
|
||||
|
||||
69
src/systemd/sd-dhcp-duid.h
Normal file
69
src/systemd/sd-dhcp-duid.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpduidhfoo
|
||||
#define foosddhcpduidhfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_DUID_TYPE_LLT = 1,
|
||||
SD_DUID_TYPE_EN = 2,
|
||||
SD_DUID_TYPE_LL = 3,
|
||||
SD_DUID_TYPE_UUID = 4
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_duid sd_dhcp_duid;
|
||||
|
||||
int sd_dhcp_duid_clear(sd_dhcp_duid *duid);
|
||||
|
||||
int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid);
|
||||
|
||||
int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size);
|
||||
int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size);
|
||||
|
||||
int sd_dhcp_duid_set(
|
||||
sd_dhcp_duid *duid,
|
||||
uint16_t duid_type,
|
||||
const void *data,
|
||||
size_t data_size);
|
||||
int sd_dhcp_duid_set_raw(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *data,
|
||||
size_t data_size);
|
||||
int sd_dhcp_duid_set_llt(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type,
|
||||
uint64_t usec);
|
||||
int sd_dhcp_duid_set_ll(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type);
|
||||
int sd_dhcp_duid_set_en(sd_dhcp_duid *duid);
|
||||
int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user