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