]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp6-lease.c
macro: introduce DEFINE_TRIVIAL_REF_UNREF_FUNC() macro and friends
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3fb2c570 2/***
810adae9 3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
3fb2c570
PF
4***/
5
6#include <errno.h>
7
b5efdb8a 8#include "alloc-util.h"
3fb2c570 9#include "dhcp6-lease-internal.h"
6599680e 10#include "dhcp6-protocol.h"
b5efdb8a
LP
11#include "strv.h"
12#include "util.h"
3fb2c570
PF
13
14int dhcp6_lease_clear_timers(DHCP6IA *ia) {
15 assert_return(ia, -EINVAL);
16
17 ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
18 ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
19
20 return 0;
21}
22
709d6710
PF
23int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
24 DHCP6Address *addr;
25 uint32_t valid = 0, t;
26
27 assert_return(ia, -EINVAL);
28 assert_return(expire, -EINVAL);
29
30 LIST_FOREACH(addresses, addr, ia->addresses) {
ee3a5027 31 t = be32toh(addr->iaaddr.lifetime_valid);
709d6710
PF
32 if (valid < t)
33 valid = t;
34 }
35
e0026dcb 36 t = be32toh(ia->ia_na.lifetime_t2);
709d6710
PF
37 if (t > valid)
38 return -EINVAL;
39
40 *expire = valid - t;
41
42 return 0;
43}
44
3fb2c570
PF
45DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
46 DHCP6Address *address;
47
48 if (!ia)
49 return NULL;
50
51 dhcp6_lease_clear_timers(ia);
52
53 while (ia->addresses) {
54 address = ia->addresses;
55
56 LIST_REMOVE(addresses, ia->addresses, address);
57
58 free(address);
59 }
60
61 return NULL;
62}
63
64int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
65 size_t len) {
66 assert_return(lease, -EINVAL);
67 assert_return(id, -EINVAL);
68
69 free(lease->serverid);
70
71 lease->serverid = memdup(id, len);
72 if (!lease->serverid)
73 return -EINVAL;
74
75 lease->serverid_len = len;
76
77 return 0;
78}
79
80int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
81 assert_return(lease, -EINVAL);
3fb2c570 82
99f1d3fc
ZJS
83 if (!lease->serverid)
84 return -ENOMSG;
85
86 if (id)
87 *id = lease->serverid;
88 if (len)
89 *len = lease->serverid_len;
3fb2c570
PF
90
91 return 0;
92}
93
94int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
95 assert_return(lease, -EINVAL);
96
97 lease->preference = preference;
98
99 return 0;
100}
101
102int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
3fb2c570
PF
103 assert_return(preference, -EINVAL);
104
fab15fec
PF
105 if (!lease)
106 return -EINVAL;
107
3fb2c570
PF
108 *preference = lease->preference;
109
110 return 0;
111}
112
ed6ee219
PF
113int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
114 assert_return(lease, -EINVAL);
115
116 lease->rapid_commit = true;
117
118 return 0;
119}
120
121int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
122 assert_return(lease, -EINVAL);
123 assert_return(rapid_commit, -EINVAL);
124
125 *rapid_commit = lease->rapid_commit;
126
127 return 0;
128}
129
3fb2c570
PF
130int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
131 assert_return(lease, -EINVAL);
132 assert_return(iaid, -EINVAL);
133
e0026dcb 134 *iaid = lease->ia.ia_na.id;
3fb2c570
PF
135
136 return 0;
137}
138
e7504d95
PF
139int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
140 uint32_t *lifetime_preferred,
141 uint32_t *lifetime_valid) {
ea3b3a75
PF
142 assert_return(lease, -EINVAL);
143 assert_return(addr, -EINVAL);
144 assert_return(lifetime_preferred, -EINVAL);
145 assert_return(lifetime_valid, -EINVAL);
146
147 if (!lease->addr_iter)
148 return -ENOMSG;
149
ee3a5027
PF
150 memcpy(addr, &lease->addr_iter->iaaddr.address,
151 sizeof(struct in6_addr));
152 *lifetime_preferred =
153 be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
154 *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
ea3b3a75
PF
155
156 lease->addr_iter = lease->addr_iter->addresses_next;
157
158 return 0;
159}
160
e7504d95
PF
161void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
162 if (lease)
163 lease->addr_iter = lease->ia.addresses;
ea3b3a75
PF
164}
165
652bf042
PF
166int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
167 uint8_t *prefix_len,
168 uint32_t *lifetime_preferred,
169 uint32_t *lifetime_valid) {
170 assert_return(lease, -EINVAL);
171 assert_return(prefix, -EINVAL);
172 assert_return(prefix_len, -EINVAL);
173 assert_return(lifetime_preferred, -EINVAL);
174 assert_return(lifetime_valid, -EINVAL);
175
176 if (!lease->prefix_iter)
177 return -ENOMSG;
178
179 memcpy(prefix, &lease->prefix_iter->iapdprefix.address,
180 sizeof(struct in6_addr));
181 *prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
182 *lifetime_preferred =
183 be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
184 *lifetime_valid =
185 be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
186
187 lease->prefix_iter = lease->prefix_iter->addresses_next;
188
189 return 0;
190}
191
192void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
193 if (lease)
194 lease->prefix_iter = lease->pd.addresses;
195}
196
7bd8e95d
PF
197int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
198 int r;
199
200 assert_return(lease, -EINVAL);
201 assert_return(optval, -EINVAL);
202
203 if (!optlen)
204 return 0;
205
206 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns,
207 lease->dns_count,
208 &lease->dns_allocated);
209 if (r < 0) {
210 log_dhcp6_client(client, "Invalid DNS server option: %s",
211 strerror(-r));
212
213 return r;
214 }
215
216 lease->dns_count = r;
217
218 return 0;
219}
220
221int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) {
222 assert_return(lease, -EINVAL);
223 assert_return(addrs, -EINVAL);
224
225 if (lease->dns_count) {
226 *addrs = lease->dns;
227 return lease->dns_count;
228 }
229
230 return -ENOENT;
231}
232
5da1b97f
PF
233int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
234 size_t optlen) {
235 int r;
236 char **domains;
237
238 assert_return(lease, -EINVAL);
239 assert_return(optval, -EINVAL);
240
241 if (!optlen)
242 return 0;
243
244 r = dhcp6_option_parse_domainname(optval, optlen, &domains);
245 if (r < 0)
246 return 0;
247
130d3d22 248 strv_free_and_replace(lease->domains, domains);
5da1b97f
PF
249 lease->domains_count = r;
250
251 return r;
252}
253
254int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
255 assert_return(lease, -EINVAL);
256 assert_return(domains, -EINVAL);
257
258 if (lease->domains_count) {
259 *domains = lease->domains;
260 return lease->domains_count;
261 }
262
263 return -ENOENT;
264}
265
52efd56a 266int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
6599680e
PF
267 int r;
268 uint16_t subopt;
269 size_t sublen;
270 uint8_t *subval;
271
272 assert_return(lease, -EINVAL);
273 assert_return(optval, -EINVAL);
274
63a54aa1 275 lease->ntp = mfree(lease->ntp);
41e4615d
PF
276 lease->ntp_count = 0;
277 lease->ntp_allocated = 0;
278
6599680e
PF
279 while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
280 &subval)) >= 0) {
281 int s;
282 char **servers;
283
284 switch(subopt) {
285 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
286 case DHCP6_NTP_SUBOPTION_MC_ADDR:
287 if (sublen != 16)
288 return 0;
289
290 s = dhcp6_option_parse_ip6addrs(subval, sublen,
291 &lease->ntp,
292 lease->ntp_count,
293 &lease->ntp_allocated);
294 if (s < 0)
295 return s;
296
297 lease->ntp_count = s;
298
299 break;
300
301 case DHCP6_NTP_SUBOPTION_SRV_FQDN:
302 r = dhcp6_option_parse_domainname(subval, sublen,
303 &servers);
304 if (r < 0)
305 return 0;
306
130d3d22 307 strv_free_and_replace(lease->ntp_fqdn, servers);
6599680e
PF
308 lease->ntp_fqdn_count = r;
309
310 break;
311 }
312 }
313
314 if (r != -ENOMSG)
315 return r;
316
317 return 0;
318}
319
41e4615d
PF
320int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
321 int r;
322
323 assert_return(lease, -EINVAL);
324 assert_return(optval, -EINVAL);
325
326 if (!optlen)
327 return 0;
328
329 if (lease->ntp || lease->ntp_fqdn) {
330 log_dhcp6_client(client, "NTP information already provided");
331
332 return 0;
333 }
334
335 log_dhcp6_client(client, "Using deprecated SNTP information");
336
337 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
338 lease->ntp_count,
339 &lease->ntp_allocated);
340 if (r < 0) {
341 log_dhcp6_client(client, "Invalid SNTP server option: %s",
342 strerror(-r));
343
344 return r;
345 }
346
347 lease->ntp_count = r;
348
349 return 0;
350}
351
6599680e
PF
352int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
353 struct in6_addr **addrs) {
354 assert_return(lease, -EINVAL);
355 assert_return(addrs, -EINVAL);
356
357 if (lease->ntp_count) {
358 *addrs = lease->ntp;
359 return lease->ntp_count;
360 }
361
362 return -ENOENT;
363}
364
365int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
366 assert_return(lease, -EINVAL);
367 assert_return(ntp_fqdn, -EINVAL);
368
369 if (lease->ntp_fqdn_count) {
370 *ntp_fqdn = lease->ntp_fqdn;
371 return lease->ntp_fqdn_count;
372 }
373
374 return -ENOENT;
375}
376
3fb2c570 377sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
3733eec3
LP
378
379 if (!lease)
380 return NULL;
381
382 assert(lease->n_ref >= 1);
383 lease->n_ref++;
3fb2c570
PF
384
385 return lease;
386}
387
388sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
3fb2c570 389
3733eec3
LP
390 if (!lease)
391 return NULL;
5da1b97f 392
3733eec3
LP
393 assert(lease->n_ref >= 1);
394 lease->n_ref--;
5da1b97f 395
3733eec3
LP
396 if (lease->n_ref > 0)
397 return NULL;
6599680e 398
3733eec3
LP
399 free(lease->serverid);
400 dhcp6_lease_free_ia(&lease->ia);
dce6563f 401 dhcp6_lease_free_ia(&lease->pd);
3733eec3
LP
402
403 free(lease->dns);
404
405 lease->domains = strv_free(lease->domains);
406
407 free(lease->ntp);
408
409 lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
6b430fdb 410 return mfree(lease);
3fb2c570
PF
411}
412
413int dhcp6_lease_new(sd_dhcp6_lease **ret) {
414 sd_dhcp6_lease *lease;
415
416 lease = new0(sd_dhcp6_lease, 1);
417 if (!lease)
418 return -ENOMEM;
419
3733eec3 420 lease->n_ref = 1;
3fb2c570
PF
421
422 LIST_HEAD_INIT(lease->ia.addresses);
423
424 *ret = lease;
425 return 0;
426}