chiark / gitweb /
log: rearrange log function naming
[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
501                 r = lease_parse_string(option, len, &domainname);
502                 if (r < 0)
503                         return r;
504
505                 if (!hostname_is_valid(domainname) || is_localhost(domainname))
506                         break;
507
508                 free(lease->domainname);
509                 lease->domainname = domainname;
510                 domainname = NULL;
511
512                 break;
513         }
514         case DHCP_OPTION_HOST_NAME:
515         {
516                 _cleanup_free_ char *hostname = NULL;
517
518                 r = lease_parse_string(option, len, &hostname);
519                 if (r < 0)
520                         return r;
521
522                 if (!hostname_is_valid(hostname) || is_localhost(hostname))
523                         break;
524
525                 free(lease->hostname);
526                 lease->hostname = hostname;
527                 hostname = NULL;
528
529                 break;
530         }
531         case DHCP_OPTION_ROOT_PATH:
532                 r = lease_parse_string(option, len, &lease->root_path);
533                 if (r < 0)
534                         return r;
535
536                 break;
537
538         case DHCP_OPTION_RENEWAL_T1_TIME:
539                 lease_parse_u32(option, len, &lease->t1, 1);
540
541                 break;
542
543         case DHCP_OPTION_REBINDING_T2_TIME:
544                 lease_parse_u32(option, len, &lease->t2, 1);
545
546                 break;
547
548         case DHCP_OPTION_ENABLE_IP_FORWARDING:
549                 lease_parse_bool(option, len, &lease->ip_forward);
550
551                 break;
552
553         case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
554                 lease_parse_bool(option, len, &lease->ip_forward_non_local);
555
556                 break;
557
558         case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
559                 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
560                         &lease->static_route_allocated);
561                 if (r < 0)
562                         return r;
563
564                 break;
565         }
566
567         return 0;
568 }
569
570 int dhcp_lease_new(sd_dhcp_lease **ret) {
571         sd_dhcp_lease *lease;
572
573         lease = new0(sd_dhcp_lease, 1);
574         if (!lease)
575                 return -ENOMEM;
576
577         lease->router = INADDR_ANY;
578         lease->n_ref = REFCNT_INIT;
579
580         *ret = lease;
581         return 0;
582 }
583
584 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
585         _cleanup_free_ char *temp_path = NULL;
586         _cleanup_fclose_ FILE *f = NULL;
587         struct in_addr address;
588         const struct in_addr *addresses;
589         const uint8_t *client_id;
590         size_t client_id_len;
591         const char *string;
592         uint16_t mtu;
593         struct sd_dhcp_route *routes;
594         int r;
595
596         assert(lease);
597         assert(lease_file);
598
599         r = fopen_temporary(lease_file, &f, &temp_path);
600         if (r < 0)
601                 goto finish;
602
603         fchmod(fileno(f), 0644);
604
605         r = sd_dhcp_lease_get_address(lease, &address);
606         if (r < 0)
607                 goto finish;
608
609         fprintf(f,
610                 "# This is private data. Do not parse.\n"
611                 "ADDRESS=%s\n", inet_ntoa(address));
612
613         r = sd_dhcp_lease_get_netmask(lease, &address);
614         if (r < 0)
615                 goto finish;
616
617         fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
618
619         r = sd_dhcp_lease_get_router(lease, &address);
620         if (r >= 0)
621                 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
622
623         r = sd_dhcp_lease_get_server_identifier(lease, &address);
624         if (r >= 0)
625                 fprintf(f, "SERVER_ADDRESS=%s\n",
626                         inet_ntoa(address));
627
628         r = sd_dhcp_lease_get_next_server(lease, &address);
629         if (r >= 0)
630                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
631
632         r = sd_dhcp_lease_get_mtu(lease, &mtu);
633         if (r >= 0)
634                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
635
636         fputs("DNS=", f);
637         r = sd_dhcp_lease_get_dns(lease, &addresses);
638         if (r >= 0)
639                 serialize_in_addrs(f, addresses, r);
640         fputs("\n", f);
641
642         fputs("NTP=", f);
643         r = sd_dhcp_lease_get_ntp(lease, &addresses);
644         if (r >= 0)
645                 serialize_in_addrs(f, addresses, r);
646         fputs("\n", f);
647
648         r = sd_dhcp_lease_get_domainname(lease, &string);
649         if (r >= 0)
650                 fprintf(f, "DOMAINNAME=%s\n", string);
651
652         r = sd_dhcp_lease_get_hostname(lease, &string);
653         if (r >= 0)
654                 fprintf(f, "HOSTNAME=%s\n", string);
655
656         r = sd_dhcp_lease_get_root_path(lease, &string);
657         if (r >= 0)
658                 fprintf(f, "ROOT_PATH=%s\n", string);
659
660         r = sd_dhcp_lease_get_routes(lease, &routes);
661         if (r >= 0)
662                 serialize_dhcp_routes(f, "ROUTES", routes, r);
663
664         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
665         if (r >= 0) {
666                 _cleanup_free_ char *client_id_hex;
667
668                 client_id_hex = hexmem (client_id, client_id_len);
669                 if (!client_id_hex) {
670                         r = -ENOMEM;
671                         goto finish;
672                 }
673                 fprintf(f, "CLIENTID=%s\n", client_id_hex);
674         }
675
676         r = 0;
677
678         fflush(f);
679
680         if (ferror(f) || rename(temp_path, lease_file) < 0) {
681                 r = -errno;
682                 unlink(lease_file);
683                 unlink(temp_path);
684         }
685
686 finish:
687         if (r < 0)
688                 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
689
690         return r;
691 }
692
693 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
694         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
695         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
696                             *server_address = NULL, *next_server = NULL,
697                             *dns = NULL, *ntp = NULL, *mtu = NULL,
698                             *routes = NULL, *client_id_hex = NULL;
699         struct in_addr addr;
700         int r;
701
702         assert(lease_file);
703         assert(ret);
704
705         r = dhcp_lease_new(&lease);
706         if (r < 0)
707                 return r;
708
709         r = parse_env_file(lease_file, NEWLINE,
710                            "ADDRESS", &address,
711                            "ROUTER", &router,
712                            "NETMASK", &netmask,
713                            "SERVER_IDENTIFIER", &server_address,
714                            "NEXT_SERVER", &next_server,
715                            "DNS", &dns,
716                            "NTP", &ntp,
717                            "MTU", &mtu,
718                            "DOMAINNAME", &lease->domainname,
719                            "HOSTNAME", &lease->hostname,
720                            "ROOT_PATH", &lease->root_path,
721                            "ROUTES", &routes,
722                            "CLIENTID", &client_id_hex,
723                            NULL);
724         if (r < 0) {
725                 if (r == -ENOENT)
726                         return 0;
727
728                 log_error("Failed to read %s: %s", lease_file, strerror(-r));
729                 return r;
730         }
731
732         r = inet_pton(AF_INET, address, &addr);
733         if (r < 0)
734                 return r;
735
736         lease->address = addr.s_addr;
737
738         if (router) {
739                 r = inet_pton(AF_INET, router, &addr);
740                 if (r < 0)
741                         return r;
742
743                 lease->router = addr.s_addr;
744         }
745
746         r = inet_pton(AF_INET, netmask, &addr);
747         if (r < 0)
748                 return r;
749
750         lease->subnet_mask = addr.s_addr;
751
752         if (server_address) {
753                 r = inet_pton(AF_INET, server_address, &addr);
754                 if (r < 0)
755                         return r;
756
757                 lease->server_address = addr.s_addr;
758         }
759
760         if (next_server) {
761                 r = inet_pton(AF_INET, next_server, &addr);
762                 if (r < 0)
763                         return r;
764
765                 lease->next_server = addr.s_addr;
766         }
767
768         if (dns) {
769                 r = deserialize_in_addrs(&lease->dns, dns);
770                 if (r < 0)
771                         return r;
772
773                 lease->dns_size = r;
774         }
775
776         if (ntp) {
777                 r = deserialize_in_addrs(&lease->ntp, ntp);
778                 if (r < 0)
779                         return r;
780
781                 lease->ntp_size = r;
782         }
783
784         if (mtu) {
785                 uint16_t u;
786                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
787                         lease->mtu = u;
788         }
789
790         if (routes) {
791                 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
792                                 &lease->static_route_allocated, routes);
793                 if (r < 0)
794                     return r;
795         }
796
797         if (client_id_hex) {
798                 if (strlen (client_id_hex) % 2)
799                         return -EINVAL;
800
801                 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
802                 if (!lease->client_id)
803                         return -ENOMEM;
804                 lease->client_id_len = strlen (client_id_hex) / 2;
805         }
806
807         *ret = lease;
808         lease = NULL;
809
810         return 0;
811 }
812
813 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
814         struct in_addr address;
815         struct in_addr mask;
816         int r;
817
818         assert(lease);
819
820         address.s_addr = lease->address;
821
822         /* fall back to the default subnet masks based on address class */
823         r = in_addr_default_subnet_mask(&address, &mask);
824         if (r < 0)
825                 return r;
826
827         lease->subnet_mask = mask.s_addr;
828
829         return 0;
830 }
831
832 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
833                                 size_t *client_id_len) {
834         assert_return(lease, -EINVAL);
835         assert_return(client_id, -EINVAL);
836         assert_return(client_id_len, -EINVAL);
837
838         *client_id = lease->client_id;
839         *client_id_len = lease->client_id_len;
840         return 0;
841 }
842
843 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
844                              size_t client_id_len) {
845         assert_return(lease, -EINVAL);
846         assert_return((!client_id && !client_id_len) ||
847                       (client_id && client_id_len), -EINVAL);
848
849         free (lease->client_id);
850         lease->client_id = NULL;
851         lease->client_id_len = 0;
852
853         if (client_id) {
854                 lease->client_id = memdup (client_id, client_id_len);
855                 lease->client_id_len = client_id_len;
856         }
857
858         return 0;
859 }