f98c860948d05ae92be3486bb83105ae8f483dfd
[olsrd.git] / src / olsr_cfg.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 #include "olsr_cfg_data.h"
44
45 #include "olsr.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 #include "olsr_protocol.h"
52 #include "common/string.h"
53 #include "olsr_time.h"
54
55 #include <unistd.h>
56 #include <string.h>
57 #include <sys/types.h>
58 #include <sys/socket.h>
59 #include <arpa/inet.h>
60 #include <getopt.h>
61 #include <errno.h>
62 #include <assert.h>
63
64 #ifdef DEBUG
65 #define PARSER_DEBUG_PRINTF(x, args...)   printf(x, ##args)
66 #else
67 #define PARSER_DEBUG_PRINTF(x, ...)   do { } while (0)
68 #endif
69
70 /* options that have no short command line variant */
71 enum cfg_long_options {
72   CFG_LOG_DEBUG = 256,
73   CFG_LOG_INFO,
74   CFG_LOG_WARN,
75   CFG_LOG_ERROR,
76   CFG_LOG_STDERR,
77   CFG_LOG_SYSLOG,
78   CFG_LOG_FILE,
79
80   CFG_OLSRPORT,
81   CFG_DLPATH,
82
83   CFG_HTTPPORT,
84   CFG_HTTPLIMIT,
85   CFG_TXTPORT,
86   CFG_TXTLIMIT,
87
88   CFG_HNA_HTIME,
89   CFG_HNA_VTIME,
90   CFG_MID_HTIME,
91   CFG_MID_VTIME,
92   CFG_TC_HTIME,
93   CFG_TC_VTIME,
94 };
95
96 /* remember which log severities have been explicitly set */
97 static bool cfg_has_log[LOG_SEVERITY_COUNT];
98
99 /*
100  * Special strcat for reading the config file and
101  * joining a longer section { ... } to one string
102  */
103 static void
104 read_cfg_cat(char **pdest, const char *src)
105 {
106   char *tmp = *pdest;
107   if (*src) {
108     size_t size = 1 + (tmp ? strlen(tmp) : 0) + strlen(src);
109     *pdest = olsr_malloc(size, "read_cfg_cat");
110     assert(0 == **pdest);
111     if (tmp) {
112       strscpy(*pdest, tmp, size);
113       free(tmp);
114     }
115     strscat(*pdest, src, size);
116   }
117 }
118
119 /*
120  * Read the olsrd.conf file and replace/insert found
121  * options into the argv[] array at the position of
122  * the original -f filename parameters. Note, that
123  * longer sections { ... } are joined to one string
124  */
125 static int
126 read_cfg(const char *filename, int *pargc, char ***pargv, int **pline)
127 {
128   FILE *f = fopen(filename, "r");
129   if (f) {
130     int bopen = 0, optind_tmp = optind, line_lst = 0, line = 0;
131     char sbuf[512], *pbuf = NULL, *p;
132
133     while ((p = fgets(sbuf, sizeof(sbuf), f)) || pbuf) {
134       line++;
135       if (!p) {
136         *sbuf = 0;
137         goto eof;
138       }
139       while (*p && '#' != *p) {
140         if ('"' == *p || '\'' == *p) {
141           char sep = *p;
142           while (*++p && sep != *p);
143         }
144         p++;
145       }
146       *p = 0;
147       while (sbuf <= --p && ' ' >= *p);
148       *(p + 1) = 0;
149       if (*sbuf) {
150         if (bopen) {
151           read_cfg_cat(&pbuf, sbuf);
152           if ('}' == *p) {
153             bopen = 0;
154           }
155         } else if (p == sbuf && '{' == *p) {
156           read_cfg_cat(&pbuf, " ");
157           read_cfg_cat(&pbuf, sbuf);
158           bopen = 1;
159         } else {
160           if ('{' == *p) {
161             bopen = 1;
162           }
163         eof:
164           if (pbuf) {
165             int i, *line_tmp;
166             char **argv_tmp;
167             int argc_tmp = *pargc + 2;
168             char *q = pbuf, *n;
169             size_t size;
170
171             while (*q && ' ' >= *q)
172               q++;
173             p = q;
174             while (' ' < *p)
175               p++;
176             size = p - q + 3;
177             n = olsr_malloc(size, "config arg0");
178             strscpy(n, "--", size);
179             strscat(n, q, size);
180             while (*q && ' ' >= *p)
181               p++;
182
183             line_tmp = olsr_malloc((argc_tmp+1) * sizeof(line_tmp[0]), "config line");
184             argv_tmp = olsr_malloc((argc_tmp+1) * sizeof(argv_tmp[0]), "config args");
185             for (i = 0; i < argc_tmp; i++) {
186               if (i < optind_tmp) {
187                 line_tmp[i] = (*pline)[i];
188                 argv_tmp[i] = (*pargv)[i];
189               } else if (i == optind_tmp) {
190                 line_tmp[i] = line_lst;
191                 argv_tmp[i] = n;
192               } else if (i == 1 + optind_tmp) {
193                 line_tmp[i] = line_lst;
194                 argv_tmp[i] = olsr_strdup(p);
195               } else {
196                 line_tmp[i] = (*pline)[i - 2];
197                 argv_tmp[i] = (*pargv)[i - 2];
198               }
199             }
200             optind_tmp += 2;
201             *pargc = argc_tmp;
202             free(*pargv);
203             *pargv = argv_tmp;
204             free(*pline);
205             *pline = line_tmp;
206             line_lst = line;
207             free(pbuf);
208             pbuf = NULL;
209           }
210           read_cfg_cat(&pbuf, sbuf);
211         }
212       }
213     }
214     fclose(f);
215     return 0;
216   }
217   return -1;
218 }
219
220 /*
221  * Free an array of string tokens
222  */
223 static void
224 parse_tok_free(char **s)
225 {
226   if (s) {
227     char **p = s;
228     while (*p) {
229       free(*p);
230       p++;
231     }
232     free(s);
233   }
234 }
235
236 /*
237  * Test for end-of-string or { ... } section
238  */
239 static inline bool
240 parse_tok_delim(const char *p)
241 {
242   switch (*p) {
243   case 0:
244   case '{':
245   case '}':
246     return true;
247   }
248   return false;
249 }
250
251 /*
252  * Slit the src string into tokens and return
253  * an array of token strings. May return NULL
254  * if no token found, otherwise you need to
255  * free the strings using parse_tok_free()
256  */
257 static char **
258 parse_tok(const char *s, const char **snext)
259 {
260   char **tmp, **ret = NULL;
261   int i, count = 0;
262   const char *p = s;
263
264   while (!parse_tok_delim(p)) {
265     while (!parse_tok_delim(p) && ' ' >= *p)
266       p++;
267     if (!parse_tok_delim(p)) {
268       char c = 0;
269       const char *q = p;
270       if ('"' == *p || '\'' == *p) {
271         c = *q++;
272         while (!parse_tok_delim(++p) && c != *p);
273       } else {
274         while (!parse_tok_delim(p) && ' ' < *p)
275           p++;
276       }
277       tmp = ret;
278       ret = olsr_malloc((2 + count) * sizeof(ret[0]), "parse_tok");
279       for (i = 0; i < count; i++) {
280         ret[i] = tmp[i];
281       }
282       if (tmp)
283         free(tmp);
284       ret[count++] = olsr_strndup(q, p - q);
285       ret[count] = NULL;
286       if (c)
287         p++;
288     }
289   }
290   if (snext)
291     *snext = p;
292   return ret;
293 }
294
295 /*
296  * Returns default interface options
297  */
298 struct olsr_if_options *
299 olsr_get_default_if_options(void)
300 {
301   struct olsr_if_options *new_io = olsr_malloc(sizeof(*new_io), "default_if_config");
302
303   /* No memset because olsr_malloc uses calloc() */
304   /* memset(&new_io->ipv4_broadcast, 0, sizeof(new_io->ipv4_broadcast)); */
305   new_io->ipv6_addrtype = OLSR_IP6T_AUTO;
306   inet_pton(AF_INET6, OLSR_IPV6_MCAST_SITE_LOCAL, &new_io->ipv6_multi_site.v6);
307   inet_pton(AF_INET6, OLSR_IPV6_MCAST_GLOBAL, &new_io->ipv6_multi_glbl.v6);
308   /* new_io->weight.fixed = false; */
309   /* new_io->weight.value = 0; */
310   new_io->hello_params.emission_interval = HELLO_INTERVAL;
311   new_io->hello_params.validity_time = NEIGHB_HOLD_TIME;
312   /* new_io->lq_mult = NULL; */
313   new_io->autodetect_chg = true;
314   new_io->mode = IF_MODE_MESH;
315   return new_io;
316 }
317
318 /**
319  * Create a new interf_name struct using a given
320  * name and insert it into the interface list.
321  */
322 static struct olsr_if_config *
323 queue_if(const char *name, struct olsr_config *cfg)
324 {
325   struct olsr_if_config *new_if;
326
327   /* check if the interface already exists */
328   for (new_if = cfg->if_configs; new_if != NULL; new_if = new_if->next) {
329     if (0 == strcasecmp(new_if->name, name)) {
330       fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
331       return NULL;
332     }
333   }
334
335   new_if = olsr_malloc(sizeof(*new_if), "queue interface");
336   new_if->name = olsr_strdup(name);
337   /* new_if->config = NULL; */
338   /* memset(&new_if->hemu_ip, 0, sizeof(new_if->hemu_ip)); */
339   /* new_if->interf = NULL; */
340   new_if->cnf = olsr_get_default_if_options();
341   new_if->next = cfg->if_configs;
342   cfg->if_configs = new_if;
343
344   return new_if;
345 }
346
347 /*
348  * Parses a single hna option block
349  * @argstr:     arguments string
350  * @ip_version: AF_INET of AF_INET6
351  * @rcfg:       config struct to write/change values into
352  * @rmsg:       a buf[FILENAME_MAX + 256] to sprint err msgs
353  * @returns configuration status as defined in olsr_parse_cfg_result
354  */
355 static olsr_parse_cfg_result
356 parse_cfg_hna(char *argstr, const int ip_version, struct olsr_config *rcfg, char *rmsg)
357 {
358   char **tok;
359 #ifdef DEBUG
360   struct ipaddr_str buf;
361 #endif
362   if ('{' != *argstr) {
363     sprintf(rmsg, "No {}\n");
364     return CFG_ERROR;
365   }
366   if (NULL != (tok = parse_tok(argstr + 1, NULL))) {
367     char **p = tok;
368     if (ip_version != rcfg->ip_version) {
369       sprintf(rmsg, "IPv%d addresses can only be used if \"IpVersion\" == %d\n",
370               AF_INET == ip_version ? 4 : 6, AF_INET == ip_version ? 4 : 6);
371       parse_tok_free(tok);
372       return CFG_ERROR;
373     }
374     while (p[0]) {
375       union olsr_ip_addr ipaddr;
376       if (!p[1]) {
377         sprintf(rmsg, "Odd args in %s\n", argstr);
378         parse_tok_free(tok);
379         return CFG_ERROR;
380       }
381       if (inet_pton(ip_version, p[0], &ipaddr) <= 0) {
382         sprintf(rmsg, "Failed converting IP address %s\n", p[0]);
383         parse_tok_free(tok);
384         return CFG_ERROR;
385       }
386       if (AF_INET == ip_version) {
387         union olsr_ip_addr netmask;
388         if (inet_pton(AF_INET, p[1], &netmask) <= 0) {
389           sprintf(rmsg, "Failed converting IP address %s\n", p[1]);
390           parse_tok_free(tok);
391           return CFG_ERROR;
392         }
393         if ((ipaddr.v4.s_addr & ~netmask.v4.s_addr) != 0) {
394           sprintf(rmsg, "The IP address %s/%s is not a network address!\n", p[0], p[1]);
395           parse_tok_free(tok);
396           return CFG_ERROR;
397         }
398         ip_prefix_list_add(&rcfg->hna_entries, &ipaddr, netmask_to_prefix((uint8_t *) & netmask, rcfg->ipsize));
399         PARSER_DEBUG_PRINTF("Hna4 %s/%d\n", ip_to_string(rcfg->ip_version, &buf, &ipaddr),
400                             netmask_to_prefix((uint8_t *) & netmask, rcfg->ipsize));
401       } else {
402         int prefix = -1;
403         sscanf('/' == *p[1] ? p[1] + 1 : p[1], "%d", &prefix);
404         if (0 > prefix || 128 < prefix) {
405           sprintf(rmsg, "Illegal IPv6 prefix %s\n", p[1]);
406           parse_tok_free(tok);
407           return CFG_ERROR;
408         }
409         ip_prefix_list_add(&rcfg->hna_entries, &ipaddr, prefix);
410         PARSER_DEBUG_PRINTF("Hna6 %s/%d\n", ip_to_string(rcfg->ip_version, &buf, &ipaddr), prefix);
411       }
412       p += 2;
413     }
414     parse_tok_free(tok);
415   }
416   return CFG_OK;
417 }
418
419 /*
420  * Parses a single interface option block
421  * @argstr:     arguments string
422  * @rcfg:       config struct to write/change values into
423  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
424  * @returns configuration status as defined in olsr_parse_cfg_result
425  */
426 static olsr_parse_cfg_result
427 parse_cfg_interface(char *argstr, struct olsr_config *rcfg, char *rmsg)
428 {
429   char **tok;
430   const char *nxt;
431 #ifdef DEBUG
432   struct ipaddr_str buf;
433 #endif
434   if (NULL != (tok = parse_tok(argstr, &nxt))) {
435     if ('{' != *nxt) {
436       sprintf(rmsg, "No {}\n");
437       parse_tok_free(tok);
438       return CFG_ERROR;
439     } else {
440       char **tok_next = parse_tok(nxt + 1, NULL);
441       char **p = tok;
442       while (p[0]) {
443         char **p_next = tok_next;
444         struct olsr_if_config *new_if = queue_if(p[0], rcfg);
445         PARSER_DEBUG_PRINTF("Interface %s\n", p[0]);
446         while (new_if && p_next && p_next[0]) {
447           if (!p_next[1]) {
448             sprintf(rmsg, "Odd args in %s\n", nxt);
449             parse_tok_free(tok_next);
450             parse_tok_free(tok);
451             return CFG_ERROR;
452           }
453           if (0 == strcasecmp("Mode", p_next[0])) {
454             if (0 == strcasecmp("Ether", p_next[1])) {
455               new_if->cnf->mode = IF_MODE_ETHER;
456             } else {
457               new_if->cnf->mode = IF_MODE_MESH;
458             }
459             PARSER_DEBUG_PRINTF("\tMode: %s\n", INTERFACE_MODE_NAMES[new_if->cnf->mode]);
460           } else if (0 == strcasecmp("AutoDetectChanges", p_next[0])) {
461             new_if->cnf->autodetect_chg = (0 == strcasecmp("yes", p_next[1]));
462             PARSER_DEBUG_PRINTF("\tAutodetect changes: %d\n", new_if->cnf->autodetect_chg);
463           } else if (0 == strcasecmp("Ip4Broadcast", p_next[0])) {
464             union olsr_ip_addr ipaddr;
465             if (inet_pton(AF_INET, p_next[1], &ipaddr) <= 0) {
466               sprintf(rmsg, "Failed converting IP address %s\n", p_next[1]);
467               parse_tok_free(tok_next);
468               parse_tok_free(tok);
469               return CFG_ERROR;
470             }
471             new_if->cnf->ipv4_broadcast = ipaddr;
472             PARSER_DEBUG_PRINTF("\tIPv4 broadcast: %s\n", ip4_to_string(&buf, new_if->cnf->ipv4_broadcast.v4));
473           } else if (0 == strcasecmp("Ip6AddrType", p_next[0])) {
474             if (0 == strcasecmp("site-local", p_next[1])) {
475               new_if->cnf->ipv6_addrtype = OLSR_IP6T_SITELOCAL;
476             } else if (0 == strcasecmp("unique-local", p_next[1])) {
477               new_if->cnf->ipv6_addrtype = OLSR_IP6T_UNIQUELOCAL;
478             } else if (0 == strcasecmp("global", p_next[1])) {
479               new_if->cnf->ipv6_addrtype = OLSR_IP6T_GLOBAL;
480             } else {
481               new_if->cnf->ipv6_addrtype = OLSR_IP6T_AUTO;
482             }
483             PARSER_DEBUG_PRINTF("\tIPv6 addrtype: %d\n", new_if->cnf->ipv6_addrtype);
484           } else if (0 == strcasecmp("Ip6MulticastSite", p_next[0])) {
485             union olsr_ip_addr ipaddr;
486             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
487               sprintf(rmsg, "Failed converting IP address %s\n", p_next[1]);
488               parse_tok_free(tok_next);
489               parse_tok_free(tok);
490               return CFG_ERROR;
491             }
492             new_if->cnf->ipv6_multi_site = ipaddr;
493             PARSER_DEBUG_PRINTF("\tIPv6 site-local multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_site.v6));
494           } else if (0 == strcasecmp("Ip6MulticastGlobal", p_next[0])) {
495             union olsr_ip_addr ipaddr;
496             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
497               sprintf(rmsg, "Failed converting IP address %s\n", p_next[1]);
498               parse_tok_free(tok_next);
499               parse_tok_free(tok);
500               return CFG_ERROR;
501             }
502             new_if->cnf->ipv6_multi_glbl = ipaddr;
503             PARSER_DEBUG_PRINTF("\tIPv6 global multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_glbl.v6));
504           } else if (0 == strcasecmp("HelloInterval", p_next[0])) {
505             new_if->cnf->hello_params.emission_interval = olsr_txt_to_milli(p_next[1]);
506             PARSER_DEBUG_PRINTF("\tHELLO interval1: %u ms\n", new_if->cnf->hello_params.emission_interval);
507           } else if (0 == strcasecmp("HelloValidityTime", p_next[0])) {
508             new_if->cnf->hello_params.validity_time = olsr_txt_to_milli(p_next[1]);
509             PARSER_DEBUG_PRINTF("\tHELLO validity: %u ms\n", new_if->cnf->hello_params.validity_time);
510           } else if (0 == strcasecmp("Tcinterval", p_next[0])) {
511             PARSER_DEBUG_PRINTF("\tIgnore TC interval1: %s ms in interface\n", p_next[1]);
512           } else if (0 == strcasecmp("TcValidityTime", p_next[0])) {
513             PARSER_DEBUG_PRINTF("\tIgnore TC validity: %s ms in interface\n", p_next[1]);
514           } else if (0 == strcasecmp("Midinterval", p_next[0])) {
515             PARSER_DEBUG_PRINTF("\tIgnore MID interval1: %s ms in interface\n", p_next[1]);
516           } else if (0 == strcasecmp("MidValidityTime", p_next[0])) {
517             PARSER_DEBUG_PRINTF("\tIgnore MID validity: %s ms in interface\n", p_next[1]);
518           } else if (0 == strcasecmp("Hnainterval", p_next[0])) {
519             PARSER_DEBUG_PRINTF("\tIgnore HNA interval1: %s ms in interface\n", p_next[1]);
520           } else if (0 == strcasecmp("HnaValidityTime", p_next[0])) {
521             PARSER_DEBUG_PRINTF("\tIgnore HNA validity: %s ms in interface\n", p_next[1]);
522           } else if (0 == strcasecmp("Weight", p_next[0])) {
523             new_if->cnf->weight.fixed = true;
524             PARSER_DEBUG_PRINTF("\tFixed willingness: %d\n", new_if->cnf->weight.value);
525           } else if (0 == strcasecmp("LinkQualityMult", p_next[0])) {
526             float f;
527             struct olsr_lq_mult *mult = olsr_malloc(sizeof(*mult), "lqmult");
528             if (!p_next[2]) {
529               sprintf(rmsg, "Odd args in %s\n", nxt);
530               parse_tok_free(tok_next);
531               parse_tok_free(tok);
532               return CFG_ERROR;
533             }
534             memset(&mult->addr, 0, sizeof(mult->addr));
535             if (0 != strcasecmp("default", p_next[1])) {
536               if (inet_pton(rcfg->ip_version, p_next[1], &mult->addr) <= 0) {
537                 sprintf(rmsg, "Failed converting IP address %s\n", p_next[1]);
538                 parse_tok_free(tok_next);
539                 parse_tok_free(tok);
540                 return CFG_ERROR;
541               }
542             }
543             f = 0;
544             sscanf(p_next[2], "%f", &f);
545             mult->value = (uint32_t) (f * LINK_LOSS_MULTIPLIER);
546             mult->next = new_if->cnf->lq_mult;
547             new_if->cnf->lq_mult = mult;
548             PARSER_DEBUG_PRINTF("\tLinkQualityMult %s %0.2f\n", ip_to_string(rcfg->ip_version, &buf, &mult->addr),
549                                 (float)mult->value / LINK_LOSS_MULTIPLIER);
550             p_next++;
551           } else {
552             sprintf(rmsg, "Unknown arg: %s %s\n", p_next[0], p_next[1]);
553             parse_tok_free(tok_next);
554             parse_tok_free(tok);
555             return CFG_ERROR;
556           }
557           p_next += 2;
558         }
559         p++;
560       }
561       parse_tok_free(tok_next);
562     }
563     parse_tok_free(tok);
564   } else {
565     sprintf(rmsg, "Error in %s\n", argstr);
566     return CFG_ERROR;
567   }
568   return CFG_OK;
569 }
570
571 /*
572  * Parses a single loadplugin option block
573  * @argstr:     arguments string
574  * @rcfg:       config struct to write/change values into
575  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
576  * @returns configuration status as defined in olsr_parse_cfg_result
577  */
578 static olsr_parse_cfg_result
579 parse_cfg_loadplugin(char *argstr, struct olsr_config *rcfg, char *rmsg)
580 {
581   char **tok;
582   const char *nxt;
583   if (NULL != (tok = parse_tok(argstr, &nxt))) {
584     if ('{' != *nxt) {
585       sprintf(rmsg, "No {}\n");
586       parse_tok_free(tok);
587       return CFG_ERROR;
588     } else {
589       char **tok_next = parse_tok(nxt + 1, NULL);
590       struct plugin_entry *pe = olsr_malloc(sizeof(*pe), "plugin");
591       pe->name = olsr_strdup(*tok);
592       pe->params = NULL;
593       pe->next = rcfg->plugins;
594       rcfg->plugins = pe;
595       PARSER_DEBUG_PRINTF("Plugin: %s\n", pe->name);
596       if (tok_next) {
597         char **p_next = tok_next;
598         while (p_next[0]) {
599           struct plugin_param *pp = olsr_malloc(sizeof(*pp), "plparam");
600           if (0 != strcasecmp("PlParam", p_next[0]) || !p_next[1] || !p_next[2]) {
601             sprintf(rmsg, "Odd args in %s\n", nxt);
602             parse_tok_free(tok_next);
603             parse_tok_free(tok);
604             return CFG_ERROR;
605           }
606           pp->key = olsr_strdup(p_next[1]);
607           pp->value = olsr_strdup(p_next[2]);
608           pp->next = pe->params;
609           pe->params = pp;
610           PARSER_DEBUG_PRINTF("\tPlParam: %s %s\n", pp->key, pp->value);
611           p_next += 3;
612         }
613         parse_tok_free(tok_next);
614       }
615     }
616     parse_tok_free(tok);
617   } else {
618     sprintf(rmsg, "Error in %s\n", argstr);
619     return CFG_ERROR;
620   }
621   return CFG_OK;
622 }
623
624 /*
625  * Parses a the parameter string of --log(debug|info|warn|error)
626  * @argstr:     arguments string
627  * @rcfg:       config struct to write/change values into
628  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
629  * @returns configuration status as defined in olsr_parse_cfg_result
630  */
631 static olsr_parse_cfg_result
632 parse_cfg_debug(char *argstr, struct olsr_config *rcfg, char *rmsg)
633 {
634   int dlevel, i;
635   dlevel = atoi(argstr);
636
637   if (dlevel < MIN_DEBUGLVL || dlevel > MAX_DEBUGLVL) {
638     sprintf(rmsg, "Error, debug level must be between -2 and 3\n");
639     return CFG_ERROR;
640   }
641
642   switch (dlevel) {
643   case 3:
644     /* all logging */
645     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
646       rcfg->log_event[SEVERITY_DEBUG][i] = true;
647     }
648   case 2:
649     /* all info, warnings and errors */
650     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
651       rcfg->log_event[SEVERITY_INFO][i] = true;
652     }
653   case 1:
654     /* some INFO level output, plus all warnings and errors */
655     rcfg->log_event[SEVERITY_INFO][LOG_2NEIGH] = true;
656     rcfg->log_event[SEVERITY_INFO][LOG_LINKS] = true;
657     rcfg->log_event[SEVERITY_INFO][LOG_MAIN] = true;
658     rcfg->log_event[SEVERITY_INFO][LOG_NEIGHTABLE] = true;
659     rcfg->log_event[SEVERITY_INFO][LOG_PLUGINS] = true;
660     rcfg->log_event[SEVERITY_INFO][LOG_ROUTING] = true;
661     rcfg->log_event[SEVERITY_INFO][LOG_TC] = true;
662   case 0:
663     /* errors and warnings */
664     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
665       rcfg->log_event[SEVERITY_WARN][i] = true;
666     }
667   case -1:
668     /* only error messages */
669     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
670       rcfg->log_event[SEVERITY_ERR][i] = true;
671     }
672   default:                     /* no logging at all ! */
673     break;
674   }
675
676   PARSER_DEBUG_PRINTF("Debug level: %d\n", dlevel);
677
678   if (dlevel > 0) {
679     rcfg->no_fork = 1;
680   }
681
682   /* prevent fallback to default 0 */
683   cfg_has_log[SEVERITY_ERR] = true;
684   return CFG_OK;
685 }
686
687 /*
688  * Parses a the parameter string of --log(debug|info|warn|error)
689  * @argstr:     arguments string
690  * @rcfg:       config struct to write/change values into
691  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
692  * @returns configuration status as defined in olsr_parse_cfg_result
693  */
694 static olsr_parse_cfg_result
695 parse_cfg_log(char *argstr, struct olsr_config *rcfg, char *rmsg, enum log_severity sev)
696 {
697   char *p = (char *)argstr, *next;
698   int i;
699   bool first;
700
701   while (p != NULL) {
702     /* split at ',' */
703     next = strchr(p, ',');
704     if (next) {
705       *next++ = 0;
706     }
707
708     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
709       if (strcasecmp(p, LOG_SOURCE_NAMES[i]) == 0) {
710         break;
711       }
712     }
713
714     if (i == LOG_SOURCE_COUNT) {
715       sprintf(rmsg, "Error, unknown logging source: %s\n", p);
716       return CFG_ERROR;
717     }
718
719     /* handle "all" keyword */
720     if (i == LOG_ALL) {
721       for (i = 0; i < LOG_SOURCE_COUNT; i++) {
722         rcfg->log_event[sev][i] = true;
723       }
724     }
725     else {
726       rcfg->log_event[sev][i] = true;
727     }
728     p = next;
729   }
730
731
732   PARSER_DEBUG_PRINTF("Log_%s:", LOG_SEVERITY_NAMES[sev]);
733   for (i = 0, first = true; i < LOG_SOURCE_COUNT; i++) {
734     if (rcfg->log_event[sev][i]) {
735       PARSER_DEBUG_PRINTF("%c%s", first ? ' ' : ',', LOG_SOURCE_NAMES[i]);
736       first = false;
737     }
738   }
739   PARSER_DEBUG_PRINTF("\n");
740   cfg_has_log[sev] = true;
741   return CFG_OK;
742 }
743
744 /*
745  * Parses a single option found on the command line.
746  * @optint: return value of previous getopt_long()
747  * @argstr: argument string provided by getopt_long()
748  * @line:   line number (if option is read from file)
749  * @rcfg:   config struct to write/change values into
750  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
751  * @returns configuration status as defined in olsr_parse_cfg_result
752  */
753 static olsr_parse_cfg_result
754 parse_cfg_option(const int optint, char *argstr, const int line, struct olsr_config *rcfg, char *rmsg)
755 {
756   switch (optint) {
757   case 'D':                    /* delgw */
758     rcfg->del_gws = true;
759     PARSER_DEBUG_PRINTF("del_gws set to %d\n", rcfg->del_gws);
760     break;
761   case 'i':                    /* iface */
762     /* Ignored */
763     break;
764   case 'n':                    /* nofork */
765     rcfg->no_fork = true;
766     PARSER_DEBUG_PRINTF("no_fork set to %d\n", rcfg->no_fork);
767     break;
768   case 'A':                    /* AllowNoInt (yes/no) */
769     rcfg->allow_no_interfaces = (0 == strcasecmp("yes", argstr));
770     PARSER_DEBUG_PRINTF("Noint set to %d\n", rcfg->allow_no_interfaces);
771     break;
772   case 'C':                    /* ClearScreen (yes/no) */
773     rcfg->clear_screen = (0 == strcasecmp("yes", argstr));
774     PARSER_DEBUG_PRINTF("Clear screen %s\n", rcfg->clear_screen ? "enabled" : "disabled");
775     break;
776   case 'd':                    /* DebugLevel (i) */
777     return parse_cfg_debug(argstr, rcfg, rmsg);
778     break;
779   case 'F':                    /* FIBMetric (str) */
780     {
781       char **tok;
782       if (NULL != (tok = parse_tok(argstr, NULL))) {
783         if (strcasecmp(*tok, CFG_FIBM_FLAT) == 0) {
784           rcfg->fib_metric = FIBM_FLAT;
785         } else if (strcasecmp(*tok, CFG_FIBM_CORRECT) == 0) {
786           rcfg->fib_metric = FIBM_CORRECT;
787         } else if (strcasecmp(*tok, CFG_FIBM_APPROX) == 0) {
788           rcfg->fib_metric = FIBM_APPROX;
789         } else {
790           sprintf(rmsg, "FIBMetric must be \"%s\", \"%s\", or \"%s\"!\n", CFG_FIBM_FLAT, CFG_FIBM_CORRECT, CFG_FIBM_APPROX);
791           return CFG_ERROR;
792         }
793         parse_tok_free(tok);
794       } else {
795         sprintf(rmsg, "Error in %s\n", argstr);
796         return CFG_ERROR;
797       }
798       PARSER_DEBUG_PRINTF("FIBMetric: %d=%s\n", rcfg->fib_metric, argstr);
799     }
800     break;
801   case '4':                    /* Hna4 (4body) */
802     return parse_cfg_hna(argstr, AF_INET, rcfg, rmsg);
803     break;
804   case '6':                    /* Hna6 (6body) */
805     return parse_cfg_hna(argstr, AF_INET6, rcfg, rmsg);
806     break;
807   case 'I':                    /* Interface if1 if2 { ifbody } */
808     return parse_cfg_interface(argstr, rcfg, rmsg);
809     break;
810   case 'V':                    /* IpVersion (i) */
811     {
812       int ver = -1;
813       sscanf(argstr, "%d", &ver);
814       if (ver == 4) {
815         rcfg->ip_version = AF_INET;
816         rcfg->ipsize = sizeof(struct in_addr);
817       } else if (ver == 6) {
818         rcfg->ip_version = AF_INET6;
819         rcfg->ipsize = sizeof(struct in6_addr);
820       } else {
821         sprintf(rmsg, "IpVersion must be 4 or 6!\n");
822         return CFG_ERROR;
823       }
824     }
825     PARSER_DEBUG_PRINTF("IpVersion: %d\n", rcfg->ip_version);
826     break;
827   case 'J':                    /* LinkQualityDijkstraLimit (i,f) */
828     {
829       int limit = -1;
830       char t[10] = {0};
831       sscanf(argstr, "%d %10s", &limit, t);
832       if (0 <= limit && limit < (1 << (8 * sizeof(rcfg->lq_dlimit))))
833         rcfg->lq_dlimit = limit;
834       rcfg->lq_dinter = olsr_txt_to_milli(t);
835       PARSER_DEBUG_PRINTF("Link quality dijkstra limit %d, %u ms\n", rcfg->lq_dlimit, rcfg->lq_dinter);
836     }
837     break;
838   case 'E':                    /* LinkQualityFishEye (i) */
839     {
840       int arg = -1;
841       sscanf(argstr, "%d", &arg);
842       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->lq_fish))))
843         rcfg->lq_fish = arg;
844       PARSER_DEBUG_PRINTF("Link quality fish eye %d\n", rcfg->lq_fish);
845     }
846     break;
847   case 'p':                    /* LoadPlugin (soname {PlParams}) */
848     return parse_cfg_loadplugin(argstr, rcfg, rmsg);
849     break;
850   case 'M':                    /* MprCoverage (i) */
851     {
852       int arg = -1;
853       sscanf(argstr, "%d", &arg);
854       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->mpr_coverage))))
855         rcfg->mpr_coverage = arg;
856       PARSER_DEBUG_PRINTF("MPR coverage %d\n", rcfg->mpr_coverage);
857     }
858     break;
859   case 'N':                    /* NatThreshold (f) */
860     {
861 #ifdef DEBUG
862       struct millitxt_buf tbuf;
863 #endif
864
865       rcfg->lq_nat_thresh = olsr_txt_to_milli(argstr);
866       PARSER_DEBUG_PRINTF("NAT threshold %s\n", olsr_milli_to_txt(&tbuf, rcfg->lq_nat_thresh));
867     }
868     break;
869   case 'Y':                    /* NicChgsPollInt (f) */
870     rcfg->nic_chgs_pollrate = olsr_txt_to_milli(argstr);
871     PARSER_DEBUG_PRINTF("NIC Changes Pollrate %u ms\n", rcfg->nic_chgs_pollrate);
872     break;
873   case 'T':                    /* Pollrate (f) */
874     {
875       rcfg->pollrate = olsr_txt_to_milli(argstr);
876       PARSER_DEBUG_PRINTF("Pollrate %u ms\n", rcfg->pollrate);
877     }
878     break;
879   case 'q':                    /* RtProto (i) */
880     {
881       int arg = -1;
882       sscanf(argstr, "%d", &arg);
883       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rtproto))))
884         rcfg->rtproto = arg;
885       PARSER_DEBUG_PRINTF("RtProto: %d\n", rcfg->rtproto);
886     }
887     break;
888   case 'R':                    /* RtTableDefault (i) */
889     {
890       int arg = -1;
891       sscanf(argstr, "%d", &arg);
892       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rttable_default))))
893         rcfg->rttable_default = arg;
894       PARSER_DEBUG_PRINTF("RtTableDefault: %d\n", rcfg->rttable_default);
895     }
896     break;
897   case 'r':                    /* RtTable (i) */
898     {
899       int arg = -1;
900       sscanf(argstr, "%d", &arg);
901       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rttable))))
902         rcfg->rttable = arg;
903       PARSER_DEBUG_PRINTF("RtTable: %d\n", rcfg->rttable);
904     }
905     break;
906   case 't':                    /* TcRedundancy (i) */
907     {
908       int arg = -1;
909       sscanf(argstr, "%d", &arg);
910       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tc_redundancy))))
911         rcfg->tc_redundancy = arg;
912       PARSER_DEBUG_PRINTF("TC redundancy %d\n", rcfg->tc_redundancy);
913     }
914     break;
915   case 'Z':                    /* TosValue (i) */
916     {
917       int arg = -1;
918       sscanf(argstr, "%d", &arg);
919       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tos))))
920         rcfg->tos = arg;
921       PARSER_DEBUG_PRINTF("TOS: %d\n", rcfg->tos);
922     }
923     break;
924   case 'w':                    /* Willingness (i) */
925     {
926       int arg = -1;
927       sscanf(argstr, "%d", &arg);
928       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->willingness))))
929         rcfg->willingness = arg;
930       rcfg->willingness_auto = false;
931       PARSER_DEBUG_PRINTF("Willingness: %d (no auto)\n", rcfg->willingness);
932     }
933     break;
934   case CFG_LOG_DEBUG:          /* Log (string) */
935     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_DEBUG);
936     break;
937   case CFG_LOG_INFO:           /* Log (string) */
938     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_INFO);
939     break;
940   case CFG_LOG_WARN:           /* Log (string) */
941     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_WARN);
942     break;
943   case CFG_LOG_ERROR:          /* Log (string) */
944     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_ERR);
945     break;
946   case CFG_LOG_STDERR:
947     rcfg->log_target_stderr = true;
948     break;
949   case CFG_LOG_SYSLOG:
950     rcfg->log_target_syslog = true;
951     break;
952   case CFG_LOG_FILE:
953     rcfg->log_target_file = strdup(argstr);
954     break;
955
956   case 's':                    /* SourceIpMode (string) */
957     rcfg->source_ip_mode = (0 == strcasecmp("yes", argstr)) ? 1 : 0;
958     PARSER_DEBUG_PRINTF("Source IP mode %s\n", rcfg->source_ip_mode ? "enabled" : "disabled");
959     break;
960   case 'o':                    /* Originator Address (ip) */
961     if (inet_pton(AF_INET, argstr, &rcfg->router_id) <= 0) {
962       sprintf(rmsg, "Failed converting IP address %s for originator address\n", argstr);
963       return CFG_ERROR;
964     }
965     break;
966   case CFG_OLSRPORT:           /* port (i) */
967     {
968       int arg = -1;
969       sscanf(argstr, "%d", &arg);
970       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->olsr_port))))
971         rcfg->olsr_port = arg;
972       PARSER_DEBUG_PRINTF("OLSR port: %d\n", rcfg->olsr_port);
973     }
974     break;
975   case CFG_DLPATH:
976     rcfg->dlPath = strdup(argstr);
977     PARSER_DEBUG_PRINTF("Dynamic library path: %s\n", rcfg->dlPath);
978     break;
979   case CFG_HTTPPORT:
980     {
981       int arg = -1;
982       sscanf(argstr, "%d", &arg);
983       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http))))
984         rcfg->comport_http = arg;
985       PARSER_DEBUG_PRINTF("HTTP port: %d\n", rcfg->comport_http);
986     }
987     break;
988   case CFG_HTTPLIMIT:
989     {
990       int arg = -1;
991       sscanf(argstr, "%d", &arg);
992       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http_limit))))
993         rcfg->comport_http_limit = arg;
994       PARSER_DEBUG_PRINTF("HTTP connection limit: %d\n", rcfg->comport_http_limit);
995     }
996     break;
997   case CFG_TXTPORT:
998     {
999       int arg = -1;
1000       sscanf(argstr, "%d", &arg);
1001       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt))))
1002         rcfg->comport_txt = arg;
1003       PARSER_DEBUG_PRINTF("TXT port: %d\n", rcfg->comport_txt);
1004     }
1005     break;
1006   case CFG_TXTLIMIT:
1007     {
1008       int arg = -1;
1009       sscanf(argstr, "%d", &arg);
1010       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt_limit))))
1011         rcfg->comport_txt_limit = arg;
1012       PARSER_DEBUG_PRINTF("TXT connection limit: %d\n", rcfg->comport_txt_limit);
1013     }
1014     break;
1015   case CFG_HNA_HTIME:
1016     rcfg->hna_params.emission_interval = olsr_txt_to_milli(argstr);
1017     PARSER_DEBUG_PRINTF("\tHNA interval1: %u ms\n", rcfg->hna_params.emission_interval);
1018     break;
1019   case CFG_HNA_VTIME:
1020     rcfg->hna_params.validity_time = olsr_txt_to_milli(argstr);
1021     PARSER_DEBUG_PRINTF("\tHNA validity: %u ms\n", rcfg->hna_params.validity_time);
1022     break;
1023   case CFG_MID_HTIME:
1024     rcfg->mid_params.emission_interval = olsr_txt_to_milli(argstr);
1025     PARSER_DEBUG_PRINTF("\tMID interval1: %u ms\n", rcfg->mid_params.emission_interval);
1026     break;
1027   case CFG_MID_VTIME:
1028     rcfg->mid_params.validity_time = olsr_txt_to_milli(argstr);
1029     PARSER_DEBUG_PRINTF("\tMID validity: %u ms\n", rcfg->mid_params.validity_time);
1030     break;
1031   case CFG_TC_HTIME:
1032     rcfg->tc_params.emission_interval = olsr_txt_to_milli(argstr);
1033     PARSER_DEBUG_PRINTF("\tTC interval1: %u ms\n", rcfg->tc_params.emission_interval);
1034     break;
1035   case CFG_TC_VTIME:
1036     rcfg->tc_params.validity_time = olsr_txt_to_milli(argstr);
1037     PARSER_DEBUG_PRINTF("\tTC validity: %u ms\n", rcfg->tc_params.validity_time);
1038     break;
1039
1040   default:
1041     sprintf(rmsg, "Unknown arg in line %d.\n", line);
1042     return CFG_ERROR;
1043   }                             /* switch */
1044   return CFG_OK;
1045 }
1046
1047 /*
1048  * Parses command line options using the getopt() runtime
1049  * function. May also replace a "-f filename" combination
1050  * with options read in from a config file.
1051  *
1052  * @argc: the argv count from main() - or zero if no argv
1053  * @argv: the array of strings provided from the enviroment
1054  * @file: the default config file name (used if argc <= 1)
1055  * @rmsg: to provide buf[FILENAME_MAX + 256] to sprint err msgs
1056  * @rcfg: returns a valid config pointer, clean with olsr_free_cfg()
1057  * @returns a parsing status result code
1058  */
1059 olsr_parse_cfg_result
1060 olsr_parse_cfg(int argc, char *argv[], const char *file, char *rmsg, struct olsr_config ** rcfg)
1061 {
1062   int opt;
1063   int opt_idx = 0;
1064   char *opt_str = 0;
1065   int opt_argc = 0;
1066   char **opt_argv = olsr_malloc(argc * sizeof(opt_argv[0]), "opt_argv");
1067   int *opt_line = olsr_malloc(argc * sizeof(opt_line[0]), "opt_line");
1068   olsr_parse_cfg_result rslt = CFG_OK;
1069
1070   /*
1071    * Original cmd line params
1072    *
1073    * -bcast                   (removed)
1074    * -delgw                   (-> --delgw)
1075    * -dispin                  (-> --dispin)
1076    * -dispout                 (-> --dispout)
1077    * -d (level)               (preserved)
1078    * -f (config)              (preserved)
1079    * -hemu (queue_if(hcif01)) (-> --hemu)
1080    * -hint                    (removed)
1081    * -hnaint                  (removed)
1082    * -i if0 if1...            (see comment below)
1083    * -int (WIN32)             (preserved)
1084    * -ipc (ipc conn = 1)      (-> --ipc)
1085    * -ipv6                    (-> -V or --IpVersion)
1086    * -lqa (lq aging)          (removed)
1087    * -lql (lq lev)            (removed)
1088    * -lqnt (lq nat)           (removed)
1089    * -midint                  (removed)
1090    * -multi (ipv6 mcast)      (removed)
1091    * -nofork                  (preserved)
1092    * -tcint                   (removed)
1093    * -T (pollrate)            (preserved)
1094    *
1095    * Note: Remaining args are interpreted as list of
1096    * interfaces. For this reason, '-i' is ignored which
1097    * adds the following non-minus args to the list.
1098    */
1099
1100   /* *INDENT-OFF* */
1101   static struct option long_options[] = {
1102     {"config",                   required_argument, 0, 'f'}, /* (filename) */
1103     {"delgw",                    no_argument,       0, 'D'},
1104     {"help",                     optional_argument, 0, 'h'},
1105     {"iface",                    no_argument,       0, 'i'}, /* if0 if1... */
1106 #ifdef WIN32
1107     {"int",                      no_argument,       0, 'l'},
1108 #endif
1109     {"ipc",                      no_argument,       0, 'P'},
1110     {"log_debug",                required_argument, 0, CFG_LOG_DEBUG}, /* src1,src2,... */
1111     {"log_info",                 required_argument, 0, CFG_LOG_INFO}, /* src1,src2,... */
1112     {"log_warn",                 required_argument, 0, CFG_LOG_WARN}, /* src1,src2,... */
1113     {"log_error",                required_argument, 0, CFG_LOG_ERROR}, /* src1,src2,... */
1114     {"log_stderr",               no_argument,       0, CFG_LOG_STDERR},
1115     {"log_syslog",               no_argument,       0, CFG_LOG_SYSLOG},
1116     {"log_file",                 required_argument, 0, CFG_LOG_FILE}, /* (filename) */
1117     {"nofork",                   no_argument,       0, 'n'},
1118     {"version",                  no_argument,       0, 'v'},
1119     {"AllowNoInt",               required_argument, 0, 'A'}, /* (yes/no) */
1120     {"ClearScreen",              required_argument, 0, 'C'}, /* (yes/no) */
1121     {"DebugLevel",               required_argument, 0, 'd'}, /* (i) */
1122     {"FIBMetric",                required_argument, 0, 'F'}, /* (str) */
1123     {"Hna4",                     required_argument, 0, '4'}, /* (4body) */
1124     {"Hna6",                     required_argument, 0, '6'}, /* (6body) */
1125     {"Interface",                required_argument, 0, 'I'}, /* (if1 if2 {ifbody}) */
1126     {"IpVersion",                required_argument, 0, 'V'}, /* (i) */
1127     {"LinkQualityDijkstraLimit", required_argument, 0, 'J'}, /* (i,f) */
1128     {"LinkQualityFishEye",       required_argument, 0, 'E'}, /* (i) */
1129     {"LoadPlugin",               required_argument, 0, 'p'}, /* (soname {PlParams}) */
1130     {"MprCoverage",              required_argument, 0, 'M'}, /* (i) */
1131     {"NatThreshold",             required_argument, 0, 'N'}, /* (f) */
1132     {"NicChgsPollInt",           required_argument, 0, 'Y'}, /* (f) */
1133     {"Pollrate",                 required_argument, 0, 'T'}, /* (f) */
1134     {"RtProto",                  required_argument, 0, 'q'}, /* (i) */
1135     {"RtTableDefault",           required_argument, 0, 'R'}, /* (i) */
1136     {"RtTable",                  required_argument, 0, 'r'}, /* (i) */
1137     {"TcRedundancy",             required_argument, 0, 't'}, /* (i) */
1138     {"TosValue",                 required_argument, 0, 'Z'}, /* (i) */
1139     {"Willingness",              required_argument, 0, 'w'}, /* (i) */
1140     {"RouterId",                 required_argument, 0, 'o'}, /* (ip) */
1141     {"SourceIpMode",             required_argument, 0, 's'}, /* (yes/no) */
1142     {"OlsrPort",                 required_argument, 0, CFG_OLSRPORT},  /* (i) */
1143     {"dlPath",                   required_argument, 0, CFG_DLPATH},    /* (path) */
1144     {"HttpPort",                 required_argument, 0, CFG_HTTPPORT},  /* (i) */
1145     {"HttpLimit",                required_argument, 0, CFG_HTTPLIMIT}, /* (i) */
1146     {"TxtPort",                  required_argument, 0, CFG_TXTPORT},   /* (i) */
1147     {"TxtLimit",                 required_argument, 0, CFG_TXTLIMIT},  /* (i) */
1148     {"TcInterval",               required_argument, 0, CFG_TC_HTIME},  /* (f) */
1149     {"TcValidityTime",           required_argument, 0, CFG_TC_VTIME},  /* (f) */
1150     {"MidInterval",              required_argument, 0, CFG_MID_HTIME},  /* (f) */
1151     {"MidValidityTime",          required_argument, 0, CFG_MID_VTIME},  /* (f) */
1152     {"HnaInterval",              required_argument, 0, CFG_HNA_HTIME},  /* (f) */
1153     {"HnaValidityTime",          required_argument, 0, CFG_HNA_VTIME},  /* (f) */
1154
1155     {"IpcConnect",               required_argument, 0,  0 }, /* ignored */
1156     {"UseHysteresis",            required_argument, 0,  0 }, /* ignored */
1157     {"HystScaling",              required_argument, 0,  0 }, /* ignored */
1158     {"HystThrHigh",              required_argument, 0,  0 }, /* ignored */
1159     {"HystThrLow",               required_argument, 0,  0 }, /* ignored */
1160     {"LinkQualityLevel",         required_argument, 0,  0 }, /* ignored */
1161     {"LinkQualityWinsize",       required_argument, 0,  0 }, /* ignored */
1162     {"LinkQualityAlgorithm",     required_argument, 0,  0 }, /* ignored */
1163     {"LinkQualityAging",         required_argument, 0,  0 }, /* ignored */
1164     {"dispout",                  no_argument,       0,  0 }, /* ignored */
1165     {"dispin",                   no_argument,       0,  0 }, /* ignored */
1166     {0, 0, 0, 0}
1167   }, *popt = long_options;
1168   /* *INDENT-ON* */
1169
1170   /*
1171    * olsr_malloc() uses calloc, so opt_line is already filled
1172    * memset(opt_line, 0, argc * sizeof(opt_line[0]));
1173    */
1174
1175   /* cleanup static logsource flags */
1176   cfg_has_log[SEVERITY_DEBUG] = false;
1177   cfg_has_log[SEVERITY_INFO] = false;
1178   cfg_has_log[SEVERITY_WARN] = false;
1179   cfg_has_log[SEVERITY_ERR] = false;
1180
1181   /* Copy argv array for safe free'ing later on */
1182   while (opt_argc < argc) {
1183     const char *p = argv[opt_argc];
1184     if (0 == strcasecmp(p, "-nofork"))
1185       p = "-n";
1186 #ifdef WIN32
1187     else if (0 == strcasecmp(p, "-int"))
1188       p = "-l";
1189 #endif
1190     opt_argv[opt_argc] = olsr_strdup(p);
1191     opt_argc++;
1192   }
1193
1194   /* get option count */
1195   for (opt_idx = 0; long_options[opt_idx].name; opt_idx++);
1196
1197   /* Calculate short option string */
1198   opt_str = olsr_malloc(opt_idx * 3, "create short opt_string");
1199   opt_idx = 0;
1200   while (popt->name) {
1201     if (popt->val > 0 && popt->val < 128) {
1202       opt_str[opt_idx++] = popt->val;
1203
1204       switch (popt->has_arg) {
1205       case optional_argument:
1206         opt_str[opt_idx++] = ':';
1207         /* Fall through */
1208       case required_argument:
1209         opt_str[opt_idx++] = ':';
1210         break;
1211       }
1212     }
1213     popt++;
1214   }
1215
1216   /*
1217    * If no arguments, revert to default behaviour
1218    */
1219
1220   if (1 >= opt_argc) {
1221     char *argv0_tmp = opt_argv[0];
1222     free(opt_argv);
1223     opt_argv = olsr_malloc(3 * sizeof(opt_argv[0]), "default argv");
1224     opt_argv[0] = argv0_tmp;
1225     opt_argv[1] = olsr_strdup("-f");
1226     opt_argv[2] = olsr_strdup(file);
1227     opt_argc = 3;
1228   }
1229
1230   rmsg[0] = '\0';
1231   *rcfg = olsr_get_default_cfg();
1232
1233   while (0 <= (opt = getopt_long(opt_argc, opt_argv, opt_str, long_options, &opt_idx))) {
1234     switch (opt) {
1235     case 0:
1236       sprintf(rmsg, "Ignored deprecated %s\n", long_options[opt_idx].name);
1237       rslt = CFG_WARN;
1238       break;
1239     case 'f':                  /* config (filename) */
1240       PARSER_DEBUG_PRINTF("Read config from %s\n", optarg);
1241       if (0 > read_cfg(optarg, &opt_argc, &opt_argv, &opt_line)) {
1242         sprintf(rmsg, "Could not read specified config file %s!\n%s", optarg, strerror(errno));
1243         return CFG_ERROR;
1244       }
1245       break;
1246 #ifdef WIN32
1247     case 'l':                  /* win32: list ifaces */
1248       ListInterfaces();
1249       rslt = CFG_EXIT;
1250       break;
1251 #endif
1252     case 'v':                  /* version */
1253       fprintf(stderr,  "*** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
1254       rslt = CFG_EXIT;
1255       break;
1256     case 'h':                  /* help */
1257       popt = long_options;
1258       printf("Usage: olsrd [OPTIONS]... [interfaces]...\n");
1259       while (popt->name) {
1260         if (popt->val) {
1261           if (popt->val > 0 && popt->val < 128) {
1262             printf("-%c or --%s ", popt->val, popt->name);
1263           } else {
1264             printf("      --%s ", popt->name);
1265           }
1266           switch (popt->has_arg) {
1267           case required_argument:
1268             printf("arg");
1269             break;
1270           case optional_argument:
1271             printf("[arg]");
1272             break;
1273           }
1274           printf("\n");
1275         }
1276         popt++;
1277       }
1278       if (optarg == NULL) {
1279         printf("Use '--help=log'for help about the available logging sources\n");
1280       } else if (strcasecmp(optarg, "log") == 0) {
1281         int i;
1282
1283         printf("Log sources for --log_debug, --log_info, --log_warn and --log_error:\n");
1284         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1285           printf("\t%s\n", LOG_SOURCE_NAMES[i]);
1286         }
1287       }
1288       rslt = CFG_EXIT;
1289       break;
1290     default:
1291       rslt = parse_cfg_option(opt, optarg, opt_line[optind], *rcfg, rmsg);
1292       if (rslt != CFG_OK) {
1293         return rslt;
1294       }
1295     }                           /* switch(opt) */
1296   }                             /* while getopt_long() */
1297
1298   while (optind < opt_argc) {
1299     PARSER_DEBUG_PRINTF("new interface %s\n", opt_argv[optind]);
1300     queue_if(opt_argv[optind++], *rcfg);
1301   }
1302
1303   /* Some cleanup */
1304   while (0 < opt_argc) {
1305     free(opt_argv[--opt_argc]);
1306   }
1307   free(opt_argv);
1308   free(opt_line);
1309   free(opt_str);
1310
1311   /* logging option post processing */
1312   if (rslt != CFG_ERROR && rslt != CFG_EXIT) {
1313     if (!((*rcfg)->log_target_syslog || (*rcfg)->log_target_syslog || (*rcfg)->log_target_file != NULL)) {
1314       (*rcfg)->log_target_stderr = true;
1315       PARSER_DEBUG_PRINTF("Log: activate default logging target stderr\n");
1316     }
1317     for (opt = SEVERITY_INFO; opt < LOG_SEVERITY_COUNT; opt++) {
1318       if (!cfg_has_log[opt] && cfg_has_log[opt - 1]) {
1319         int i;
1320
1321         PARSER_DEBUG_PRINTF("Log: copy log level %s to %s\n", LOG_SEVERITY_NAMES[opt - 1], LOG_SEVERITY_NAMES[opt]);
1322
1323         /* copy debug to info, info to warning, warning to error (if neccessary) */
1324         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1325           (*rcfg)->log_event[opt][i] = (*rcfg)->log_event[opt - 1][i];
1326         }
1327         cfg_has_log[opt] = true;
1328       }
1329     }
1330     if (!cfg_has_log[SEVERITY_ERR]) {
1331       /* no logging at all defined ? fall back to default */
1332       char def[10] = DEF_DEBUGLVL;
1333       parse_cfg_debug(def, *rcfg, rmsg);
1334     }
1335   }
1336   return rslt;
1337 }
1338
1339 /*
1340  * Checks a given config for illegal values
1341  */
1342 int
1343 olsr_sanity_check_cfg(struct olsr_config *cfg)
1344 {
1345   struct olsr_if_config *in = cfg->if_configs;
1346   struct olsr_if_options *io;
1347   struct millitxt_buf tbuf;
1348
1349   /* IP version */
1350   if (cfg->ip_version != AF_INET && cfg->ip_version != AF_INET6) {
1351     fprintf(stderr, "Ipversion %d not allowed!\n", cfg->ip_version);
1352     return -1;
1353   }
1354
1355   /* TOS */
1356   if (cfg->tos > MAX_TOS) {
1357     fprintf(stderr, "TOS %d is not allowed\n", cfg->tos);
1358     return -1;
1359   }
1360
1361   /* Willingness */
1362   if (cfg->willingness_auto == false && (cfg->willingness > MAX_WILLINGNESS)) {
1363     fprintf(stderr, "Willingness %d is not allowed\n", cfg->willingness);
1364     return -1;
1365   }
1366
1367   /* Check Link quality dijkstra limit */
1368   if (cfg->lq_dinter < cfg->pollrate && cfg->lq_dlimit != 255) {
1369     fprintf(stderr, "Link quality dijkstra limit must be higher than pollrate\n");
1370     return -1;
1371   }
1372
1373   /* NIC Changes Pollrate */
1374   if (cfg->nic_chgs_pollrate < MIN_NICCHGPOLLRT || cfg->nic_chgs_pollrate > MAX_NICCHGPOLLRT) {
1375     fprintf(stderr, "NIC Changes Pollrate %u ms is not allowed\n", cfg->nic_chgs_pollrate);
1376     return -1;
1377   }
1378
1379   /* TC redundancy */
1380   if (cfg->tc_redundancy > MAX_TC_REDUNDANCY) {
1381     fprintf(stderr, "TC redundancy %d is not allowed\n", cfg->tc_redundancy);
1382     return -1;
1383   }
1384
1385   /* MPR coverage */
1386   if (cfg->mpr_coverage < MIN_MPR_COVERAGE || cfg->mpr_coverage > MAX_MPR_COVERAGE) {
1387     fprintf(stderr, "MPR coverage %d is not allowed\n", cfg->mpr_coverage);
1388     return -1;
1389   }
1390
1391   /* NAT threshold value */
1392   if (cfg->lq_nat_thresh < 100 || cfg->lq_nat_thresh > 1000) {
1393     fprintf(stderr, "NAT threshold %s is not allowed\n", olsr_milli_to_txt(&tbuf, cfg->lq_nat_thresh));
1394     return -1;
1395   }
1396
1397   /* Source ip mode need fixed router id */
1398   if (0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)) && cfg->source_ip_mode) {
1399     fprintf(stderr, "You cannot use source ip routing without setting a fixed router id\n");
1400     return -1;
1401   }
1402
1403   /* check OLSR port */
1404   if (cfg->olsr_port == 0) {
1405     fprintf(stderr, "0 is not a valid UDP port\n");
1406     return -1;
1407   }
1408
1409   /* TC interval */
1410   if (cfg->tc_params.emission_interval < cfg->pollrate ||
1411       cfg->tc_params.emission_interval > cfg->tc_params.validity_time) {
1412     fprintf(stderr, "Bad TC parameters! (em: %u ms, vt: %u ms)\n",
1413         cfg->tc_params.emission_interval,
1414         cfg->tc_params.validity_time);
1415     return -1;
1416   }
1417
1418   /* MID interval */
1419   if (cfg->mid_params.emission_interval < cfg->pollrate ||
1420       cfg->mid_params.emission_interval > cfg->mid_params.validity_time) {
1421     fprintf(stderr, "Bad MID parameters! (em: %u ms, vt: %u ms)\n",
1422         cfg->mid_params.emission_interval,
1423         cfg->mid_params.validity_time);
1424     return -1;
1425   }
1426
1427   /* HNA interval */
1428   if (cfg->hna_params.emission_interval < cfg->pollrate ||
1429       cfg->hna_params.emission_interval > cfg->hna_params.validity_time) {
1430     fprintf(stderr, "Bad HNA parameters! (em: %u ms, vt: %u ms)\n",
1431         cfg->hna_params.emission_interval,
1432         cfg->hna_params.validity_time);
1433     return -1;
1434   }
1435
1436   if (in == NULL) {
1437     fprintf(stderr, "No interfaces configured!\n");
1438     return -1;
1439   }
1440
1441   /* Interfaces */
1442   while (in) {
1443     io = in->cnf;
1444
1445     if (in->name == NULL || !strlen(in->name)) {
1446       fprintf(stderr, "Interface has no name!\n");
1447       return -1;
1448     }
1449
1450     if (io == NULL) {
1451       fprintf(stderr, "Interface %s has no configuration!\n", in->name);
1452       return -1;
1453     }
1454
1455     /* HELLO interval */
1456
1457     if (io->hello_params.emission_interval < cfg->pollrate ||
1458         io->hello_params.emission_interval > io->hello_params.validity_time) {
1459       fprintf(stderr, "Bad HELLO parameters! (em: %u ms, vt: %u ms)\n",
1460           io->hello_params.emission_interval,
1461           io->hello_params.validity_time);
1462       return -1;
1463     }
1464     in = in->next;
1465   }
1466
1467   return 0;
1468 }
1469
1470 /*
1471  * Free resources occupied by a configuration
1472  */
1473 void
1474 olsr_free_cfg(struct olsr_config *cfg)
1475 {
1476   struct olsr_if_config *ind, *in = cfg->if_configs;
1477   struct plugin_entry *ped, *pe = cfg->plugins;
1478   struct olsr_lq_mult *mult, *next_mult;
1479
1480   /* free logfile string if necessary */
1481   if (cfg->log_target_file) {
1482     free(cfg->log_target_file);
1483   }
1484
1485   /* free dynamic library path */
1486   if (cfg->dlPath) {
1487     free(cfg->dlPath);
1488   }
1489
1490   /*
1491    * Free HNAs.
1492    */
1493   ip_prefix_list_flush(&cfg->hna_entries);
1494
1495   /*
1496    * Free Interfaces - remove_interface() already called
1497    */
1498   while (in) {
1499     for (mult = in->cnf->lq_mult; mult != NULL; mult = next_mult) {
1500       next_mult = mult->next;
1501       free(mult);
1502     }
1503
1504     free(in->cnf);
1505     ind = in;
1506     in = in->next;
1507     free(ind->name);
1508     if (ind->config)
1509       free(ind->config);
1510     free(ind);
1511   }
1512
1513   /*
1514    * Free Plugins - olsr_close_plugins() allready called
1515    */
1516   while (pe) {
1517     struct plugin_param *pard, *par = pe->params;
1518     while (par) {
1519       pard = par;
1520       par = par->next;
1521       free(pard->key);
1522       free(pard->value);
1523       free(pard);
1524     }
1525     ped = pe;
1526     pe = pe->next;
1527     free(ped->name);
1528     free(ped);
1529   }
1530
1531   free(cfg);
1532
1533   return;
1534 }
1535
1536 /*
1537  * Get a default config
1538  */
1539 struct olsr_config *
1540 olsr_get_default_cfg(void)
1541 {
1542   int i;
1543   struct olsr_config *cfg = olsr_malloc(sizeof(struct olsr_config), "default config");
1544
1545   cfg->ip_version = AF_INET;
1546   cfg->ipsize = sizeof(struct in_addr);
1547
1548   assert(cfg->no_fork == false);
1549   cfg->allow_no_interfaces = DEF_ALLOW_NO_INTS;
1550   cfg->willingness_auto = DEF_WILL_AUTO;
1551   cfg->clear_screen = DEF_CLEAR_SCREEN;
1552   assert(cfg->del_gws == false);
1553
1554   cfg->tos = DEF_TOS;
1555   assert(cfg->rtproto == 0);
1556   cfg->rttable = 254;
1557   assert(cfg->rttable_default == 0);
1558   cfg->fib_metric = DEF_FIB_METRIC;
1559
1560   for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1561     assert(cfg->log_event[SEVERITY_DEBUG][i] == false);
1562     assert(cfg->log_event[SEVERITY_INFO][i] == false);
1563     assert(cfg->log_event[SEVERITY_WARN][i] == false);
1564     assert(cfg->log_event[SEVERITY_ERR][i] == false);
1565   }
1566   cfg->log_target_stderr = true;
1567   assert(cfg->log_target_file == NULL);
1568   assert(cfg->log_target_syslog == false);
1569
1570   assert(cfg->plugins == NULL);
1571   list_init_head(&cfg->hna_entries);
1572   assert(cfg->if_configs == NULL);
1573
1574   cfg->pollrate = DEF_POLLRATE;
1575   cfg->nic_chgs_pollrate = DEF_NICCHGPOLLRT;
1576   cfg->lq_nat_thresh = DEF_LQ_NAT_THRESH;
1577   cfg->tc_redundancy = TC_REDUNDANCY;
1578   cfg->mpr_coverage = MPR_COVERAGE;
1579   cfg->lq_fish = DEF_LQ_FISH;
1580   cfg->lq_dinter = DEF_LQ_DIJK_INTER;
1581   cfg->lq_dlimit = DEF_LQ_DIJK_LIMIT;
1582   assert(cfg->willingness == 0);
1583
1584   cfg->olsr_port = OLSRPORT;
1585   assert(cfg->dlPath == NULL);
1586
1587   cfg->comport_http       = DEF_HTTPPORT;
1588   cfg->comport_http_limit = DEF_HTTPLIMIT;
1589   cfg->comport_txt        = DEF_TXTPORT;
1590   cfg->comport_txt_limit  = DEF_TXTLIMIT;
1591
1592
1593   cfg->tc_params.emission_interval = TC_INTERVAL;
1594   cfg->tc_params.validity_time = TOP_HOLD_TIME;
1595   cfg->mid_params.emission_interval = MID_INTERVAL;
1596   cfg->mid_params.validity_time = MID_HOLD_TIME;
1597   cfg->hna_params.emission_interval = HNA_INTERVAL;
1598   cfg->hna_params.validity_time = HNA_HOLD_TIME;
1599
1600   assert(0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)));
1601   assert(0 == cfg->source_ip_mode);
1602   cfg->will_int = 10 * HELLO_INTERVAL;
1603   cfg->exit_value = EXIT_SUCCESS;
1604
1605   assert(cfg->ioctl_s == 0);
1606 #if defined linux
1607   assert(cfg->rts_linux == 0);
1608 #endif
1609 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
1610   assert(cfg->rts_bsd == 0);
1611 #endif
1612
1613   return cfg;
1614 }
1615
1616 /*
1617  * Local Variables:
1618  * c-basic-offset: 2
1619  * indent-tabs-mode: nil
1620  * End:
1621  */