2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of olsr.org, olsrd nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Visit http://www.olsr.org for more information.
35 * If you find this software useful feel free to make a donation
36 * to the project. For more information see the website or contact
37 * the copyright holders.
41 #include "process_package.h"
44 #include "lq_packet.h"
45 #include "hysteresis.h"
46 #include "two_hop_neighbor_table.h"
48 #include "mpr_selector_set.h"
52 #include "duplicate_set.h"
53 #include "rebuild_packet.h"
54 #include "scheduler.h"
56 #include "lq_plugin.h"
60 static void process_message_neighbors(struct neighbor_entry *,
61 const struct hello_message *);
63 static void linking_this_2_entries(struct neighbor_entry *,
64 struct neighbor_2_entry *, float);
66 static olsr_bool lookup_mpr_status(const struct hello_message *,
67 const struct interface *);
71 *Processes an list of neighbors from an incoming HELLO message.
72 *@param neighbor the neighbor who sent the message.
73 *@param message the HELLO message
77 process_message_neighbors(struct neighbor_entry *neighbor, const struct hello_message *message)
79 struct hello_neighbor *message_neighbors;
81 for(message_neighbors = message->neighbors;
82 message_neighbors != NULL;
83 message_neighbors = message_neighbors->next)
85 #if !defined(NODEBUG) && defined(DEBUG)
86 struct ipaddr_str buf;
88 union olsr_ip_addr *neigh_addr;
89 struct neighbor_2_entry *two_hop_neighbor;
93 *so that we don't add ourselves to the
97 if(if_ifwithaddr(&message_neighbors->address) != NULL)
100 /* Get the main address */
101 neigh_addr = mid_lookup_main_addr(&message_neighbors->address);
103 if (neigh_addr != NULL) {
104 message_neighbors->address = *neigh_addr;
107 if(((message_neighbors->status == SYM_NEIGH) ||
108 (message_neighbors->status == MPR_NEIGH)))
110 struct neighbor_2_list_entry *two_hop_neighbor_yet =
111 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
113 OLSR_PRINTF(7, "\tProcessing %s\n", olsr_ip_to_string(&buf, &message_neighbors->address));
115 if (two_hop_neighbor_yet != NULL)
117 /* Updating the holding time for this neighbor */
118 olsr_set_timer(&two_hop_neighbor_yet->nbr2_list_timer,
119 message->vtime * MSEC_PER_SEC, OLSR_NBR2_LIST_JITTER,
120 OLSR_TIMER_ONESHOT, &olsr_expire_nbr2_list,
121 two_hop_neighbor_yet, 0);
122 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
124 // For link quality OLSR, reset the path link quality here.
125 // The path link quality will be calculated in the second pass, below.
126 // Keep the saved_path_link_quality for reference.
128 if (olsr_cnf->lq_level > 0)
130 // loop through the one-hop neighbors that see this
131 // 'two_hop_neighbor'
133 struct neighbor_list_entry *walker;
135 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
136 walker != &two_hop_neighbor->neighbor_2_nblist;
137 walker = walker->next)
139 // have we found the one-hop neighbor that sent the
140 // HELLO message that we're current processing?
142 if (walker->neighbor == neighbor)
144 walker->path_linkcost = LINK_COST_BROKEN;
152 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
153 if (two_hop_neighbor == NULL)
157 "Adding 2 hop neighbor %s\n\n",
158 olsr_ip_to_string(&buf, &message_neighbors->address));
160 changes_neighborhood = OLSR_TRUE;
161 changes_topology = OLSR_TRUE;
164 olsr_malloc(sizeof(struct neighbor_2_entry), "Process HELLO");
166 two_hop_neighbor->neighbor_2_nblist.next =
167 &two_hop_neighbor->neighbor_2_nblist;
169 two_hop_neighbor->neighbor_2_nblist.prev =
170 &two_hop_neighbor->neighbor_2_nblist;
172 two_hop_neighbor->neighbor_2_pointer = 0;
174 two_hop_neighbor->neighbor_2_addr = message_neighbors->address;
176 olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
178 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
183 linking to this two_hop_neighbor entry
185 changes_neighborhood = OLSR_TRUE;
186 changes_topology = OLSR_TRUE;
188 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
194 // Separate, second pass for link quality OLSR
196 if (olsr_cnf->lq_level > 0)
198 olsr_linkcost first_hop_pathcost;
199 struct link_entry *lnk =
200 get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
205 // calculate first hop path quality
206 first_hop_pathcost = lnk->linkcost;
208 // Second pass for link quality OLSR: calculate the best 2-hop
209 // path costs to all the 2-hop neighbors indicated in the
210 // HELLO message. Since the same 2-hop neighbor may be listed
211 // more than once in the same HELLO message (each at a possibly
212 // different quality) we want to select only the best one, not just
213 // the last one listed in the HELLO message.
215 for(message_neighbors = message->neighbors;
216 message_neighbors != NULL;
217 message_neighbors = message_neighbors->next)
219 if(if_ifwithaddr(&message_neighbors->address) != NULL)
222 if(((message_neighbors->status == SYM_NEIGH) ||
223 (message_neighbors->status == MPR_NEIGH)))
225 struct neighbor_list_entry *walker;
226 struct neighbor_2_entry *two_hop_neighbor;
227 struct neighbor_2_list_entry *two_hop_neighbor_yet =
228 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
230 if(!two_hop_neighbor_yet)
233 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
235 // loop through the one-hop neighbors that see this
236 // 'two_hop_neighbor'
238 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
239 walker != &two_hop_neighbor->neighbor_2_nblist;
240 walker = walker->next)
242 // have we found the one-hop neighbor that sent the
243 // HELLO message that we're current processing?
245 if (walker->neighbor == neighbor)
247 olsr_linkcost new_second_hop_linkcost, new_path_linkcost;
249 // the link cost between the 1-hop neighbour and the
252 new_second_hop_linkcost = message_neighbors->cost;
254 // the total cost for the route
255 // "us --- 1-hop --- 2-hop"
258 first_hop_pathcost + new_second_hop_linkcost;
260 // Only copy the link quality if it is better than what we have
261 // for this 2-hop neighbor
262 if (new_path_linkcost < walker->path_linkcost)
264 walker->second_hop_linkcost = new_second_hop_linkcost;
265 walker->path_linkcost = new_path_linkcost;
267 if (olsr_is_relevant_costchange(new_path_linkcost, walker->saved_path_linkcost))
269 walker->saved_path_linkcost = new_path_linkcost;
271 if (olsr_cnf->lq_dlimit > 0)
273 changes_neighborhood = OLSR_TRUE;
274 changes_topology = OLSR_TRUE;
278 OLSR_PRINTF(3, "Skipping Dijkstra (3)\n");
289 *Links a one-hop neighbor with a 2-hop neighbor.
291 *@param neighbor the 1-hop neighbor
292 *@param two_hop_neighbor the 2-hop neighbor
296 linking_this_2_entries(struct neighbor_entry *neighbor, struct neighbor_2_entry *two_hop_neighbor, float vtime)
298 struct neighbor_list_entry *list_of_1_neighbors = olsr_malloc(sizeof(struct neighbor_list_entry), "Link entries 1");
299 struct neighbor_2_list_entry *list_of_2_neighbors = olsr_malloc(sizeof(struct neighbor_2_list_entry), "Link entries 2");
301 list_of_1_neighbors->neighbor = neighbor;
303 list_of_1_neighbors->path_linkcost = LINK_COST_BROKEN;
304 list_of_1_neighbors->saved_path_linkcost = LINK_COST_BROKEN;
305 list_of_1_neighbors->second_hop_linkcost = LINK_COST_BROKEN;
308 two_hop_neighbor->neighbor_2_nblist.next->prev = list_of_1_neighbors;
309 list_of_1_neighbors->next = two_hop_neighbor->neighbor_2_nblist.next;
311 two_hop_neighbor->neighbor_2_nblist.next = list_of_1_neighbors;
312 list_of_1_neighbors->prev = &two_hop_neighbor->neighbor_2_nblist;
313 list_of_2_neighbors->neighbor_2 = two_hop_neighbor;
314 list_of_2_neighbors->nbr2_nbr = neighbor; /* XXX refcount */
316 olsr_change_timer(list_of_2_neighbors->nbr2_list_timer, vtime * MSEC_PER_SEC,
317 OLSR_NBR2_LIST_JITTER, OLSR_TIMER_ONESHOT);
320 neighbor->neighbor_2_list.next->prev = list_of_2_neighbors;
321 list_of_2_neighbors->next = neighbor->neighbor_2_list.next;
322 neighbor->neighbor_2_list.next = list_of_2_neighbors;
323 list_of_2_neighbors->prev = &neighbor->neighbor_2_list;
325 /*increment the pointer counter*/
326 two_hop_neighbor->neighbor_2_pointer++;
330 * Check if a hello message states this node as a MPR.
332 * @param message the message to check
333 * @param n_link the buffer to put the link status in
335 *@return 1 if we are selected as MPR 0 if not
338 lookup_mpr_status(const struct hello_message *message,
339 const struct interface *in_if)
341 struct hello_neighbor *neighbors;
343 for (neighbors = message->neighbors; neighbors; neighbors = neighbors->next) {
344 if (olsr_cnf->ip_version == AF_INET
345 ? ip4equal(&neighbors->address.v4, &in_if->ip_addr.v4)
346 : ip6equal(&neighbors->address.v6, &in_if->int6_addr.sin6_addr)) {
348 if (neighbors->link == SYM_LINK && neighbors->status == MPR_NEIGH) {
358 static int deserialize_hello(struct hello_message *hello, const void *ser) {
359 const unsigned char *limit;
363 const unsigned char *curr = ser;
364 pkt_get_u8(&curr, &type);
365 if (type != HELLO_MESSAGE && type != LQ_HELLO_MESSAGE) {
366 /* No need to do anything more */
369 pkt_get_double(&curr, &hello->vtime);
370 pkt_get_u16(&curr, &size);
371 pkt_get_ipaddress(&curr, &hello->source_addr);
373 pkt_get_u8(&curr, &hello->ttl);
374 pkt_get_u8(&curr, &hello->hop_count);
375 pkt_get_u16(&curr, &hello->packet_seq_number);
376 pkt_ignore_u16(&curr);
378 pkt_get_double(&curr, &hello->htime);
379 pkt_get_u8(&curr, &hello->willingness);
381 hello->neighbors = NULL;
382 limit = ((const unsigned char *)ser) + size;
383 while (curr < limit) {
384 const struct lq_hello_info_header *info_head = (const struct lq_hello_info_header *)curr;
385 const unsigned char *limit2 = curr + ntohs(info_head->size);
387 curr = (const unsigned char *)(info_head + 1);
388 while (curr < limit2) {
389 struct hello_neighbor *neigh = olsr_malloc_hello_neighbor("HELLO deserialization");
390 pkt_get_ipaddress(&curr, &neigh->address);
392 if (type == LQ_HELLO_MESSAGE) {
393 olsr_deserialize_hello_lq_pair(&curr, neigh);
395 neigh->link = EXTRACT_LINK(info_head->link_code);
396 neigh->status = EXTRACT_STATUS(info_head->link_code);
398 neigh->next = hello->neighbors;
399 hello->neighbors = neigh;
405 void olsr_input_hello(union olsr_message *ser, struct interface *inif, union olsr_ip_addr *from) {
406 struct hello_message hello;
411 if (deserialize_hello(&hello, ser) != 0) {
414 olsr_hello_tap(&hello, inif, from);
418 *Initializing the parser functions we are using
421 olsr_init_package_process(void)
423 if (olsr_cnf->lq_level == 0)
425 olsr_parser_add_function(&olsr_input_hello, HELLO_MESSAGE, 1);
426 olsr_parser_add_function(&olsr_input_tc, TC_MESSAGE, 1);
430 olsr_parser_add_function(&olsr_input_hello, LQ_HELLO_MESSAGE, 1);
431 olsr_parser_add_function(&olsr_input_tc, LQ_TC_MESSAGE, 1);
434 olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
435 olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
439 olsr_hello_tap(struct hello_message *message,
440 struct interface *in_if,
441 const union olsr_ip_addr *from_addr)
443 struct neighbor_entry *neighbor;
448 struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
450 if (olsr_cnf->lq_level > 0)
452 struct hello_neighbor *walker;
453 // just in case our neighbor has changed its HELLO interval
454 olsr_update_packet_loss_hello_int(lnk, message->htime);
456 // find the input interface in the list of neighbor interfaces
457 for (walker = message->neighbors; walker != NULL; walker = walker->next)
458 if (ipequal(&walker->address, &in_if->ip_addr))
461 // memorize our neighbour's idea of the link quality, so that we
462 // know the link quality in both directions
463 olsr_memorize_foreign_hello_lq(lnk, walker);
465 // update packet loss for link quality calculation
466 olsr_update_packet_loss(lnk);
469 neighbor = lnk->neighbor;
474 if(olsr_cnf->use_hysteresis)
476 /* Update HELLO timeout */
477 //printf("MESSAGE HTIME: %f\n", message->htime);
478 olsr_update_hysteresis_hello(lnk, message->htime);
481 /* Check if we are chosen as MPR */
482 if(lookup_mpr_status(message, in_if))
483 /* source_addr is always the main addr of a node! */
484 olsr_update_mprs_set(&message->source_addr, message->vtime);
488 /* Check willingness */
489 if(neighbor->willingness != message->willingness)
492 struct ipaddr_str buf;
494 OLSR_PRINTF(1, "Willingness for %s changed from %d to %d - UPDATING\n",
495 olsr_ip_to_string(&buf, &neighbor->neighbor_main_addr),
496 neighbor->willingness,
497 message->willingness);
499 *If willingness changed - recalculate
501 neighbor->willingness = message->willingness;
502 changes_neighborhood = OLSR_TRUE;
503 changes_topology = OLSR_TRUE;
507 /* Don't register neighbors of neighbors that announces WILL_NEVER */
508 if(neighbor->willingness != WILL_NEVER)
509 process_message_neighbors(neighbor, message);
511 /* Process changes immedeatly in case of MPR updates */
512 olsr_process_changes();
514 olsr_free_hello_packet(message);
520 *Process a received(and parsed) MID message
521 *For every address check if there is a topology node
522 *registered with it and update its addresses.
524 *@param m the OLSR message received.
525 *@return 1 on success
529 olsr_process_received_mid(union olsr_message *m,
530 struct interface *in_if __attribute__((unused)),
531 union olsr_ip_addr *from_addr)
533 #if !defined(NODEBUG) && defined(DEBUG)
534 struct ipaddr_str buf;
536 struct mid_alias *tmp_adr;
537 struct mid_message message;
539 mid_chgestruct(&message, m);
541 if (!olsr_validate_address(&message.mid_origaddr)) {
542 olsr_free_mid_packet(&message);
547 OLSR_PRINTF(5, "Processing MID from %s...\n", olsr_ip_to_string(&buf, &message.mid_origaddr));
549 tmp_adr = message.mid_addr;
552 * If the sender interface (NB: not originator) of this message
553 * is not in the symmetric 1-hop neighborhood of this node, the
554 * message MUST be discarded.
557 if(check_neighbor_link(from_addr) != SYM_LINK) {
559 struct ipaddr_str buf;
561 OLSR_PRINTF(2, "Received MID from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
562 olsr_free_mid_packet(&message);
566 /* Update the timeout of the MID */
567 olsr_update_mid_table(&message.mid_origaddr, (float)message.vtime);
570 if (!mid_lookup_main_addr(&tmp_adr->alias_addr)){
572 struct ipaddr_str buf;
574 OLSR_PRINTF(1, "MID new: (%s, ", olsr_ip_to_string(&buf, &message.mid_origaddr));
575 OLSR_PRINTF(1, "%s)\n", olsr_ip_to_string(&buf, &tmp_adr->alias_addr));
576 insert_mid_alias(&message.mid_origaddr, &tmp_adr->alias_addr, (float)message.vtime);
578 tmp_adr = tmp_adr->next;
581 olsr_prune_aliases(&message.mid_origaddr, message.mid_addr);
583 olsr_forward_message(m, from_addr);
584 olsr_free_mid_packet(&message);
589 *Process incoming HNA message.
590 *Forwards the message if that is to be done.
592 *@param m the incoming OLSR message
594 *@return 1 on success
598 olsr_process_received_hna(union olsr_message *m,
599 struct interface *in_if __attribute__((unused)),
600 union olsr_ip_addr *from_addr)
603 olsr_u8_t olsr_msgtype;
605 olsr_u16_t olsr_msgsize;
606 union olsr_ip_addr originator;
607 //olsr_u8_t ttl; unused
609 olsr_u16_t packet_seq_number;
612 const olsr_u8_t *curr, *curr_end;
615 OLSR_PRINTF(5, "Processing HNA\n");
618 /* Check if everyting is ok */
622 curr = (const olsr_u8_t *)m;
625 pkt_get_u8(&curr, &olsr_msgtype);
626 if (olsr_msgtype != HNA_MESSAGE) {
627 OLSR_PRINTF(0, "not a HNA message!\n");
631 pkt_get_double(&curr, &vtime);
634 pkt_get_u16(&curr, &olsr_msgsize);
635 hnasize = olsr_msgsize - (olsr_cnf->ip_version == AF_INET ? offsetof(struct olsrmsg, message) : offsetof(struct olsrmsg6, message));
637 OLSR_PRINTF(0, "message size %d too small (at least %lu)!\n", olsr_msgsize, (unsigned long)(olsr_cnf->ip_version == AF_INET ? offsetof(struct olsrmsg, message) : offsetof(struct olsrmsg6, message)));
640 if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
641 OLSR_PRINTF(0, "Illegal message size %d!\n", olsr_msgsize);
644 curr_end = (const olsr_u8_t *)m + olsr_msgsize;
646 /* validate originator */
647 pkt_get_ipaddress(&curr, &originator);
648 //printf("HNA from %s\n\n", olsr_ip_to_string(&buf, &originator));
651 pkt_ignore_u8(&curr);
654 pkt_get_u8(&curr, &hop_count);
657 pkt_get_u16(&curr, &packet_seq_number);
660 * If the sender interface (NB: not originator) of this message
661 * is not in the symmetric 1-hop neighborhood of this node, the
662 * message MUST be discarded.
664 if (check_neighbor_link(from_addr) != SYM_LINK) {
666 struct ipaddr_str buf;
668 OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
672 while (curr < curr_end) {
673 union olsr_ip_addr net;
675 struct ip_prefix_list *entry;
677 pkt_get_ipaddress(&curr, &net);
678 pkt_get_prefixlen(&curr, &prefixlen);
679 entry = ip_prefix_list_find(olsr_cnf->hna_entries, &net, prefixlen);
681 /* only update if it's not from us */
682 olsr_update_hna_entry(&originator, &net, prefixlen, vtime);
687 /* Don't add an HNA entry that we are advertising ourselves. */
688 if (!ip_prefix_list_find(olsr_cnf->hna_entries, &hna_tmp->net, hna_tmp->prefixlen)) {
689 olsr_update_hna_entry(&message.originator, &hna_tmp->net, hna_tmp->prefixlen, message.vtime);
693 olsr_forward_message(m, from_addr);