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.
39 * $Id: process_package.c,v 1.50 2007/11/29 23:40:08 bernd67 Exp $
42 #include "process_package.h"
45 #include "lq_packet.h"
46 #include "hysteresis.h"
47 #include "two_hop_neighbor_table.h"
49 #include "mpr_selector_set.h"
53 #include "duplicate_set.h"
54 #include "rebuild_packet.h"
55 #include "scheduler.h"
60 static void process_message_neighbors(struct neighbor_entry *, const struct hello_message *);
62 static void linking_this_2_entries(struct neighbor_entry *, struct neighbor_2_entry *, float);
64 static int lookup_mpr_status(const struct hello_message *, const struct interface *);
68 *Processes an list of neighbors from an incoming HELLO message.
69 *@param neighbor the neighbor who sent the message.
70 *@param message the HELLO message
74 process_message_neighbors(struct neighbor_entry *neighbor, const struct hello_message *message)
76 struct hello_neighbor *message_neighbors;
78 for(message_neighbors = message->neighbors;
79 message_neighbors != NULL;
80 message_neighbors = message_neighbors->next)
82 #if !defined(NODEBUG) && defined(DEBUG)
83 struct ipaddr_str buf;
85 union olsr_ip_addr *neigh_addr;
86 struct neighbor_2_entry *two_hop_neighbor;
90 *so that we don't add ourselves to the
94 if(if_ifwithaddr(&message_neighbors->address) != NULL)
97 /* Get the main address */
98 neigh_addr = mid_lookup_main_addr(&message_neighbors->address);
100 if (neigh_addr != NULL) {
101 message_neighbors->address = *neigh_addr;
104 if(((message_neighbors->status == SYM_NEIGH) ||
105 (message_neighbors->status == MPR_NEIGH)))
107 struct neighbor_2_list_entry *two_hop_neighbor_yet =
108 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
110 OLSR_PRINTF(7, "\tProcessing %s\n", olsr_ip_to_string(&buf, &message_neighbors->address));
112 if (two_hop_neighbor_yet != NULL)
114 /* Updating the holding time for this neighbor */
115 two_hop_neighbor_yet->neighbor_2_timer = GET_TIMESTAMP(message->vtime*1000);
116 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
118 // For link quality OLSR, reset the path link quality here.
119 // The path link quality will be calculated in the second pass, below.
120 // Keep the saved_path_link_quality for reference.
122 if (olsr_cnf->lq_level > 0)
124 // loop through the one-hop neighbors that see this
125 // 'two_hop_neighbor'
127 struct neighbor_list_entry *walker;
129 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
130 walker != &two_hop_neighbor->neighbor_2_nblist;
131 walker = walker->next)
133 // have we found the one-hop neighbor that sent the
134 // HELLO message that we're current processing?
136 if (walker->neighbor == neighbor)
138 walker->path_link_quality = 0.0;
146 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
147 if (two_hop_neighbor == NULL)
151 "Adding 2 hop neighbor %s\n\n",
152 olsr_ip_to_string(&buf, &message_neighbors->address));
154 changes_neighborhood = OLSR_TRUE;
155 changes_topology = OLSR_TRUE;
158 olsr_malloc(sizeof(struct neighbor_2_entry), "Process HELLO");
160 two_hop_neighbor->neighbor_2_nblist.next =
161 &two_hop_neighbor->neighbor_2_nblist;
163 two_hop_neighbor->neighbor_2_nblist.prev =
164 &two_hop_neighbor->neighbor_2_nblist;
166 two_hop_neighbor->neighbor_2_pointer = 0;
168 two_hop_neighbor->neighbor_2_addr = message_neighbors->address;
170 olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
172 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
177 linking to this two_hop_neighbor entry
179 changes_neighborhood = OLSR_TRUE;
180 changes_topology = OLSR_TRUE;
182 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
188 // Separate, second and third pass for link quality OLSR
190 if (olsr_cnf->lq_level > 0)
192 struct link_entry *lnk =
193 get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
198 // Second pass for link quality OLSR: calculate the best 2-hop
199 // path costs to all the 2-hop neighbors indicated in the
200 // HELLO message. Since the same 2-hop neighbor may be listed
201 // more than once in the same HELLO message (each at a possibly
202 // different quality) we want to select only the best one, not just
203 // the last one listed in the HELLO message.
205 for(message_neighbors = message->neighbors;
206 message_neighbors != NULL;
207 message_neighbors = message_neighbors->next)
209 if(if_ifwithaddr(&message_neighbors->address) != NULL)
212 if(((message_neighbors->status == SYM_NEIGH) ||
213 (message_neighbors->status == MPR_NEIGH)))
215 struct neighbor_list_entry *walker;
216 struct neighbor_2_entry *two_hop_neighbor;
217 struct neighbor_2_list_entry *two_hop_neighbor_yet =
218 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
220 if(!two_hop_neighbor_yet)
223 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
225 // loop through the one-hop neighbors that see this
226 // 'two_hop_neighbor'
228 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
229 walker != &two_hop_neighbor->neighbor_2_nblist;
230 walker = walker->next)
232 // have we found the one-hop neighbor that sent the
233 // HELLO message that we're current processing?
235 if (walker->neighbor == neighbor)
237 double new_second_hop_link_quality, new_path_link_quality;
239 // path link quality = link quality between us
240 // and our one-hop neighbor x link quality between
241 // our one-hop neighbor and the two-hop neighbor
243 // let's compare this to ETX:
245 // 1 / LQ1 + 1 / LQ2 < 1 / LQ3 + 1 / LQ4 <=>
246 // LQ1 * LQ2 > LQ3 * LQ4
248 // so comparing path link quality values with ">" is
249 // equivalent to comparing ETX values with "<"
251 // the link quality between the 1-hop neighbour and the
254 new_second_hop_link_quality =
255 message_neighbors->link_quality *
256 message_neighbors->neigh_link_quality;
258 // the total quality for the route
259 // "us --- 1-hop --- 2-hop"
261 new_path_link_quality =
262 new_second_hop_link_quality *
263 lnk->loss_link_quality * lnk->neigh_link_quality;
265 // Only copy the link quality if it is better than what we have
266 // for this 2-hop neighbor
267 if (new_path_link_quality > walker->path_link_quality)
269 walker->second_hop_link_quality = new_second_hop_link_quality;
270 walker->path_link_quality = new_path_link_quality;
277 // Third pass for link quality OLSR: check if the 2-hop path qualities have
278 // actually changed. If so, signal this through the 'changes_neighborhood'
279 // and 'changes_topology' booleans. Keep a 'saved_path_link_quality' for
281 for(message_neighbors = message->neighbors;
282 message_neighbors != NULL;
283 message_neighbors = message_neighbors->next)
285 if(if_ifwithaddr(&message_neighbors->address) != NULL)
288 if(((message_neighbors->status == SYM_NEIGH) ||
289 (message_neighbors->status == MPR_NEIGH)))
291 struct neighbor_list_entry *walker;
292 struct neighbor_2_entry *two_hop_neighbor;
293 struct neighbor_2_list_entry *two_hop_neighbor_yet =
294 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
296 if(!two_hop_neighbor_yet)
299 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
301 // loop through the one-hop neighbors that see this
302 // 'two_hop_neighbor'
304 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
305 walker != &two_hop_neighbor->neighbor_2_nblist;
306 walker = walker->next)
308 // have we found the one-hop neighbor that sent the
309 // HELLO message that we're current processing?
311 if (walker->neighbor == neighbor)
313 double saved_lq, rel_lq;
315 // saved previous total link quality
317 saved_lq = walker->saved_path_link_quality;
322 // if the link cost has changed by more than 10
325 rel_lq = walker->path_link_quality / saved_lq;
327 if (rel_lq > 1.1 || rel_lq < 0.9)
329 walker->saved_path_link_quality =
330 walker->path_link_quality;
332 if (olsr_cnf->lq_dlimit > 0)
334 changes_neighborhood = OLSR_TRUE;
335 changes_topology = OLSR_TRUE;
339 OLSR_PRINTF(3, "Skipping Dijkstra (3)\n");
349 *Links a one-hop neighbor with a 2-hop neighbor.
351 *@param neighbor the 1-hop neighbor
352 *@param two_hop_neighbor the 2-hop neighbor
356 linking_this_2_entries(struct neighbor_entry *neighbor, struct neighbor_2_entry *two_hop_neighbor, float vtime)
358 struct neighbor_list_entry *list_of_1_neighbors = olsr_malloc(sizeof(struct neighbor_list_entry), "Link entries 1");
359 struct neighbor_2_list_entry *list_of_2_neighbors = olsr_malloc(sizeof(struct neighbor_2_list_entry), "Link entries 2");
361 list_of_1_neighbors->neighbor = neighbor;
363 list_of_1_neighbors->path_link_quality = 0.0;
364 list_of_1_neighbors->saved_path_link_quality = 0.0;
365 list_of_1_neighbors->second_hop_link_quality = 0.0;
368 two_hop_neighbor->neighbor_2_nblist.next->prev = list_of_1_neighbors;
369 list_of_1_neighbors->next = two_hop_neighbor->neighbor_2_nblist.next;
371 two_hop_neighbor->neighbor_2_nblist.next = list_of_1_neighbors;
372 list_of_1_neighbors->prev = &two_hop_neighbor->neighbor_2_nblist;
373 list_of_2_neighbors->neighbor_2 = two_hop_neighbor;
375 list_of_2_neighbors->neighbor_2_timer = GET_TIMESTAMP(vtime*1000);
378 neighbor->neighbor_2_list.next->prev = list_of_2_neighbors;
379 list_of_2_neighbors->next = neighbor->neighbor_2_list.next;
380 neighbor->neighbor_2_list.next = list_of_2_neighbors;
381 list_of_2_neighbors->prev = &neighbor->neighbor_2_list;
383 /*increment the pointer counter*/
384 two_hop_neighbor->neighbor_2_pointer++;
388 *Check if a hello message states this node as a MPR.
390 *@param message the message to check
391 *@param n_link the buffer to put the link status in
392 *@param n_status the buffer to put the status in
394 *@return 1 if we are selected as MPR 0 if not
397 lookup_mpr_status(const struct hello_message *message, const struct interface *in_if)
399 struct hello_neighbor *neighbors;
400 for (neighbors = message->neighbors; neighbors != NULL; neighbors = neighbors->next) {
401 //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&buf, &neighbors->address));
402 //printf("against %s\n",olsr_ip_to_string(&buf, &main_addr));
404 if (olsr_cnf->ip_version == AF_INET
405 ? /* IPv4 */ ip4equal(&neighbors->address.v4, &in_if->ip_addr.v4)
406 : /* IPv6 */ ip6equal(&neighbors->address.v6, &in_if->int6_addr.sin6_addr)) {
408 if (neighbors->link == SYM_LINK && neighbors->status == MPR_NEIGH) {
420 *Initializing the parser functions we are using
423 olsr_init_package_process(void)
425 if (olsr_cnf->lq_level == 0)
427 olsr_parser_add_function(&olsr_process_received_hello, HELLO_MESSAGE, 1);
428 olsr_parser_add_function(&olsr_input_tc, TC_MESSAGE, 1);
432 olsr_parser_add_function(&olsr_input_lq_hello, LQ_HELLO_MESSAGE, 1);
433 olsr_parser_add_function(&olsr_input_tc, LQ_TC_MESSAGE, 1);
436 olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
437 olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
441 olsr_hello_tap(struct hello_message *message,
442 struct interface *in_if,
443 const union olsr_ip_addr *from_addr)
445 struct neighbor_entry *neighbor;
450 struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
452 if (olsr_cnf->lq_level > 0)
456 struct hello_neighbor *walker;
457 // just in case our neighbor has changed its HELLO interval
458 olsr_update_packet_loss_hello_int(lnk, message->htime);
460 // find the input interface in the list of neighbor interfaces
462 for (walker = message->neighbors; walker != NULL; walker = walker->next)
463 if (ipequal(&walker->address, &in_if->ip_addr))
466 // the current reference link quality
468 saved_lq = lnk->saved_neigh_link_quality;
473 // memorize our neighbour's idea of the link quality, so that we
474 // know the link quality in both directions
477 lnk->neigh_link_quality = walker->link_quality;
480 lnk->neigh_link_quality = 0.0;
482 // if the link quality has changed by more than 10 percent,
483 // print the new link quality table
485 rel_lq = lnk->neigh_link_quality / saved_lq;
487 if (rel_lq > 1.1 || rel_lq < 0.9)
489 lnk->saved_neigh_link_quality = lnk->neigh_link_quality;
491 if (olsr_cnf->lq_dlimit > 0)
493 changes_neighborhood = OLSR_TRUE;
494 changes_topology = OLSR_TRUE;
498 OLSR_PRINTF(3, "Skipping Dijkstra (2)\n");
502 // XXX - we should check whether we actually
503 // announce this neighbour
505 signal_link_changes(OLSR_TRUE);
509 neighbor = lnk->neighbor;
514 if(olsr_cnf->use_hysteresis)
516 /* Update HELLO timeout */
517 //printf("MESSAGE HTIME: %f\n", message->htime);
518 olsr_update_hysteresis_hello(lnk, message->htime);
521 /* Check if we are chosen as MPR */
522 if(lookup_mpr_status(message, in_if))
523 /* source_addr is always the main addr of a node! */
524 olsr_update_mprs_set(&message->source_addr, message->vtime);
528 /* Check willingness */
529 if(neighbor->willingness != message->willingness)
532 struct ipaddr_str buf;
534 OLSR_PRINTF(1, "Willingness for %s changed from %d to %d - UPDATING\n",
535 olsr_ip_to_string(&buf, &neighbor->neighbor_main_addr),
536 neighbor->willingness,
537 message->willingness);
539 *If willingness changed - recalculate
541 neighbor->willingness = message->willingness;
542 changes_neighborhood = OLSR_TRUE;
543 changes_topology = OLSR_TRUE;
547 /* Don't register neighbors of neighbors that announces WILL_NEVER */
548 if(neighbor->willingness != WILL_NEVER)
549 process_message_neighbors(neighbor, message);
551 /* Process changes immedeatly in case of MPR updates */
552 olsr_process_changes();
554 olsr_free_hello_packet(message);
560 *Processes a received HELLO message.
562 *@param m the incoming OLSR message
567 olsr_process_received_hello(union olsr_message *m,
568 struct interface *in_if,
569 union olsr_ip_addr *from_addr)
571 struct hello_message message;
573 hello_chgestruct(&message, m);
575 if(!olsr_validate_address(&message.source_addr))
577 olsr_free_hello_packet(&message);
581 olsr_hello_tap(&message, in_if, from_addr);
585 *Process a received(and parsed) MID message
586 *For every address check if there is a topology node
587 *registered with it and update its addresses.
589 *@param m the OLSR message received.
590 *@return 1 on success
594 olsr_process_received_mid(union olsr_message *m,
595 struct interface *in_if,
596 union olsr_ip_addr *from_addr)
598 #if !defined(NODEBUG) && defined(DEBUG)
599 struct ipaddr_str buf;
601 struct mid_alias *tmp_adr;
602 struct mid_message message;
604 mid_chgestruct(&message, m);
606 if (!olsr_validate_address(&message.mid_origaddr)) {
607 olsr_free_mid_packet(&message);
611 if (olsr_check_dup_table_proc(&message.mid_origaddr,
612 message.mid_seqno)) {
615 OLSR_PRINTF(5, "Processing MID from %s...\n", olsr_ip_to_string(&buf, &message.mid_origaddr));
617 tmp_adr = message.mid_addr;
620 * If the sender interface (NB: not originator) of this message
621 * is not in the symmetric 1-hop neighborhood of this node, the
622 * message MUST be discarded.
625 if(check_neighbor_link(from_addr) != SYM_LINK) {
627 struct ipaddr_str buf;
629 OLSR_PRINTF(2, "Received MID from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
630 olsr_free_mid_packet(&message);
634 /* Update the timeout of the MID */
635 olsr_update_mid_table(&message.mid_origaddr, (float)message.vtime);
638 if (!mid_lookup_main_addr(&tmp_adr->alias_addr)){
640 struct ipaddr_str buf;
642 OLSR_PRINTF(1, "MID new: (%s, ", olsr_ip_to_string(&buf, &message.mid_origaddr));
643 OLSR_PRINTF(1, "%s)\n", olsr_ip_to_string(&buf, &tmp_adr->alias_addr));
644 insert_mid_alias(&message.mid_origaddr, &tmp_adr->alias_addr, (float)message.vtime);
646 tmp_adr = tmp_adr->next;
649 olsr_prune_aliases(&message.mid_origaddr, message.mid_addr);
652 olsr_forward_message(m,
653 &message.mid_origaddr,
657 olsr_free_mid_packet(&message);
662 *Process incoming HNA message.
663 *Forwards the message if that is to be done.
665 *@param m the incoming OLSR message
667 *@return 1 on success
671 olsr_process_received_hna(union olsr_message *m,
672 struct interface *in_if,
673 union olsr_ip_addr *from_addr)
676 olsr_u8_t olsr_msgtype;
678 olsr_u16_t olsr_msgsize;
679 union olsr_ip_addr originator;
680 //olsr_u8_t ttl; unused
682 olsr_u16_t packet_seq_number;
685 const olsr_u8_t *curr, *curr_end;
688 OLSR_PRINTF(5, "Processing HNA\n");
691 /* Check if everyting is ok */
695 curr = (const olsr_u8_t *)m;
698 pkt_get_u8(&curr, &olsr_msgtype);
699 if (olsr_msgtype != HNA_MESSAGE) {
700 OLSR_PRINTF(0, "not a HNA message!\n");
704 pkt_get_double(&curr, &vtime);
707 pkt_get_u16(&curr, &olsr_msgsize);
708 hnasize = olsr_msgsize - (olsr_cnf->ip_version == AF_INET ? offsetof(struct olsrmsg, message) : offsetof(struct olsrmsg6, message));
710 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)));
713 if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
714 OLSR_PRINTF(0, "Illegal message size %d!\n", olsr_msgsize);
717 curr_end = (const olsr_u8_t *)m + olsr_msgsize;
719 /* validate originator */
720 pkt_get_ipaddress(&curr, &originator);
721 //printf("HNA from %s\n\n", olsr_ip_to_string(&buf, &originator));
722 if (!olsr_validate_address(&originator)) {
723 OLSR_PRINTF(0, "invalid address!\n");
728 pkt_ignore_u8(&curr);
731 pkt_get_u8(&curr, &hop_count);
734 pkt_get_u16(&curr, &packet_seq_number);
736 if (olsr_check_dup_table_proc(&originator, packet_seq_number)) {
738 * If the sender interface (NB: not originator) of this message
739 * is not in the symmetric 1-hop neighborhood of this node, the
740 * message MUST be discarded.
742 if (check_neighbor_link(from_addr) != SYM_LINK) {
744 struct ipaddr_str buf;
746 OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
750 while (curr < curr_end) {
751 union olsr_ip_addr net;
753 struct ip_prefix_list *entry;
755 pkt_get_ipaddress(&curr, &net);
756 pkt_get_prefixlen(&curr, &prefixlen);
757 entry = ip_prefix_list_find(olsr_cnf->hna_entries, &net, prefixlen);
759 /* only update if it's not from us */
760 olsr_update_hna_entry(&originator, &net, prefixlen, vtime);
763 /* Don't add an HNA entry that we are advertising ourselves. */
764 if (!ip_prefix_list_find(olsr_cnf->hna_entries, &hna_tmp->net, hna_tmp->prefixlen)) {
765 olsr_update_hna_entry(&message.originator, &hna_tmp->net, hna_tmp->prefixlen, message.vtime);
770 olsr_forward_message(m,