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