]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - if-options.c
Add the persistent option to the default dhcpcd.conf
[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"
fd05b7dc 49#include "if-options.h"
e88c525f 50#include "ipv4.h"
793c4286 51#include "platform.h"
fd05b7dc 52
eebe9a18
RM
53unsigned long long options = 0;
54
4ca7460f
RM
55/* These options only make sense in the config file, so don't use any
56 valid short options for them */
eebe9a18
RM
57#define O_BASE MAX('z', 'Z') + 1
58#define O_ARPING O_BASE + 1
59#define O_FALLBACK O_BASE + 2
60#define O_DESTINATION O_BASE + 3
61#define O_IPV6RS O_BASE + 4
00ababe4
RM
62#define O_NOIPV6RS O_BASE + 5
63#define O_IPV6RA_FORK O_BASE + 6
eebe9a18
RM
64#define O_IPV6RA_OWN O_BASE + 7
65#define O_IPV6RA_OWN_D O_BASE + 8
7dab081f 66#define O_NOALIAS O_BASE + 9
00ababe4
RM
67#define O_IA_NA O_BASE + 10
68#define O_IA_TA O_BASE + 11
69#define O_IA_PD O_BASE + 12
d6a18654 70#define O_HOSTNAME_SHORT O_BASE + 13
4ca7460f 71
fd05b7dc 72const struct option cf_options[] = {
ba97e494
RM
73 {"background", no_argument, NULL, 'b'},
74 {"script", required_argument, NULL, 'c'},
75 {"debug", no_argument, NULL, 'd'},
6bfd88f1 76 {"env", required_argument, NULL, 'e'},
ba97e494 77 {"config", required_argument, NULL, 'f'},
6bfd88f1 78 {"reconfigure", no_argument, NULL, 'g'},
ba97e494
RM
79 {"hostname", optional_argument, NULL, 'h'},
80 {"vendorclassid", optional_argument, NULL, 'i'},
81 {"release", no_argument, NULL, 'k'},
82 {"leasetime", required_argument, NULL, 'l'},
83 {"metric", required_argument, NULL, 'm'},
84 {"rebind", no_argument, NULL, 'n'},
85 {"option", required_argument, NULL, 'o'},
86 {"persistent", no_argument, NULL, 'p'},
87 {"quiet", no_argument, NULL, 'q'},
88 {"request", optional_argument, NULL, 'r'},
89 {"inform", optional_argument, NULL, 's'},
90 {"timeout", required_argument, NULL, 't'},
91 {"userclass", required_argument, NULL, 'u'},
92 {"vendor", required_argument, NULL, 'v'},
2a07a2af 93 {"waitip", no_argument, NULL, 'w'},
ba97e494 94 {"exit", no_argument, NULL, 'x'},
d3088c74 95 {"allowinterfaces", required_argument, NULL, 'z'},
a2a9a498 96 {"reboot", required_argument, NULL, 'y'},
ba97e494
RM
97 {"noarp", no_argument, NULL, 'A'},
98 {"nobackground", no_argument, NULL, 'B'},
99 {"nohook", required_argument, NULL, 'C'},
100 {"duid", no_argument, NULL, 'D'},
101 {"lastlease", no_argument, NULL, 'E'},
102 {"fqdn", optional_argument, NULL, 'F'},
103 {"nogateway", no_argument, NULL, 'G'},
00ababe4 104 {"xidhwaddr", no_argument, NULL, 'H'},
ba97e494 105 {"clientid", optional_argument, NULL, 'I'},
900b3da4 106 {"broadcast", no_argument, NULL, 'J'},
ba97e494
RM
107 {"nolink", no_argument, NULL, 'K'},
108 {"noipv4ll", no_argument, NULL, 'L'},
109 {"nooption", optional_argument, NULL, 'O'},
110 {"require", required_argument, NULL, 'Q'},
91a44b91 111 {"static", required_argument, NULL, 'S'},
ba97e494 112 {"test", no_argument, NULL, 'T'},
dc60cba4 113 {"dumplease", no_argument, NULL, 'U'},
ba97e494 114 {"variables", no_argument, NULL, 'V'},
bf80d526 115 {"whitelist", required_argument, NULL, 'W'},
ba97e494 116 {"blacklist", required_argument, NULL, 'X'},
d3088c74 117 {"denyinterfaces", required_argument, NULL, 'Z'},
4ca7460f 118 {"arping", required_argument, NULL, O_ARPING},
41c60e02 119 {"destination", required_argument, NULL, O_DESTINATION},
ff021b0b 120 {"fallback", required_argument, NULL, O_FALLBACK},
eebe9a18 121 {"ipv6rs", no_argument, NULL, O_IPV6RS},
91cd7324 122 {"noipv6rs", no_argument, NULL, O_NOIPV6RS},
eebe9a18
RM
123 {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK},
124 {"ipv6ra_own", no_argument, NULL, O_IPV6RA_OWN},
125 {"ipv6ra_own_default", no_argument, NULL, O_IPV6RA_OWN_D},
d7555c12
RM
126 {"ipv4only", no_argument, NULL, '4'},
127 {"ipv6only", no_argument, NULL, '6'},
7dab081f 128 {"noalias", no_argument, NULL, O_NOALIAS},
00ababe4
RM
129 {"ia_na", no_argument, NULL, O_IA_NA},
130 {"ia_ta", no_argument, NULL, O_IA_TA},
131 {"ia_pd", no_argument, NULL, O_IA_PD},
d6a18654 132 {"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT},
ba97e494 133 {NULL, 0, NULL, '\0'}
fd05b7dc
RM
134};
135
136static int
137atoint(const char *s)
138{
139 char *t;
140 long n;
141
142 errno = 0;
143 n = strtol(s, &t, 0);
144 if ((errno != 0 && n == 0) || s == t ||
145 (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
146 {
367f7b11
RM
147 if (errno == 0)
148 errno = EINVAL;
765fbf7d 149 syslog(LOG_ERR, "`%s' out of range", s);
fd05b7dc
RM
150 return -1;
151 }
152
153 return (int)n;
154}
155
00ababe4 156static char *
fd05b7dc
RM
157add_environ(struct if_options *ifo, const char *value, int uniq)
158{
159 char **newlist;
160 char **lst = ifo->environ;
161 size_t i = 0, l, lv;
fa245a4d 162 char *match = NULL, *p, *n;
fd05b7dc 163
78369646
RM
164 match = strdup(value);
165 if (match == NULL) {
166 syslog(LOG_ERR, "%s: %m", __func__);
167 return NULL;
168 }
fd05b7dc
RM
169 p = strchr(match, '=');
170 if (p)
171 *p++ = '\0';
172 l = strlen(match);
173
174 while (lst && lst[i]) {
175 if (match && strncmp(lst[i], match, l) == 0) {
176 if (uniq) {
78369646
RM
177 n = strdup(value);
178 if (n == NULL) {
179 syslog(LOG_ERR, "%s: %m", __func__);
180 return NULL;
181 }
fd05b7dc 182 free(lst[i]);
78369646 183 lst[i] = n;
fd05b7dc
RM
184 } else {
185 /* Append a space and the value to it */
186 l = strlen(lst[i]);
187 lv = strlen(p);
fa245a4d
RM
188 n = realloc(lst[i], l + lv + 2);
189 if (n == NULL) {
190 syslog(LOG_ERR, "%s: %m", __func__);
191 return NULL;
192 }
193 lst[i] = n;
fd05b7dc
RM
194 lst[i][l] = ' ';
195 memcpy(lst[i] + l + 1, p, lv);
196 lst[i][l + lv + 1] = '\0';
197 }
198 free(match);
199 return lst[i];
200 }
201 i++;
202 }
203
78369646
RM
204 n = strdup(value);
205 if (n == NULL) {
206 syslog(LOG_ERR, "%s: %m", __func__);
207 return NULL;
208 }
fa245a4d
RM
209 newlist = realloc(lst, sizeof(char *) * (i + 2));
210 if (newlist == NULL) {
211 syslog(LOG_ERR, "%s: %m", __func__);
212 return NULL;
213 }
78369646 214 newlist[i] = n;
fd05b7dc
RM
215 newlist[i + 1] = NULL;
216 ifo->environ = newlist;
217 free(match);
218 return newlist[i];
219}
220
221#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
222static ssize_t
223parse_string_hwaddr(char *sbuf, ssize_t slen, const char *str, int clid)
224{
225 ssize_t l;
226 const char *p;
227 int i, punt_last = 0;
228 char c[4];
229
230 /* If surrounded by quotes then it's a string */
231 if (*str == '"') {
232 str++;
233 l = strlen(str);
234 p = str + l - 1;
235 if (*p == '"')
236 punt_last = 1;
237 } else {
238 l = hwaddr_aton(NULL, str);
239 if (l > 1) {
240 if (l > slen) {
241 errno = ENOBUFS;
242 return -1;
243 }
244 hwaddr_aton((uint8_t *)sbuf, str);
245 return l;
246 }
247 }
248
249 /* Process escapes */
250 l = 0;
251 /* If processing a string on the clientid, first byte should be
252 * 0 to indicate a non hardware type */
9c9ad2f1 253 if (clid && *str) {
fd05b7dc
RM
254 *sbuf++ = 0;
255 l++;
256 }
257 c[3] = '\0';
258 while (*str) {
259 if (++l > slen) {
260 errno = ENOBUFS;
261 return -1;
262 }
263 if (*str == '\\') {
264 str++;
857576b4 265 switch(*str) {
fd05b7dc
RM
266 case '\0':
267 break;
268 case 'b':
269 *sbuf++ = '\b';
857576b4 270 str++;
fd05b7dc
RM
271 break;
272 case 'n':
273 *sbuf++ = '\n';
857576b4 274 str++;
fd05b7dc
RM
275 break;
276 case 'r':
277 *sbuf++ = '\r';
857576b4 278 str++;
fd05b7dc
RM
279 break;
280 case 't':
281 *sbuf++ = '\t';
857576b4 282 str++;
fd05b7dc
RM
283 break;
284 case 'x':
285 /* Grab a hex code */
286 c[1] = '\0';
287 for (i = 0; i < 2; i++) {
288 if (isxdigit((unsigned char)*str) == 0)
289 break;
290 c[i] = *str++;
291 }
292 if (c[1] != '\0') {
293 c[2] = '\0';
294 *sbuf++ = strtol(c, NULL, 16);
295 } else
296 l--;
297 break;
298 case '0':
299 /* Grab an octal code */
300 c[2] = '\0';
301 for (i = 0; i < 3; i++) {
302 if (*str < '0' || *str > '7')
303 break;
304 c[i] = *str++;
305 }
306 if (c[2] != '\0') {
307 i = strtol(c, NULL, 8);
308 if (i > 255)
309 i = 255;
310 *sbuf ++= i;
311 } else
312 l--;
313 break;
314 default:
315 *sbuf++ = *str++;
316 }
317 } else
318 *sbuf++ = *str++;
319 }
c35f63c8 320 if (punt_last) {
fd05b7dc 321 *--sbuf = '\0';
c35f63c8
RM
322 l--;
323 }
fd05b7dc
RM
324 return l;
325}
326
ba97e494
RM
327static char **
328splitv(int *argc, char **argv, const char *arg)
329{
fa245a4d 330 char **n, **v = argv;
78369646 331 char *o = strdup(arg), *p, *t, *nt;
ba97e494 332
78369646
RM
333 if (o == NULL) {
334 syslog(LOG_ERR, "%s: %m", __func__);
335 return v;
336 }
ba97e494
RM
337 p = o;
338 while ((t = strsep(&p, ", "))) {
fa245a4d
RM
339 nt = strdup(t);
340 if (nt == NULL) {
341 syslog(LOG_ERR, "%s: %m", __func__);
342 return NULL;
343 }
ba97e494 344 (*argc)++;
fa245a4d
RM
345 n = realloc(v, sizeof(char *) * ((*argc)));
346 if (n == NULL) {
347 syslog(LOG_ERR, "%s: %m", __func__);
348 return NULL;
349 }
350 v = n;
351 v[(*argc) - 1] = nt;
ba97e494
RM
352 }
353 free(o);
00ababe4 354 return v;
ba97e494
RM
355}
356
1f4c1525 357#ifdef INET
91a44b91
RM
358static int
359parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
360{
361 char *p;
362 int i;
363
2f7cb97c
RM
364 if (arg == NULL || *arg == '\0') {
365 if (addr != NULL)
366 addr->s_addr = 0;
367 if (net != NULL)
368 net->s_addr = 0;
91a44b91 369 return 0;
2f7cb97c 370 }
91a44b91
RM
371 if ((p = strchr(arg, '/')) != NULL) {
372 *p++ = '\0';
373 if (net != NULL &&
374 (sscanf(p, "%d", &i) != 1 ||
eab2229c 375 inet_cidrtoaddr(i, net) != 0))
91a44b91
RM
376 {
377 syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
378 return -1;
379 }
00ababe4 380 }
2f7cb97c 381
91a44b91
RM
382 if (addr != NULL && inet_aton(arg, addr) == 0) {
383 syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
384 return -1;
385 }
2f7cb97c 386 if (p != NULL)
e095a6eb 387 *--p = '/';
2f7cb97c 388 else if (net != NULL)
e88c525f 389 net->s_addr = ipv4_getnetmask(addr->s_addr);
91a44b91 390 return 0;
1f4c1525 391}
aae24feb 392#else
1f4c1525
RM
393static int
394parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
395 __unused const char *arg)
396{
397
aae24feb
RM
398 syslog(LOG_ERR, "No IPv4 support");
399 return -1;
91a44b91 400}
1f4c1525 401#endif
91a44b91 402
00ababe4 403static const char *
d7555c12
RM
404set_option_space(const char *arg, const struct dhcp_opt **d,
405 struct if_options *ifo,
406 uint8_t *request[], uint8_t *require[], uint8_t *no[])
407{
408
aae24feb 409#ifdef INET6
d7555c12
RM
410 if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
411 *d = dhcp6_opts;
412 *request = ifo->requestmask6;
413 *require = ifo->requiremask6;
414 *no = ifo->nomask6;
415 return arg + strlen("dhcp6_");
416 }
aae24feb
RM
417#endif
418
419#ifdef INET
d7555c12 420 *d = dhcp_opts;
aae24feb
RM
421#else
422 *d = NULL;
423#endif
d7555c12
RM
424 *request = ifo->requestmask;
425 *require = ifo->requiremask;
426 *no = ifo->nomask;
427 return arg;
428}
429
fd05b7dc
RM
430static int
431parse_option(struct if_options *ifo, int opt, const char *arg)
432{
433 int i;
fa245a4d 434 char *p = NULL, *fp, *np, **nconf;
fd05b7dc 435 ssize_t s;
e095a6eb 436 struct in_addr addr, addr2;
fa245a4d 437 in_addr_t *naddr;
91a44b91 438 struct rt *rt;
a2258eb3 439 const struct dhcp_opt *d;
d7555c12 440 uint8_t *request, *require, *no;
1f4c1525
RM
441#ifdef INET6
442 long l;
367f7b11 443 uint32_t u32;
1f4c1525 444 size_t sl;
00ababe4
RM
445 struct if_iaid *iaid;
446 uint8_t _iaid[4];
5985c4e2 447 struct if_sla *sla, *slap;
1f4c1525 448#endif
fd05b7dc 449
00ababe4 450 i = 0;
fd05b7dc 451 switch(opt) {
5e2062a4 452 case 'f': /* FALLTHROUGH */
6bfd88f1 453 case 'g': /* FALLTHROUGH */
da166178
RM
454 case 'n': /* FALLTHROUGH */
455 case 'x': /* FALLTHROUGH */
dc60cba4
RM
456 case 'T': /* FALLTHROUGH */
457 case 'U': /* We need to handle non interface options */
fd05b7dc 458 break;
03c2c879
RM
459 case 'b':
460 ifo->options |= DHCPCD_BACKGROUND;
461 break;
fd05b7dc
RM
462 case 'c':
463 strlcpy(ifo->script, arg, sizeof(ifo->script));
464 break;
acb1cf88
RM
465 case 'd':
466 ifo->options |= DHCPCD_DEBUG;
467 break;
6bfd88f1
RM
468 case 'e':
469 add_environ(ifo, arg, 1);
470 break;
fd05b7dc 471 case 'h':
cc3c3560
RM
472 if (!arg) {
473 ifo->options |= DHCPCD_HOSTNAME;
474 break;
475 }
476 s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
477 if (s == -1) {
478 syslog(LOG_ERR, "hostname: %m");
479 return -1;
480 }
481 if (s != 0 && ifo->hostname[0] == '.') {
482 syslog(LOG_ERR, "hostname cannot begin with .");
483 return -1;
fd05b7dc 484 }
cc3c3560 485 ifo->hostname[s] = '\0';
ed913a59
RM
486 if (ifo->hostname[0] == '\0')
487 ifo->options &= ~DHCPCD_HOSTNAME;
488 else
489 ifo->options |= DHCPCD_HOSTNAME;
fd05b7dc
RM
490 break;
491 case 'i':
492 if (arg)
493 s = parse_string((char *)ifo->vendorclassid + 1,
eab2229c 494 VENDORCLASSID_MAX_LEN, arg);
fd05b7dc
RM
495 else
496 s = 0;
497 if (s == -1) {
765fbf7d 498 syslog(LOG_ERR, "vendorclassid: %m");
fd05b7dc
RM
499 return -1;
500 }
501 *ifo->vendorclassid = (uint8_t)s;
502 break;
2662d519
RM
503 case 'k':
504 ifo->options |= DHCPCD_RELEASE;
505 break;
fd05b7dc
RM
506 case 'l':
507 if (*arg == '-') {
765fbf7d 508 syslog(LOG_ERR,
eab2229c 509 "leasetime must be a positive value");
fd05b7dc
RM
510 return -1;
511 }
512 errno = 0;
513 ifo->leasetime = (uint32_t)strtol(arg, NULL, 0);
514 if (errno == EINVAL || errno == ERANGE) {
765fbf7d 515 syslog(LOG_ERR, "`%s' out of range", arg);
fd05b7dc
RM
516 return -1;
517 }
518 break;
519 case 'm':
520 ifo->metric = atoint(arg);
521 if (ifo->metric < 0) {
765fbf7d 522 syslog(LOG_ERR, "metric must be a positive value");
fd05b7dc
RM
523 return -1;
524 }
525 break;
526 case 'o':
d7555c12
RM
527 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
528 if (make_option_mask(d, request, arg, 1) != 0) {
765fbf7d 529 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
530 return -1;
531 }
532 break;
533 case 'p':
534 ifo->options |= DHCPCD_PERSISTENT;
535 break;
03c2c879
RM
536 case 'q':
537 ifo->options |= DHCPCD_QUIET;
538 break;
2f7cb97c 539 case 'r':
2f7cb97c
RM
540 if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
541 return -1;
5b39d8f5 542 ifo->options |= DHCPCD_REQUEST;
2f7cb97c
RM
543 ifo->req_mask.s_addr = 0;
544 break;
fd05b7dc 545 case 's':
d7555c12
RM
546 if (ifo->options & DHCPCD_IPV6 &&
547 !(ifo->options & DHCPCD_IPV4))
548 {
549 ifo->options |= DHCPCD_INFORM;
550 break;
551 }
2f7cb97c
RM
552 if (arg && *arg != '\0') {
553 if (parse_addr(&ifo->req_addr, &ifo->req_mask,
eab2229c 554 arg) != 0)
91a44b91 555 return -1;
2f7cb97c
RM
556 } else {
557 ifo->req_addr.s_addr = 0;
558 ifo->req_mask.s_addr = 0;
fd05b7dc 559 }
5b39d8f5
RM
560 ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
561 ifo->options &= ~(DHCPCD_ARP | DHCPCD_STATIC);
91a44b91 562 break;
fd05b7dc
RM
563 case 't':
564 ifo->timeout = atoint(arg);
565 if (ifo->timeout < 0) {
a2a9a498 566 syslog(LOG_ERR, "timeout must be a positive value");
fd05b7dc
RM
567 return -1;
568 }
569 break;
570 case 'u':
571 s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
eab2229c
RM
572 s = parse_string((char *)ifo->userclass +
573 ifo->userclass[0] + 2,
574 s, arg);
fd05b7dc 575 if (s == -1) {
765fbf7d 576 syslog(LOG_ERR, "userclass: %m");
fd05b7dc
RM
577 return -1;
578 }
579 if (s != 0) {
580 ifo->userclass[ifo->userclass[0] + 1] = s;
581 ifo->userclass[0] += s + 1;
582 }
583 break;
584 case 'v':
585 p = strchr(arg, ',');
586 if (!p || !p[1]) {
765fbf7d 587 syslog(LOG_ERR, "invalid vendor format");
fd05b7dc
RM
588 return -1;
589 }
95d6dcfa
RM
590
591 /* If vendor starts with , then it is not encapsulated */
592 if (p == arg) {
593 arg++;
594 s = parse_string((char *)ifo->vendor + 1,
595 VENDOR_MAX_LEN, arg);
596 if (s == -1) {
597 syslog(LOG_ERR, "vendor: %m");
598 return -1;
599 }
600 ifo->vendor[0] = (uint8_t)s;
601 ifo->options |= DHCPCD_VENDORRAW;
602 break;
603 }
604
605 /* Encapsulated vendor options */
606 if (ifo->options & DHCPCD_VENDORRAW) {
607 ifo->options &= ~DHCPCD_VENDORRAW;
608 ifo->vendor[0] = 0;
609 }
610
fd05b7dc
RM
611 *p = '\0';
612 i = atoint(arg);
613 arg = p + 1;
614 if (i < 1 || i > 254) {
765fbf7d 615 syslog(LOG_ERR, "vendor option should be between"
eab2229c 616 " 1 and 254 inclusive");
fd05b7dc
RM
617 return -1;
618 }
619 s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
620 if (inet_aton(arg, &addr) == 1) {
621 if (s < 6) {
622 s = -1;
623 errno = ENOBUFS;
624 } else
625 memcpy(ifo->vendor + ifo->vendor[0] + 3,
eab2229c 626 &addr.s_addr, sizeof(addr.s_addr));
fd05b7dc 627 } else {
eab2229c
RM
628 s = parse_string((char *)ifo->vendor +
629 ifo->vendor[0] + 3, s, arg);
fd05b7dc
RM
630 }
631 if (s == -1) {
765fbf7d 632 syslog(LOG_ERR, "vendor: %m");
fd05b7dc
RM
633 return -1;
634 }
635 if (s != 0) {
636 ifo->vendor[ifo->vendor[0] + 1] = i;
637 ifo->vendor[ifo->vendor[0] + 2] = s;
638 ifo->vendor[0] += s + 2;
639 }
640 break;
2a07a2af
RM
641 case 'w':
642 ifo->options |= DHCPCD_WAITIP;
643 break;
a2a9a498
RM
644 case 'y':
645 ifo->reboot = atoint(arg);
646 if (ifo->reboot < 0) {
647 syslog(LOG_ERR, "reboot must be a positive value");
648 return -1;
649 }
650 break;
d3088c74 651 case 'z':
378f8fa4 652 ifav = splitv(&ifac, ifav, arg);
d3088c74 653 break;
fd05b7dc
RM
654 case 'A':
655 ifo->options &= ~DHCPCD_ARP;
656 /* IPv4LL requires ARP */
657 ifo->options &= ~DHCPCD_IPV4LL;
658 break;
03c2c879
RM
659 case 'B':
660 ifo->options &= ~DHCPCD_DAEMONISE;
661 break;
fd05b7dc
RM
662 case 'C':
663 /* Commas to spaces for shell */
664 while ((p = strchr(arg, ',')))
665 *p = ' ';
666 s = strlen("skip_hooks=") + strlen(arg) + 1;
28382337
RM
667 p = malloc(sizeof(char) * s);
668 if (p == NULL) {
669 syslog(LOG_ERR, "%s: %m", __func__);
670 return -1;
671 }
fd05b7dc
RM
672 snprintf(p, s, "skip_hooks=%s", arg);
673 add_environ(ifo, p, 0);
674 free(p);
675 break;
676 case 'D':
c989b023 677 ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
fd05b7dc
RM
678 break;
679 case 'E':
680 ifo->options |= DHCPCD_LASTLEASE;
681 break;
682 case 'F':
683 if (!arg) {
684 ifo->fqdn = FQDN_BOTH;
685 break;
686 }
687 if (strcmp(arg, "none") == 0)
688 ifo->fqdn = FQDN_NONE;
689 else if (strcmp(arg, "ptr") == 0)
690 ifo->fqdn = FQDN_PTR;
691 else if (strcmp(arg, "both") == 0)
692 ifo->fqdn = FQDN_BOTH;
693 else if (strcmp(arg, "disable") == 0)
694 ifo->fqdn = FQDN_DISABLE;
695 else {
765fbf7d 696 syslog(LOG_ERR, "invalid value `%s' for FQDN", arg);
fd05b7dc
RM
697 return -1;
698 }
699 break;
700 case 'G':
701 ifo->options &= ~DHCPCD_GATEWAY;
702 break;
4242c9b3
RM
703 case 'H':
704 ifo->options |= DHCPCD_XID_HWADDR;
705 break;
fd05b7dc
RM
706 case 'I':
707 /* Strings have a type of 0 */;
708 ifo->clientid[1] = 0;
709 if (arg)
710 s = parse_string_hwaddr((char *)ifo->clientid + 1,
eab2229c 711 CLIENTID_MAX_LEN, arg, 1);
fd05b7dc
RM
712 else
713 s = 0;
714 if (s == -1) {
765fbf7d 715 syslog(LOG_ERR, "clientid: %m");
fd05b7dc
RM
716 return -1;
717 }
c989b023 718 ifo->options |= DHCPCD_CLIENTID;
fd05b7dc 719 ifo->clientid[0] = (uint8_t)s;
fd05b7dc 720 break;
900b3da4
RM
721 case 'J':
722 ifo->options |= DHCPCD_BROADCAST;
723 break;
fd05b7dc
RM
724 case 'K':
725 ifo->options &= ~DHCPCD_LINK;
726 break;
727 case 'L':
728 ifo->options &= ~DHCPCD_IPV4LL;
729 break;
730 case 'O':
d7555c12
RM
731 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
732 if (make_option_mask(d, request, arg, -1) != 0 ||
733 make_option_mask(d, require, arg, -1) != 0 ||
734 make_option_mask(d, no, arg, 1) != 0)
fd05b7dc 735 {
765fbf7d 736 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
737 return -1;
738 }
739 break;
740 case 'Q':
d7555c12
RM
741 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
742 if (make_option_mask(d, require, arg, 1) != 0 ||
743 make_option_mask(d, request, arg, 1) != 0)
fd05b7dc 744 {
765fbf7d 745 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
746 return -1;
747 }
748 break;
91a44b91
RM
749 case 'S':
750 p = strchr(arg, '=');
751 if (p == NULL) {
752 syslog(LOG_ERR, "static assignment required");
753 return -1;
754 }
755 p++;
756 if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
776961cf
RM
757 if (parse_addr(&ifo->req_addr,
758 ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
759 p) != 0)
91a44b91
RM
760 return -1;
761
762 ifo->options |= DHCPCD_STATIC;
fa8b2a7a 763 ifo->options &= ~DHCPCD_INFORM;
776961cf
RM
764 } else if (strncmp(arg, "subnet_mask=", strlen("subnet_mask=")) == 0) {
765 if (parse_addr(&ifo->req_mask, NULL, p) != 0)
766 return -1;
91a44b91 767 } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
eab2229c
RM
768 strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
769 strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
770 strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
91a44b91 771 {
332a5fe6 772 fp = np = strchr(p, ' ');
91a44b91
RM
773 if (np == NULL) {
774 syslog(LOG_ERR, "all routes need a gateway");
775 return -1;
776 }
777 *np++ = '\0';
778 while (*np == ' ')
779 np++;
780 if (ifo->routes == NULL) {
4c9c4b3e
RM
781 ifo->routes = malloc(sizeof(*ifo->routes));
782 if (ifo->routes == NULL) {
10e17e3f 783 syslog(LOG_ERR, "%s: %m", __func__);
10e17e3f
RM
784 return -1;
785 }
673e81e5 786 TAILQ_INIT(ifo->routes);
4c9c4b3e
RM
787 }
788 rt = malloc(sizeof(*rt));
789 if (rt == NULL) {
790 syslog(LOG_ERR, "%s: %m", __func__);
791 *fp = ' ';
792 return -1;
91a44b91 793 }
91a44b91
RM
794 if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
795 parse_addr(&rt->gate, NULL, np) == -1)
332a5fe6 796 {
4c9c4b3e 797 free(rt);
332a5fe6 798 *fp = ' ';
91a44b91 799 return -1;
332a5fe6 800 }
4c9c4b3e 801 TAILQ_INSERT_TAIL(ifo->routes, rt, next);
332a5fe6 802 *fp = ' ';
91a44b91
RM
803 } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
804 if (ifo->routes == NULL) {
4c9c4b3e
RM
805 ifo->routes = malloc(sizeof(*ifo->routes));
806 if (ifo->routes == NULL) {
10e17e3f
RM
807 syslog(LOG_ERR, "%s: %m", __func__);
808 return -1;
809 }
00ababe4 810 TAILQ_INIT(ifo->routes);
4c9c4b3e
RM
811 }
812 rt = malloc(sizeof(*rt));
813 if (rt == NULL) {
814 syslog(LOG_ERR, "%s: %m", __func__);
815 return -1;
91a44b91 816 }
1abffd5b
RM
817 rt->dest.s_addr = INADDR_ANY;
818 rt->net.s_addr = INADDR_ANY;
4c9c4b3e
RM
819 if (parse_addr(&rt->gate, NULL, p) == -1) {
820 free(rt);
91a44b91 821 return -1;
4c9c4b3e
RM
822 }
823 TAILQ_INSERT_TAIL(ifo->routes, rt, next);
91a44b91
RM
824 } else {
825 s = 0;
826 if (ifo->config != NULL) {
827 while (ifo->config[s] != NULL) {
eab2229c
RM
828 if (strncmp(ifo->config[s], arg,
829 p - arg) == 0)
830 {
78369646
RM
831 p = strdup(arg);
832 if (p == NULL) {
833 syslog(LOG_ERR,
834 "%s: %m", __func__);
835 return -1;
836 }
91a44b91 837 free(ifo->config[s]);
78369646 838 ifo->config[s] = p;
91a44b91
RM
839 return 1;
840 }
841 s++;
842 }
843 }
78369646 844 p = strdup(arg);
fa245a4d
RM
845 if (p == NULL) {
846 syslog(LOG_ERR, "%s: %m", __func__);
847 return -1;
848 }
78369646
RM
849 nconf = realloc(ifo->config, sizeof(char *) * (s + 2));
850 if (nconf == NULL) {
851 syslog(LOG_ERR, "%s: %m", __func__);
852 return -1;
853 }
fa245a4d 854 ifo->config = nconf;
78369646 855 ifo->config[s] = p;
91a44b91
RM
856 ifo->config[s + 1] = NULL;
857 }
858 break;
bf80d526
RM
859 case 'W':
860 if (parse_addr(&addr, &addr2, arg) != 0)
861 return -1;
862 if (strchr(arg, '/') == NULL)
863 addr2.s_addr = INADDR_BROADCAST;
fa245a4d 864 naddr = realloc(ifo->whitelist,
bf80d526 865 sizeof(in_addr_t) * (ifo->whitelist_len + 2));
fa245a4d
RM
866 if (naddr == NULL) {
867 syslog(LOG_ERR, "%s: %m", __func__);
868 return -1;
869 }
870 ifo->whitelist = naddr;
bf80d526
RM
871 ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
872 ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
873 break;
fd05b7dc 874 case 'X':
e095a6eb 875 if (parse_addr(&addr, &addr2, arg) != 0)
fd05b7dc 876 return -1;
ce6b39df
RM
877 if (strchr(arg, '/') == NULL)
878 addr2.s_addr = INADDR_BROADCAST;
fa245a4d 879 naddr = realloc(ifo->blacklist,
e095a6eb 880 sizeof(in_addr_t) * (ifo->blacklist_len + 2));
fa245a4d
RM
881 if (naddr == NULL) {
882 syslog(LOG_ERR, "%s: %m", __func__);
883 return -1;
884 }
885 ifo->blacklist = naddr;
e095a6eb
RM
886 ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
887 ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
fd05b7dc 888 break;
d3088c74 889 case 'Z':
378f8fa4 890 ifdv = splitv(&ifdc, ifdv, arg);
d3088c74 891 break;
d7555c12 892 case '4':
2f0addfd 893 ifo->options &= ~DHCPCD_IPV6;
d7555c12
RM
894 ifo->options |= DHCPCD_IPV4;
895 break;
896 case '6':
897 ifo->options &= ~DHCPCD_IPV4;
2f0addfd 898 ifo->options |= DHCPCD_IPV6;
d7555c12 899 break;
aae24feb 900#ifdef INET
4ca7460f
RM
901 case O_ARPING:
902 if (parse_addr(&addr, NULL, arg) != 0)
903 return -1;
fa245a4d 904 naddr = realloc(ifo->arping,
4ca7460f 905 sizeof(in_addr_t) * (ifo->arping_len + 1));
fa245a4d
RM
906 if (naddr == NULL) {
907 syslog(LOG_ERR, "%s: %m", __func__);
908 return -1;
909 }
910 ifo->arping = naddr;
4ca7460f
RM
911 ifo->arping[ifo->arping_len++] = addr.s_addr;
912 break;
41c60e02 913 case O_DESTINATION:
d7555c12 914 if (make_option_mask(dhcp_opts, ifo->dstmask, arg, 2) != 0) {
41c60e02
RM
915 if (errno == EINVAL)
916 syslog(LOG_ERR, "option `%s' does not take"
917 " an IPv4 address", arg);
918 else
919 syslog(LOG_ERR, "unknown option `%s'", arg);
920 return -1;
921 }
922 break;
ff021b0b
RM
923 case O_FALLBACK:
924 free(ifo->fallback);
78369646
RM
925 ifo->fallback = strdup(arg);
926 if (ifo->fallback == NULL) {
927 syslog(LOG_ERR, "%s: %m", __func__);
00ababe4 928 return -1;
78369646 929 }
ff021b0b 930 break;
aae24feb 931#endif
eebe9a18
RM
932 case O_IPV6RS:
933 ifo->options |= DHCPCD_IPV6RS;
934 break;
91cd7324 935 case O_NOIPV6RS:
61dd6cf9
RM
936 ifo->options &= ~DHCPCD_IPV6RS;
937 break;
eebe9a18 938 case O_IPV6RA_FORK:
61dd6cf9 939 ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
91cd7324 940 break;
eebe9a18
RM
941 case O_IPV6RA_OWN:
942 ifo->options |= DHCPCD_IPV6RA_OWN;
943 break;
944 case O_IPV6RA_OWN_D:
945 ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT;
946 break;
7dab081f
RM
947 case O_NOALIAS:
948 ifo->options |= DHCPCD_NOALIAS;
949 break;
00ababe4
RM
950#ifdef INET6
951 case O_IA_NA:
952 i = D6_OPTION_IA_NA;
953 /* FALLTHROUGH */
954 case O_IA_TA:
955 if (i == 0)
956 i = D6_OPTION_IA_TA;
957 /* FALLTHROUGH */
958 case O_IA_PD:
959 if (i == 0)
960 i = D6_OPTION_IA_PD;
961 ifo->options |= DHCPCD_IA_FORCED;
962 if (ifo->ia_type != 0 && ifo->ia_type != i) {
963 syslog(LOG_ERR, "cannot specify a different IA type");
964 return -1;
965 }
966 ifo->ia_type = i;
967 if (arg == NULL)
968 break;
969 fp = strchr(arg, ' ');
eade34fd
RM
970 if (fp)
971 *fp++ = '\0';
367f7b11
RM
972 errno = 0;
973 l = strtol(arg, &np, 0);
7784695d
RM
974 if (l >= 0 && l <= (long)UINT32_MAX &&
975 errno == 0 && *np == '\0')
976 {
367f7b11
RM
977 u32 = htonl(l);
978 memcpy(&_iaid, &u32, sizeof(_iaid));
979 goto got_iaid;
980 }
00ababe4
RM
981 if ((s = parse_string((char *)_iaid, sizeof(_iaid), arg)) < 1) {
982 syslog(LOG_ERR, "%s: invalid IAID", arg);
983 return -1;
984 }
985 if (s < 4)
986 _iaid[3] = '\0';
987 if (s < 3)
988 _iaid[2] = '\0';
989 if (s < 2)
990 _iaid[1] = '\0';
367f7b11 991got_iaid:
00ababe4
RM
992 iaid = NULL;
993 for (sl = 0; sl < ifo->iaid_len; sl++) {
994 if (ifo->iaid[sl].iaid[0] == _iaid[0] &&
995 ifo->iaid[sl].iaid[1] == _iaid[1] &&
996 ifo->iaid[sl].iaid[2] == _iaid[2] &&
997 ifo->iaid[sl].iaid[3] == _iaid[3])
998 {
999 iaid = &ifo->iaid[sl];
1000 break;
1001 }
1002 }
1003 if (iaid == NULL) {
1004 iaid = realloc(ifo->iaid,
1005 sizeof(*ifo->iaid) * (ifo->iaid_len + 1));
1006 if (iaid == NULL) {
1007 syslog(LOG_ERR, "%s: %m", __func__);
1008 return -1;
1009 }
1010 ifo->iaid = iaid;
1011 iaid = &ifo->iaid[ifo->iaid_len++];
1012 iaid->iaid[0] = _iaid[0];
1013 iaid->iaid[1] = _iaid[1];
1014 iaid->iaid[2] = _iaid[2];
1015 iaid->iaid[3] = _iaid[3];
1016 iaid->sla = NULL;
1017 iaid->sla_len = 0;
1018 }
1019 for (p = fp; p; p = fp) {
1020 fp = strchr(p, ' ');
1021 if (fp)
1022 *fp++ = '\0';
1023 sla = realloc(iaid->sla,
1024 sizeof(*iaid->sla) * (iaid->sla_len + 1));
1025 if (sla == NULL) {
1026 syslog(LOG_ERR, "%s: %m", __func__);
1027 return -1;
1028 }
1029 iaid->sla = sla;
1030 sla = &iaid->sla[iaid->sla_len++];
1031 np = strchr(p, '/');
1032 if (np)
1033 *np++ = '\0';
00ababe4
RM
1034 if (strlcpy(sla->ifname, p,
1035 sizeof(sla->ifname)) >= sizeof(sla->ifname))
1036 {
1037 syslog(LOG_ERR, "%s: interface name too long",
1038 arg);
1039 return -1;
1040 }
1041 p = np;
367f7b11
RM
1042 if (p) {
1043 np = strchr(p, '/');
1044 if (np)
1045 *np++ = '\0';
83919266
RM
1046 if (*p == '\0')
1047 sla->sla_set = 0;
1048 else {
1049 errno = 0;
1050 sla->sla = atoint(p);
1051 sla->sla_set = 1;
1052 if (errno)
1053 return -1;
1054 }
367f7b11
RM
1055 if (np) {
1056 sla->prefix_len = atoint(np);
1057 if (sla->prefix_len < 0 ||
1058 sla->prefix_len > 128)
1059 return -1;
1060 } else
1061 sla->prefix_len = 64;
5985c4e2
RM
1062 } else {
1063 sla->sla_set = 0;
1064 /* Sanity - check there are no more
1065 * unspecified SLA's */
1066 for (sl = 0; sl < iaid->sla_len - 1; sl++) {
1067 slap = &iaid->sla[sl];
1068 if (slap->sla_set == 0 &&
1069 strcmp(slap->ifname, sla->ifname)
1070 == 0)
1071 {
1072 syslog(LOG_WARNING,
1073 "%s: cannot specify the "
1074 "same interface twice with "
1075 "an automatic SLA",
1076 sla->ifname);
1077 iaid->sla_len--;
1078 break;
1079 }
1080 }
367f7b11 1081 }
00ababe4
RM
1082 }
1083 break;
d6a18654 1084 case O_HOSTNAME_SHORT:
9c54b11b 1085 ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
d6a18654 1086 break;
00ababe4 1087#endif
fd05b7dc
RM
1088 default:
1089 return 0;
1090 }
1091
1092 return 1;
1093}
1094
1095static int
1096parse_config_line(struct if_options *ifo, const char *opt, char *line)
1097{
1098 unsigned int i;
1099
1100 for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
1101 if (!cf_options[i].name ||
1102 strcmp(cf_options[i].name, opt) != 0)
1103 continue;
1104
1105 if (cf_options[i].has_arg == required_argument && !line) {
1106 fprintf(stderr,
eab2229c
RM
1107 PACKAGE ": option requires an argument -- %s\n",
1108 opt);
fd05b7dc
RM
1109 return -1;
1110 }
1111
1112 return parse_option(ifo, cf_options[i].val, line);
1113 }
1114
1115 fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
1116 return -1;
1117}
1118
741f46c6 1119static void
b0272a9d 1120finish_config(struct if_options *ifo)
741f46c6
RM
1121{
1122
1123 /* Terminate the encapsulated options */
1124 if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
1125 ifo->vendor[0]++;
1126 ifo->vendor[ifo->vendor[0]] = DHO_END;
1127 }
b0272a9d 1128}
741f46c6
RM
1129
1130#ifdef INET6
b0272a9d
RM
1131static void
1132finish_config6(struct if_options *ifo, const char *ifname)
1133{
1134
741f46c6
RM
1135 if (!(ifo->options & DHCPCD_IPV6))
1136 ifo->options &= ~DHCPCD_IPV6RS;
1137
1138 if (ifname && ifo->iaid_len == 0 && ifo->options & DHCPCD_IPV6) {
1139 ifo->iaid = malloc(sizeof(*ifo->iaid));
1140 if (ifo->iaid == NULL)
1141 syslog(LOG_ERR, "%s: %m", __func__);
1142 else {
1143 if (ifo->ia_type == 0)
1144 ifo->ia_type = D6_OPTION_IA_NA;
1145 ifo->iaid_len = strlen(ifname);
1146 if (ifo->iaid_len <= sizeof(ifo->iaid->iaid)) {
1147 strncpy((char *)ifo->iaid->iaid, ifname,
1148 sizeof(ifo->iaid->iaid));
1149 memset(ifo->iaid->iaid + ifo->iaid_len, 0,
1150 sizeof(ifo->iaid->iaid) -ifo->iaid_len);
1151 } else {
1152 uint32_t idx = if_nametoindex(ifname);
1153 memcpy(ifo->iaid->iaid, &idx, sizeof(idx));
1154 }
1155 ifo->iaid_len = 1;
1156 ifo->iaid->sla = NULL;
1157 ifo->iaid->sla_len = 0;
1158 }
a7386a6e 1159 }
741f46c6 1160}
b0272a9d 1161#endif
741f46c6 1162
fd05b7dc 1163struct if_options *
6f767217
RM
1164read_config(const char *file,
1165 const char *ifname, const char *ssid, const char *profile)
fd05b7dc
RM
1166{
1167 struct if_options *ifo;
1168 FILE *f;
27805e96 1169 char *line, *option, *p;
6f767217 1170 int skip = 0, have_profile = 0;
fd05b7dc
RM
1171
1172 /* Seed our default options */
10e17e3f
RM
1173 ifo = calloc(1, sizeof(*ifo));
1174 if (ifo == NULL) {
1175 syslog(LOG_ERR, "%s: %m", __func__);
1176 return NULL;
1177 }
aae24feb
RM
1178 ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK;
1179#ifdef INET
d7555c12 1180 ifo->options |= DHCPCD_IPV4 | DHCPCD_IPV4LL;
00ababe4 1181 ifo->options |= DHCPCD_GATEWAY | DHCPCD_ARP;
aae24feb
RM
1182#endif
1183#ifdef INET6
d7555c12 1184 ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | DHCPCD_IPV6RA_REQRDNSS;
66fd5d67 1185 ifo->dadtransmits = ipv6_dadtransmits(ifname);
aae24feb 1186#endif
fd05b7dc 1187 ifo->timeout = DEFAULT_TIMEOUT;
a2a9a498 1188 ifo->reboot = DEFAULT_REBOOT;
f43e5853 1189 ifo->metric = -1;
ed913a59 1190 strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
793c4286 1191
27805e96
RM
1192 ifo->vendorclassid[0] = strlen(vendor);
1193 memcpy(ifo->vendorclassid + 1, vendor, ifo->vendorclassid[0]);
fd05b7dc
RM
1194
1195 /* Parse our options file */
9f7780b0 1196 f = fopen(file ? file : CONFIG, "r");
5e2062a4
RM
1197 if (f == NULL) {
1198 if (file != NULL)
1199 syslog(LOG_ERR, "fopen `%s': %m", file);
fd05b7dc 1200 return ifo;
5e2062a4 1201 }
fd05b7dc 1202
e1caa8db
RM
1203 while ((line = get_line(f))) {
1204 option = strsep(&line, " \t");
fd05b7dc
RM
1205 /* Trim trailing whitespace */
1206 if (line && *line) {
1207 p = line + strlen(line) - 1;
1208 while (p != line &&
eab2229c
RM
1209 (*p == ' ' || *p == '\t') &&
1210 *(p - 1) != '\\')
fd05b7dc
RM
1211 *p-- = '\0';
1212 }
1213 /* Start of an interface block, skip if not ours */
1214 if (strcmp(option, "interface") == 0) {
1215 if (ifname && line && strcmp(line, ifname) == 0)
1216 skip = 0;
1217 else
1218 skip = 1;
1219 continue;
c53cf4ef
RM
1220 }
1221 /* Start of an ssid block, skip if not ours */
1222 if (strcmp(option, "ssid") == 0) {
1223 if (ssid && line && strcmp(line, ssid) == 0)
1224 skip = 0;
1225 else
1226 skip = 1;
1227 continue;
fd05b7dc 1228 }
6f767217
RM
1229 /* Start of a profile block, skip if not ours */
1230 if (strcmp(option, "profile") == 0) {
1231 if (profile && line && strcmp(line, profile) == 0) {
1232 skip = 0;
1233 have_profile = 1;
1234 } else
1235 skip = 1;
1236 continue;
1237 }
fd05b7dc
RM
1238 if (skip)
1239 continue;
378f8fa4 1240 parse_config_line(ifo, option, line);
fd05b7dc 1241 }
fd05b7dc
RM
1242 fclose(f);
1243
6f767217
RM
1244 if (profile && !have_profile) {
1245 free_options(ifo);
1246 errno = ENOENT;
1247 ifo = NULL;
1248 }
1249
b0272a9d
RM
1250 finish_config(ifo);
1251#ifdef INET6
1252 finish_config6(ifo, ifname);
1253#endif
fd05b7dc
RM
1254 return ifo;
1255}
1256
1257int
1258add_options(struct if_options *ifo, int argc, char **argv)
1259{
29c0fd6f
RM
1260 int oi, opt, r;
1261
1262 if (argc == 0)
1263 return 1;
fd05b7dc
RM
1264
1265 optind = 0;
29c0fd6f 1266 r = 1;
fd05b7dc
RM
1267 while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
1268 {
1269 r = parse_option(ifo, opt, optarg);
1270 if (r != 1)
1271 break;
1272 }
741f46c6 1273
b0272a9d
RM
1274 finish_config(ifo);
1275#ifdef INET6
1276 finish_config6(ifo, NULL);
1277#endif
fd05b7dc
RM
1278 return r;
1279}
1280
1281void
1282free_options(struct if_options *ifo)
1283{
1284 size_t i;
1285
f43e5853
RM
1286 if (ifo) {
1287 if (ifo->environ) {
1288 i = 0;
1289 while (ifo->environ[i])
1290 free(ifo->environ[i++]);
1291 free(ifo->environ);
1292 }
91a44b91
RM
1293 if (ifo->config) {
1294 i = 0;
1295 while (ifo->config[i])
1296 free(ifo->config[i++]);
1297 free(ifo->config);
1298 }
e88c525f 1299 ipv4_freeroutes(ifo->routes);
ff021b0b 1300 free(ifo->arping);
f43e5853 1301 free(ifo->blacklist);
ff021b0b 1302 free(ifo->fallback);
00ababe4
RM
1303#ifdef INET6
1304 for (i = 0; i < ifo->iaid_len; i++)
1305 free(ifo->iaid[i].sla);
1306 free(ifo->iaid);
1307#endif
f43e5853 1308 free(ifo);
fd05b7dc 1309 }
fd05b7dc 1310}