1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
8 #include "alloc-util.h"
9 #include "dhcp6-lease-internal.h"
10 #include "dhcp6-protocol.h"
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
);
20 if (!triple_timestamp_is_set(&lease
->timestamp
))
23 *ret
= triple_timestamp_by_clock(&lease
->timestamp
, clock
);
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
);
31 *ret
= lease
->server_address
;
35 int dhcp6_lease_ia_rebind_expire(const DHCP6IA
*ia
, uint32_t *expire
) {
37 uint32_t valid
= 0, t
;
39 assert_return(ia
, -EINVAL
);
40 assert_return(expire
, -EINVAL
);
42 LIST_FOREACH(addresses
, addr
, ia
->addresses
) {
43 t
= be32toh(addr
->iaaddr
.lifetime_valid
);
48 t
= be32toh(ia
->ia_na
.lifetime_t2
);
57 DHCP6IA
*dhcp6_lease_free_ia(DHCP6IA
*ia
) {
58 DHCP6Address
*address
;
63 while (ia
->addresses
) {
64 address
= ia
->addresses
;
66 LIST_REMOVE(addresses
, ia
->addresses
, address
);
74 int dhcp6_lease_set_clientid(sd_dhcp6_lease
*lease
, const uint8_t *id
, size_t len
) {
77 assert_return(lease
, -EINVAL
);
78 assert_return(id
, -EINVAL
);
79 assert_return(len
> 0, -EINVAL
);
81 clientid
= memdup(id
, len
);
85 free_and_replace(lease
->clientid
, clientid
);
86 lease
->clientid_len
= len
;
91 int dhcp6_lease_get_clientid(sd_dhcp6_lease
*lease
, uint8_t **ret_id
, size_t *ret_len
) {
92 assert_return(lease
, -EINVAL
);
98 *ret_id
= lease
->clientid
;
100 *ret_len
= lease
->clientid_len
;
105 int dhcp6_lease_set_serverid(sd_dhcp6_lease
*lease
, const uint8_t *id
, size_t len
) {
108 assert_return(lease
, -EINVAL
);
109 assert_return(id
, -EINVAL
);
110 assert_return(len
> 0, -EINVAL
);
112 serverid
= memdup(id
, len
);
116 free_and_replace(lease
->serverid
, serverid
);
117 lease
->serverid_len
= len
;
122 int dhcp6_lease_get_serverid(sd_dhcp6_lease
*lease
, uint8_t **ret_id
, size_t *ret_len
) {
123 assert_return(lease
, -EINVAL
);
125 if (!lease
->serverid
)
129 *ret_id
= lease
->serverid
;
131 *ret_len
= lease
->serverid_len
;
136 int dhcp6_lease_set_preference(sd_dhcp6_lease
*lease
, uint8_t preference
) {
137 assert_return(lease
, -EINVAL
);
139 lease
->preference
= preference
;
144 int dhcp6_lease_get_preference(sd_dhcp6_lease
*lease
, uint8_t *preference
) {
145 assert_return(preference
, -EINVAL
);
150 *preference
= lease
->preference
;
155 int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease
*lease
) {
156 assert_return(lease
, -EINVAL
);
158 lease
->rapid_commit
= true;
163 int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease
*lease
, bool *rapid_commit
) {
164 assert_return(lease
, -EINVAL
);
165 assert_return(rapid_commit
, -EINVAL
);
167 *rapid_commit
= lease
->rapid_commit
;
172 int sd_dhcp6_lease_get_address(sd_dhcp6_lease
*lease
, struct in6_addr
*addr
,
173 uint32_t *lifetime_preferred
,
174 uint32_t *lifetime_valid
) {
175 assert_return(lease
, -EINVAL
);
176 assert_return(addr
, -EINVAL
);
177 assert_return(lifetime_preferred
, -EINVAL
);
178 assert_return(lifetime_valid
, -EINVAL
);
180 if (!lease
->addr_iter
)
183 memcpy(addr
, &lease
->addr_iter
->iaaddr
.address
,
184 sizeof(struct in6_addr
));
185 *lifetime_preferred
=
186 be32toh(lease
->addr_iter
->iaaddr
.lifetime_preferred
);
187 *lifetime_valid
= be32toh(lease
->addr_iter
->iaaddr
.lifetime_valid
);
189 lease
->addr_iter
= lease
->addr_iter
->addresses_next
;
194 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease
*lease
) {
196 lease
->addr_iter
= lease
->ia
.addresses
;
199 int sd_dhcp6_lease_get_pd(sd_dhcp6_lease
*lease
, struct in6_addr
*prefix
,
201 uint32_t *lifetime_preferred
,
202 uint32_t *lifetime_valid
) {
203 assert_return(lease
, -EINVAL
);
204 assert_return(prefix
, -EINVAL
);
205 assert_return(prefix_len
, -EINVAL
);
206 assert_return(lifetime_preferred
, -EINVAL
);
207 assert_return(lifetime_valid
, -EINVAL
);
209 if (!lease
->prefix_iter
)
212 memcpy(prefix
, &lease
->prefix_iter
->iapdprefix
.address
,
213 sizeof(struct in6_addr
));
214 *prefix_len
= lease
->prefix_iter
->iapdprefix
.prefixlen
;
215 *lifetime_preferred
=
216 be32toh(lease
->prefix_iter
->iapdprefix
.lifetime_preferred
);
218 be32toh(lease
->prefix_iter
->iapdprefix
.lifetime_valid
);
220 lease
->prefix_iter
= lease
->prefix_iter
->addresses_next
;
225 void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease
*lease
) {
227 lease
->prefix_iter
= lease
->pd
.addresses
;
230 int dhcp6_lease_add_dns(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
231 assert_return(lease
, -EINVAL
);
232 assert_return(optval
, -EINVAL
);
237 return dhcp6_option_parse_addresses(optval
, optlen
, &lease
->dns
, &lease
->dns_count
);
240 int sd_dhcp6_lease_get_dns(sd_dhcp6_lease
*lease
, const struct in6_addr
**ret
) {
241 assert_return(lease
, -EINVAL
);
242 assert_return(ret
, -EINVAL
);
248 return lease
->dns_count
;
251 int dhcp6_lease_add_domains(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
252 _cleanup_strv_free_
char **domains
= NULL
;
255 assert_return(lease
, -EINVAL
);
256 assert_return(optval
, -EINVAL
);
261 r
= dhcp6_option_parse_domainname_list(optval
, optlen
, &domains
);
265 return strv_extend_strv(&lease
->domains
, domains
, true);
268 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease
*lease
, char ***ret
) {
269 assert_return(lease
, -EINVAL
);
270 assert_return(ret
, -EINVAL
);
275 *ret
= lease
->domains
;
276 return strv_length(lease
->domains
);
279 int dhcp6_lease_add_ntp(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
282 assert_return(lease
, -EINVAL
);
283 assert_return(optval
, -EINVAL
);
285 for (size_t offset
= 0; offset
< optlen
;) {
286 const uint8_t *subval
;
290 r
= dhcp6_option_parse(optval
, optlen
, &offset
, &subopt
, &sublen
, &subval
);
295 case DHCP6_NTP_SUBOPTION_SRV_ADDR
:
296 case DHCP6_NTP_SUBOPTION_MC_ADDR
:
300 r
= dhcp6_option_parse_addresses(subval
, sublen
, &lease
->ntp
, &lease
->ntp_count
);
306 case DHCP6_NTP_SUBOPTION_SRV_FQDN
: {
307 _cleanup_free_
char *server
= NULL
;
309 r
= dhcp6_option_parse_domainname(subval
, sublen
, &server
);
313 if (strv_contains(lease
->ntp_fqdn
, server
))
316 r
= strv_consume(&lease
->ntp_fqdn
, TAKE_PTR(server
));
327 int dhcp6_lease_add_sntp(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
328 assert_return(lease
, -EINVAL
);
329 assert_return(optval
, -EINVAL
);
334 /* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
335 return dhcp6_option_parse_addresses(optval
, optlen
, &lease
->sntp
, &lease
->sntp_count
);
338 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease
*lease
, const struct in6_addr
**ret
) {
339 assert_return(lease
, -EINVAL
);
340 assert_return(ret
, -EINVAL
);
344 return lease
->ntp_count
;
347 if (lease
->sntp
&& !lease
->ntp_fqdn
) {
348 /* Fallback to the deprecated SNTP option. */
350 return lease
->sntp_count
;
356 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease
*lease
, char ***ret
) {
357 assert_return(lease
, -EINVAL
);
358 assert_return(ret
, -EINVAL
);
360 if (!lease
->ntp_fqdn
)
363 *ret
= lease
->ntp_fqdn
;
364 return strv_length(lease
->ntp_fqdn
);
367 int dhcp6_lease_set_fqdn(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
371 assert_return(lease
, -EINVAL
);
372 assert_return(optval
, -EINVAL
);
377 /* Ignore the flags field, it doesn't carry any useful
378 information for clients. */
379 r
= dhcp6_option_parse_domainname(optval
+ 1, optlen
- 1, &fqdn
);
383 return free_and_replace(lease
->fqdn
, fqdn
);
386 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease
*lease
, const char **ret
) {
387 assert_return(lease
, -EINVAL
);
388 assert_return(ret
, -EINVAL
);
397 static sd_dhcp6_lease
*dhcp6_lease_free(sd_dhcp6_lease
*lease
) {
401 free(lease
->clientid
);
402 free(lease
->serverid
);
403 dhcp6_lease_free_ia(&lease
->ia
);
404 dhcp6_lease_free_ia(&lease
->pd
);
407 strv_free(lease
->domains
);
409 strv_free(lease
->ntp_fqdn
);
415 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease
, sd_dhcp6_lease
, dhcp6_lease_free
);
417 int dhcp6_lease_new(sd_dhcp6_lease
**ret
) {
418 sd_dhcp6_lease
*lease
;
420 lease
= new0(sd_dhcp6_lease
, 1);
426 LIST_HEAD_INIT(lease
->ia
.addresses
);