source: rtems-libbsd/dhcpcd/if-options.c @ 1378632

55-freebsd-126-freebsd-12
Last change on this file since 1378632 was f724741, checked in by Sebastian Huber <sebastian.huber@…>, on 01/21/14 at 15:14:42

DHCPCD(8): Add getopt_long_r() support

  • Property mode set to 100644
File size: 47.3 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/queue.h>
31
32#include <arpa/inet.h>
33
34#include <ctype.h>
35#include <errno.h>
36#ifdef __rtems__
37#define __need_getopt_newlib
38#endif /* __rtems__ */
39#include <getopt.h>
40#include <limits.h>
41#include <paths.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <unistd.h>
47#include <time.h>
48
49#include "config.h"
50#include "common.h"
51#include "dhcp.h"
52#include "dhcp6.h"
53#include "dhcpcd-embedded.h"
54#include "if-options.h"
55#include "ipv4.h"
56#include "platform.h"
57
58unsigned long long options = 0;
59
60/* These options only make sense in the config file, so don't use any
61   valid short options for them */
62#define O_BASE                  MAX('z', 'Z') + 1
63#define O_ARPING                O_BASE + 1
64#define O_FALLBACK              O_BASE + 2
65#define O_DESTINATION           O_BASE + 3
66#define O_IPV6RS                O_BASE + 4
67#define O_NOIPV6RS              O_BASE + 5
68#define O_IPV6RA_FORK           O_BASE + 6
69#define O_IPV6RA_OWN            O_BASE + 7
70#define O_IPV6RA_OWN_D          O_BASE + 8
71#define O_NOALIAS               O_BASE + 9
72#define O_IA_NA                 O_BASE + 10
73#define O_IA_TA                 O_BASE + 11
74#define O_IA_PD                 O_BASE + 12
75#define O_HOSTNAME_SHORT        O_BASE + 13
76#define O_DEV                   O_BASE + 14
77#define O_NODEV                 O_BASE + 15
78#define O_NOIPV4                O_BASE + 16
79#define O_NOIPV6                O_BASE + 17
80#define O_IAID                  O_BASE + 18
81#define O_DEFINE                O_BASE + 19
82#define O_DEFINE6               O_BASE + 20
83#define O_EMBED                 O_BASE + 21
84#define O_ENCAP                 O_BASE + 22
85#define O_VENDOPT               O_BASE + 23
86#define O_VENDCLASS             O_BASE + 24
87#define O_AUTHPROTOCOL          O_BASE + 25
88#define O_AUTHTOKEN             O_BASE + 26
89#define O_AUTHNOTREQUIRED       O_BASE + 27
90#define O_NODHCP                O_BASE + 28
91#define O_NODHCP6               O_BASE + 29
92
93char *dev_load;
94
95const struct option cf_options[] = {
96        {"background",      no_argument,       NULL, 'b'},
97        {"script",          required_argument, NULL, 'c'},
98        {"debug",           no_argument,       NULL, 'd'},
99        {"env",             required_argument, NULL, 'e'},
100        {"config",          required_argument, NULL, 'f'},
101        {"reconfigure",     no_argument,       NULL, 'g'},
102        {"hostname",        optional_argument, NULL, 'h'},
103        {"vendorclassid",   optional_argument, NULL, 'i'},
104        {"release",         no_argument,       NULL, 'k'},
105        {"leasetime",       required_argument, NULL, 'l'},
106        {"metric",          required_argument, NULL, 'm'},
107        {"rebind",          no_argument,       NULL, 'n'},
108        {"option",          required_argument, NULL, 'o'},
109        {"persistent",      no_argument,       NULL, 'p'},
110        {"quiet",           no_argument,       NULL, 'q'},
111        {"request",         optional_argument, NULL, 'r'},
112        {"inform",          optional_argument, NULL, 's'},
113        {"timeout",         required_argument, NULL, 't'},
114        {"userclass",       required_argument, NULL, 'u'},
115        {"vendor",          required_argument, NULL, 'v'},
116        {"waitip",          optional_argument, NULL, 'w'},
117        {"exit",            no_argument,       NULL, 'x'},
118        {"allowinterfaces", required_argument, NULL, 'z'},
119        {"reboot",          required_argument, NULL, 'y'},
120        {"noarp",           no_argument,       NULL, 'A'},
121        {"nobackground",    no_argument,       NULL, 'B'},
122        {"nohook",          required_argument, NULL, 'C'},
123        {"duid",            no_argument,       NULL, 'D'},
124        {"lastlease",       no_argument,       NULL, 'E'},
125        {"fqdn",            optional_argument, NULL, 'F'},
126        {"nogateway",       no_argument,       NULL, 'G'},
127        {"xidhwaddr",       no_argument,       NULL, 'H'},
128        {"clientid",        optional_argument, NULL, 'I'},
129        {"broadcast",       no_argument,       NULL, 'J'},
130        {"nolink",          no_argument,       NULL, 'K'},
131        {"noipv4ll",        no_argument,       NULL, 'L'},
132        {"nooption",        optional_argument, NULL, 'O'},
133        {"require",         required_argument, NULL, 'Q'},
134        {"static",          required_argument, NULL, 'S'},
135        {"test",            no_argument,       NULL, 'T'},
136        {"dumplease",       no_argument,       NULL, 'U'},
137        {"variables",       no_argument,       NULL, 'V'},
138        {"whitelist",       required_argument, NULL, 'W'},
139        {"blacklist",       required_argument, NULL, 'X'},
140        {"denyinterfaces",  required_argument, NULL, 'Z'},
141        {"arping",          required_argument, NULL, O_ARPING},
142        {"destination",     required_argument, NULL, O_DESTINATION},
143        {"fallback",        required_argument, NULL, O_FALLBACK},
144        {"ipv6rs",          no_argument,       NULL, O_IPV6RS},
145        {"noipv6rs",        no_argument,       NULL, O_NOIPV6RS},
146        {"ipv6ra_fork",     no_argument,       NULL, O_IPV6RA_FORK},
147        {"ipv6ra_own",      no_argument,       NULL, O_IPV6RA_OWN},
148        {"ipv6ra_own_default", no_argument,    NULL, O_IPV6RA_OWN_D},
149        {"ipv4only",        no_argument,       NULL, '4'},
150        {"ipv6only",        no_argument,       NULL, '6'},
151        {"noipv4",          no_argument,       NULL, O_NOIPV4},
152        {"noipv6",          no_argument,       NULL, O_NOIPV6},
153        {"noalias",         no_argument,       NULL, O_NOALIAS},
154        {"iaid",            required_argument, NULL, O_IAID},
155        {"ia_na",           no_argument,       NULL, O_IA_NA},
156        {"ia_ta",           no_argument,       NULL, O_IA_TA},
157        {"ia_pd",           no_argument,       NULL, O_IA_PD},
158        {"hostname_short",  no_argument,       NULL, O_HOSTNAME_SHORT},
159        {"dev",             required_argument, NULL, O_DEV},
160        {"nodev",           no_argument,       NULL, O_NODEV},
161        {"define",          required_argument, NULL, O_DEFINE},
162        {"define6",         required_argument, NULL, O_DEFINE6},
163        {"embed",           required_argument, NULL, O_EMBED},
164        {"encap",           required_argument, NULL, O_ENCAP},
165        {"vendopt",         required_argument, NULL, O_VENDOPT},
166        {"vendclass",       required_argument, NULL, O_VENDCLASS},
167        {"authprotocol",    required_argument, NULL, O_AUTHPROTOCOL},
168        {"authtoken",       required_argument, NULL, O_AUTHTOKEN},
169        {"noauthrequired",  no_argument,       NULL, O_AUTHNOTREQUIRED},
170        {"nodhcp",          no_argument,       NULL, O_NODHCP},
171        {"nodhcp6",         no_argument,       NULL, O_NODHCP6},
172        {NULL,              0,                 NULL, '\0'}
173};
174
175static int
176atoint(const char *s)
177{
178        char *t;
179        long n;
180
181        errno = 0;
182        n = strtol(s, &t, 0);
183        if ((errno != 0 && n == 0) || s == t ||
184            (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
185        {
186                if (errno == 0)
187                        errno = EINVAL;
188                syslog(LOG_ERR, "`%s' out of range", s);
189                return -1;
190        }
191
192        return (int)n;
193}
194
195static char *
196add_environ(struct if_options *ifo, const char *value, int uniq)
197{
198        char **newlist;
199        char **lst = ifo->environ;
200        size_t i = 0, l, lv;
201        char *match = NULL, *p, *n;
202
203        match = strdup(value);
204        if (match == NULL) {
205                syslog(LOG_ERR, "%s: %m", __func__);
206                return NULL;
207        }
208        p = strchr(match, '=');
209        if (p)
210                *p++ = '\0';
211        l = strlen(match);
212
213        while (lst && lst[i]) {
214                if (match && strncmp(lst[i], match, l) == 0) {
215                        if (uniq) {
216                                n = strdup(value);
217                                if (n == NULL) {
218                                        syslog(LOG_ERR, "%s: %m", __func__);
219                                        return NULL;
220                                }
221                                free(lst[i]);
222                                lst[i] = n;
223                        } else {
224                                /* Append a space and the value to it */
225                                l = strlen(lst[i]);
226                                lv = strlen(p);
227                                n = realloc(lst[i], l + lv + 2);
228                                if (n == NULL) {
229                                        syslog(LOG_ERR, "%s: %m", __func__);
230                                        return NULL;
231                                }
232                                lst[i] = n;
233                                lst[i][l] = ' ';
234                                memcpy(lst[i] + l + 1, p, lv);
235                                lst[i][l + lv + 1] = '\0';
236                        }
237                        free(match);
238                        return lst[i];
239                }
240                i++;
241        }
242
243        n = strdup(value);
244        if (n == NULL) {
245                syslog(LOG_ERR, "%s: %m", __func__);
246                return NULL;
247        }
248        newlist = realloc(lst, sizeof(char *) * (i + 2));
249        if (newlist == NULL) {
250                syslog(LOG_ERR, "%s: %m", __func__);
251                return NULL;
252        }
253        newlist[i] = n;
254        newlist[i + 1] = NULL;
255        ifo->environ = newlist;
256        free(match);
257        return newlist[i];
258}
259
260#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
261static ssize_t
262parse_string_hwaddr(char *sbuf, ssize_t slen, const char *str, int clid)
263{
264        ssize_t l;
265        const char *p;
266        int i, punt_last = 0;
267        char c[4];
268
269        /* If surrounded by quotes then it's a string */
270        if (*str == '"') {
271                str++;
272                l = strlen(str);
273                p = str + l - 1;
274                if (*p == '"')
275                        punt_last = 1;
276        } else {
277                l = hwaddr_aton(NULL, str);
278                if (l > 1) {
279                        if (l > slen) {
280                                errno = ENOBUFS;
281                                return -1;
282                        }
283                        hwaddr_aton((uint8_t *)sbuf, str);
284                        return l;
285                }
286        }
287
288        /* Process escapes */
289        l = 0;
290        /* If processing a string on the clientid, first byte should be
291         * 0 to indicate a non hardware type */
292        if (clid && *str) {
293                if (sbuf)
294                        *sbuf++ = 0;
295                l++;
296        }
297        c[3] = '\0';
298        while (*str) {
299                if (++l > slen && sbuf) {
300                        errno = ENOBUFS;
301                        return -1;
302                }
303                if (*str == '\\') {
304                        str++;
305                        switch(*str) {
306                        case '\0':
307                                break;
308                        case 'b':
309                                if (sbuf)
310                                        *sbuf++ = '\b';
311                                str++;
312                                break;
313                        case 'n':
314                                if (sbuf)
315                                        *sbuf++ = '\n';
316                                str++;
317                                break;
318                        case 'r':
319                                if (sbuf)
320                                        *sbuf++ = '\r';
321                                str++;
322                                break;
323                        case 't':
324                                if (sbuf)
325                                        *sbuf++ = '\t';
326                                str++;
327                                break;
328                        case 'x':
329                                /* Grab a hex code */
330                                c[1] = '\0';
331                                for (i = 0; i < 2; i++) {
332                                        if (isxdigit((unsigned char)*str) == 0)
333                                                break;
334                                        c[i] = *str++;
335                                }
336                                if (c[1] != '\0' && sbuf) {
337                                        c[2] = '\0';
338                                        *sbuf++ = strtol(c, NULL, 16);
339                                } else
340                                        l--;
341                                break;
342                        case '0':
343                                /* Grab an octal code */
344                                c[2] = '\0';
345                                for (i = 0; i < 3; i++) {
346                                        if (*str < '0' || *str > '7')
347                                                break;
348                                        c[i] = *str++;
349                                }
350                                if (c[2] != '\0' && sbuf) {
351                                        i = strtol(c, NULL, 8);
352                                        if (i > 255)
353                                                i = 255;
354                                        *sbuf ++= i;
355                                } else
356                                        l--;
357                                break;
358                        default:
359                                if (sbuf)
360                                        *sbuf++ = *str;
361                                str++;
362                                break;
363                        }
364                } else {
365                        if (sbuf)
366                                *sbuf++ = *str;
367                        str++;
368                }
369        }
370        if (punt_last) {
371                if (sbuf)
372                        *--sbuf = '\0';
373                l--;
374        }
375        return l;
376}
377
378static int
379parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
380{
381        unsigned long l;
382        size_t s;
383        uint32_t u32;
384        char *np;
385
386        errno = 0;
387        l = strtoul(arg, &np, 0);
388        if (l <= (unsigned long)UINT32_MAX && errno == 0 && *np == '\0') {
389                if (n)
390                        u32 = htonl(l);
391                else
392                        u32 = l;
393                memcpy(iaid, &u32, sizeof(u32));
394                return 0;
395        }
396
397        if ((s = parse_string((char *)iaid, len, arg)) < 1) {
398                syslog(LOG_ERR, "%s: invalid IAID", arg);
399                return -1;
400        }
401        if (s < 4)
402                iaid[3] = '\0';
403        if (s < 3)
404                iaid[2] = '\0';
405        if (s < 2)
406                iaid[1] = '\0';
407        return 0;
408}
409
410static int
411parse_iaid(uint8_t *iaid, const char *arg, size_t len)
412{
413
414        return parse_iaid1(iaid, arg, len, 1);
415}
416
417static int
418parse_uint32(uint32_t *i, const char *arg)
419{
420
421        return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
422}
423
424static char **
425splitv(int *argc, char **argv, const char *arg)
426{
427        char **n, **v = argv;
428        char *o = strdup(arg), *p, *t, *nt;
429
430        if (o == NULL) {
431                syslog(LOG_ERR, "%s: %m", __func__);
432                return v;
433        }
434        p = o;
435        while ((t = strsep(&p, ", "))) {
436                nt = strdup(t);
437                if (nt == NULL) {
438                        syslog(LOG_ERR, "%s: %m", __func__);
439                        return NULL;
440                }
441                (*argc)++;
442                n = realloc(v, sizeof(char *) * ((*argc)));
443                if (n == NULL) {
444                        syslog(LOG_ERR, "%s: %m", __func__);
445                        return NULL;
446                }
447                v = n;
448                v[(*argc) - 1] = nt;
449        }
450        free(o);
451        return v;
452}
453
454#ifdef INET
455static int
456parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
457{
458        char *p;
459        int i;
460
461        if (arg == NULL || *arg == '\0') {
462                if (addr != NULL)
463                        addr->s_addr = 0;
464                if (net != NULL)
465                        net->s_addr = 0;
466                return 0;
467        }
468        if ((p = strchr(arg, '/')) != NULL) {
469                *p++ = '\0';
470                if (net != NULL &&
471                    (sscanf(p, "%d", &i) != 1 ||
472                        inet_cidrtoaddr(i, net) != 0))
473                {
474                        syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
475                        return -1;
476                }
477        }
478
479        if (addr != NULL && inet_aton(arg, addr) == 0) {
480                syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
481                return -1;
482        }
483        if (p != NULL)
484                *--p = '/';
485        else if (net != NULL)
486                net->s_addr = ipv4_getnetmask(addr->s_addr);
487        return 0;
488}
489#else
490static int
491parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
492    __unused const char *arg)
493{
494
495        syslog(LOG_ERR, "No IPv4 support");
496        return -1;
497}
498#endif
499
500static const char *
501set_option_space(const char *arg, const struct dhcp_opt **d, size_t *dl,
502    struct if_options *ifo,
503    uint8_t *request[], uint8_t *require[], uint8_t *no[])
504{
505
506#ifdef INET6
507        if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
508                *d = dhcp6_opts;
509                *dl = dhcp6_opts_len;
510                *request = ifo->requestmask6;
511                *require = ifo->requiremask6;
512                *no = ifo->nomask6;
513                return arg + strlen("dhcp6_");
514        }
515#endif
516
517#ifdef INET
518        *d = dhcp_opts;
519        *dl = dhcp_opts_len;
520#else
521        *d = NULL;
522        *dl = 0;
523#endif
524        *request = ifo->requestmask;
525        *require = ifo->requiremask;
526        *no = ifo->nomask;
527        return arg;
528}
529
530/* Pointer to last defined option */
531static struct dhcp_opt *ldop;
532static struct dhcp_opt *edop;
533
534void
535free_dhcp_opt_embenc(struct dhcp_opt *opt)
536{
537        size_t i;
538        struct dhcp_opt *o;
539
540        free(opt->var);
541
542        for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
543                free_dhcp_opt_embenc(o);
544        free(opt->embopts);
545        opt->embopts_len = 0;
546        opt->embopts = NULL;
547
548        for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
549                free_dhcp_opt_embenc(o);
550        free(opt->encopts);
551        opt->encopts_len = 0;
552        opt->encopts = NULL;
553}
554
555static char *
556strwhite(const char *s)
557{
558
559        if (s == NULL)
560                return NULL;
561        while (*s != ' ' && *s != '\t') {
562                if (*s == '\0')
563                        return NULL;
564                s++;
565        }
566        return UNCONST(s);
567}
568
569static char *
570strskipwhite(const char *s)
571{
572
573        if (s == NULL)
574                return NULL;
575        while (*s == ' ' || *s == '\t') {
576                if (*s == '\0')
577                        return NULL;
578                s++;
579        }
580        return UNCONST(s);
581}
582
583/* Find the end pointer of a string. */
584static char *
585strend(const char *s)
586{
587
588        s = strskipwhite(s);
589        if (s == NULL)
590                return NULL;
591        if (*s != '"')
592                return strchr(s, ' ');
593        s++;
594        for (; *s != '"' ; s++) {
595                if (*s == '\0')
596                        return NULL;
597                if (*s == '\\') {
598                        if (*(++s) == '\0')
599                                return NULL;
600                }
601        }
602        return UNCONST(++s);
603}
604
605static int
606parse_option(const char *ifname, struct if_options *ifo,
607    int opt, const char *arg)
608{
609        int i, l, t;
610        unsigned int u;
611        char *p = NULL, *fp, *np, **nconf;
612        ssize_t s;
613        struct in_addr addr, addr2;
614        in_addr_t *naddr;
615        struct rt *rt;
616        const struct dhcp_opt *d;
617        uint8_t *request, *require, *no;
618        struct dhcp_opt **dop, *ndop;
619        size_t *dop_len, dl;
620        struct vivco *vivco;
621        struct token *token;
622#ifdef INET6
623        size_t sl;
624        struct if_ia *ia;
625        uint8_t iaid[4];
626        struct if_sla *sla, *slap;
627#endif
628
629        dop = NULL;
630        dop_len = NULL;
631        i = 0;
632        switch(opt) {
633        case 'f': /* FALLTHROUGH */
634        case 'g': /* FALLTHROUGH */
635        case 'n': /* FALLTHROUGH */
636        case 'x': /* FALLTHROUGH */
637        case 'T': /* FALLTHROUGH */
638        case 'U': /* FALLTHROUGH */
639        case 'V': /* We need to handle non interface options */
640                break;
641        case 'b':
642                ifo->options |= DHCPCD_BACKGROUND;
643                break;
644        case 'c':
645                strlcpy(ifo->script, arg, sizeof(ifo->script));
646                break;
647        case 'd':
648                ifo->options |= DHCPCD_DEBUG;
649                break;
650        case 'e':
651                add_environ(ifo, arg, 1);
652                break;
653        case 'h':
654                if (!arg) {
655                        ifo->options |= DHCPCD_HOSTNAME;
656                        break;
657                }
658                s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
659                if (s == -1) {
660                        syslog(LOG_ERR, "hostname: %m");
661                        return -1;
662                }
663                if (s != 0 && ifo->hostname[0] == '.') {
664                        syslog(LOG_ERR, "hostname cannot begin with .");
665                        return -1;
666                }
667                ifo->hostname[s] = '\0';
668                if (ifo->hostname[0] == '\0')
669                        ifo->options &= ~DHCPCD_HOSTNAME;
670                else
671                        ifo->options |= DHCPCD_HOSTNAME;
672                break;
673        case 'i':
674                if (arg)
675                        s = parse_string((char *)ifo->vendorclassid + 1,
676                            VENDORCLASSID_MAX_LEN, arg);
677                else
678                        s = 0;
679                if (s == -1) {
680                        syslog(LOG_ERR, "vendorclassid: %m");
681                        return -1;
682                }
683                *ifo->vendorclassid = (uint8_t)s;
684                break;
685        case 'k':
686                ifo->options |= DHCPCD_RELEASE;
687                break;
688        case 'l':
689                if (*arg == '-') {
690                        syslog(LOG_ERR,
691                            "leasetime must be a positive value");
692                        return -1;
693                }
694                errno = 0;
695                ifo->leasetime = (uint32_t)strtoul(arg, NULL, 0);
696                if (errno == EINVAL || errno == ERANGE) {
697                        syslog(LOG_ERR, "`%s' out of range", arg);
698                        return -1;
699                }
700                break;
701        case 'm':
702                ifo->metric = atoint(arg);
703                if (ifo->metric < 0) {
704                        syslog(LOG_ERR, "metric must be a positive value");
705                        return -1;
706                }
707                break;
708        case 'o':
709                arg = set_option_space(arg, &d, &dl, ifo,
710                    &request, &require, &no);
711                if (make_option_mask(d, dl, request, arg, 1) != 0) {
712                        syslog(LOG_ERR, "unknown option `%s'", arg);
713                        return -1;
714                }
715                break;
716        case 'p':
717                ifo->options |= DHCPCD_PERSISTENT;
718                break;
719        case 'q':
720                ifo->options |= DHCPCD_QUIET;
721                break;
722        case 'r':
723                if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
724                        return -1;
725                ifo->options |= DHCPCD_REQUEST;
726                ifo->req_mask.s_addr = 0;
727                break;
728        case 's':
729                if (ifo->options & DHCPCD_IPV6 &&
730                    !(ifo->options & DHCPCD_IPV4))
731                {
732                        ifo->options |= DHCPCD_INFORM;
733                        break;
734                }
735                if (arg && *arg != '\0') {
736                        if (parse_addr(&ifo->req_addr, &ifo->req_mask,
737                                arg) != 0)
738                                return -1;
739                } else {
740                        ifo->req_addr.s_addr = 0;
741                        ifo->req_mask.s_addr = 0;
742                }
743                ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
744                ifo->options &= ~(DHCPCD_ARP | DHCPCD_STATIC);
745                break;
746        case 't':
747                ifo->timeout = atoint(arg);
748                if (ifo->timeout < 0) {
749                        syslog(LOG_ERR, "timeout must be a positive value");
750                        return -1;
751                }
752                break;
753        case 'u':
754                s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
755                s = parse_string((char *)ifo->userclass +
756                    ifo->userclass[0] + 2,
757                    s, arg);
758                if (s == -1) {
759                        syslog(LOG_ERR, "userclass: %m");
760                        return -1;
761                }
762                if (s != 0) {
763                        ifo->userclass[ifo->userclass[0] + 1] = s;
764                        ifo->userclass[0] += s + 1;
765                }
766                break;
767        case 'v':
768                p = strchr(arg, ',');
769                if (!p || !p[1]) {
770                        syslog(LOG_ERR, "invalid vendor format: %s", arg);
771                        return -1;
772                }
773
774                /* If vendor starts with , then it is not encapsulated */
775                if (p == arg) {
776                        arg++;
777                        s = parse_string((char *)ifo->vendor + 1,
778                            VENDOR_MAX_LEN, arg);
779                        if (s == -1) {
780                                syslog(LOG_ERR, "vendor: %m");
781                                return -1;
782                        }
783                        ifo->vendor[0] = (uint8_t)s;
784                        ifo->options |= DHCPCD_VENDORRAW;
785                        break;
786                }
787
788                /* Encapsulated vendor options */
789                if (ifo->options & DHCPCD_VENDORRAW) {
790                        ifo->options &= ~DHCPCD_VENDORRAW;
791                        ifo->vendor[0] = 0;
792                }
793
794                /* No need to strip the comma */
795                i = atoint(arg);
796                if (i < 1 || i > 254) {
797                        syslog(LOG_ERR, "vendor option should be between"
798                            " 1 and 254 inclusive");
799                        return -1;
800                }
801
802                arg = p + 1;
803                s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
804                if (inet_aton(arg, &addr) == 1) {
805                        if (s < 6) {
806                                s = -1;
807                                errno = ENOBUFS;
808                        } else {
809                                memcpy(ifo->vendor + ifo->vendor[0] + 3,
810                                    &addr.s_addr, sizeof(addr.s_addr));
811                                s = sizeof(addr.s_addr);
812                        }
813                } else {
814                        s = parse_string((char *)ifo->vendor +
815                            ifo->vendor[0] + 3, s, arg);
816                }
817                if (s == -1) {
818                        syslog(LOG_ERR, "vendor: %m");
819                        return -1;
820                }
821                if (s != 0) {
822                        ifo->vendor[ifo->vendor[0] + 1] = i;
823                        ifo->vendor[ifo->vendor[0] + 2] = s;
824                        ifo->vendor[0] += s + 2;
825                }
826                break;
827        case 'w':
828                ifo->options |= DHCPCD_WAITIP;
829                if (arg != NULL && arg[0] != '\0') {
830                        if (arg[0] == '4' || arg[1] == '4')
831                                ifo->options |= DHCPCD_WAITIP4;
832                        if (arg[0] == '6' || arg[1] == '6')
833                                ifo->options |= DHCPCD_WAITIP6;
834                }
835                break;
836        case 'y':
837                ifo->reboot = atoint(arg);
838                if (ifo->reboot < 0) {
839                        syslog(LOG_ERR, "reboot must be a positive value");
840                        return -1;
841                }
842                break;
843        case 'z':
844                ifav = splitv(&ifac, ifav, arg);
845                break;
846        case 'A':
847                ifo->options &= ~DHCPCD_ARP;
848                /* IPv4LL requires ARP */
849                ifo->options &= ~DHCPCD_IPV4LL;
850                break;
851        case 'B':
852                ifo->options &= ~DHCPCD_DAEMONISE;
853                break;
854        case 'C':
855                /* Commas to spaces for shell */
856                while ((p = strchr(arg, ',')))
857                        *p = ' ';
858                s = strlen("skip_hooks=") + strlen(arg) + 1;
859                p = malloc(sizeof(char) * s);
860                if (p == NULL) {
861                        syslog(LOG_ERR, "%s: %m", __func__);
862                        return -1;
863                }
864                snprintf(p, s, "skip_hooks=%s", arg);
865                add_environ(ifo, p, 0);
866                free(p);
867                break;
868        case 'D':
869                ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
870                break;
871        case 'E':
872                ifo->options |= DHCPCD_LASTLEASE;
873                break;
874        case 'F':
875                if (!arg) {
876                        ifo->fqdn = FQDN_BOTH;
877                        break;
878                }
879                if (strcmp(arg, "none") == 0)
880                        ifo->fqdn = FQDN_NONE;
881                else if (strcmp(arg, "ptr") == 0)
882                        ifo->fqdn = FQDN_PTR;
883                else if (strcmp(arg, "both") == 0)
884                        ifo->fqdn = FQDN_BOTH;
885                else if (strcmp(arg, "disable") == 0)
886                        ifo->fqdn = FQDN_DISABLE;
887                else {
888                        syslog(LOG_ERR, "invalid value `%s' for FQDN", arg);
889                        return -1;
890                }
891                break;
892        case 'G':
893                ifo->options &= ~DHCPCD_GATEWAY;
894                break;
895        case 'H':
896                ifo->options |= DHCPCD_XID_HWADDR;
897                break;
898        case 'I':
899                /* Strings have a type of 0 */;
900                ifo->clientid[1] = 0;
901                if (arg)
902                        s = parse_string_hwaddr((char *)ifo->clientid + 1,
903                            CLIENTID_MAX_LEN, arg, 1);
904                else
905                        s = 0;
906                if (s == -1) {
907                        syslog(LOG_ERR, "clientid: %m");
908                        return -1;
909                }
910                ifo->options |= DHCPCD_CLIENTID;
911                ifo->clientid[0] = (uint8_t)s;
912                break;
913        case 'J':
914                ifo->options |= DHCPCD_BROADCAST;
915                break;
916        case 'K':
917                ifo->options &= ~DHCPCD_LINK;
918                break;
919        case 'L':
920                ifo->options &= ~DHCPCD_IPV4LL;
921                break;
922        case 'O':
923                arg = set_option_space(arg, &d, &dl, ifo,
924                    &request, &require, &no);
925                if (make_option_mask(d, dl, request, arg, -1) != 0 ||
926                    make_option_mask(d, dl, require, arg, -1) != 0 ||
927                    make_option_mask(d, dl, no, arg, 1) != 0)
928                {
929                        syslog(LOG_ERR, "unknown option `%s'", arg);
930                        return -1;
931                }
932                break;
933        case 'Q':
934                arg = set_option_space(arg, &d, &dl, ifo,
935                    &request, &require, &no);
936                if (make_option_mask(d, dl, require, arg, 1) != 0 ||
937                    make_option_mask(d, dl, request, arg, 1) != 0)
938                {
939                        syslog(LOG_ERR, "unknown option `%s'", arg);
940                        return -1;
941                }
942                break;
943        case 'S':
944                p = strchr(arg, '=');
945                if (p == NULL) {
946                        syslog(LOG_ERR, "static assignment required");
947                        return -1;
948                }
949                p++;
950                if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
951                        if (parse_addr(&ifo->req_addr,
952                            ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
953                            p) != 0)
954                                return -1;
955
956                        ifo->options |= DHCPCD_STATIC;
957                        ifo->options &= ~DHCPCD_INFORM;
958                } else if (strncmp(arg, "subnet_mask=", strlen("subnet_mask=")) == 0) {
959                        if (parse_addr(&ifo->req_mask, NULL, p) != 0)
960                                return -1;
961                } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
962                    strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
963                    strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
964                    strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
965                {
966                        fp = np = strwhite(p);
967                        if (np == NULL) {
968                                syslog(LOG_ERR, "all routes need a gateway");
969                                return -1;
970                        }
971                        *np++ = '\0';
972                        np = strskipwhite(np);
973                        if (ifo->routes == NULL) {
974                                ifo->routes = malloc(sizeof(*ifo->routes));
975                                if (ifo->routes == NULL) {
976                                        syslog(LOG_ERR, "%s: %m", __func__);
977                                        return -1;
978                                }
979                                TAILQ_INIT(ifo->routes);
980                        }
981                        rt = malloc(sizeof(*rt));
982                        if (rt == NULL) {
983                                syslog(LOG_ERR, "%s: %m", __func__);
984                                *fp = ' ';
985                                return -1;
986                        }
987                        if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
988                            parse_addr(&rt->gate, NULL, np) == -1)
989                        {
990                                free(rt);
991                                *fp = ' ';
992                                return -1;
993                        }
994                        TAILQ_INSERT_TAIL(ifo->routes, rt, next);
995                        *fp = ' ';
996                } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
997                        if (ifo->routes == NULL) {
998                                ifo->routes = malloc(sizeof(*ifo->routes));
999                                if (ifo->routes == NULL) {
1000                                        syslog(LOG_ERR, "%s: %m", __func__);
1001                                        return -1;
1002                                }
1003                                TAILQ_INIT(ifo->routes);
1004                        }
1005                        rt = malloc(sizeof(*rt));
1006                        if (rt == NULL) {
1007                                syslog(LOG_ERR, "%s: %m", __func__);
1008                                return -1;
1009                        }
1010                        rt->dest.s_addr = INADDR_ANY;
1011                        rt->net.s_addr = INADDR_ANY;
1012                        if (parse_addr(&rt->gate, NULL, p) == -1) {
1013                                free(rt);
1014                                return -1;
1015                        }
1016                        TAILQ_INSERT_TAIL(ifo->routes, rt, next);
1017                } else {
1018                        s = 0;
1019                        if (ifo->config != NULL) {
1020                                while (ifo->config[s] != NULL) {
1021                                        if (strncmp(ifo->config[s], arg,
1022                                                p - arg) == 0)
1023                                        {
1024                                                p = strdup(arg);
1025                                                if (p == NULL) {
1026                                                        syslog(LOG_ERR,
1027                                                            "%s: %m", __func__);
1028                                                        return -1;
1029                                                }
1030                                                free(ifo->config[s]);
1031                                                ifo->config[s] = p;
1032                                                return 1;
1033                                        }
1034                                        s++;
1035                                }
1036                        }
1037                        p = strdup(arg);
1038                        if (p == NULL) {
1039                                syslog(LOG_ERR, "%s: %m", __func__);
1040                                return -1;
1041                        }
1042                        nconf = realloc(ifo->config, sizeof(char *) * (s + 2));
1043                        if (nconf == NULL) {
1044                                syslog(LOG_ERR, "%s: %m", __func__);
1045                                return -1;
1046                        }
1047                        ifo->config = nconf;
1048                        ifo->config[s] = p;
1049                        ifo->config[s + 1] = NULL;
1050                }
1051                break;
1052        case 'W':
1053                if (parse_addr(&addr, &addr2, arg) != 0)
1054                        return -1;
1055                if (strchr(arg, '/') == NULL)
1056                        addr2.s_addr = INADDR_BROADCAST;
1057                naddr = realloc(ifo->whitelist,
1058                    sizeof(in_addr_t) * (ifo->whitelist_len + 2));
1059                if (naddr == NULL) {
1060                        syslog(LOG_ERR, "%s: %m", __func__);
1061                        return -1;
1062                }
1063                ifo->whitelist = naddr;
1064                ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
1065                ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
1066                break;
1067        case 'X':
1068                if (parse_addr(&addr, &addr2, arg) != 0)
1069                        return -1;
1070                if (strchr(arg, '/') == NULL)
1071                        addr2.s_addr = INADDR_BROADCAST;
1072                naddr = realloc(ifo->blacklist,
1073                    sizeof(in_addr_t) * (ifo->blacklist_len + 2));
1074                if (naddr == NULL) {
1075                        syslog(LOG_ERR, "%s: %m", __func__);
1076                        return -1;
1077                }
1078                ifo->blacklist = naddr;
1079                ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
1080                ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
1081                break;
1082        case 'Z':
1083                ifdv = splitv(&ifdc, ifdv, arg);
1084                break;
1085        case '4':
1086                ifo->options &= ~DHCPCD_IPV6;
1087                ifo->options |= DHCPCD_IPV4;
1088                break;
1089        case '6':
1090                ifo->options &= ~DHCPCD_IPV4;
1091                ifo->options |= DHCPCD_IPV6;
1092                break;
1093        case O_NOIPV4:
1094                ifo->options &= ~DHCPCD_IPV4;
1095                break;
1096        case O_NOIPV6:
1097                ifo->options &= ~DHCPCD_IPV6;
1098                break;
1099#ifdef INET
1100        case O_ARPING:
1101                while (arg && *arg != '\0') {
1102                        fp = strwhite(arg);
1103                        if (fp)
1104                                *fp++ = '\0';
1105                        if (parse_addr(&addr, NULL, arg) != 0)
1106                                return -1;
1107                        naddr = realloc(ifo->arping,
1108                            sizeof(in_addr_t) * (ifo->arping_len + 1));
1109                        if (naddr == NULL) {
1110                                syslog(LOG_ERR, "%s: %m", __func__);
1111                                return -1;
1112                        }
1113                        ifo->arping = naddr;
1114                        ifo->arping[ifo->arping_len++] = addr.s_addr;
1115                        arg = strskipwhite(fp);
1116                }
1117                break;
1118        case O_DESTINATION:
1119                if (make_option_mask(dhcp_opts, dhcp_opts_len,
1120                    ifo->dstmask, arg, 2) != 0) {
1121                        if (errno == EINVAL)
1122                                syslog(LOG_ERR, "option `%s' does not take"
1123                                    " an IPv4 address", arg);
1124                        else
1125                                syslog(LOG_ERR, "unknown option `%s'", arg);
1126                        return -1;
1127                }
1128                break;
1129        case O_FALLBACK:
1130                free(ifo->fallback);
1131                ifo->fallback = strdup(arg);
1132                if (ifo->fallback == NULL) {
1133                        syslog(LOG_ERR, "%s: %m", __func__);
1134                        return -1;
1135                }
1136                break;
1137#endif
1138        case O_IAID:
1139                if (ifname == NULL) {
1140                        syslog(LOG_ERR,
1141                            "IAID must belong in an interface block");
1142                        return -1;
1143                }
1144                if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1)
1145                        return -1;
1146                ifo->options |= DHCPCD_IAID;
1147                break;
1148        case O_IPV6RS:
1149                ifo->options |= DHCPCD_IPV6RS;
1150                break;
1151        case O_NOIPV6RS:
1152                ifo->options &= ~DHCPCD_IPV6RS;
1153                break;
1154        case O_IPV6RA_FORK:
1155                ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
1156                break;
1157        case O_IPV6RA_OWN:
1158                ifo->options |= DHCPCD_IPV6RA_OWN;
1159                break;
1160        case O_IPV6RA_OWN_D:
1161                ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT;
1162                break;
1163        case O_NOALIAS:
1164                ifo->options |= DHCPCD_NOALIAS;
1165                break;
1166#ifdef INET6
1167        case O_IA_NA:
1168                i = D6_OPTION_IA_NA;
1169                /* FALLTHROUGH */
1170        case O_IA_TA:
1171                if (i == 0)
1172                        i = D6_OPTION_IA_TA;
1173                /* FALLTHROUGH */
1174        case O_IA_PD:
1175                if (i == 0) {
1176                        if (ifname == NULL) {
1177                                syslog(LOG_ERR,
1178                                    "IA PD must belong in an interface block");
1179                                return -1;
1180                        }
1181                        i = D6_OPTION_IA_PD;
1182                }
1183                if (arg != NULL && ifname == NULL) {
1184                        syslog(LOG_ERR,
1185                            "IA with IAID must belong in an interface block");
1186                        return -1;
1187                }
1188                ifo->options |= DHCPCD_IA_FORCED;
1189                if (ifo->ia_type != 0 && ifo->ia_type != i) {
1190                        syslog(LOG_ERR, "cannot specify a different IA type");
1191                        return -1;
1192                }
1193                ifo->ia_type = i;
1194                if (arg == NULL)
1195                        break;
1196                fp = strwhite(arg);
1197                if (fp)
1198                        *fp++ = '\0';
1199                if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
1200                        return -1;
1201                ia = NULL;
1202                for (sl = 0; sl < ifo->ia_len; sl++) {
1203                        if (ifo->ia[sl].iaid[0] == iaid[0] &&
1204                            ifo->ia[sl].iaid[1] == iaid[1] &&
1205                            ifo->ia[sl].iaid[2] == iaid[2] &&
1206                            ifo->ia[sl].iaid[3] == iaid[3])
1207                        {
1208                                ia = &ifo->ia[sl];
1209                                break;
1210                        }
1211                }
1212                if (ia == NULL) {
1213                        ia = realloc(ifo->ia,
1214                            sizeof(*ifo->ia) * (ifo->ia_len + 1));
1215                        if (ia == NULL) {
1216                                syslog(LOG_ERR, "%s: %m", __func__);
1217                                return -1;
1218                        }
1219                        ifo->ia = ia;
1220                        ia = &ifo->ia[ifo->ia_len++];
1221                        ia->iaid[0] = iaid[0];
1222                        ia->iaid[1] = iaid[1];
1223                        ia->iaid[2] = iaid[2];
1224                        ia->iaid[3] = iaid[3];
1225                        ia->sla = NULL;
1226                        ia->sla_len = 0;
1227                }
1228                if (ifo->ia_type != D6_OPTION_IA_PD)
1229                        break;
1230                for (p = fp; p; p = fp) {
1231                        fp = strwhite(p);
1232                        if (fp) {
1233                                *fp++ = '\0';
1234                                fp = strskipwhite(fp);
1235                        }
1236                        sla = realloc(ia->sla,
1237                            sizeof(*ia->sla) * (ia->sla_len + 1));
1238                        if (sla == NULL) {
1239                                syslog(LOG_ERR, "%s: %m", __func__);
1240                                return -1;
1241                        }
1242                        ia->sla = sla;
1243                        sla = &ia->sla[ia->sla_len++];
1244                        np = strchr(p, '/');
1245                        if (np)
1246                                *np++ = '\0';
1247                        if (strcmp(ifname, p) == 0) {
1248                                syslog(LOG_ERR,
1249                                    "%s: cannot assign IA_PD to itself",
1250                                    ifname);
1251                                return -1;
1252                        }
1253                        if (strlcpy(sla->ifname, p,
1254                            sizeof(sla->ifname)) >= sizeof(sla->ifname))
1255                        {
1256                                syslog(LOG_ERR, "%s: interface name too long",
1257                                    arg);
1258                                return -1;
1259                        }
1260                        p = np;
1261                        if (p) {
1262                                np = strchr(p, '/');
1263                                if (np)
1264                                        *np++ = '\0';
1265                                if (*p == '\0')
1266                                        sla->sla_set = 0;
1267                                else {
1268                                        errno = 0;
1269                                        sla->sla = atoint(p);
1270                                        sla->sla_set = 1;
1271                                        if (errno)
1272                                                return -1;
1273                                }
1274                                if (np) {
1275                                        sla->prefix_len = atoint(np);
1276                                        if (sla->prefix_len < 0 ||
1277                                            sla->prefix_len > 128)
1278                                                return -1;
1279                                } else
1280                                        sla->prefix_len = 64;
1281                        } else {
1282                                sla->sla_set = 0;
1283                                /* Sanity - check there are no more
1284                                 * unspecified SLA's */
1285                                for (sl = 0; sl < ia->sla_len - 1; sl++) {
1286                                        slap = &ia->sla[sl];
1287                                        if (slap->sla_set == 0 &&
1288                                            strcmp(slap->ifname, sla->ifname)
1289                                            == 0)
1290                                        {
1291                                                syslog(LOG_WARNING,
1292                                                    "%s: cannot specify the "
1293                                                    "same interface twice with "
1294                                                    "an automatic SLA",
1295                                                    sla->ifname);
1296                                                ia->sla_len--;
1297                                                break;
1298                                        }
1299                                }
1300                        }
1301                }
1302#endif
1303                break;
1304        case O_HOSTNAME_SHORT:
1305                ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
1306                break;
1307        case O_DEV:
1308                if (dev_load)
1309                        free(dev_load);
1310                dev_load = strdup(arg);
1311                break;
1312        case O_NODEV:
1313                ifo->options &= ~DHCPCD_DEV;
1314                break;
1315        case O_DEFINE:
1316                dop = &ifo->dhcp_override;
1317                dop_len = &ifo->dhcp_override_len;
1318                /* FALLTHROUGH */
1319        case O_DEFINE6:
1320                if (dop == NULL) {
1321                        dop = &ifo->dhcp6_override;
1322                        dop_len = &ifo->dhcp6_override_len;
1323                }
1324                /* FALLTHROUGH */
1325        case O_VENDOPT:
1326                if (dop == NULL) {
1327                        dop = &ifo->vivso_override;
1328                        dop_len = &ifo->vivso_override_len;
1329                }
1330                edop = ldop = NULL;
1331                /* FALLTHROUGH */
1332        case O_EMBED:
1333                if (dop == NULL) {
1334                        if (edop) {
1335                                dop = &edop->embopts;
1336                                dop_len = &edop->embopts_len;
1337                        } else if (ldop) {
1338                                dop = &ldop->embopts;
1339                                dop_len = &ldop->embopts_len;
1340                        } else {
1341                                syslog(LOG_ERR,
1342                                    "embed must be after a define or encap");
1343                                return -1;
1344                        }
1345                }
1346                /* FALLTHROUGH */
1347        case O_ENCAP:
1348                if (dop == NULL) {
1349                        if (ldop == NULL) {
1350                                syslog(LOG_ERR, "encap must be after a define");
1351                                return -1;
1352                        }
1353                        dop = &ldop->encopts;
1354                        dop_len = &ldop->encopts_len;
1355                }
1356
1357                /* Shared code for define, define6, embed and encap */
1358
1359                /* code */
1360                if (opt == O_EMBED) /* Embedded options don't have codes */
1361                        u = 0;
1362                else {
1363                        fp = strwhite(arg);
1364                        if (fp == NULL) {
1365                                syslog(LOG_ERR, "invalid syntax: %s", arg);
1366                                return -1;
1367                        }
1368                        *fp++ = '\0';
1369                        errno = 0;
1370                        u = strtoul(arg, &np, 0);
1371                        if (u > UINT32_MAX || errno != 0 || *np != '\0') {
1372                                syslog(LOG_ERR, "invalid code: %s", arg);
1373                                return -1;
1374                        }
1375                        arg = strskipwhite(fp);
1376                        if (arg == NULL) {
1377                                syslog(LOG_ERR, "invalid syntax");
1378                                return -1;
1379                        }
1380                }
1381                /* type */
1382                fp = strwhite(arg);
1383                if (fp)
1384                        *fp++ = '\0';
1385                np = strchr(arg, ':');
1386                /* length */
1387                if (np) {
1388                        *np++ = '\0';
1389                        if ((l = atoint(np)) == -1)
1390                                return -1;
1391                } else
1392                        l = 0;
1393                t = 0;
1394                if (strcasecmp(arg, "request") == 0) {
1395                        t |= REQUEST;
1396                        arg = strskipwhite(fp);
1397                        fp = strwhite(arg);
1398                        if (fp == NULL) {
1399                                syslog(LOG_ERR, "incomplete request type");
1400                                return -1;
1401                        }
1402                        *fp++ = '\0';
1403                } else if (strcasecmp(arg, "norequest") == 0) {
1404                        t |= NOREQ;
1405                        arg = strskipwhite(fp);
1406                        fp = strwhite(arg);
1407                        if (fp == NULL) {
1408                                syslog(LOG_ERR, "incomplete request type");
1409                                return -1;
1410                        }
1411                        *fp++ = '\0';
1412                }
1413                if (strcasecmp(arg, "index") == 0) {
1414                        t |= INDEX;
1415                        arg = strskipwhite(fp);
1416                        fp = strwhite(arg);
1417                        if (fp == NULL) {
1418                                syslog(LOG_ERR, "incomplete index type");
1419                                return -1;
1420                        }
1421                        *fp++ = '\0';
1422                }
1423                if (strcasecmp(arg, "array") == 0) {
1424                        t |= ARRAY;
1425                        arg = strskipwhite(fp);
1426                        fp = strwhite(arg);
1427                        if (fp == NULL) {
1428                                syslog(LOG_ERR, "incomplete array type");
1429                                return -1;
1430                        }
1431                        *fp++ = '\0';
1432                }
1433                if (strcasecmp(arg, "ipaddress") == 0)
1434                        t |= ADDRIPV4;
1435                else if (strcasecmp(arg, "ip6address") == 0)
1436                        t |= ADDRIPV6;
1437                else if (strcasecmp(arg, "string") == 0)
1438                        t |= STRING;
1439                else if (strcasecmp(arg, "byte") == 0)
1440                        t |= UINT8;
1441                else if (strcasecmp(arg, "uint16") == 0)
1442                        t |= UINT16;
1443                else if (strcasecmp(arg, "int16") == 0)
1444                        t |= SINT16;
1445                else if (strcasecmp(arg, "uint32") == 0)
1446                        t |= UINT32;
1447                else if (strcasecmp(arg, "int32") == 0)
1448                        t |= SINT32;
1449                else if (strcasecmp(arg, "flag") == 0)
1450                        t |= FLAG;
1451                else if (strcasecmp(arg, "domain") == 0)
1452                        t |= STRING | RFC3397;
1453                else if (strcasecmp(arg, "binhex") == 0)
1454                        t |= BINHEX;
1455                else if (strcasecmp(arg, "embed") == 0)
1456                        t |= EMBED;
1457                else if (strcasecmp(arg, "encap") == 0)
1458                        t |= ENCAP;
1459                else if (strcasecmp(arg, "rfc3361") ==0)
1460                        t |= STRING | RFC3361;
1461                else if (strcasecmp(arg, "rfc3442") ==0)
1462                        t |= STRING | RFC3442;
1463                else if (strcasecmp(arg, "rfc5969") == 0)
1464                        t |= STRING | RFC5969;
1465                else if (strcasecmp(arg, "option") == 0)
1466                        t |= OPTION;
1467                else {
1468                        syslog(LOG_ERR, "unknown type: %s", arg);
1469                        return -1;
1470                }
1471                if (l && !(t & (STRING | BINHEX))) {
1472                        syslog(LOG_WARNING,
1473                            "ignoring length for type `%s'", arg);
1474                        l = 0;
1475                }
1476                if (t & ARRAY && t & (STRING | BINHEX)) {
1477                        syslog(LOG_WARNING, "ignoring array for strings");
1478                        t &= ~ARRAY;
1479                }
1480                /* variable */
1481                if (!fp) {
1482                        if (!(t & OPTION)) {
1483                                syslog(LOG_ERR,
1484                                    "type %s requires a variable name", arg);
1485                                return -1;
1486                        }
1487                        np = NULL;
1488                } else {
1489                        arg = strskipwhite(fp);
1490                        fp = strwhite(arg);
1491                        if (fp)
1492                                *fp++ = '\0';
1493                        np = strdup(arg);
1494                        if (np == NULL) {
1495                                syslog(LOG_ERR, "%s: %m", __func__);
1496                                return -1;
1497                        }
1498                }
1499                if (opt != O_EMBED) {
1500                        for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
1501                        {
1502                                /* type 0 seems freshly malloced struct
1503                                 * for us to use */
1504                                if (ndop->option == u || ndop->type == 0)
1505                                        break;
1506                        }
1507                        if (dl == *dop_len)
1508                                ndop = NULL;
1509                } else
1510                        ndop = NULL;
1511                if (ndop == NULL) {
1512                        if ((ndop = realloc(*dop,
1513                            sizeof(**dop) * ((*dop_len) + 1))) == NULL)
1514                        {
1515                                syslog(LOG_ERR, "%s: %m", __func__);
1516                                return -1;
1517                        }
1518                        *dop = ndop;
1519                        ndop = &(*dop)[(*dop_len)++];
1520                        ndop->embopts = NULL;
1521                        ndop->embopts_len = 0;
1522                        ndop->encopts = NULL;
1523                        ndop->encopts_len = 0;
1524                } else
1525                        free_dhcp_opt_embenc(ndop);
1526                ndop->option = u; /* could have been 0 */
1527                ndop->type = t;
1528                ndop->len = l;
1529                ndop->var = np;
1530                /* Save the define for embed and encap options */
1531                if (opt == O_DEFINE || opt == O_DEFINE6 || opt == O_VENDOPT)
1532                        ldop = ndop;
1533                else if (opt == O_ENCAP)
1534                        edop = ndop;
1535                break;
1536        case O_VENDCLASS:
1537                fp = strwhite(arg);
1538                if (fp)
1539                        *fp++ = '\0';
1540                errno = 0;
1541                u = strtoul(arg, &np, 0);
1542                if (u > UINT32_MAX || errno != 0 || *np != '\0') {
1543                        syslog(LOG_ERR, "invalid code: %s", arg);
1544                        return -1;
1545                }
1546                if (fp) {
1547                        s = parse_string(NULL, 0, fp);
1548                        if (s == -1) {
1549                                syslog(LOG_ERR, "%s: %m", __func__);
1550                                return -1;
1551                        }
1552                        if (s + (sizeof(uint16_t) * 2) > UINT16_MAX) {
1553                                syslog(LOG_ERR, "vendor class is too big");
1554                                return -1;
1555                        }
1556                        np = malloc(s);
1557                        if (np == NULL) {
1558                                syslog(LOG_ERR, "%s: %m", __func__);
1559                                return -1;
1560                        }
1561                        parse_string(np, s, fp);
1562                } else {
1563                        s = 0;
1564                        np = NULL;
1565                }
1566                vivco = realloc(ifo->vivco, sizeof(*ifo->vivco) *
1567                    (ifo->vivco_len + 1));
1568                if (vivco == NULL) {
1569                        syslog(LOG_ERR, "%s: %m", __func__);
1570                        return -1;
1571                }
1572                ifo->vivco = vivco;
1573                ifo->vivco_en = u;
1574                vivco = &ifo->vivco[ifo->vivco_len++];
1575                vivco->len = s;
1576                vivco->data = (uint8_t *)np;
1577                break;
1578        case O_AUTHPROTOCOL:
1579                fp = strwhite(arg);
1580                if (fp)
1581                        *fp++ = '\0';
1582                if (strcasecmp(arg, "token") == 0)
1583                        ifo->auth.protocol = AUTH_PROTO_TOKEN;
1584                else if (strcasecmp(arg, "delayed") == 0)
1585                        ifo->auth.protocol = AUTH_PROTO_DELAYED;
1586                else if (strcasecmp(arg, "delayedrealm") == 0)
1587                        ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
1588                else {
1589                        syslog(LOG_ERR, "%s: unsupported protocol", arg);
1590                        return -1;
1591                }
1592                arg = strskipwhite(fp);
1593                fp = strwhite(arg);
1594                if (arg == NULL) {
1595                        ifo->auth.options |= DHCPCD_AUTH_SEND;
1596                        ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
1597                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1598                        break;
1599                }
1600                if (fp)
1601                        *fp++ = '\0';
1602                if (strcasecmp(arg, "hmacmd5") == 0 ||
1603                    strcasecmp(arg, "hmac-md5") == 0)
1604                        ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
1605                else {
1606                        syslog(LOG_ERR, "%s: unsupported algorithm", arg);
1607                        return 1;
1608                }
1609                arg = fp;
1610                if (arg == NULL) {
1611                        ifo->auth.options |= DHCPCD_AUTH_SEND;
1612                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1613                        break;
1614                }
1615                if (strcasecmp(arg, "monotonic") == 0)
1616                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1617                else {
1618                        syslog(LOG_ERR, "%s: unsupported RDM", arg);
1619                        return -1;
1620                }
1621                break;
1622        case O_AUTHTOKEN:
1623                fp = strwhite(arg);
1624                if (fp == NULL) {
1625                        syslog(LOG_ERR, "authtoken requires a realm");
1626                        return -1;
1627                }
1628                *fp++ = '\0';
1629                token = malloc(sizeof(*token));
1630                if (token == NULL) {
1631                        syslog(LOG_ERR, "%s: %m", __func__);
1632                        return -1;
1633                }
1634                if (parse_uint32(&token->secretid, arg) == -1) {
1635                        syslog(LOG_ERR, "%s: not a number", arg);
1636                        free(token);
1637                        return -1;
1638                }
1639                arg = fp;
1640                fp = strend(arg);
1641                if (fp == NULL) {
1642                        syslog(LOG_ERR, "authtoken requies an a key");
1643                        free(token);
1644                        return -1;
1645                }
1646                *fp++ = '\0';
1647                token->realm_len = parse_string(NULL, 0, arg);
1648                if (token->realm_len) {
1649                        token->realm = malloc(token->realm_len);
1650                        if (token->realm == NULL) {
1651                                free(token);
1652                                syslog(LOG_ERR, "%s: %m", __func__);
1653                                return -1;
1654                        }
1655                        parse_string((char *)token->realm, token->realm_len,
1656                            arg);
1657                }
1658                arg = fp;
1659                fp = strend(arg);
1660                if (fp == NULL) {
1661                        syslog(LOG_ERR, "authtoken requies an an expiry date");
1662                        free(token->realm);
1663                        free(token);
1664                        return -1;
1665                }
1666                *fp++ = '\0';
1667                if (*arg == '"') {
1668                        arg++;
1669                        np = strchr(arg, '"');
1670                        if (np)
1671                                *np = '\0';
1672                }
1673                if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
1674                        token->expire =0;
1675                else {
1676                        struct tm tm;
1677
1678                        memset(&tm, 0, sizeof(tm));
1679                        if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
1680                                syslog(LOG_ERR, "%s: invalid date time", arg);
1681                                free(token->realm);
1682                                free(token);
1683                                return -1;
1684                        }
1685                        if ((token->expire = mktime(&tm)) == (time_t)-1) {
1686                                syslog(LOG_ERR, "%s: mktime: %m", __func__);
1687                                free(token->realm);
1688                                free(token);
1689                                return -1;
1690                        }
1691                }
1692                arg = fp;
1693                token->key_len = parse_string(NULL, 0, arg);
1694                if (token->key_len == 0) {
1695                        syslog(LOG_ERR, "authtoken needs a key");
1696                        free(token->realm);
1697                        free(token);
1698                        return -1;
1699                }
1700                token->key = malloc(token->key_len);
1701                parse_string((char *)token->key, token->key_len, arg);
1702                TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
1703                break;
1704        case O_AUTHNOTREQUIRED:
1705                ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
1706                break;
1707        case O_NODHCP:
1708                ifo->options &= ~DHCPCD_DHCP;
1709                break;
1710        case O_NODHCP6:
1711                ifo->options &= ~DHCPCD_DHCP6;
1712                break;
1713        default:
1714                return 0;
1715        }
1716
1717        return 1;
1718}
1719
1720static int
1721parse_config_line(const char *ifname, struct if_options *ifo,
1722    const char *opt, char *line)
1723{
1724        unsigned int i;
1725
1726        for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
1727                if (!cf_options[i].name ||
1728                    strcmp(cf_options[i].name, opt) != 0)
1729                        continue;
1730
1731                if (cf_options[i].has_arg == required_argument && !line) {
1732                        fprintf(stderr,
1733                            PACKAGE ": option requires an argument -- %s\n",
1734                            opt);
1735                        return -1;
1736                }
1737
1738                return parse_option(ifname, ifo, cf_options[i].val, line);
1739        }
1740
1741        fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
1742        return -1;
1743}
1744
1745static void
1746finish_config(struct if_options *ifo)
1747{
1748
1749        /* Terminate the encapsulated options */
1750        if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
1751                ifo->vendor[0]++;
1752                ifo->vendor[ifo->vendor[0]] = DHO_END;
1753                /* We are called twice.
1754                 * This should be fixed, but in the meantime, this
1755                 * guard should suffice */
1756                ifo->options |= DHCPCD_VENDORRAW;
1757        }
1758}
1759
1760struct if_options *
1761read_config(const char *file,
1762    const char *ifname, const char *ssid, const char *profile)
1763{
1764        struct if_options *ifo;
1765        FILE *f;
1766        char *line, *option, *p;
1767        int skip = 0, have_profile = 0;
1768#ifndef EMBEDDED_CONFIG
1769        char *buf;
1770        const char * const *e;
1771        size_t buflen, ol;
1772#endif
1773#if !defined(INET) || !defined(INET6)
1774        size_t i;
1775        struct dhcp_opt *opt;
1776#endif
1777
1778        /* Seed our default options */
1779        ifo = calloc(1, sizeof(*ifo));
1780        if (ifo == NULL) {
1781                syslog(LOG_ERR, "%s: %m", __func__);
1782                return NULL;
1783        }
1784        ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK;
1785#ifdef PLUGIN_DEV
1786        ifo->options |= DHCPCD_DEV;
1787#endif
1788#ifdef INET
1789        ifo->options |= DHCPCD_IPV4 | DHCPCD_DHCP | DHCPCD_IPV4LL;
1790        ifo->options |= DHCPCD_GATEWAY | DHCPCD_ARP;
1791#endif
1792#ifdef INET6
1793        ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | DHCPCD_IPV6RA_REQRDNSS;
1794        ifo->options |= DHCPCD_DHCP6;
1795        ifo->dadtransmits = ipv6_dadtransmits(ifname);
1796#endif
1797        ifo->timeout = DEFAULT_TIMEOUT;
1798        ifo->reboot = DEFAULT_REBOOT;
1799        ifo->metric = -1;
1800        ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
1801        TAILQ_INIT(&ifo->auth.tokens);
1802        strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
1803
1804        ifo->vendorclassid[0] = strlen(vendor);
1805        memcpy(ifo->vendorclassid + 1, vendor, ifo->vendorclassid[0]);
1806
1807        /* Parse our embedded options file */
1808        if (ifname == NULL) {
1809                /* Space for initial estimates */
1810#if defined(INET) && defined(INITDEFINES)
1811                ifo->dhcp_override =
1812                    calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
1813                if (ifo->dhcp_override == NULL)
1814                        syslog(LOG_ERR, "%s: %m", __func__);
1815                else
1816                        ifo->dhcp_override_len = INITDEFINES;
1817#endif
1818
1819#if defined(INET6) && defined(INITDEFINE6S)
1820                ifo->dhcp6_override =
1821                    calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
1822                if (ifo->dhcp6_override == NULL)
1823                        syslog(LOG_ERR, "%s: %m", __func__);
1824                else
1825                        ifo->dhcp6_override_len = INITDEFINE6S;
1826#endif
1827
1828                /* Now load our embedded config */
1829#ifdef EMBEDDED_CONFIG
1830                f = fopen(EMBEDDED_CONFIG, "r");
1831                if (f == NULL)
1832                        syslog(LOG_ERR, "fopen `%s': %m", EMBEDDED_CONFIG);
1833
1834                while (f && (line = get_line(f))) {
1835#else
1836                buflen = 80;
1837                buf = malloc(buflen);
1838                if (buf == NULL) {
1839                        syslog(LOG_ERR, "%s: %m", __func__);
1840                        return NULL;
1841                }
1842                for (e = dhcpcd_embedded_conf; *e; e++) {
1843                        ol = strlen(*e) + 1;
1844                        if (ol > buflen) {
1845                                free(buf);
1846                                buflen = ol;
1847                                buf = malloc(buflen);
1848                                if (buf == NULL) {
1849                                        syslog(LOG_ERR, "%s: %m", __func__);
1850                                        return NULL;
1851                                }
1852                        }
1853                        memcpy(buf, *e, ol);
1854                        line = buf;
1855#endif
1856                        option = strsep(&line, " \t");
1857                        if (line)
1858                                line = strskipwhite(line);
1859                        /* Trim trailing whitespace */
1860                        if (line && *line) {
1861                                p = line + strlen(line) - 1;
1862                                while (p != line &&
1863                                    (*p == ' ' || *p == '\t') &&
1864                                    *(p - 1) != '\\')
1865                                        *p-- = '\0';
1866                        }
1867                        parse_config_line(NULL, ifo, option, line);
1868
1869                }
1870
1871#ifdef EMBEDDED_CONFIG
1872                if (f)
1873                        fclose(f);
1874#else
1875                free(buf);
1876#endif
1877#ifdef INET
1878                dhcp_opts = ifo->dhcp_override;
1879                dhcp_opts_len = ifo->dhcp_override_len;
1880#else
1881                for (i = 0, opt = ifo->dhcp_override;
1882                    i < ifo->dhcp_override_len;
1883                    i++, opt++)
1884                        free_dhcp_opt_embenc(opt);
1885                free(ifo->dhcp_override);
1886#endif
1887                ifo->dhcp_override = NULL;
1888                ifo->dhcp_override_len = 0;
1889
1890#ifdef INET6
1891                dhcp6_opts = ifo->dhcp6_override;
1892                dhcp6_opts_len = ifo->dhcp6_override_len;
1893#else
1894                for (i = 0, opt = ifo->dhcp6_override;
1895                    i < ifo->dhcp6_override_len;
1896                    i++, opt++)
1897                        free_dhcp_opt_embenc(opt);
1898                free(ifo->dhcp6_override);
1899#endif
1900                ifo->dhcp6_override = NULL;
1901                ifo->dhcp6_override_len = 0;
1902
1903                vivso = ifo->vivso_override;
1904                vivso_len = ifo->vivso_override_len;
1905                ifo->vivso_override = NULL;
1906                ifo->vivso_override_len = 0;
1907        }
1908
1909        /* Parse our options file */
1910        f = fopen(file ? file : CONFIG, "r");
1911        if (f == NULL) {
1912                if (file != NULL)
1913                        syslog(LOG_ERR, "fopen `%s': %m", file);
1914                return ifo;
1915        }
1916
1917        while ((line = get_line(f))) {
1918                option = strsep(&line, " \t");
1919                if (line)
1920                        line = strskipwhite(line);
1921                /* Trim trailing whitespace */
1922                if (line && *line) {
1923                        p = line + strlen(line) - 1;
1924                        while (p != line &&
1925                            (*p == ' ' || *p == '\t') &&
1926                            *(p - 1) != '\\')
1927                                *p-- = '\0';
1928                }
1929                /* Start of an interface block, skip if not ours */
1930                if (strcmp(option, "interface") == 0) {
1931                        if (ifname && line && strcmp(line, ifname) == 0)
1932                                skip = 0;
1933                        else
1934                                skip = 1;
1935                        continue;
1936                }
1937                /* Start of an ssid block, skip if not ours */
1938                if (strcmp(option, "ssid") == 0) {
1939                        if (ssid && line && strcmp(line, ssid) == 0)
1940                                skip = 0;
1941                        else
1942                                skip = 1;
1943                        continue;
1944                }
1945                /* Start of a profile block, skip if not ours */
1946                if (strcmp(option, "profile") == 0) {
1947                        if (profile && line && strcmp(line, profile) == 0) {
1948                                skip = 0;
1949                                have_profile = 1;
1950                        } else
1951                                skip = 1;
1952                        continue;
1953                }
1954                if (skip)
1955                        continue;
1956                parse_config_line(ifname, ifo, option, line);
1957        }
1958        fclose(f);
1959
1960        if (profile && !have_profile) {
1961                free_options(ifo);
1962                errno = ENOENT;
1963                ifo = NULL;
1964        }
1965
1966        finish_config(ifo);
1967        return ifo;
1968}
1969
1970int
1971add_options(const char *ifname, struct if_options *ifo, int argc, char **argv)
1972{
1973        int oi, opt, r;
1974
1975        if (argc == 0)
1976                return 1;
1977
1978        optind = 0;
1979        r = 1;
1980        while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
1981        {
1982                r = parse_option(ifname, ifo, opt, optarg);
1983                if (r != 1)
1984                        break;
1985        }
1986
1987        finish_config(ifo);
1988        return r;
1989}
1990
1991void
1992free_options(struct if_options *ifo)
1993{
1994        size_t i;
1995        struct dhcp_opt *opt;
1996        struct vivco *vo;
1997        struct token *token;
1998
1999        if (ifo) {
2000                if (ifo->environ) {
2001                        i = 0;
2002                        while (ifo->environ[i])
2003                                free(ifo->environ[i++]);
2004                        free(ifo->environ);
2005                }
2006                if (ifo->config) {
2007                        i = 0;
2008                        while (ifo->config[i])
2009                                free(ifo->config[i++]);
2010                        free(ifo->config);
2011                }
2012                ipv4_freeroutes(ifo->routes);
2013                free(ifo->arping);
2014                free(ifo->blacklist);
2015                free(ifo->fallback);
2016
2017                for (i = 0, opt = ifo->dhcp_override;
2018                    i < ifo->dhcp_override_len;
2019                    i++, opt++)
2020                        free_dhcp_opt_embenc(opt);
2021                free(ifo->dhcp_override);
2022                for (i = 0, opt = ifo->dhcp6_override;
2023                    i < ifo->dhcp6_override_len;
2024                    i++, opt++)
2025                        free_dhcp_opt_embenc(opt);
2026                free(ifo->dhcp6_override);
2027                for (i = 0, vo = ifo->vivco;
2028                    i < ifo->vivco_len;
2029                    i++, vo++)
2030                        free(vo->data);
2031                free(ifo->vivco);
2032                for (i = 0, opt = ifo->vivso_override;
2033                    i < ifo->vivso_override_len;
2034                    i++, opt++)
2035                        free_dhcp_opt_embenc(opt);
2036                free(ifo->vivso_override);
2037
2038#ifdef INET6
2039                for (i = 0; i < ifo->ia_len; i++)
2040                        free(ifo->ia[i].sla);
2041#endif
2042                free(ifo->ia);
2043
2044                while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
2045                        TAILQ_REMOVE(&ifo->auth.tokens, token, next);
2046                        if (token->realm_len)
2047                                free(token->realm);
2048                        free(token->key);
2049                        free(token);
2050                }
2051                free(ifo);
2052        }
2053}
Note: See TracBrowser for help on using the repository browser.