]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - if-options.c
Use Mt for email address.
[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
1f4c1525 355#ifdef INET
91a44b91
RM
356static int
357parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
358{
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;
1f4c1525 389}
aae24feb 390#else
1f4c1525
RM
391static int
392parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
393 __unused const char *arg)
394{
395
aae24feb
RM
396 syslog(LOG_ERR, "No IPv4 support");
397 return -1;
91a44b91 398}
1f4c1525 399#endif
91a44b91 400
00ababe4 401static const char *
d7555c12
RM
402set_option_space(const char *arg, const struct dhcp_opt **d,
403 struct if_options *ifo,
404 uint8_t *request[], uint8_t *require[], uint8_t *no[])
405{
406
aae24feb 407#ifdef INET6
d7555c12
RM
408 if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
409 *d = dhcp6_opts;
410 *request = ifo->requestmask6;
411 *require = ifo->requiremask6;
412 *no = ifo->nomask6;
413 return arg + strlen("dhcp6_");
414 }
aae24feb
RM
415#endif
416
417#ifdef INET
d7555c12 418 *d = dhcp_opts;
aae24feb
RM
419#else
420 *d = NULL;
421#endif
d7555c12
RM
422 *request = ifo->requestmask;
423 *require = ifo->requiremask;
424 *no = ifo->nomask;
425 return arg;
426}
427
fd05b7dc
RM
428static int
429parse_option(struct if_options *ifo, int opt, const char *arg)
430{
431 int i;
fa245a4d 432 char *p = NULL, *fp, *np, **nconf;
fd05b7dc 433 ssize_t s;
e095a6eb 434 struct in_addr addr, addr2;
fa245a4d 435 in_addr_t *naddr;
91a44b91 436 struct rt *rt;
a2258eb3 437 const struct dhcp_opt *d;
d7555c12 438 uint8_t *request, *require, *no;
1f4c1525
RM
439#ifdef INET6
440 long l;
367f7b11 441 uint32_t u32;
1f4c1525 442 size_t sl;
00ababe4
RM
443 struct if_iaid *iaid;
444 uint8_t _iaid[4];
5985c4e2 445 struct if_sla *sla, *slap;
1f4c1525 446#endif
fd05b7dc 447
00ababe4 448 i = 0;
fd05b7dc 449 switch(opt) {
5e2062a4 450 case 'f': /* FALLTHROUGH */
6bfd88f1 451 case 'g': /* FALLTHROUGH */
da166178
RM
452 case 'n': /* FALLTHROUGH */
453 case 'x': /* FALLTHROUGH */
dc60cba4
RM
454 case 'T': /* FALLTHROUGH */
455 case 'U': /* We need to handle non interface options */
fd05b7dc 456 break;
03c2c879
RM
457 case 'b':
458 ifo->options |= DHCPCD_BACKGROUND;
459 break;
fd05b7dc
RM
460 case 'c':
461 strlcpy(ifo->script, arg, sizeof(ifo->script));
462 break;
acb1cf88
RM
463 case 'd':
464 ifo->options |= DHCPCD_DEBUG;
465 break;
6bfd88f1
RM
466 case 'e':
467 add_environ(ifo, arg, 1);
468 break;
fd05b7dc 469 case 'h':
cc3c3560
RM
470 if (!arg) {
471 ifo->options |= DHCPCD_HOSTNAME;
472 break;
473 }
474 s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
475 if (s == -1) {
476 syslog(LOG_ERR, "hostname: %m");
477 return -1;
478 }
479 if (s != 0 && ifo->hostname[0] == '.') {
480 syslog(LOG_ERR, "hostname cannot begin with .");
481 return -1;
fd05b7dc 482 }
cc3c3560 483 ifo->hostname[s] = '\0';
ed913a59
RM
484 if (ifo->hostname[0] == '\0')
485 ifo->options &= ~DHCPCD_HOSTNAME;
486 else
487 ifo->options |= DHCPCD_HOSTNAME;
fd05b7dc
RM
488 break;
489 case 'i':
490 if (arg)
491 s = parse_string((char *)ifo->vendorclassid + 1,
eab2229c 492 VENDORCLASSID_MAX_LEN, arg);
fd05b7dc
RM
493 else
494 s = 0;
495 if (s == -1) {
765fbf7d 496 syslog(LOG_ERR, "vendorclassid: %m");
fd05b7dc
RM
497 return -1;
498 }
499 *ifo->vendorclassid = (uint8_t)s;
500 break;
2662d519
RM
501 case 'k':
502 ifo->options |= DHCPCD_RELEASE;
503 break;
fd05b7dc
RM
504 case 'l':
505 if (*arg == '-') {
765fbf7d 506 syslog(LOG_ERR,
eab2229c 507 "leasetime must be a positive value");
fd05b7dc
RM
508 return -1;
509 }
510 errno = 0;
511 ifo->leasetime = (uint32_t)strtol(arg, NULL, 0);
512 if (errno == EINVAL || errno == ERANGE) {
765fbf7d 513 syslog(LOG_ERR, "`%s' out of range", arg);
fd05b7dc
RM
514 return -1;
515 }
516 break;
517 case 'm':
518 ifo->metric = atoint(arg);
519 if (ifo->metric < 0) {
765fbf7d 520 syslog(LOG_ERR, "metric must be a positive value");
fd05b7dc
RM
521 return -1;
522 }
523 break;
524 case 'o':
d7555c12
RM
525 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
526 if (make_option_mask(d, request, arg, 1) != 0) {
765fbf7d 527 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
528 return -1;
529 }
530 break;
531 case 'p':
532 ifo->options |= DHCPCD_PERSISTENT;
533 break;
03c2c879
RM
534 case 'q':
535 ifo->options |= DHCPCD_QUIET;
536 break;
2f7cb97c 537 case 'r':
2f7cb97c
RM
538 if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
539 return -1;
5b39d8f5 540 ifo->options |= DHCPCD_REQUEST;
2f7cb97c
RM
541 ifo->req_mask.s_addr = 0;
542 break;
fd05b7dc 543 case 's':
d7555c12
RM
544 if (ifo->options & DHCPCD_IPV6 &&
545 !(ifo->options & DHCPCD_IPV4))
546 {
547 ifo->options |= DHCPCD_INFORM;
548 break;
549 }
2f7cb97c
RM
550 if (arg && *arg != '\0') {
551 if (parse_addr(&ifo->req_addr, &ifo->req_mask,
eab2229c 552 arg) != 0)
91a44b91 553 return -1;
2f7cb97c
RM
554 } else {
555 ifo->req_addr.s_addr = 0;
556 ifo->req_mask.s_addr = 0;
fd05b7dc 557 }
5b39d8f5
RM
558 ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
559 ifo->options &= ~(DHCPCD_ARP | DHCPCD_STATIC);
91a44b91 560 break;
fd05b7dc
RM
561 case 't':
562 ifo->timeout = atoint(arg);
563 if (ifo->timeout < 0) {
a2a9a498 564 syslog(LOG_ERR, "timeout must be a positive value");
fd05b7dc
RM
565 return -1;
566 }
567 break;
568 case 'u':
569 s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
eab2229c
RM
570 s = parse_string((char *)ifo->userclass +
571 ifo->userclass[0] + 2,
572 s, arg);
fd05b7dc 573 if (s == -1) {
765fbf7d 574 syslog(LOG_ERR, "userclass: %m");
fd05b7dc
RM
575 return -1;
576 }
577 if (s != 0) {
578 ifo->userclass[ifo->userclass[0] + 1] = s;
579 ifo->userclass[0] += s + 1;
580 }
581 break;
582 case 'v':
583 p = strchr(arg, ',');
584 if (!p || !p[1]) {
765fbf7d 585 syslog(LOG_ERR, "invalid vendor format");
fd05b7dc
RM
586 return -1;
587 }
95d6dcfa
RM
588
589 /* If vendor starts with , then it is not encapsulated */
590 if (p == arg) {
591 arg++;
592 s = parse_string((char *)ifo->vendor + 1,
593 VENDOR_MAX_LEN, arg);
594 if (s == -1) {
595 syslog(LOG_ERR, "vendor: %m");
596 return -1;
597 }
598 ifo->vendor[0] = (uint8_t)s;
599 ifo->options |= DHCPCD_VENDORRAW;
600 break;
601 }
602
603 /* Encapsulated vendor options */
604 if (ifo->options & DHCPCD_VENDORRAW) {
605 ifo->options &= ~DHCPCD_VENDORRAW;
606 ifo->vendor[0] = 0;
607 }
608
fd05b7dc
RM
609 *p = '\0';
610 i = atoint(arg);
611 arg = p + 1;
612 if (i < 1 || i > 254) {
765fbf7d 613 syslog(LOG_ERR, "vendor option should be between"
eab2229c 614 " 1 and 254 inclusive");
fd05b7dc
RM
615 return -1;
616 }
617 s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
618 if (inet_aton(arg, &addr) == 1) {
619 if (s < 6) {
620 s = -1;
621 errno = ENOBUFS;
622 } else
623 memcpy(ifo->vendor + ifo->vendor[0] + 3,
eab2229c 624 &addr.s_addr, sizeof(addr.s_addr));
fd05b7dc 625 } else {
eab2229c
RM
626 s = parse_string((char *)ifo->vendor +
627 ifo->vendor[0] + 3, s, arg);
fd05b7dc
RM
628 }
629 if (s == -1) {
765fbf7d 630 syslog(LOG_ERR, "vendor: %m");
fd05b7dc
RM
631 return -1;
632 }
633 if (s != 0) {
634 ifo->vendor[ifo->vendor[0] + 1] = i;
635 ifo->vendor[ifo->vendor[0] + 2] = s;
636 ifo->vendor[0] += s + 2;
637 }
638 break;
2a07a2af
RM
639 case 'w':
640 ifo->options |= DHCPCD_WAITIP;
641 break;
a2a9a498
RM
642 case 'y':
643 ifo->reboot = atoint(arg);
644 if (ifo->reboot < 0) {
645 syslog(LOG_ERR, "reboot must be a positive value");
646 return -1;
647 }
648 break;
d3088c74 649 case 'z':
378f8fa4 650 ifav = splitv(&ifac, ifav, arg);
d3088c74 651 break;
fd05b7dc
RM
652 case 'A':
653 ifo->options &= ~DHCPCD_ARP;
654 /* IPv4LL requires ARP */
655 ifo->options &= ~DHCPCD_IPV4LL;
656 break;
03c2c879
RM
657 case 'B':
658 ifo->options &= ~DHCPCD_DAEMONISE;
659 break;
fd05b7dc
RM
660 case 'C':
661 /* Commas to spaces for shell */
662 while ((p = strchr(arg, ',')))
663 *p = ' ';
664 s = strlen("skip_hooks=") + strlen(arg) + 1;
28382337
RM
665 p = malloc(sizeof(char) * s);
666 if (p == NULL) {
667 syslog(LOG_ERR, "%s: %m", __func__);
668 return -1;
669 }
fd05b7dc
RM
670 snprintf(p, s, "skip_hooks=%s", arg);
671 add_environ(ifo, p, 0);
672 free(p);
673 break;
674 case 'D':
c989b023 675 ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
fd05b7dc
RM
676 break;
677 case 'E':
678 ifo->options |= DHCPCD_LASTLEASE;
679 break;
680 case 'F':
681 if (!arg) {
682 ifo->fqdn = FQDN_BOTH;
683 break;
684 }
685 if (strcmp(arg, "none") == 0)
686 ifo->fqdn = FQDN_NONE;
687 else if (strcmp(arg, "ptr") == 0)
688 ifo->fqdn = FQDN_PTR;
689 else if (strcmp(arg, "both") == 0)
690 ifo->fqdn = FQDN_BOTH;
691 else if (strcmp(arg, "disable") == 0)
692 ifo->fqdn = FQDN_DISABLE;
693 else {
765fbf7d 694 syslog(LOG_ERR, "invalid value `%s' for FQDN", arg);
fd05b7dc
RM
695 return -1;
696 }
697 break;
698 case 'G':
699 ifo->options &= ~DHCPCD_GATEWAY;
700 break;
4242c9b3
RM
701 case 'H':
702 ifo->options |= DHCPCD_XID_HWADDR;
703 break;
fd05b7dc
RM
704 case 'I':
705 /* Strings have a type of 0 */;
706 ifo->clientid[1] = 0;
707 if (arg)
708 s = parse_string_hwaddr((char *)ifo->clientid + 1,
eab2229c 709 CLIENTID_MAX_LEN, arg, 1);
fd05b7dc
RM
710 else
711 s = 0;
712 if (s == -1) {
765fbf7d 713 syslog(LOG_ERR, "clientid: %m");
fd05b7dc
RM
714 return -1;
715 }
c989b023 716 ifo->options |= DHCPCD_CLIENTID;
fd05b7dc 717 ifo->clientid[0] = (uint8_t)s;
fd05b7dc 718 break;
900b3da4
RM
719 case 'J':
720 ifo->options |= DHCPCD_BROADCAST;
721 break;
fd05b7dc
RM
722 case 'K':
723 ifo->options &= ~DHCPCD_LINK;
724 break;
725 case 'L':
726 ifo->options &= ~DHCPCD_IPV4LL;
727 break;
728 case 'O':
d7555c12
RM
729 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
730 if (make_option_mask(d, request, arg, -1) != 0 ||
731 make_option_mask(d, require, arg, -1) != 0 ||
732 make_option_mask(d, no, arg, 1) != 0)
fd05b7dc 733 {
765fbf7d 734 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
735 return -1;
736 }
737 break;
738 case 'Q':
d7555c12
RM
739 arg = set_option_space(arg, &d, ifo, &request, &require, &no);
740 if (make_option_mask(d, require, arg, 1) != 0 ||
741 make_option_mask(d, request, arg, 1) != 0)
fd05b7dc 742 {
765fbf7d 743 syslog(LOG_ERR, "unknown option `%s'", arg);
fd05b7dc
RM
744 return -1;
745 }
746 break;
91a44b91
RM
747 case 'S':
748 p = strchr(arg, '=');
749 if (p == NULL) {
750 syslog(LOG_ERR, "static assignment required");
751 return -1;
752 }
753 p++;
754 if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
776961cf
RM
755 if (parse_addr(&ifo->req_addr,
756 ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
757 p) != 0)
91a44b91
RM
758 return -1;
759
760 ifo->options |= DHCPCD_STATIC;
fa8b2a7a 761 ifo->options &= ~DHCPCD_INFORM;
776961cf
RM
762 } else if (strncmp(arg, "subnet_mask=", strlen("subnet_mask=")) == 0) {
763 if (parse_addr(&ifo->req_mask, NULL, p) != 0)
764 return -1;
91a44b91 765 } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
eab2229c
RM
766 strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
767 strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
768 strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
91a44b91 769 {
332a5fe6 770 fp = np = strchr(p, ' ');
91a44b91
RM
771 if (np == NULL) {
772 syslog(LOG_ERR, "all routes need a gateway");
773 return -1;
774 }
775 *np++ = '\0';
776 while (*np == ' ')
777 np++;
778 if (ifo->routes == NULL) {
4c9c4b3e
RM
779 ifo->routes = malloc(sizeof(*ifo->routes));
780 if (ifo->routes == NULL) {
10e17e3f 781 syslog(LOG_ERR, "%s: %m", __func__);
10e17e3f
RM
782 return -1;
783 }
673e81e5 784 TAILQ_INIT(ifo->routes);
4c9c4b3e
RM
785 }
786 rt = malloc(sizeof(*rt));
787 if (rt == NULL) {
788 syslog(LOG_ERR, "%s: %m", __func__);
789 *fp = ' ';
790 return -1;
91a44b91 791 }
91a44b91
RM
792 if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
793 parse_addr(&rt->gate, NULL, np) == -1)
332a5fe6 794 {
4c9c4b3e 795 free(rt);
332a5fe6 796 *fp = ' ';
91a44b91 797 return -1;
332a5fe6 798 }
4c9c4b3e 799 TAILQ_INSERT_TAIL(ifo->routes, rt, next);
332a5fe6 800 *fp = ' ';
91a44b91
RM
801 } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
802 if (ifo->routes == NULL) {
4c9c4b3e
RM
803 ifo->routes = malloc(sizeof(*ifo->routes));
804 if (ifo->routes == NULL) {
10e17e3f
RM
805 syslog(LOG_ERR, "%s: %m", __func__);
806 return -1;
807 }
00ababe4 808 TAILQ_INIT(ifo->routes);
4c9c4b3e
RM
809 }
810 rt = malloc(sizeof(*rt));
811 if (rt == NULL) {
812 syslog(LOG_ERR, "%s: %m", __func__);
813 return -1;
91a44b91 814 }
1abffd5b
RM
815 rt->dest.s_addr = INADDR_ANY;
816 rt->net.s_addr = INADDR_ANY;
4c9c4b3e
RM
817 if (parse_addr(&rt->gate, NULL, p) == -1) {
818 free(rt);
91a44b91 819 return -1;
4c9c4b3e
RM
820 }
821 TAILQ_INSERT_TAIL(ifo->routes, rt, next);
91a44b91
RM
822 } else {
823 s = 0;
824 if (ifo->config != NULL) {
825 while (ifo->config[s] != NULL) {
eab2229c
RM
826 if (strncmp(ifo->config[s], arg,
827 p - arg) == 0)
828 {
78369646
RM
829 p = strdup(arg);
830 if (p == NULL) {
831 syslog(LOG_ERR,
832 "%s: %m", __func__);
833 return -1;
834 }
91a44b91 835 free(ifo->config[s]);
78369646 836 ifo->config[s] = p;
91a44b91
RM
837 return 1;
838 }
839 s++;
840 }
841 }
78369646 842 p = strdup(arg);
fa245a4d
RM
843 if (p == NULL) {
844 syslog(LOG_ERR, "%s: %m", __func__);
845 return -1;
846 }
78369646
RM
847 nconf = realloc(ifo->config, sizeof(char *) * (s + 2));
848 if (nconf == NULL) {
849 syslog(LOG_ERR, "%s: %m", __func__);
850 return -1;
851 }
fa245a4d 852 ifo->config = nconf;
78369646 853 ifo->config[s] = p;
91a44b91
RM
854 ifo->config[s + 1] = NULL;
855 }
856 break;
bf80d526
RM
857 case 'W':
858 if (parse_addr(&addr, &addr2, arg) != 0)
859 return -1;
860 if (strchr(arg, '/') == NULL)
861 addr2.s_addr = INADDR_BROADCAST;
fa245a4d 862 naddr = realloc(ifo->whitelist,
bf80d526 863 sizeof(in_addr_t) * (ifo->whitelist_len + 2));
fa245a4d
RM
864 if (naddr == NULL) {
865 syslog(LOG_ERR, "%s: %m", __func__);
866 return -1;
867 }
868 ifo->whitelist = naddr;
bf80d526
RM
869 ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
870 ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
871 break;
fd05b7dc 872 case 'X':
e095a6eb 873 if (parse_addr(&addr, &addr2, arg) != 0)
fd05b7dc 874 return -1;
ce6b39df
RM
875 if (strchr(arg, '/') == NULL)
876 addr2.s_addr = INADDR_BROADCAST;
fa245a4d 877 naddr = realloc(ifo->blacklist,
e095a6eb 878 sizeof(in_addr_t) * (ifo->blacklist_len + 2));
fa245a4d
RM
879 if (naddr == NULL) {
880 syslog(LOG_ERR, "%s: %m", __func__);
881 return -1;
882 }
883 ifo->blacklist = naddr;
e095a6eb
RM
884 ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
885 ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
fd05b7dc 886 break;
d3088c74 887 case 'Z':
378f8fa4 888 ifdv = splitv(&ifdc, ifdv, arg);
d3088c74 889 break;
d7555c12 890 case '4':
2f0addfd 891 ifo->options &= ~DHCPCD_IPV6;
d7555c12
RM
892 ifo->options |= DHCPCD_IPV4;
893 break;
894 case '6':
895 ifo->options &= ~DHCPCD_IPV4;
2f0addfd 896 ifo->options |= DHCPCD_IPV6;
d7555c12 897 break;
aae24feb 898#ifdef INET
4ca7460f
RM
899 case O_ARPING:
900 if (parse_addr(&addr, NULL, arg) != 0)
901 return -1;
fa245a4d 902 naddr = realloc(ifo->arping,
4ca7460f 903 sizeof(in_addr_t) * (ifo->arping_len + 1));
fa245a4d
RM
904 if (naddr == NULL) {
905 syslog(LOG_ERR, "%s: %m", __func__);
906 return -1;
907 }
908 ifo->arping = naddr;
4ca7460f
RM
909 ifo->arping[ifo->arping_len++] = addr.s_addr;
910 break;
41c60e02 911 case O_DESTINATION:
d7555c12 912 if (make_option_mask(dhcp_opts, ifo->dstmask, arg, 2) != 0) {
41c60e02
RM
913 if (errno == EINVAL)
914 syslog(LOG_ERR, "option `%s' does not take"
915 " an IPv4 address", arg);
916 else
917 syslog(LOG_ERR, "unknown option `%s'", arg);
918 return -1;
919 }
920 break;
ff021b0b
RM
921 case O_FALLBACK:
922 free(ifo->fallback);
78369646
RM
923 ifo->fallback = strdup(arg);
924 if (ifo->fallback == NULL) {
925 syslog(LOG_ERR, "%s: %m", __func__);
00ababe4 926 return -1;
78369646 927 }
ff021b0b 928 break;
aae24feb 929#endif
eebe9a18
RM
930 case O_IPV6RS:
931 ifo->options |= DHCPCD_IPV6RS;
932 break;
91cd7324 933 case O_NOIPV6RS:
61dd6cf9
RM
934 ifo->options &= ~DHCPCD_IPV6RS;
935 break;
eebe9a18 936 case O_IPV6RA_FORK:
61dd6cf9 937 ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
91cd7324 938 break;
eebe9a18
RM
939 case O_IPV6RA_OWN:
940 ifo->options |= DHCPCD_IPV6RA_OWN;
941 break;
942 case O_IPV6RA_OWN_D:
943 ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT;
944 break;
7dab081f
RM
945 case O_NOALIAS:
946 ifo->options |= DHCPCD_NOALIAS;
947 break;
00ababe4
RM
948#ifdef INET6
949 case O_IA_NA:
950 i = D6_OPTION_IA_NA;
951 /* FALLTHROUGH */
952 case O_IA_TA:
953 if (i == 0)
954 i = D6_OPTION_IA_TA;
955 /* FALLTHROUGH */
956 case O_IA_PD:
957 if (i == 0)
958 i = D6_OPTION_IA_PD;
959 ifo->options |= DHCPCD_IA_FORCED;
960 if (ifo->ia_type != 0 && ifo->ia_type != i) {
961 syslog(LOG_ERR, "cannot specify a different IA type");
962 return -1;
963 }
964 ifo->ia_type = i;
965 if (arg == NULL)
966 break;
967 fp = strchr(arg, ' ');
eade34fd
RM
968 if (fp)
969 *fp++ = '\0';
367f7b11
RM
970 errno = 0;
971 l = strtol(arg, &np, 0);
7784695d
RM
972 if (l >= 0 && l <= (long)UINT32_MAX &&
973 errno == 0 && *np == '\0')
974 {
367f7b11
RM
975 u32 = htonl(l);
976 memcpy(&_iaid, &u32, sizeof(_iaid));
977 goto got_iaid;
978 }
00ababe4
RM
979 if ((s = parse_string((char *)_iaid, sizeof(_iaid), arg)) < 1) {
980 syslog(LOG_ERR, "%s: invalid IAID", arg);
981 return -1;
982 }
983 if (s < 4)
984 _iaid[3] = '\0';
985 if (s < 3)
986 _iaid[2] = '\0';
987 if (s < 2)
988 _iaid[1] = '\0';
367f7b11 989got_iaid:
00ababe4
RM
990 iaid = NULL;
991 for (sl = 0; sl < ifo->iaid_len; sl++) {
992 if (ifo->iaid[sl].iaid[0] == _iaid[0] &&
993 ifo->iaid[sl].iaid[1] == _iaid[1] &&
994 ifo->iaid[sl].iaid[2] == _iaid[2] &&
995 ifo->iaid[sl].iaid[3] == _iaid[3])
996 {
997 iaid = &ifo->iaid[sl];
998 break;
999 }
1000 }
1001 if (iaid == NULL) {
1002 iaid = realloc(ifo->iaid,
1003 sizeof(*ifo->iaid) * (ifo->iaid_len + 1));
1004 if (iaid == NULL) {
1005 syslog(LOG_ERR, "%s: %m", __func__);
1006 return -1;
1007 }
1008 ifo->iaid = iaid;
1009 iaid = &ifo->iaid[ifo->iaid_len++];
1010 iaid->iaid[0] = _iaid[0];
1011 iaid->iaid[1] = _iaid[1];
1012 iaid->iaid[2] = _iaid[2];
1013 iaid->iaid[3] = _iaid[3];
1014 iaid->sla = NULL;
1015 iaid->sla_len = 0;
1016 }
1017 for (p = fp; p; p = fp) {
1018 fp = strchr(p, ' ');
1019 if (fp)
1020 *fp++ = '\0';
1021 sla = realloc(iaid->sla,
1022 sizeof(*iaid->sla) * (iaid->sla_len + 1));
1023 if (sla == NULL) {
1024 syslog(LOG_ERR, "%s: %m", __func__);
1025 return -1;
1026 }
1027 iaid->sla = sla;
1028 sla = &iaid->sla[iaid->sla_len++];
1029 np = strchr(p, '/');
1030 if (np)
1031 *np++ = '\0';
00ababe4
RM
1032 if (strlcpy(sla->ifname, p,
1033 sizeof(sla->ifname)) >= sizeof(sla->ifname))
1034 {
1035 syslog(LOG_ERR, "%s: interface name too long",
1036 arg);
1037 return -1;
1038 }
1039 p = np;
367f7b11
RM
1040 if (p) {
1041 np = strchr(p, '/');
1042 if (np)
1043 *np++ = '\0';
83919266
RM
1044 if (*p == '\0')
1045 sla->sla_set = 0;
1046 else {
1047 errno = 0;
1048 sla->sla = atoint(p);
1049 sla->sla_set = 1;
1050 if (errno)
1051 return -1;
1052 }
367f7b11
RM
1053 if (np) {
1054 sla->prefix_len = atoint(np);
1055 if (sla->prefix_len < 0 ||
1056 sla->prefix_len > 128)
1057 return -1;
1058 } else
1059 sla->prefix_len = 64;
5985c4e2
RM
1060 } else {
1061 sla->sla_set = 0;
1062 /* Sanity - check there are no more
1063 * unspecified SLA's */
1064 for (sl = 0; sl < iaid->sla_len - 1; sl++) {
1065 slap = &iaid->sla[sl];
1066 if (slap->sla_set == 0 &&
1067 strcmp(slap->ifname, sla->ifname)
1068 == 0)
1069 {
1070 syslog(LOG_WARNING,
1071 "%s: cannot specify the "
1072 "same interface twice with "
1073 "an automatic SLA",
1074 sla->ifname);
1075 iaid->sla_len--;
1076 break;
1077 }
1078 }
367f7b11 1079 }
00ababe4
RM
1080 }
1081 break;
1082#endif
fd05b7dc
RM
1083 default:
1084 return 0;
1085 }
1086
1087 return 1;
1088}
1089
1090static int
1091parse_config_line(struct if_options *ifo, const char *opt, char *line)
1092{
1093 unsigned int i;
1094
1095 for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
1096 if (!cf_options[i].name ||
1097 strcmp(cf_options[i].name, opt) != 0)
1098 continue;
1099
1100 if (cf_options[i].has_arg == required_argument && !line) {
1101 fprintf(stderr,
eab2229c
RM
1102 PACKAGE ": option requires an argument -- %s\n",
1103 opt);
fd05b7dc
RM
1104 return -1;
1105 }
1106
1107 return parse_option(ifo, cf_options[i].val, line);
1108 }
1109
1110 fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
1111 return -1;
1112}
1113
741f46c6
RM
1114static void
1115finish_config(struct if_options *ifo, const char *ifname)
1116{
1117
1118 /* Terminate the encapsulated options */
1119 if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
1120 ifo->vendor[0]++;
1121 ifo->vendor[ifo->vendor[0]] = DHO_END;
1122 }
1123
1124#ifdef INET6
1125 if (!(ifo->options & DHCPCD_IPV6))
1126 ifo->options &= ~DHCPCD_IPV6RS;
1127
1128 if (ifname && ifo->iaid_len == 0 && ifo->options & DHCPCD_IPV6) {
1129 ifo->iaid = malloc(sizeof(*ifo->iaid));
1130 if (ifo->iaid == NULL)
1131 syslog(LOG_ERR, "%s: %m", __func__);
1132 else {
1133 if (ifo->ia_type == 0)
1134 ifo->ia_type = D6_OPTION_IA_NA;
1135 ifo->iaid_len = strlen(ifname);
1136 if (ifo->iaid_len <= sizeof(ifo->iaid->iaid)) {
1137 strncpy((char *)ifo->iaid->iaid, ifname,
1138 sizeof(ifo->iaid->iaid));
1139 memset(ifo->iaid->iaid + ifo->iaid_len, 0,
1140 sizeof(ifo->iaid->iaid) -ifo->iaid_len);
1141 } else {
1142 uint32_t idx = if_nametoindex(ifname);
1143 memcpy(ifo->iaid->iaid, &idx, sizeof(idx));
1144 }
1145 ifo->iaid_len = 1;
1146 ifo->iaid->sla = NULL;
1147 ifo->iaid->sla_len = 0;
1148 }
a7386a6e 1149 }
741f46c6
RM
1150#endif
1151}
1152
fd05b7dc 1153struct if_options *
6f767217
RM
1154read_config(const char *file,
1155 const char *ifname, const char *ssid, const char *profile)
fd05b7dc
RM
1156{
1157 struct if_options *ifo;
1158 FILE *f;
27805e96 1159 char *line, *option, *p;
6f767217 1160 int skip = 0, have_profile = 0;
fd05b7dc
RM
1161
1162 /* Seed our default options */
10e17e3f
RM
1163 ifo = calloc(1, sizeof(*ifo));
1164 if (ifo == NULL) {
1165 syslog(LOG_ERR, "%s: %m", __func__);
1166 return NULL;
1167 }
aae24feb
RM
1168 ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK;
1169#ifdef INET
d7555c12 1170 ifo->options |= DHCPCD_IPV4 | DHCPCD_IPV4LL;
00ababe4 1171 ifo->options |= DHCPCD_GATEWAY | DHCPCD_ARP;
aae24feb
RM
1172#endif
1173#ifdef INET6
d7555c12 1174 ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | DHCPCD_IPV6RA_REQRDNSS;
66fd5d67 1175 ifo->dadtransmits = ipv6_dadtransmits(ifname);
aae24feb 1176#endif
fd05b7dc 1177 ifo->timeout = DEFAULT_TIMEOUT;
a2a9a498 1178 ifo->reboot = DEFAULT_REBOOT;
f43e5853 1179 ifo->metric = -1;
ed913a59 1180 strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
793c4286 1181
27805e96
RM
1182 ifo->vendorclassid[0] = strlen(vendor);
1183 memcpy(ifo->vendorclassid + 1, vendor, ifo->vendorclassid[0]);
fd05b7dc
RM
1184
1185 /* Parse our options file */
9f7780b0 1186 f = fopen(file ? file : CONFIG, "r");
5e2062a4
RM
1187 if (f == NULL) {
1188 if (file != NULL)
1189 syslog(LOG_ERR, "fopen `%s': %m", file);
fd05b7dc 1190 return ifo;
5e2062a4 1191 }
fd05b7dc 1192
e1caa8db
RM
1193 while ((line = get_line(f))) {
1194 option = strsep(&line, " \t");
fd05b7dc
RM
1195 /* Trim trailing whitespace */
1196 if (line && *line) {
1197 p = line + strlen(line) - 1;
1198 while (p != line &&
eab2229c
RM
1199 (*p == ' ' || *p == '\t') &&
1200 *(p - 1) != '\\')
fd05b7dc
RM
1201 *p-- = '\0';
1202 }
1203 /* Start of an interface block, skip if not ours */
1204 if (strcmp(option, "interface") == 0) {
1205 if (ifname && line && strcmp(line, ifname) == 0)
1206 skip = 0;
1207 else
1208 skip = 1;
1209 continue;
c53cf4ef
RM
1210 }
1211 /* Start of an ssid block, skip if not ours */
1212 if (strcmp(option, "ssid") == 0) {
1213 if (ssid && line && strcmp(line, ssid) == 0)
1214 skip = 0;
1215 else
1216 skip = 1;
1217 continue;
fd05b7dc 1218 }
6f767217
RM
1219 /* Start of a profile block, skip if not ours */
1220 if (strcmp(option, "profile") == 0) {
1221 if (profile && line && strcmp(line, profile) == 0) {
1222 skip = 0;
1223 have_profile = 1;
1224 } else
1225 skip = 1;
1226 continue;
1227 }
fd05b7dc
RM
1228 if (skip)
1229 continue;
378f8fa4 1230 parse_config_line(ifo, option, line);
fd05b7dc 1231 }
fd05b7dc
RM
1232 fclose(f);
1233
6f767217
RM
1234 if (profile && !have_profile) {
1235 free_options(ifo);
1236 errno = ENOENT;
1237 ifo = NULL;
1238 }
1239
741f46c6 1240 finish_config(ifo, ifname);
fd05b7dc
RM
1241 return ifo;
1242}
1243
1244int
1245add_options(struct if_options *ifo, int argc, char **argv)
1246{
29c0fd6f
RM
1247 int oi, opt, r;
1248
1249 if (argc == 0)
1250 return 1;
fd05b7dc
RM
1251
1252 optind = 0;
29c0fd6f 1253 r = 1;
fd05b7dc
RM
1254 while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
1255 {
1256 r = parse_option(ifo, opt, optarg);
1257 if (r != 1)
1258 break;
1259 }
741f46c6
RM
1260
1261 finish_config(ifo, NULL);
fd05b7dc
RM
1262 return r;
1263}
1264
1265void
1266free_options(struct if_options *ifo)
1267{
1268 size_t i;
1269
f43e5853
RM
1270 if (ifo) {
1271 if (ifo->environ) {
1272 i = 0;
1273 while (ifo->environ[i])
1274 free(ifo->environ[i++]);
1275 free(ifo->environ);
1276 }
91a44b91
RM
1277 if (ifo->config) {
1278 i = 0;
1279 while (ifo->config[i])
1280 free(ifo->config[i++]);
1281 free(ifo->config);
1282 }
e88c525f 1283 ipv4_freeroutes(ifo->routes);
ff021b0b 1284 free(ifo->arping);
f43e5853 1285 free(ifo->blacklist);
ff021b0b 1286 free(ifo->fallback);
00ababe4
RM
1287#ifdef INET6
1288 for (i = 0; i < ifo->iaid_len; i++)
1289 free(ifo->iaid[i].sla);
1290 free(ifo->iaid);
1291#endif
f43e5853 1292 free(ifo);
fd05b7dc 1293 }
fd05b7dc 1294}