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