bcdcc4730d1f69932a1315c3ea722d8d3585583e
[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 "olsr_ip_prefix_list.h"
49 #include "olsr_protocol.h"
50 #include "common/string.h"
51 #include "olsr_clock.h"
52 #include "os_net.h"
53 #include "os_system.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])) || (0 == strcasecmp("TcValidityTime", p_next[0])) ||
511                      (0 == strcasecmp("Midinterval", p_next[0])) || (0 == strcasecmp("MidValidityTime", p_next[0])) ||
512                      (0 == strcasecmp("Hnainterval", p_next[0])) || (0 == strcasecmp("HnaValidityTime", p_next[0]))) {
513             fprintf(stderr,"ERROR: %s is deprecated within the interface section. All message intervals/validities except Hellos are global!\n",p_next[0]);
514             os_exit(1);
515           } else if (0 == strcasecmp("Weight", p_next[0])) {
516             new_if->cnf->weight.fixed = true;
517             PARSER_DEBUG_PRINTF("\tFixed willingness: %d\n", new_if->cnf->weight.value);
518           } else if (0 == strcasecmp("LinkQualityMult", p_next[0])) {
519             float f;
520             struct olsr_lq_mult *mult = olsr_malloc(sizeof(*mult), "lqmult");
521             if (!p_next[2]) {
522               sprintf(rmsg, "Odd args in %s\n", nxt);
523               parse_tok_free(tok_next);
524               parse_tok_free(tok);
525               return CFG_ERROR;
526             }
527             memset(&mult->addr, 0, sizeof(mult->addr));
528             if (0 != strcasecmp("default", p_next[1])) {
529               if (inet_pton(rcfg->ip_version, p_next[1], &mult->addr) <= 0) {
530                 sprintf(rmsg, "Failed converting IP address %s\n", p_next[1]);
531                 parse_tok_free(tok_next);
532                 parse_tok_free(tok);
533                 return CFG_ERROR;
534               }
535             }
536             f = 0;
537             sscanf(p_next[2], "%f", &f);
538             mult->value = (uint32_t) (f * LINK_LOSS_MULTIPLIER);
539             mult->next = new_if->cnf->lq_mult;
540             new_if->cnf->lq_mult = mult;
541             PARSER_DEBUG_PRINTF("\tLinkQualityMult %s %0.2f\n", ip_to_string(rcfg->ip_version, &buf, &mult->addr),
542                                 (float)mult->value / LINK_LOSS_MULTIPLIER);
543             p_next++;
544           } else {
545             sprintf(rmsg, "Unknown arg: %s %s\n", p_next[0], p_next[1]);
546             parse_tok_free(tok_next);
547             parse_tok_free(tok);
548             return CFG_ERROR;
549           }
550           p_next += 2;
551         }
552         p++;
553       }
554       parse_tok_free(tok_next);
555     }
556     parse_tok_free(tok);
557   } else {
558     sprintf(rmsg, "Error in %s\n", argstr);
559     return CFG_ERROR;
560   }
561   return CFG_OK;
562 }
563
564 /*
565  * Parses a single loadplugin option block
566  * @argstr:     arguments string
567  * @rcfg:       config struct to write/change values into
568  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
569  * @returns configuration status as defined in olsr_parse_cfg_result
570  */
571 static olsr_parse_cfg_result
572 parse_cfg_loadplugin(char *argstr, struct olsr_config *rcfg, char *rmsg)
573 {
574   char **tok;
575   const char *nxt;
576   if (NULL != (tok = parse_tok(argstr, &nxt))) {
577     if ('{' != *nxt) {
578       sprintf(rmsg, "No {}\n");
579       parse_tok_free(tok);
580       return CFG_ERROR;
581     } else {
582       char **tok_next = parse_tok(nxt + 1, NULL);
583       struct plugin_entry *pe = olsr_malloc(sizeof(*pe), "plugin");
584       pe->name = olsr_strdup(*tok);
585       pe->params = NULL;
586       pe->next = rcfg->plugins;
587       rcfg->plugins = pe;
588       PARSER_DEBUG_PRINTF("Plugin: %s\n", pe->name);
589       if (tok_next) {
590         char **p_next = tok_next;
591         while (p_next[0]) {
592           struct plugin_param *pp = olsr_malloc(sizeof(*pp), "plparam");
593           if (0 != strcasecmp("PlParam", p_next[0]) || !p_next[1] || !p_next[2]) {
594             sprintf(rmsg, "Odd args in %s\n", nxt);
595             parse_tok_free(tok_next);
596             parse_tok_free(tok);
597             return CFG_ERROR;
598           }
599           pp->key = olsr_strdup(p_next[1]);
600           pp->value = olsr_strdup(p_next[2]);
601           pp->next = pe->params;
602           pe->params = pp;
603           PARSER_DEBUG_PRINTF("\tPlParam: %s %s\n", pp->key, pp->value);
604           p_next += 3;
605         }
606         parse_tok_free(tok_next);
607       }
608     }
609     parse_tok_free(tok);
610   } else {
611     sprintf(rmsg, "Error in %s\n", argstr);
612     return CFG_ERROR;
613   }
614   return CFG_OK;
615 }
616
617 /*
618  * Parses a the parameter string of --log(debug|info|warn|error)
619  * @argstr:     arguments string
620  * @rcfg:       config struct to write/change values into
621  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
622  * @returns configuration status as defined in olsr_parse_cfg_result
623  */
624 static olsr_parse_cfg_result
625 parse_cfg_debug(char *argstr, struct olsr_config *rcfg, char *rmsg)
626 {
627   int dlevel, i;
628   dlevel = atoi(argstr);
629
630   if (dlevel < MIN_DEBUGLVL || dlevel > MAX_DEBUGLVL) {
631     sprintf(rmsg, "Error, debug level must be between -2 and 3\n");
632     return CFG_ERROR;
633   }
634
635   switch (dlevel) {
636   case 3:
637     /* all logging */
638     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
639       rcfg->log_event[SEVERITY_DEBUG][i] = true;
640     }
641   case 2:
642     /* all info, warnings and errors */
643     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
644       rcfg->log_event[SEVERITY_INFO][i] = true;
645     }
646   case 1:
647     /* some INFO level output, plus all warnings and errors */
648     rcfg->log_event[SEVERITY_INFO][LOG_2NEIGH] = true;
649     rcfg->log_event[SEVERITY_INFO][LOG_LINKS] = true;
650     rcfg->log_event[SEVERITY_INFO][LOG_MAIN] = true;
651     rcfg->log_event[SEVERITY_INFO][LOG_NEIGHTABLE] = true;
652     rcfg->log_event[SEVERITY_INFO][LOG_PLUGINS] = true;
653     rcfg->log_event[SEVERITY_INFO][LOG_ROUTING] = true;
654     rcfg->log_event[SEVERITY_INFO][LOG_TC] = true;
655   case 0:
656     /* errors and warnings */
657     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
658       rcfg->log_event[SEVERITY_WARN][i] = true;
659     }
660   case -1:
661     /* only error messages */
662     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
663       rcfg->log_event[SEVERITY_ERR][i] = true;
664     }
665   default:                     /* no logging at all ! */
666     break;
667   }
668
669   PARSER_DEBUG_PRINTF("Debug level: %d\n", dlevel);
670
671   if (dlevel > 0) {
672     rcfg->no_fork = 1;
673   }
674
675   /* prevent fallback to default 0 */
676   cfg_has_log[SEVERITY_ERR] = true;
677   return CFG_OK;
678 }
679
680 /*
681  * Parses a the parameter string of --log(debug|info|warn|error)
682  * @argstr:     arguments string
683  * @rcfg:       config struct to write/change values into
684  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
685  * @returns configuration status as defined in olsr_parse_cfg_result
686  */
687 static olsr_parse_cfg_result
688 parse_cfg_log(char *argstr, struct olsr_config *rcfg, char *rmsg, enum log_severity sev)
689 {
690   char *p = (char *)argstr, *next;
691   int i;
692   bool first;
693
694   while (p != NULL) {
695     /* split at ',' */
696     next = strchr(p, ',');
697     if (next) {
698       *next++ = 0;
699     }
700
701     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
702       if (strcasecmp(p, LOG_SOURCE_NAMES[i]) == 0) {
703         break;
704       }
705     }
706
707     if (i == LOG_SOURCE_COUNT) {
708       sprintf(rmsg, "Error, unknown logging source: %s\n", p);
709       return CFG_ERROR;
710     }
711
712     /* handle "all" keyword */
713     if (i == LOG_ALL) {
714       for (i = 0; i < LOG_SOURCE_COUNT; i++) {
715         rcfg->log_event[sev][i] = true;
716       }
717     }
718     else {
719       rcfg->log_event[sev][i] = true;
720     }
721     p = next;
722   }
723
724
725   PARSER_DEBUG_PRINTF("Log_%s:", LOG_SEVERITY_NAMES[sev]);
726   for (i = 0, first = true; i < LOG_SOURCE_COUNT; i++) {
727     if (rcfg->log_event[sev][i]) {
728       PARSER_DEBUG_PRINTF("%c%s", first ? ' ' : ',', LOG_SOURCE_NAMES[i]);
729       first = false;
730     }
731   }
732   PARSER_DEBUG_PRINTF("\n");
733   cfg_has_log[sev] = true;
734   return CFG_OK;
735 }
736
737 /*
738  * Parses a single option found on the command line.
739  * @optint: return value of previous getopt_long()
740  * @argstr: argument string provided by getopt_long()
741  * @line:   line number (if option is read from file)
742  * @rcfg:   config struct to write/change values into
743  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
744  * @returns configuration status as defined in olsr_parse_cfg_result
745  */
746 static olsr_parse_cfg_result
747 parse_cfg_option(const int optint, char *argstr, const int line, struct olsr_config *rcfg, char *rmsg)
748 {
749   switch (optint) {
750   case 'i':                    /* iface */
751     /* Ignored */
752     break;
753   case 'n':                    /* nofork */
754     rcfg->no_fork = true;
755     PARSER_DEBUG_PRINTF("no_fork set to %d\n", rcfg->no_fork);
756     break;
757   case 'A':                    /* AllowNoInt (yes/no) */
758     rcfg->allow_no_interfaces = (0 == strcasecmp("yes", argstr));
759     PARSER_DEBUG_PRINTF("Noint set to %d\n", rcfg->allow_no_interfaces);
760     break;
761   case 'C':                    /* ClearScreen (yes/no) */
762     rcfg->clear_screen = (0 == strcasecmp("yes", argstr));
763     PARSER_DEBUG_PRINTF("Clear screen %s\n", rcfg->clear_screen ? "enabled" : "disabled");
764     break;
765   case 'd':                    /* DebugLevel (i) */
766     return parse_cfg_debug(argstr, rcfg, rmsg);
767     break;
768   case 'F':                    /* FIBMetric (str) */
769     {
770       char **tok;
771       if (NULL != (tok = parse_tok(argstr, NULL))) {
772         if (strcasecmp(*tok, CFG_FIBM_FLAT) == 0) {
773           rcfg->fib_metric = FIBM_FLAT;
774         } else if (strcasecmp(*tok, CFG_FIBM_CORRECT) == 0) {
775           rcfg->fib_metric = FIBM_CORRECT;
776         } else if (strcasecmp(*tok, CFG_FIBM_APPROX) == 0) {
777           rcfg->fib_metric = FIBM_APPROX;
778         } else {
779           sprintf(rmsg, "FIBMetric must be \"%s\", \"%s\", or \"%s\"!\n", CFG_FIBM_FLAT, CFG_FIBM_CORRECT, CFG_FIBM_APPROX);
780           return CFG_ERROR;
781         }
782         parse_tok_free(tok);
783       } else {
784         sprintf(rmsg, "Error in %s\n", argstr);
785         return CFG_ERROR;
786       }
787       PARSER_DEBUG_PRINTF("FIBMetric: %d=%s\n", rcfg->fib_metric, argstr);
788     }
789     break;
790   case '4':                    /* Hna4 (4body) */
791     return parse_cfg_hna(argstr, AF_INET, rcfg, rmsg);
792     break;
793   case '6':                    /* Hna6 (6body) */
794     return parse_cfg_hna(argstr, AF_INET6, rcfg, rmsg);
795     break;
796   case 'I':                    /* Interface if1 if2 { ifbody } */
797     return parse_cfg_interface(argstr, rcfg, rmsg);
798     break;
799   case 'V':                    /* IpVersion (i) */
800     {
801       int ver = -1;
802       sscanf(argstr, "%d", &ver);
803       if (ver == 4) {
804         rcfg->ip_version = AF_INET;
805         rcfg->ipsize = sizeof(struct in_addr);
806       } else if (ver == 6) {
807         rcfg->ip_version = AF_INET6;
808         rcfg->ipsize = sizeof(struct in6_addr);
809       } else {
810         sprintf(rmsg, "IpVersion must be 4 or 6!\n");
811         return CFG_ERROR;
812       }
813     }
814     PARSER_DEBUG_PRINTF("IpVersion: %d\n", rcfg->ip_version);
815     break;
816   case 'E':                    /* LinkQualityFishEye (i) */
817     {
818       int arg = -1;
819       sscanf(argstr, "%d", &arg);
820       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->lq_fish))))
821         rcfg->lq_fish = arg;
822       PARSER_DEBUG_PRINTF("Link quality fish eye %d\n", rcfg->lq_fish);
823     }
824     break;
825   case 'p':                    /* LoadPlugin (soname {PlParams}) */
826     return parse_cfg_loadplugin(argstr, rcfg, rmsg);
827     break;
828   case 'M':                    /* MprCoverage (i) */
829     {
830       int arg = -1;
831       sscanf(argstr, "%d", &arg);
832       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->mpr_coverage))))
833         rcfg->mpr_coverage = arg;
834       PARSER_DEBUG_PRINTF("MPR coverage %d\n", rcfg->mpr_coverage);
835     }
836     break;
837   case 'N':                    /* NatThreshold (f) */
838     {
839 #ifdef DEBUG
840       struct millitxt_buf tbuf;
841 #endif
842
843       rcfg->lq_nat_thresh = olsr_txt_to_milli(argstr);
844       PARSER_DEBUG_PRINTF("NAT threshold %s\n", olsr_milli_to_txt(&tbuf, rcfg->lq_nat_thresh));
845     }
846     break;
847   case 'Y':                    /* NicChgsPollInt (f) */
848     rcfg->nic_chgs_pollrate = olsr_txt_to_milli(argstr);
849     PARSER_DEBUG_PRINTF("NIC Changes Pollrate %u ms\n", rcfg->nic_chgs_pollrate);
850     break;
851   case 'T':                    /* Pollrate (f) */
852     {
853       rcfg->pollrate = olsr_txt_to_milli(argstr);
854       PARSER_DEBUG_PRINTF("Pollrate %u ms\n", rcfg->pollrate);
855     }
856     break;
857   case 'q':                    /* RtProto (i) */
858     {
859       int arg = -1;
860       sscanf(argstr, "%d", &arg);
861       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_proto))))
862         rcfg->rt_proto = arg;
863       PARSER_DEBUG_PRINTF("RtProto: %d\n", rcfg->rt_proto);
864     }
865     break;
866   case 'R':                    /* RtTableDefault (i) */
867     {
868       int arg = -1;
869       sscanf(argstr, "%d", &arg);
870       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_table_default))))
871         rcfg->rt_table_default = arg;
872       PARSER_DEBUG_PRINTF("RtTableDefault: %d\n", rcfg->rt_table_default);
873     }
874     break;
875   case 'r':                    /* RtTable (i) */
876     {
877       int arg = -1;
878       sscanf(argstr, "%d", &arg);
879       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_table))))
880         rcfg->rt_table = arg;
881       PARSER_DEBUG_PRINTF("RtTable: %d\n", rcfg->rt_table);
882     }
883     break;
884   case 't':                    /* TcRedundancy (i) */
885     {
886       int arg = -1;
887       sscanf(argstr, "%d", &arg);
888       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tc_redundancy))))
889         rcfg->tc_redundancy = arg;
890       PARSER_DEBUG_PRINTF("TC redundancy %d\n", rcfg->tc_redundancy);
891     }
892     break;
893   case 'Z':                    /* TosValue (i) */
894     {
895       int arg = -1;
896       sscanf(argstr, "%d", &arg);
897       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tos))))
898         rcfg->tos = arg;
899       PARSER_DEBUG_PRINTF("TOS: %d\n", rcfg->tos);
900     }
901     break;
902   case 'w':                    /* Willingness (i) */
903     {
904       int arg = -1;
905       sscanf(argstr, "%d", &arg);
906       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->willingness))))
907         rcfg->willingness = arg;
908       rcfg->willingness_auto = false;
909       PARSER_DEBUG_PRINTF("Willingness: %d (no auto)\n", rcfg->willingness);
910     }
911     break;
912   case CFG_LOG_DEBUG:          /* Log (string) */
913     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_DEBUG);
914     break;
915   case CFG_LOG_INFO:           /* Log (string) */
916     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_INFO);
917     break;
918   case CFG_LOG_WARN:           /* Log (string) */
919     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_WARN);
920     break;
921   case CFG_LOG_ERROR:          /* Log (string) */
922     return parse_cfg_log(argstr, rcfg, rmsg, SEVERITY_ERR);
923     break;
924   case CFG_LOG_STDERR:
925     rcfg->log_target_stderr = true;
926     break;
927   case CFG_LOG_SYSLOG:
928     rcfg->log_target_syslog = true;
929     break;
930   case CFG_LOG_FILE:
931     rcfg->log_target_file = strdup(argstr);
932     break;
933
934   case 's':                    /* SourceIpMode (string) */
935     rcfg->source_ip_mode = (0 == strcasecmp("yes", argstr)) ? 1 : 0;
936     PARSER_DEBUG_PRINTF("Source IP mode %s\n", rcfg->source_ip_mode ? "enabled" : "disabled");
937     break;
938   case 'o':                    /* Originator Address (ip) */
939     if (inet_pton(AF_INET, argstr, &rcfg->router_id) <= 0) {
940       sprintf(rmsg, "Failed converting IP address %s for originator address\n", argstr);
941       return CFG_ERROR;
942     }
943     break;
944   case CFG_OLSRPORT:           /* port (i) */
945     {
946       int arg = -1;
947       sscanf(argstr, "%d", &arg);
948       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->olsr_port))))
949         rcfg->olsr_port = arg;
950       PARSER_DEBUG_PRINTF("OLSR port: %d\n", rcfg->olsr_port);
951     }
952     break;
953   case CFG_DLPATH:
954     rcfg->dlPath = strdup(argstr);
955     PARSER_DEBUG_PRINTF("Dynamic library path: %s\n", rcfg->dlPath);
956     break;
957   case CFG_HTTPPORT:
958     {
959       int arg = -1;
960       sscanf(argstr, "%d", &arg);
961       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http))))
962         rcfg->comport_http = arg;
963       PARSER_DEBUG_PRINTF("HTTP port: %d\n", rcfg->comport_http);
964     }
965     break;
966   case CFG_HTTPLIMIT:
967     {
968       int arg = -1;
969       sscanf(argstr, "%d", &arg);
970       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http_limit))))
971         rcfg->comport_http_limit = arg;
972       PARSER_DEBUG_PRINTF("HTTP connection limit: %d\n", rcfg->comport_http_limit);
973     }
974     break;
975   case CFG_TXTPORT:
976     {
977       int arg = -1;
978       sscanf(argstr, "%d", &arg);
979       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt))))
980         rcfg->comport_txt = arg;
981       PARSER_DEBUG_PRINTF("TXT port: %d\n", rcfg->comport_txt);
982     }
983     break;
984   case CFG_TXTLIMIT:
985     {
986       int arg = -1;
987       sscanf(argstr, "%d", &arg);
988       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt_limit))))
989         rcfg->comport_txt_limit = arg;
990       PARSER_DEBUG_PRINTF("TXT connection limit: %d\n", rcfg->comport_txt_limit);
991     }
992     break;
993   case CFG_HNA_HTIME:
994     rcfg->hna_params.emission_interval = olsr_txt_to_milli(argstr);
995     PARSER_DEBUG_PRINTF("HNA interval1: %u ms\n", rcfg->hna_params.emission_interval);
996     break;
997   case CFG_HNA_VTIME:
998     rcfg->hna_params.validity_time = olsr_txt_to_milli(argstr);
999     PARSER_DEBUG_PRINTF("HNA validity: %u ms\n", rcfg->hna_params.validity_time);
1000     break;
1001   case CFG_MID_HTIME:
1002     rcfg->mid_params.emission_interval = olsr_txt_to_milli(argstr);
1003     PARSER_DEBUG_PRINTF("MID interval1: %u ms\n", rcfg->mid_params.emission_interval);
1004     break;
1005   case CFG_MID_VTIME:
1006     rcfg->mid_params.validity_time = olsr_txt_to_milli(argstr);
1007     PARSER_DEBUG_PRINTF("MID validity: %u ms\n", rcfg->mid_params.validity_time);
1008     break;
1009   case CFG_TC_HTIME:
1010     rcfg->tc_params.emission_interval = olsr_txt_to_milli(argstr);
1011     PARSER_DEBUG_PRINTF("TC interval1: %u ms\n", rcfg->tc_params.emission_interval);
1012     break;
1013   case CFG_TC_VTIME:
1014     rcfg->tc_params.validity_time = olsr_txt_to_milli(argstr);
1015     PARSER_DEBUG_PRINTF("TC validity: %u ms\n", rcfg->tc_params.validity_time);
1016     break;
1017
1018   default:
1019     sprintf(rmsg, "Unknown arg in line %d.\n", line);
1020     return CFG_ERROR;
1021   }                             /* switch */
1022   return CFG_OK;
1023 }
1024
1025 /*
1026  * Parses command line options using the getopt() runtime
1027  * function. May also replace a "-f filename" combination
1028  * with options read in from a config file.
1029  *
1030  * @argc: the argv count from main() - or zero if no argv
1031  * @argv: the array of strings provided from the enviroment
1032  * @file: the default config file name (used if argc <= 1)
1033  * @rmsg: to provide buf[FILENAME_MAX + 256] to sprint err msgs
1034  * @rcfg: returns a valid config pointer, clean with olsr_free_cfg()
1035  * @returns a parsing status result code
1036  */
1037 olsr_parse_cfg_result
1038 olsr_parse_cfg(int argc, char *argv[], const char *file, char *rmsg, struct olsr_config ** rcfg)
1039 {
1040   int opt;
1041   int opt_idx = 0;
1042   char *opt_str = 0;
1043   int opt_argc = 0;
1044   char **opt_argv = olsr_malloc(argc * sizeof(opt_argv[0]), "opt_argv");
1045   int *opt_line = olsr_malloc(argc * sizeof(opt_line[0]), "opt_line");
1046   olsr_parse_cfg_result rslt = CFG_OK;
1047
1048   /*
1049    * Original cmd line params
1050    *
1051    * -bcast                   (removed)
1052    * -delgw                   (-> --delgw)
1053    * -dispin                  (-> --dispin)
1054    * -dispout                 (-> --dispout)
1055    * -d (level)               (preserved)
1056    * -f (config)              (preserved)
1057    * -hemu (queue_if(hcif01)) (-> --hemu)
1058    * -hint                    (removed)
1059    * -hnaint                  (removed)
1060    * -i if0 if1...            (see comment below)
1061    * -int (WIN32)             (preserved)
1062    * -ipc (ipc conn = 1)      (-> --ipc)
1063    * -ipv6                    (-> -V or --IpVersion)
1064    * -lqa (lq aging)          (removed)
1065    * -lql (lq lev)            (removed)
1066    * -lqnt (lq nat)           (removed)
1067    * -midint                  (removed)
1068    * -multi (ipv6 mcast)      (removed)
1069    * -nofork                  (preserved)
1070    * -tcint                   (removed)
1071    * -T (pollrate)            (preserved)
1072    *
1073    * Note: Remaining args are interpreted as list of
1074    * interfaces. For this reason, '-i' is ignored which
1075    * adds the following non-minus args to the list.
1076    */
1077
1078   /* *INDENT-OFF* */
1079   static struct option long_options[] = {
1080     {"config",                   required_argument, 0, 'f'}, /* (filename) */
1081     {"delgw",                    no_argument,       0, 'D'},
1082     {"help",                     optional_argument, 0, 'h'},
1083     {"iface",                    no_argument,       0, 'i'}, /* if0 if1... */
1084 #ifdef WIN32
1085     {"int",                      no_argument,       0, 'l'},
1086 #endif
1087     {"ipc",                      no_argument,       0, 'P'},
1088     {"log_debug",                required_argument, 0, CFG_LOG_DEBUG}, /* src1,src2,... */
1089     {"log_info",                 required_argument, 0, CFG_LOG_INFO}, /* src1,src2,... */
1090     {"log_warn",                 required_argument, 0, CFG_LOG_WARN}, /* src1,src2,... */
1091     {"log_error",                required_argument, 0, CFG_LOG_ERROR}, /* src1,src2,... */
1092     {"log_stderr",               no_argument,       0, CFG_LOG_STDERR},
1093     {"log_syslog",               no_argument,       0, CFG_LOG_SYSLOG},
1094     {"log_file",                 required_argument, 0, CFG_LOG_FILE}, /* (filename) */
1095     {"nofork",                   no_argument,       0, 'n'},
1096     {"version",                  no_argument,       0, 'v'},
1097     {"AllowNoInt",               required_argument, 0, 'A'}, /* (yes/no) */
1098     {"ClearScreen",              required_argument, 0, 'C'}, /* (yes/no) */
1099     {"DebugLevel",               required_argument, 0, 'd'}, /* (i) */
1100     {"FIBMetric",                required_argument, 0, 'F'}, /* (str) */
1101     {"Hna4",                     required_argument, 0, '4'}, /* (4body) */
1102     {"Hna6",                     required_argument, 0, '6'}, /* (6body) */
1103     {"Interface",                required_argument, 0, 'I'}, /* (if1 if2 {ifbody}) */
1104     {"IpVersion",                required_argument, 0, 'V'}, /* (i) */
1105     {"LinkQualityDijkstraLimit", required_argument, 0, 'J'}, /* (i,f) */
1106     {"LinkQualityFishEye",       required_argument, 0, 'E'}, /* (i) */
1107     {"LoadPlugin",               required_argument, 0, 'p'}, /* (soname {PlParams}) */
1108     {"MprCoverage",              required_argument, 0, 'M'}, /* (i) */
1109     {"NatThreshold",             required_argument, 0, 'N'}, /* (f) */
1110     {"NicChgsPollInt",           required_argument, 0, 'Y'}, /* (f) */
1111     {"Pollrate",                 required_argument, 0, 'T'}, /* (f) */
1112     {"RtProto",                  required_argument, 0, 'q'}, /* (i) */
1113     {"RtTableDefault",           required_argument, 0, 'R'}, /* (i) */
1114     {"RtTable",                  required_argument, 0, 'r'}, /* (i) */
1115     {"TcRedundancy",             required_argument, 0, 't'}, /* (i) */
1116     {"TosValue",                 required_argument, 0, 'Z'}, /* (i) */
1117     {"Willingness",              required_argument, 0, 'w'}, /* (i) */
1118     {"RouterId",                 required_argument, 0, 'o'}, /* (ip) */
1119     {"SourceIpMode",             required_argument, 0, 's'}, /* (yes/no) */
1120     {"OlsrPort",                 required_argument, 0, CFG_OLSRPORT},  /* (i) */
1121     {"dlPath",                   required_argument, 0, CFG_DLPATH},    /* (path) */
1122     {"HttpPort",                 required_argument, 0, CFG_HTTPPORT},  /* (i) */
1123     {"HttpLimit",                required_argument, 0, CFG_HTTPLIMIT}, /* (i) */
1124     {"TxtPort",                  required_argument, 0, CFG_TXTPORT},   /* (i) */
1125     {"TxtLimit",                 required_argument, 0, CFG_TXTLIMIT},  /* (i) */
1126     {"TcInterval",               required_argument, 0, CFG_TC_HTIME},  /* (f) */
1127     {"TcValidityTime",           required_argument, 0, CFG_TC_VTIME},  /* (f) */
1128     {"MidInterval",              required_argument, 0, CFG_MID_HTIME},  /* (f) */
1129     {"MidValidityTime",          required_argument, 0, CFG_MID_VTIME},  /* (f) */
1130     {"HnaInterval",              required_argument, 0, CFG_HNA_HTIME},  /* (f) */
1131     {"HnaValidityTime",          required_argument, 0, CFG_HNA_VTIME},  /* (f) */
1132
1133     {"IpcConnect",               required_argument, 0,  0 }, /* ignored */
1134     {"UseHysteresis",            required_argument, 0,  0 }, /* ignored */
1135     {"HystScaling",              required_argument, 0,  0 }, /* ignored */
1136     {"HystThrHigh",              required_argument, 0,  0 }, /* ignored */
1137     {"HystThrLow",               required_argument, 0,  0 }, /* ignored */
1138     {"LinkQualityLevel",         required_argument, 0,  0 }, /* ignored */
1139     {"LinkQualityWinsize",       required_argument, 0,  0 }, /* ignored */
1140     {"LinkQualityAlgorithm",     required_argument, 0,  0 }, /* ignored */
1141     {"LinkQualityAging",         required_argument, 0,  0 }, /* ignored */
1142     {"dispout",                  no_argument,       0,  0 }, /* ignored */
1143     {"dispin",                   no_argument,       0,  0 }, /* ignored */
1144     {0, 0, 0, 0}
1145   }, *popt = long_options;
1146   /* *INDENT-ON* */
1147
1148   /*
1149    * olsr_malloc() uses calloc, so opt_line is already filled
1150    * memset(opt_line, 0, argc * sizeof(opt_line[0]));
1151    */
1152
1153   /* cleanup static logsource flags */
1154   cfg_has_log[SEVERITY_DEBUG] = false;
1155   cfg_has_log[SEVERITY_INFO] = false;
1156   cfg_has_log[SEVERITY_WARN] = false;
1157   cfg_has_log[SEVERITY_ERR] = false;
1158
1159   /* Copy argv array for safe free'ing later on */
1160   while (opt_argc < argc) {
1161     const char *p = argv[opt_argc];
1162     if (0 == strcasecmp(p, "-nofork"))
1163       p = "-n";
1164 #ifdef WIN32
1165     else if (0 == strcasecmp(p, "-int"))
1166       p = "-l";
1167 #endif
1168     opt_argv[opt_argc] = olsr_strdup(p);
1169     opt_argc++;
1170   }
1171
1172   /* get option count */
1173   for (opt_idx = 0; long_options[opt_idx].name; opt_idx++);
1174
1175   /* Calculate short option string */
1176   opt_str = olsr_malloc(opt_idx * 3, "create short opt_string");
1177   opt_idx = 0;
1178   while (popt->name) {
1179     if (popt->val > 0 && popt->val < 128) {
1180       opt_str[opt_idx++] = popt->val;
1181
1182       switch (popt->has_arg) {
1183       case optional_argument:
1184         opt_str[opt_idx++] = ':';
1185         /* Fall through */
1186       case required_argument:
1187         opt_str[opt_idx++] = ':';
1188         break;
1189       }
1190     }
1191     popt++;
1192   }
1193
1194   /*
1195    * If no arguments, revert to default behaviour
1196    */
1197
1198   if (1 >= opt_argc) {
1199     char *argv0_tmp = opt_argv[0];
1200     free(opt_argv);
1201     opt_argv = olsr_malloc(3 * sizeof(opt_argv[0]), "default argv");
1202     opt_argv[0] = argv0_tmp;
1203     opt_argv[1] = olsr_strdup("-f");
1204     opt_argv[2] = olsr_strdup(file);
1205     opt_argc = 3;
1206   }
1207
1208   rmsg[0] = '\0';
1209   *rcfg = olsr_get_default_cfg();
1210
1211   while (0 <= (opt = getopt_long(opt_argc, opt_argv, opt_str, long_options, &opt_idx))) {
1212     switch (opt) {
1213     case 0:
1214       sprintf(rmsg, "Ignored deprecated %s\n", long_options[opt_idx].name);
1215       rslt = CFG_WARN;
1216       break;
1217     case 'f':                  /* config (filename) */
1218       PARSER_DEBUG_PRINTF("Read config from %s\n", optarg);
1219       if (0 > read_cfg(optarg, &opt_argc, &opt_argv, &opt_line)) {
1220         sprintf(rmsg, "Could not read specified config file %s!\n%s", optarg, strerror(errno));
1221         return CFG_ERROR;
1222       }
1223       break;
1224 #ifdef WIN32
1225     case 'l':                  /* win32: list ifaces */
1226       ListInterfaces();
1227       rslt = CFG_EXIT;
1228       break;
1229 #endif
1230     case 'v':                  /* version */
1231       fprintf(stderr,  "*** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
1232       rslt = CFG_EXIT;
1233       break;
1234     case 'h':                  /* help */
1235       popt = long_options;
1236       printf("Usage: olsrd [OPTIONS]... [interfaces]...\n");
1237       while (popt->name) {
1238         if (popt->val) {
1239           if (popt->val > 0 && popt->val < 128) {
1240             printf("-%c or --%s ", popt->val, popt->name);
1241           } else {
1242             printf("      --%s ", popt->name);
1243           }
1244           switch (popt->has_arg) {
1245           case required_argument:
1246             printf("arg");
1247             break;
1248           case optional_argument:
1249             printf("[arg]");
1250             break;
1251           }
1252           printf("\n");
1253         }
1254         popt++;
1255       }
1256       if (optarg == NULL) {
1257         printf("Use '--help=log'for help about the available logging sources\n");
1258       } else if (strcasecmp(optarg, "log") == 0) {
1259         int i;
1260
1261         printf("Log sources for --log_debug, --log_info, --log_warn and --log_error:\n");
1262         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1263           printf("\t%s\n", LOG_SOURCE_NAMES[i]);
1264         }
1265       }
1266       rslt = CFG_EXIT;
1267       break;
1268     default:
1269       rslt = parse_cfg_option(opt, optarg, opt_line[optind], *rcfg, rmsg);
1270       if (rslt != CFG_OK) {
1271         return rslt;
1272       }
1273     }                           /* switch(opt) */
1274   }                             /* while getopt_long() */
1275
1276   while (optind < opt_argc) {
1277     PARSER_DEBUG_PRINTF("new interface %s\n", opt_argv[optind]);
1278     queue_if(opt_argv[optind++], *rcfg);
1279   }
1280
1281   /* Some cleanup */
1282   while (0 < opt_argc) {
1283     free(opt_argv[--opt_argc]);
1284   }
1285   free(opt_argv);
1286   free(opt_line);
1287   free(opt_str);
1288
1289   /* logging option post processing */
1290   if (rslt != CFG_ERROR && rslt != CFG_EXIT) {
1291     if (!((*rcfg)->log_target_syslog || (*rcfg)->log_target_syslog || (*rcfg)->log_target_file != NULL)) {
1292       (*rcfg)->log_target_stderr = true;
1293       PARSER_DEBUG_PRINTF("Log: activate default logging target stderr\n");
1294     }
1295     for (opt = SEVERITY_INFO; opt < LOG_SEVERITY_COUNT; opt++) {
1296       if (!cfg_has_log[opt] && cfg_has_log[opt - 1]) {
1297         int i;
1298
1299         PARSER_DEBUG_PRINTF("Log: copy log level %s to %s\n", LOG_SEVERITY_NAMES[opt - 1], LOG_SEVERITY_NAMES[opt]);
1300
1301         /* copy debug to info, info to warning, warning to error (if neccessary) */
1302         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1303           (*rcfg)->log_event[opt][i] = (*rcfg)->log_event[opt - 1][i];
1304         }
1305         cfg_has_log[opt] = true;
1306       }
1307     }
1308     if (!cfg_has_log[SEVERITY_ERR]) {
1309       /* no logging at all defined ? fall back to default */
1310       char def[10] = DEF_DEBUGLVL;
1311       parse_cfg_debug(def, *rcfg, rmsg);
1312     }
1313   }
1314   return rslt;
1315 }
1316
1317 /*
1318  * Checks a given config for illegal values
1319  */
1320 int
1321 olsr_sanity_check_cfg(struct olsr_config *cfg)
1322 {
1323   struct olsr_if_config *in = cfg->if_configs;
1324   struct olsr_if_options *io;
1325   struct millitxt_buf tbuf;
1326
1327   /* rttable */
1328   if (cfg->rt_table == 0) cfg->rt_table = 254;
1329
1330   /* rttable_default */
1331   if (cfg->rt_table_default == 0) cfg->rt_table_default = cfg->rt_table;
1332
1333   /* IP version */
1334   if (cfg->ip_version != AF_INET && cfg->ip_version != AF_INET6) {
1335     fprintf(stderr, "Ipversion %d not allowed!\n", cfg->ip_version);
1336     return -1;
1337   }
1338
1339   /* TOS */
1340   if (cfg->tos > MAX_TOS) {
1341     fprintf(stderr, "TOS %d is not allowed\n", cfg->tos);
1342     return -1;
1343   }
1344
1345   /* Willingness */
1346   if (cfg->willingness_auto == false && (cfg->willingness > MAX_WILLINGNESS)) {
1347     fprintf(stderr, "Willingness %d is not allowed\n", cfg->willingness);
1348     return -1;
1349   }
1350
1351   /* NIC Changes Pollrate */
1352   if (cfg->nic_chgs_pollrate < MIN_NICCHGPOLLRT || cfg->nic_chgs_pollrate > MAX_NICCHGPOLLRT) {
1353     fprintf(stderr, "NIC Changes Pollrate %u ms is not allowed\n", cfg->nic_chgs_pollrate);
1354     return -1;
1355   }
1356
1357   /* TC redundancy */
1358   if (cfg->tc_redundancy > MAX_TC_REDUNDANCY) {
1359     fprintf(stderr, "TC redundancy %d is not allowed\n", cfg->tc_redundancy);
1360     return -1;
1361   }
1362
1363   /* MPR coverage */
1364   if (cfg->mpr_coverage < MIN_MPR_COVERAGE || cfg->mpr_coverage > MAX_MPR_COVERAGE) {
1365     fprintf(stderr, "MPR coverage %d is not allowed\n", cfg->mpr_coverage);
1366     return -1;
1367   }
1368
1369   /* NAT threshold value */
1370   if (cfg->lq_nat_thresh < 100 || cfg->lq_nat_thresh > 1000) {
1371     fprintf(stderr, "NAT threshold %s is not allowed\n", olsr_milli_to_txt(&tbuf, cfg->lq_nat_thresh));
1372     return -1;
1373   }
1374
1375   /* Source ip mode need fixed router id */
1376   if (0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)) && cfg->source_ip_mode) {
1377     fprintf(stderr, "You cannot use source ip routing without setting a fixed router id\n");
1378     return -1;
1379   }
1380
1381   /* check OLSR port */
1382   if (cfg->olsr_port == 0) {
1383     fprintf(stderr, "0 is not a valid UDP port\n");
1384     return -1;
1385   }
1386
1387   /* TC interval */
1388   if (cfg->tc_params.emission_interval < cfg->pollrate ||
1389       cfg->tc_params.emission_interval > cfg->tc_params.validity_time) {
1390     fprintf(stderr, "Bad TC parameters! (em: %u ms, vt: %u ms)\n",
1391         cfg->tc_params.emission_interval,
1392         cfg->tc_params.validity_time);
1393     return -1;
1394   }
1395
1396   /* MID interval */
1397   if (cfg->mid_params.emission_interval < cfg->pollrate ||
1398       cfg->mid_params.emission_interval > cfg->mid_params.validity_time) {
1399     fprintf(stderr, "Bad MID parameters! (em: %u ms, vt: %u ms)\n",
1400         cfg->mid_params.emission_interval,
1401         cfg->mid_params.validity_time);
1402     return -1;
1403   }
1404
1405   /* HNA interval */
1406   if (cfg->hna_params.emission_interval < cfg->pollrate ||
1407       cfg->hna_params.emission_interval > cfg->hna_params.validity_time) {
1408     fprintf(stderr, "Bad HNA parameters! (em: %u ms, vt: %u ms)\n",
1409         cfg->hna_params.emission_interval,
1410         cfg->hna_params.validity_time);
1411     return -1;
1412   }
1413
1414   if (in == NULL) {
1415     fprintf(stderr, "No interfaces configured!\n");
1416     return -1;
1417   }
1418
1419   /* Interfaces */
1420   while (in) {
1421     io = in->cnf;
1422
1423     if (in->name == NULL || !strlen(in->name)) {
1424       fprintf(stderr, "Interface has no name!\n");
1425       return -1;
1426     }
1427
1428     if (io == NULL) {
1429       fprintf(stderr, "Interface %s has no configuration!\n", in->name);
1430       return -1;
1431     }
1432
1433     /* HELLO interval */
1434
1435     if (io->hello_params.emission_interval < cfg->pollrate ||
1436         io->hello_params.emission_interval > io->hello_params.validity_time) {
1437       fprintf(stderr, "Bad HELLO parameters! (em: %u ms, vt: %u ms)\n",
1438           io->hello_params.emission_interval,
1439           io->hello_params.validity_time);
1440       return -1;
1441     }
1442     in = in->next;
1443   }
1444
1445   return 0;
1446 }
1447
1448 /*
1449  * Free resources occupied by a configuration
1450  */
1451 void
1452 olsr_free_cfg(struct olsr_config *cfg)
1453 {
1454   struct olsr_if_config *ind, *in = cfg->if_configs;
1455   struct plugin_entry *ped, *pe = cfg->plugins;
1456   struct olsr_lq_mult *mult, *next_mult;
1457
1458   /* free logfile string if necessary */
1459   if (cfg->log_target_file) {
1460     free(cfg->log_target_file);
1461   }
1462
1463   /* free dynamic library path */
1464   if (cfg->dlPath) {
1465     free(cfg->dlPath);
1466   }
1467
1468   /*
1469    * Free HNAs.
1470    */
1471   ip_prefix_list_flush(&cfg->hna_entries);
1472
1473   /*
1474    * Free Interfaces - remove_interface() already called
1475    */
1476   while (in) {
1477     for (mult = in->cnf->lq_mult; mult != NULL; mult = next_mult) {
1478       next_mult = mult->next;
1479       free(mult);
1480     }
1481
1482     free(in->cnf);
1483     ind = in;
1484     in = in->next;
1485     free(ind->name);
1486     if (ind->config)
1487       free(ind->config);
1488     free(ind);
1489   }
1490
1491   /*
1492    * Free Plugins - olsr_close_plugins() allready called
1493    */
1494   while (pe) {
1495     struct plugin_param *pard, *par = pe->params;
1496     while (par) {
1497       pard = par;
1498       par = par->next;
1499       free(pard->key);
1500       free(pard->value);
1501       free(pard);
1502     }
1503     ped = pe;
1504     pe = pe->next;
1505     free(ped->name);
1506     free(ped);
1507   }
1508
1509   free(cfg);
1510
1511   return;
1512 }
1513
1514 /*
1515  * Get a default config
1516  */
1517 struct olsr_config *
1518 olsr_get_default_cfg(void)
1519 {
1520   int i;
1521   struct olsr_config *cfg = olsr_malloc(sizeof(struct olsr_config), "default config");
1522
1523   cfg->ip_version = AF_INET;
1524   cfg->ipsize = sizeof(struct in_addr);
1525
1526   assert(cfg->no_fork == false);
1527   cfg->allow_no_interfaces = DEF_ALLOW_NO_INTS;
1528   cfg->willingness_auto = DEF_WILL_AUTO;
1529   cfg->clear_screen = DEF_CLEAR_SCREEN;
1530
1531   cfg->tos = DEF_TOS;
1532   assert(cfg->rt_proto == 0);
1533   cfg->rt_table = 254;
1534   assert(cfg->rt_table_default == 0); /*does this ever fire!*/
1535   cfg->fib_metric = DEF_FIB_METRIC;
1536
1537   for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1538     assert(cfg->log_event[SEVERITY_DEBUG][i] == false);
1539     assert(cfg->log_event[SEVERITY_INFO][i] == false);
1540     assert(cfg->log_event[SEVERITY_WARN][i] == false);
1541     assert(cfg->log_event[SEVERITY_ERR][i] == false);
1542   }
1543   cfg->log_target_stderr = true;
1544   assert(cfg->log_target_file == NULL);
1545   assert(cfg->log_target_syslog == false);
1546
1547   assert(cfg->plugins == NULL);
1548   list_init_head(&cfg->hna_entries);
1549   assert(cfg->if_configs == NULL);
1550
1551   cfg->pollrate = DEF_POLLRATE;
1552   cfg->nic_chgs_pollrate = DEF_NICCHGPOLLRT;
1553   cfg->lq_nat_thresh = DEF_LQ_NAT_THRESH;
1554   cfg->tc_redundancy = TC_REDUNDANCY;
1555   cfg->mpr_coverage = MPR_COVERAGE;
1556   cfg->lq_fish = DEF_LQ_FISH;
1557   assert(cfg->willingness == 0);
1558
1559   cfg->olsr_port = OLSRPORT;
1560   assert(cfg->dlPath == NULL);
1561
1562   cfg->comport_http       = DEF_HTTPPORT;
1563   cfg->comport_http_limit = DEF_HTTPLIMIT;
1564   cfg->comport_txt        = DEF_TXTPORT;
1565   cfg->comport_txt_limit  = DEF_TXTLIMIT;
1566
1567
1568   cfg->tc_params.emission_interval = TC_INTERVAL;
1569   cfg->tc_params.validity_time = TOP_HOLD_TIME;
1570   cfg->mid_params.emission_interval = MID_INTERVAL;
1571   cfg->mid_params.validity_time = MID_HOLD_TIME;
1572   cfg->hna_params.emission_interval = HNA_INTERVAL;
1573   cfg->hna_params.validity_time = HNA_HOLD_TIME;
1574
1575   assert(0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)));
1576   assert(0 == cfg->source_ip_mode);
1577   cfg->will_int = 10 * HELLO_INTERVAL;
1578   cfg->exit_value = EXIT_SUCCESS;
1579
1580   assert(cfg->ioctl_s == 0);
1581 #if defined linux
1582   assert(cfg->rtnl_s == 0);
1583 #endif
1584 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
1585   assert(cfg->rts_bsd == 0);
1586 #endif
1587
1588   return cfg;
1589 }
1590
1591 /*
1592  * Local Variables:
1593  * c-basic-offset: 2
1594  * indent-tabs-mode: nil
1595  * End:
1596  */