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