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