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