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