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