Fix build without DEBUG/INFO output
[oonf.git] / src-plugins / nhdp / nhdp / nhdp_domain.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 <stdio.h>
47
48 #include "common/avl.h"
49 #include "common/avl_comp.h"
50 #include "common/common_types.h"
51 #include "common/list.h"
52 #include "common/netaddr.h"
53 #include "core/oonf_cfg.h"
54 #include "core/oonf_logging.h"
55 #include "subsystems/oonf_class.h"
56 #include "subsystems/oonf_rfc5444.h"
57
58 #include "nhdp/nhdp.h"
59 #include "nhdp/nhdp_db.h"
60 #include "nhdp/nhdp_domain.h"
61 #include "nhdp/nhdp_interfaces.h"
62 #include "nhdp/nhdp_internal.h"
63
64 static void _apply_metric(struct nhdp_domain *domain, const char *metric_name);
65 static void _remove_metric(struct nhdp_domain *);
66 static void _apply_mpr(struct nhdp_domain *domain,
67     const char *mpr_name, uint8_t willingness);
68 static void _remove_mpr(struct nhdp_domain *);
69
70 static void _cb_update_everyone_mpr(void);
71
72 static void _recalculate_neighbor_metric(struct nhdp_domain *domain,
73         struct nhdp_neighbor *neigh);
74 static const char *_link_to_string(struct nhdp_metric_str *, uint32_t);
75 static const char *_path_to_string(struct nhdp_metric_str *, uint32_t, uint8_t);
76 static const char *_int_to_string(struct nhdp_metric_str *, struct nhdp_link *);
77
78 /* domain class */
79 static struct oonf_class _domain_class = {
80   .name = NHDP_CLASS_DOMAIN,
81   .size = sizeof(struct nhdp_domain),
82 };
83
84 /* default metric handler (hopcount) */
85 static struct nhdp_domain_metric _no_metric = {
86   .name = "Hopcount metric",
87
88   .incoming_link_start = RFC7181_METRIC_MAX,
89   .outgoing_link_start = RFC7181_METRIC_MAX,
90   .incoming_2hop_start = RFC7181_METRIC_MAX,
91   .outgoing_2hop_start = RFC7181_METRIC_MAX,
92
93   .link_to_string = _link_to_string,
94   .path_to_string = _path_to_string,
95   .internal_link_to_string = _int_to_string,
96
97   .no_default_handling = true,
98 };
99
100 /* default MPR handler (no MPR handling) */
101 static struct nhdp_domain_mpr _everyone_mprs = {
102   .name = "Everyone MPR",
103
104   .update_mpr = _cb_update_everyone_mpr,
105 };
106
107 /* non-default routing domains registered to NHDP */
108 static struct list_entity _domain_list;
109 static struct list_entity _domain_listener_list;
110
111 static size_t _domain_counter = 0;
112
113 /* tree of known routing metrics/mpr-algorithms */
114 static struct avl_tree _domain_metrics;
115 static struct avl_tree _domain_mprs;
116
117 /* flooding domain */
118 static struct nhdp_domain _flooding_domain;
119
120 /* NHDP RFC5444 protocol */
121 static struct oonf_rfc5444_protocol *_protocol;
122
123 /* remember if node is MPR or not */
124 static bool _node_is_selected_as_mpr = false;
125
126 /**
127  * Initialize nhdp metric core
128  * @param p pointer to rfc5444 protocol
129  */
130 void
131 nhdp_domain_init(struct oonf_rfc5444_protocol *p) {
132   _protocol = p;
133
134   oonf_class_add(&_domain_class);
135   list_init_head(&_domain_list);
136   list_init_head(&_domain_listener_list);
137
138   avl_init(&_domain_metrics, avl_comp_strcasecmp, false);
139   avl_init(&_domain_mprs, avl_comp_strcasecmp, false);
140
141   /* initialize flooding domain */
142   _flooding_domain.metric = &_no_metric;
143   _flooding_domain.mpr = &_everyone_mprs;
144
145   _flooding_domain.mpr->_refcount++;
146   _flooding_domain.metric->_refcount++;
147 }
148
149 /**
150  * cleanup allocated resources for nhdp metric core
151  */
152 void
153 nhdp_domain_cleanup(void) {
154   struct nhdp_domain *domain, *d_it;
155   struct nhdp_domain_listener *listener, *l_it;
156   int i;
157
158   list_for_each_element_safe(&_domain_list, domain, _node, d_it) {
159     /* free allocated TLVs */
160     for (i=0; i<4; i++) {
161       rfc5444_writer_unregister_addrtlvtype(
162           &_protocol->writer, &domain->_metric_addrtlvs[i]);
163     }
164
165     /* remove domain */
166     list_remove(&domain->_node);
167     oonf_class_free(&_domain_class, domain);
168   }
169
170   list_for_each_element_safe(&_domain_listener_list, listener, _node, l_it) {
171     nhdp_domain_listener_remove(listener);
172   }
173   oonf_class_remove(&_domain_class);
174 }
175
176 /**
177  * @return number of registered nhdp domains
178  */
179 size_t
180 nhdp_domain_get_count(void) {
181   return _domain_counter;
182 }
183
184 /**
185  * Add a new metric handler to nhdp
186  * @param metric pointer to NHDP link metric
187  * @return 0 if successful, -1 if metric was already registered
188  */
189 int
190 nhdp_domain_metric_add(struct nhdp_domain_metric *metric) {
191   /* initialize key */
192   metric->_node.key = metric->name;
193
194   /* insert default values if not set */
195   if (metric->incoming_link_start == 0) {
196     metric->incoming_link_start = RFC7181_METRIC_MAX;
197   }
198   if (metric->outgoing_link_start == 0) {
199     metric->outgoing_link_start = RFC7181_METRIC_INFINITE;
200   }
201   if (metric->incoming_2hop_start == 0) {
202     metric->incoming_2hop_start = RFC7181_METRIC_INFINITE;
203   }
204   if (metric->outgoing_2hop_start == 0) {
205     metric->outgoing_2hop_start = RFC7181_METRIC_INFINITE;
206   }
207
208   /* initialize to_string method if empty */
209   if (metric->link_to_string == NULL) {
210     metric->link_to_string = _link_to_string;
211   }
212   if (metric->path_to_string == NULL) {
213     metric->path_to_string = _path_to_string;
214   }
215
216   if (metric->internal_link_to_string == NULL) {
217     metric->internal_link_to_string = _int_to_string;
218   }
219
220   /* hook into tree */
221   return avl_insert(&_domain_metrics, &metric->_node);
222 }
223
224 /**
225  * Remove a metric handler from the nhdp metric core
226  * @param metric pointer to metric handler
227  */
228 void
229 nhdp_domain_metric_remove(struct nhdp_domain_metric *metric) {
230   struct nhdp_domain *domain;
231
232   list_for_each_element(&_domain_list, domain, _node) {
233     if (domain->metric == metric) {
234       _remove_metric(domain);
235       break;
236     }
237   }
238
239   avl_remove(&_domain_metrics, &metric->_node);
240 }
241
242 /**
243  * Add a new mpr handler to nhdp
244  * @param mpr pointer to mpr handler
245  * @return 0 if successful, -1 if metric is already registered
246  */
247 int
248 nhdp_domain_mpr_add(struct nhdp_domain_mpr *mpr) {
249   struct nhdp_domain *domain;
250
251   /* initialize key */
252   mpr->_node.key = mpr->name;
253
254   if (avl_insert(&_domain_mprs, &mpr->_node)) {
255     return -1;
256   }
257
258   list_for_each_element(&_domain_list, domain, _node) {
259     if (domain->mpr == &_everyone_mprs) {
260       _apply_mpr(domain, domain->mpr_name, domain->local_willingness);
261     }
262   }
263   if (_flooding_domain.mpr == &_everyone_mprs) {
264     _apply_mpr(&_flooding_domain,
265         _flooding_domain.mpr_name, _flooding_domain.local_willingness);
266   }
267   return 0;
268 }
269
270 /**
271  * Remove a metric handler from the nhdp metric core
272  * @param mpr pointer to mpr handler
273  */
274 void
275 nhdp_domain_mpr_remove(struct nhdp_domain_mpr *mpr) {
276   struct nhdp_domain *domain;
277
278   list_for_each_element(&_domain_list, domain, _node) {
279     if (domain->mpr == mpr) {
280       _remove_mpr(domain);
281       break;
282     }
283   }
284
285   avl_remove(&_domain_mprs, &mpr->_node);
286 }
287
288 /**
289  * Adds a listener to the NHDP domain system
290  * @param listener pointer to NHDP domain listener
291  */
292 void
293 nhdp_domain_listener_add(struct nhdp_domain_listener *listener) {
294   list_add_tail(&_domain_listener_list, &listener->_node);
295 }
296
297 /**
298  * Removes a listener from the NHDP domain system
299  * @param listener pointer to NHDP domain listener
300  */
301 void
302 nhdp_domain_listener_remove(struct nhdp_domain_listener *listener) {
303   if (list_is_node_added(&listener->_node)) {
304     list_remove(&listener->_node);
305   }
306 }
307
308 /**
309  * @param ext TLV extension value of MPR/Linkmetrics
310  * @return NHDP domain registered to this extension, NULL if not found
311  */
312 struct nhdp_domain *
313 nhdp_domain_get_by_ext(uint8_t ext) {
314   struct nhdp_domain *d;
315
316   list_for_each_element(&_domain_list, d, _node) {
317     if (d->ext == ext) {
318       return d;
319     }
320   }
321   return NULL;
322 }
323
324 /**
325  * Initialize the domain data of a new NHDP link
326  * @param lnk NHDP link
327  */
328 void
329 nhdp_domain_init_link(struct nhdp_link *lnk) {
330   struct nhdp_domain *domain;
331   struct nhdp_link_domaindata *data;
332   int i;
333
334   /* initialize metrics */
335   for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
336     lnk->_domaindata[i].metric.in = RFC7181_METRIC_INFINITE;
337     lnk->_domaindata[i].metric.out = RFC7181_METRIC_INFINITE;
338   }
339   list_for_each_element(&_domain_list, domain, _node) {
340     data = nhdp_domain_get_linkdata(domain, lnk);
341
342     if (domain->metric->no_default_handling) {
343       data->metric.in = domain->metric->incoming_link_start;
344       data->metric.out = domain->metric->outgoing_link_start;
345     }
346   }
347 }
348
349 /**
350  * Initialize the domain data of a new NHDP twohop neighbor
351  * @param l2hop NHDP twohop neighbor
352  */
353 void
354 nhdp_domain_init_l2hop(struct nhdp_l2hop *l2hop) {
355   struct nhdp_domain *domain;
356   struct nhdp_l2hop_domaindata *data;
357   int i;
358
359   /* initialize metrics */
360   for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
361     l2hop->_domaindata[i].metric.in = RFC7181_METRIC_INFINITE;
362     l2hop->_domaindata[i].metric.out = RFC7181_METRIC_INFINITE;
363   }
364
365   list_for_each_element(&_domain_list, domain, _node) {
366     data = nhdp_domain_get_l2hopdata(domain, l2hop);
367
368     if (domain->metric->no_default_handling) {
369       data->metric.in = domain->metric->incoming_2hop_start;
370       data->metric.out = domain->metric->outgoing_2hop_start;
371     }
372   }
373 }
374
375 /**
376  * Initialize the domain data of a new NHDP neighbor
377  * @param neigh NHDP neighbor
378  */
379 void
380 nhdp_domain_init_neighbor(struct nhdp_neighbor *neigh) {
381   struct nhdp_domain *domain;
382   struct nhdp_neighbor_domaindata *data;
383   int i;
384
385   /* initialize flooding MPR settings */
386   neigh->flooding_willingness = RFC7181_WILLINGNESS_NEVER;
387   neigh->local_is_flooding_mpr = false;
388   neigh->neigh_is_flooding_mpr = false;
389
390   for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
391     neigh->_domaindata[i].metric.in = RFC7181_METRIC_INFINITE;
392     neigh->_domaindata[i].metric.out = RFC7181_METRIC_INFINITE;
393
394     neigh->_domaindata[i].best_link = NULL;
395     neigh->_domaindata[i].willingness = RFC7181_WILLINGNESS_NEVER;
396
397
398     neigh->_domaindata[i].local_is_mpr = false;
399     neigh->_domaindata[i].neigh_is_mpr = false;
400   }
401
402   /* initialize metrics and mprs */
403   list_for_each_element(&_domain_list, domain, _node) {
404     data = nhdp_domain_get_neighbordata(domain, neigh);
405
406     if (domain->metric->no_default_handling) {
407       data->metric.in = domain->metric->incoming_link_start;
408       data->metric.out = domain->metric->outgoing_link_start;
409     }
410   }
411 }
412
413 /**
414  * Process an in linkmetric tlv for a nhdp link
415  * @param domain pointer to NHDP domain
416  * @param lnk pointer to nhdp link
417  * @param value pointer to value of metric tlv,
418  *   must have a length of at least 2
419  */
420 void
421 nhdp_domain_process_metric_linktlv(struct nhdp_domain *domain,
422     struct nhdp_link *lnk, uint8_t *value) {
423   struct rfc7181_metric_field metric_field;
424   uint32_t metric;
425
426   memcpy(&metric_field, value, sizeof(metric_field));
427   metric = rfc7181_metric_decode(&metric_field);
428
429   if (rfc7181_metric_has_flag(&metric_field, RFC7181_LINKMETRIC_INCOMING_LINK)) {
430     nhdp_domain_get_linkdata(domain, lnk)->metric.out = metric;
431   }
432   if (rfc7181_metric_has_flag(&metric_field, RFC7181_LINKMETRIC_INCOMING_NEIGH)) {
433     nhdp_domain_get_neighbordata(domain, lnk->neigh)->metric.out = metric;
434   }
435 }
436
437 /**
438  * Process an in linkmetric tlv for a nhdp twohop neighbor
439  * @param domain pointer to NHDP domain
440  * @param l2hop pointer to nhdp twohop neighbor
441  * @param value value of metric tlv
442  */
443 void
444 nhdp_domain_process_metric_2hoptlv(struct nhdp_domain *domain,
445     struct nhdp_l2hop *l2hop, uint8_t *value) {
446   struct rfc7181_metric_field metric_field;
447   struct nhdp_l2hop_domaindata *data;
448   uint32_t metric;
449
450   memcpy(&metric_field, value, sizeof(metric_field));
451   metric = rfc7181_metric_decode(&metric_field);
452
453   data = nhdp_domain_get_l2hopdata(domain, l2hop);
454   if (rfc7181_metric_has_flag(&metric_field, RFC7181_LINKMETRIC_INCOMING_NEIGH)) {
455     data->metric.in = metric;
456   }
457   if (rfc7181_metric_has_flag(&metric_field, RFC7181_LINKMETRIC_OUTGOING_NEIGH)) {
458     data->metric.out = metric;
459   }
460 }
461
462 /**
463  * Neighborhood changed in terms of metrics or connectivity.
464  * This will trigger a MPR set recalculation.
465  */
466 void
467 nhdp_domain_neighborhood_changed(void) {
468   struct nhdp_domain_listener *listener;
469   struct nhdp_domain *domain;
470   struct nhdp_neighbor *neigh;
471   
472   list_for_each_element(&_domain_list, domain, _node) {
473     list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
474       _recalculate_neighbor_metric(domain, neigh);
475     }
476
477     if (domain->mpr->update_mpr != NULL) {
478       domain->mpr->update_mpr();
479     }
480   }
481
482   // TODO: flooding mpr ?
483   // (Why do we need to consider flooding MPRs here?)
484
485   list_for_each_element(&_domain_listener_list, listener, _node) {
486     if (listener->update) {
487       listener->update(NULL);
488     }
489   }
490
491   /* check if we still have routing MPR selectors */
492   OONF_DEBUG(LOG_NHDP, "Checking if we still have routing MPR selectors");
493   _node_is_selected_as_mpr = false;
494
495   list_for_each_element(&_domain_list, domain, _node) {
496     list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
497       if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
498         _node_is_selected_as_mpr = true;
499         return;
500       }
501     }
502   }
503 }
504
505 /**
506  * One neighbor changed in terms of metrics or connectivity.
507  * This will trigger a MPR set recalculation.
508  * @param neigh neighbor where the changed happened
509  */
510 void
511 nhdp_domain_neighbor_changed(struct nhdp_neighbor *neigh) {
512   struct nhdp_domain_listener *listener;
513   struct nhdp_domain *domain;
514   
515
516   list_for_each_element(&_domain_list, domain, _node) {
517     _recalculate_neighbor_metric(domain, neigh);
518
519     if (domain->mpr->update_mpr != NULL) {
520       domain->mpr->update_mpr();
521     }
522   }
523
524   // TODO: flooding mpr ?
525   // (Why do we need to consider flooding MPRs here?)
526
527   list_for_each_element(&_domain_listener_list, listener, _node) {
528     if (listener->update) {
529       listener->update(neigh);
530     }
531   }
532
533   /* check if we still have routing MPR selectors */
534   OONF_DEBUG(LOG_NHDP, "Checking if we still have routing MPR selectors");
535   _node_is_selected_as_mpr = false;
536
537   list_for_each_element(&_domain_list, domain, _node) {
538     list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
539       if (nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr) {
540         _node_is_selected_as_mpr = true;
541         return;
542       }
543     }
544   }
545 }
546
547 /**
548  * @return true if this node is selected as a MPR by any other node
549  */
550 bool
551 nhdp_domain_node_is_mpr(void) {
552   return _node_is_selected_as_mpr;
553 }
554
555 /**
556  *
557  * @param mprtypes destination buffer for mpr types
558  * @param mprtypes_size size of destination buffer
559  * @param tlv pointer to mprtypes TLV, might be NULL
560  * @return number of bytes written into destination buffer
561  */
562 size_t
563 nhdp_domain_process_mprtypes_tlv(
564     uint8_t *mprtypes, size_t mprtypes_size,
565     struct rfc5444_reader_tlvblock_entry *tlv) {
566   struct nhdp_domain *domain;
567   size_t count;
568
569   if (!tlv) {
570     domain = list_first_element(&_domain_list, domain, _node);
571     mprtypes[0] = domain->ext;
572
573     return 1;
574   }
575
576   memset(mprtypes, 255, mprtypes_size);
577
578   count = 0;
579   list_for_each_element(&_domain_list, domain, _node) {
580     mprtypes[count++] = domain->ext;
581     if (count >= mprtypes_size) {
582       break;
583     }
584   }
585   return count;
586 }
587
588 /**
589  * Process an in MPR tlv for a NHDP link
590  * @param mprtypes list of extenstions for MPR
591  * @param mprtypes_size length of mprtypes array
592  * @param neigh NHDP neighbor
593  * @param tlv MPR tlv context
594  */
595 void
596 nhdp_domain_process_mpr_tlv(uint8_t *mprtypes, size_t mprtypes_size,
597     struct nhdp_neighbor *neigh, struct rfc5444_reader_tlvblock_entry *tlv) {
598   struct nhdp_domain *domain;
599   size_t bit_idx, byte_idx;
600   size_t i;
601
602   neigh->local_is_flooding_mpr = false;
603   list_for_each_element(&_domain_list, domain, _node) {
604     nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr = false;
605   }
606
607   if (!tlv) {
608     return;
609   }
610
611   /* set flooding MPR flag */
612   neigh->local_is_flooding_mpr =
613       (tlv->single_value[0] & RFC7181_MPR_FLOODING) != 0;
614   OONF_DEBUG(LOG_NHDP_R, "Flooding MPR for neighbor: %s",
615       neigh->local_is_flooding_mpr ? "true" : "false");
616
617   /* set routing MPR flags */
618   for (i=0; i<mprtypes_size; i++) {
619     domain = nhdp_domain_get_by_ext(mprtypes[i]);
620     if (domain == NULL) {
621       continue;
622     }
623     bit_idx = (i + 1) & 7;
624     byte_idx = (i + 1) >> 3;
625
626     if (byte_idx >= tlv->length) {
627       continue;
628     }
629
630     nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr =
631         (tlv->single_value[byte_idx] & (1 << bit_idx)) != 0;
632
633     OONF_DEBUG(LOG_NHDP_R, "Routing MPR for neighbor in domain %u: %s",
634         domain->ext, nhdp_domain_get_neighbordata(domain, neigh)->local_is_mpr ? "true" : "false");
635   }
636 }
637
638 /**
639  * Process an in Willingness tlv and put values into
640  * temporary storage in MPR handler object. Call
641  * nhdp_domain_store_willingness to permanently store them later.
642  * @param mprtypes list of extenstions for MPR
643  * @param mprtypes_size length of mprtypes array
644  * @param tlv Willingness tlv context
645  */
646 void
647 nhdp_domain_process_willingness_tlv(
648     uint8_t *mprtypes, size_t mprtypes_size,
649     struct rfc5444_reader_tlvblock_entry *tlv) {
650   struct nhdp_domain *domain;
651   size_t idx, i;
652   uint8_t value;
653
654   _flooding_domain._tmp_willingness = RFC7181_WILLINGNESS_NEVER;
655   list_for_each_element(&_domain_list, domain, _node) {
656     domain->_tmp_willingness= RFC7181_WILLINGNESS_NEVER;
657   }
658
659   if (!tlv) {
660     return;
661   }
662
663   /* copy flooding willingness */
664   _flooding_domain._tmp_willingness
665     = tlv->single_value[0] & RFC7181_WILLINGNESS_MASK;
666   OONF_DEBUG(LOG_NHDP_R, "Received flooding willingness: %u",
667       _flooding_domain._tmp_willingness);
668
669   for (i=0; i<mprtypes_size; i++) {
670     domain = nhdp_domain_get_by_ext(mprtypes[i]);
671     if (domain == NULL) {
672       continue;
673     }
674
675     idx = (i + 1) / 2;
676     if (idx >= tlv->length) {
677       continue;
678     }
679
680     value = tlv->single_value[idx];
681     if ((domain->index & 1) == 0) {
682       value >>= RFC7181_WILLINGNESS_SHIFT;
683     }
684     else {
685       value &= RFC7181_WILLINGNESS_MASK;
686     }
687
688     domain->_tmp_willingness = value;
689
690     OONF_DEBUG(LOG_NHDP_R, "Received routing willingness for domain %u: %u",
691         domain->ext, domain->_tmp_willingness);
692   }
693 }
694
695 /**
696  * Stores the willingness data processed by
697  * nhdp_domain_process_willingness_tlv() into a neighbor object
698  * @param neigh NHDP neighbor
699  */
700 void
701 nhdp_domain_store_willingness(struct nhdp_neighbor *neigh) {
702   struct nhdp_neighbor_domaindata *neighdata;
703   struct nhdp_domain *domain;
704
705   neigh->flooding_willingness = _flooding_domain._tmp_willingness;
706   OONF_DEBUG(LOG_NHDP_R, "Set flooding willingness: %u",
707       neigh->flooding_willingness);
708
709   list_for_each_element(&_domain_list, domain, _node) {
710     neighdata = nhdp_domain_get_neighbordata(domain, neigh);
711     neighdata->willingness = domain->_tmp_willingness;
712     OONF_DEBUG(LOG_NHDP_R, "Set routing willingness for domain %u: %u",
713         domain->ext, neighdata->willingness);
714   }
715 }
716
717 /**
718  * Generate MPRTYPES tlv value
719  * @param mprtypes pointer to destination buffer for value
720  * @param mprtypes_size length of destination buffer
721  * @return number of bytes written into buffer
722  */
723 size_t
724 nhdp_domain_encode_mprtypes_tlvvalue(
725     uint8_t *mprtypes, size_t mprtypes_size) {
726   struct nhdp_domain *domain;
727   size_t count;
728
729   count = 0;
730   list_for_each_element(&_domain_list, domain, _node) {
731     mprtypes[count++] = domain->ext;
732
733     if (count >= mprtypes_size) {
734       break;
735     }
736   }
737
738   return count;
739 }
740
741 /**
742  * Calculates the tlvvalue of a MPR tlv
743  *
744  * @param tlvvalue destination for value of MPR tlv
745  * @param tlvsize length of tlv value
746  * @param neigh pointer to NHDP neighbor for MPR tlv
747  * @return length of tlvvalue, 0 if an error happened
748  */
749 size_t
750 nhdp_domain_encode_mpr_tlvvalue(
751     uint8_t *tlvvalue, size_t tlvsize, struct nhdp_neighbor *neigh) {
752   struct nhdp_domain *domain;
753   size_t bit_idx, byte_idx, len;
754
755   memset(tlvvalue, 0, tlvsize);
756   len = 0;
757   /* set flooding MPR flag */
758   if (neigh->neigh_is_flooding_mpr) {
759     tlvvalue[0] |= RFC7181_MPR_FLOODING;
760   }
761
762   OONF_DEBUG(LOG_NHDP_W, "Set flooding MPR: %s",
763       neigh->neigh_is_flooding_mpr ? "true" : "false");
764
765   list_for_each_element(&_domain_list, domain, _node) {
766     bit_idx = (domain->index + 1) & 7;
767     byte_idx = (domain->index + 1) >> 3;
768
769     if (byte_idx >= tlvsize) {
770       return 0;
771     }
772     if (byte_idx+1 > len) {
773       len = byte_idx + 1;
774     }
775
776     if (nhdp_domain_get_neighbordata(domain, neigh)->neigh_is_mpr) {
777       tlvvalue[byte_idx] |= (1 << bit_idx);
778     }
779
780     OONF_DEBUG(LOG_NHDP_W, "Set routing MPR for domain %u: %s",
781         domain->ext, nhdp_domain_get_neighbordata(domain, neigh)->neigh_is_mpr ? "true" : "false");
782   }
783   return len;
784 }
785
786 /**
787  * Calculates the tlvvalue of a Willingness tlv
788  * @param tlvvalue destination array
789  * @param tlvsize length of destination array
790  * @return length of tlvvalue, 0 if an error happened
791  */
792 size_t
793 nhdp_domain_encode_willingness_tlvvalue(uint8_t *tlvvalue, size_t tlvsize) {
794   struct nhdp_domain *domain;
795   uint8_t value;
796   size_t idx, len;
797
798   memset(tlvvalue, 0, tlvsize);
799   len = 0;
800
801   /* set flooding willingness */
802   tlvvalue[0] = _flooding_domain.local_willingness;
803   OONF_DEBUG(LOG_NHDP_W, "Set flooding willingness: %u",
804       _flooding_domain.local_willingness);
805
806   /* set routing willingness */
807   list_for_each_element(&_domain_list, domain, _node) {
808     idx = (domain->index + 1) / 2;
809     if (idx >= tlvsize) {
810       return -1;
811     }
812     if (idx+1 > len) {
813       len = idx + 1;
814     }
815
816     value = domain->local_willingness & RFC7181_WILLINGNESS_MASK;
817
818     if ((domain->index & 1) == 0) {
819       value <<= RFC7181_WILLINGNESS_SHIFT;
820     }
821
822     OONF_DEBUG(LOG_NHDP_W, "Set routing willingness for domain %u: %x"
823         " (%"PRINTF_SIZE_T_SPECIFIER")",
824         domain->ext, value, idx);
825
826     tlvvalue[idx] |= value;
827   }
828
829   return len;
830 }
831
832 /**
833  * Sets a new flodding MPR algorithm
834  * @param mpr_name name of MPR algorithm
835  * @param willingness of MPR algorithm
836  */
837 void
838 nhdp_domain_set_flooding_mpr(const char *mpr_name, uint8_t willingness) {
839   _apply_mpr(&_flooding_domain, mpr_name, willingness);
840 }
841
842 /**
843  * Sets the incoming metric of a link. This is the only function external
844  * code should use to commit the calculated metric values to the nhdp db.
845  * @param metric NHDP domain metric
846  * @param lnk NHDP link
847  * @param metric_in incoming metric value for NHDP link
848  * @return true if metric changed, false otherwise
849  */
850 bool
851 nhdp_domain_set_incoming_metric(struct nhdp_domain_metric *metric,
852     struct nhdp_link *lnk, uint32_t metric_in) {
853   struct nhdp_link_domaindata *linkdata;
854   struct nhdp_domain *domain;
855   bool changed;
856
857   changed = false;
858   list_for_each_element(&_domain_list, domain, _node) {
859     if (domain->metric == metric) {
860       linkdata = nhdp_domain_get_linkdata(domain, lnk);
861       changed |= (linkdata->metric.in != metric_in);
862       linkdata->metric.in = metric_in;
863     }
864   }
865   return changed;
866 }
867
868 /**
869  * get list of nhdp domains
870  * @return domain list
871  */
872 struct list_entity *
873 nhdp_domain_get_list(void) {
874   return &_domain_list;
875 }
876
877 /**
878  * get list of nhdp domain listeners for metric/mpr changes
879  * @return listener list
880  */
881 struct list_entity *
882 nhdp_domain_get_listener_list(void) {
883   return &_domain_listener_list;
884 }
885
886 /**
887  * get current NHDP flooding domain
888  * @return flooding domain
889  */
890 const struct nhdp_domain *
891 nhdp_domain_get_flooding(void) {
892   return &_flooding_domain;
893 }
894
895 /**
896  * Recalculate the 'best link/metric' values of a neighbor
897  * @param domain NHDP domain
898  * @param neigh NHDP neighbor
899  */
900 static void
901 _recalculate_neighbor_metric(
902     struct nhdp_domain *domain,
903     struct nhdp_neighbor *neigh) {
904   struct nhdp_link *lnk;
905   struct nhdp_link_domaindata *linkdata;
906   struct nhdp_neighbor_domaindata *neighdata;
907   struct nhdp_metric oldmetric;
908 #ifdef OONF_LOG_DEBUG_INFO
909   struct netaddr_str nbuf;
910 #endif
911
912   neighdata = nhdp_domain_get_neighbordata(domain, neigh);
913
914   /* copy old metric value */
915   memcpy(&oldmetric, &neighdata->metric, sizeof(oldmetric));
916
917   /* reset metric */
918   neighdata->metric.in = RFC7181_METRIC_INFINITE;
919   neighdata->metric.out = RFC7181_METRIC_INFINITE;
920
921   /* reset best link */
922   neighdata->best_link = NULL;
923   neighdata->best_link_ifindex = 0;
924
925   OONF_DEBUG(LOG_NHDP, "Recalculate neighbor %s metrics (ext %u):",
926       netaddr_to_string(&nbuf, &neigh->originator), domain->ext);
927
928   /* get best metric */
929   list_for_each_element(&neigh->_links, lnk, _neigh_node) {
930     linkdata = nhdp_domain_get_linkdata(domain, lnk);
931     if (linkdata->metric.out < neighdata->metric.out) {
932       OONF_DEBUG(LOG_NHDP, "Link on if %s has better outgoing metric: %u",
933               lnk->local_if->os_if_listener.data->name,
934               linkdata->metric.out);
935
936       neighdata->metric.out = linkdata->metric.out;
937       neighdata->best_link = lnk;
938     }
939     if (linkdata->metric.in < neighdata->metric.in) {
940       OONF_DEBUG(LOG_NHDP, "Link on if %s has better incoming metric: %u",
941               lnk->local_if->os_if_listener.data->name,
942               linkdata->metric.in);
943       neighdata->metric.in = linkdata->metric.in;
944     }
945   }
946
947   if (neighdata->best_link != NULL) {
948     OONF_DEBUG(LOG_NHDP, "Best link if: %s",
949         nhdp_interface_get_if_listener(neighdata->best_link->local_if)->data->name);
950     neighdata->best_link_ifindex =
951         nhdp_interface_get_if_listener(neighdata->best_link->local_if)->data->index;
952   }
953
954   if (memcmp(&oldmetric, &neighdata->metric, sizeof(oldmetric)) != 0) {
955     /* mark metric as updated */
956     domain->neighbor_metric_changed = true;
957   }
958 }
959
960 /**
961  * Add a new domain to the NHDP system
962  * @param ext TLV extension type used for new domain
963  * @return pointer to new domain, NULL, if out of memory or
964  *   maximum number of domains has been reached.
965  */
966 struct nhdp_domain *
967 nhdp_domain_add(uint8_t ext) {
968   struct nhdp_domain *domain;
969   int i;
970
971   domain = nhdp_domain_get_by_ext(ext);
972   if (domain) {
973     return domain;
974   }
975
976   if (_domain_counter == NHDP_MAXIMUM_DOMAINS) {
977     OONF_WARN(LOG_NHDP, "Maximum number of NHDP domains reached: %d",
978         NHDP_MAXIMUM_DOMAINS);
979     return NULL;
980   }
981
982   /* initialize new domain */
983   domain = oonf_class_malloc(&_domain_class);
984   if (domain == NULL) {
985     return NULL;
986   }
987
988   domain->ext = ext;
989   domain->index = _domain_counter++;
990   domain->metric = &_no_metric;
991   domain->mpr = &_everyone_mprs;
992
993   domain->mpr->_refcount++;
994   domain->metric->_refcount++;
995
996   /* initialize metric TLVs */
997   for (i=0; i<4; i++) {
998     domain->_metric_addrtlvs[i].type = RFC7181_ADDRTLV_LINK_METRIC;
999     domain->_metric_addrtlvs[i].exttype = domain->ext;
1000
1001     rfc5444_writer_register_addrtlvtype(&_protocol->writer,
1002         &domain->_metric_addrtlvs[i], -1);
1003   }
1004
1005   /* add to domain list */
1006   list_add_tail(&_domain_list, &domain->_node);
1007
1008   oonf_class_event(&_domain_class, domain,OONF_OBJECT_ADDED);
1009   return domain;
1010 }
1011
1012 /**
1013  * Configure a NHDP domain to a metric and a MPR algorithm
1014  * @param ext TLV extension type used for new domain
1015  * @param metric_name name of the metric algorithm to be used,
1016  *   might be CFG_DOMAIN_NO_METRIC (for hopcount metric)
1017  *   or CFG_DOMAIN_ANY_METRIC (for a metric the NHDP core should
1018  *   choose).
1019  * @param mpr_name name of the MPR algorithm to be used,
1020  *   might be CFG_DOMAIN_NO_MPR (every node is MPR)
1021  *   or CFG_DOMAIN_ANY_MPR (for a MPR the NHDP core should
1022  *   choose).
1023  * @param willingness routing willingness for domain
1024  * @return pointer to configured domain, NULL, if out of memory or
1025  *   maximum number of domains has been reached.
1026  */
1027 struct nhdp_domain *
1028 nhdp_domain_configure(uint8_t ext, const char *metric_name,
1029     const char *mpr_name, uint8_t willingness) {
1030   struct nhdp_domain *domain;
1031
1032   domain = nhdp_domain_add(ext);
1033   if (domain == NULL) {
1034     return NULL;
1035   }
1036
1037   OONF_DEBUG(LOG_NHDP, "Configure domain %u to metric=%s",
1038       domain->index, metric_name);
1039   _apply_metric(domain, metric_name);
1040
1041   OONF_DEBUG(LOG_NHDP, "Configure domain %u to mpr=%s, willingness=%u",
1042       domain->index, mpr_name, willingness);
1043   _apply_mpr(domain, mpr_name, willingness);
1044
1045   oonf_class_event(&_domain_class, domain, OONF_OBJECT_CHANGED);
1046
1047   return domain;
1048 }
1049
1050 /**
1051  * Apply a new metric algorithm to a NHDP domain
1052  * @param domain pointer to NHDP domain
1053  * @param metric_name name of the metric algorithm to be used,
1054  *   might be CFG_DOMAIN_NO_METRIC (for hopcount metric)
1055  *   or CFG_DOMAIN_ANY_METRIC (for a metric the NHDP core should
1056  *   choose).
1057  */
1058 static void
1059 _apply_metric(struct nhdp_domain *domain, const char *metric_name) {
1060   struct nhdp_domain_metric *metric;
1061
1062   /* check if we have to remove the old metric first */
1063   if (strcasecmp(domain->metric_name, metric_name) == 0) {
1064     /* nothing to do, we already have the right metric */
1065     return;
1066   }
1067
1068   if (domain->metric != &_no_metric) {
1069     _remove_metric(domain);
1070   }
1071
1072   /* Handle wildcard metric name first */
1073   if (strcasecmp(metric_name, CFG_DOMAIN_ANY_METRIC_MPR) == 0
1074       && !avl_is_empty(&_domain_metrics)) {
1075     metric_name = avl_first_element(&_domain_metrics, metric, _node)->name;
1076   }
1077
1078   /* look for metric implementation */
1079   metric = avl_find_element(&_domain_metrics, metric_name, metric, _node);
1080   if (metric == NULL) {
1081     metric = &_no_metric;
1082   }
1083
1084   /* copy new metric name */
1085   strscpy(domain->metric_name, metric->name, sizeof(domain->metric_name));
1086
1087   /* link domain and metric */
1088   domain->metric->_refcount--;
1089   domain->metric = metric;
1090
1091   /* activate metric */
1092   if (metric->_refcount == 0 && metric->enable) {
1093     metric->enable();
1094   }
1095   metric->_refcount++;
1096 }
1097
1098 /**
1099  * Reset the metric of a NHDP domain to hopcount
1100  * @param domain pointer to NHDP domain
1101  */
1102 static void
1103 _remove_metric(struct nhdp_domain *domain) {
1104   domain->metric->_refcount--;
1105   if (!domain->metric->_refcount && domain->metric->disable) {
1106     domain->metric->disable();
1107   }
1108   strscpy(domain->metric_name, CFG_DOMAIN_NO_METRIC_MPR, sizeof(domain->metric_name));
1109   domain->metric = &_no_metric;
1110   domain->metric->_refcount++;
1111 }
1112
1113 /**
1114  * Apply a new MPR algorithm to a NHDP domain
1115  * @param domain pointer to NHDP domain
1116  * @param mpr_name name of the MPR algorithm to be used,
1117  *   might be CFG_DOMAIN_NO_MPR (every node is MPR)
1118  *   or CFG_DOMAIN_ANY_MPR (for a MPR the NHDP core should
1119  *   choose).
1120  * @param willingness routing willingness for domain
1121  */
1122 static void
1123 _apply_mpr(struct nhdp_domain *domain, const char *mpr_name, uint8_t willingness) {
1124   struct nhdp_domain_mpr *mpr;
1125
1126   domain->local_willingness = willingness;
1127
1128   /* check if we have to remove the old mpr first */
1129   if (strcasecmp(domain->mpr_name, mpr_name) == 0) {
1130     /* nothing else to do, we already have the right MPR */
1131     return;
1132   }
1133   if (domain->mpr != &_everyone_mprs) {
1134     /* replace old MPR algorithm with "everyone MPR" */
1135     _remove_mpr(domain);
1136   }
1137
1138   /* Handle wildcard mpr name first */
1139   if (strcasecmp(mpr_name, CFG_DOMAIN_ANY_METRIC_MPR) == 0
1140       && !avl_is_empty(&_domain_mprs)) {
1141     mpr_name = avl_first_element(&_domain_mprs, mpr, _node)->name;
1142   }
1143
1144   /* look for mpr implementation */
1145   mpr = avl_find_element(&_domain_mprs, mpr_name, mpr, _node);
1146   if (mpr == NULL) {
1147     mpr = &_everyone_mprs;
1148   }
1149
1150   /* copy new metric name */
1151   strscpy(domain->mpr_name, mpr->name, sizeof(domain->mpr_name));
1152
1153   /* link domain and mpr */
1154   domain->mpr->_refcount--;
1155   domain->mpr = mpr;
1156
1157   /* activate mpr */
1158   if (mpr->_refcount == 0 && mpr->enable) {
1159     mpr->enable();
1160   }
1161   mpr->_refcount++;
1162 }
1163
1164 /**
1165  * Reset the MPR of a NHDP domain to 'everyone is MPR'
1166  * @param domain pointer to NHDP domain
1167  */
1168 static void
1169 _remove_mpr(struct nhdp_domain *domain) {
1170   domain->mpr->_refcount--;
1171   if (!domain->mpr->_refcount && domain->mpr->disable) {
1172     domain->mpr->disable();
1173   }
1174   strscpy(domain->mpr_name, CFG_DOMAIN_NO_METRIC_MPR, sizeof(domain->mpr_name));
1175   domain->mpr = &_everyone_mprs;
1176   domain->mpr->_refcount++;
1177 }
1178
1179 static void
1180 _cb_update_everyone_mpr(void) {
1181   struct nhdp_neighbor *neigh;
1182   struct nhdp_domain *domain;
1183   struct nhdp_neighbor_domaindata *domaindata;
1184
1185   list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
1186     if (_flooding_domain.mpr == &_everyone_mprs) {
1187       neigh->neigh_is_flooding_mpr =
1188           neigh->flooding_willingness > RFC7181_WILLINGNESS_NEVER;
1189     }
1190
1191     list_for_each_element(nhdp_domain_get_list(), domain, _node) {
1192       if (domain->mpr == &_everyone_mprs) {
1193         domaindata = nhdp_domain_get_neighbordata(domain, neigh);
1194         domaindata->neigh_is_mpr =
1195             domaindata->willingness > RFC7181_WILLINGNESS_NEVER;
1196       }
1197     }
1198   }
1199 }
1200
1201 /**
1202  * Default implementation to convert a link metric value into text
1203  * @param buf pointer to metric output buffer
1204  * @param metric link metric value
1205  * @return pointer to string representation of linkmetric value
1206  */
1207 static const char *
1208 _link_to_string(struct nhdp_metric_str *buf, uint32_t metric) {
1209   snprintf(buf->buf, sizeof(*buf), "0x%x", metric);
1210
1211   return buf->buf;
1212 }
1213
1214 /**
1215  * Default implementation to convert a path metric value into text
1216  * @param buf pointer to metric output buffer
1217  * @param metric path metric value
1218  * @param hopcount hopcount of path
1219  * @return pointer to string representation of path metric value
1220  */
1221 static const char *
1222 _path_to_string(struct nhdp_metric_str *buf, uint32_t metric,
1223     uint8_t hopcount __attribute((unused))) {
1224   snprintf(buf->buf, sizeof(*buf), "0x%x", metric);
1225
1226   return buf->buf;
1227 }
1228
1229 static const char *
1230 _int_to_string(struct nhdp_metric_str *buf,
1231     struct nhdp_link *lnk __attribute__((unused))) {
1232   strscpy(buf->buf, "-", sizeof(*buf));
1233   return buf->buf;
1234 }