]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pim6sd/vif.c
This commit was generated by cvs2svn to compensate for changes in r69833,
[FreeBSD/FreeBSD.git] / usr.sbin / pim6sd / vif.c
1 /*
2  *  Copyright (c) 1998 by the University of Southern California.
3  *  All rights reserved.
4  *
5  *  Permission to use, copy, modify, and distribute this software and
6  *  its documentation in source and binary forms for lawful
7  *  purposes and without fee is hereby granted, provided
8  *  that the above copyright notice appear in all copies and that both
9  *  the copyright notice and this permission notice appear in supporting
10  *  documentation, and that any documentation, advertising materials,
11  *  and other materials related to such distribution and use acknowledge
12  *  that the software was developed by the University of Southern
13  *  California and/or Information Sciences Institute.
14  *  The name of the University of Southern California may not
15  *  be used to endorse or promote products derived from this software
16  *  without specific prior written permission.
17  *
18  *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
20  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23  *  NON-INFRINGEMENT.
24  *
25  *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  *
30  *  Other copyrights might apply to parts of this software and are so
31  *  noted when applicable.
32  */
33 /*
34  *  Questions concerning this software should be directed to
35  *  Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
36  *
37  */
38 /*
39  * This program has been derived from pim6dd.        
40  * The pim6dd program is covered by the license in the accompanying file
41  * named "LICENSE.pim6dd".
42  */
43 /*
44  * This program has been derived from pimd.        
45  * The pimd program is covered by the license in the accompanying file
46  * named "LICENSE.pimd".
47  *
48  */
49 /*
50  * Part of this program has been derived from mrouted.
51  * The mrouted program is covered by the license in the accompanying file
52  * named "LICENSE.mrouted".
53  *
54  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
55  * Leland Stanford Junior University.
56  *
57  * $FreeBSD$
58  */
59
60 #include <sys/ioctl.h>
61 #include <errno.h>
62 #include <syslog.h>
63 #include <string.h>
64 #include <stdlib.h>
65 #include "vif.h"
66 #include "mld6.h"
67 #include "pim6.h"
68 #include "pimd.h"
69 #include "route.h"
70 #include "config.h"
71 #include "inet6.h"
72 #include "kern.h"
73 #include "mld6_proto.h"
74 #include "pim6_proto.h"
75 #include "mrt.h"
76 #include "debug.h"
77 #include "timer.h"
78
79 struct uvif     uvifs[MAXMIFS]; /*the list of virtualsinterfaces */
80 vifi_t numvifs;                         /*total number of interface */
81 int vifs_down;
82 vifi_t reg_vif_num;                /*register interface*/
83 int phys_vif; /* An enabled vif that has a global address */
84 int udp_socket;
85 int total_interfaces;
86 if_set                  if_nullset;
87 if_set                  if_result;
88
89 int init_reg_vif __P((void));
90 void start_all_vifs __P((void));
91 void start_vif __P((vifi_t vifi));
92 void stop_vif __P((vifi_t vivi));
93 int update_reg_vif __P((vifi_t register_vifi));
94
95 extern int cfparse __P((int, int));
96
97 void init_vifs()
98 {
99         vifi_t vifi;
100         struct uvif *v;
101         int enabled_vifs;
102
103         numvifs = 0;
104         reg_vif_num = NO_VIF;
105
106         /*
107          * Configure the vifs based on the interface configuration of
108          * the kernel and the contents of the configuration file.
109          * (Open a UDP socket for ioctl use in the config procedures if
110          * the kernel can't handle IOCTL's on the MLD socket.)
111          */
112 #ifdef IOCTL_OK_ON_RAW_SOCKET
113         udp_socket = mld6_socket;
114 #else
115         if ((udp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
116                 log(LOG_ERR, errno, "UDP6 socket");
117 #endif
118
119         /* clean all the interfaces ... */
120
121         for(vifi = 0,v=uvifs; vifi < MAXVIFS; ++ vifi, ++v)
122         {
123                 memset(v,0,sizeof(*v)); /* everything is zeroed  => NULL , pointer NULL , addrANY ...) */
124                 v->uv_metric = DEFAULT_METRIC;
125                 v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
126                 strncpy(v->uv_name,"",IFNAMSIZ);
127                 v->uv_local_pref = default_source_preference;
128                 v->uv_local_metric = default_source_metric;
129         }
130         IF_DEBUG(DEBUG_IF)
131                 log(LOG_DEBUG,0,"Interfaces world initialized...");
132         IF_DEBUG(DEBUG_IF)
133                 log(LOG_DEBUG,0,"Getting vifs from kernel");
134         config_vifs_from_kernel();
135         if (max_global_address() == NULL)
136                 log(LOG_ERR, 0, "There's no global address");
137         IF_DEBUG(DEBUG_IF)
138                 log(LOG_DEBUG,0,"Getting vifs from %s",configfilename);
139
140         /* read config from file */
141         if (cfparse(1, 0) != 0)
142                 log(LOG_ERR, 0, "fatal error in parsing the config file");
143
144         enabled_vifs = 0;
145         phys_vif = -1;
146
147         for( vifi = 0, v = uvifs ; vifi < numvifs ; ++ vifi,++v)
148         {
149                 if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
150                         continue;
151                 if(v->uv_linklocal == NULL)
152                         log(LOG_ERR,0,"there is no link-local address on vif %s",v->uv_name);
153                 if (phys_vif == -1) {
154                         struct phaddr *p;
155
156                         /*
157                          * If this vif has a global address, set its id
158                          * to phys_vif.
159                          */
160                         for(p = v->uv_addrs; p; p = p->pa_next) {
161                                 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
162                                     !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
163                                         phys_vif = vifi;
164                                         break;
165                                 }
166                         }
167                 }
168                 enabled_vifs++;
169         }
170         if (enabled_vifs < 2)
171                 log(LOG_ERR,0,"can't forward: %s",
172                 enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif" );
173
174         memset(&if_nullset,0,sizeof(if_nullset));
175         k_init_pim(mld6_socket);        
176         IF_DEBUG(DEBUG_PIM_DETAIL)
177                 log(LOG_DEBUG,0,"Pim kernel initialization done");
178
179
180         /* Add a dummy virtual interface to support Registers in the kernel. */
181         init_reg_vif();
182
183         start_all_vifs();
184
185 }
186 int init_reg_vif()
187 {
188         struct uvif *v;
189         vifi_t i;
190
191         v = &uvifs[numvifs];
192         if (( numvifs+1 ) == MAXVIFS )
193         {
194      /* Exit the program! The PIM router must have a Register vif */
195     log(LOG_ERR, 0,
196         "cannot install the Register vif: too many interfaces");
197     /* To make lint happy */
198     return (FALSE);
199         }
200
201     /*
202      * So far in PIM we need only one register vif and we save its number in
203      * the global reg_vif_num.
204      */
205
206
207         reg_vif_num = numvifs;
208
209     /* Use the address of the first available physical interface to
210      * create the register vif.
211      */
212
213         for(i =0 ; i < numvifs ; i++)
214         {
215                 if(uvifs[i].uv_flags & (VIFF_DOWN | VIFF_DISABLED | MIFF_REGISTER))
216                         continue;
217         else
218                 break;
219         }
220         if( i >= numvifs)
221         {
222                   log(LOG_ERR, 0, "No physical interface enabled");
223         return -1;
224     }
225
226         
227         memcpy(v,&uvifs[i],sizeof(*v));
228         strncpy(v->uv_name,"register_mif0",IFNAMSIZ);
229         v->uv_flags = MIFF_REGISTER;
230
231 #ifdef PIM_EXPERIMENTAL
232         v->uv_flags |= MIFF_REGISTER_KERNEL_ENCAP;
233 #endif
234
235     IF_DEBUG(DEBUG_IF)
236                 log(LOG_DEBUG,0,"Interface %s (subnet %s) ,installed on vif #%u - rate = %d",
237         v->uv_name,net6name(&v->uv_prefix.sin6_addr,&v->uv_subnetmask),
238         reg_vif_num,v->uv_rate_limit);
239
240         numvifs++;
241         total_interfaces++;
242         return 0;       
243 }
244
245 void start_all_vifs()
246 {
247         vifi_t vifi;
248         struct uvif *v;
249         u_int action;
250
251
252    /* Start first the NON-REGISTER vifs */
253
254         for(action=0; ;action = MIFF_REGISTER )
255         {
256                 for(vifi= 0,v = uvifs;vifi < numvifs ; ++vifi, ++v)
257                 {
258                         if (( v->uv_flags & MIFF_REGISTER ) ^ action )
259         /* If starting non-registers but the vif is a register
260          * or if starting registers, but the interface is not
261          * a register, then just continue.
262          */
263                                 continue;
264
265                         if ( v->uv_flags & (VIFF_DISABLED | VIFF_DOWN ))
266                         {
267                                 IF_DEBUG(DEBUG_IF)
268                                 {
269                                         if ( v-> uv_flags & VIFF_DISABLED)
270                                                 log(LOG_DEBUG,0,"%s is DISABLED ; vif #%u out of service",v->uv_name,vifi); 
271                                         else
272                                                 log(LOG_DEBUG,0,"%s is DOWN ; vif #%u out of service",v->uv_name,vifi);
273                                 }       
274                         }
275                         else
276                                 start_vif(vifi);
277                 }
278                 if ( action == MIFF_REGISTER)
279                         break;
280         }       
281 }
282
283 /*
284  * Initialize the vif and add to the kernel. The vif can be either
285  * physical, register or tunnel (tunnels will be used in the future
286  * when this code becomes PIM multicast boarder router.
287  */
288
289
290 void start_vif (vifi_t vifi)
291 {
292         struct uvif *v;
293
294         v = &uvifs[vifi];
295
296         /* Initialy no router on any vif */
297
298         if( v-> uv_flags & MIFF_REGISTER)
299                 v->uv_flags = v->uv_flags & ~VIFF_DOWN;
300         else
301         {
302                 v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~ VIFF_DOWN;
303                 v->uv_pim_hello_timer = 1 + RANDOM() % pim_hello_period;
304                 v->uv_jp_timer = 1 + RANDOM() % pim_join_prune_period;
305         }
306
307         /* Tell kernel to add, i.e. start this vif */
308
309         k_add_vif(mld6_socket,vifi,&uvifs[vifi]);
310         IF_DEBUG(DEBUG_IF)
311                 log(LOG_DEBUG,0,"%s comes up ,vif #%u now in service",v->uv_name,vifi);
312
313         if (!(v->uv_flags & MIFF_REGISTER)) {
314             /*
315              * Join the PIM multicast group on the interface.
316              */
317             k_join(mld6_socket, &allpim6routers_group.sin6_addr,
318                    v->uv_ifindex);
319
320             /*
321              * Join the ALL-ROUTERS multicast group on the interface.
322              * This allows mtrace requests to loop back if they are run
323              * on the multicast router.this allow receiving mld6 messages too.
324              */
325             k_join(mld6_socket, &allrouters_group.sin6_addr, v->uv_ifindex);
326
327             /*
328              * Until neighbors are discovered, assume responsibility for sending
329              * periodic group membership queries to the subnet.  Send the first
330              * query.
331              */
332             v->uv_flags |= VIFF_QUERIER;
333             if (!v->uv_querier) {
334                 v->uv_querier = (struct listaddr *)malloc(sizeof(struct listaddr));
335                 memset(v->uv_querier, 0, sizeof(struct listaddr));
336             }
337             v->uv_querier->al_addr = v->uv_linklocal->pa_addr;
338             v->uv_querier->al_timer = MLD6_OTHER_QUERIER_PRESENT_INTERVAL;
339             time(&v->uv_querier->al_ctime); /* reset timestamp */
340             query_groups(v);
341   
342             /*
343              * Send a probe via the new vif to look for neighbors.
344              */
345             send_pim6_hello(v, pim_hello_holdtime);
346         }
347 }
348
349 /*
350  * Stop a vif (either physical interface, tunnel or
351  * register.) If we are running only PIM we don't have tunnels.
352  */ 
353
354
355 void stop_vif( vifi_t vifi )
356 {
357         struct uvif *v;
358         struct listaddr *a;
359         register pim_nbr_entry_t *n;
360         register pim_nbr_entry_t *next;
361         struct vif_acl *acl;
362
363  
364     /*
365      * TODO: make sure that the kernel viftable is
366      * consistent with the daemon table
367      */
368
369         v=&uvifs[vifi];
370         if( !( v->uv_flags&MIFF_REGISTER ) )
371         {
372                 k_leave( mld6_socket , &allpim6routers_group.sin6_addr , v->uv_ifindex );
373                 k_leave( mld6_socket , &allrouters_group.sin6_addr , v->uv_ifindex );
374     /*
375      * Discard all group addresses.  (No need to tell kernel;
376      * the k_del_vif() call will clean up kernel state.)
377      */
378
379                 while( v->uv_groups!=NULL )
380                 {
381                         a=v->uv_groups;
382                         v->uv_groups=a->al_next;
383                         free((char *)a);
384                 }
385         }
386
387     /*
388      * TODO: inform (eventually) the neighbors I am going down by sending
389      * PIM_HELLO with holdtime=0 so someone else should become a DR.
390      */
391     /* TODO: dummy! Implement it!! Any problems if don't use it? */
392     delete_vif_from_mrt(vifi);
393
394     /*
395      * Delete the interface from the kernel's vif structure.
396      */
397
398         k_del_vif( mld6_socket , vifi );
399         v->uv_flags=(v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS) | VIFF_DOWN;
400         if( !(v->uv_flags & MIFF_REGISTER ))
401         {
402         RESET_TIMER(v->uv_pim_hello_timer);
403         RESET_TIMER(v->uv_jp_timer);
404         RESET_TIMER(v->uv_gq_timer);
405
406                 for( n=v->uv_pim_neighbors ; n!=NULL ; n = next )
407                 {
408                         next=n->next;                   /* Free the space for each neighbour */
409                         free((char *)n);
410                 }
411                 v->uv_pim_neighbors=NULL;
412         }
413
414         
415    /* TODO: currently not used */
416    /* The Access Control List (list with the scoped addresses) */
417
418         while( v->uv_acl!=NULL )
419         {
420                 acl=v->uv_acl;
421                 v->uv_acl=acl->acl_next;
422                 free((char *)acl);
423         }
424
425         vifs_down=TRUE;
426
427         IF_DEBUG(DEBUG_IF)
428                 log( LOG_DEBUG ,0,"%s goes down , vif #%u out of service" , v->uv_name , vifi);
429 }
430
431 /*
432  * Update the register vif in the multicast routing daemon and the
433  * kernel because the interface used initially to get its local address
434  * is DOWN. register_vifi is the index to the Register vif which needs
435  * to be updated. As a result the Register vif has a new uv_lcl_addr and
436  * is UP (virtually :))
437  */
438 int
439 update_reg_vif( vifi_t register_vifi )
440 {
441     register struct uvif *v;
442     register vifi_t vifi;
443
444     /* Find the first useable vif with solid physical background */
445     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
446         if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL
447                            | MIFF_REGISTER))
448             continue;
449         /* Found. Stop the bogus Register vif first */
450         stop_vif(register_vifi);
451         uvifs[register_vifi].uv_linklocal->pa_addr =
452             uvifs[vifi].uv_linklocal->pa_addr;
453         start_vif(register_vifi);
454         IF_DEBUG(DEBUG_PIM_REGISTER | DEBUG_IF)
455             log(LOG_NOTICE, 0, "%s has come up; vif #%u now in service",
456                 uvifs[register_vifi].uv_name, register_vifi);
457         return 0;
458     }
459     vifs_down = TRUE;
460     log(LOG_WARNING, 0, "Cannot start Register vif: %s",
461         uvifs[vifi].uv_name);
462     return(-1);
463 }
464
465 /*
466  * return the max global Ipv6 address of an UP and ENABLED interface
467  * other than the MIFF_REGISTER interface.
468 */
469 struct sockaddr_in6 *
470 max_global_address()
471 {
472         vifi_t vifi;
473         struct uvif *v;
474         struct phaddr *p;
475         struct phaddr *pmax = NULL;
476
477         for(vifi=0,v=uvifs;vifi< numvifs;++vifi,++v)
478         {
479                 if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
480                         continue;
481                 /*
482                  * take first the max global address of the interface
483                  * (without link local) => aliasing
484                  */
485                 for(p=v->uv_addrs;p!=NULL;p=p->pa_next)
486                 {
487                         /*
488                          * If this is the first global address, take it anyway.
489                          */
490                         if (pmax == NULL) {
491                                 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
492                                     !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
493                                         pmax = p;
494                         }
495                         else {
496                                 if (inet6_lessthan(&pmax->pa_addr,
497                                                    &p->pa_addr) &&
498                                     !IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
499                                     !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
500                                         pmax=p; 
501                         }
502                 }
503         }
504
505         return(pmax ? &pmax->pa_addr : NULL);
506 }
507
508 struct sockaddr_in6 *
509 uv_global(vifi)
510         vifi_t vifi;
511 {
512         struct uvif *v = &uvifs[vifi];
513         struct phaddr *p;
514
515         for (p = v->uv_addrs; p; p = p->pa_next) {
516                 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
517                     !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
518                         return(&p->pa_addr);
519         }
520
521         return(NULL);
522 }
523
524 /*
525  * Check if the interface exists in the mif table. If true 
526  * return the highest address of the interface else return NULL.
527  */
528 struct sockaddr_in6 *
529 local_iface(char *ifname)
530 {
531         register struct uvif *v;
532         vifi_t vifi;
533         struct phaddr *p;
534         struct phaddr *pmax = NULL;
535
536         for(vifi=0,v=uvifs;vifi<numvifs;++vifi,++v)
537         {
538                 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
539                         continue;
540                 if(EQUAL(v->uv_name, ifname))
541                 {
542                         for(p=v->uv_addrs; p!=NULL; p=p->pa_next)
543                         {
544                                 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr)&&
545                                     !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
546                                         /*
547                                          * If this is the first global address
548                                          * or larger than the current MAX global
549                                          * address, remember it.
550                                          */
551                                         if (pmax == NULL ||
552                                             inet6_lessthan(&pmax->pa_addr,
553                                                            &p->pa_addr))
554                                                 pmax = p;
555                                 }
556                         }
557                         if (pmax)
558                                 return(&pmax->pa_addr);
559                 }
560         }
561
562         return NULL;
563 }
564
565 /*  
566  * See if any interfaces have changed from up state to down, or vice versa,
567  * including any non-multicast-capable interfaces that are in use as local
568  * tunnel end-points.  Ignore interfaces that have been administratively
569  * disabled.
570  */     
571 void
572 check_vif_state()
573 {
574     register vifi_t vifi;
575     register struct uvif *v;
576     struct ifreq ifr;
577     static int checking_vifs=0;
578
579     /*
580      * XXX: TODO: True only for DVMRP?? Check.
581      * If we get an error while checking, (e.g. two interfaces go down
582      * at once, and we decide to send a prune out one of the failed ones)
583      * then don't go into an infinite loop!
584      */
585     if( checking_vifs )
586         return;
587
588     vifs_down=FALSE;
589     checking_vifs=TRUE;
590
591     /* TODO: Check all potential interfaces!!! */
592     /* Check the physical and tunnels only */
593     for( vifi=0 , v=uvifs ; vifi<numvifs ; ++vifi , ++v )
594     {
595         if( v->uv_flags & ( VIFF_DISABLED|MIFF_REGISTER ) )
596             continue;
597
598         strncpy( ifr.ifr_name , v->uv_name , IFNAMSIZ );
599   
600         /* get the interface flags */
601         if( ioctl( udp_socket , SIOCGIFFLAGS , (char *)&ifr )<0 )
602             log(LOG_ERR, errno,
603                 "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
604
605         if( v->uv_flags & VIFF_DOWN )
606         {
607             if ( ifr.ifr_flags & IFF_UP )
608             {
609                 start_vif( vifi );
610             }
611             else
612                 vifs_down=TRUE;
613         }
614         else
615         {
616             if( !( ifr.ifr_flags & IFF_UP ))
617             {
618                 log( LOG_NOTICE ,0,
619                      "%s has gone down ; vif #%u taken out of  service",
620                      v->uv_name , vifi );
621                 stop_vif ( vifi );
622                 vifs_down = TRUE;
623             }
624         }
625     }
626
627     /* Check the register(s) vif(s) */
628     for( vifi=0 , v=uvifs ; vifi<numvifs ; ++vifi , ++v )
629     {
630         register vifi_t vifi2;
631         register struct uvif *v2;
632         int found;
633
634         if( !(v->uv_flags & MIFF_REGISTER ) )
635             continue;
636         else
637         {
638             found=0;
639
640             /* Find a physical vif with the same IP address as the
641              * Register vif.
642              */
643             for( vifi2=0 , v2=uvifs ; vifi2<numvifs ; ++vifi2 , ++v2 )
644             {
645                 if( v2->uv_flags & ( VIFF_DISABLED|VIFF_DOWN|VIFF_TUNNEL|MIFF_REGISTER ))
646                     continue;
647                 if( IN6_ARE_ADDR_EQUAL( &v->uv_linklocal->pa_addr.sin6_addr,
648                                         &v2->uv_linklocal->pa_addr.sin6_addr ))
649                 {
650                     found=1;
651                     break;
652                 }
653             }
654             if(!found)
655                 /* The physical interface with the IP address as the Register
656                  * vif is probably DOWN. Get a replacement.
657                  */
658                 update_reg_vif( vifi );
659         }
660     }
661     checking_vifs=0;
662 }
663
664 /*
665  * If the source is directly connected to us, find the vif number for
666  * the corresponding physical interface (tunnels excluded).
667  * Local addresses are excluded.
668  * Return the vif number or NO_VIF if not found.
669  */
670
671 vifi_t
672 find_vif_direct(src)
673     struct sockaddr_in6 *src;
674 {
675     vifi_t vifi;
676     register struct uvif *v;
677     register struct phaddr *p;
678    
679     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) 
680     {
681         if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL|MIFF_REGISTER))
682                 continue;
683         for (p = v->uv_addrs; p; p = p->pa_next) 
684         {
685             if (inet6_equal(src, &p->pa_addr))
686                 return(NO_VIF);
687             if (inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
688                 return(vifi);
689         }
690     }
691
692     return (NO_VIF);
693 }
694
695 /*
696  * Checks if src is local address. If "yes" return the vif index,
697  * otherwise return value is NO_VIF.
698  */
699
700 vifi_t
701 local_address(src)
702     struct sockaddr_in6 *src;
703 {
704     vifi_t vifi;
705     register struct uvif *v;
706     register struct phaddr *p;
707
708     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
709         if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
710             continue;
711         for (p = v->uv_addrs; p; p = p->pa_next) {
712             if (inet6_equal(src, &p->pa_addr))
713                 return(vifi);
714         }
715     }
716     /* Returning NO_VIF means not a local address */
717     return (NO_VIF);
718 }
719
720
721 /*  
722  * If the source is directly connected, or is local address,
723  * find the vif number for the corresponding physical interface
724  * (tunnels excluded).
725  * Return the vif number or NO_VIF if not found.
726  */ 
727
728 vifi_t
729 find_vif_direct_local(src)
730     struct sockaddr_in6 *src;
731
732     vifi_t vifi;
733     register struct uvif *v; 
734     register struct phaddr *p;
735    
736
737     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
738         if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL |MIFF_REGISTER))
739                 continue;
740         for (p = v->uv_addrs; p; p = p->pa_next) {
741                 if (inet6_equal(src, &p->pa_addr) ||
742                 inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))  
743                         return(vifi);
744         }
745     }
746     return (NO_VIF);
747 }
748
749 int
750 vif_forwarder(if_set *p1 , if_set *p2)
751 {
752         int idx;
753
754         for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
755         {
756                 if (p1->ifs_bits[idx] & p2->ifs_bits[idx])
757                         return(TRUE);
758                 
759         }
760
761         /* (p1 & p2) is empty. We're not the forwarder */
762         return(FALSE);
763 }
764
765 if_set *
766 vif_and(if_set *p1 , if_set *p2, if_set *result)
767 {
768         int idx;
769
770         IF_ZERO(result);
771
772         for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
773         {
774                 result->ifs_bits[idx] = p1->ifs_bits[idx] & p2->ifs_bits[idx];
775         }
776
777         return(result);
778 }
779
780 if_set *
781 vif_xor(if_set *p1 , if_set *p2, if_set *result)
782 {
783         int idx;
784
785         IF_ZERO(result);
786
787         for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
788         {
789                 result->ifs_bits[idx] =
790                         p1->ifs_bits[idx] ^ p2->ifs_bits[idx];
791         }
792
793         return(result);
794 }
795 /*  
796  * stop all vifs
797  */ 
798 void
799 stop_all_vifs()
800 {
801     vifi_t vifi;
802     struct uvif *v;
803  
804     for (vifi = 0, v=uvifs; vifi < numvifs; ++vifi, ++v) {
805         if (!(v->uv_flags &  VIFF_DOWN)) {
806             stop_vif(vifi);
807         }
808     }
809 }
810
811 struct uvif *
812 find_vif(ifname)
813         char *ifname;
814 {
815         struct uvif *v;
816         vifi_t vifi;
817
818         for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v) {
819                 if (strcasecmp(v->uv_name, ifname) == 0)
820                         return(v);
821         }
822
823         return(NULL);
824 }