vif.c revision 1.9 1 /* $NetBSD: vif.c,v 1.9 2002/06/02 13:47:04 itojun Exp $ */
2
3 /*
4 * The mrouted program is covered by the license in the accompanying file
5 * named "LICENSE". Use of the mrouted program represents acceptance of
6 * the terms and conditions listed in that file.
7 *
8 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
9 * Leland Stanford Junior University.
10 */
11
12
13 #include "defs.h"
14 #include <fcntl.h>
15
16 /*
17 * Exported variables.
18 */
19 struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
20 vifi_t numvifs; /* number of vifs in use */
21 int vifs_down; /* 1=>some interfaces are down */
22 int phys_vif; /* An enabled vif */
23 int udp_socket; /* Since the honkin' kernel doesn't support */
24 /* ioctls on raw IP sockets, we need a UDP */
25 /* socket as well as our IGMP (raw) socket. */
26 /* How dumb. */
27 int vifs_with_neighbors; /* == 1 if I am a leaf */
28
29 typedef struct {
30 vifi_t vifi;
31 struct listaddr *g;
32 int q_time;
33 } cbk_t;
34
35 /*
36 * Forward declarations.
37 */
38 static void start_vif __P((vifi_t vifi));
39 static void start_vif2 __P((vifi_t vifi));
40 static void stop_vif __P((vifi_t vifi));
41 static void age_old_hosts __P((void));
42 static void send_probe_on_vif __P((struct uvif *v));
43 static int info_version __P((char *p));
44 static void DelVif __P((void *arg));
45 static int SetTimer __P((int vifi, struct listaddr *g));
46 static int DeleteTimer __P((int id));
47 static void SendQuery __P((void *arg));
48 static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire,
49 int q_time));
50
51
52 /*
53 * Initialize the virtual interfaces, but do not install
54 * them in the kernel. Start routing on all vifs that are
55 * not down or disabled.
56 */
57 void
58 init_vifs()
59 {
60 vifi_t vifi;
61 struct uvif *v;
62 int enabled_vifs, enabled_phyints;
63 extern char *configfilename;
64
65 numvifs = 0;
66 vifs_with_neighbors = 0;
67 vifs_down = FALSE;
68
69 /*
70 * Configure the vifs based on the interface configuration of the
71 * the kernel and the contents of the configuration file.
72 * (Open a UDP socket for ioctl use in the config procedures.)
73 */
74 if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
75 log(LOG_ERR, errno, "UDP socket");
76 log(LOG_INFO,0,"Getting vifs from kernel interfaces");
77 config_vifs_from_kernel();
78 log(LOG_INFO,0,"Getting vifs from %s",configfilename);
79 config_vifs_from_file();
80
81 /*
82 * Quit if there are fewer than two enabled vifs.
83 */
84 enabled_vifs = 0;
85 enabled_phyints = 0;
86 phys_vif = -1;
87 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
88 if (!(v->uv_flags & VIFF_DISABLED)) {
89 ++enabled_vifs;
90 if (!(v->uv_flags & VIFF_TUNNEL)) {
91 if (phys_vif == -1)
92 phys_vif = vifi;
93 ++enabled_phyints;
94 }
95 }
96 }
97 if (enabled_vifs < 2)
98 log(LOG_ERR, 0, "can't forward: %s",
99 enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
100
101 if (enabled_phyints == 0)
102 log(LOG_WARNING, 0,
103 "no enabled interfaces, forwarding via tunnels only");
104
105 log(LOG_INFO, 0, "Installing vifs in mrouted...");
106 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
107 if (!(v->uv_flags & VIFF_DISABLED)) {
108 if (!(v->uv_flags & VIFF_DOWN)) {
109 if (v->uv_flags & VIFF_TUNNEL)
110 log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
111 inet_fmt(v->uv_lcl_addr, s1),
112 inet_fmt(v->uv_rmt_addr, s2));
113 else
114 log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
115 inet_fmt(v->uv_lcl_addr, s1));
116 start_vif2(vifi);
117 } else log(LOG_INFO, 0,
118 "%s is not yet up; vif #%u not in service",
119 v->uv_name, vifi);
120 }
121 }
122 }
123
124 /*
125 * Start routing on all virtual interfaces that are not down or
126 * administratively disabled.
127 */
128 void
129 init_installvifs()
130 {
131 vifi_t vifi;
132 struct uvif *v;
133
134 log(LOG_INFO, 0, "Installing vifs in kernel...");
135 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
136 if (!(v->uv_flags & VIFF_DISABLED)) {
137 if (!(v->uv_flags & VIFF_DOWN)) {
138 if (v->uv_flags & VIFF_TUNNEL)
139 log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
140 inet_fmt(v->uv_lcl_addr, s1),
141 inet_fmt(v->uv_rmt_addr, s2));
142 else
143 log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
144 inet_fmt(v->uv_lcl_addr, s1));
145 k_add_vif(vifi, &uvifs[vifi]);
146 } else log(LOG_INFO, 0,
147 "%s is not yet up; vif #%u not in service",
148 v->uv_name, vifi);
149 }
150 }
151 }
152
153 /*
154 * See if any interfaces have changed from up state to down, or vice versa,
155 * including any non-multicast-capable interfaces that are in use as local
156 * tunnel end-points. Ignore interfaces that have been administratively
157 * disabled.
158 */
159 void
160 check_vif_state()
161 {
162 register vifi_t vifi;
163 register struct uvif *v;
164 struct ifreq ifr;
165
166 vifs_down = FALSE;
167 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
168
169 if (v->uv_flags & VIFF_DISABLED) continue;
170
171 strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
172 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
173 log(LOG_ERR, errno,
174 "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
175
176 if (v->uv_flags & VIFF_DOWN) {
177 if (ifr.ifr_flags & IFF_UP) {
178 v->uv_flags &= ~VIFF_DOWN;
179 start_vif(vifi);
180 log(LOG_INFO, 0,
181 "%s has come up; vif #%u now in service",
182 v->uv_name, vifi);
183 }
184 else vifs_down = TRUE;
185 }
186 else {
187 if (!(ifr.ifr_flags & IFF_UP)) {
188 stop_vif(vifi);
189 v->uv_flags |= VIFF_DOWN;
190 log(LOG_INFO, 0,
191 "%s has gone down; vif #%u taken out of service",
192 v->uv_name, vifi);
193 vifs_down = TRUE;
194 }
195 }
196 }
197 }
198
199 /*
200 * Send a probe message on vif v
201 */
202 static void
203 send_probe_on_vif(v)
204 register struct uvif *v;
205 {
206 register char *p;
207 register int datalen = 0;
208 struct listaddr *nbr;
209 int i;
210
211 p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
212
213 for (i = 0; i < 4; i++)
214 *p++ = ((char *)&(dvmrp_genid))[i];
215 datalen += 4;
216
217 /*
218 * add the neighbor list on the interface to the message
219 */
220 nbr = v->uv_neighbors;
221
222 while (nbr) {
223 for (i = 0; i < 4; i++)
224 *p++ = ((char *)&nbr->al_addr)[i];
225 datalen +=4;
226 nbr = nbr->al_next;
227 }
228
229 send_igmp(v->uv_lcl_addr,
230 (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
231 : dvmrp_group,
232 IGMP_DVMRP, DVMRP_PROBE,
233 htonl(MROUTED_LEVEL |
234 ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)),
235 datalen);
236 }
237
238 /*
239 * Add a vifi to the kernel and start routing on it.
240 */
241 static void
242 start_vif(vifi)
243 vifi_t vifi;
244 {
245 /*
246 * Install the interface in the kernel's vif structure.
247 */
248 k_add_vif(vifi, &uvifs[vifi]);
249
250 start_vif2(vifi);
251 }
252
253 /*
254 * Add a vifi to all the user-level data structures but don't add
255 * it to the kernel yet.
256 */
257 static void
258 start_vif2(vifi)
259 vifi_t vifi;
260 {
261 struct uvif *v;
262 u_int32_t src;
263 struct phaddr *p;
264
265 v = &uvifs[vifi];
266 src = v->uv_lcl_addr;
267
268 /*
269 * Update the existing route entries to take into account the new vif.
270 */
271 add_vif_to_routes(vifi);
272
273 if (!(v->uv_flags & VIFF_TUNNEL)) {
274 /*
275 * Join the DVMRP multicast group on the interface.
276 * (This is not strictly necessary, since the kernel promiscuously
277 * receives IGMP packets addressed to ANY IP multicast group while
278 * multicast routing is enabled. However, joining the group allows
279 * this host to receive non-IGMP packets as well, such as 'pings'.)
280 */
281 k_join(dvmrp_group, src);
282
283 /*
284 * Join the ALL-ROUTERS multicast group on the interface.
285 * This allows mtrace requests to loop back if they are run
286 * on the multicast router.
287 */
288 k_join(allrtrs_group, src);
289
290 /*
291 * Install an entry in the routing table for the subnet to which
292 * the interface is connected.
293 */
294 start_route_updates();
295 update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
296 for (p = v->uv_addrs; p; p = p->pa_next) {
297 start_route_updates();
298 update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi);
299 }
300
301 /*
302 * Until neighbors are discovered, assume responsibility for sending
303 * periodic group membership queries to the subnet. Send the first
304 * query.
305 */
306 v->uv_flags |= VIFF_QUERIER;
307 send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
308 (v->uv_flags & VIFF_IGMPV1) ? 0 :
309 IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
310 age_old_hosts();
311 }
312
313 v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
314
315 /*
316 * Send a probe via the new vif to look for neighbors.
317 */
318 send_probe_on_vif(v);
319 }
320
321 /*
322 * Stop routing on the specified virtual interface.
323 */
324 static void
325 stop_vif(vifi)
326 vifi_t vifi;
327 {
328 struct uvif *v;
329 struct listaddr *a;
330 struct phaddr *p;
331
332 v = &uvifs[vifi];
333
334 if (!(v->uv_flags & VIFF_TUNNEL)) {
335 /*
336 * Depart from the DVMRP multicast group on the interface.
337 */
338 k_leave(dvmrp_group, v->uv_lcl_addr);
339
340 /*
341 * Depart from the ALL-ROUTERS multicast group on the interface.
342 */
343 k_leave(allrtrs_group, v->uv_lcl_addr);
344
345 /*
346 * Update the entry in the routing table for the subnet to which
347 * the interface is connected, to take into account the interface
348 * failure.
349 */
350 start_route_updates();
351 update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
352 for (p = v->uv_addrs; p; p = p->pa_next) {
353 start_route_updates();
354 update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi);
355 }
356
357 /*
358 * Discard all group addresses. (No need to tell kernel;
359 * the k_del_vif() call, below, will clean up kernel state.)
360 */
361 while (v->uv_groups != NULL) {
362 a = v->uv_groups;
363 v->uv_groups = a->al_next;
364 free((char *)a);
365 }
366
367 v->uv_flags &= ~VIFF_QUERIER;
368 }
369
370 /*
371 * Update the existing route entries to take into account the vif failure.
372 */
373 delete_vif_from_routes(vifi);
374
375 /*
376 * Delete the interface from the kernel's vif structure.
377 */
378 k_del_vif(vifi);
379
380 /*
381 * Discard all neighbor addresses.
382 */
383 if (v->uv_neighbors)
384 vifs_with_neighbors--;
385
386 while (v->uv_neighbors != NULL) {
387 a = v->uv_neighbors;
388 v->uv_neighbors = a->al_next;
389 free((char *)a);
390 }
391 }
392
393
394 /*
395 * stop routing on all vifs
396 */
397 void
398 stop_all_vifs()
399 {
400 vifi_t vifi;
401 struct uvif *v;
402 struct listaddr *a;
403 struct vif_acl *acl;
404
405 for (vifi = 0; vifi < numvifs; vifi++) {
406 v = &uvifs[vifi];
407 while (v->uv_groups != NULL) {
408 a = v->uv_groups;
409 v->uv_groups = a->al_next;
410 free((char *)a);
411 }
412 while (v->uv_neighbors != NULL) {
413 a = v->uv_neighbors;
414 v->uv_neighbors = a->al_next;
415 free((char *)a);
416 }
417 while (v->uv_acl != NULL) {
418 acl = v->uv_acl;
419 v->uv_acl = acl->acl_next;
420 free((char *)acl);
421 }
422 }
423 }
424
425
426 /*
427 * Find the virtual interface from which an incoming packet arrived,
428 * based on the packet's source and destination IP addresses.
429 */
430 vifi_t
431 find_vif(src, dst)
432 register u_int32_t src;
433 register u_int32_t dst;
434 {
435 register vifi_t vifi;
436 register struct uvif *v;
437 register struct phaddr *p;
438
439 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
440 if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
441 if (v->uv_flags & VIFF_TUNNEL) {
442 if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr)
443 return(vifi);
444 }
445 else {
446 if ((src & v->uv_subnetmask) == v->uv_subnet &&
447 ((v->uv_subnetmask == 0xffffffff) ||
448 (src != v->uv_subnetbcast)))
449 return(vifi);
450 for (p=v->uv_addrs; p; p=p->pa_next) {
451 if ((src & p->pa_subnetmask) == p->pa_subnet &&
452 ((p->pa_subnetmask == 0xffffffff) ||
453 (src != p->pa_subnetbcast)))
454 return(vifi);
455 }
456 }
457 }
458 }
459 return (NO_VIF);
460 }
461
462 static void
463 age_old_hosts()
464 {
465 register vifi_t vifi;
466 register struct uvif *v;
467 register struct listaddr *g;
468
469 /*
470 * Decrement the old-hosts-present timer for each
471 * active group on each vif.
472 */
473 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
474 for (g = v->uv_groups; g != NULL; g = g->al_next)
475 if (g->al_old)
476 g->al_old--;
477 }
478
479
480 /*
481 * Send group membership queries to all subnets for which I am querier.
482 */
483 void
484 query_groups()
485 {
486 register vifi_t vifi;
487 register struct uvif *v;
488
489 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
490 if (v->uv_flags & VIFF_QUERIER) {
491 send_igmp(v->uv_lcl_addr, allhosts_group,
492 IGMP_HOST_MEMBERSHIP_QUERY,
493 (v->uv_flags & VIFF_IGMPV1) ? 0 :
494 IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
495 }
496 }
497 age_old_hosts();
498 }
499
500 /*
501 * Process an incoming host membership query
502 */
503 void
504 accept_membership_query(src, dst, group, tmo)
505 u_int32_t src, dst, group;
506 int tmo;
507 {
508 register vifi_t vifi;
509 register struct uvif *v;
510
511 if ((vifi = find_vif(src, dst)) == NO_VIF ||
512 (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
513 log(LOG_INFO, 0,
514 "ignoring group membership query from non-adjacent host %s",
515 inet_fmt(src, s1));
516 return;
517 }
518
519 v = &uvifs[vifi];
520
521 /*
522 * If we consider ourselves the querier for this vif, but hear a
523 * query from a router with a lower IP address, yield to them.
524 *
525 * This is done here as well as in the neighbor discovery in case
526 * there is a querier that doesn't speak DVMRP.
527 *
528 * XXX If this neighbor doesn't speak DVMRP, then we need to create
529 * some neighbor state for him so that we can time him out!
530 */
531 if ((v->uv_flags & VIFF_QUERIER) &&
532 (ntohl(src) < ntohl(v->uv_lcl_addr))) {
533 v->uv_flags &= ~VIFF_QUERIER;
534
535 }
536 }
537
538 /*
539 * Process an incoming group membership report.
540 */
541 void
542 accept_group_report(src, dst, group, r_type)
543 u_int32_t src, dst, group;
544 int r_type;
545 {
546 register vifi_t vifi;
547 register struct uvif *v;
548 register struct listaddr *g;
549
550 if ((vifi = find_vif(src, dst)) == NO_VIF ||
551 (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
552 log(LOG_INFO, 0,
553 "ignoring group membership report from non-adjacent host %s",
554 inet_fmt(src, s1));
555 return;
556 }
557
558 v = &uvifs[vifi];
559
560 /*
561 * Look for the group in our group list; if found, reset its timer.
562 */
563 for (g = v->uv_groups; g != NULL; g = g->al_next) {
564 if (group == g->al_addr) {
565 if (r_type == IGMP_v1_HOST_MEMBERSHIP_REPORT)
566 g->al_old = OLD_AGE_THRESHOLD;
567 #ifdef SNMP
568 g->al_genid = src;
569 #endif /* SNMP */
570
571 /** delete old timers, set a timer for expiration **/
572 g->al_timer = GROUP_EXPIRE_TIME;
573 if (g->al_query)
574 g->al_query = DeleteTimer(g->al_query);
575 if (g->al_timerid)
576 g->al_timerid = DeleteTimer(g->al_timerid);
577 g->al_timerid = SetTimer(vifi, g);
578 break;
579 }
580 }
581
582 /*
583 * If not found, add it to the list and update kernel cache.
584 */
585 if (g == NULL) {
586 g = (struct listaddr *)malloc(sizeof(struct listaddr));
587 if (g == NULL)
588 log(LOG_ERR, 0, "ran out of memory"); /* fatal */
589
590 g->al_addr = group;
591 if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT)
592 g->al_old = 0;
593 else
594 g->al_old = OLD_AGE_THRESHOLD;
595 #ifdef SNMP
596 g->al_genid = src;
597 #endif
598
599 /** set a timer for expiration **/
600 g->al_query = 0;
601 g->al_timer = GROUP_EXPIRE_TIME;
602 time(&g->al_ctime);
603 g->al_timerid = SetTimer(vifi, g);
604 g->al_next = v->uv_groups;
605 v->uv_groups = g;
606
607 update_lclgrp(vifi, group);
608 }
609
610 /*
611 * Check if a graft is necessary for this group
612 */
613 chkgrp_graft(vifi, group);
614 }
615
616
617 void
618 accept_leave_message(src, dst, group)
619 u_int32_t src, dst, group;
620 {
621 register vifi_t vifi;
622 register struct uvif *v;
623 register struct listaddr *g;
624
625 if ((vifi = find_vif(src, dst)) == NO_VIF ||
626 (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
627 log(LOG_INFO, 0,
628 "ignoring group leave report from non-adjacent host %s",
629 inet_fmt(src, s1));
630 return;
631 }
632
633 v = &uvifs[vifi];
634
635 if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
636 return;
637
638 /*
639 * Look for the group in our group list in order to set up a short-timeout
640 * query.
641 */
642 for (g = v->uv_groups; g != NULL; g = g->al_next) {
643 if (group == g->al_addr) {
644 log(LOG_DEBUG, 0,
645 "[vif.c, _accept_leave_message] %d %ld\n",
646 g->al_old, g->al_query);
647
648 /* Ignore the leave message if there are old hosts present */
649 if (g->al_old)
650 return;
651
652 /* still waiting for a reply to a query, ignore the leave */
653 if (g->al_query)
654 return;
655
656 /** delete old timer set a timer for expiration **/
657 if (g->al_timerid)
658 g->al_timerid = DeleteTimer(g->al_timerid);
659
660 /** send a group specific querry **/
661 g->al_timer = LEAVE_EXPIRE_TIME;
662 send_igmp(v->uv_lcl_addr, g->al_addr,
663 IGMP_HOST_MEMBERSHIP_QUERY,
664 LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE,
665 g->al_addr, 0);
666 g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3,
667 LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE);
668 g->al_timerid = SetTimer(vifi, g);
669 break;
670 }
671 }
672 }
673
674
675 /*
676 * Send a periodic probe on all vifs.
677 * Useful to determine one-way interfaces.
678 * Detect neighbor loss faster.
679 */
680 void
681 probe_for_neighbors()
682 {
683 register vifi_t vifi;
684 register struct uvif *v;
685
686 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
687 if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
688 send_probe_on_vif(v);
689 }
690 }
691 }
692
693
694 /*
695 * Send a list of all of our neighbors to the requestor, `src'.
696 */
697 void
698 accept_neighbor_request(src, dst)
699 u_int32_t src, dst;
700 {
701 vifi_t vifi;
702 struct uvif *v;
703 u_char *p, *ncount;
704 struct listaddr *la;
705 int datalen;
706 u_int32_t temp_addr, us, them = src;
707
708 /* Determine which of our addresses to use as the source of our response
709 * to this query.
710 */
711 if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
712 int udp; /* find best interface to reply on */
713 struct sockaddr_in addr;
714 int addrlen = sizeof(addr);
715
716 memset(&addr, 0, sizeof(addr));
717 addr.sin_family = AF_INET;
718 #if (defined(BSD) && (BSD >= 199103))
719 addr.sin_len = sizeof addr;
720 #endif
721 addr.sin_addr.s_addr = dst;
722 addr.sin_port = htons(2000); /* any port over 1024 will do... */
723 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
724 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
725 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
726 log(LOG_WARNING, errno, "Determining local address");
727 close(udp);
728 return;
729 }
730 close(udp);
731 us = addr.sin_addr.s_addr;
732 } else /* query sent to us alone */
733 us = dst;
734
735 #define PUT_ADDR(a) temp_addr = ntohl(a); \
736 *p++ = temp_addr >> 24; \
737 *p++ = (temp_addr >> 16) & 0xFF; \
738 *p++ = (temp_addr >> 8) & 0xFF; \
739 *p++ = temp_addr & 0xFF;
740
741 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
742 datalen = 0;
743
744 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
745 if (v->uv_flags & VIFF_DISABLED)
746 continue;
747
748 ncount = 0;
749
750 for (la = v->uv_neighbors; la; la = la->al_next) {
751
752 /* Make sure that there's room for this neighbor... */
753 if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
754 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
755 htonl(MROUTED_LEVEL), datalen);
756 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
757 datalen = 0;
758 ncount = 0;
759 }
760
761 /* Put out the header for this neighbor list... */
762 if (ncount == 0) {
763 PUT_ADDR(v->uv_lcl_addr);
764 *p++ = v->uv_metric;
765 *p++ = v->uv_threshold;
766 ncount = p;
767 *p++ = 0;
768 datalen += 4 + 3;
769 }
770
771 PUT_ADDR(la->al_addr);
772 datalen += 4;
773 (*ncount)++;
774 }
775 }
776
777 if (datalen != 0)
778 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
779 datalen);
780 }
781
782 /*
783 * Send a list of all of our neighbors to the requestor, `src'.
784 */
785 void
786 accept_neighbor_request2(src, dst)
787 u_int32_t src, dst;
788 {
789 vifi_t vifi;
790 struct uvif *v;
791 u_char *p, *ncount;
792 struct listaddr *la;
793 int datalen;
794 u_int32_t us, them = src;
795
796 /* Determine which of our addresses to use as the source of our response
797 * to this query.
798 */
799 if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
800 int udp; /* find best interface to reply on */
801 struct sockaddr_in addr;
802 int addrlen = sizeof(addr);
803
804 memset(&addr, 0, sizeof(addr));
805 addr.sin_family = AF_INET;
806 #if (defined(BSD) && (BSD >= 199103))
807 addr.sin_len = sizeof addr;
808 #endif
809 addr.sin_addr.s_addr = dst;
810 addr.sin_port = htons(2000); /* any port over 1024 will do... */
811 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
812 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
813 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
814 log(LOG_WARNING, errno, "Determining local address");
815 close(udp);
816 return;
817 }
818 close(udp);
819 us = addr.sin_addr.s_addr;
820 } else /* query sent to us alone */
821 us = dst;
822
823 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
824 datalen = 0;
825
826 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
827 register u_short vflags = v->uv_flags;
828 register u_char rflags = 0;
829 if (vflags & VIFF_TUNNEL)
830 rflags |= DVMRP_NF_TUNNEL;
831 if (vflags & VIFF_SRCRT)
832 rflags |= DVMRP_NF_SRCRT;
833 if (vflags & VIFF_DOWN)
834 rflags |= DVMRP_NF_DOWN;
835 if (vflags & VIFF_DISABLED)
836 rflags |= DVMRP_NF_DISABLED;
837 if (vflags & VIFF_QUERIER)
838 rflags |= DVMRP_NF_QUERIER;
839 if (vflags & VIFF_LEAF)
840 rflags |= DVMRP_NF_LEAF;
841 ncount = 0;
842 la = v->uv_neighbors;
843 if (la == NULL) {
844 /*
845 * include down & disabled interfaces and interfaces on
846 * leaf nets.
847 */
848 if (rflags & DVMRP_NF_TUNNEL)
849 rflags |= DVMRP_NF_DOWN;
850 if (datalen > MAX_DVMRP_DATA_LEN - 12) {
851 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
852 htonl(MROUTED_LEVEL), datalen);
853 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
854 datalen = 0;
855 }
856 *(u_int*)p = v->uv_lcl_addr;
857 p += 4;
858 *p++ = v->uv_metric;
859 *p++ = v->uv_threshold;
860 *p++ = rflags;
861 *p++ = 1;
862 *(u_int*)p = v->uv_rmt_addr;
863 p += 4;
864 datalen += 12;
865 } else {
866 for ( ; la; la = la->al_next) {
867 /* Make sure that there's room for this neighbor... */
868 if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
869 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
870 htonl(MROUTED_LEVEL), datalen);
871 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
872 datalen = 0;
873 ncount = 0;
874 }
875 /* Put out the header for this neighbor list... */
876 if (ncount == 0) {
877 *(u_int*)p = v->uv_lcl_addr;
878 p += 4;
879 *p++ = v->uv_metric;
880 *p++ = v->uv_threshold;
881 *p++ = rflags;
882 ncount = p;
883 *p++ = 0;
884 datalen += 4 + 4;
885 }
886 *(u_int*)p = la->al_addr;
887 p += 4;
888 datalen += 4;
889 (*ncount)++;
890 }
891 }
892 }
893 if (datalen != 0)
894 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
895 datalen);
896 }
897
898 void
899 accept_info_request(src, dst, p, datalen)
900 u_int32_t src, dst;
901 u_char *p;
902 int datalen;
903 {
904 u_char *q;
905 int len;
906 int outlen = 0;
907
908 q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
909
910 /* To be general, this must deal properly with breaking up over-sized
911 * packets. That implies passing a length to each function, and
912 * allowing each function to request to be called again. Right now,
913 * we're only implementing the one thing we are positive will fit into
914 * a single packet, so we wimp out.
915 */
916 while (datalen > 0) {
917 len = 0;
918 switch (*p) {
919 case DVMRP_INFO_VERSION:
920 len = info_version(q);
921 break;
922
923 case DVMRP_INFO_NEIGHBORS:
924 default:
925 log(LOG_INFO, 0, "ignoring unknown info type %d", *p);
926 break;
927 }
928 *(q+1) = len++;
929 outlen += len * 4;
930 q += len * 4;
931 len = (*(p+1) + 1) * 4;
932 p += len;
933 datalen -= len;
934 }
935
936 if (outlen != 0)
937 send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
938 htonl(MROUTED_LEVEL), outlen);
939 }
940
941 /*
942 * Information response -- return version string
943 */
944 static int
945 info_version(p)
946 char *p;
947 {
948 int len;
949 extern char versionstring[];
950
951 *p++ = DVMRP_INFO_VERSION;
952 p++; /* skip over length */
953 *p++ = 0; /* zero out */
954 *p++ = 0; /* reserved fields */
955 strcpy(p, versionstring); /* XXX strncpy!!! */
956
957 len = strlen(versionstring);
958 return ((len + 3) / 4);
959 }
960
961 /*
962 * Process an incoming neighbor-list message.
963 */
964 void
965 accept_neighbors(src, dst, p, datalen, level)
966 u_int32_t src, dst, level;
967 u_char *p;
968 int datalen;
969 {
970 log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
971 inet_fmt(src, s1), inet_fmt(dst, s2));
972 }
973
974
975 /*
976 * Process an incoming neighbor-list message.
977 */
978 void
979 accept_neighbors2(src, dst, p, datalen, level)
980 u_int32_t src, dst, level;
981 u_char *p;
982 int datalen;
983 {
984 log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
985 inet_fmt(src, s1), inet_fmt(dst, s2));
986 }
987
988 /*
989 * Process an incoming info reply message.
990 */
991 void
992 accept_info_reply(src, dst, p, datalen)
993 u_int32_t src, dst;
994 u_char *p;
995 int datalen;
996 {
997 log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s",
998 inet_fmt(src, s1), inet_fmt(dst, s2));
999 }
1000
1001
1002 /*
1003 * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
1004 * 'msgtype' is the type of DVMRP message received from the neighbor.
1005 * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
1006 */
1007 int
1008 update_neighbor(vifi, addr, msgtype, p, datalen, level)
1009 vifi_t vifi;
1010 u_int32_t addr;
1011 int msgtype;
1012 char *p;
1013 int datalen;
1014 u_int32_t level;
1015 {
1016 register struct uvif *v;
1017 register struct listaddr *n;
1018 u_int32_t genid = 0;
1019 u_int32_t router;
1020 u_int32_t send_tables = 0;
1021 int do_reset = FALSE;
1022 int nflags;
1023
1024 v = &uvifs[vifi];
1025 nflags = (level >> 16) & 0xff;
1026
1027 /*
1028 * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
1029 * IT IS ASSUMED that this was preceded by a call to find_vif(), which
1030 * checks that 'addr' is either a valid remote tunnel endpoint or a
1031 * non-broadcast address belonging to a directly-connected subnet.
1032 * Therefore, here we check only that 'addr' is not our own address
1033 * (due to an impostor or erroneous loopback) or an address of the form
1034 * {subnet,0} ("the unknown host"). These checks are not performed in
1035 * find_vif() because those types of address are acceptable for some
1036 * types of IGMP message (such as group membership reports).
1037 */
1038 if (!(v->uv_flags & VIFF_TUNNEL) &&
1039 (addr == v->uv_lcl_addr ||
1040 addr == v->uv_subnet )) {
1041 log(LOG_WARNING, 0,
1042 "received DVMRP message from 'the unknown host' or self: %s",
1043 inet_fmt(addr, s1));
1044 return (FALSE);
1045 }
1046
1047 /*
1048 * Look for addr in list of neighbors.
1049 */
1050 for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
1051 if (addr == n->al_addr) {
1052 break;
1053 }
1054 }
1055
1056 /*
1057 * Found it. Reset its timer, and check for a version change
1058 */
1059 if (n) {
1060 n->al_timer = 0;
1061
1062 /*
1063 * update the neighbors version and protocol number
1064 * if changed => router went down and came up,
1065 * so take action immediately.
1066 */
1067 if ((n->al_pv != (level & 0xff)) ||
1068 (n->al_mv != ((level >> 8) & 0xff))) {
1069
1070 do_reset = TRUE;
1071 log(LOG_DEBUG, 0,
1072 "version change neighbor %s [old:%d.%d, new:%d.%d]",
1073 inet_fmt(addr, s1),
1074 n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
1075
1076 n->al_pv = level & 0xff;
1077 n->al_mv = (level >> 8) & 0xff;
1078 }
1079 } else {
1080 /*
1081 * If not found, add it to the list. If the neighbor has a lower
1082 * IP address than me, yield querier duties to it.
1083 */
1084 log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
1085 inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
1086 (level >> 16) & 0xff);
1087
1088 n = (struct listaddr *)malloc(sizeof(struct listaddr));
1089 if (n == NULL)
1090 log(LOG_ERR, 0, "ran out of memory"); /* fatal */
1091
1092 n->al_addr = addr;
1093 n->al_pv = level & 0xff;
1094 n->al_mv = (level >> 8) & 0xff;
1095 n->al_genid = 0;
1096
1097 time(&n->al_ctime);
1098 n->al_timer = 0;
1099 n->al_next = v->uv_neighbors;
1100
1101 /*
1102 * If we thought that we had no neighbors on this vif, send a route
1103 * report to the vif. If this is just a new neighbor on the same
1104 * vif, send the route report just to the new neighbor.
1105 */
1106 if (v->uv_neighbors == NULL) {
1107 send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group;
1108 vifs_with_neighbors++;
1109 } else {
1110 send_tables = addr;
1111 }
1112
1113 v->uv_neighbors = n;
1114
1115 if (!(v->uv_flags & VIFF_TUNNEL) &&
1116 ntohl(addr) < ntohl(v->uv_lcl_addr))
1117 v->uv_flags &= ~VIFF_QUERIER;
1118 }
1119
1120 /*
1121 * Check if the router gen-ids are the same.
1122 * Need to reset the prune state of the router if not.
1123 * Also check for one-way interfaces by seeing if we are in our
1124 * neighbor's list of known routers.
1125 */
1126 if (msgtype == DVMRP_PROBE) {
1127
1128 /* Check genid neighbor flag. Also check version number; 3.3 and
1129 * 3.4 didn't set this flag. */
1130 if ((((level >> 16) & 0xff) & NF_GENID) ||
1131 (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) {
1132
1133 int i;
1134
1135 if (datalen < 4) {
1136 log(LOG_WARNING, 0,
1137 "received truncated probe message from %s (len %d)",
1138 inet_fmt(addr, s1), datalen);
1139 return (FALSE);
1140 }
1141
1142 for (i = 0; i < 4; i++)
1143 ((char *)&genid)[i] = *p++;
1144 datalen -= 4;
1145
1146 if (n->al_genid == 0)
1147 n->al_genid = genid;
1148 else if (n->al_genid != genid) {
1149 log(LOG_DEBUG, 0,
1150 "new genid neigbor %s on vif %d [old:%x, new:%x]",
1151 inet_fmt(addr, s1), vifi, n->al_genid, genid);
1152
1153 n->al_genid = genid;
1154 do_reset = TRUE;
1155 }
1156
1157 /*
1158 * loop through router list and check for one-way ifs.
1159 */
1160
1161 v->uv_flags |= VIFF_ONEWAY;
1162
1163 while (datalen > 0) {
1164 if (datalen < 4) {
1165 log(LOG_WARNING, 0,
1166 "received truncated probe message from %s (len %d)",
1167 inet_fmt(addr, s1), datalen);
1168 return (FALSE);
1169 }
1170 for (i = 0; i < 4; i++)
1171 ((char *)&router)[i] = *p++;
1172 datalen -= 4;
1173 if (router == v->uv_lcl_addr) {
1174 v->uv_flags &= ~VIFF_ONEWAY;
1175 break;
1176 }
1177 }
1178 }
1179 }
1180 if (n->al_flags != nflags) {
1181 n->al_flags = nflags;
1182
1183 if (n->al_flags & NF_LEAF) {
1184 /*XXX If we have non-leaf neighbors then we know we shouldn't
1185 * mark this vif as a leaf. For now we just count on other
1186 * probes and/or reports resetting the timer. */
1187 if (!v->uv_leaf_timer)
1188 v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
1189 } else {
1190 /* If we get a leaf to non-leaf transition, we *must* update
1191 * the routing table. */
1192 if (v->uv_flags & VIFF_LEAF && send_tables == 0)
1193 send_tables = addr;
1194 v->uv_flags &= ~VIFF_LEAF;
1195 v->uv_leaf_timer = 0;
1196 }
1197 }
1198 if (do_reset) {
1199 reset_neighbor_state(vifi, addr);
1200 if (!send_tables)
1201 send_tables = addr;
1202 }
1203 if (send_tables)
1204 report(ALL_ROUTES, vifi, send_tables);
1205
1206 return (TRUE);
1207 }
1208
1209
1210 /*
1211 * On every timer interrupt, advance the timer in each neighbor and
1212 * group entry on every vif.
1213 */
1214 void
1215 age_vifs()
1216 {
1217 register vifi_t vifi;
1218 register struct uvif *v;
1219 register struct listaddr *a, *prev_a, *n;
1220 register u_int32_t addr;
1221
1222 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
1223 if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
1224 v->uv_flags |= VIFF_LEAF;
1225 }
1226
1227 for (prev_a = (struct listaddr *)&(v->uv_neighbors),
1228 a = v->uv_neighbors;
1229 a != NULL;
1230 prev_a = a, a = a->al_next) {
1231
1232 if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME)
1233 continue;
1234
1235 /*
1236 * Neighbor has expired; delete it from the neighbor list,
1237 * delete it from the 'dominants' and 'subordinates arrays of
1238 * any route entries and assume querier duties unless there is
1239 * another neighbor with a lower IP address than mine.
1240 */
1241 addr = a->al_addr;
1242 prev_a->al_next = a->al_next;
1243 free((char *)a);
1244 a = prev_a;
1245
1246 delete_neighbor_from_routes(addr, vifi);
1247
1248 if (v->uv_neighbors == NULL)
1249 vifs_with_neighbors--;
1250
1251 v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
1252
1253 if (!(v->uv_flags & VIFF_TUNNEL)) {
1254 v->uv_flags |= VIFF_QUERIER;
1255 for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
1256 if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
1257 v->uv_flags &= ~VIFF_QUERIER;
1258 }
1259 if (!(n->al_flags & NF_LEAF)) {
1260 v->uv_leaf_timer = 0;
1261 }
1262 }
1263 }
1264 }
1265 }
1266 }
1267
1268 /*
1269 * Returns the neighbor info struct for a given neighbor
1270 */
1271 struct listaddr *
1272 neighbor_info(vifi, addr)
1273 vifi_t vifi;
1274 u_int32_t addr;
1275 {
1276 struct listaddr *u;
1277
1278 for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
1279 if (u->al_addr == addr)
1280 return u;
1281
1282 return NULL;
1283 }
1284
1285 /*
1286 * Print the contents of the uvifs array on file 'fp'.
1287 */
1288 void
1289 dump_vifs(fp)
1290 FILE *fp;
1291 {
1292 register vifi_t vifi;
1293 register struct uvif *v;
1294 register struct listaddr *a;
1295 register struct phaddr *p;
1296 struct sioc_vif_req v_req;
1297
1298 fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
1299
1300 if (vifs_with_neighbors == 1)
1301 fprintf(fp,"[This host is a leaf]\n\n");
1302
1303 fprintf(fp,
1304 "\nVirtual Interface Table\n%s",
1305 "Vif Name Local-Address ");
1306 fprintf(fp,
1307 "M Thr Rate Flags\n");
1308
1309 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
1310
1311 fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ",
1312 vifi,
1313 v->uv_name,
1314 inet_fmt(v->uv_lcl_addr, s1),
1315 (v->uv_flags & VIFF_TUNNEL) ?
1316 "tunnel":
1317 "subnet",
1318 (v->uv_flags & VIFF_TUNNEL) ?
1319 inet_fmt(v->uv_rmt_addr, s2) :
1320 inet_fmts(v->uv_subnet, v->uv_subnetmask, s3),
1321 v->uv_metric,
1322 v->uv_threshold,
1323 v->uv_rate_limit);
1324
1325 if (v->uv_flags & VIFF_ONEWAY) fprintf(fp, " one-way");
1326 if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down");
1327 if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
1328 if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
1329 if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
1330 if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf");
1331 if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1");
1332 fprintf(fp, "\n");
1333
1334 if (v->uv_addrs != NULL) {
1335 fprintf(fp, " alternate subnets: %s\n",
1336 inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1));
1337 for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
1338 fprintf(fp, " %s\n",
1339 inet_fmts(p->pa_subnet, p->pa_subnetmask, s1));
1340 }
1341 }
1342
1343 if (v->uv_neighbors != NULL) {
1344 fprintf(fp, " peers: %s (%d.%d) (0x%x)\n",
1345 inet_fmt(v->uv_neighbors->al_addr, s1),
1346 v->uv_neighbors->al_pv, v->uv_neighbors->al_mv,
1347 v->uv_neighbors->al_flags);
1348 for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
1349 fprintf(fp, " %s (%d.%d) (0x%x)\n",
1350 inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv,
1351 a->al_flags);
1352 }
1353 }
1354
1355 if (v->uv_groups != NULL) {
1356 fprintf(fp, " groups: %-15s\n",
1357 inet_fmt(v->uv_groups->al_addr, s1));
1358 for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) {
1359 fprintf(fp, " %-15s\n",
1360 inet_fmt(a->al_addr, s1));
1361 }
1362 }
1363 if (v->uv_acl != NULL) {
1364 struct vif_acl *acl;
1365
1366 fprintf(fp, " boundaries: %-18s\n",
1367 inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1));
1368 for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) {
1369 fprintf(fp, " : %-18s\n",
1370 inet_fmts(acl->acl_addr, acl->acl_mask, s1));
1371 }
1372 }
1373 v_req.vifi = vifi;
1374 if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
1375 log(LOG_WARNING, 0,
1376 "SIOCGETVIFCNT fails");
1377 }
1378 else {
1379 fprintf(fp, " pkts in : %ld\n",
1380 v_req.icount);
1381 fprintf(fp, " pkts out: %ld\n",
1382 v_req.ocount);
1383 }
1384 fprintf(fp, "\n");
1385 }
1386 fprintf(fp, "\n");
1387 }
1388
1389 /*
1390 * Time out record of a group membership on a vif
1391 */
1392 static void
1393 DelVif(arg)
1394 void *arg;
1395 {
1396 cbk_t *cbk = (cbk_t *)arg;
1397 vifi_t vifi = cbk->vifi;
1398 struct uvif *v = &uvifs[vifi];
1399 struct listaddr *a, **anp, *g = cbk->g;
1400
1401 /*
1402 * Group has expired
1403 * delete all kernel cache entries with this group
1404 */
1405 if (g->al_query)
1406 DeleteTimer(g->al_query);
1407
1408 delete_lclgrp(vifi, g->al_addr);
1409
1410 anp = &(v->uv_groups);
1411 while ((a = *anp) != NULL) {
1412 if (a == g) {
1413 *anp = a->al_next;
1414 free((char *)a);
1415 } else {
1416 anp = &a->al_next;
1417 }
1418 }
1419
1420 free(cbk);
1421 }
1422
1423 /*
1424 * Set a timer to delete the record of a group membership on a vif.
1425 */
1426 static int
1427 SetTimer(vifi, g)
1428 vifi_t vifi;
1429 struct listaddr *g;
1430 {
1431 cbk_t *cbk;
1432
1433 cbk = (cbk_t *) malloc(sizeof(cbk_t));
1434 cbk->g = g;
1435 cbk->vifi = vifi;
1436 return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
1437 }
1438
1439 /*
1440 * Delete a timer that was set above.
1441 */
1442 static int
1443 DeleteTimer(id)
1444 int id;
1445 {
1446 timer_clearTimer(id);
1447 return 0;
1448 }
1449
1450 /*
1451 * Send a group-specific query.
1452 */
1453 static void
1454 SendQuery(arg)
1455 void *arg;
1456 {
1457 cbk_t *cbk = (cbk_t *)arg;
1458 register struct uvif *v = &uvifs[cbk->vifi];
1459
1460 send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
1461 IGMP_HOST_MEMBERSHIP_QUERY,
1462 cbk->q_time, cbk->g->al_addr, 0);
1463 cbk->g->al_query = 0;
1464 free(cbk);
1465 }
1466
1467 /*
1468 * Set a timer to send a group-specific query.
1469 */
1470 static int
1471 SetQueryTimer(g, vifi, to_expire, q_time)
1472 struct listaddr *g;
1473 vifi_t vifi;
1474 int to_expire, q_time;
1475 {
1476 cbk_t *cbk;
1477
1478 cbk = (cbk_t *) malloc(sizeof(cbk_t));
1479 cbk->g = g;
1480 cbk->q_time = q_time;
1481 cbk->vifi = vifi;
1482 return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
1483 }
1484