0e8654cc58a45ef4fb84a14944812ed0723c8fd8
[olsrd.git] / src / process_package.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
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 
15  *   distribution.
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.
19  *
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.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
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.
38  *
39  * $Id: process_package.c,v 1.49 2007/11/29 23:03:07 bernd67 Exp $
40  */
41
42 #include "process_package.h"
43 #include "ipcalc.h"
44 #include "defs.h"
45 #include "lq_packet.h"
46 #include "hysteresis.h"
47 #include "two_hop_neighbor_table.h"
48 #include "tc_set.h"
49 #include "mpr_selector_set.h"
50 #include "mid_set.h"
51 #include "olsr.h"
52 #include "parser.h"
53 #include "duplicate_set.h"
54 #include "rebuild_packet.h"
55 #include "scheduler.h"
56 #include "net_olsr.h"
57
58 #include <stddef.h>
59
60 static void process_message_neighbors(struct neighbor_entry *, const struct hello_message *);
61
62 static void linking_this_2_entries(struct neighbor_entry *, struct neighbor_2_entry *, float);
63
64 static int lookup_mpr_status(const struct hello_message *, const struct interface *);
65
66
67 /**
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
71  *@return nada
72  */
73 static void
74 process_message_neighbors(struct neighbor_entry *neighbor, const struct hello_message *message)
75 {
76   struct hello_neighbor        *message_neighbors;
77
78   for(message_neighbors = message->neighbors;
79       message_neighbors != NULL;
80       message_neighbors = message_neighbors->next)
81     {
82 #if !defined(NODEBUG) && defined(DEBUG)
83       struct ipaddr_str buf;
84 #endif
85       union olsr_ip_addr      *neigh_addr;
86       struct neighbor_2_entry *two_hop_neighbor;
87
88       /*
89        *check all interfaces
90        *so that we don't add ourselves to the
91        *2 hop list
92        *IMPORTANT!
93        */
94       if(if_ifwithaddr(&message_neighbors->address) != NULL)
95         continue;
96
97       /* Get the main address */
98       neigh_addr = mid_lookup_main_addr(&message_neighbors->address);
99
100       if (neigh_addr != NULL) {
101         message_neighbors->address = *neigh_addr;
102       }
103
104       if(((message_neighbors->status == SYM_NEIGH) ||
105           (message_neighbors->status == MPR_NEIGH)))
106         {
107           struct neighbor_2_list_entry *two_hop_neighbor_yet =
108             olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
109 #ifdef DEBUG
110           OLSR_PRINTF(7, "\tProcessing %s\n", olsr_ip_to_string(&buf, &message_neighbors->address));
111 #endif
112           if (two_hop_neighbor_yet != NULL)
113             {
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;
117
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.
121
122               if (olsr_cnf->lq_level > 0)
123                 {
124                   // loop through the one-hop neighbors that see this
125                   // 'two_hop_neighbor'
126
127                   struct neighbor_list_entry *walker;
128
129                   for (walker = two_hop_neighbor->neighbor_2_nblist.next;
130                        walker != &two_hop_neighbor->neighbor_2_nblist;
131                        walker = walker->next)
132                     {
133                       // have we found the one-hop neighbor that sent the
134                       // HELLO message that we're current processing?
135
136                       if (walker->neighbor == neighbor)
137                         {
138                           walker->path_link_quality = 0.0;
139                         }
140                     }
141                 }
142             }
143           else
144             {
145               two_hop_neighbor =
146                 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
147               if (two_hop_neighbor == NULL)
148                 {
149 #ifdef DEBUG
150                   OLSR_PRINTF(5, 
151                               "Adding 2 hop neighbor %s\n\n", 
152                               olsr_ip_to_string(&buf, &message_neighbors->address));
153 #endif
154                   changes_neighborhood = OLSR_TRUE;
155                   changes_topology = OLSR_TRUE;
156
157                   two_hop_neighbor =
158                     olsr_malloc(sizeof(struct neighbor_2_entry), "Process HELLO");
159                   
160                   two_hop_neighbor->neighbor_2_nblist.next =
161                     &two_hop_neighbor->neighbor_2_nblist;
162
163                   two_hop_neighbor->neighbor_2_nblist.prev =
164                     &two_hop_neighbor->neighbor_2_nblist;
165
166                   two_hop_neighbor->neighbor_2_pointer = 0;
167                   
168                   two_hop_neighbor->neighbor_2_addr = message_neighbors->address;
169
170                   olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
171
172                   linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime);
173                 }
174               else
175                 {
176                   /*
177                     linking to this two_hop_neighbor entry
178                   */    
179                   changes_neighborhood = OLSR_TRUE;
180                   changes_topology = OLSR_TRUE;
181                   
182                   linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime); 
183                 }
184             }
185         }
186     }
187
188   // Separate, second and third pass for link quality OLSR
189
190   if (olsr_cnf->lq_level > 0)
191     {
192       struct link_entry *lnk =
193         get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
194
195       if(!lnk)
196         return;
197
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.
204
205       for(message_neighbors = message->neighbors;
206           message_neighbors != NULL;
207           message_neighbors = message_neighbors->next)
208         {
209           if(if_ifwithaddr(&message_neighbors->address) != NULL)
210             continue;
211
212           if(((message_neighbors->status == SYM_NEIGH) ||
213               (message_neighbors->status == MPR_NEIGH)))
214             {
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);
219
220               if(!two_hop_neighbor_yet)
221                 continue;
222
223               two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
224
225               // loop through the one-hop neighbors that see this
226               // 'two_hop_neighbor'
227
228               for (walker = two_hop_neighbor->neighbor_2_nblist.next;
229                    walker != &two_hop_neighbor->neighbor_2_nblist;
230                    walker = walker->next)
231                 {
232                   // have we found the one-hop neighbor that sent the
233                   // HELLO message that we're current processing?
234
235                   if (walker->neighbor == neighbor)
236                     {
237                       double new_second_hop_link_quality, new_path_link_quality;
238
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
242
243                       // let's compare this to ETX:
244
245                       // 1 / LQ1 + 1 / LQ2 < 1 / LQ3 + 1 / LQ4 <=>
246                       // LQ1 * LQ2 > LQ3 * LQ4
247
248                       // so comparing path link quality values with ">" is
249                       // equivalent to comparing ETX values with "<"
250
251                       // the link quality between the 1-hop neighbour and the
252                       // 2-hop neighbour
253
254                       new_second_hop_link_quality = 
255                         message_neighbors->link_quality *
256                         message_neighbors->neigh_link_quality;
257
258                       // the total quality for the route
259                       // "us --- 1-hop --- 2-hop"
260
261                       new_path_link_quality =
262                         new_second_hop_link_quality *
263                         lnk->loss_link_quality * lnk->neigh_link_quality;
264
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)
268                         {
269                           walker->second_hop_link_quality = new_second_hop_link_quality;
270                           walker->path_link_quality = new_path_link_quality;
271                         }
272                     }
273                 }
274             }
275         }
276
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
280       // later reference.
281       for(message_neighbors = message->neighbors;
282           message_neighbors != NULL;
283           message_neighbors = message_neighbors->next)
284         {
285           if(if_ifwithaddr(&message_neighbors->address) != NULL)
286             continue;
287
288           if(((message_neighbors->status == SYM_NEIGH) ||
289               (message_neighbors->status == MPR_NEIGH)))
290             {
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);
295
296               if(!two_hop_neighbor_yet)
297                 continue;
298
299               two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
300
301               // loop through the one-hop neighbors that see this
302               // 'two_hop_neighbor'
303
304               for (walker = two_hop_neighbor->neighbor_2_nblist.next;
305                    walker != &two_hop_neighbor->neighbor_2_nblist;
306                    walker = walker->next)
307                 {
308                   // have we found the one-hop neighbor that sent the
309                   // HELLO message that we're current processing?
310
311                   if (walker->neighbor == neighbor)
312                     {
313                       double saved_lq, rel_lq;
314
315                       // saved previous total link quality
316
317                       saved_lq = walker->saved_path_link_quality;
318
319                       if (saved_lq == 0.0)
320                         saved_lq = -1.0;
321
322                       // if the link cost has changed by more than 10
323                       // percent, signal
324
325                       rel_lq = walker->path_link_quality / saved_lq;
326
327                       if (rel_lq > 1.1 || rel_lq < 0.9)
328                         {
329                           walker->saved_path_link_quality =
330                             walker->path_link_quality;
331
332                           if (olsr_cnf->lq_dlimit > 0)
333                           {
334                             changes_neighborhood = OLSR_TRUE;
335                             changes_topology = OLSR_TRUE;
336                           }
337
338                           else
339                             OLSR_PRINTF(3, "Skipping Dijkstra (3)\n");
340                         }
341                     }
342                 }
343             }
344         }
345     }
346 }
347
348 /**
349  *Links a one-hop neighbor with a 2-hop neighbor.
350  *
351  *@param neighbor the 1-hop neighbor
352  *@param two_hop_neighbor the 2-hop neighbor
353  *@return nada
354  */
355 static void
356 linking_this_2_entries(struct neighbor_entry *neighbor, struct neighbor_2_entry *two_hop_neighbor, float vtime)
357 {
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");
360
361   list_of_1_neighbors->neighbor = neighbor;
362
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;
366
367   /* Queue */
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;
370
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;
374   
375   list_of_2_neighbors->neighbor_2_timer = GET_TIMESTAMP(vtime*1000);
376
377   /* Queue */
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;
382   
383   /*increment the pointer counter*/
384   two_hop_neighbor->neighbor_2_pointer++;
385 }
386
387 /**
388  *Check if a hello message states this node as a MPR.
389  *
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
393  *
394  *@return 1 if we are selected as MPR 0 if not
395  */
396 static int
397 lookup_mpr_status(const struct hello_message *message, const struct interface *in_if)
398 {  
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));
403
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)) {
407       //printf("ok");
408       if (neighbors->link == SYM_LINK && neighbors->status == MPR_NEIGH) {
409         return 1;
410       }
411       break;
412     }
413   }
414   /* Not found */
415   return 0;
416 }
417
418
419 /**
420  *Initializing the parser functions we are using
421  */
422 void
423 olsr_init_package_process(void)
424 {
425   if (olsr_cnf->lq_level == 0)
426     {
427       olsr_parser_add_function(&olsr_process_received_hello, HELLO_MESSAGE, 1);
428       olsr_parser_add_function(&olsr_input_tc, TC_MESSAGE, 1);
429     }
430   else
431     {
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);
434     }
435
436   olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
437   olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
438 }
439
440 void
441 olsr_hello_tap(struct hello_message *message,
442                struct interface *in_if,
443                const union olsr_ip_addr *from_addr)
444 {
445   struct neighbor_entry     *neighbor;
446
447   /*
448    * Update link status
449    */
450   struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
451
452   if (olsr_cnf->lq_level > 0)
453     {
454       double saved_lq;
455       double rel_lq;
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);
459
460       // find the input interface in the list of neighbor interfaces
461
462       for (walker = message->neighbors; walker != NULL; walker = walker->next)
463         if (ipequal(&walker->address, &in_if->ip_addr))
464           break;
465
466       // the current reference link quality
467
468       saved_lq = lnk->saved_neigh_link_quality;
469
470       if (saved_lq == 0.0)
471         saved_lq = -1.0;
472
473       // memorize our neighbour's idea of the link quality, so that we
474       // know the link quality in both directions
475
476       if (walker != NULL)
477         lnk->neigh_link_quality = walker->link_quality;
478
479       else
480         lnk->neigh_link_quality = 0.0;
481
482       // if the link quality has changed by more than 10 percent,
483       // print the new link quality table
484
485       rel_lq = lnk->neigh_link_quality / saved_lq;
486
487       if (rel_lq > 1.1 || rel_lq < 0.9)
488         {
489           lnk->saved_neigh_link_quality = lnk->neigh_link_quality;
490
491           if (olsr_cnf->lq_dlimit > 0)
492           {
493             changes_neighborhood = OLSR_TRUE;
494             changes_topology = OLSR_TRUE;
495           }
496
497           else
498             OLSR_PRINTF(3, "Skipping Dijkstra (2)\n");
499
500           // create a new ANSN
501
502           // XXX - we should check whether we actually
503           // announce this neighbour
504
505           signal_link_changes(OLSR_TRUE);
506         }
507     }
508   
509   neighbor = lnk->neighbor;
510
511   /*
512    * Hysteresis
513    */
514   if(olsr_cnf->use_hysteresis)
515     {
516       /* Update HELLO timeout */
517       //printf("MESSAGE HTIME: %f\n", message->htime);
518       olsr_update_hysteresis_hello(lnk, message->htime);
519     }
520
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);
525
526
527
528   /* Check willingness */
529   if(neighbor->willingness != message->willingness)
530     {
531 #ifndef NODEBUG
532       struct ipaddr_str buf;
533 #endif
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);
538       /*
539        *If willingness changed - recalculate
540        */
541       neighbor->willingness = message->willingness;
542       changes_neighborhood = OLSR_TRUE;
543       changes_topology = OLSR_TRUE;
544     }
545
546
547   /* Don't register neighbors of neighbors that announces WILL_NEVER */
548   if(neighbor->willingness != WILL_NEVER)
549     process_message_neighbors(neighbor, message);
550
551   /* Process changes immedeatly in case of MPR updates */
552   olsr_process_changes();
553
554   olsr_free_hello_packet(message);
555
556   return;
557 }
558
559 /**
560  *Processes a received HELLO message. 
561  *
562  *@param m the incoming OLSR message
563  *@return 0 on sucess
564  */
565
566 void
567 olsr_process_received_hello(union olsr_message *m,
568                             struct interface *in_if,
569                             union olsr_ip_addr *from_addr)
570 {
571   struct hello_message      message;
572
573   hello_chgestruct(&message, m);
574
575   if(!olsr_validate_address(&message.source_addr))
576     {
577       olsr_free_hello_packet(&message);
578       return;
579     }
580
581   olsr_hello_tap(&message, in_if, from_addr);
582 }
583
584 /**
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.
588  *
589  *@param m the OLSR message received.
590  *@return 1 on success
591  */
592
593 void
594 olsr_process_received_mid(union olsr_message *m,
595                           struct interface *in_if,
596                           union olsr_ip_addr *from_addr)
597 {
598 #if !defined(NODEBUG) && defined(DEBUG)
599   struct ipaddr_str buf;
600 #endif
601   struct mid_alias *tmp_adr;
602   struct mid_message message;
603
604   mid_chgestruct(&message, m);
605
606   if (!olsr_validate_address(&message.mid_origaddr)) {
607     olsr_free_mid_packet(&message);
608     return;
609   }
610
611   if (olsr_check_dup_table_proc(&message.mid_origaddr, 
612                                 message.mid_seqno)) {
613
614 #ifdef DEBUG
615     OLSR_PRINTF(5, "Processing MID from %s...\n", olsr_ip_to_string(&buf, &message.mid_origaddr));
616 #endif
617     tmp_adr = message.mid_addr;
618
619     /*
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.
623      */
624
625     if(check_neighbor_link(from_addr) != SYM_LINK) {
626 #ifndef NODEBUG
627       struct ipaddr_str buf;
628 #endif
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);
631       return;
632     }
633
634     /* Update the timeout of the MID */
635     olsr_update_mid_table(&message.mid_origaddr, (float)message.vtime);
636
637     while (tmp_adr) {
638       if (!mid_lookup_main_addr(&tmp_adr->alias_addr)){
639 #ifndef NODEBUG
640         struct ipaddr_str buf;
641 #endif
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);
645       }
646       tmp_adr = tmp_adr->next;
647     } 
648   
649     olsr_prune_aliases(&message.mid_origaddr, message.mid_addr);
650   }
651
652   olsr_forward_message(m, 
653                        &message.mid_origaddr, 
654                        message.mid_seqno, 
655                        in_if,
656                        from_addr);
657   olsr_free_mid_packet(&message);
658 }
659
660
661 /**
662  *Process incoming HNA message.
663  *Forwards the message if that is to be done.
664  *
665  *@param m the incoming OLSR message
666  *the OLSR message.
667  *@return 1 on success
668  */
669
670 void
671 olsr_process_received_hna(union olsr_message *m,
672                           struct interface *in_if,
673                           union olsr_ip_addr *from_addr)
674 {
675
676   olsr_u8_t          olsr_msgtype;
677   double             vtime;
678   olsr_u16_t         olsr_msgsize;
679   union olsr_ip_addr originator;
680   //olsr_u8_t          ttl; unused
681   olsr_u8_t          hop_count;
682   olsr_u16_t         packet_seq_number;
683
684   int                hnasize;
685   const olsr_u8_t    *curr, *curr_end;
686
687 #ifdef DEBUG
688   OLSR_PRINTF(5, "Processing HNA\n");
689 #endif
690
691   /* Check if everyting is ok */
692   if (!m) {
693     return;
694   }
695   curr = (const olsr_u8_t *)m;
696
697   /* olsr_msgtype */
698   pkt_get_u8(&curr, &olsr_msgtype);
699   if (olsr_msgtype != HNA_MESSAGE) {
700     OLSR_PRINTF(0, "not a HNA message!\n");
701     return;
702   }
703   /* Get vtime */
704   pkt_get_double(&curr, &vtime);
705
706   /* olsr_msgsize */
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));
709   if (hnasize < 0) {
710     OLSR_PRINTF(0, "message size %d too small (at least %d)!\n", olsr_msgsize, (olsr_cnf->ip_version == AF_INET ? offsetof(struct olsrmsg, message) : offsetof(struct olsrmsg6, message)));
711     return;
712   }
713   if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
714     OLSR_PRINTF(0, "Illegal message size %d!\n", olsr_msgsize);
715     return;
716   }
717   curr_end = (const olsr_u8_t *)m + olsr_msgsize;
718
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");
724     return;
725   }
726
727   /* ttl */
728   pkt_ignore_u8(&curr);
729
730   /* hopcnt */
731   pkt_get_u8(&curr, &hop_count);
732
733   /* seqno */
734   pkt_get_u16(&curr, &packet_seq_number);
735
736   if (olsr_check_dup_table_proc(&originator, packet_seq_number)) {
737     /*
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.
741      */
742     if (check_neighbor_link(from_addr) != SYM_LINK) {
743 #ifndef NODEBUG
744       struct ipaddr_str buf;
745 #endif
746       OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
747       return;
748     }
749 #if 1
750     while (curr < curr_end) {
751       union olsr_ip_addr net;
752       olsr_u8_t prefixlen;
753       struct ip_prefix_list *entry;
754
755       pkt_get_ipaddress(&curr, &net);
756       pkt_get_prefixlen(&curr, &prefixlen);
757       entry = ip_prefix_list_find(olsr_cnf->hna_entries, &net, prefixlen);
758       if (entry == NULL) {
759         /* only update if it's not from us */
760         olsr_update_hna_entry(&originator, &net, prefixlen, vtime);
761 #else
762     while (hna_tmp) {
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);
766 #endif
767       }
768     }
769   }
770   olsr_forward_message(m, 
771                        &originator, 
772                        packet_seq_number, 
773                        in_if,
774                        from_addr);
775 }