Removed superfluous maxplen config var
[olsrd.git] / src / olsr_cfg.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "olsr_cfg.h"
43
44 #include "olsr.h"
45 // #include "ipcalc.h"
46 #include "parser.h"
47 #include "net_olsr.h"
48 #include "ifnet.h"
49 #include "log.h"
50 #include "olsr_ip_prefix_list.h"
51
52 #include <unistd.h>
53 #include <string.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <arpa/inet.h>
57 #include <getopt.h>
58 #include <errno.h>
59
60 #ifdef DEBUG
61 #define PARSER_DEBUG_PRINTF(x, args...)   printf(x, ##args)
62 #else
63 #define PARSER_DEBUG_PRINTF(x, ...)   do { } while (0)
64 #endif
65
66 /*
67  * Special strcat for reading the config file and
68  * joining a longer section { ... } to one string
69  */
70 static void
71 read_cfg_cat(char **pdest, const char *src)
72 {
73   char *tmp = *pdest;
74   if (*src) {
75     *pdest = olsr_malloc(1 + (tmp ? strlen(tmp) : 0) + strlen(src), "read_cfg_cat");
76     if (tmp) {
77       strcpy(*pdest, tmp);
78       free(tmp);
79     }
80     strcat(*pdest, src);
81   }
82 }
83
84 /*
85  * Read the olsrd.conf file and replace/insert found
86  * options into the argv[] array at the position of
87  * the original -f filename parameters. Note, that
88  * longer sections { ... } are joined to one string
89  */
90 static int
91 read_cfg(const char *filename, int *pargc, char ***pargv, int **pline)
92 {
93   FILE *f = fopen(filename, "r");
94   if (f) {
95     int bopen = 0, optind_tmp = optind, line_lst = 0, line = 0;
96     char sbuf[512], *pbuf = NULL, *p;
97
98     while ((p = fgets(sbuf, sizeof(sbuf), f)) || pbuf) {
99       line++;
100       if (!p) {
101         *sbuf = 0;
102         goto eof;
103       }
104       while (*p && '#' != *p) {
105         if ('"' == *p || '\'' == *p) {
106           char sep = *p;
107           while (*++p && sep != *p);
108         }
109         p++;
110       }
111       *p = 0;
112       while (sbuf <= --p && ' ' >= *p);
113       *(p + 1) = 0;
114       if (*sbuf) {
115         if (bopen) {
116           read_cfg_cat(&pbuf, sbuf);
117           if ('}' == *p) {
118             bopen = 0;
119           }
120         } else if (p == sbuf && '{' == *p) {
121           read_cfg_cat(&pbuf, " ");
122           read_cfg_cat(&pbuf, sbuf);
123           bopen = 1;
124         } else {
125           if ('{' == *p) {
126             bopen = 1;
127           }
128         eof:
129           if (pbuf) {
130             int i, *line_tmp;
131             char **argv_tmp;
132             int argc_tmp = *pargc + 2;
133             char *q = pbuf, *n;
134
135             while (*q && ' ' >= *q)
136               q++;
137             p = q;
138             while (' ' < *p)
139               p++;
140             n = olsr_malloc(p - q + 3, "config arg0");
141             strcpy(n, "--");
142             strncat(n, q, p - q);
143             while (*q && ' ' >= *p)
144               p++;
145
146             line_tmp = olsr_malloc(argc_tmp * sizeof(line_tmp[0]), "config line");
147             argv_tmp = olsr_malloc(argc_tmp * sizeof(argv_tmp[0]), "config args");
148             for (i = 0; i < argc_tmp; i++) {
149               if (i < optind_tmp) {
150                 line_tmp[i] = (*pline)[i];
151                 argv_tmp[i] = (*pargv)[i];
152               } else if (i == optind_tmp) {
153                 line_tmp[i] = line_lst;
154                 argv_tmp[i] = n;
155               } else if (i == 1 + optind_tmp) {
156                 line_tmp[i] = line_lst;
157                 argv_tmp[i] = olsr_strdup(p);
158               } else {
159                 line_tmp[i] = (*pline)[i - 2];
160                 argv_tmp[i] = (*pargv)[i - 2];
161               }
162             }
163             optind_tmp += 2;
164             *pargc = argc_tmp;
165             free(*pargv);
166             *pargv = argv_tmp;
167             free(*pline);
168             *pline = line_tmp;
169             line_lst = line;
170             free(pbuf);
171             pbuf = NULL;
172           }
173           read_cfg_cat(&pbuf, sbuf);
174         }
175       }
176     }
177     fclose(f);
178     return 0;
179   }
180   return -1;
181 }
182
183 /*
184  * Free an array of string tokens
185  */
186 static void
187 parse_tok_free(char **s)
188 {
189   if (s) {
190     char **p = s;
191     while (*p) {
192       free(*p);
193       p++;
194     }
195     free(s);
196   }
197 }
198
199 /*
200  * Test for end-of-string or { ... } section
201  */
202 static inline bool
203 parse_tok_delim(const char *p)
204 {
205   switch (*p) {
206   case 0:
207   case '{':
208   case '}':
209     return true;
210   }
211   return false;
212 }
213
214 /*
215  * Slit the src string into tokens and return
216  * an array of token strings. May return NULL
217  * if no token found, otherwise you need to
218  * free the strings using parse_tok_free()
219  */
220 static char **
221 parse_tok(const char *s, const char **snext)
222 {
223   char **tmp, **ret = NULL;
224   int i, count = 0;
225   const char *p = s;
226
227   while (!parse_tok_delim(p)) {
228     while (!parse_tok_delim(p) && ' ' >= *p)
229       p++;
230     if (!parse_tok_delim(p)) {
231       char c = 0;
232       const char *q = p;
233       if ('"' == *p || '\'' == *p) {
234         c = *q++;
235         while (!parse_tok_delim(++p) && c != *p);
236       } else {
237         while (!parse_tok_delim(p) && ' ' < *p)
238           p++;
239       }
240       tmp = ret;
241       ret = olsr_malloc((2 + count) * sizeof(ret[0]), "parse_tok");
242       for (i = 0; i < count; i++) {
243         ret[i] = tmp[i];
244       }
245       if (tmp)
246         free(tmp);
247       ret[count++] = olsr_strndup(q, p - q);
248       ret[count] = NULL;
249       if (c)
250         p++;
251     }
252   }
253   if (snext)
254     *snext = p;
255   return ret;
256 }
257
258 /*
259  * Returns default interface options
260  */
261 static struct olsr_if_options *
262 get_default_olsr_if_options(void)
263 {
264   struct olsr_if_options *new_io = olsr_malloc(sizeof(*new_io), "default_if_config");
265
266   /* No memset because olsr_malloc uses calloc() */
267   /* memset(&new_io->ipv4_broadcast, 0, sizeof(new_io->ipv4_broadcast)); */
268   new_io->ipv6_addrtype = OLSR_IP6T_AUTO;
269   inet_pton(AF_INET6, OLSR_IPV6_MCAST_SITE_LOCAL, &new_io->ipv6_multi_site.v6);
270   inet_pton(AF_INET6, OLSR_IPV6_MCAST_GLOBAL, &new_io->ipv6_multi_glbl.v6);
271   /* new_io->weight.fixed = false; */
272   /* new_io->weight.value = 0; */
273   new_io->hello_params.emission_interval = HELLO_INTERVAL;
274   new_io->hello_params.validity_time = NEIGHB_HOLD_TIME;
275   new_io->tc_params.emission_interval = TC_INTERVAL;
276   new_io->tc_params.validity_time = TOP_HOLD_TIME;
277   new_io->mid_params.emission_interval = MID_INTERVAL;
278   new_io->mid_params.validity_time = MID_HOLD_TIME;
279   new_io->hna_params.emission_interval = HNA_INTERVAL;
280   new_io->hna_params.validity_time = HNA_HOLD_TIME;
281   /* new_io->lq_mult = NULL; */
282   new_io->autodetect_chg = true;
283
284   return new_io;
285 }
286
287 /**
288  * Create a new interf_name struct using a given
289  * name and insert it into the interface list.
290  */
291 static struct olsr_if_config *
292 queue_if(const char *name, struct olsr_config *cfg)
293 {
294   struct olsr_if_config *new_if;
295
296   /* check if the interface already exists */
297   for (new_if = cfg->if_configs; new_if != NULL; new_if = new_if->next) {
298     if (0 == strcmp(new_if->name, name)) {
299       fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
300       return NULL;
301     }
302   }
303
304   new_if = olsr_malloc(sizeof(*new_if), "queue interface");
305   new_if->name = olsr_strdup(name);
306   /* new_if->config = NULL; */
307   /* memset(&new_if->hemu_ip, 0, sizeof(new_if->hemu_ip)); */
308   /* new_if->interf = NULL; */
309   new_if->cnf = get_default_olsr_if_options();
310   new_if->next = cfg->if_configs;
311   cfg->if_configs = new_if;
312
313   return new_if;
314 }
315
316 /*
317  * Parses a single hna option block
318  */
319 static void
320 parse_cfg_hna(char *argstr, const int ip_version, struct olsr_config *cfg)
321 {
322   char **tok;
323 #ifdef DEBUG
324   struct ipaddr_str buf;
325 #endif
326   if ('{' != *argstr) {
327     fprintf(stderr, "No {}\n");
328     exit(EXIT_FAILURE);
329   }
330   if (NULL != (tok = parse_tok(argstr + 1, NULL))) {
331     char **p = tok;
332     if (ip_version != cfg->ip_version) {
333       fprintf(stderr, "IPv%d addresses can only be used if \"IpVersion\" == %d\n",
334               AF_INET == ip_version ? 4 : 6, AF_INET == ip_version ? 4 : 6);
335       exit(EXIT_FAILURE);
336     }
337     while (p[0]) {
338       union olsr_ip_addr ipaddr;
339       if (!p[1]) {
340         fprintf(stderr, "Odd args in %s\n", argstr);
341         exit(EXIT_FAILURE);
342       }
343       if (inet_pton(ip_version, p[0], &ipaddr) <= 0) {
344         fprintf(stderr, "Failed converting IP address %s\n", p[0]);
345         exit(EXIT_FAILURE);
346       }
347       if (AF_INET == ip_version) {
348         union olsr_ip_addr netmask;
349         if (inet_pton(AF_INET, p[1], &netmask) <= 0) {
350           fprintf(stderr, "Failed converting IP address %s\n", p[1]);
351           exit(EXIT_FAILURE);
352         }
353         if ((ipaddr.v4.s_addr & ~netmask.v4.s_addr) != 0) {
354           fprintf(stderr, "The IP address %s/%s is not a network address!\n", p[0], p[1]);
355           exit(EXIT_FAILURE);
356         }
357         ip_prefix_list_add(&cfg->hna_entries, &ipaddr, netmask_to_prefix((uint8_t *) & netmask, cfg->ipsize));
358         PARSER_DEBUG_PRINTF("Hna4 %s/%d\n", ip_to_string(cfg->ip_version, &buf, &ipaddr),
359                             netmask_to_prefix((uint8_t *) & netmask, cfg->ipsize));
360       } else {
361         int prefix = -1;
362         sscanf('/' == *p[1] ? p[1] + 1 : p[1], "%d", &prefix);
363         if (0 > prefix || 128 < prefix) {
364           fprintf(stderr, "Illegal IPv6 prefix %s\n", p[1]);
365           exit(EXIT_FAILURE);
366         }
367         ip_prefix_list_add(&cfg->hna_entries, &ipaddr, prefix);
368         PARSER_DEBUG_PRINTF("Hna6 %s/%d\n", ip_to_string(cfg->ip_version, &buf, &ipaddr), prefix);
369       }
370       p += 2;
371     }
372     parse_tok_free(tok);
373   }
374 }
375
376 /*
377  * Parses a single interface option block
378  */
379 static void
380 parse_cfg_interface(char *argstr, struct olsr_config *cfg)
381 {
382   char **tok;
383   const char *nxt;
384 #ifdef DEBUG
385   struct ipaddr_str buf;
386 #endif
387   if (NULL != (tok = parse_tok(argstr, &nxt))) {
388     if ('{' != *nxt) {
389       fprintf(stderr, "No {}\n");
390       exit(EXIT_FAILURE);
391     } else {
392       char **tok_next = parse_tok(nxt + 1, NULL);
393       char **p = tok;
394       while (p[0]) {
395         char **p_next = tok_next;
396         struct olsr_if_config *new_if = queue_if(p[0], cfg);
397         PARSER_DEBUG_PRINTF("Interface %s\n", p[0]);
398         while (new_if && p_next[0]) {
399           if (!p_next[1]) {
400             fprintf(stderr, "Odd args in %s\n", nxt);
401             exit(EXIT_FAILURE);
402           }
403           if (0 == strcmp("AutoDetectChanges", p_next[0])) {
404             new_if->cnf->autodetect_chg = (0 == strcmp("yes", p_next[1]));
405             PARSER_DEBUG_PRINTF("\tAutodetect changes: %d\n", new_if->cnf->autodetect_chg);
406           } else if (0 == strcmp("Ip4Broadcast", p_next[0])) {
407             union olsr_ip_addr ipaddr;
408             if (inet_pton(AF_INET, p_next[1], &ipaddr) <= 0) {
409               fprintf(stderr, "Failed converting IP address %s\n", p_next[1]);
410               exit(EXIT_FAILURE);
411             }
412             new_if->cnf->ipv4_broadcast = ipaddr;
413             PARSER_DEBUG_PRINTF("\tIPv4 broadcast: %s\n", ip4_to_string(&buf, new_if->cnf->ipv4_broadcast.v4));
414           } else if (0 == strcmp("Ip6AddrType", p_next[0])) {
415             if (0 == strcmp("site-local", p_next[1])) {
416               new_if->cnf->ipv6_addrtype = OLSR_IP6T_SITELOCAL;
417             } else if (0 == strcmp("unique-local", p_next[1])) {
418               new_if->cnf->ipv6_addrtype = OLSR_IP6T_UNIQUELOCAL;
419             } else if (0 == strcmp("global", p_next[1])) {
420               new_if->cnf->ipv6_addrtype = OLSR_IP6T_GLOBAL;
421             } else {
422               new_if->cnf->ipv6_addrtype = OLSR_IP6T_AUTO;
423             }
424             PARSER_DEBUG_PRINTF("\tIPv6 addrtype: %d\n", new_if->cnf->ipv6_addrtype);
425           } else if (0 == strcmp("Ip6MulticastSite", p_next[0])) {
426             union olsr_ip_addr ipaddr;
427             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
428               fprintf(stderr, "Failed converting IP address %s\n", p_next[1]);
429               exit(EXIT_FAILURE);
430             }
431             new_if->cnf->ipv6_multi_site = ipaddr;
432             PARSER_DEBUG_PRINTF("\tIPv6 site-local multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_site.v6));
433           } else if (0 == strcmp("Ip6MulticastGlobal", p_next[0])) {
434             union olsr_ip_addr ipaddr;
435             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
436               fprintf(stderr, "Failed converting IP address %s\n", p_next[1]);
437               exit(EXIT_FAILURE);
438             }
439             new_if->cnf->ipv6_multi_glbl = ipaddr;
440             PARSER_DEBUG_PRINTF("\tIPv6 global multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_glbl.v6));
441           } else if (0 == strcmp("HelloInterval", p_next[0])) {
442             new_if->cnf->hello_params.emission_interval = 0;
443             sscanf(p_next[1], "%f", &new_if->cnf->hello_params.emission_interval);
444             PARSER_DEBUG_PRINTF("\tHELLO interval: %0.2f\n", new_if->cnf->hello_params.emission_interval);
445           } else if (0 == strcmp("HelloValidityTime", p_next[0])) {
446             new_if->cnf->hello_params.validity_time = 0;
447             sscanf(p_next[1], "%f", &new_if->cnf->hello_params.validity_time);
448             PARSER_DEBUG_PRINTF("\tHELLO validity: %0.2f\n", new_if->cnf->hello_params.validity_time);
449           } else if (0 == strcmp("TcInterval", p_next[0])) {
450             new_if->cnf->tc_params.emission_interval = 0;
451             sscanf(p_next[1], "%f", &new_if->cnf->tc_params.emission_interval);
452             PARSER_DEBUG_PRINTF("\tTC interval: %0.2f\n", new_if->cnf->tc_params.emission_interval);
453           } else if (0 == strcmp("TcValidityTime", p_next[0])) {
454             new_if->cnf->tc_params.validity_time = 0;
455             sscanf(p_next[1], "%f", &new_if->cnf->tc_params.validity_time);
456             PARSER_DEBUG_PRINTF("\tTC validity: %0.2f\n", new_if->cnf->tc_params.validity_time);
457           } else if (0 == strcmp("MidInterval", p_next[0])) {
458             new_if->cnf->mid_params.emission_interval = 0;
459             sscanf(p_next[1], "%f", &new_if->cnf->mid_params.emission_interval);
460             PARSER_DEBUG_PRINTF("\tMID interval: %0.2f\n", new_if->cnf->mid_params.emission_interval);
461           } else if (0 == strcmp("MidValidityTime", p_next[0])) {
462             new_if->cnf->mid_params.validity_time = 0;
463             sscanf(p_next[1], "%f", &new_if->cnf->mid_params.validity_time);
464             PARSER_DEBUG_PRINTF("\tMID validity: %0.2f\n", new_if->cnf->mid_params.validity_time);
465           } else if (0 == strcmp("HnaInterval", p_next[0])) {
466             new_if->cnf->hna_params.emission_interval = 0;
467             sscanf(p_next[1], "%f", &new_if->cnf->hna_params.emission_interval);
468             PARSER_DEBUG_PRINTF("\tHNA interval: %0.2f\n", new_if->cnf->hna_params.emission_interval);
469           } else if (0 == strcmp("HnaValidityTime", p_next[0])) {
470             new_if->cnf->hna_params.validity_time = 0;
471             sscanf(p_next[1], "%f", &new_if->cnf->hna_params.validity_time);
472             PARSER_DEBUG_PRINTF("\tHNA validity: %0.2f\n", new_if->cnf->hna_params.validity_time);
473           } else if (0 == strcmp("Weight", p_next[0])) {
474             new_if->cnf->weight.fixed = true;
475             PARSER_DEBUG_PRINTF("\tFixed willingness: %d\n", new_if->cnf->weight.value);
476           } else if (0 == strcmp("LinkQualityMult", p_next[0])) {
477             float f;
478             struct olsr_lq_mult *mult = olsr_malloc(sizeof(*mult), "lqmult");
479             if (!p_next[2]) {
480               fprintf(stderr, "Odd args in %s\n", nxt);
481               exit(EXIT_FAILURE);
482             }
483             memset(&mult->addr, 0, sizeof(mult->addr));
484             if (0 != strcmp("default", p_next[1])) {
485               if (inet_pton(cfg->ip_version, p_next[1], &mult->addr) <= 0) {
486                 fprintf(stderr, "Failed converting IP address %s\n", p_next[1]);
487                 exit(EXIT_FAILURE);
488               }
489             }
490             f = 0;
491             sscanf(p_next[2], "%f", &f);
492             mult->value = (uint32_t) (f * LINK_LOSS_MULTIPLIER);
493             mult->next = new_if->cnf->lq_mult;
494             new_if->cnf->lq_mult = mult;
495             PARSER_DEBUG_PRINTF("\tLinkQualityMult %s %0.2f\n", ip_to_string(cfg->ip_version, &buf, &mult->addr),
496                                 (float)mult->value / LINK_LOSS_MULTIPLIER);
497             p_next++;
498           } else {
499             fprintf(stderr, "Unknown arg: %s %s\n", p_next[0], p_next[1]);
500             exit(EXIT_FAILURE);
501           }
502           p_next += 2;
503         }
504         p++;
505       }
506       if (tok_next)
507         parse_tok_free(tok_next);
508     }
509     parse_tok_free(tok);
510   } else {
511     fprintf(stderr, "Error in %s\n", argstr);
512     exit(EXIT_FAILURE);
513   }
514 }
515
516 /*
517  * Parses a single ipc option block
518  */
519 static void
520 parse_cfg_ipc(char *argstr, struct olsr_config *cfg)
521 {
522   char **tok;
523   const char *nxt;
524 #ifdef DEBUG
525   struct ipaddr_str buf;
526 #endif
527   if ('{' != *argstr) {
528     fprintf(stderr, "No {}\n");
529     exit(EXIT_FAILURE);
530   }
531   if (NULL != (tok = parse_tok(argstr + 1, &nxt))) {
532     char **p = tok;
533     while (p[0]) {
534       if (!p[1]) {
535         fprintf(stderr, "Odd args in %s\n", argstr);
536         exit(EXIT_FAILURE);
537       }
538       if (0 == strcmp("MaxConnections", p[0])) {
539         int arg = -1;
540         sscanf(argstr, "%d", &arg);
541         if (0 <= arg && arg < 1 << (8 * sizeof(cfg->ipc_connections)))
542           cfg->ipc_connections = arg;
543         PARSER_DEBUG_PRINTF("\tIPC connections: %d\n", cfg->ipc_connections);
544       } else if (0 == strcmp("Host", p[0])) {
545         union olsr_ip_addr ipaddr;
546         if (inet_pton(cfg->ip_version, p[1], &ipaddr) <= 0) {
547           fprintf(stderr, "Failed converting IP address %s\n", p[0]);
548           exit(EXIT_FAILURE);
549         }
550
551         ip_acl_add(&cfg->ipc_nets, &ipaddr, 8 * cfg->ipsize, false);
552         PARSER_DEBUG_PRINTF("\tIPC host: %s\n", ip_to_string(cfg->ip_version, &buf, &ipaddr));
553       } else if (0 == strcmp("Net", p[0])) {
554         union olsr_ip_addr ipaddr;
555         if (!p[2]) {
556           fprintf(stderr, "Odd args in %s\n", nxt);
557           exit(EXIT_FAILURE);
558         }
559         if (inet_pton(cfg->ip_version, p[1], &ipaddr) <= 0) {
560           fprintf(stderr, "Failed converting IP address %s\n", p[0]);
561           exit(EXIT_FAILURE);
562         }
563         if (AF_INET == cfg->ip_version) {
564           union olsr_ip_addr netmask;
565           if (inet_pton(AF_INET, p[2], &netmask) <= 0) {
566             fprintf(stderr, "Failed converting IP address %s\n", p[2]);
567             exit(EXIT_FAILURE);
568           }
569           if ((ipaddr.v4.s_addr & ~netmask.v4.s_addr) != 0) {
570             fprintf(stderr, "The IP address %s/%s is not a network address!\n", p[1], p[2]);
571             exit(EXIT_FAILURE);
572           }
573           ip_acl_add(&cfg->ipc_nets, &ipaddr, olsr_netmask_to_prefix(&netmask), false);
574           PARSER_DEBUG_PRINTF("\tIPC net: %s/%d\n", ip_to_string(cfg->ip_version, &buf, &ipaddr), olsr_netmask_to_prefix(&netmask));
575         } else {
576           int prefix = -1;
577           sscanf('/' == *p[2] ? p[2] + 1 : p[2], "%d", &prefix);
578           if (0 > prefix || 128 < prefix) {
579             fprintf(stderr, "Illegal IPv6 prefix %s\n", p[2]);
580             exit(EXIT_FAILURE);
581           }
582           ip_acl_add(&cfg->ipc_nets, &ipaddr, prefix, false);
583           PARSER_DEBUG_PRINTF("\tIPC net: %s/%d\n", ip_to_string(cfg->ip_version, &buf, &ipaddr), prefix);
584         }
585         p++;
586       } else {
587         fprintf(stderr, "Unknown arg: %s %s\n", p[0], p[1]);
588         exit(EXIT_FAILURE);
589       }
590       p += 2;
591     }
592     parse_tok_free(tok);
593   }
594 }
595
596 /*
597  * Parses a single loadplugin option block
598  */
599 static void
600 parse_cfg_loadplugin(char *argstr, struct olsr_config *cfg)
601 {
602   char **tok;
603   const char *nxt;
604   if (NULL != (tok = parse_tok(argstr, &nxt))) {
605     if ('{' != *nxt) {
606       fprintf(stderr, "No {}\n");
607       exit(EXIT_FAILURE);
608     } else {
609       char **tok_next = parse_tok(nxt + 1, NULL);
610       struct plugin_entry *pe = olsr_malloc(sizeof(*pe), "plugin");
611       pe->name = olsr_strdup(*tok);
612       pe->params = NULL;
613       pe->next = cfg->plugins;
614       cfg->plugins = pe;
615       PARSER_DEBUG_PRINTF("Plugin: %s\n", pe->name);
616       if (tok_next) {
617         char **p_next = tok_next;
618         while (p_next[0]) {
619           struct plugin_param *pp = olsr_malloc(sizeof(*pp), "plparam");
620           if (0 != strcmp("PlParam", p_next[0]) || !p_next[1] || !p_next[2]) {
621             fprintf(stderr, "Odd args in %s\n", nxt);
622             exit(EXIT_FAILURE);
623           }
624           pp->key = olsr_strdup(p_next[1]);
625           pp->value = olsr_strdup(p_next[2]);
626           pp->next = pe->params;
627           pe->params = pp;
628           PARSER_DEBUG_PRINTF("\tPlParam: %s %s\n", pp->key, pp->value);
629           p_next += 3;
630         }
631         parse_tok_free(tok_next);
632       }
633     }
634     parse_tok_free(tok);
635   } else {
636     fprintf(stderr, "Error in %s\n", argstr);
637     exit(EXIT_FAILURE);
638   }
639 }
640
641 /*
642  * Parses a single loadplugin option block
643  */
644 static void
645 parse_cfg_log(char *argstr, struct olsr_config *cfg)
646 {
647   char *p = (char *)argstr, *nextEquals, *nextColon, *nextSlash;
648   bool hasErrorOption = false;
649   int i, j;
650
651   while (p != NULL && *p != 0) {
652     /* split at ',' */
653     nextColon = strchr(p, ',');
654     if (nextColon) {
655       *nextColon++ = 0;
656     }
657
658     nextEquals = strchr(p, '=');
659     if (nextEquals) {
660       *nextEquals++ = 0;
661     }
662
663     for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
664       if (strcasecmp(p, LOG_SEVERITY_NAMES[j]) == 0) {
665         break;
666       }
667     }
668
669     if (j < LOG_SEVERITY_COUNT) {
670       p = nextEquals;
671       while (p != NULL && *p != 0) {
672         /* split at '/' */
673         nextSlash = strchr(p, '/');
674         if (nextSlash) {
675           *nextSlash++ = 0;
676         }
677
678         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
679           if (strcasecmp(p, LOG_SOURCE_NAMES[i]) == 0) {
680             break;
681           }
682         }
683
684         if (i < LOG_SOURCE_COUNT) {
685           cfg->log_event[j][i] = true;
686         }
687         p = nextSlash;
688       }
689     } else if (strcasecmp(p, "stderr") == 0) {
690       cfg->log_target_stderr = true;
691     } else if (strcasecmp(p, "syslog") == 0) {
692       cfg->log_target_syslog = true;
693     } else if (strcasecmp(p, "file") == 0) {
694       cfg->log_target_file = olsr_strdup(nextEquals);
695     }
696     p = nextColon;
697   }
698
699   /* process results to clean them up */
700
701   /* first handle "all" keyword */
702   for (i = 0; i < LOG_SEVERITY_COUNT; i++) {
703     if (cfg->log_event[i][LOG_ALL]) {
704       for (j = 1; j < LOG_SOURCE_COUNT; j++) {
705         cfg->log_event[i][j] = true;
706       }
707     }
708   }
709
710   /* then copy from info to warn and from warn to error */
711   for (i = 0; i < LOG_SOURCE_COUNT; i++) {
712     if (cfg->log_event[SEVERITY_INFO][i]) {
713       cfg->log_event[SEVERITY_WARN][i] = true;
714     }
715     if (cfg->log_event[SEVERITY_WARN][i]) {
716       cfg->log_event[SEVERITY_ERROR][i] = true;
717     }
718     if (!hasErrorOption) {
719       cfg->log_event[SEVERITY_ERROR][i] = true;
720     }
721   }
722
723   /* choose stderr as target if none activated */
724   if (cfg->log_target_file == NULL && !cfg->log_target_stderr && !cfg->log_target_syslog) {
725     cfg->log_target_stderr = true;
726   }
727 }
728
729 /*
730  * Parses a single option found on the command line
731  */
732 static void
733 parse_cfg_option(const int optint, char *argstr, const int line, struct olsr_config *cfg)
734 {
735   switch (optint) {
736   case 'D':                    /* delgw */
737     cfg->del_gws = true;
738     PARSER_DEBUG_PRINTF("del_gws set to %d\n", cfg->del_gws);
739     break;
740   case 'X':                    /* dispin */
741     PARSER_DEBUG_PRINTF("Calling parser_set_disp_pack_in(true)\n");
742     parser_set_disp_pack_in(true);
743     break;
744   case 'O':                    /* dispout */
745     PARSER_DEBUG_PRINTF("Calling net_set_disp_pack_out(true)\n");
746     net_set_disp_pack_out(true);
747     break;
748   case 'i':                    /* iface */
749     /* Ignored */
750     break;
751 #ifdef WIN32
752   case 'l':                    /* int */
753     ListInterfaces();
754     exit(0);
755 #endif
756   case 'P':                    /* ipc */
757     cfg->ipc_connections = 1;
758     PARSER_DEBUG_PRINTF("IPC connections: %d\n", cfg->ipc_connections);
759     break;
760   case 'n':                    /* nofork */
761     cfg->no_fork = true;
762     PARSER_DEBUG_PRINTF("no_fork set to %d\n", cfg->no_fork);
763     break;
764   case 'v':                    /* version */
765     /* Version string already printed */
766     exit(0);
767   case 'A':                    /* AllowNoInt (yes/no) */
768     cfg->allow_no_interfaces = (0 == strcmp("yes", argstr));
769     PARSER_DEBUG_PRINTF("Noint set to %d\n", cfg->allow_no_interfaces);
770     break;
771   case 'C':                    /* ClearScreen (yes/no) */
772     cfg->clear_screen = (0 == strcmp("yes", argstr));
773     PARSER_DEBUG_PRINTF("Clear screen %s\n", cfg->clear_screen ? "enabled" : "disabled");
774     break;
775   case 'd':                    /* DebugLevel (i) */
776     {
777       int arg = -1;
778       sscanf(argstr, "%d", &arg);
779       if (0 <= arg && arg < 128)
780         cfg->debug_level = arg;
781       PARSER_DEBUG_PRINTF("Debug level: %d\n", cfg->debug_level);
782     }
783     break;
784   case 'F':                    /* FIBMetric (str) */
785     {
786       char **tok;
787       if (NULL != (tok = parse_tok(argstr, NULL))) {
788         if (strcmp(*tok, CFG_FIBM_FLAT) == 0) {
789           cfg->fib_metric = FIBM_FLAT;
790         } else if (strcmp(*tok, CFG_FIBM_CORRECT) == 0) {
791           cfg->fib_metric = FIBM_CORRECT;
792         } else if (strcmp(*tok, CFG_FIBM_APPROX) == 0) {
793           cfg->fib_metric = FIBM_APPROX;
794         } else {
795           fprintf(stderr, "FIBMetric must be \"%s\", \"%s\", or \"%s\"!\n", CFG_FIBM_FLAT, CFG_FIBM_CORRECT, CFG_FIBM_APPROX);
796           exit(EXIT_FAILURE);
797         }
798         parse_tok_free(tok);
799       } else {
800         fprintf(stderr, "Error in %s\n", argstr);
801         exit(EXIT_FAILURE);
802       }
803       PARSER_DEBUG_PRINTF("FIBMetric: %d=%s\n", cfg->fib_metric, argstr);
804     }
805     break;
806   case '4':                    /* Hna4 (4body) */
807     parse_cfg_hna(argstr, AF_INET, cfg);
808     break;
809   case '6':                    /* Hna6 (6body) */
810     parse_cfg_hna(argstr, AF_INET6, cfg);
811     break;
812   case 'I':                    /* Interface if1 if2 { ifbody } */
813     parse_cfg_interface(argstr, cfg);
814     break;
815   case 'Q':                    /* IpcConnect (Host,Net,MaxConnections) */
816     parse_cfg_ipc(argstr, cfg);
817     break;
818   case 'V':                    /* IpVersion (i) */
819     {
820       int ver = -1;
821       sscanf(argstr, "%d", &ver);
822       if (ver == 4) {
823         cfg->ip_version = AF_INET;
824         cfg->ipsize = sizeof(struct in_addr);
825       } else if (ver == 6) {
826         cfg->ip_version = AF_INET6;
827         cfg->ipsize = sizeof(struct in6_addr);
828       } else {
829         fprintf(stderr, "IpVersion must be 4 or 6!\n");
830         exit(EXIT_FAILURE);
831       }
832     }
833     PARSER_DEBUG_PRINTF("IpVersion: %d\n", cfg->ip_version);
834     break;
835   case 'J':                    /* LinkQualityDijkstraLimit (i,f) */
836     {
837       int arg = -1;
838       sscanf(argstr, "%d %f", &arg, &cfg->lq_dinter);
839       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->lq_dlimit))))
840         cfg->lq_dlimit = arg;
841       PARSER_DEBUG_PRINTF("Link quality dijkstra limit %d, %0.2f\n", cfg->lq_dlimit, cfg->lq_dinter);
842     }
843     break;
844   case 'E':                    /* LinkQualityFishEye (i) */
845     {
846       int arg = -1;
847       sscanf(argstr, "%d", &arg);
848       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->lq_fish))))
849         cfg->lq_fish = arg;
850       PARSER_DEBUG_PRINTF("Link quality fish eye %d\n", cfg->lq_fish);
851     }
852     break;
853   case 'p':                    /* LoadPlugin (soname {PlParams}) */
854     parse_cfg_loadplugin(argstr, cfg);
855     break;
856   case 'M':                    /* MprCoverage (i) */
857     {
858       int arg = -1;
859       sscanf(argstr, "%d", &arg);
860       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->mpr_coverage))))
861         cfg->mpr_coverage = arg;
862       PARSER_DEBUG_PRINTF("MPR coverage %d\n", cfg->mpr_coverage);
863     }
864     break;
865   case 'N':                    /* NatThreshold (f) */
866     sscanf(argstr, "%f", &cfg->lq_nat_thresh);
867     PARSER_DEBUG_PRINTF("NAT threshold %0.2f\n", cfg->lq_nat_thresh);
868     break;
869   case 'Y':                    /* NicChgsPollInt (f) */
870     sscanf(argstr, "%f", &cfg->nic_chgs_pollrate);
871     PARSER_DEBUG_PRINTF("NIC Changes Pollrate %0.2f\n", cfg->nic_chgs_pollrate);
872     break;
873   case 'T':                    /* Pollrate (f) */
874     {
875       float arg = -1;
876       sscanf(argstr, "%f", &arg);
877       if (0 <= arg)
878         cfg->pollrate = conv_pollrate_to_microsecs(arg);
879       PARSER_DEBUG_PRINTF("Pollrate %u\n", cfg->pollrate);
880     }
881     break;
882   case 'q':                    /* RtProto (i) */
883     {
884       int arg = -1;
885       sscanf(argstr, "%d", &arg);
886       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->rtproto))))
887         cfg->rtproto = arg;
888       PARSER_DEBUG_PRINTF("RtProto: %d\n", cfg->rtproto);
889     }
890     break;
891   case 'R':                    /* RtTableDefault (i) */
892     {
893       int arg = -1;
894       sscanf(argstr, "%d", &arg);
895       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->rttable_default))))
896         cfg->rttable_default = arg;
897       PARSER_DEBUG_PRINTF("RtTableDefault: %d\n", cfg->rttable_default);
898     }
899     break;
900   case 'r':                    /* RtTable (i) */
901     {
902       int arg = -1;
903       sscanf(argstr, "%d", &arg);
904       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->rttable))))
905         cfg->rttable = arg;
906       PARSER_DEBUG_PRINTF("RtTable: %d\n", cfg->rttable);
907     }
908     break;
909   case 't':                    /* TcRedundancy (i) */
910     {
911       int arg = -1;
912       sscanf(argstr, "%d", &arg);
913       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->tc_redundancy))))
914         cfg->tc_redundancy = arg;
915       PARSER_DEBUG_PRINTF("TC redundancy %d\n", cfg->tc_redundancy);
916     }
917     break;
918   case 'Z':                    /* TosValue (i) */
919     {
920       int arg = -1;
921       sscanf(argstr, "%d", &arg);
922       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->tos))))
923         cfg->tos = arg;
924       PARSER_DEBUG_PRINTF("TOS: %d\n", cfg->tos);
925     }
926     break;
927   case 'w':                    /* Willingness (i) */
928     {
929       int arg = -1;
930       sscanf(argstr, "%d", &arg);
931       if (0 <= arg && arg < (1 << (8 * sizeof(cfg->willingness))))
932         cfg->willingness = arg;
933       cfg->willingness_auto = false;
934       PARSER_DEBUG_PRINTF("Willingness: %d (no auto)\n", cfg->willingness);
935     }
936     break;
937   case 'L':                    /* Log (string) */
938     parse_cfg_log(argstr, cfg);
939     break;
940   default:
941     fprintf(stderr, "Unknown arg in line %d.\n", line);
942     exit(EXIT_FAILURE);
943   }                             /* switch */
944 }
945
946 /*
947  * Parses command line options using the getopt() runtime
948  * function. May also replace a "-f filename" combination
949  * with options read in from a config file.
950  */
951 struct olsr_config *
952 olsr_parse_cfg(int argc, char *argv[], const char *conf_file_name)
953 {
954   int opt;
955   int opt_idx = 0;
956   char *opt_str = 0;
957   int opt_argc = 0;
958   char **opt_argv = olsr_malloc(argc * sizeof(opt_argv[0]), "opt_argv");
959   int *opt_line = olsr_malloc(argc * sizeof(opt_line[0]), "opt_line");
960   struct olsr_config *cfg = olsr_get_default_cfg();
961
962   /*
963    * Original cmd line params
964    *
965    * -bcast                   (removed)
966    * -delgw                   (-> --delgw)
967    * -dispin                  (-> --dispin)
968    * -dispout                 (-> --dispout)
969    * -d (level)               (preserved)
970    * -f (config)              (preserved)
971    * -hemu (queue_if(hcif01)) (-> --hemu)
972    * -hint                    (removed)
973    * -hnaint                  (removed)
974    * -i if0 if1...            (see comment below)
975    * -int (WIN32)             (preserved)
976    * -ipc (ipc conn = 1)      (-> --ipc)
977    * -ipv6                    (-> -V or --IpVersion)
978    * -lqa (lq aging)          (removed)
979    * -lql (lq lev)            (removed)
980    * -lqnt (lq nat)           (removed)
981    * -midint                  (removed)
982    * -multi (ipv6 mcast)      (removed)
983    * -nofork                  (preserved)
984    * -tcint                   (removed)
985    * -T (pollrate)            (preserved)
986    *
987    * Note: Remaining args are interpreted as list of
988    * interfaces. For this reason, '-i' is ignored which
989    * adds the following non-minus args to the list.
990    */
991
992   /* *INDENT-OFF* */
993   static struct option long_options[] = {
994     {"config",                   required_argument, 0, 'f'}, /* (filename) */
995     {"delgw",                    no_argument,       0, 'D'},
996     {"dispin",                   no_argument,       0, 'X'},
997     {"dispout",                  no_argument,       0, 'O'},
998     {"help",                     no_argument,       0, 'h'},
999     {"iface",                    no_argument,       0, 'i'}, /* if0 if1... */
1000 #ifdef WIN32
1001     {"int",                      no_argument,       0, 'l'},
1002 #endif
1003     {"ipc",                      no_argument,       0, 'P'},
1004     {"log",                      required_argument, 0, 'L'}, /* info=src1/...,warn=src3/... */
1005     {"nofork",                   no_argument,       0, 'n'},
1006     {"version",                  no_argument,       0, 'v'},
1007     {"AllowNoInt",               required_argument, 0, 'A'}, /* (yes/no) */
1008     {"ClearScreen",              required_argument, 0, 'C'}, /* (yes/no) */
1009     {"DebugLevel",               required_argument, 0, 'd'}, /* (i) */
1010     {"FIBMetric",                required_argument, 0, 'F'}, /* (str) */
1011     {"Hna4",                     required_argument, 0, '4'}, /* (4body) */
1012     {"Hna6",                     required_argument, 0, '6'}, /* (6body) */
1013     {"Interface",                required_argument, 0, 'I'}, /* (if1 if2 {ifbody}) */
1014     {"IpcConnect",               required_argument, 0, 'Q'}, /* (Host,Net,MaxConnections) */
1015     {"IpVersion",                required_argument, 0, 'V'}, /* (i) */
1016     {"LinkQualityDijkstraLimit", required_argument, 0, 'J'}, /* (i,f) */
1017     {"LinkQualityFishEye",       required_argument, 0, 'E'}, /* (i) */
1018     {"LoadPlugin",               required_argument, 0, 'p'}, /* (soname {PlParams}) */
1019     {"MprCoverage",              required_argument, 0, 'M'}, /* (i) */
1020     {"NatThreshold",             required_argument, 0, 'N'}, /* (f) */
1021     {"NicChgsPollInt",           required_argument, 0, 'Y'}, /* (f) */
1022     {"Pollrate",                 required_argument, 0, 'T'}, /* (f) */
1023     {"RtProto",                  required_argument, 0, 'q'}, /* (i) */
1024     {"RtTableDefault",           required_argument, 0, 'R'}, /* (i) */
1025     {"RtTable",                  required_argument, 0, 'r'}, /* (i) */
1026     {"TcRedundancy",             required_argument, 0, 't'}, /* (i) */
1027     {"TosValue",                 required_argument, 0, 'Z'}, /* (i) */
1028     {"Willingness",              required_argument, 0, 'w'}, /* (i) */
1029     {"UseHysteresis",            required_argument, 0,  0 }, /* ignored */
1030     {"HystScaling",              required_argument, 0,  0 }, /* ignored */
1031     {"HystThrHigh",              required_argument, 0,  0 }, /* ignored */
1032     {"HystThrLow",               required_argument, 0,  0 }, /* ignored */
1033     {"LinkQualityLevel",         required_argument, 0,  0 }, /* ignored */
1034     {"LinkQualityWinsize",       required_argument, 0,  0 }, /* ignored */
1035     {"LinkQualityAlgorithm",     required_argument, 0,  0 }, /* ignored */
1036     {"LinkQualityAging",         required_argument, 0,  0 }, /* ignored */
1037     {0, 0, 0, 0}
1038   }, *popt = long_options;
1039   /* *INDENT-ON* */
1040
1041   /*
1042    * olsr_malloc() uses calloc, so opt_line is already filled
1043    * memset(opt_line, 0, argc * sizeof(opt_line[0]));
1044    */
1045
1046   /* Copy argv array for safe free'ing later on */
1047   while (opt_argc < argc) {
1048     const char *p = argv[opt_argc];
1049     if (0 == strcmp(p, "-nofork"))
1050       p = "-n";
1051 #ifdef WIN32
1052     else if (0 == strcmp(p, "-int"))
1053       p = "-l";
1054 #endif
1055     opt_argv[opt_argc] = olsr_strdup(p);
1056     opt_argc++;
1057   }
1058
1059   /* get option count */
1060   for (opt_idx = 0; long_options[opt_idx].name; opt_idx++);
1061
1062   /* Calculate short option string */
1063   opt_str = olsr_malloc(opt_idx * 3, "create short opt_string");
1064   opt_idx = 0;
1065   while (popt->name) {
1066     if (popt->val) {
1067       opt_str[opt_idx++] = popt->val;
1068
1069       switch (popt->has_arg) {
1070       case optional_argument:
1071         opt_str[opt_idx++] = ':';
1072         /* Fall through */
1073       case required_argument:
1074         opt_str[opt_idx++] = ':';
1075         break;
1076       }
1077     }
1078     popt++;
1079   }
1080
1081   /* If no arguments, revert to default behaviour */
1082   if (1 == opt_argc) {
1083     char *argv0_tmp = opt_argv[0];
1084     free(opt_argv);
1085     opt_argv = olsr_malloc(3 * sizeof(opt_argv[0]), "default argv");
1086     opt_argv[0] = argv0_tmp;
1087     opt_argv[1] = olsr_strdup("-f");
1088     opt_argv[2] = olsr_strdup(conf_file_name);
1089     opt_argc = 3;
1090   }
1091
1092   while (0 <= (opt = getopt_long(opt_argc, opt_argv, opt_str, long_options, &opt_idx))) {
1093     switch (opt) {
1094     case 0:
1095       fprintf(stderr, "Warning: ignored deprecated %s\n", long_options[opt_idx].name);
1096       break;
1097     case 'f':                  /* config (filename) */
1098       PARSER_DEBUG_PRINTF("Read config from %s\n", optarg);
1099       if (0 > read_cfg(optarg, &opt_argc, &opt_argv, &opt_line)) {
1100         fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", optarg, strerror(errno));
1101         exit(EXIT_FAILURE);
1102       }
1103       break;
1104     case 'h':                  /* help */
1105       popt = long_options;
1106       printf("Usage: olsrd [OPTIONS]... [interfaces]...\n");
1107       while (popt->name) {
1108         if (' ' <= popt->val) {
1109           printf("-%c or --%s ", popt->val, popt->name);
1110           switch (popt->has_arg) {
1111           case required_argument:
1112             printf("arg");
1113             break;
1114           case optional_argument:
1115             printf("[arg]");
1116             break;
1117           }
1118           printf("\n");
1119         }
1120         popt++;
1121       }
1122       exit(0);
1123     default:
1124       parse_cfg_option(opt, optarg, opt_line[optind], cfg);
1125     }                           /* switch(opt) */
1126   }                             /* while getopt_long() */
1127
1128   while (optind < opt_argc) {
1129     PARSER_DEBUG_PRINTF("new interface %s\n", opt_argv[optind]);
1130     queue_if(opt_argv[optind++], cfg);
1131   }
1132
1133   /* Some cleanup */
1134   while (0 < opt_argc) {
1135     free(opt_argv[--opt_argc]);
1136   }
1137   free(opt_argv);
1138   free(opt_line);
1139   free(opt_str);
1140
1141   return cfg;
1142 }
1143
1144 /*
1145  * Checks a given config for illegal values
1146  */
1147 int
1148 olsr_sanity_check_cfg(struct olsr_config *cfg)
1149 {
1150   struct olsr_if_config *in = cfg->if_configs;
1151   struct olsr_if_options *io;
1152
1153   /* Debug level */
1154   if (cfg->debug_level < MIN_DEBUGLVL || cfg->debug_level > MAX_DEBUGLVL) {
1155     fprintf(stderr, "Debuglevel %d is not allowed\n", cfg->debug_level);
1156     return -1;
1157   }
1158
1159   /* IP version */
1160   if (cfg->ip_version != AF_INET && cfg->ip_version != AF_INET6) {
1161     fprintf(stderr, "Ipversion %d not allowed!\n", cfg->ip_version);
1162     return -1;
1163   }
1164
1165   /* TOS */
1166   if (cfg->tos > MAX_TOS) {
1167     fprintf(stderr, "TOS %d is not allowed\n", cfg->tos);
1168     return -1;
1169   }
1170
1171   /* Willingness */
1172   if (cfg->willingness_auto == false && (cfg->willingness > MAX_WILLINGNESS)) {
1173     fprintf(stderr, "Willingness %d is not allowed\n", cfg->willingness);
1174     return -1;
1175   }
1176
1177   /* Check Link quality dijkstra limit */
1178   if (cfg->lq_dinter < conv_pollrate_to_secs(cfg->pollrate) && cfg->lq_dlimit != 255) {
1179     fprintf(stderr, "Link quality dijkstra limit must be higher than pollrate\n");
1180     return -1;
1181   }
1182
1183   /* NIC Changes Pollrate */
1184   if (cfg->nic_chgs_pollrate < MIN_NICCHGPOLLRT || cfg->nic_chgs_pollrate > MAX_NICCHGPOLLRT) {
1185     fprintf(stderr, "NIC Changes Pollrate %0.2f is not allowed\n", cfg->nic_chgs_pollrate);
1186     return -1;
1187   }
1188
1189   /* TC redundancy */
1190   if (cfg->tc_redundancy > MAX_TC_REDUNDANCY) {
1191     fprintf(stderr, "TC redundancy %d is not allowed\n", cfg->tc_redundancy);
1192     return -1;
1193   }
1194
1195   /* MPR coverage */
1196   if (cfg->mpr_coverage < MIN_MPR_COVERAGE || cfg->mpr_coverage > MAX_MPR_COVERAGE) {
1197     fprintf(stderr, "MPR coverage %d is not allowed\n", cfg->mpr_coverage);
1198     return -1;
1199   }
1200
1201   /* NAT threshold value */
1202   if (cfg->lq_nat_thresh < 0.1 || cfg->lq_nat_thresh > 1.0) {
1203     fprintf(stderr, "NAT threshold %f is not allowed\n", cfg->lq_nat_thresh);
1204     return -1;
1205   }
1206
1207   if (in == NULL) {
1208     fprintf(stderr, "No interfaces configured!\n");
1209     return -1;
1210   }
1211
1212   /* Interfaces */
1213   while (in) {
1214     io = in->cnf;
1215
1216     if (in->name == NULL || !strlen(in->name)) {
1217       fprintf(stderr, "Interface has no name!\n");
1218       return -1;
1219     }
1220
1221     if (io == NULL) {
1222       fprintf(stderr, "Interface %s has no configuration!\n", in->name);
1223       return -1;
1224     }
1225
1226     /* HELLO interval */
1227
1228     if (io->hello_params.emission_interval < conv_pollrate_to_secs(cfg->pollrate) ||
1229         io->hello_params.emission_interval > io->hello_params.validity_time) {
1230       fprintf(stderr, "Bad HELLO parameters! (em: %0.2f, vt: %0.2f)\n", io->hello_params.emission_interval,
1231               io->hello_params.validity_time);
1232       return -1;
1233     }
1234
1235     /* TC interval */
1236     if (io->tc_params.emission_interval < conv_pollrate_to_secs(cfg->pollrate) ||
1237         io->tc_params.emission_interval > io->tc_params.validity_time) {
1238       fprintf(stderr, "Bad TC parameters! (em: %0.2f, vt: %0.2f)\n", io->tc_params.emission_interval, io->tc_params.validity_time);
1239       return -1;
1240     }
1241
1242     /* MID interval */
1243     if (io->mid_params.emission_interval < conv_pollrate_to_secs(cfg->pollrate) ||
1244         io->mid_params.emission_interval > io->mid_params.validity_time) {
1245       fprintf(stderr, "Bad MID parameters! (em: %0.2f, vt: %0.2f)\n", io->mid_params.emission_interval,
1246               io->mid_params.validity_time);
1247       return -1;
1248     }
1249
1250     /* HNA interval */
1251     if (io->hna_params.emission_interval < conv_pollrate_to_secs(cfg->pollrate) ||
1252         io->hna_params.emission_interval > io->hna_params.validity_time) {
1253       fprintf(stderr, "Bad HNA parameters! (em: %0.2f, vt: %0.2f)\n", io->hna_params.emission_interval,
1254               io->hna_params.validity_time);
1255       return -1;
1256     }
1257
1258     in = in->next;
1259   }
1260
1261   return 0;
1262 }
1263
1264 /*
1265  * Free resources occupied by a configuration
1266  */
1267 void
1268 olsr_free_cfg(struct olsr_config *cfg)
1269 {
1270   struct olsr_if_config *ind, *in = cfg->if_configs;
1271   struct plugin_entry *ped, *pe = cfg->plugins;
1272   struct olsr_lq_mult *mult, *next_mult;
1273
1274   /* free logfile string if necessary */
1275   if (cfg->log_target_file) {
1276     free(cfg->log_target_file);
1277   }
1278
1279   /*
1280    * Free HNAs.
1281    */
1282   ip_prefix_list_flush(&cfg->hna_entries);
1283
1284   /*
1285    * Free IPCs.
1286    */
1287   ip_acl_flush(&cfg->ipc_nets);
1288
1289   /*
1290    * Free Interfaces - remove_interface() already called
1291    */
1292   while (in) {
1293     for (mult = in->cnf->lq_mult; mult != NULL; mult = next_mult) {
1294       next_mult = mult->next;
1295       free(mult);
1296     }
1297
1298     free(in->cnf);
1299     ind = in;
1300     in = in->next;
1301     free(ind->name);
1302     if (ind->config)
1303       free(ind->config);
1304     free(ind);
1305   }
1306
1307   /*
1308    * Free Plugins - olsr_close_plugins() allready called
1309    */
1310   while (pe) {
1311     struct plugin_param *pard, *par = pe->params;
1312     while (par) {
1313       pard = par;
1314       par = par->next;
1315       free(pard->key);
1316       free(pard->value);
1317       free(pard);
1318     }
1319     ped = pe;
1320     pe = pe->next;
1321     free(ped->name);
1322     free(ped);
1323   }
1324
1325   free(cfg);
1326
1327   return;
1328 }
1329
1330 /*
1331  * Get a default config
1332  */
1333 struct olsr_config *
1334 olsr_get_default_cfg(void)
1335 {
1336   struct olsr_config *cfg = olsr_malloc(sizeof(struct olsr_config), "default config");
1337
1338   /*
1339    * olsr_malloc calls calloc(), no memset necessary:
1340    * memset(cfg, 0, sizeof(*cfg));
1341    */
1342
1343   cfg->debug_level = DEF_DEBUGLVL;
1344   cfg->no_fork = false;
1345   cfg->ip_version = AF_INET;
1346   cfg->ipsize = sizeof(struct in_addr);
1347   cfg->allow_no_interfaces = DEF_ALLOW_NO_INTS;
1348   cfg->tos = DEF_TOS;
1349   cfg->rtproto = 0;
1350   cfg->rttable = 254;
1351   cfg->rttable_default = 0;
1352   cfg->willingness_auto = DEF_WILL_AUTO;
1353   cfg->ipc_connections = DEF_IPC_CONNECTIONS;
1354   cfg->fib_metric = DEF_FIB_METRIC;
1355
1356   cfg->pollrate = conv_pollrate_to_microsecs(DEF_POLLRATE);
1357   cfg->nic_chgs_pollrate = DEF_NICCHGPOLLRT;
1358
1359   cfg->tc_redundancy = TC_REDUNDANCY;
1360   cfg->mpr_coverage = MPR_COVERAGE;
1361   cfg->lq_fish = DEF_LQ_FISH;
1362   cfg->lq_dlimit = DEF_LQ_DIJK_LIMIT;
1363   cfg->lq_dinter = DEF_LQ_DIJK_INTER;
1364   cfg->lq_nat_thresh = DEF_LQ_NAT_THRESH;
1365   cfg->clear_screen = DEF_CLEAR_SCREEN;
1366
1367   cfg->del_gws = false;
1368   cfg->will_int = 10 * HELLO_INTERVAL;
1369   cfg->exit_value = EXIT_SUCCESS;
1370   cfg->max_tc_vtime = 0.0;
1371   cfg->ioctl_s = 0;
1372
1373   list_head_init(&cfg->hna_entries);
1374   ip_acl_init(&cfg->ipc_nets);
1375
1376 #if defined linux
1377   cfg->rts_linux = 0;
1378 #endif
1379 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
1380   cfg->rts_bsd = 0;
1381 #endif
1382   return cfg;
1383 }
1384
1385 /*
1386  * Local Variables:
1387  * c-basic-offset: 2
1388  * indent-tabs-mode: nil
1389  * End:
1390  */