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