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