Added checks for NULL returned from get_best_link_to_neighbor in the LQ code
[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.36 2005/11/29 18:38:40 kattemat Exp $
40  */
41
42
43 #include "defs.h"
44 #include "process_package.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
56
57 /**
58  *Initializing the parser functions we are using
59  */
60 void
61 olsr_init_package_process()
62 {
63   if (olsr_cnf->lq_level == 0)
64     {
65       olsr_parser_add_function(&olsr_process_received_hello, HELLO_MESSAGE, 1);
66       olsr_parser_add_function(&olsr_process_received_tc, TC_MESSAGE, 1);
67     }
68
69   else
70     {
71       olsr_parser_add_function(&olsr_input_lq_hello, LQ_HELLO_MESSAGE, 1);
72       olsr_parser_add_function(&olsr_input_lq_tc, LQ_TC_MESSAGE, 1);
73     }
74
75   olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
76   olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
77 }
78
79 void
80 olsr_hello_tap(struct hello_message *message, struct interface *in_if,
81                union olsr_ip_addr *from_addr)
82 {
83   struct link_entry         *link;
84   struct neighbor_entry     *neighbor;
85   struct hello_neighbor *walker;
86   double saved_lq;
87   double rel_lq;
88
89   /*
90    * Update link status
91    */
92   link = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
93
94   if (olsr_cnf->lq_level > 0)
95     {
96       // just in case our neighbor has changed its HELLO interval
97
98       olsr_update_packet_loss_hello_int(link, message->htime);
99
100       // find the input interface in the list of neighbor interfaces
101
102       for (walker = message->neighbors; walker != NULL; walker = walker->next)
103         if (COMP_IP(&walker->address, &in_if->ip_addr))
104           break;
105
106       // the current reference link quality
107
108       saved_lq = link->saved_neigh_link_quality;
109
110       if (saved_lq == 0.0)
111         saved_lq = -1.0;
112
113       // memorize our neighbour's idea of the link quality, so that we
114       // know the link quality in both directions
115
116       if (walker != NULL)
117         link->neigh_link_quality = walker->link_quality;
118
119       else
120         link->neigh_link_quality = 0.0;
121
122       // if the link quality has changed by more than 10 percent,
123       // print the new link quality table
124
125       rel_lq = link->neigh_link_quality / saved_lq;
126
127       if (rel_lq > 1.1 || rel_lq < 0.9)
128         {
129           link->saved_neigh_link_quality = link->neigh_link_quality;
130
131           if (olsr_cnf->lq_dlimit > 0)
132           {
133             changes_neighborhood = OLSR_TRUE;
134             changes_topology = OLSR_TRUE;
135           }
136
137           else
138             OLSR_PRINTF(3, "Skipping Dijkstra (2)\n")
139
140           // create a new ANSN
141
142           // XXX - we should check whether we actually
143           // announce this neighbour
144
145           changes = OLSR_TRUE;
146         }
147     }
148   
149   neighbor = link->neighbor;
150
151   /*
152    * Hysteresis
153    */
154   if(olsr_cnf->use_hysteresis)
155     {
156       /* Update HELLO timeout */
157       //printf("MESSAGE HTIME: %f\n", message->htime);
158       olsr_update_hysteresis_hello(link, message->htime);
159     }
160
161   /* Check if we are chosen as MPR */
162   if(olsr_lookup_mpr_status(message, in_if))
163     /* source_addr is always the main addr of a node! */
164     olsr_update_mprs_set(&message->source_addr, (float)message->vtime);
165
166
167
168   /* Check willingness */
169   if(neighbor->willingness != message->willingness)
170     {
171       OLSR_PRINTF(1, "Willingness for %s changed from %d to %d - UPDATING\n", 
172                   olsr_ip_to_string(&neighbor->neighbor_main_addr),
173                   neighbor->willingness,
174                   message->willingness)
175       /*
176        *If willingness changed - recalculate
177        */
178       neighbor->willingness = message->willingness;
179       changes_neighborhood = OLSR_TRUE;
180       changes_topology = OLSR_TRUE;
181     }
182
183
184   /* Don't register neighbors of neighbors that announces WILL_NEVER */
185   if(neighbor->willingness != WILL_NEVER)
186     olsr_process_message_neighbors(neighbor, message);
187
188   /* Process changes immedeatly in case of MPR updates */
189   olsr_process_changes();
190
191   olsr_free_hello_packet(message);
192
193   return;
194 }
195
196 /**
197  *Processes a received HELLO message. 
198  *
199  *@param m the incoming OLSR message
200  *@return 0 on sucess
201  */
202
203 void
204 olsr_process_received_hello(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
205 {
206   struct hello_message      message;
207
208   hello_chgestruct(&message, m);
209
210   if(!olsr_validate_address(&message.source_addr))
211     {
212       olsr_free_hello_packet(&message);
213       return;
214     }
215
216   olsr_hello_tap(&message, in_if, from_addr);
217 }
218
219 void
220 olsr_tc_tap(struct tc_message *message, struct interface *in_if,
221             union olsr_ip_addr *from_addr, union olsr_message *m)
222 {
223   struct tc_mpr_addr              *mpr;
224   struct tc_entry                 *tc_last;
225
226   if(!olsr_check_dup_table_proc(&message->originator, 
227                                 message->packet_seq_number))
228     {
229       goto forward;
230     }
231
232   OLSR_PRINTF(3, "Processing TC from %s\n",
233               olsr_ip_to_string(&message->originator))
234
235   /*
236    *      If the sender interface (NB: not originator) of this message
237    *      is not in the symmetric 1-hop neighborhood of this node, the
238    *      message MUST be discarded.
239    */
240
241   if(check_neighbor_link(from_addr) != SYM_LINK)
242     {
243       OLSR_PRINTF(2, "Received TC from NON SYM neighbor %s\n",
244                   olsr_ip_to_string(from_addr))
245       olsr_free_tc_packet(message);
246       return;
247     }
248
249   if(olsr_cnf->debug_level > 2)
250     {
251       mpr = message->multipoint_relay_selector_address;
252       OLSR_PRINTF(3, "mpr_selector_list:[")
253
254       while(mpr!=NULL)
255         {
256           OLSR_PRINTF(3, "%s:", olsr_ip_to_string(&mpr->address))
257           mpr=mpr->next;
258         }
259
260       OLSR_PRINTF(3, "]\n")
261     }
262
263   tc_last = olsr_lookup_tc_entry(&message->originator);
264    
265   if(tc_last != NULL)
266     {
267       /* Update entry */
268
269       /* Delete destinations with lower ANSN */
270       if(olsr_tc_delete_mprs(tc_last, message))
271         changes_topology = OLSR_TRUE; 
272
273       /* Update destinations */
274       if(olsr_tc_update_mprs(tc_last, message))
275         changes_topology = OLSR_TRUE;
276
277       /* Delete possible empty TC entry */
278       if(changes_topology)
279         olsr_tc_delete_entry_if_empty(tc_last);
280     }
281
282   else
283     {
284       /*if message is empty then skip it */
285       if(message->multipoint_relay_selector_address != NULL)
286         {
287           /* New entry */
288           tc_last = olsr_add_tc_entry(&message->originator);      
289           
290           /* Update destinations */
291           olsr_tc_update_mprs(tc_last, message);
292           
293           changes_topology = OLSR_TRUE;
294         }
295       else
296         {
297           OLSR_PRINTF(3, "Dropping empty TC from %s\n",
298                       olsr_ip_to_string(&message->originator))
299         }
300     }
301
302   /* Process changes */
303   //olsr_process_changes();
304
305  forward:
306
307   olsr_forward_message(m, 
308                        &message->originator, 
309                        message->packet_seq_number, 
310                        in_if,
311                        from_addr);
312
313   olsr_free_tc_packet(message);
314
315   return;
316 }
317
318 /**
319  *Process a received TopologyControl message
320  *
321  *
322  *@param m the incoming OLSR message
323  *@return 0 on success
324  */
325 void
326 olsr_process_received_tc(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
327
328   struct tc_message               message;
329
330   tc_chgestruct(&message, m, from_addr);
331
332   if(!olsr_validate_address(&message.source_addr))
333     {
334       olsr_free_tc_packet(&message);
335       return;
336     }
337
338   olsr_tc_tap(&message, in_if, from_addr, m);
339 }
340
341
342
343
344
345
346 /**
347  *Process a received(and parsed) MID message
348  *For every address check if there is a topology node
349  *registered with it and update its addresses.
350  *
351  *@param m the OLSR message received.
352  *@return 1 on success
353  */
354
355 void
356 olsr_process_received_mid(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
357 {
358   struct mid_alias *tmp_adr;
359   struct mid_message message;
360
361   mid_chgestruct(&message, m);
362
363   if(!olsr_validate_address(&message.mid_origaddr))
364     {
365       olsr_free_mid_packet(&message);
366       return;
367     }
368
369   if(!olsr_check_dup_table_proc(&message.mid_origaddr, 
370                                 message.mid_seqno))
371     {
372       goto forward;
373     }
374
375 #ifdef DEBUG
376   OLSR_PRINTF(5, "Processing MID from %s...\n", olsr_ip_to_string(&message.mid_origaddr))
377 #endif
378   tmp_adr = message.mid_addr;
379
380   /*
381    *      If the sender interface (NB: not originator) of this message
382    *      is not in the symmetric 1-hop neighborhood of this node, the
383    *      message MUST be discarded.
384    */
385
386   if(check_neighbor_link(from_addr) != SYM_LINK)
387     {
388       OLSR_PRINTF(2, "Received MID from NON SYM neighbor %s\n", olsr_ip_to_string(from_addr))
389       olsr_free_mid_packet(&message);
390       return;
391     }
392
393   /* Update the timeout of the MID */
394   olsr_update_mid_table(&message.mid_origaddr, (float)message.vtime);
395
396   while(tmp_adr)
397     {
398       if(!mid_lookup_main_addr(&tmp_adr->alias_addr))
399         {
400           OLSR_PRINTF(1, "MID new: (%s, ", olsr_ip_to_string(&message.mid_origaddr))
401           OLSR_PRINTF(1, "%s)\n", olsr_ip_to_string(&tmp_adr->alias_addr))
402           insert_mid_alias(&message.mid_origaddr, &tmp_adr->alias_addr, (float)message.vtime);
403         }
404
405
406       tmp_adr = tmp_adr->next;
407     } 
408   
409  forward:  
410   olsr_forward_message(m, 
411                        &message.mid_origaddr, 
412                        message.mid_seqno, 
413                        in_if,
414                        from_addr);
415   olsr_free_mid_packet(&message);
416
417   return;
418 }
419
420
421
422
423
424 /**
425  *Process incoming HNA message.
426  *Forwards the message if that is to be done.
427  *
428  *@param m the incoming OLSR message
429  *the OLSR message.
430  *@return 1 on success
431  */
432
433 void
434 olsr_process_received_hna(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
435 {
436   struct hna_net_addr  *hna_tmp;
437   struct  hna_message message;
438
439 #ifdef DEBUG
440   OLSR_PRINTF(5, "Processing HNA\n")
441 #endif
442
443   hna_chgestruct(&message, m);
444
445   if(!olsr_validate_address(&message.originator))
446     {
447       olsr_free_hna_packet(&message);
448       return;
449     }
450
451   if(!olsr_check_dup_table_proc(&message.originator, 
452                                 message.packet_seq_number))
453     {
454       goto forward;
455     }
456
457   hna_tmp = message.hna_net;
458
459   /*
460    *      If the sender interface (NB: not originator) of this message
461    *      is not in the symmetric 1-hop neighborhood of this node, the
462    *      message MUST be discarded.
463    */
464   if(check_neighbor_link(from_addr) != SYM_LINK)
465     {
466       OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(from_addr))
467       olsr_free_hna_packet(&message);
468       return;
469     }
470
471   while(hna_tmp)
472     {
473       olsr_update_hna_entry(&message.originator, &hna_tmp->net, &hna_tmp->netmask, (float)message.vtime); 
474       
475       hna_tmp = hna_tmp->next;
476     }
477
478  forward:
479   olsr_forward_message(m, 
480                        &message.originator, 
481                        message.packet_seq_number, 
482                        in_if,
483                        from_addr);
484   olsr_free_hna_packet(&message);
485
486   return;
487 }
488
489
490
491
492
493
494
495 /**
496  *Processes an list of neighbors from an incoming HELLO message.
497  *@param neighbor the neighbor who sendt the message.
498  *@param message the HELLO message
499  *@return nada
500  */
501 void
502 olsr_process_message_neighbors(struct neighbor_entry *neighbor,
503                                struct hello_message *message)
504 {
505   struct hello_neighbor        *message_neighbors;
506
507   for(message_neighbors = message->neighbors;
508       message_neighbors != NULL;
509       message_neighbors = message_neighbors->next)
510     {
511       union olsr_ip_addr      *neigh_addr;
512       struct neighbor_2_entry *two_hop_neighbor;
513
514       /*
515        *check all interfaces
516        *so that we don't add ourselves to the
517        *2 hop list
518        *IMPORTANT!
519        */
520       if(if_ifwithaddr(&message_neighbors->address) != NULL)
521         continue;
522
523       /* Get the main address */
524       neigh_addr = mid_lookup_main_addr(&message_neighbors->address);
525
526       if (neigh_addr != NULL)
527         COPY_IP(&message_neighbors->address, neigh_addr);
528       
529       if(((message_neighbors->status == SYM_NEIGH) ||
530           (message_neighbors->status == MPR_NEIGH)))
531         {
532           struct neighbor_2_list_entry *two_hop_neighbor_yet =
533             olsr_lookup_my_neighbors(neighbor, &message_neighbors->address);
534 #ifdef DEBUG
535           OLSR_PRINTF(7, "\tProcessing %s\n", olsr_ip_to_string(&message_neighbors->address))
536 #endif
537           if (two_hop_neighbor_yet != NULL)
538             {
539               /* Updating the holding time for this neighbor */
540               two_hop_neighbor_yet->neighbor_2_timer = GET_TIMESTAMP(message->vtime*1000);
541               two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
542             }
543           else
544             {
545               two_hop_neighbor =
546                 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
547               if (two_hop_neighbor == NULL)
548                 {
549 #ifdef DEBUG
550                   OLSR_PRINTF(5, 
551                               "Adding 2 hop neighbor %s\n\n", 
552                               olsr_ip_to_string(&message_neighbors->address))
553 #endif
554                   changes_neighborhood = OLSR_TRUE;
555                   changes_topology = OLSR_TRUE;
556
557                   two_hop_neighbor =
558                     olsr_malloc(sizeof(struct neighbor_2_entry),
559                                 "Process HELLO");
560                   
561                   two_hop_neighbor->neighbor_2_nblist.next =
562                     &two_hop_neighbor->neighbor_2_nblist;
563
564                   two_hop_neighbor->neighbor_2_nblist.prev =
565                     &two_hop_neighbor->neighbor_2_nblist;
566
567                   two_hop_neighbor->neighbor_2_pointer = 0;
568                   
569                   COPY_IP(&two_hop_neighbor->neighbor_2_addr,
570                           &message_neighbors->address);
571
572                   olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
573
574                   olsr_linking_this_2_entries(neighbor, two_hop_neighbor,
575                                               (float)message->vtime);
576                 }
577               else
578                 {
579                   /*
580                     linking to this two_hop_neighbor entry
581                   */    
582                   changes_neighborhood = OLSR_TRUE;
583                   changes_topology = OLSR_TRUE;
584                   
585                   olsr_linking_this_2_entries(neighbor, two_hop_neighbor,
586                                               (float)message->vtime); 
587                 }
588             }
589
590           if (olsr_cnf->lq_level > 0)
591             {
592               struct neighbor_list_entry *walker;
593               struct link_entry *link;
594
595               link = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
596
597               if(!link)
598                 continue;
599
600               // loop through the one-hop neighbors that see this
601               // two hop neighbour
602
603               for (walker = two_hop_neighbor->neighbor_2_nblist.next;
604                    walker != &two_hop_neighbor->neighbor_2_nblist;
605                    walker = walker->next)
606                 {
607                   // have we found the one-hop neighbor that sent the
608                   // HELLO message that we're current processing?
609
610                   if (walker->neighbor == neighbor)
611                     {
612                       double saved_lq, rel_lq;
613
614                       // saved previous total link quality
615
616                       saved_lq = walker->saved_path_link_quality;
617
618                       if (saved_lq == 0.0)
619                         saved_lq = -1.0;
620
621                       // path link quality = link quality between us
622                       // and our one-hop neighbor x link quality between
623                       // our one-hop neighbor and the two-hop neighbor
624
625                       // let's compare this to ETX:
626
627                       // 1 / LQ1 + 1 / LQ2 < 1 / LQ3 + 1 / LQ4 <=>
628                       // LQ1 * LQ2 > LQ3 * LQ4
629
630                       // so comparing path link quality values with ">" is
631                       // equivalent to comparing ETX values with "<"
632
633                       // the link quality between the 1-hop neighbour and the
634                       // 2-hop neighbour
635
636                       walker->second_hop_link_quality =
637                         message_neighbors->link_quality *
638                         message_neighbors->neigh_link_quality;
639
640                       // the total quality for the route
641                       // "us --- 1-hop --- 2-hop"
642
643                       walker->path_link_quality =
644                         walker->second_hop_link_quality *
645                         link->loss_link_quality * link->neigh_link_quality;
646
647                       // if the link quality has changed by more than 10
648                       // percent, signal
649
650                       rel_lq = walker->path_link_quality / saved_lq;
651
652                       if (rel_lq > 1.1 || rel_lq < 0.9)
653                         {
654                           walker->saved_path_link_quality =
655                             walker->path_link_quality;
656
657                           if (olsr_cnf->lq_dlimit > 0)
658                           {
659                             changes_neighborhood = OLSR_TRUE;
660                             changes_topology = OLSR_TRUE;
661                           }
662
663                           else
664                             OLSR_PRINTF(3, "Skipping Dijkstra (3)\n")
665                         }
666                     }
667                 }
668             }
669         }
670     }
671 }
672
673
674
675
676
677
678
679
680 /**
681  *Links a one-hop neighbor with a 2-hop neighbor.
682  *
683  *@param neighbor the 1-hop neighbor
684  *@param two_hop_neighbor the 2-hop neighbor
685  *@return nada
686  */
687 void
688 olsr_linking_this_2_entries(struct neighbor_entry *neighbor,struct neighbor_2_entry *two_hop_neighbor, float vtime)
689 {
690   struct neighbor_list_entry    *list_of_1_neighbors;
691   struct neighbor_2_list_entry  *list_of_2_neighbors;
692
693   list_of_1_neighbors = olsr_malloc(sizeof(struct neighbor_list_entry), "Link entries 1");
694
695   list_of_2_neighbors = olsr_malloc(sizeof(struct neighbor_2_list_entry), "Link entries 2");
696
697   list_of_1_neighbors->neighbor = neighbor;
698
699   list_of_1_neighbors->path_link_quality = 0.0;
700   list_of_1_neighbors->saved_path_link_quality = 0.0;
701   list_of_1_neighbors->second_hop_link_quality = 0.0;
702
703   /* Queue */
704   two_hop_neighbor->neighbor_2_nblist.next->prev = list_of_1_neighbors;
705   list_of_1_neighbors->next = two_hop_neighbor->neighbor_2_nblist.next;
706   two_hop_neighbor->neighbor_2_nblist.next = list_of_1_neighbors;
707   list_of_1_neighbors->prev = &two_hop_neighbor->neighbor_2_nblist;
708
709
710   list_of_2_neighbors->neighbor_2 = two_hop_neighbor;
711   
712   list_of_2_neighbors->neighbor_2_timer = GET_TIMESTAMP(vtime*1000);
713
714   /* Queue */
715   neighbor->neighbor_2_list.next->prev = list_of_2_neighbors;
716   list_of_2_neighbors->next = neighbor->neighbor_2_list.next;
717   neighbor->neighbor_2_list.next = list_of_2_neighbors;
718   list_of_2_neighbors->prev = &neighbor->neighbor_2_list;
719   
720   /*increment the pointer counter*/
721   two_hop_neighbor->neighbor_2_pointer++;
722 }
723
724
725
726
727
728
729 /**
730  *Check if a hello message states this node as a MPR.
731  *
732  *@param message the message to check
733  *@param n_link the buffer to put the link status in
734  *@param n_status the buffer to put the status in
735  *
736  *@return 1 if we are selected as MPR 0 if not
737  */
738 int
739 olsr_lookup_mpr_status(struct hello_message *message, struct interface *in_if)
740 {
741   
742   struct hello_neighbor  *neighbors;
743
744   neighbors=message->neighbors;
745   
746   while(neighbors!=NULL)
747     {  
748       //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&neighbors->address));
749       //printf("against %s\n",olsr_ip_to_string(&main_addr));
750
751
752     if(olsr_cnf->ip_version == AF_INET)
753       { 
754         /* IPv4 */  
755         if(COMP_IP(&neighbors->address, &in_if->ip_addr))
756           {
757             //printf("ok");
758             if((neighbors->link == SYM_LINK) && (neighbors->status == MPR_NEIGH))
759               return 1;
760             
761             return 0;
762           }
763       }
764     else
765       { 
766         /* IPv6 */  
767         if(COMP_IP(&neighbors->address, &in_if->int6_addr.sin6_addr))
768           {
769             //printf("ok");
770             if((neighbors->link == SYM_LINK) && (neighbors->status == MPR_NEIGH))
771               return 1;
772             
773             return 0;
774           }
775       }
776  
777       neighbors = neighbors->next; 
778     }
779
780   /* Not found */
781   return 0;
782 }