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