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
);
249 return lease
->dns_count
;
252 int dhcp6_lease_add_domains(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
253 _cleanup_strv_free_
char **domains
= NULL
;
256 assert_return(lease
, -EINVAL
);
257 assert_return(optval
, -EINVAL
);
262 r
= dhcp6_option_parse_domainname_list(optval
, optlen
, &domains
);
266 return strv_extend_strv(&lease
->domains
, domains
, true);
269 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease
*lease
, char ***ret
) {
270 assert_return(lease
, -EINVAL
);
271 assert_return(ret
, -EINVAL
);
276 *ret
= lease
->domains
;
277 return strv_length(lease
->domains
);
280 int dhcp6_lease_add_ntp(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
283 assert_return(lease
, -EINVAL
);
284 assert_return(optval
, -EINVAL
);
286 for (size_t offset
= 0; offset
< optlen
;) {
287 const uint8_t *subval
;
291 r
= dhcp6_option_parse(optval
, optlen
, &offset
, &subopt
, &sublen
, &subval
);
296 case DHCP6_NTP_SUBOPTION_SRV_ADDR
:
297 case DHCP6_NTP_SUBOPTION_MC_ADDR
:
301 r
= dhcp6_option_parse_addresses(subval
, sublen
, &lease
->ntp
, &lease
->ntp_count
);
307 case DHCP6_NTP_SUBOPTION_SRV_FQDN
: {
308 _cleanup_free_
char *server
= NULL
;
310 r
= dhcp6_option_parse_domainname(subval
, sublen
, &server
);
314 if (strv_contains(lease
->ntp_fqdn
, server
))
317 r
= strv_consume(&lease
->ntp_fqdn
, TAKE_PTR(server
));
328 int dhcp6_lease_add_sntp(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
329 assert_return(lease
, -EINVAL
);
330 assert_return(optval
, -EINVAL
);
335 /* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
336 return dhcp6_option_parse_addresses(optval
, optlen
, &lease
->sntp
, &lease
->sntp_count
);
339 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease
*lease
, const struct in6_addr
**ret
) {
340 assert_return(lease
, -EINVAL
);
345 return lease
->ntp_count
;
348 if (lease
->sntp
&& !lease
->ntp_fqdn
) {
349 /* Fallback to the deprecated SNTP option. */
352 return lease
->sntp_count
;
358 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease
*lease
, char ***ret
) {
359 assert_return(lease
, -EINVAL
);
361 if (!lease
->ntp_fqdn
)
365 *ret
= lease
->ntp_fqdn
;
366 return strv_length(lease
->ntp_fqdn
);
369 int dhcp6_lease_set_fqdn(sd_dhcp6_lease
*lease
, const uint8_t *optval
, size_t optlen
) {
373 assert_return(lease
, -EINVAL
);
374 assert_return(optval
, -EINVAL
);
379 /* Ignore the flags field, it doesn't carry any useful
380 information for clients. */
381 r
= dhcp6_option_parse_domainname(optval
+ 1, optlen
- 1, &fqdn
);
385 return free_and_replace(lease
->fqdn
, fqdn
);
388 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease
*lease
, const char **ret
) {
389 assert_return(lease
, -EINVAL
);
390 assert_return(ret
, -EINVAL
);
399 static sd_dhcp6_lease
*dhcp6_lease_free(sd_dhcp6_lease
*lease
) {
403 free(lease
->clientid
);
404 free(lease
->serverid
);
405 dhcp6_lease_free_ia(&lease
->ia
);
406 dhcp6_lease_free_ia(&lease
->pd
);
409 strv_free(lease
->domains
);
411 strv_free(lease
->ntp_fqdn
);
417 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease
, sd_dhcp6_lease
, dhcp6_lease_free
);
419 int dhcp6_lease_new(sd_dhcp6_lease
**ret
) {
420 sd_dhcp6_lease
*lease
;
422 lease
= new0(sd_dhcp6_lease
, 1);
428 LIST_HEAD_INIT(lease
->ia
.addresses
);