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