chiark / gitweb /
34aa36c6e6629c9331d6230ae8fccb57804194b6
[elogind.git] / src / libsystemd-network / sd-dhcp-lease.c
1 /***
2   This file is part of systemd.
3
4   Copyright (C) 2013 Intel Corporation. All rights reserved.
5   Copyright (C) 2014 Tom Gundersen
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 <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <net/ethernet.h>
26 #include <arpa/inet.h>
27 #include <sys/param.h>
28
29 #include "util.h"
30 #include "list.h"
31 #include "mkdir.h"
32 #include "fileio.h"
33 #include "unaligned.h"
34 #include "in-addr-util.h"
35
36 #include "dhcp-protocol.h"
37 #include "dhcp-internal.h"
38 #include "dhcp-lease-internal.h"
39 #include "sd-dhcp-lease.h"
40 #include "sd-dhcp-client.h"
41 #include "network-internal.h"
42
43 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
44         assert_return(lease, -EINVAL);
45         assert_return(addr, -EINVAL);
46
47         addr->s_addr = lease->address;
48
49         return 0;
50 }
51
52 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
53         assert_return(lease, -EINVAL);
54         assert_return(lifetime, -EINVAL);
55
56         *lifetime = lease->lifetime;
57
58         return 0;
59 }
60
61 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
62         assert_return(lease, -EINVAL);
63         assert_return(mtu, -EINVAL);
64
65         if (lease->mtu)
66                 *mtu = lease->mtu;
67         else
68                 return -ENOENT;
69
70         return 0;
71 }
72
73 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
74         assert_return(lease, -EINVAL);
75         assert_return(addr, -EINVAL);
76
77         if (lease->dns_size) {
78                 *addr = lease->dns;
79                 return lease->dns_size;
80         } else
81                 return -ENOENT;
82
83         return 0;
84 }
85
86 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
87         assert_return(lease, -EINVAL);
88         assert_return(addr, -EINVAL);
89
90         if (lease->ntp_size) {
91                 *addr = lease->ntp;
92                 return lease->ntp_size;
93         } else
94                 return -ENOENT;
95
96         return 0;
97 }
98
99 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
100         assert_return(lease, -EINVAL);
101         assert_return(domainname, -EINVAL);
102
103         if (lease->domainname)
104                 *domainname = lease->domainname;
105         else
106                 return -ENOENT;
107
108         return 0;
109 }
110
111 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
112         assert_return(lease, -EINVAL);
113         assert_return(hostname, -EINVAL);
114
115         if (lease->hostname)
116                 *hostname = lease->hostname;
117         else
118                 return -ENOENT;
119
120         return 0;
121 }
122
123 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
124         assert_return(lease, -EINVAL);
125         assert_return(root_path, -EINVAL);
126
127         if (lease->root_path)
128                 *root_path = lease->root_path;
129         else
130                 return -ENOENT;
131
132         return 0;
133 }
134
135 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
136         assert_return(lease, -EINVAL);
137         assert_return(addr, -EINVAL);
138
139         if (lease->router != INADDR_ANY)
140                 addr->s_addr = lease->router;
141         else
142                 return -ENOENT;
143
144         return 0;
145 }
146
147 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
148         assert_return(lease, -EINVAL);
149         assert_return(addr, -EINVAL);
150
151         addr->s_addr = lease->subnet_mask;
152
153         return 0;
154 }
155
156 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
157         assert_return(lease, -EINVAL);
158         assert_return(addr, -EINVAL);
159
160         addr->s_addr = lease->server_address;
161
162         return 0;
163 }
164
165 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
166         assert_return(lease, -EINVAL);
167         assert_return(addr, -EINVAL);
168
169         addr->s_addr = lease->next_server;
170
171         return 0;
172 }
173
174 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
175
176         assert_return(lease, -EINVAL);
177         assert_return(routes, -EINVAL);
178
179         if (lease->static_route_size) {
180                 *routes = lease->static_route;
181                 return lease->static_route_size;
182         } else
183                 return -ENOENT;
184
185         return 0;
186 }
187
188 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
189         if (lease)
190                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
191
192         return lease;
193 }
194
195 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
196         if (lease && REFCNT_DEC(lease->n_ref) == 0) {
197                 free(lease->hostname);
198                 free(lease->domainname);
199                 free(lease->dns);
200                 free(lease->ntp);
201                 free(lease->static_route);
202                 free(lease->client_id);
203                 free(lease);
204         }
205
206         return NULL;
207 }
208
209 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
210         assert(option);
211         assert(ret);
212
213         if (len == 4) {
214                 *ret = unaligned_read_be32((be32_t*) option);
215
216                 if (*ret < min)
217                         *ret = min;
218         }
219 }
220
221 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
222         lease_parse_u32(option, len, (uint32_t *)ret, 0);
223 }
224
225 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
226         assert(option);
227         assert(ret);
228
229         if (len == 2) {
230                 *ret = unaligned_read_be16((be16_t*) option);
231
232                 if (*ret < min)
233                         *ret = min;
234         }
235 }
236
237 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
238         assert(option);
239         assert(ret);
240
241         if (len == 4)
242                 memcpy(ret, option, 4);
243 }
244
245 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
246         assert(option);
247         assert(ret);
248
249         if (len == 1)
250                 *ret = !!(*option);
251 }
252
253 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
254         assert(option);
255         assert(ret);
256
257         if (len == 1) {
258                 *ret = *option;
259
260                 if (*ret < min)
261                         *ret = min;
262         }
263 }
264
265 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
266         assert(option);
267         assert(ret);
268
269         if (len >= 1) {
270                 char *string;
271
272                 string = strndup((const char *)option, len);
273                 if (!string)
274                         return -errno;
275
276                 free(*ret);
277                 *ret = string;
278         }
279
280         return 0;
281 }
282
283 static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
284         assert(option);
285         assert(ret);
286         assert(ret_size);
287
288         if (len && !(len % (4 * mult))) {
289                 size_t size;
290                 struct in_addr *addresses;
291
292                 size = len / 4;
293
294                 addresses = newdup(struct in_addr, option, size);
295                 if (!addresses)
296                         return -ENOMEM;
297
298                 free(*ret);
299                 *ret = addresses;
300                 *ret_size = size;
301         }
302
303         return 0;
304 }
305
306 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
307         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
308 }
309
310 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
311         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
312 }
313
314 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
315         size_t *routes_size, size_t *routes_allocated) {
316
317         struct in_addr addr;
318
319         assert(option);
320         assert(routes);
321         assert(routes_size);
322         assert(routes_allocated);
323
324         if (!len)
325                 return 0;
326
327         if (len % 8 != 0)
328                 return -EINVAL;
329
330         if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
331                 return -ENOMEM;
332
333         while (len >= 8) {
334                 struct sd_dhcp_route *route = *routes + *routes_size;
335                 int r;
336
337                 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
338                 if (r < 0) {
339                         log_error("Failed to determine destination prefix length from class based IP, ignoring");
340                         continue;
341                 }
342
343                 lease_parse_be32(option, 4, &addr.s_addr);
344                 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
345                 option += 4;
346
347                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
348                 option += 4;
349
350                 len -= 8;
351                 (*routes_size)++;
352         }
353
354         return 0;
355 }
356
357 /* parses RFC3442 Classless Static Route Option */
358 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
359         size_t *routes_size, size_t *routes_allocated) {
360
361         assert(option);
362         assert(routes);
363         assert(routes_size);
364         assert(routes_allocated);
365
366         /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)*  */
367
368         while (len > 0) {
369                 uint8_t dst_octets;
370                 struct sd_dhcp_route *route;
371
372                 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
373                     return -ENOMEM;
374
375                 route = *routes + *routes_size;
376
377                 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
378                 route->dst_prefixlen = *option;
379                 option++;
380                 len--;
381
382                 /* can't have more than 4 octets in IPv4 */
383                 if (dst_octets > 4 || len < dst_octets)
384                         return -EINVAL;
385
386                 route->dst_addr.s_addr = 0;
387                 memcpy(&route->dst_addr.s_addr, option, dst_octets);
388                 option += dst_octets;
389                 len -= dst_octets;
390
391                 if (len < 4)
392                         return -EINVAL;
393
394                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
395                 option += 4;
396                 len -= 4;
397
398                 (*routes_size)++;
399         }
400
401         return 0;
402 }
403
404 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
405                               void *user_data) {
406         sd_dhcp_lease *lease = user_data;
407         int r;
408
409         assert(lease);
410
411         switch(code) {
412
413         case DHCP_OPTION_TIME_OFFSET:
414                 lease_parse_s32(option, len, &lease->time_offset);
415
416                 break;
417
418         case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
419                 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
420
421                 break;
422
423         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
424                 lease_parse_u32(option, len, &lease->lifetime, 1);
425
426                 break;
427
428         case DHCP_OPTION_SERVER_IDENTIFIER:
429                 lease_parse_be32(option, len, &lease->server_address);
430
431                 break;
432
433         case DHCP_OPTION_SUBNET_MASK:
434                 lease_parse_be32(option, len, &lease->subnet_mask);
435
436                 break;
437
438         case DHCP_OPTION_BROADCAST:
439                 lease_parse_be32(option, len, &lease->broadcast);
440
441                 break;
442
443         case DHCP_OPTION_ROUTER:
444                 lease_parse_be32(option, len, &lease->router);
445
446                 break;
447
448         case DHCP_OPTION_DOMAIN_NAME_SERVER:
449                 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
450                 if (r < 0)
451                         return r;
452
453                 break;
454
455         case DHCP_OPTION_NTP_SERVER:
456                 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
457                 if (r < 0)
458                         return r;
459
460                 break;
461
462         case DHCP_OPTION_POLICY_FILTER:
463                 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
464                 if (r < 0)
465                         return r;
466
467                 break;
468
469         case DHCP_OPTION_STATIC_ROUTE:
470                 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
471                         &lease->static_route_allocated);
472                 if (r < 0)
473                         return r;
474
475                 break;
476
477         case DHCP_OPTION_INTERFACE_MTU:
478                 lease_parse_u16(option, len, &lease->mtu, 68);
479
480                 break;
481
482         case DHCP_OPTION_INTERFACE_MDR:
483                 lease_parse_u16(option, len, &lease->mdr, 576);
484
485                 break;
486
487         case DHCP_OPTION_INTERFACE_TTL:
488                 lease_parse_u8(option, len, &lease->ttl, 1);
489
490                 break;
491
492         case DHCP_OPTION_BOOT_FILE_SIZE:
493                 lease_parse_u16(option, len, &lease->boot_file_size, 0);
494
495                 break;
496
497         case DHCP_OPTION_DOMAIN_NAME:
498         {
499                 _cleanup_free_ char *domainname = NULL;
500                 char *e;
501
502                 r = lease_parse_string(option, len, &domainname);
503                 if (r < 0)
504                         return r;
505
506                 /* Chop off trailing dot of domain name that some DHCP
507                  * servers send us back. Internally we want to store
508                  * host names without trailing dots and
509                  * host_name_is_valid() doesn't accept them. */
510                 e = endswith(domainname, ".");
511                 if (e)
512                         *e = 0;
513
514                 if (!hostname_is_valid(domainname) || is_localhost(domainname))
515                         break;
516
517                 free(lease->domainname);
518                 lease->domainname = domainname;
519                 domainname = NULL;
520
521                 break;
522         }
523         case DHCP_OPTION_HOST_NAME:
524         {
525                 _cleanup_free_ char *hostname = NULL;
526                 char *e;
527
528                 r = lease_parse_string(option, len, &hostname);
529                 if (r < 0)
530                         return r;
531
532                 e = endswith(hostname, ".");
533                 if (e)
534                         *e = 0;
535
536                 if (!hostname_is_valid(hostname) || is_localhost(hostname))
537                         break;
538
539                 free(lease->hostname);
540                 lease->hostname = hostname;
541                 hostname = NULL;
542
543                 break;
544         }
545         case DHCP_OPTION_ROOT_PATH:
546                 r = lease_parse_string(option, len, &lease->root_path);
547                 if (r < 0)
548                         return r;
549
550                 break;
551
552         case DHCP_OPTION_RENEWAL_T1_TIME:
553                 lease_parse_u32(option, len, &lease->t1, 1);
554
555                 break;
556
557         case DHCP_OPTION_REBINDING_T2_TIME:
558                 lease_parse_u32(option, len, &lease->t2, 1);
559
560                 break;
561
562         case DHCP_OPTION_ENABLE_IP_FORWARDING:
563                 lease_parse_bool(option, len, &lease->ip_forward);
564
565                 break;
566
567         case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
568                 lease_parse_bool(option, len, &lease->ip_forward_non_local);
569
570                 break;
571
572         case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
573                 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
574                         &lease->static_route_allocated);
575                 if (r < 0)
576                         return r;
577
578                 break;
579         }
580
581         return 0;
582 }
583
584 int dhcp_lease_new(sd_dhcp_lease **ret) {
585         sd_dhcp_lease *lease;
586
587         lease = new0(sd_dhcp_lease, 1);
588         if (!lease)
589                 return -ENOMEM;
590
591         lease->router = INADDR_ANY;
592         lease->n_ref = REFCNT_INIT;
593
594         *ret = lease;
595         return 0;
596 }
597
598 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
599         _cleanup_free_ char *temp_path = NULL;
600         _cleanup_fclose_ FILE *f = NULL;
601         struct in_addr address;
602         const struct in_addr *addresses;
603         const uint8_t *client_id;
604         size_t client_id_len;
605         const char *string;
606         uint16_t mtu;
607         struct sd_dhcp_route *routes;
608         int r;
609
610         assert(lease);
611         assert(lease_file);
612
613         r = fopen_temporary(lease_file, &f, &temp_path);
614         if (r < 0)
615                 goto finish;
616
617         fchmod(fileno(f), 0644);
618
619         r = sd_dhcp_lease_get_address(lease, &address);
620         if (r < 0)
621                 goto finish;
622
623         fprintf(f,
624                 "# This is private data. Do not parse.\n"
625                 "ADDRESS=%s\n", inet_ntoa(address));
626
627         r = sd_dhcp_lease_get_netmask(lease, &address);
628         if (r < 0)
629                 goto finish;
630
631         fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
632
633         r = sd_dhcp_lease_get_router(lease, &address);
634         if (r >= 0)
635                 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
636
637         r = sd_dhcp_lease_get_server_identifier(lease, &address);
638         if (r >= 0)
639                 fprintf(f, "SERVER_ADDRESS=%s\n",
640                         inet_ntoa(address));
641
642         r = sd_dhcp_lease_get_next_server(lease, &address);
643         if (r >= 0)
644                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
645
646         r = sd_dhcp_lease_get_mtu(lease, &mtu);
647         if (r >= 0)
648                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
649
650         fputs("DNS=", f);
651         r = sd_dhcp_lease_get_dns(lease, &addresses);
652         if (r >= 0)
653                 serialize_in_addrs(f, addresses, r);
654         fputs("\n", f);
655
656         fputs("NTP=", f);
657         r = sd_dhcp_lease_get_ntp(lease, &addresses);
658         if (r >= 0)
659                 serialize_in_addrs(f, addresses, r);
660         fputs("\n", f);
661
662         r = sd_dhcp_lease_get_domainname(lease, &string);
663         if (r >= 0)
664                 fprintf(f, "DOMAINNAME=%s\n", string);
665
666         r = sd_dhcp_lease_get_hostname(lease, &string);
667         if (r >= 0)
668                 fprintf(f, "HOSTNAME=%s\n", string);
669
670         r = sd_dhcp_lease_get_root_path(lease, &string);
671         if (r >= 0)
672                 fprintf(f, "ROOT_PATH=%s\n", string);
673
674         r = sd_dhcp_lease_get_routes(lease, &routes);
675         if (r >= 0)
676                 serialize_dhcp_routes(f, "ROUTES", routes, r);
677
678         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
679         if (r >= 0) {
680                 _cleanup_free_ char *client_id_hex;
681
682                 client_id_hex = hexmem (client_id, client_id_len);
683                 if (!client_id_hex) {
684                         r = -ENOMEM;
685                         goto finish;
686                 }
687                 fprintf(f, "CLIENTID=%s\n", client_id_hex);
688         }
689
690         r = 0;
691
692         fflush(f);
693
694         if (ferror(f) || rename(temp_path, lease_file) < 0) {
695                 r = -errno;
696                 unlink(lease_file);
697                 unlink(temp_path);
698         }
699
700 finish:
701         if (r < 0)
702                 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
703
704         return r;
705 }
706
707 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
708         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
709         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
710                             *server_address = NULL, *next_server = NULL,
711                             *dns = NULL, *ntp = NULL, *mtu = NULL,
712                             *routes = NULL, *client_id_hex = NULL;
713         struct in_addr addr;
714         int r;
715
716         assert(lease_file);
717         assert(ret);
718
719         r = dhcp_lease_new(&lease);
720         if (r < 0)
721                 return r;
722
723         r = parse_env_file(lease_file, NEWLINE,
724                            "ADDRESS", &address,
725                            "ROUTER", &router,
726                            "NETMASK", &netmask,
727                            "SERVER_IDENTIFIER", &server_address,
728                            "NEXT_SERVER", &next_server,
729                            "DNS", &dns,
730                            "NTP", &ntp,
731                            "MTU", &mtu,
732                            "DOMAINNAME", &lease->domainname,
733                            "HOSTNAME", &lease->hostname,
734                            "ROOT_PATH", &lease->root_path,
735                            "ROUTES", &routes,
736                            "CLIENTID", &client_id_hex,
737                            NULL);
738         if (r < 0) {
739                 if (r == -ENOENT)
740                         return 0;
741
742                 return log_error_errno(r, "Failed to read %s: %m", lease_file);
743         }
744
745         r = inet_pton(AF_INET, address, &addr);
746         if (r < 0)
747                 return r;
748
749         lease->address = addr.s_addr;
750
751         if (router) {
752                 r = inet_pton(AF_INET, router, &addr);
753                 if (r < 0)
754                         return r;
755
756                 lease->router = addr.s_addr;
757         }
758
759         r = inet_pton(AF_INET, netmask, &addr);
760         if (r < 0)
761                 return r;
762
763         lease->subnet_mask = addr.s_addr;
764
765         if (server_address) {
766                 r = inet_pton(AF_INET, server_address, &addr);
767                 if (r < 0)
768                         return r;
769
770                 lease->server_address = addr.s_addr;
771         }
772
773         if (next_server) {
774                 r = inet_pton(AF_INET, next_server, &addr);
775                 if (r < 0)
776                         return r;
777
778                 lease->next_server = addr.s_addr;
779         }
780
781         if (dns) {
782                 r = deserialize_in_addrs(&lease->dns, dns);
783                 if (r < 0)
784                         return r;
785
786                 lease->dns_size = r;
787         }
788
789         if (ntp) {
790                 r = deserialize_in_addrs(&lease->ntp, ntp);
791                 if (r < 0)
792                         return r;
793
794                 lease->ntp_size = r;
795         }
796
797         if (mtu) {
798                 uint16_t u;
799                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
800                         lease->mtu = u;
801         }
802
803         if (routes) {
804                 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
805                                 &lease->static_route_allocated, routes);
806                 if (r < 0)
807                     return r;
808         }
809
810         if (client_id_hex) {
811                 if (strlen (client_id_hex) % 2)
812                         return -EINVAL;
813
814                 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
815                 if (!lease->client_id)
816                         return -ENOMEM;
817                 lease->client_id_len = strlen (client_id_hex) / 2;
818         }
819
820         *ret = lease;
821         lease = NULL;
822
823         return 0;
824 }
825
826 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
827         struct in_addr address;
828         struct in_addr mask;
829         int r;
830
831         assert(lease);
832
833         address.s_addr = lease->address;
834
835         /* fall back to the default subnet masks based on address class */
836         r = in_addr_default_subnet_mask(&address, &mask);
837         if (r < 0)
838                 return r;
839
840         lease->subnet_mask = mask.s_addr;
841
842         return 0;
843 }
844
845 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
846                                 size_t *client_id_len) {
847         assert_return(lease, -EINVAL);
848         assert_return(client_id, -EINVAL);
849         assert_return(client_id_len, -EINVAL);
850
851         *client_id = lease->client_id;
852         *client_id_len = lease->client_id_len;
853         return 0;
854 }
855
856 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
857                              size_t client_id_len) {
858         assert_return(lease, -EINVAL);
859         assert_return((!client_id && !client_id_len) ||
860                       (client_id && client_id_len), -EINVAL);
861
862         free (lease->client_id);
863         lease->client_id = NULL;
864         lease->client_id_len = 0;
865
866         if (client_id) {
867                 lease->client_id = memdup (client_id, client_id_len);
868                 lease->client_id_len = client_id_len;
869         }
870
871         return 0;
872 }