]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
cfb5b380 | 2 | |
51517f9e | 3 | #include "sd-device.h" |
07630cea | 4 | #include "sd-id128.h" |
cfb5b380 | 5 | |
cfb5b380 | 6 | #include "dhcp-identifier.h" |
07630cea | 7 | #include "dhcp6-protocol.h" |
cfb5b380 | 8 | #include "network-internal.h" |
07630cea LP |
9 | #include "siphash24.h" |
10 | #include "sparse-endian.h" | |
07630cea | 11 | #include "virt.h" |
cfb5b380 TG |
12 | |
13 | #define SYSTEMD_PEN 43793 | |
14 | #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) | |
15 | ||
3b6a4e97 ZJS |
16 | int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { |
17 | struct duid d; | |
18 | ||
19 | assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); | |
20 | if (duid_len > MAX_DUID_LEN) | |
21 | return -EINVAL; | |
22 | ||
23 | switch (duid_type) { | |
24 | case DUID_TYPE_LLT: | |
25 | if (duid_len <= sizeof(d.llt)) | |
26 | return -EINVAL; | |
27 | break; | |
28 | case DUID_TYPE_EN: | |
29 | if (duid_len != sizeof(d.en)) | |
30 | return -EINVAL; | |
31 | break; | |
32 | case DUID_TYPE_LL: | |
33 | if (duid_len <= sizeof(d.ll)) | |
34 | return -EINVAL; | |
35 | break; | |
36 | case DUID_TYPE_UUID: | |
37 | if (duid_len != sizeof(d.uuid)) | |
38 | return -EINVAL; | |
39 | break; | |
40 | default: | |
41 | /* accept unknown type in order to be forward compatible */ | |
42 | break; | |
43 | } | |
44 | return 0; | |
45 | } | |
46 | ||
cfb5b380 TG |
47 | int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { |
48 | sd_id128_t machine_id; | |
dbe81cbd | 49 | uint64_t hash; |
cfb5b380 TG |
50 | int r; |
51 | ||
52 | assert(duid); | |
53 | assert(len); | |
54 | ||
55 | r = sd_id128_get_machine(&machine_id); | |
56 | if (r < 0) | |
57 | return r; | |
58 | ||
413708d1 | 59 | unaligned_write_be16(&duid->type, DUID_TYPE_EN); |
9ee18af3 TG |
60 | unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); |
61 | ||
cfb5b380 TG |
62 | *len = sizeof(duid->type) + sizeof(duid->en); |
63 | ||
64 | /* a bit of snake-oil perhaps, but no need to expose the machine-id | |
dbe81cbd | 65 | directly; duid->en.id might not be aligned, so we need to copy */ |
933f9cae | 66 | hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); |
dbe81cbd | 67 | memcpy(duid->en.id, &hash, sizeof(duid->en.id)); |
cfb5b380 TG |
68 | |
69 | return 0; | |
70 | } | |
71 | ||
9ee18af3 | 72 | int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { |
51517f9e YW |
73 | /* name is a pointer to memory in the sd_device struct, so must |
74 | * have the same scope */ | |
75 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; | |
cfb5b380 TG |
76 | const char *name = NULL; |
77 | uint64_t id; | |
78 | ||
75f86906 | 79 | if (detect_container() <= 0) { |
cfb5b380 | 80 | /* not in a container, udev will be around */ |
cfb5b380 | 81 | char ifindex_str[2 + DECIMAL_STR_MAX(int)]; |
51517f9e | 82 | int initialized, r; |
cfb5b380 TG |
83 | |
84 | sprintf(ifindex_str, "n%d", ifindex); | |
51517f9e YW |
85 | if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { |
86 | r = sd_device_get_is_initialized(device, &initialized); | |
87 | if (r < 0) | |
88 | return r; | |
89 | if (!initialized) | |
40862866 TG |
90 | /* not yet ready */ |
91 | return -EBUSY; | |
cfb5b380 | 92 | |
40862866 TG |
93 | name = net_get_name(device); |
94 | } | |
cfb5b380 TG |
95 | } |
96 | ||
97 | if (name) | |
933f9cae | 98 | id = siphash24(name, strlen(name), HASH_KEY.bytes); |
cfb5b380 | 99 | else |
e2acdb6b | 100 | /* fall back to MAC address if no predictable name available */ |
933f9cae DM |
101 | id = siphash24(mac, mac_len, HASH_KEY.bytes); |
102 | ||
103 | id = htole64(id); | |
cfb5b380 TG |
104 | |
105 | /* fold into 32 bits */ | |
9ee18af3 | 106 | unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32)); |
cfb5b380 TG |
107 | |
108 | return 0; | |
109 | } |