]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-lease.c
sd-dhcp6-lease: convert assert_return() -> assert() in non-public functions
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <errno.h>
7
8 #include "alloc-util.h"
9 #include "dhcp6-lease-internal.h"
10 #include "dhcp6-protocol.h"
11 #include "strv.h"
12 #include "util.h"
13
14 int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
15 assert_return(lease, -EINVAL);
16 assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
17 assert_return(clock_supported(clock), -EOPNOTSUPP);
18 assert_return(ret, -EINVAL);
19
20 if (!triple_timestamp_is_set(&lease->timestamp))
21 return -ENODATA;
22
23 *ret = triple_timestamp_by_clock(&lease->timestamp, clock);
24 return 0;
25 }
26
27 int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
28 assert_return(lease, -EINVAL);
29 assert_return(ret, -EINVAL);
30
31 *ret = lease->server_address;
32 return 0;
33 }
34
35 int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
36 DHCP6Address *addr;
37 uint32_t valid = 0, t;
38
39 assert(ia);
40 assert(expire);
41
42 LIST_FOREACH(addresses, addr, ia->addresses) {
43 t = be32toh(addr->iaaddr.lifetime_valid);
44 if (valid < t)
45 valid = t;
46 }
47
48 t = be32toh(ia->ia_na.lifetime_t2);
49 if (t > valid)
50 return -EINVAL;
51
52 *expire = valid - t;
53
54 return 0;
55 }
56
57 DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
58 DHCP6Address *address;
59
60 if (!ia)
61 return NULL;
62
63 while (ia->addresses) {
64 address = ia->addresses;
65
66 LIST_REMOVE(addresses, ia->addresses, address);
67
68 free(address);
69 }
70
71 return NULL;
72 }
73
74 int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
75 uint8_t *clientid;
76
77 assert(lease);
78 assert(id);
79 assert(len > 0);
80
81 clientid = memdup(id, len);
82 if (!clientid)
83 return -ENOMEM;
84
85 free_and_replace(lease->clientid, clientid);
86 lease->clientid_len = len;
87
88 return 0;
89 }
90
91 int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
92 assert(lease);
93
94 if (!lease->clientid)
95 return -ENODATA;
96
97 if (ret_id)
98 *ret_id = lease->clientid;
99 if (ret_len)
100 *ret_len = lease->clientid_len;
101
102 return 0;
103 }
104
105 int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
106 uint8_t *serverid;
107
108 assert(lease);
109 assert(id);
110 assert(len > 0);
111
112 serverid = memdup(id, len);
113 if (!serverid)
114 return -ENOMEM;
115
116 free_and_replace(lease->serverid, serverid);
117 lease->serverid_len = len;
118
119 return 0;
120 }
121
122 int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
123 assert(lease);
124
125 if (!lease->serverid)
126 return -ENODATA;
127
128 if (ret_id)
129 *ret_id = lease->serverid;
130 if (ret_len)
131 *ret_len = lease->serverid_len;
132 return 0;
133 }
134
135 int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
136 assert(lease);
137
138 lease->preference = preference;
139 return 0;
140 }
141
142 int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *ret) {
143 assert(lease);
144 assert(ret);
145
146 *ret = lease->preference;
147 return 0;
148 }
149
150 int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
151 assert(lease);
152
153 lease->rapid_commit = true;
154 return 0;
155 }
156
157 int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *ret) {
158 assert(lease);
159 assert(ret);
160
161 *ret = lease->rapid_commit;
162 return 0;
163 }
164
165 int sd_dhcp6_lease_get_address(
166 sd_dhcp6_lease *lease,
167 struct in6_addr *ret_addr,
168 uint32_t *ret_lifetime_preferred,
169 uint32_t *ret_lifetime_valid) {
170
171 assert_return(lease, -EINVAL);
172
173 if (!lease->addr_iter)
174 return -ENOMSG;
175
176 if (ret_addr)
177 *ret_addr = lease->addr_iter->iaaddr.address;
178 if (ret_lifetime_preferred)
179 *ret_lifetime_preferred = be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
180 if (ret_lifetime_valid)
181 *ret_lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
182
183 lease->addr_iter = lease->addr_iter->addresses_next;
184 return 0;
185 }
186
187 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
188 if (lease)
189 lease->addr_iter = lease->ia_na.addresses;
190 }
191
192 int sd_dhcp6_lease_get_pd(
193 sd_dhcp6_lease *lease,
194 struct in6_addr *ret_prefix,
195 uint8_t *ret_prefix_len,
196 uint32_t *ret_lifetime_preferred,
197 uint32_t *ret_lifetime_valid) {
198
199 assert_return(lease, -EINVAL);
200
201 if (!lease->prefix_iter)
202 return -ENOMSG;
203
204 if (ret_prefix)
205 *ret_prefix = lease->prefix_iter->iapdprefix.address;
206 if (ret_prefix_len)
207 *ret_prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
208 if (ret_lifetime_preferred)
209 *ret_lifetime_preferred = be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
210 if (ret_lifetime_valid)
211 *ret_lifetime_valid = be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
212
213 lease->prefix_iter = lease->prefix_iter->addresses_next;
214 return 0;
215 }
216
217 void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
218 if (lease)
219 lease->prefix_iter = lease->ia_pd.addresses;
220 }
221
222 int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
223 assert(lease);
224 assert(optval || optlen == 0);
225
226 if (optlen == 0)
227 return 0;
228
229 return dhcp6_option_parse_addresses(optval, optlen, &lease->dns, &lease->dns_count);
230 }
231
232 int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
233 assert_return(lease, -EINVAL);
234
235 if (!lease->dns)
236 return -ENOENT;
237
238 if (ret)
239 *ret = lease->dns;
240
241 return lease->dns_count;
242 }
243
244 int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
245 _cleanup_strv_free_ char **domains = NULL;
246 int r;
247
248 assert(lease);
249 assert(optval || optlen == 0);
250
251 if (optlen == 0)
252 return 0;
253
254 r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
255 if (r < 0)
256 return r;
257
258 return strv_extend_strv(&lease->domains, domains, true);
259 }
260
261 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) {
262 assert_return(lease, -EINVAL);
263 assert_return(ret, -EINVAL);
264
265 if (!lease->domains)
266 return -ENOENT;
267
268 *ret = lease->domains;
269 return strv_length(lease->domains);
270 }
271
272 int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
273 int r;
274
275 assert(lease);
276 assert(optval || optlen == 0);
277
278 for (size_t offset = 0; offset < optlen;) {
279 const uint8_t *subval;
280 size_t sublen;
281 uint16_t subopt;
282
283 r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
284 if (r < 0)
285 return r;
286
287 switch(subopt) {
288 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
289 case DHCP6_NTP_SUBOPTION_MC_ADDR:
290 if (sublen != 16)
291 return 0;
292
293 r = dhcp6_option_parse_addresses(subval, sublen, &lease->ntp, &lease->ntp_count);
294 if (r < 0)
295 return r;
296
297 break;
298
299 case DHCP6_NTP_SUBOPTION_SRV_FQDN: {
300 _cleanup_free_ char *server = NULL;
301
302 r = dhcp6_option_parse_domainname(subval, sublen, &server);
303 if (r < 0)
304 return r;
305
306 if (strv_contains(lease->ntp_fqdn, server))
307 continue;
308
309 r = strv_consume(&lease->ntp_fqdn, TAKE_PTR(server));
310 if (r < 0)
311 return r;
312
313 break;
314 }}
315 }
316
317 return 0;
318 }
319
320 int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
321 assert(lease);
322 assert(optval || optlen == 0);
323
324 if (optlen == 0)
325 return 0;
326
327 /* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
328 return dhcp6_option_parse_addresses(optval, optlen, &lease->sntp, &lease->sntp_count);
329 }
330
331 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
332 assert_return(lease, -EINVAL);
333
334 if (lease->ntp) {
335 if (ret)
336 *ret = lease->ntp;
337 return lease->ntp_count;
338 }
339
340 if (lease->sntp && !lease->ntp_fqdn) {
341 /* Fallback to the deprecated SNTP option. */
342 if (ret)
343 *ret = lease->sntp;
344 return lease->sntp_count;
345 }
346
347 return -ENOENT;
348 }
349
350 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
351 assert_return(lease, -EINVAL);
352
353 if (!lease->ntp_fqdn)
354 return -ENOENT;
355
356 if (ret)
357 *ret = lease->ntp_fqdn;
358 return strv_length(lease->ntp_fqdn);
359 }
360
361 int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
362 char *fqdn;
363 int r;
364
365 assert(lease);
366 assert(optval || optlen == 0);
367
368 if (optlen == 0)
369 return 0;
370
371 if (optlen < 2)
372 return -ENODATA;
373
374 /* Ignore the flags field, it doesn't carry any useful
375 information for clients. */
376 r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
377 if (r < 0)
378 return r;
379
380 return free_and_replace(lease->fqdn, fqdn);
381 }
382
383 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
384 assert_return(lease, -EINVAL);
385 assert_return(ret, -EINVAL);
386
387 if (!lease->fqdn)
388 return -ENOENT;
389
390 *ret = lease->fqdn;
391 return 0;
392 }
393
394 static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
395 if (!lease)
396 return NULL;
397
398 free(lease->clientid);
399 free(lease->serverid);
400 dhcp6_lease_free_ia(&lease->ia_na);
401 dhcp6_lease_free_ia(&lease->ia_pd);
402 free(lease->dns);
403 free(lease->fqdn);
404 strv_free(lease->domains);
405 free(lease->ntp);
406 strv_free(lease->ntp_fqdn);
407 free(lease->sntp);
408
409 return mfree(lease);
410 }
411
412 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
413
414 int dhcp6_lease_new(sd_dhcp6_lease **ret) {
415 sd_dhcp6_lease *lease;
416
417 assert(ret);
418
419 lease = new0(sd_dhcp6_lease, 1);
420 if (!lease)
421 return -ENOMEM;
422
423 lease->n_ref = 1;
424
425 LIST_HEAD_INIT(lease->ia_na.addresses);
426
427 *ret = lease;
428 return 0;
429 }