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