Merge branch 'master' into mpr_rework
[oonf.git] / src-plugins / olsrv2 / olsrv2 / olsrv2.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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 /**
43  * @file
44  */
45
46 #include <errno.h>
47
48 #include "common/avl.h"
49 #include "common/common_types.h"
50 #include "common/list.h"
51 #include "common/netaddr.h"
52 #include "common/netaddr_acl.h"
53 #include "config/cfg_schema.h"
54 #include "core/oonf_logging.h"
55 #include "core/oonf_subsystem.h"
56 #include "subsystems/oonf_rfc5444.h"
57 #include "subsystems/oonf_telnet.h"
58 #include "subsystems/oonf_timer.h"
59 #include "subsystems/os_interface.h"
60
61 #include "nhdp/nhdp_interfaces.h"
62
63 #include "olsrv2/olsrv2.h"
64 #include "olsrv2/olsrv2_lan.h"
65 #include "olsrv2/olsrv2_originator.h"
66 #include "olsrv2/olsrv2_reader.h"
67 #include "olsrv2/olsrv2_tc.h"
68 #include "olsrv2/olsrv2_writer.h"
69
70 /* definitions */
71
72 /*! configuration option for locally attached networks */
73 #define _LOCAL_ATTACHED_NETWORK_KEY "lan"
74
75 /**
76  * Default values for locally attached network parameters
77  */
78 enum _lan_option_defaults {
79   LAN_DEFAULT_DOMAIN    = 0,//!< LAN_DEFAULT_DOMAIN
80   LAN_DEFAULT_METRIC    = 1,//!< LAN_DEFAULT_METRIC
81   LAN_DEFAULT_DISTANCE  = 2,//!< LAN_DEFAULT_DISTANCE
82 };
83
84 /*! locally attached network option for source-specific prefix */
85 #define LAN_OPTION_SRC    "src="
86
87 /*! locally attached network option for outgoing metric */
88 #define LAN_OPTION_METRIC "metric="
89
90 /*! locally attached network option for domain */
91 #define LAN_OPTION_DOMAIN "domain="
92
93 /*! locally attached network option for hopcount distance */
94 #define LAN_OPTION_DIST   "dist="
95
96 /**
97  * olsrv2 plugin config
98  */
99 struct _config {
100   /*! topology control interval */
101   uint64_t tc_interval;
102
103   /*! topology control validity */
104   uint64_t tc_validity;
105
106   /*! olsrv2 f_hold_time */
107   uint64_t f_hold_time;
108
109   /*! olsrv2 p_hold_time */
110   uint64_t p_hold_time;
111
112   /*! decides NHDP routable status */
113   bool nhdp_routable;
114
115   /*! IP filter for routable addresses */
116   struct netaddr_acl routable_acl;
117
118   /*! IP filter for valid originator */
119   struct netaddr_acl originator_acl;
120 };
121
122 /**
123  * Additional parameters of a single locally attached network
124  */
125 struct _lan_data {
126   /*! domain of LAN */
127   struct nhdp_domain *domain;
128
129   /*! source prefix */
130   struct netaddr source_prefix;
131
132   /*! olsrv2 metric */
133   uint32_t metric;
134
135   /*! routing metric (distance) */
136   uint32_t dist;
137 };
138
139 /* prototypes */
140 static void _early_cfg_init(void);
141 static int _init(void);
142 static void _initiate_shutdown(void);
143 static void _cleanup(void);
144
145 static const char *_parse_lan_parameters(struct os_route_key *prefix,
146                 struct _lan_data *dst, const char *src);
147 static void _parse_lan_array(struct cfg_named_section *section, bool add);
148 static void _cb_generate_tc(struct oonf_timer_instance *);
149
150 static void _update_originator(int af_family);
151 static int _cb_if_event(struct os_interface_listener *);
152
153 static void _cb_cfg_olsrv2_changed(void);
154 static void _cb_cfg_domain_changed(void);
155
156 /* subsystem definition */
157 static struct cfg_schema_entry _rt_domain_entries[] = {
158   CFG_MAP_BOOL(olsrv2_routing_domain, use_srcip_in_routes, "srcip_routes", "true",
159       "Set the source IP of IPv4-routes to a fixed value."),
160   CFG_MAP_INT32_MINMAX(olsrv2_routing_domain, protocol, "protocol", "100",
161       "Protocol number to be used in routing table", 0, false, 1, 254),
162   CFG_MAP_INT32_MINMAX(olsrv2_routing_domain, table, "table", "254",
163       "Routing table number for routes", 0, false, 1, 254),
164   CFG_MAP_INT32_MINMAX(olsrv2_routing_domain, distance, "distance", "2",
165       "Metric Distance to be used in routing table", 0, false, 1, 255),
166   CFG_MAP_BOOL(olsrv2_routing_domain, source_specific, "source_specific", "true",
167       "This domain uses IPv6 source specific routing"),
168 };
169
170 static struct cfg_schema_section _rt_domain_section = {
171   .type = CFG_NHDP_DOMAIN_SECTION,
172   .mode = CFG_SSMODE_NAMED_WITH_DEFAULT,
173   .def_name = CFG_NHDP_DEFAULT_DOMAIN,
174   .cb_delta_handler = _cb_cfg_domain_changed,
175   .entries = _rt_domain_entries,
176   .entry_count = ARRAYSIZE(_rt_domain_entries),
177 };
178
179 static struct cfg_schema_entry _olsrv2_entries[] = {
180   CFG_MAP_CLOCK_MIN(_config, tc_interval, "tc_interval", "5.0",
181     "Time between two TC messages", 100),
182   CFG_MAP_CLOCK_MIN(_config, tc_validity, "tc_validity", "300.0",
183     "Validity time of a TC messages", 100),
184   CFG_MAP_CLOCK_MIN(_config, f_hold_time, "forward_hold_time", "300.0",
185     "Holdtime for forwarding set information", 100),
186   CFG_MAP_CLOCK_MIN(_config, p_hold_time, "processing_hold_time", "300.0",
187     "Holdtime for processing set information", 100),
188   CFG_MAP_BOOL(_config, nhdp_routable, "nhdp_routable", "no",
189     "Decides if NHDP interface addresses"
190     " are routed to other nodes. 'true' means the 'routable_acl' parameter"
191     " will be matched to the addresses to decide."),
192   CFG_MAP_ACL_V46(_config, routable_acl, "routable_acl",
193       OLSRV2_ROUTABLE_IPV4 OLSRV2_ROUTABLE_IPV6 ACL_DEFAULT_ACCEPT,
194     "Filter to decide which addresses are considered routable"),
195
196   CFG_VALIDATE_LAN(_LOCAL_ATTACHED_NETWORK_KEY, "",
197     "locally attached network, a combination of an"
198     " ip address or prefix followed by an up to four optional parameters"
199     " which define link metric cost, hopcount distance, domain of the prefix"
200     " and the source-prefix ( <"LAN_OPTION_METRIC"...> <"LAN_OPTION_DIST"...>"
201     " <"LAN_OPTION_DOMAIN"<num>/all> <"LAN_OPTION_SRC"...> ).",
202     .list = true),
203
204   CFG_MAP_ACL_V46(_config, originator_acl, "originator",
205     OLSRV2_ORIGINATOR_IPV4 OLSRV2_ORIGINATOR_IPV6 ACL_DEFAULT_ACCEPT,
206     "Filter for router originator addresses (ipv4 and ipv6)"
207     " from the interface addresses. Olsrv2 will prefer routable addresses"
208     " over linklocal addresses and addresses from loopback over other interfaces."),
209 };
210
211 static struct cfg_schema_section _olsrv2_section = {
212   .type = CFG_OLSRV2_SECTION,
213   .cb_delta_handler = _cb_cfg_olsrv2_changed,
214   .entries = _olsrv2_entries,
215   .entry_count = ARRAYSIZE(_olsrv2_entries),
216   .next_section = &_rt_domain_section,
217 };
218
219 static const char *_dependencies[] = {
220   OONF_CLASS_SUBSYSTEM,
221   OONF_RFC5444_SUBSYSTEM,
222   OONF_TIMER_SUBSYSTEM,
223   OONF_OS_INTERFACE_SUBSYSTEM,
224   OONF_NHDP_SUBSYSTEM,
225 };
226 static struct oonf_subsystem _olsrv2_subsystem = {
227   .name = OONF_OLSRV2_SUBSYSTEM,
228   .dependencies = _dependencies,
229   .dependencies_count = ARRAYSIZE(_dependencies),
230   .early_cfg_init = _early_cfg_init,
231   .init = _init,
232   .cleanup = _cleanup,
233   .initiate_shutdown = _initiate_shutdown,
234   .cfg_section = &_olsrv2_section,
235 };
236 DECLARE_OONF_PLUGIN(_olsrv2_subsystem);
237
238 static struct _config _olsrv2_config;
239
240 /* timer for TC generation */
241 static struct oonf_timer_class _tc_timer_class = {
242   .name = "TC generation",
243   .periodic = true,
244   .callback = _cb_generate_tc,
245 };
246
247 static struct oonf_timer_instance _tc_timer = {
248   .class = &_tc_timer_class,
249 };
250
251 /* global interface listener */
252 static struct os_interface_listener _if_listener = {
253   .name = OS_INTERFACE_ANY,
254   .if_changed = _cb_if_event,
255 };
256
257 /* global variables */
258 static struct oonf_rfc5444_protocol *_protocol;
259
260 /* Additional logging sources */
261 enum oonf_log_source LOG_OLSRV2;
262 enum oonf_log_source LOG_OLSRV2_R;
263 enum oonf_log_source LOG_OLSRV2_ROUTING;
264 enum oonf_log_source LOG_OLSRV2_W;
265
266 /**
267  * Initialize additional logging sources for NHDP
268  */
269 static void
270 _early_cfg_init(void) {
271   LOG_OLSRV2 = _olsrv2_subsystem.logging;
272   LOG_OLSRV2_R = oonf_log_register_source(OONF_OLSRV2_SUBSYSTEM "_r");
273   LOG_OLSRV2_W = oonf_log_register_source(OONF_OLSRV2_SUBSYSTEM "_w");
274   LOG_OLSRV2_ROUTING = oonf_log_register_source(OONF_OLSRV2_SUBSYSTEM "_routing");
275 }
276
277 /**
278  * Initialize OLSRV2 subsystem
279  * @return -1 if an error happened, 0 otherwise
280  */
281 static int
282 _init(void) {
283   _protocol = oonf_rfc5444_get_default_protocol();
284
285   if (olsrv2_writer_init(_protocol)) {
286     return -1;
287   }
288
289   if (olsrv2_routing_init()) {
290     olsrv2_writer_cleanup();
291     oonf_rfc5444_remove_protocol(_protocol);
292     return -1;
293   }
294
295   /* activate interface listener */
296   os_interface_add(&_if_listener);
297
298   /* activate the rest of the olsrv2 protocol */
299   olsrv2_lan_init();
300   olsrv2_originator_init();
301   olsrv2_reader_init(_protocol);
302   olsrv2_tc_init();
303
304   /* initialize timer */
305   oonf_timer_add(&_tc_timer_class);
306
307   return 0;
308 }
309
310 /**
311  * Begin shutdown by deactivating reader and writer. Also flush all routes
312  */
313 static void
314 _initiate_shutdown(void) {
315   olsrv2_writer_cleanup();
316   olsrv2_reader_cleanup();
317   olsrv2_routing_initiate_shutdown();
318 }
319
320 /**
321  * Cleanup OLSRV2 subsystem
322  */
323 static void
324 _cleanup(void) {
325   /* remove interface listener */
326   os_interface_remove(&_if_listener);
327
328   /* cleanup configuration */
329   netaddr_acl_remove(&_olsrv2_config.routable_acl);
330   netaddr_acl_remove(&_olsrv2_config.originator_acl);
331
332   /* cleanup all parts of olsrv2 */
333   olsrv2_routing_cleanup();
334   olsrv2_originator_cleanup();
335   olsrv2_tc_cleanup();
336   olsrv2_lan_cleanup();
337
338   /* free protocol instance */
339   _protocol = NULL;
340 }
341
342 /**
343  * @return interval between two tcs
344  */
345 uint64_t
346 olsrv2_get_tc_interval(void) {
347   return _olsrv2_config.tc_interval;
348 }
349
350 /**
351  * @return validity of the local TCs
352  */
353 uint64_t
354 olsrv2_get_tc_validity(void) {
355   return _olsrv2_config.tc_validity;
356 }
357
358 /**
359  * @param addr NHDP address to be checked
360  * @return true if address should be routed, false otherwise
361  */
362 bool
363 olsrv2_is_nhdp_routable(struct netaddr *addr) {
364   if (!_olsrv2_config.nhdp_routable) {
365     return false;
366   }
367   return olsrv2_is_routable(addr);
368 }
369
370 /**
371  * @param addr address to be checked
372  * @return true if address should be routed, false otherwise
373  */
374 bool
375 olsrv2_is_routable(struct netaddr *addr) {
376   return netaddr_acl_check_accept(&_olsrv2_config.routable_acl, addr);
377 }
378
379 /**
380  * default implementation for rfc5444 processing handling according
381  * to MPR settings.
382  * @param context
383  * @param vtime
384  * @return
385  */
386 bool
387 olsrv2_mpr_shall_process(
388     struct rfc5444_reader_tlvblock_context *context, uint64_t vtime) {
389   enum oonf_duplicate_result dup_result;
390   bool process;
391 #ifdef OONF_LOG_DEBUG_INFO
392   struct netaddr_str buf;
393 #endif
394
395   /* check if message has originator and sequence number */
396   if (!context->has_origaddr || !context->has_seqno) {
397     OONF_DEBUG(LOG_OLSRV2, "Do not process message type %u,"
398         " originator or sequence number is missing!",
399         context->msg_type);
400     return false;
401   }
402
403   /* check forwarding set */
404   dup_result = oonf_duplicate_entry_add(&_protocol->processed_set,
405       context->msg_type, &context->orig_addr,
406       context->seqno, vtime + _olsrv2_config.f_hold_time);
407   process = oonf_duplicate_is_new(dup_result);
408
409   OONF_DEBUG(LOG_OLSRV2, "Do %sprocess message type %u from %s"
410       " with seqno %u (dupset result: %u)",
411       process ? "" : "not ",
412       context->msg_type,
413       netaddr_to_string(&buf, &context->orig_addr),
414       context->seqno, dup_result);
415   return process;
416 }
417
418 /**
419  * default implementation for rfc5444 forwarding handling according
420  * to MPR settings.
421  * @param context RFC5444 reader context
422  * @param source_address source address of RFC5444 message
423  * @param vtime validity time of message information
424  * @return true if message was forwarded, false otherwise
425  */
426 bool
427 olsrv2_mpr_shall_forwarding(struct rfc5444_reader_tlvblock_context *context,
428     struct netaddr *source_address, uint64_t vtime) {
429   struct nhdp_interface *interf;
430   struct nhdp_laddr *laddr;
431   struct nhdp_neighbor *neigh;
432   enum oonf_duplicate_result dup_result;
433   bool forward;
434 #ifdef OONF_LOG_DEBUG_INFO
435   struct netaddr_str buf;
436 #endif
437
438   /* check if message has originator and sequence number */
439   if (!context->has_origaddr || !context->has_seqno) {
440     OONF_DEBUG(LOG_OLSRV2, "Do not forward message type %u,"
441         " originator or sequence number is missing!",
442         context->msg_type);
443     return false;
444   }
445
446   /* check input interface */
447   if (_protocol->input_interface == NULL) {
448     OONF_DEBUG(LOG_OLSRV2, "Do not forward because input interface is not set");
449     return false;
450   }
451
452   /* checp input source address */
453   if (!source_address) {
454     OONF_DEBUG(LOG_OLSRV2, "Do not forward because input source is not set");
455     return false;
456   }
457
458   /* check if this is coming from the unicast receiver */
459   if (strcmp(_protocol->input_interface->name, RFC5444_UNICAST_INTERFACE) == 0) {
460     return false;
461   }
462
463   /* check forwarding set */
464   dup_result = oonf_duplicate_entry_add(&_protocol->forwarded_set,
465       context->msg_type, &context->orig_addr,
466       context->seqno, vtime + _olsrv2_config.f_hold_time);
467   if (!oonf_duplicate_is_new(dup_result)) {
468     OONF_DEBUG(LOG_OLSRV2, "Do not forward message type %u from %s"
469         " with seqno %u (dupset result: %u)",
470         context->msg_type,
471         netaddr_to_string(&buf, &context->orig_addr),
472         context->seqno, dup_result);
473     return false;
474   }
475
476   /* get NHDP interface */
477   interf = nhdp_interface_get(_protocol->input_interface->name);
478   if (interf == NULL) {
479     OONF_DEBUG(LOG_OLSRV2, "Do not forward because NHDP does not handle"
480         " interface '%s'", _protocol->input_interface->name);
481     return false;
482   }
483
484   /* get NHDP link address corresponding to source */
485   laddr = nhdp_interface_get_link_addr(interf, source_address);
486   if (laddr == NULL) {
487     OONF_DEBUG(LOG_OLSRV2, "Do not forward because source IP %s is"
488         " not a direct neighbor",
489         netaddr_to_string(&buf, source_address));
490     return false;
491   }
492
493   if (netaddr_get_address_family(&context->orig_addr)
494       == netaddr_get_address_family(source_address)) {
495     /* get NHDP neighbor */
496     neigh = laddr->link->neigh;
497   }
498   else if (laddr->link->dualstack_partner) {
499     /* get dualstack NHDP neighbor */
500     neigh = laddr->link->dualstack_partner->neigh;
501   }
502   else {
503     OONF_DEBUG(LOG_OLSRV2, "Do not forward because this is a dualstack"
504         " message, but the link source %s is not dualstack capable",
505         netaddr_to_string(&buf, source_address));
506     return false;
507   }
508
509   /* forward if this neighbor has selected us as a flooding MPR */
510   forward = neigh->local_is_flooding_mpr && neigh->symmetric > 0;
511   OONF_DEBUG(LOG_OLSRV2, "Do %sforward message type %u from %s"
512       " with seqno %u (%s/%u)",
513       forward ? "" : "not ",
514       context->msg_type,
515       netaddr_to_string(&buf, &context->orig_addr),
516       context->seqno,
517       neigh->local_is_flooding_mpr ? "true" : "false", neigh->symmetric);
518   return forward;
519 }
520
521 /**
522  * Schema entry validator for an attached network.
523  * See CFG_VALIDATE_ACL_*() macros.
524  * @param entry pointer to schema entry
525  * @param section_name name of section type and name
526  * @param value value of schema entry
527  * @param out pointer to autobuffer for validator output
528  * @return 0 if validation found no problems, -1 otherwise
529  */
530 int
531 olsrv2_validate_lan(const struct cfg_schema_entry *entry,
532     const char *section_name, const char *value, struct autobuf *out) {
533   struct netaddr_str buf;
534   struct _lan_data data;
535   const char *ptr, *result;
536   struct os_route_key prefix;
537
538   if (value == NULL) {
539     cfg_schema_help_netaddr(entry, out);
540     cfg_append_printable_line(out,
541         "    This value is followed by a list of four optional parameters.");
542     cfg_append_printable_line(out,
543         "    - '"LAN_OPTION_SRC"<prefix>' the source specific prefix of this attached network."
544         " The default is 2.");
545     cfg_append_printable_line(out,
546         "    - '"LAN_OPTION_METRIC"<m>' the link metric of the LAN (between %u and %u)."
547         " The default is 0.", RFC7181_METRIC_MIN, RFC7181_METRIC_MAX);
548     cfg_append_printable_line(out,
549         "    - '"LAN_OPTION_DOMAIN"<d>' the domain of the LAN (between 0 and 255) or 'all'."
550         " The default is all.");
551     cfg_append_printable_line(out,
552         "    - '"LAN_OPTION_DIST"<d>' the hopcount distance of the LAN (between 0 and 255)."
553         " The default is 2.");
554     return 0;
555   }
556
557   ptr = str_cpynextword(buf.buf, value, sizeof(buf));
558   if (cfg_schema_validate_netaddr(entry, section_name, buf.buf, out)) {
559     /* check prefix first */
560     return -1;
561   }
562
563   if (netaddr_from_string(&prefix.dst, buf.buf)) {
564     return -1;
565   }
566
567   result = _parse_lan_parameters(&prefix, &data, ptr);
568   if (result) {
569     cfg_append_printable_line(out, "Value '%s' for entry '%s'"
570         " in section %s has %s",
571         value, entry->key.entry, section_name, result);
572     return -1;
573   }
574
575   if (data.metric < RFC7181_METRIC_MIN || data.metric > RFC7181_METRIC_MAX) {
576     cfg_append_printable_line(out, "Metric %u for prefix %s must be between %u and %u",
577         data.metric, buf.buf, RFC7181_METRIC_MIN, RFC7181_METRIC_MAX);
578     return -1;
579   }
580   if (data.dist > 255) {
581     cfg_append_printable_line(out,
582         "Distance %u for prefix %s must be between 0 and 255", data.dist, buf.buf);
583     return -1;
584   }
585
586   return 0;
587 }
588
589 /**
590  * Parse parameters of lan prefix string
591  * @param prefix source specific prefix (to store source prefix)
592  * @param dst pointer to data structure to store results.
593  * @param src source string
594  * @return NULL if parser worked without an error, a pointer
595  *   to the suffix of the error message otherwise.
596  */
597 static const char *
598 _parse_lan_parameters(struct os_route_key *prefix,
599                 struct _lan_data *dst, const char *src) {
600   char buffer[64];
601   const char *ptr, *next;
602   unsigned ext;
603
604   ptr = src;
605   dst->domain = NULL;
606   dst->metric = LAN_DEFAULT_METRIC;
607   dst->dist   = LAN_DEFAULT_DISTANCE;
608
609   while (ptr != NULL) {
610     next = str_cpynextword(buffer, ptr, sizeof(buffer));
611
612     if (strncasecmp(buffer, LAN_OPTION_METRIC, 7) == 0) {
613       dst->metric = strtoul(&buffer[7], NULL, 0);
614       if (dst->metric == 0 && errno != 0) {
615         return "an illegal metric parameter";
616       }
617     }
618     else if (strncasecmp(buffer, LAN_OPTION_DOMAIN, 7) == 0) {
619       fprintf(stderr, "domain='%s'\n", &buffer[7]);
620       if (strcasecmp(&buffer[7], "all") == 0) {
621         dst->domain = NULL;
622       }
623       else {
624         ext = strtoul(&buffer[7], NULL, 10);
625         if ((ext == 0 && errno != 0) || ext > 255) {
626           return "an illegal domain parameter";
627         }
628         dst->domain = nhdp_domain_get_by_ext(ext);
629         if (dst->domain == NULL) {
630           return "an unknown domain extension number";
631         }
632       }
633     }
634     else if (strncasecmp(buffer, LAN_OPTION_DIST, 5) == 0) {
635       dst->dist = strtoul(&buffer[5], NULL, 10);
636       if (dst->dist == 0 && errno != 0) {
637         return "an illegal distance parameter";
638       }
639     }
640     else if (strncasecmp(buffer, LAN_OPTION_SRC, 4) == 0) {
641       if (netaddr_from_string(&prefix->src, &buffer[4])) {
642         return "an illegal source prefix";
643       }
644       if (netaddr_get_address_family(&prefix->dst)
645             != netaddr_get_address_family(&prefix->src)) {
646           return "an illegal source prefix address type";
647       }
648       if (!os_routing_supports_source_specific(
649           netaddr_get_address_family(&prefix->dst))) {
650         return "an unsupported sourc specific prefix";
651       }
652     }
653     else {
654       return "an unknown parameter";
655     }
656     ptr = next;
657   }
658   return NULL;
659 }
660
661 /**
662  * Takes a named configuration section, extracts the attached network
663  * array and apply it
664  * @param section pointer to configuration section.
665  * @param add true if new lan entries should be created, false if
666  *   existing entries should be removed.
667  */
668 static void
669 _parse_lan_array(struct cfg_named_section *section, bool add) {
670   struct netaddr_str addr_buf;
671   struct netaddr addr;
672   struct os_route_key prefix;
673   struct _lan_data data;
674
675   const char *value, *ptr;
676   struct cfg_entry *entry;
677
678   if (section == NULL) {
679     return;
680   }
681
682   entry = cfg_db_get_entry(section, _LOCAL_ATTACHED_NETWORK_KEY);
683   if (entry == NULL) {
684     return;
685   }
686
687   strarray_for_each_element(&entry->val, value) {
688     /* extract data */
689     ptr = str_cpynextword(addr_buf.buf, value, sizeof(addr_buf));
690     if (netaddr_from_string(&addr, addr_buf.buf)) {
691       continue;
692     }
693
694     os_routing_init_sourcespec_prefix(&prefix, &addr);
695
696     /* truncate address */
697     netaddr_truncate(&prefix.dst, &prefix.dst);
698
699     if (_parse_lan_parameters(&prefix, &data, ptr)) {
700       continue;
701     }
702
703     if (data.domain == NULL) {
704       list_for_each_element(nhdp_domain_get_list(), data.domain, _node) {
705         if (add) {
706           olsrv2_lan_add(data.domain, &prefix, data.metric, data.dist);
707         }
708         else {
709           olsrv2_lan_remove(data.domain, &prefix);
710         }
711       }
712     }
713     else {
714       if (add) {
715         olsrv2_lan_add(data.domain, &prefix, data.metric, data.dist);
716       }
717       else {
718         olsrv2_lan_remove(data.domain, &prefix);
719       }
720     }
721   }
722 }
723
724 /**
725  * Callback to trigger normal tc generation with timer
726  * @param ptr timer instance that fired
727  */
728 static void
729 _cb_generate_tc(struct oonf_timer_instance *ptr __attribute__((unused))) {
730   if (nhdp_domain_node_is_mpr() || !avl_is_empty(olsrv2_lan_get_tree())) {
731     olsrv2_writer_send_tc();
732   }
733 }
734
735 static uint32_t
736 _get_addr_priority(const struct netaddr *addr) {
737 #ifdef OONF_LOG_DEBUG_INFO
738   struct netaddr_str nbuf;
739 #endif
740
741   if (!netaddr_acl_check_accept(&_olsrv2_config.originator_acl, addr)) {
742     /* does not match the acl */
743     OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 0 (not in ACL)",
744         netaddr_to_string(&nbuf, addr));
745     return 0;
746   }
747
748
749   if (netaddr_get_address_family(addr) == AF_INET) {
750     if (netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, addr)) {
751       /* linklocal */
752       OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 1 (linklocal)",
753           netaddr_to_string(&nbuf, addr));
754       return 1;
755     }
756
757     /* routable */
758     OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 2 (routable)",
759         netaddr_to_string(&nbuf, addr));
760     return 2;
761   }
762
763   if (netaddr_get_address_family(addr) == AF_INET6) {
764     if (netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, addr)) {
765       /* linklocal */
766       OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 1 (linklocal)",
767           netaddr_to_string(&nbuf, addr));
768       return 1;
769     }
770
771     /* routable */
772     OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 2 (routable)",
773         netaddr_to_string(&nbuf, addr));
774     return 2;
775   }
776
777   /* unknown */
778   OONF_DEBUG(LOG_OLSRV2, "check priority for %s: 0 (unknown)",
779       netaddr_to_string(&nbuf, addr));
780
781   return 0;
782 }
783
784 /**
785  * Check if current originators are still valid and
786  * lookup new one if necessary.
787  */
788 static void
789 _update_originator(int af_family) {
790   const struct netaddr *originator;
791   struct nhdp_interface *nhdp_if;
792   struct os_interface_listener *if_listener;
793   struct netaddr new_originator;
794   struct os_interface_ip *ip;
795   uint32_t new_priority;
796   uint32_t old_priority;
797   uint32_t priority;
798 #ifdef OONF_LOG_DEBUG_INFO
799   struct netaddr_str buf;
800 #endif
801
802   OONF_DEBUG(LOG_OLSRV2, "Updating OLSRV2 %s originator",
803       af_family == AF_INET ? "ipv4" : "ipv6");
804
805   originator = olsrv2_originator_get(af_family);
806
807   old_priority = 0;
808   new_priority = 0;
809
810   netaddr_invalidate(&new_originator);
811
812   avl_for_each_element(nhdp_interface_get_tree(), nhdp_if, _node) {
813     if_listener = nhdp_interface_get_if_listener(nhdp_if);
814
815     /* check if originator is still valid */
816     avl_for_each_element(&if_listener->data->addresses, ip, _node) {
817       if (netaddr_get_address_family(&ip->address) == af_family) {
818         priority = _get_addr_priority(&ip->address) * 4;
819         if (priority == 0) {
820           /* not useful */
821           continue;
822         }
823
824         if (if_listener->data->flags.loopback) {
825           priority += 2;
826         }
827         if (netaddr_cmp(originator, &ip->address) == 0) {
828           old_priority = priority + 1;
829         }
830
831         if (priority > old_priority && priority > new_priority) {
832           memcpy(&new_originator, &ip->address, sizeof(new_originator));
833           new_priority = priority;
834         }
835       }
836     }
837   }
838
839   if (new_priority > old_priority) {
840     OONF_DEBUG(LOG_OLSRV2, "Set originator to %s",
841         netaddr_to_string(&buf, &new_originator));
842     olsrv2_originator_set(&new_originator);
843   }
844 }
845
846 /**
847  * Callback for interface events
848  * @param listener pointer to interface listener
849  * @return always 0
850  */
851 static int
852 _cb_if_event(struct os_interface_listener *if_listener __attribute__((unused))) {
853   _update_originator(AF_INET);
854   _update_originator(AF_INET6);
855   return 0;
856 }
857
858 /**
859  * Callback fired when olsrv2 section changed
860  */
861 static void
862 _cb_cfg_olsrv2_changed(void) {
863   if (cfg_schema_tobin(&_olsrv2_config, _olsrv2_section.post,
864       _olsrv2_entries, ARRAYSIZE(_olsrv2_entries))) {
865     OONF_WARN(LOG_OLSRV2, "Cannot convert OLSRV2 configuration.");
866     return;
867   }
868
869   /* set tc timer interval */
870   oonf_timer_set(&_tc_timer, _olsrv2_config.tc_interval);
871
872   /* check if we have to change the originators */
873   _update_originator(AF_INET);
874   _update_originator(AF_INET6);
875
876   /* run through all pre-update LAN entries and remove them */
877   _parse_lan_array(_olsrv2_section.pre, false);
878
879   /* run through all post-update LAN entries and add them */
880   _parse_lan_array(_olsrv2_section.post, true);
881 }
882
883 /**
884  * Callback fired when domain section changed
885  */
886 static void
887 _cb_cfg_domain_changed(void) {
888   struct olsrv2_routing_domain rtdomain;
889   struct nhdp_domain *domain;
890   char *error = NULL;
891   int ext;
892
893   ext = strtol(_rt_domain_section.section_name, &error, 10);
894   if (error != NULL && *error != 0) {
895     /* illegal domain name */
896     return;
897   }
898
899   if (ext < 0 || ext > 255) {
900     /* name out of range */
901     return;
902   }
903
904   domain = nhdp_domain_add(ext);
905   if (domain == NULL) {
906     return;
907   }
908
909   memset(&rtdomain, 0, sizeof(rtdomain));
910   if (cfg_schema_tobin(&rtdomain, _rt_domain_section.post,
911       _rt_domain_entries, ARRAYSIZE(_rt_domain_entries))) {
912     OONF_WARN(LOG_OLSRV2, "Cannot convert OLSRV2 routing domain parameters.");
913     return;
914   }
915
916   olsrv2_routing_set_domain_parameter(domain, &rtdomain);
917 }