3 * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4 * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
46 #include "common/common_types.h"
47 #include "common/avl.h"
48 #include "common/netaddr.h"
49 #include "core/oonf_logging.h"
50 #include "core/oonf_subsystem.h"
51 #include "subsystems/oonf_duplicate_set.h"
52 #include "subsystems/oonf_rfc5444.h"
54 #include "nhdp/nhdp_domain.h"
56 #include "olsrv2/olsrv2.h"
57 #include "olsrv2/olsrv2_internal.h"
58 #include "olsrv2/olsrv2_originator.h"
59 #include "olsrv2/olsrv2_reader.h"
60 #include "olsrv2/olsrv2_routing.h"
61 #include "olsrv2/olsrv2_tc.h"
63 /* constants and definitions */
65 /* OLSRv2 message TLV array index */
74 /* OLSRv2 address TLV array index pass 1 */
76 IDX_ADDRTLV_LINK_METRIC,
77 IDX_ADDRTLV_NBR_ADDR_TYPE,
79 IDX_ADDRTLV_SRC_PREFIX,
83 * session data during TC parsing
86 /*! pointer to tc node of current data */
87 struct olsrv2_tc_node *node;
89 /*! validity time of current data */
92 /*! true if current TC is not fragmented */
95 /*! MPR type value of current TC */
96 uint8_t mprtypes[NHDP_MAXIMUM_DOMAINS];
98 /*! number of entries in MPR type value */
101 /*! true if a change happened for this domain */
102 bool changed[NHDP_MAXIMUM_DOMAINS];
106 static enum rfc5444_result
107 _cb_messagetlvs(struct rfc5444_reader_tlvblock_context *context);
109 static enum rfc5444_result
110 _cb_addresstlvs(struct rfc5444_reader_tlvblock_context *context);
111 static void _handle_gateways(struct rfc5444_reader_tlvblock_entry *tlv,
112 struct os_route_key *ssprefix, const uint32_t *cost_out,
113 const struct netaddr *addr);
114 static enum rfc5444_result _cb_messagetlvs_end(
115 struct rfc5444_reader_tlvblock_context *context, bool dropped);
117 /* definition of the RFC5444 reader components */
118 static struct rfc5444_reader_tlvblock_consumer _olsrv2_message_consumer = {
119 .order = RFC5444_MAIN_PARSER_PRIORITY,
120 .msg_id = RFC7181_MSGTYPE_TC,
121 .block_callback = _cb_messagetlvs,
122 .end_callback = _cb_messagetlvs_end,
125 static struct rfc5444_reader_tlvblock_consumer_entry _olsrv2_message_tlvs[] = {
126 [IDX_TLV_ITIME] = { .type = RFC5497_MSGTLV_INTERVAL_TIME, .type_ext = 0, .match_type_ext = true,
127 .min_length = 1, .max_length = 511, .match_length = true },
128 [IDX_TLV_VTIME] = { .type = RFC5497_MSGTLV_VALIDITY_TIME, .type_ext = 0, .match_type_ext = true,
129 .mandatory = true, .min_length = 1, .max_length = 511, .match_length = true },
130 [IDX_TLV_CONT_SEQ_NUM] = { .type = RFC7181_MSGTLV_CONT_SEQ_NUM,
131 .mandatory = true, .min_length = 2, .max_length = 65535, .match_length = true },
132 [IDX_TLV_MPRTYPES] = { .type = RFC7722_MSGTLV_MPR_TYPES,
133 .type_ext = RFC7722_MSGTLV_MPR_TYPES_EXT, .match_type_ext = true,
134 .min_length = 1, .max_length = NHDP_MAXIMUM_DOMAINS, .match_length = true },
135 [IDX_TLV_SSR] = { .type = DRAFT_SSR_MSGTLV_CAPABILITY,
136 .type_ext = DRAFT_SSR_MSGTLV_CAPABILITY_EXT, .match_type_ext = true },
139 static struct rfc5444_reader_tlvblock_consumer _olsrv2_address_consumer = {
140 .order = RFC5444_MAIN_PARSER_PRIORITY,
141 .msg_id = RFC7181_MSGTYPE_TC,
142 .addrblock_consumer = true,
143 .block_callback = _cb_addresstlvs,
146 static struct rfc5444_reader_tlvblock_consumer_entry _olsrv2_address_tlvs[] = {
147 [IDX_ADDRTLV_LINK_METRIC] = { .type = RFC7181_ADDRTLV_LINK_METRIC,
148 .min_length = 2, .max_length = 65535, .match_length = true },
149 [IDX_ADDRTLV_NBR_ADDR_TYPE] = { .type = RFC7181_ADDRTLV_NBR_ADDR_TYPE,
150 .min_length = 1, .max_length = 65535, .match_length = true },
151 [IDX_ADDRTLV_GATEWAY] = { .type = RFC7181_ADDRTLV_GATEWAY,
152 .min_length = 1, .max_length = 65535, .match_length = true },
153 [IDX_ADDRTLV_SRC_PREFIX] = { .type = SRCSPEC_GW_ADDRTLV_SRC_PREFIX,
154 .min_length = 1, .max_length = 17, .match_length = true },
157 /* nhdp multiplexer/protocol */
158 static struct oonf_rfc5444_protocol *_protocol = NULL;
160 static struct _olsrv2_data _current;
163 * Initialize olsrv2 reader
164 * @param p RFC5444 protocol instance
167 olsrv2_reader_init(struct oonf_rfc5444_protocol *p) {
170 rfc5444_reader_add_message_consumer(
171 &_protocol->reader, &_olsrv2_message_consumer,
172 _olsrv2_message_tlvs, ARRAYSIZE(_olsrv2_message_tlvs));
173 rfc5444_reader_add_message_consumer(
174 &_protocol->reader, &_olsrv2_address_consumer,
175 _olsrv2_address_tlvs, ARRAYSIZE(_olsrv2_address_tlvs));
179 * Cleanup nhdp reader
182 olsrv2_reader_cleanup(void) {
183 rfc5444_reader_remove_message_consumer(
184 &_protocol->reader, &_olsrv2_address_consumer);
185 rfc5444_reader_remove_message_consumer(
186 &_protocol->reader, &_olsrv2_message_consumer);
190 * Callback that parses message TLVs of TC
191 * @param context RFC5444 tlvblock reader context
192 * @return see rfc5444_result enum
194 static enum rfc5444_result
195 _cb_messagetlvs(struct rfc5444_reader_tlvblock_context *context) {
200 #ifdef OONF_LOG_DEBUG_INFO
201 struct netaddr_str buf;
205 * First remove all old session data.
206 * Do not put anything that could drop a session before this point,
207 * otherwise the cleanup path will run on an outdated session object.
209 memset(&_current, 0, sizeof(_current));
211 OONF_DEBUG(LOG_OLSRV2_R, "Received TC from %s",
212 netaddr_to_string(&buf, _protocol->input.src_address));
214 if (!context->has_origaddr || !context->has_hopcount
215 || !context->has_hoplimit || !context->has_seqno) {
216 OONF_DEBUG(LOG_OLSRV2_R, "Missing message flag");
217 return RFC5444_DROP_MESSAGE;
220 if (olsrv2_originator_is_local(&context->orig_addr)) {
221 OONF_DEBUG(LOG_OLSRV2_R, "We are hearing ourself");
222 return RFC5444_DROP_MESSAGE;
225 switch (context->addr_len) {
237 if (!oonf_rfc5444_is_interface_active(_protocol->input.interface, af_type)) {
238 OONF_DEBUG(LOG_OLSRV2_R, "We do not handle address length %u on interface %s",
239 context->addr_len, _protocol->input.interface->name);
240 return RFC5444_DROP_MESSAGE;
243 OONF_DEBUG(LOG_OLSRV2_R, "Originator: %s Seqno: %u",
244 netaddr_to_string(&buf, &context->orig_addr), context->seqno);
246 /* get cont_seq_num extension */
247 tmp = _olsrv2_message_tlvs[IDX_TLV_CONT_SEQ_NUM].type_ext;
248 if (tmp != RFC7181_CONT_SEQ_NUM_COMPLETE
249 && tmp != RFC7181_CONT_SEQ_NUM_INCOMPLETE) {
250 OONF_DEBUG(LOG_OLSRV2_R, "Illegal extension of CONT_SEQ_NUM TLV: %u",
252 return RFC5444_DROP_MESSAGE;
254 _current.complete_tc = tmp == RFC7181_CONT_SEQ_NUM_COMPLETE;
258 _olsrv2_message_tlvs[IDX_TLV_CONT_SEQ_NUM].tlv->single_value, 2);
261 /* get VTime/ITime */
262 tmp = rfc5497_timetlv_get_from_vector(
263 _olsrv2_message_tlvs[IDX_TLV_VTIME].tlv->single_value,
264 _olsrv2_message_tlvs[IDX_TLV_VTIME].tlv->length,
266 _current.vtime = rfc5497_timetlv_decode(tmp);
268 if (_olsrv2_message_tlvs[IDX_TLV_ITIME].tlv) {
269 tmp = rfc5497_timetlv_get_from_vector(
270 _olsrv2_message_tlvs[IDX_TLV_ITIME].tlv->single_value,
271 _olsrv2_message_tlvs[IDX_TLV_ITIME].tlv->length,
273 itime = rfc5497_timetlv_decode(tmp);
280 _current.mprtypes_size = nhdp_domain_process_mprtypes_tlv(
281 _current.mprtypes, sizeof(_current.mprtypes),
282 _olsrv2_message_tlvs[IDX_TLV_MPRTYPES].tlv);
284 /* test if we already forwarded the message */
285 if (!olsrv2_mpr_shall_forwarding(
286 context, _protocol->input.src_address, _current.vtime)) {
287 /* mark message as 'no forward */
288 rfc5444_reader_prevent_forwarding(context);
291 /* test if we already processed the message */
292 if (!olsrv2_mpr_shall_process(context, _current.vtime)) {
293 OONF_DEBUG(LOG_OLSRV2_R, "Processing set says 'do not process'");
294 return RFC5444_DROP_MSG_BUT_FORWARD;
298 _current.node = olsrv2_tc_node_add(
299 &context->orig_addr, _current.vtime, ansn);
300 if (_current.node == NULL) {
301 OONF_DEBUG(LOG_OLSRV2_R, "Cannot create node");
302 return RFC5444_DROP_MSG_BUT_FORWARD;
305 /* check if the topology information is recent enough */
306 if (_current.complete_tc) {
307 if (rfc5444_seqno_is_smaller(ansn, _current.node->ansn)) {
308 OONF_DEBUG(LOG_OLSRV2_R, "ANSN %u is smaller than last stored ANSN %u",
309 ansn, _current.node->ansn);
310 return RFC5444_DROP_MSG_BUT_FORWARD;
314 if (!rfc5444_seqno_is_larger(ansn, _current.node->ansn)) {
315 OONF_DEBUG(LOG_OLSRV2_R, "ANSN %u is smaller than last stored ANSN %u",
316 ansn, _current.node->ansn);
317 return RFC5444_DROP_MSG_BUT_FORWARD;
321 /* overwrite old ansn */
322 _current.node->ansn = ansn;
324 /* reset validity time and interval time */
325 oonf_timer_set(&_current.node->_validity_time, _current.vtime);
326 _current.node->interval_time = itime;
328 /* set source-specific flags */
329 _current.node->source_specific = _olsrv2_message_tlvs[IDX_TLV_SSR].tlv != NULL;
331 /* continue parsing the message */
336 * Callback that parses address TLVs of TC
337 * @param context RFC5444 tlvblock reader context
338 * @return see rfc5444_result enum
340 static enum rfc5444_result
341 _cb_addresstlvs(struct rfc5444_reader_tlvblock_context *context __attribute__((unused))) {
342 struct rfc5444_reader_tlvblock_entry *tlv;
343 struct nhdp_domain *domain;
344 struct olsrv2_tc_edge *edge;
345 struct olsrv2_tc_attachment *end;
346 uint32_t cost_in[NHDP_MAXIMUM_DOMAINS];
347 uint32_t cost_out[NHDP_MAXIMUM_DOMAINS];
348 struct rfc7181_metric_field metric_value;
350 struct os_route_key ssprefix;
352 #ifdef OONF_LOG_DEBUG_INFO
353 struct netaddr_str buf;
356 if (_current.node == NULL) {
360 for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
361 cost_in[i] = RFC7181_METRIC_INFINITE;
362 cost_out[i] = RFC7181_METRIC_INFINITE;
365 OONF_DEBUG(LOG_OLSRV2_R, "Found address in tc: %s",
366 netaddr_to_string(&buf, &context->addr));
368 os_routing_init_sourcespec_prefix(&ssprefix, &context->addr);
370 for (tlv = _olsrv2_address_tlvs[IDX_ADDRTLV_LINK_METRIC].tlv;
371 tlv; tlv = tlv->next_entry) {
372 domain = nhdp_domain_get_by_ext(tlv->type_ext);
373 if (domain == NULL) {
377 memcpy(&metric_value, tlv->single_value, sizeof(metric_value));
379 OONF_DEBUG(LOG_OLSRV2_R, "Metric for domain %d: 0x%02x%02x",
380 domain->index, metric_value.b[0], metric_value.b[1]);
382 if (rfc7181_metric_has_flag(&metric_value, RFC7181_LINKMETRIC_INCOMING_NEIGH)) {
383 cost_in[domain->index] = rfc7181_metric_decode(&metric_value);
384 OONF_DEBUG(LOG_OLSRV2_R, "Incoming metric: %d", cost_in[domain->index]);
387 if (rfc7181_metric_has_flag(&metric_value, RFC7181_LINKMETRIC_OUTGOING_NEIGH)) {
388 cost_out[domain->index] = rfc7181_metric_decode(&metric_value);
389 OONF_DEBUG(LOG_OLSRV2_R, "Outgoing metric: %d", cost_out[domain->index]);
393 if ((tlv = _olsrv2_address_tlvs[IDX_ADDRTLV_NBR_ADDR_TYPE].tlv)) {
394 /* parse originator neighbor */
395 if ((tlv->single_value[0] & RFC7181_NBR_ADDR_TYPE_ORIGINATOR) != 0) {
396 edge = olsrv2_tc_edge_add(_current.node, &context->addr);
398 OONF_DEBUG(LOG_OLSRV2_R, "Address is originator");
399 edge->ansn = _current.node->ansn;
401 for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
402 if (cost_out[i] <= RFC7181_METRIC_MAX) {
403 _current.changed[i] |= (edge->cost[i] != cost_out[i]);
404 edge->cost[i] = cost_out[i];
406 else if (_current.complete_tc) {
407 _current.changed[i] |= (edge->cost[i] != RFC7181_METRIC_INFINITE);
408 edge->cost[i] = RFC7181_METRIC_INFINITE;
410 if (edge->inverse->virtual && cost_in[i] <= RFC7181_METRIC_MAX) {
411 _current.changed[i] |= (edge->inverse->cost[i] != cost_in[i]);
412 edge->inverse->cost[i] = cost_in[i];
414 else if (edge->inverse->virtual && _current.complete_tc) {
415 _current.changed[i] |= (edge->inverse->cost[i] != RFC7181_METRIC_INFINITE);
416 edge->inverse->cost[i] = RFC7181_METRIC_INFINITE;
421 /* parse routable neighbor (which is not an originator) */
422 else if ((tlv->single_value[0] & RFC7181_NBR_ADDR_TYPE_ROUTABLE) != 0) {
423 end = olsrv2_tc_endpoint_add(_current.node, &ssprefix, true);
425 OONF_DEBUG(LOG_OLSRV2_R, "Address is routable, but not originator");
426 end->ansn = _current.node->ansn;
427 for (i=0; i< NHDP_MAXIMUM_DOMAINS; i++) {
428 if (cost_out[i] <= RFC7181_METRIC_MAX) {
429 _current.changed[i] |= (end->cost[i] != cost_out[i]);
430 end->cost[i] = cost_out[i];
432 else if (_current.complete_tc) {
433 _current.changed[i] |= (end->cost[i] != RFC7181_METRIC_INFINITE);
434 end->cost[i] = RFC7181_METRIC_INFINITE;
441 if ((tlv = _olsrv2_address_tlvs[IDX_ADDRTLV_GATEWAY].tlv)) {
442 _handle_gateways(tlv, &ssprefix, cost_out, &context->addr);
448 _handle_gateways(struct rfc5444_reader_tlvblock_entry *tlv,
449 struct os_route_key *ssprefix, const uint32_t *cost_out,
450 const struct netaddr *addr) {
451 struct olsrv2_tc_attachment *end;
452 struct nhdp_domain *domain;
456 if (tlv->length > 1 && tlv->length < _current.mprtypes_size) {
461 switch (tlv->type_ext) {
462 case RFC7181_DSTSPEC_GATEWAY:
463 case RFC7181_SRCSPEC_GATEWAY:
464 /* truncate address */
465 netaddr_truncate(&ssprefix->dst, &ssprefix->dst);
467 case RFC7181_SRCSPEC_DEF_GATEWAY:
468 os_routing_init_sourcespec_src_prefix(ssprefix, addr);
470 /* truncate address */
471 netaddr_truncate(&ssprefix->src, &ssprefix->src);
477 if (_olsrv2_address_tlvs[IDX_ADDRTLV_SRC_PREFIX].tlv) {
478 /* copy source specific prefix */
479 ssprefix->src._prefix_len = _olsrv2_address_tlvs[IDX_ADDRTLV_SRC_PREFIX].tlv->single_value[0];
480 memcpy(&ssprefix->src._addr[0],
481 &_olsrv2_address_tlvs[IDX_ADDRTLV_SRC_PREFIX].tlv->single_value[1],
482 _olsrv2_address_tlvs[IDX_ADDRTLV_SRC_PREFIX].tlv->length - 1);
485 /* parse attached network */
486 end = olsrv2_tc_endpoint_add(_current.node, ssprefix, false);
491 end->ansn = _current.node->ansn;
493 if (_current.complete_tc) {
494 /* clear unused metrics */
495 for (i=0; i<NHDP_MAXIMUM_DOMAINS; i++) {
496 end->cost[i] = RFC7181_METRIC_INFINITE;
500 /* use MT definition of AN tlv */
501 for (i=0; i<_current.mprtypes_size; i++) {
502 domain = nhdp_domain_get_by_ext(_current.mprtypes[i]);
508 end->cost[domain->index] = cost_out[domain->index];
510 if (tlv->length == 1) {
511 end->distance[domain->index] = tlv->single_value[0];
514 end->distance[domain->index] = tlv->single_value[i];
517 OONF_DEBUG(LOG_OLSRV2_R, "Address is Attached Network (domain %u): dist=%u",
518 domain->ext, end->distance[domain->index]);
523 * Callback that is called when message parsing of TLV is finished
524 * @param context tlv block reader context
525 * @param dropped true if context was dropped by a callback
526 * @return see rfc5444_result enum
528 static enum rfc5444_result
529 _cb_messagetlvs_end(struct rfc5444_reader_tlvblock_context *context __attribute__((unused)),
531 /* cleanup everything that is not the current ANSN, check for ss-prefixes */
532 struct olsrv2_tc_edge *edge, *edge_it;
533 struct olsrv2_tc_attachment *end, *end_it;
534 struct nhdp_domain *domain;
535 #ifdef OONF_LOG_DEBUG_INFO
536 struct netaddr_str nbuf1, nbuf2;
539 if (dropped || _current.node == NULL) {
543 avl_for_each_element_safe(&_current.node->_edges, edge, _node, edge_it) {
544 if (edge->ansn != _current.node->ansn) {
545 olsrv2_tc_edge_remove(edge);
549 avl_for_each_element_safe(&_current.node->_attached_networks, end, _src_node, end_it) {
550 if (end->ansn != _current.node->ansn) {
551 olsrv2_tc_endpoint_remove(end);
556 list_for_each_element(nhdp_domain_get_list(), domain, _node) {
557 _current.node->ss_attached_networks[domain->index] = false;
559 OONF_DEBUG(LOG_OLSRV2_R, "Look for source-specific attachents of %s:",
560 netaddr_to_string(&nbuf1, &_current.node->target.prefix.dst));
561 avl_for_each_element_safe(&_current.node->_attached_networks, end, _src_node, end_it) {
562 OONF_DEBUG(LOG_OLSRV2_R, " attachent [%s]/[%s]: %x / %u",
563 netaddr_to_string(&nbuf1, &end->dst->target.prefix.dst),
564 netaddr_to_string(&nbuf2, &end->dst->target.prefix.src),
565 end->cost[domain->index], netaddr_get_prefix_length(&end->dst->target.prefix.src));
567 if (end->cost[domain->index] <= RFC7181_METRIC_MAX
568 && netaddr_get_prefix_length(&end->dst->target.prefix.src) > 0) {
569 _current.node->ss_attached_networks[domain->index] = true;
575 olsrv2_tc_trigger_change(_current.node);
576 _current.node = NULL;
578 list_for_each_element(nhdp_domain_get_list(), domain, _node) {
579 if (_current.changed[domain->index]) {
580 olsrv2_routing_domain_changed(domain);