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 *, olsr_reltime);
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)
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, 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;
125 * For link quality OLSR, reset the path link quality here.
126 * The path link quality will be calculated in the second pass, below.
127 * Keep the saved_path_link_quality for reference.
130 if (olsr_cnf->lq_level > 0)
133 * loop through the one-hop neighbors that see this
137 struct neighbor_list_entry *walker;
139 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
140 walker != &two_hop_neighbor->neighbor_2_nblist;
141 walker = walker->next)
144 * have we found the one-hop neighbor that sent the
145 * HELLO message that we're current processing?
148 if (walker->neighbor == neighbor)
150 walker->path_linkcost = LINK_COST_BROKEN;
158 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
159 if (two_hop_neighbor == NULL)
163 "Adding 2 hop neighbor %s\n\n",
164 olsr_ip_to_string(&buf, &message_neighbors->address));
166 changes_neighborhood = OLSR_TRUE;
167 changes_topology = OLSR_TRUE;
170 olsr_malloc(sizeof(struct neighbor_2_entry), "Process HELLO");
172 two_hop_neighbor->neighbor_2_nblist.next =
173 &two_hop_neighbor->neighbor_2_nblist;
175 two_hop_neighbor->neighbor_2_nblist.prev =
176 &two_hop_neighbor->neighbor_2_nblist;
178 two_hop_neighbor->neighbor_2_pointer = 0;
180 two_hop_neighbor->neighbor_2_addr = message_neighbors->address;
182 olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
184 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
189 linking to this two_hop_neighbor entry
191 changes_neighborhood = OLSR_TRUE;
192 changes_topology = OLSR_TRUE;
194 linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
200 /* Separate, second pass for link quality OLSR */
201 /* Separate, second and third pass for link quality OLSR */
203 if (olsr_cnf->lq_level > 0)
205 olsr_linkcost first_hop_pathcost;
206 struct link_entry *lnk =
207 get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
212 /* calculate first hop path quality */
213 first_hop_pathcost = lnk->linkcost;
215 * Second pass for link quality OLSR: calculate the best 2-hop
216 * path costs to all the 2-hop neighbors indicated in the
217 * HELLO message. Since the same 2-hop neighbor may be listed
218 * more than once in the same HELLO message (each at a possibly
219 * different quality) we want to select only the best one, not just
220 * the last one listed in the HELLO message.
223 for(message_neighbors = message->neighbors;
224 message_neighbors != NULL;
225 message_neighbors = message_neighbors->next)
227 if(if_ifwithaddr(&message_neighbors->address) != NULL)
230 if(((message_neighbors->status == SYM_NEIGH) ||
231 (message_neighbors->status == MPR_NEIGH)))
233 struct neighbor_list_entry *walker;
234 struct neighbor_2_entry *two_hop_neighbor;
235 struct neighbor_2_list_entry *two_hop_neighbor_yet =
236 olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
238 if(!two_hop_neighbor_yet)
241 two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
244 * loop through the one-hop neighbors that see this
248 for (walker = two_hop_neighbor->neighbor_2_nblist.next;
249 walker != &two_hop_neighbor->neighbor_2_nblist;
250 walker = walker->next)
253 * have we found the one-hop neighbor that sent the
254 * HELLO message that we're current processing?
257 if (walker->neighbor == neighbor)
259 olsr_linkcost new_second_hop_linkcost, new_path_linkcost;
261 // the link cost between the 1-hop neighbour and the
264 new_second_hop_linkcost = message_neighbors->cost;
266 // the total cost for the route
267 // "us --- 1-hop --- 2-hop"
270 first_hop_pathcost + new_second_hop_linkcost;
272 // Only copy the link quality if it is better than what we have
273 // for this 2-hop neighbor
274 if (new_path_linkcost < walker->path_linkcost)
276 walker->second_hop_linkcost = new_second_hop_linkcost;
277 walker->path_linkcost = new_path_linkcost;
279 if (olsr_is_relevant_costchange(new_path_linkcost, walker->saved_path_linkcost))
281 walker->saved_path_linkcost = new_path_linkcost;
283 if (olsr_cnf->lq_dlimit > 0)
285 changes_neighborhood = OLSR_TRUE;
286 changes_topology = OLSR_TRUE;
290 OLSR_PRINTF(3, "Skipping Dijkstra (3)\n");
301 *Links a one-hop neighbor with a 2-hop neighbor.
303 *@param neighbor the 1-hop neighbor
304 *@param two_hop_neighbor the 2-hop neighbor
308 linking_this_2_entries(struct neighbor_entry *neighbor, struct neighbor_2_entry *two_hop_neighbor, olsr_reltime vtime)
310 struct neighbor_list_entry *list_of_1_neighbors = olsr_malloc(sizeof(struct neighbor_list_entry), "Link entries 1");
311 struct neighbor_2_list_entry *list_of_2_neighbors = olsr_malloc(sizeof(struct neighbor_2_list_entry), "Link entries 2");
313 list_of_1_neighbors->neighbor = neighbor;
315 list_of_1_neighbors->path_linkcost = LINK_COST_BROKEN;
316 list_of_1_neighbors->saved_path_linkcost = LINK_COST_BROKEN;
317 list_of_1_neighbors->second_hop_linkcost = LINK_COST_BROKEN;
320 two_hop_neighbor->neighbor_2_nblist.next->prev = list_of_1_neighbors;
321 list_of_1_neighbors->next = two_hop_neighbor->neighbor_2_nblist.next;
323 two_hop_neighbor->neighbor_2_nblist.next = list_of_1_neighbors;
324 list_of_1_neighbors->prev = &two_hop_neighbor->neighbor_2_nblist;
325 list_of_2_neighbors->neighbor_2 = two_hop_neighbor;
326 list_of_2_neighbors->nbr2_nbr = neighbor; /* XXX refcount */
328 olsr_change_timer(list_of_2_neighbors->nbr2_list_timer, vtime,
329 OLSR_NBR2_LIST_JITTER, OLSR_TIMER_ONESHOT);
332 neighbor->neighbor_2_list.next->prev = list_of_2_neighbors;
333 list_of_2_neighbors->next = neighbor->neighbor_2_list.next;
334 neighbor->neighbor_2_list.next = list_of_2_neighbors;
335 list_of_2_neighbors->prev = &neighbor->neighbor_2_list;
337 /*increment the pointer counter*/
338 two_hop_neighbor->neighbor_2_pointer++;
342 * Check if a hello message states this node as a MPR.
344 * @param message the message to check
345 * @param n_link the buffer to put the link status in
347 *@return 1 if we are selected as MPR 0 if not
350 lookup_mpr_status(const struct hello_message *message,
351 const struct interface *in_if)
353 struct hello_neighbor *neighbors;
355 for (neighbors = message->neighbors; neighbors; neighbors = neighbors->next) {
356 if (olsr_cnf->ip_version == AF_INET
357 ? ip4equal(&neighbors->address.v4, &in_if->ip_addr.v4)
358 : ip6equal(&neighbors->address.v6, &in_if->int6_addr.sin6_addr)) {
360 if (neighbors->link == SYM_LINK && neighbors->status == MPR_NEIGH) {
370 static int deserialize_hello(struct hello_message *hello, const void *ser) {
371 const unsigned char *limit;
375 const unsigned char *curr = ser;
376 pkt_get_u8(&curr, &type);
377 if (type != HELLO_MESSAGE && type != LQ_HELLO_MESSAGE) {
378 /* No need to do anything more */
381 pkt_get_reltime(&curr, &hello->vtime);
382 pkt_get_u16(&curr, &size);
383 pkt_get_ipaddress(&curr, &hello->source_addr);
385 pkt_get_u8(&curr, &hello->ttl);
386 pkt_get_u8(&curr, &hello->hop_count);
387 pkt_get_u16(&curr, &hello->packet_seq_number);
388 pkt_ignore_u16(&curr);
390 pkt_get_reltime(&curr, &hello->htime);
391 pkt_get_u8(&curr, &hello->willingness);
393 hello->neighbors = NULL;
394 limit = ((const unsigned char *)ser) + size;
395 while (curr < limit) {
396 const struct lq_hello_info_header *info_head = (const struct lq_hello_info_header *)curr;
397 const unsigned char *limit2 = curr + ntohs(info_head->size);
399 curr = (const unsigned char *)(info_head + 1);
400 while (curr < limit2) {
401 struct hello_neighbor *neigh = olsr_malloc_hello_neighbor("HELLO deserialization");
402 pkt_get_ipaddress(&curr, &neigh->address);
404 if (type == LQ_HELLO_MESSAGE) {
405 olsr_deserialize_hello_lq_pair(&curr, neigh);
407 neigh->link = EXTRACT_LINK(info_head->link_code);
408 neigh->status = EXTRACT_STATUS(info_head->link_code);
410 neigh->next = hello->neighbors;
411 hello->neighbors = neigh;
417 void olsr_input_hello(union olsr_message *ser, struct interface *inif, union olsr_ip_addr *from) {
418 struct hello_message hello;
423 if (deserialize_hello(&hello, ser) != 0) {
426 olsr_hello_tap(&hello, inif, from);
430 *Initializing the parser functions we are using
433 olsr_init_package_process(void)
435 if (olsr_cnf->lq_level == 0)
437 olsr_parser_add_function(&olsr_input_hello, HELLO_MESSAGE, 1);
438 olsr_parser_add_function(&olsr_input_tc, TC_MESSAGE, 1);
442 olsr_parser_add_function(&olsr_input_hello, LQ_HELLO_MESSAGE, 1);
443 olsr_parser_add_function(&olsr_input_tc, LQ_TC_MESSAGE, 1);
446 olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
447 olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
451 olsr_hello_tap(struct hello_message *message,
452 struct interface *in_if,
453 const union olsr_ip_addr *from_addr)
455 struct neighbor_entry *neighbor;
460 struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
462 if (olsr_cnf->lq_level > 0)
464 struct hello_neighbor *walker;
465 /* just in case our neighbor has changed its HELLO interval */
466 olsr_update_packet_loss_hello_int(lnk, message->htime);
468 /* find the input interface in the list of neighbor interfaces */
469 for (walker = message->neighbors; walker != NULL; walker = walker->next)
470 if (ipequal(&walker->address, &in_if->ip_addr))
473 // memorize our neighbour's idea of the link quality, so that we
474 // know the link quality in both directions
475 olsr_memorize_foreign_hello_lq(lnk, walker);
477 /* update packet loss for link quality calculation */
478 olsr_update_packet_loss(lnk);
481 neighbor = lnk->neighbor;
486 if(olsr_cnf->use_hysteresis)
488 /* Update HELLO timeout */
489 /* printf("MESSAGE HTIME: %f\n", message->htime);*/
490 olsr_update_hysteresis_hello(lnk, message->htime);
493 /* Check if we are chosen as MPR */
494 if(lookup_mpr_status(message, in_if))
495 /* source_addr is always the main addr of a node! */
496 olsr_update_mprs_set(&message->source_addr, message->vtime);
500 /* Check willingness */
501 if(neighbor->willingness != message->willingness)
503 struct ipaddr_str buf;
504 OLSR_PRINTF(1, "Willingness for %s changed from %d to %d - UPDATING\n",
505 olsr_ip_to_string(&buf, &neighbor->neighbor_main_addr),
506 neighbor->willingness,
507 message->willingness);
509 *If willingness changed - recalculate
511 neighbor->willingness = message->willingness;
512 changes_neighborhood = OLSR_TRUE;
513 changes_topology = OLSR_TRUE;
517 /* Don't register neighbors of neighbors that announces WILL_NEVER */
518 if(neighbor->willingness != WILL_NEVER)
519 process_message_neighbors(neighbor, message);
521 /* Process changes immedeatly in case of MPR updates */
522 olsr_process_changes();
524 olsr_free_hello_packet(message);
530 *Process a received(and parsed) MID message
531 *For every address check if there is a topology node
532 *registered with it and update its addresses.
534 *@param m the OLSR message received.
535 *@return 1 on success
539 olsr_process_received_mid(union olsr_message *m,
540 struct interface *in_if __attribute__((unused)),
541 union olsr_ip_addr *from_addr)
544 struct ipaddr_str buf;
546 struct mid_alias *tmp_adr;
547 struct mid_message message;
549 mid_chgestruct(&message, m);
551 if (!olsr_validate_address(&message.mid_origaddr)) {
552 olsr_free_mid_packet(&message);
557 OLSR_PRINTF(5, "Processing MID from %s...\n", olsr_ip_to_string(&buf, &message.mid_origaddr));
559 tmp_adr = message.mid_addr;
562 * If the sender interface (NB: not originator) of this message
563 * is not in the symmetric 1-hop neighborhood of this node, the
564 * message MUST be discarded.
567 if(check_neighbor_link(from_addr) != SYM_LINK) {
568 struct ipaddr_str buf;
569 OLSR_PRINTF(2, "Received MID from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
570 olsr_free_mid_packet(&message);
574 /* Update the timeout of the MID */
575 olsr_update_mid_table(&message.mid_origaddr, message.vtime);
578 if (!mid_lookup_main_addr(&tmp_adr->alias_addr)){
579 struct ipaddr_str buf;
580 OLSR_PRINTF(1, "MID new: (%s, ", olsr_ip_to_string(&buf, &message.mid_origaddr));
581 OLSR_PRINTF(1, "%s)\n", olsr_ip_to_string(&buf, &tmp_adr->alias_addr));
582 insert_mid_alias(&message.mid_origaddr, &tmp_adr->alias_addr, message.vtime);
584 tmp_adr = tmp_adr->next;
587 olsr_prune_aliases(&message.mid_origaddr, message.mid_addr);
589 olsr_forward_message(m, from_addr);
590 olsr_free_mid_packet(&message);
595 *Process incoming HNA message.
596 *Forwards the message if that is to be done.
598 *@param m the incoming OLSR message
600 *@return 1 on success
604 olsr_process_received_hna(union olsr_message *m,
605 struct interface *in_if __attribute__((unused)),
606 union olsr_ip_addr *from_addr)
609 olsr_u8_t olsr_msgtype;
611 olsr_u16_t olsr_msgsize;
612 union olsr_ip_addr originator;
614 olsr_u16_t packet_seq_number;
617 const olsr_u8_t *curr, *curr_end;
620 OLSR_PRINTF(5, "Processing HNA\n");
623 /* Check if everyting is ok */
627 curr = (const olsr_u8_t *)m;
630 pkt_get_u8(&curr, &olsr_msgtype);
631 if (olsr_msgtype != HNA_MESSAGE) {
632 OLSR_PRINTF(0, "not a HNA message!\n");
636 pkt_get_reltime(&curr, &vtime);
639 pkt_get_u16(&curr, &olsr_msgsize);
640 hnasize = olsr_msgsize - (olsr_cnf->ip_version == AF_INET ? offsetof(struct olsrmsg, message) : offsetof(struct olsrmsg6, message));
642 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)));
645 if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
646 OLSR_PRINTF(0, "Illegal message size %d!\n", olsr_msgsize);
649 curr_end = (const olsr_u8_t *)m + olsr_msgsize;
651 /* validate originator */
652 pkt_get_ipaddress(&curr, &originator);
653 /*printf("HNA from %s\n\n", olsr_ip_to_string(&buf, &originator));*/
656 pkt_ignore_u8(&curr);
659 pkt_get_u8(&curr, &hop_count);
662 pkt_get_u16(&curr, &packet_seq_number);
665 * If the sender interface (NB: not originator) of this message
666 * is not in the symmetric 1-hop neighborhood of this node, the
667 * message MUST be discarded.
669 if (check_neighbor_link(from_addr) != SYM_LINK) {
670 struct ipaddr_str buf;
671 OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
675 while (curr < curr_end) {
676 union olsr_ip_addr net;
678 struct ip_prefix_list *entry;
680 pkt_get_ipaddress(&curr, &net);
681 pkt_get_prefixlen(&curr, &prefixlen);
682 entry = ip_prefix_list_find(olsr_cnf->hna_entries, &net, prefixlen);
684 /* only update if it's not from us */
685 olsr_update_hna_entry(&originator, &net, prefixlen, vtime);
690 /* Don't add an HNA entry that we are advertising ourselves. */
691 if (!ip_prefix_list_find(olsr_cnf->hna_entries, &hna_tmp->net, hna_tmp->prefixlen)) {
692 olsr_update_hna_entry(&message.originator, &hna_tmp->net, hna_tmp->prefixlen, message.vtime);
696 olsr_forward_message(m, from_addr);