Merge branch 'master' into mpr_rework
[oonf.git] / src-plugins / nhdp / nhdp / nhdp_reader.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 "common/common_types.h"
47 #include "common/netaddr.h"
48 #include "core/oonf_logging.h"
49 #include "core/oonf_subsystem.h"
50 #include "subsystems/oonf_rfc5444.h"
51
52 #include "nhdp/nhdp.h"
53 #include "nhdp/nhdp_db.h"
54 #include "nhdp/nhdp_domain.h"
55 #include "nhdp/nhdp_hysteresis.h"
56 #include "nhdp/nhdp_interfaces.h"
57 #include "nhdp/nhdp_internal.h"
58 #include "nhdp/nhdp_reader.h"
59
60 /* NHDP message TLV array index */
61 enum {
62   IDX_TLV_ITIME,
63   IDX_TLV_VTIME,
64   IDX_TLV_WILLINGNESS,
65   IDX_TLV_MPRTYPES,
66   IDX_TLV_IPV4ORIG,
67   IDX_TLV_MAC,
68 };
69
70 /* NHDP address TLV array index pass 1 */
71 enum {
72   IDX_ADDRTLV1_LOCAL_IF,
73   IDX_ADDRTLV1_LINK_STATUS,
74 };
75
76 /* NHDP address TLV array index pass 2 */
77 enum {
78   IDX_ADDRTLV2_LOCAL_IF,
79   IDX_ADDRTLV2_LINK_STATUS,
80   IDX_ADDRTLV2_OTHER_NEIGHB,
81   IDX_ADDRTLV2_MPR,
82   IDX_ADDRTLV2_LINKMETRIC,
83 };
84
85 /* prototypes */
86 static void _cleanup_error(void);
87 static enum rfc5444_result _pass2_process_localif(struct netaddr *addr, uint8_t local_if);
88 static void _handle_originator(struct rfc5444_reader_tlvblock_context *context);
89
90 static enum rfc5444_result _cb_messagetlvs(
91     struct rfc5444_reader_tlvblock_context *context);
92 static enum rfc5444_result _cb_failed_constraints(
93       struct rfc5444_reader_tlvblock_context *context);
94
95 static enum rfc5444_result
96 _cb_addresstlvs_pass1(struct rfc5444_reader_tlvblock_context *context);
97 static enum rfc5444_result _cb_addresstlvs_pass1_end(
98     struct rfc5444_reader_tlvblock_context *context, bool dropped);
99
100 static enum rfc5444_result _cb_addr_pass2_block(
101       struct rfc5444_reader_tlvblock_context *context);
102 static enum rfc5444_result _cb_msg_pass2_end(
103     struct rfc5444_reader_tlvblock_context *context, bool dropped);
104
105 /* definition of the RFC5444 reader components */
106 static struct rfc5444_reader_tlvblock_consumer _nhdp_message_pass1_consumer = {
107   .order = RFC5444_MAIN_PARSER_PRIORITY,
108   .msg_id = RFC6130_MSGTYPE_HELLO,
109   .block_callback = _cb_messagetlvs,
110   .block_callback_failed_constraints = _cb_failed_constraints,
111   .end_callback = _cb_addresstlvs_pass1_end,
112 };
113
114 static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_message_tlvs[] = {
115   [IDX_TLV_VTIME] = { .type = RFC5497_MSGTLV_VALIDITY_TIME, .type_ext = 0, .match_type_ext = true,
116       .mandatory = true, .min_length = 1, .max_length = 65535, .match_length = true },
117   [IDX_TLV_ITIME] = { .type = RFC5497_MSGTLV_INTERVAL_TIME, .type_ext = 0, .match_type_ext = true,
118       .min_length = 1, .max_length = 65535, .match_length = true },
119   [IDX_TLV_WILLINGNESS] = { .type = RFC7181_MSGTLV_MPR_WILLING, .type_ext = 0, .match_type_ext = true,
120     .min_length = 1, .max_length = 65535, .match_length = true },
121   [IDX_TLV_MPRTYPES] = { .type = DRAFT_MT_MSGTLV_MPR_TYPES,
122       .type_ext = DRAFT_MT_MSGTLV_MPR_TYPES_EXT, .match_type_ext = true,
123       .min_length = 1, .max_length = NHDP_MAXIMUM_DOMAINS, .match_length = true },
124   [IDX_TLV_IPV4ORIG] = { .type = NHDP_MSGTLV_IPV4ORIGINATOR, .type_ext = 0, .match_type_ext = true,
125       .min_length = 4, .match_length = true },
126   [IDX_TLV_MAC] = { .type = NHDP_MSGTLV_MAC, .type_ext = 0, .match_type_ext = true,
127       .min_length = 6, .match_length = true },
128 };
129
130 static struct rfc5444_reader_tlvblock_consumer _nhdp_address_pass1_consumer = {
131   .order = RFC5444_MAIN_PARSER_PRIORITY,
132   .msg_id = RFC6130_MSGTYPE_HELLO,
133   .addrblock_consumer = true,
134   .block_callback = _cb_addresstlvs_pass1,
135   .block_callback_failed_constraints = _cb_failed_constraints,
136 };
137
138 static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_address_pass1_tlvs[] = {
139   [IDX_ADDRTLV1_LOCAL_IF] = { .type = RFC6130_ADDRTLV_LOCAL_IF, .type_ext = 0, .match_type_ext = true,
140       .min_length = 1, .max_length = 65535, .match_length = true },
141   [IDX_ADDRTLV1_LINK_STATUS] = { .type = RFC6130_ADDRTLV_LINK_STATUS, .type_ext = 0, .match_type_ext = true,
142       .min_length = 1, .max_length = 65535, .match_length = true },
143 };
144
145 static struct rfc5444_reader_tlvblock_consumer _nhdp_message_pass2_consumer = {
146   .order = RFC5444_MAIN_PARSER_PRIORITY + 1,
147   .msg_id = RFC6130_MSGTYPE_HELLO,
148   .end_callback = _cb_msg_pass2_end,
149   .block_callback_failed_constraints = _cb_failed_constraints,
150 };
151
152 static struct rfc5444_reader_tlvblock_consumer _nhdp_address_pass2_consumer= {
153   .order = RFC5444_MAIN_PARSER_PRIORITY + 1,
154   .msg_id = RFC6130_MSGTYPE_HELLO,
155   .addrblock_consumer = true,
156   .block_callback = _cb_addr_pass2_block,
157   .block_callback_failed_constraints = _cb_failed_constraints,
158 };
159
160 static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_address_pass2_tlvs[] = {
161   [IDX_ADDRTLV2_LOCAL_IF] = { .type = RFC6130_ADDRTLV_LOCAL_IF, .type_ext = 0, .match_type_ext = true,
162       .min_length = 1, .max_length = 65535, .match_length = true },
163   [IDX_ADDRTLV2_LINK_STATUS] = { .type = RFC6130_ADDRTLV_LINK_STATUS, .type_ext = 0, .match_type_ext = true,
164       .min_length = 1, .max_length = 65535, .match_length = true },
165   [IDX_ADDRTLV2_OTHER_NEIGHB] = { .type = RFC6130_ADDRTLV_OTHER_NEIGHB, .type_ext = 0, .match_type_ext = true,
166       .min_length = 1, .max_length = 65535, .match_length = true },
167   [IDX_ADDRTLV2_MPR] = { .type = RFC7181_ADDRTLV_MPR,
168       .min_length = 1, .max_length = 65535, .match_length = true },
169   [IDX_ADDRTLV2_LINKMETRIC] = { .type = RFC7181_ADDRTLV_LINK_METRIC, .min_length = 2, .match_length = true },
170 };
171
172 /* nhdp multiplexer/protocol */
173 static struct oonf_rfc5444_protocol *_protocol = NULL;
174
175 /* temporary variables for message parsing */
176 static struct {
177   struct nhdp_interface *localif;
178   struct nhdp_neighbor *neighbor;
179
180   struct nhdp_link *link;
181
182   struct netaddr originator_v4;
183   struct netaddr mac;
184
185   bool naddr_conflict, laddr_conflict;
186   bool link_heard, link_lost;
187   bool has_thisif;
188
189   bool originator_in_addrblk;
190   uint64_t vtime, itime;
191
192   uint8_t mprtypes[NHDP_MAXIMUM_DOMAINS];
193   size_t mprtypes_size;
194 } _current;
195
196 /**
197  * Initialize nhdp reader
198  * @param p rfc5444 protocol
199  */
200 void
201 nhdp_reader_init(struct oonf_rfc5444_protocol *p) {
202   _protocol = p;
203
204   rfc5444_reader_add_message_consumer(
205       &_protocol->reader, &_nhdp_message_pass1_consumer,
206       _nhdp_message_tlvs, ARRAYSIZE(_nhdp_message_tlvs));
207   rfc5444_reader_add_message_consumer(
208       &_protocol->reader, &_nhdp_address_pass1_consumer,
209       _nhdp_address_pass1_tlvs, ARRAYSIZE(_nhdp_address_pass1_tlvs));
210   rfc5444_reader_add_message_consumer(
211       &_protocol->reader, &_nhdp_message_pass2_consumer, NULL, 0);
212   rfc5444_reader_add_message_consumer(
213       &_protocol->reader, &_nhdp_address_pass2_consumer,
214       _nhdp_address_pass2_tlvs, ARRAYSIZE(_nhdp_address_pass2_tlvs));
215 }
216
217 /**
218  * Cleanup nhdp reader
219  */
220 void
221 nhdp_reader_cleanup(void) {
222   rfc5444_reader_remove_message_consumer(
223       &_protocol->reader, &_nhdp_address_pass2_consumer);
224   rfc5444_reader_remove_message_consumer(
225       &_protocol->reader, &_nhdp_message_pass2_consumer);
226   rfc5444_reader_remove_message_consumer(
227       &_protocol->reader, &_nhdp_address_pass1_consumer);
228   rfc5444_reader_remove_message_consumer(
229       &_protocol->reader, &_nhdp_message_pass1_consumer);
230 }
231
232 /**
233  * An error happened during processing and the message was dropped.
234  * Make sure that there are no uninitialized datastructures left.
235  */
236 static void
237 _cleanup_error(void) {
238   if (_current.link) {
239     nhdp_db_link_remove(_current.link);
240     _current.link = NULL;
241   }
242
243   if (_current.neighbor) {
244     nhdp_db_neighbor_remove(_current.neighbor);
245     _current.neighbor = NULL;
246   }
247 }
248
249 /**
250  * Process an address with a LOCAL_IF TLV
251  * @param addr pointer to netaddr object with address
252  * @param local_if value of LOCAL_IF TLV
253  * @return
254  */
255 static enum rfc5444_result
256 _pass2_process_localif(struct netaddr *addr, uint8_t local_if) {
257   struct nhdp_neighbor *neigh;
258   struct nhdp_naddr *naddr;
259   struct nhdp_link *lnk;
260   struct nhdp_laddr *laddr;
261
262   /* make sure link addresses are added to the right link */
263   if (local_if == RFC6130_LOCALIF_THIS_IF) {
264     laddr = nhdp_interface_get_link_addr(_current.localif, addr);
265     if (laddr == NULL) {
266       /* create new link address */
267       laddr = nhdp_db_link_addr_add(_current.link, addr);
268       if (laddr == NULL) {
269         return RFC5444_DROP_MESSAGE;
270       }
271     }
272     else {
273       /* move to target link if necessary */
274       lnk = laddr->link;
275       lnk->_process_count--;
276
277       if (lnk != _current.link) {
278         nhdp_db_link_addr_move(_current.link, laddr);
279
280         if (lnk->_process_count == 0) {
281           /* no address left to process, remove old link */
282           nhdp_db_link_remove(lnk);
283         }
284       }
285
286       /* remove mark from address */
287       laddr->_might_be_removed = false;
288     }
289   }
290
291   /* make sure neighbor addresses are added to the right neighbor */
292   naddr = nhdp_db_neighbor_addr_get(addr);
293   if (naddr == NULL) {
294     /* create new neighbor address */
295     naddr = nhdp_db_neighbor_addr_add(_current.neighbor, addr);
296     if (naddr == NULL) {
297       return RFC5444_DROP_MESSAGE;
298     }
299   }
300   else {
301     /* move to target neighbor if necessary */
302     neigh = naddr->neigh;
303     neigh->_process_count--;
304
305     if (neigh != _current.neighbor) {
306       nhdp_db_neighbor_addr_move(_current.neighbor, naddr);
307
308       if (neigh->_process_count == 0) {
309         /* no address left to process, remove old neighbor */
310         nhdp_db_neighbor_remove(neigh);
311       }
312     }
313
314     /* remove mark from address */
315     naddr->_might_be_removed = false;
316
317     /* mark as not lost */
318     nhdp_db_neighbor_addr_not_lost(naddr);
319   }
320
321   return RFC5444_OKAY;
322 }
323
324 /**
325  * Handle in originator address of NHDP Hello
326  */
327 static void
328 _handle_originator(struct rfc5444_reader_tlvblock_context *context) {
329   struct nhdp_neighbor *neigh;
330 #ifdef OONF_LOG_DEBUG_INFO
331   struct netaddr_str buf;
332 #endif
333
334   OONF_DEBUG(LOG_NHDP_R, "Handle originator %s",
335       netaddr_to_string(&buf, &context->orig_addr));
336
337   neigh = nhdp_db_neighbor_get_by_originator(&context->orig_addr);
338   if (!neigh) {
339     return;
340   }
341
342   if (_current.neighbor == neigh) {
343     /* everything is fine, move along */
344     return;
345   }
346
347   if (_current.neighbor == NULL && !_current.naddr_conflict) {
348     /* we take the neighbor selected by the originator */
349     _current.neighbor = neigh;
350     return;
351   }
352
353   if (neigh->_process_count > 0) {
354     /* neighbor selected by originator will already be cleaned up */
355     return;
356   }
357
358   nhdp_db_neighbor_set_originator(neigh, &NETADDR_UNSPEC);
359 }
360
361 /**
362  * Handle in HELLO messages and its TLVs
363  * @param consumer tlvblock consumer
364  * @param context message context
365  * @return see rfc5444_result enum
366  */
367 static enum rfc5444_result
368 _cb_messagetlvs(struct rfc5444_reader_tlvblock_context *context) {
369   struct rfc5444_reader_tlvblock_entry *tlv;
370   struct nhdp_neighbor *neigh;
371   struct nhdp_link *lnk;
372   int af_type;
373 #ifdef OONF_LOG_INFO
374   struct netaddr_str buf;
375 #endif
376
377   /*
378    * First remove all old session data.
379    * Do not put anything that could drop a session before this point,
380    * otherwise the cleanup path will run on an outdated session object.
381    */
382   memset(&_current, 0, sizeof(_current));
383
384   OONF_INFO(LOG_NHDP_R,
385       "Incoming message type %d from %s through %s (addrlen = %u), got message tlvs",
386       context->msg_type, netaddr_socket_to_string(&buf, _protocol->input.src_socket),
387       _protocol->input.interface->name, context->addr_len);
388
389   switch (context->addr_len) {
390     case 4:
391       af_type = AF_INET;
392       break;
393     case 16:
394       af_type = AF_INET6;
395       break;
396     default:
397       af_type = 0;
398       break;
399   }
400
401   if (!oonf_rfc5444_is_interface_active(_protocol->input.interface, af_type)) {
402     OONF_DEBUG(LOG_NHDP_R, "We do not handle address length %u on interface %s",
403         context->addr_len, _protocol->input.interface->name);
404     return RFC5444_DROP_MESSAGE;
405   }
406
407   /* remember local NHDP interface */
408   _current.localif = nhdp_interface_get(_protocol->input.interface->name);
409   if (!_current.localif) {
410     /* incoming message through an interface unspecific socket, ignore it */
411     return RFC5444_DROP_MESSAGE;
412   }
413
414   /* extract originator address */
415   if (context->has_origaddr) {
416     OONF_DEBUG(LOG_NHDP_R, "Got originator: %s",
417         netaddr_to_string(&buf, &context->orig_addr));
418   }
419
420   /*
421    * extract validity time and interval time, no vector possible because
422    * HELLO is always single-hop
423    */
424   tlv = _nhdp_message_tlvs[IDX_TLV_VTIME].tlv;
425   _current.vtime = rfc5497_timetlv_decode(tlv->single_value[0]);
426
427   if (_nhdp_message_tlvs[IDX_TLV_ITIME].tlv) {
428     tlv = _nhdp_message_tlvs[IDX_TLV_ITIME].tlv;
429     _current.itime = rfc5497_timetlv_decode(tlv->single_value[0]);
430   }
431
432   /* extract mpr types for MT implementation */
433   _current.mprtypes_size = nhdp_domain_process_mprtypes_tlv(
434       _current.mprtypes, sizeof(_current.mprtypes),
435       _nhdp_message_tlvs[IDX_TLV_MPRTYPES].tlv);
436
437   /* extract willingness into temporary buffers */
438   nhdp_domain_process_willingness_tlv(_current.mprtypes, _current.mprtypes_size,
439         _nhdp_message_tlvs[IDX_TLV_WILLINGNESS].tlv);
440
441   /* extract v4 originator in dualstack messages */
442   if (_nhdp_message_tlvs[IDX_TLV_IPV4ORIG].tlv) {
443     if (netaddr_from_binary(&_current.originator_v4,
444         _nhdp_message_tlvs[IDX_TLV_IPV4ORIG].tlv->single_value, 4, AF_INET)) {
445       /* error, could not parse address */
446       return RFC5444_DROP_MESSAGE;
447     }
448
449     OONF_DEBUG(LOG_NHDP_R, "Got originator: %s",
450         netaddr_to_string(&buf, &_current.originator_v4));
451   }
452
453   /* extract mac address if present */
454   if (_nhdp_message_tlvs[IDX_TLV_MAC].tlv) {
455     if (netaddr_from_binary(&_current.mac,
456         _nhdp_message_tlvs[IDX_TLV_MAC].tlv->single_value, 6, AF_MAC48)) {
457       /* error, could not parse address */
458       return RFC5444_DROP_MESSAGE;
459     }
460   }
461
462   /* clear flags in neighbors */
463   list_for_each_element(nhdp_db_get_neigh_list(), neigh, _global_node) {
464     neigh->_process_count = 0;
465   }
466
467   list_for_each_element(&_current.localif->_links, lnk, _if_node) {
468     lnk->_process_count = 0;
469   }
470
471   return RFC5444_OKAY;
472 }
473
474 static enum rfc5444_result
475 _cb_failed_constraints(struct rfc5444_reader_tlvblock_context *context __attribute__((unused))) {
476 #ifdef OONF_LOG_INFO
477   struct netaddr_str nbuf;
478 #endif
479
480   OONF_INFO(LOG_NHDP_R,
481       "Incoming message type %d from %s through %s (addrlen = %u) failed constraints",
482       context->msg_type, netaddr_socket_to_string(&nbuf, _protocol->input.src_socket),
483       _protocol->input.interface->name, context->addr_len);
484   return RFC5444_DROP_MESSAGE;
485 }
486
487 /**
488  * Process addresses of NHDP Hello message to determine link/neighbor status
489  * @param consumer
490  * @param context
491  * @return
492  */
493 static enum rfc5444_result
494 _cb_addresstlvs_pass1(struct rfc5444_reader_tlvblock_context *context) {
495   uint8_t local_if, link_status;
496   struct nhdp_naddr *naddr;
497   struct nhdp_laddr *laddr;
498 #ifdef OONF_LOG_DEBUG_INFO
499   struct netaddr_str nbuf;
500 #endif
501
502   local_if = 255;
503   link_status = 255;
504
505   if (_nhdp_address_pass1_tlvs[IDX_ADDRTLV1_LOCAL_IF].tlv) {
506     local_if = _nhdp_address_pass1_tlvs[IDX_ADDRTLV1_LOCAL_IF].tlv->single_value[0];
507     local_if &= RFC6130_LOCALIF_BITMASK;
508   }
509   if (_nhdp_address_pass1_tlvs[IDX_ADDRTLV1_LINK_STATUS].tlv) {
510     link_status = _nhdp_address_pass1_tlvs[IDX_ADDRTLV1_LINK_STATUS].tlv->single_value[0];
511     link_status &= RFC6130_LINKSTATUS_BITMASK;
512   }
513
514   OONF_DEBUG(LOG_NHDP_R, "Pass 1: address %s, local_if %u, link_status: %u",
515       netaddr_to_string(&nbuf, &context->addr), local_if, link_status);
516
517   if (context->has_origaddr && !_current.originator_in_addrblk
518       && netaddr_cmp(&context->addr, &context->orig_addr) == 0) {
519     /* originator is inside address block, prevent using it */
520     _current.originator_in_addrblk = true;
521   }
522
523   if (local_if == RFC6130_LOCALIF_THIS_IF
524         || local_if == RFC6130_LOCALIF_OTHER_IF) {
525     /* still no neighbor address conflict, so keep checking */
526     naddr = nhdp_db_neighbor_addr_get(&context->addr);
527     if (naddr != NULL) {
528       OONF_DEBUG(LOG_NHDP_R, "Found neighbor in database");
529       naddr->neigh->_process_count++;
530
531       if (!_current.naddr_conflict) {
532         if (_current.neighbor == NULL) {
533           /* first neighbor, just remember it */
534           _current.neighbor = naddr->neigh;
535         }
536         else if (_current.neighbor != naddr->neigh) {
537           /* this is a neighbor address conflict */
538           OONF_DEBUG(LOG_NHDP_R, "Conflict between neighbor addresses detected");
539           _current.neighbor = NULL;
540           _current.naddr_conflict = true;
541         }
542       }
543     }
544   }
545
546   if (local_if == RFC6130_LOCALIF_THIS_IF) {
547     /* check for link address conflict */
548     laddr = nhdp_interface_get_link_addr(_current.localif, &context->addr);
549     if (laddr != NULL) {
550       OONF_DEBUG(LOG_NHDP_R, "Found link in database");
551       laddr->link->_process_count++;
552
553       if (!_current.laddr_conflict) {
554         if (_current.link == NULL) {
555           /* first link, just remember it */
556           _current.link = laddr->link;
557         }
558         else if (_current.link != laddr->link) {
559           /* this is a link address conflict */
560           OONF_DEBUG(LOG_NHDP_R, "Conflict between link addresses detected");
561           _current.link = NULL;
562           _current.laddr_conflict = true;
563         }
564       }
565     }
566
567     /* remember that we had a local_if = THIS_IF address */
568     _current.has_thisif = true;
569   }
570
571   /* detect if our own node is seen by our neighbor */
572   if (link_status != 255
573       && nhdp_interface_addr_if_get(_current.localif, &context->addr) != NULL) {
574     if (link_status == RFC6130_LINKSTATUS_LOST) {
575       OONF_DEBUG(LOG_NHDP_R, "Link neighbor lost this node address: %s",
576           netaddr_to_string(&nbuf, &context->addr));
577       _current.link_lost = true;
578     }
579     else {
580       OONF_DEBUG(LOG_NHDP_R, "Link neighbor heard this node address: %s",
581           netaddr_to_string(&nbuf, &context->addr));
582       _current.link_heard = true;
583     }
584   }
585
586   /* we do nothing in this pass except for detecting the situation */
587   return RFC5444_OKAY;
588 }
589
590 /**
591  * Handle end of message for pass1 processing. Create link/neighbor if necessary,
592  * mark addresses as potentially lost.
593  * @param consumer
594  * @param context
595  * @param dropped
596  * @return
597  */
598 static enum rfc5444_result
599 _cb_addresstlvs_pass1_end(struct rfc5444_reader_tlvblock_context *context, bool dropped) {
600   struct nhdp_naddr *naddr;
601   struct nhdp_laddr *laddr;
602
603   if (dropped) {
604     _cleanup_error();
605     return RFC5444_OKAY;
606   }
607
608   /* handle originator address */
609   if (context->has_origaddr && !_current.originator_in_addrblk
610       && netaddr_get_address_family(&context->orig_addr) != AF_UNSPEC) {
611     _handle_originator(context);
612   }
613
614   /* allocate neighbor and link if necessary */
615   if (_current.neighbor == NULL) {
616     OONF_DEBUG(LOG_NHDP_R, "Create new neighbor");
617     _current.neighbor = nhdp_db_neighbor_add();
618     if (_current.neighbor == NULL) {
619       return RFC5444_DROP_MESSAGE;
620     }
621   }
622   else {
623     /* mark existing neighbor addresses */
624     avl_for_each_element(&_current.neighbor->_neigh_addresses, naddr, _neigh_node) {
625       if (netaddr_get_binlength(&naddr->neigh_addr) == context->addr_len) {
626         naddr->_might_be_removed = true;
627       }
628     }
629   }
630
631   /* allocate link if necessary */
632   if (_current.link == NULL) {
633     OONF_DEBUG(LOG_NHDP_R, "Create new link");
634     _current.link = nhdp_db_link_add(_current.neighbor, _current.localif);
635     if (_current.link == NULL) {
636       return RFC5444_DROP_MESSAGE;
637     }
638   }
639   else {
640     /* mark existing link addresses */
641     avl_for_each_element(&_current.link->_addresses, laddr, _link_node) {
642       laddr->_might_be_removed = true;
643     }
644   }
645
646   /* copy interface address of link */
647   memcpy(&_current.link->if_addr, _protocol->input.src_address, sizeof(struct netaddr));
648
649   /* copy mac address */
650   if (netaddr_get_address_family(&_current.mac) == AF_MAC48) {
651     memcpy(&_current.link->remote_mac, &_current.mac, sizeof(_current.mac));
652   }
653
654   if (!_current.has_thisif) {
655     struct netaddr addr;
656
657     /* translate like a RFC5444 address */
658     if(netaddr_from_binary(&addr, netaddr_get_binptr(_protocol->input.src_address),
659         netaddr_get_binlength(_protocol->input.src_address), 0)) {
660       return RFC5444_DROP_MESSAGE;
661     }
662
663     /* parse as if it would be tagged with a LOCAL_IF = THIS_IF TLV */
664     _pass2_process_localif(&addr, RFC6130_LOCALIF_THIS_IF);
665   }
666
667   /* remember vtime and itime */
668   _current.link->vtime_value = _current.vtime;
669   _current.link->itime_value = _current.itime;
670
671   /* update hysteresis */
672   nhdp_hysteresis_update(_current.link, context);
673
674   /* handle dualstack information */
675   if (context->has_origaddr) {
676     if (netaddr_get_address_family(&_current.originator_v4) != AF_UNSPEC) {
677       struct nhdp_neighbor *neigh2;
678       struct nhdp_link *lnk2;
679
680       neigh2 = nhdp_db_neighbor_get_by_originator(&_current.originator_v4);
681       if (neigh2) {
682         nhdp_db_neighbor_connect_dualstack(_current.neighbor, neigh2);
683       }
684
685       lnk2 = nhdp_interface_link_get_by_originator(_current.localif, &_current.originator_v4);
686       if (lnk2) {
687         nhdp_db_link_connect_dualstack(_current.link, lnk2);
688       }
689     }
690     else if (netaddr_get_address_family(&context->orig_addr) == AF_INET6
691         && netaddr_get_address_family(&_current.originator_v4) == AF_UNSPEC) {
692       nhdp_db_neigbor_disconnect_dualstack(_current.neighbor);
693       nhdp_db_link_disconnect_dualstack(_current.link);
694     }
695   }
696
697   OONF_DEBUG(LOG_NHDP_R, "pass1 finished");
698
699   return RFC5444_OKAY;
700 }
701
702
703 /**
704  * Process MPR, Willingness and Linkmetric TLVs for local neighbor
705  * @param addr address the TLVs are attached to
706  */
707 static void
708 _process_domainspecific_linkdata(struct netaddr *addr __attribute__((unused))) {
709   struct rfc5444_reader_tlvblock_entry *tlv;
710   struct nhdp_domain *domain;
711   struct nhdp_neighbor_domaindata *neighdata;
712 #ifdef OONF_LOG_DEBUG_INFO
713   struct netaddr_str buf;
714 #endif
715   /*
716    * clear routing mpr, willingness and metric values
717    * that should be present in HELLO
718    */
719   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
720     neighdata = nhdp_domain_get_neighbordata(domain, _current.neighbor);
721
722     neighdata->local_is_mpr = false;
723     neighdata->willingness = 0;
724     nhdp_domain_get_linkdata(domain, _current.link)->metric.out =
725         RFC7181_METRIC_INFINITE;
726     neighdata->metric.out = RFC7181_METRIC_INFINITE;
727   }
728
729   /* process MPR settings of link */
730   nhdp_domain_process_mpr_tlv(_current.mprtypes, _current.mprtypes_size,
731       _current.link, _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_MPR].tlv);
732
733   /* update out metric with other sides in metric */
734   tlv = _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LINKMETRIC].tlv;
735   while (tlv) {
736     /* get metric handler */
737     domain = nhdp_domain_get_by_ext(tlv->type_ext);
738     if (domain != NULL && !domain->metric->no_default_handling) {
739       nhdp_domain_process_metric_linktlv(domain, _current.link, tlv->single_value);
740
741       /* extract tlv value */
742       OONF_DEBUG(LOG_NHDP_R, "Pass 2: address %s, LQ (ext %u): %02x%02x",
743           netaddr_to_string(&buf, addr), tlv->type_ext,
744           tlv->single_value[0], tlv->single_value[1]);
745     }
746
747     tlv = tlv->next_entry;
748   }
749 }
750
751 /**
752  * Process Linkmetric TLVs for twohop neighbor
753  * @param l2hop pointer to twohop neighbor
754  * @param addr address the TLVs are attached to
755  */
756 static void
757 _process_domainspecific_2hopdata(struct nhdp_l2hop *l2hop,
758     struct netaddr *addr __attribute__((unused))) {
759   struct rfc5444_reader_tlvblock_entry *tlv;
760   struct nhdp_domain *domain;
761   struct nhdp_l2hop_domaindata *data;
762 #ifdef OONF_LOG_DEBUG_INFO
763   struct netaddr_str buf;
764 #endif
765
766   /* clear metric values that should be present in HELLO */
767   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
768     if (!domain->metric->no_default_handling) {
769       data = nhdp_domain_get_l2hopdata(domain, l2hop);
770       data->metric.in = RFC7181_METRIC_INFINITE;
771       data->metric.out = RFC7181_METRIC_INFINITE;
772     }
773   }
774
775   /* update 2-hop metric (no direction reversal!) */
776   tlv = _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LINKMETRIC].tlv;
777   while (tlv) {
778     /* get metric handler */
779     domain = nhdp_domain_get_by_ext(tlv->type_ext);
780     if (domain != NULL && !domain->metric->no_default_handling) {
781       nhdp_domain_process_metric_2hoptlv(domain, l2hop, tlv->single_value);
782
783       OONF_DEBUG(LOG_NHDP_R, "Pass 2: address %s, LQ (ext %u): %02x%02x",
784           netaddr_to_string(&buf, addr), tlv->type_ext,
785           tlv->single_value[0], tlv->single_value[1]);
786
787     }
788
789     tlv = tlv->next_entry;
790   }
791 }
792
793 /**
794  * Second pass for processing the addresses of the NHDP Hello. This one will update
795  * the database
796  * @param consumer
797  * @param context
798  * @return
799  */
800 static enum rfc5444_result
801 _cb_addr_pass2_block(struct rfc5444_reader_tlvblock_context *context) {
802   uint8_t local_if, link_status, other_neigh;
803   struct nhdp_l2hop *l2hop;
804 #ifdef OONF_LOG_DEBUG_INFO
805   struct netaddr_str buf;
806 #endif
807
808   local_if = 255;
809   link_status = 255;
810   other_neigh = 255;
811
812   /* read values of TLVs that can only be present once */
813   if (_nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LOCAL_IF].tlv) {
814     local_if = _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LOCAL_IF].tlv->single_value[0];
815     local_if &= RFC6130_LOCALIF_BITMASK;
816   }
817   if (_nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LINK_STATUS].tlv) {
818     link_status = _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_LINK_STATUS].tlv->single_value[0];
819     link_status &= RFC6130_LINKSTATUS_BITMASK;
820   }
821   if (_nhdp_address_pass2_tlvs[IDX_ADDRTLV2_OTHER_NEIGHB].tlv) {
822     other_neigh = _nhdp_address_pass2_tlvs[IDX_ADDRTLV2_OTHER_NEIGHB].tlv->single_value[0];
823     other_neigh &= RFC6130_OTHERNEIGHB_SYMMETRIC;
824   }
825   OONF_DEBUG(LOG_NHDP_R, "Pass 2: address %s, local_if %u, link_status: %u, other_neigh: %u",
826       netaddr_to_string(&buf, &context->addr), local_if, link_status, other_neigh);
827
828   if (local_if == RFC6130_LOCALIF_THIS_IF || local_if == RFC6130_LOCALIF_OTHER_IF) {
829     /* parse LOCAL_IF TLV */
830     _pass2_process_localif(&context->addr, local_if);
831   }
832
833   /* handle 2hop-addresses */
834   if (link_status != 255 || other_neigh != 255) {
835     if (nhdp_interface_addr_if_get(_current.localif, &context->addr) != NULL) {
836       _process_domainspecific_linkdata(&context->addr);
837     }
838     else if (nhdp_interface_addr_global_get(&context->addr) != NULL) {
839       OONF_DEBUG(LOG_NHDP_R, "Link neighbor heard this node address: %s",
840           netaddr_to_string(&buf, &context->addr));
841     }
842     else if (link_status == RFC6130_LINKSTATUS_SYMMETRIC
843         || other_neigh == RFC6130_OTHERNEIGHB_SYMMETRIC){
844       l2hop  = ndhp_db_link_2hop_get(_current.link, &context->addr);
845       if (l2hop == NULL) {
846         /* create new 2hop address */
847         l2hop = nhdp_db_link_2hop_add(_current.link, &context->addr);
848         if (l2hop == NULL) {
849           return RFC5444_DROP_MESSAGE;
850         }
851       }
852
853       /* remember if 2hop is same interface */
854       l2hop->same_interface = link_status == RFC6130_LINKSTATUS_SYMMETRIC;
855
856       /* refresh validity time of 2hop address */
857       nhdp_db_link_2hop_set_vtime(l2hop, _current.vtime);
858
859       _process_domainspecific_2hopdata(l2hop, &context->addr);
860     }
861     else {
862       l2hop = ndhp_db_link_2hop_get(_current.link, &context->addr);
863       if (l2hop) {
864         /* remove 2hop address */
865         nhdp_db_link_2hop_remove(l2hop);
866       }
867     }
868   }
869
870   return RFC5444_OKAY;
871 }
872
873 /**
874  * Finalize changes of the database and update the status of the link
875  * @param consumer
876  * @param context
877  * @param dropped
878  * @return
879  */
880 static enum rfc5444_result
881 _cb_msg_pass2_end(struct rfc5444_reader_tlvblock_context *context, bool dropped) {
882   struct nhdp_naddr *naddr;
883   struct nhdp_laddr *laddr, *la_it;
884   struct nhdp_l2hop *twohop, *twohop_it;
885   uint64_t t;
886 #ifdef OONF_LOG_DEBUG_INFO
887   struct netaddr_str nbuf;
888 #endif
889
890   if (dropped) {
891     _cleanup_error();
892     return RFC5444_OKAY;
893   }
894
895   /* remove leftover link addresses */
896   avl_for_each_element_safe(&_current.link->_addresses, laddr, _link_node, la_it) {
897     if (laddr->_might_be_removed) {
898       nhdp_db_link_addr_remove(laddr);
899     }
900   }
901
902   /* remove leftover neighbor addresses */
903   avl_for_each_element(&_current.neighbor->_neigh_addresses, naddr, _neigh_node) {
904     if (naddr->_might_be_removed) {
905       /* mark as lost */
906       nhdp_db_neighbor_addr_set_lost(naddr, _current.localif->n_hold_time);
907
908       /* section 12.6.1: remove all similar n2 addresses */
909       // TODO: not nice, replace with new iteration macro
910       twohop_it = avl_find_element(&_current.link->_2hop, &naddr->neigh_addr, twohop_it, _link_node);
911       while (twohop_it) {
912         twohop = twohop_it;
913         twohop_it = avl_next_element_safe(&_current.link->_2hop, twohop_it, _link_node);
914         if (twohop_it != NULL && !twohop_it->_link_node.follower) {
915           twohop_it = NULL;
916         }
917
918         nhdp_db_link_2hop_remove(twohop);
919       }
920     }
921   }
922
923   /* Section 12.5.4: update link */
924   if (_current.link_heard) {
925     /* Section 12.5.4.1.1: we have been heard, so the link is symmetric */
926     nhdp_db_link_set_symtime(_current.link, _current.vtime);
927
928     OONF_DEBUG(LOG_NHDP_R, "Reset link timer for link to %s to %" PRIu64,
929         netaddr_to_string(&nbuf, &_current.link->if_addr), _current.vtime);
930   }
931   else if (_current.link_lost) {
932     /* Section 12.5.4.1.2 */
933     if (oonf_timer_is_active(&_current.link->sym_time)) {
934       OONF_DEBUG(LOG_NHDP_R, "Stop link timer for link to %s",
935           netaddr_to_string(&nbuf, &_current.link->if_addr));
936
937       oonf_timer_stop(&_current.link->sym_time);
938
939       /*
940        * the stop timer might have modified to link status, but do not trigger
941        * cleanup until this processing is over
942        */
943       if (_nhdp_db_link_calculate_status(_current.link)== RFC6130_LINKSTATUS_HEARD) {
944         nhdp_db_link_set_vtime(_current.link, _current.localif->l_hold_time);
945       }
946     }
947   }
948
949   /* Section 12.5.4.3 */
950   t = oonf_timer_get_due(&_current.link->sym_time);
951   if (!oonf_timer_is_active(&_current.link->sym_time) || t < _current.vtime) {
952     t = _current.vtime;
953   }
954   oonf_timer_set(&_current.link->heard_time, t);
955
956   /* Section 12.5.4.4: link status pending is not influenced by the code above */
957   if (_current.link->status != NHDP_LINK_PENDING) {
958     t += _current.localif->l_hold_time;
959   }
960
961   /* Section 12.5.4.5 */
962   if (!oonf_timer_is_active(&_current.link->vtime)
963       || (int64_t)t > oonf_timer_get_due(&_current.link->vtime)) {
964     oonf_timer_set(&_current.link->vtime, t);
965   }
966
967   /* overwrite originator of neighbor entry */
968   nhdp_db_neighbor_set_originator(_current.neighbor, &context->orig_addr);
969
970   /* copy willingness to permanent storage */
971   nhdp_domain_store_willingness(_current.link);
972
973   /* update ip flooding settings */
974   nhdp_interface_update_status(_current.localif);
975
976   /* update link status */
977   nhdp_db_link_update_status(_current.link);
978
979   /* update link metrics and MPR */
980   nhdp_domain_recalculate_metrics(NULL, _current.neighbor);
981   nhdp_domain_delayed_mpr_recalculation(NULL, _current.neighbor);
982
983   return RFC5444_OKAY;
984 }