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