1 /* $NetBSD: vif.c,v 1.8 2000/10/12 06:07:04 augustss 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 addr.sin_family = AF_INET; 717 #if (defined(BSD) && (BSD >= 199103)) 718 addr.sin_len = sizeof addr; 719 #endif 720 addr.sin_addr.s_addr = dst; 721 addr.sin_port = htons(2000); /* any port over 1024 will do... */ 722 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 723 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 724 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { 725 log(LOG_WARNING, errno, "Determining local address"); 726 close(udp); 727 return; 728 } 729 close(udp); 730 us = addr.sin_addr.s_addr; 731 } else /* query sent to us alone */ 732 us = dst; 733 734 #define PUT_ADDR(a) temp_addr = ntohl(a); \ 735 *p++ = temp_addr >> 24; \ 736 *p++ = (temp_addr >> 16) & 0xFF; \ 737 *p++ = (temp_addr >> 8) & 0xFF; \ 738 *p++ = temp_addr & 0xFF; 739 740 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 741 datalen = 0; 742 743 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { 744 if (v->uv_flags & VIFF_DISABLED) 745 continue; 746 747 ncount = 0; 748 749 for (la = v->uv_neighbors; la; la = la->al_next) { 750 751 /* Make sure that there's room for this neighbor... */ 752 if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { 753 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, 754 htonl(MROUTED_LEVEL), datalen); 755 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 756 datalen = 0; 757 ncount = 0; 758 } 759 760 /* Put out the header for this neighbor list... */ 761 if (ncount == 0) { 762 PUT_ADDR(v->uv_lcl_addr); 763 *p++ = v->uv_metric; 764 *p++ = v->uv_threshold; 765 ncount = p; 766 *p++ = 0; 767 datalen += 4 + 3; 768 } 769 770 PUT_ADDR(la->al_addr); 771 datalen += 4; 772 (*ncount)++; 773 } 774 } 775 776 if (datalen != 0) 777 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL), 778 datalen); 779 } 780 781 /* 782 * Send a list of all of our neighbors to the requestor, `src'. 783 */ 784 void 785 accept_neighbor_request2(src, dst) 786 u_int32_t src, dst; 787 { 788 vifi_t vifi; 789 struct uvif *v; 790 u_char *p, *ncount; 791 struct listaddr *la; 792 int datalen; 793 u_int32_t us, them = src; 794 795 /* Determine which of our addresses to use as the source of our response 796 * to this query. 797 */ 798 if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ 799 int udp; /* find best interface to reply on */ 800 struct sockaddr_in addr; 801 int addrlen = sizeof(addr); 802 803 addr.sin_family = AF_INET; 804 #if (defined(BSD) && (BSD >= 199103)) 805 addr.sin_len = sizeof addr; 806 #endif 807 addr.sin_addr.s_addr = dst; 808 addr.sin_port = htons(2000); /* any port over 1024 will do... */ 809 if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 810 || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 811 || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { 812 log(LOG_WARNING, errno, "Determining local address"); 813 close(udp); 814 return; 815 } 816 close(udp); 817 us = addr.sin_addr.s_addr; 818 } else /* query sent to us alone */ 819 us = dst; 820 821 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 822 datalen = 0; 823 824 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { 825 register u_short vflags = v->uv_flags; 826 register u_char rflags = 0; 827 if (vflags & VIFF_TUNNEL) 828 rflags |= DVMRP_NF_TUNNEL; 829 if (vflags & VIFF_SRCRT) 830 rflags |= DVMRP_NF_SRCRT; 831 if (vflags & VIFF_DOWN) 832 rflags |= DVMRP_NF_DOWN; 833 if (vflags & VIFF_DISABLED) 834 rflags |= DVMRP_NF_DISABLED; 835 if (vflags & VIFF_QUERIER) 836 rflags |= DVMRP_NF_QUERIER; 837 if (vflags & VIFF_LEAF) 838 rflags |= DVMRP_NF_LEAF; 839 ncount = 0; 840 la = v->uv_neighbors; 841 if (la == NULL) { 842 /* 843 * include down & disabled interfaces and interfaces on 844 * leaf nets. 845 */ 846 if (rflags & DVMRP_NF_TUNNEL) 847 rflags |= DVMRP_NF_DOWN; 848 if (datalen > MAX_DVMRP_DATA_LEN - 12) { 849 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, 850 htonl(MROUTED_LEVEL), datalen); 851 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 852 datalen = 0; 853 } 854 *(u_int*)p = v->uv_lcl_addr; 855 p += 4; 856 *p++ = v->uv_metric; 857 *p++ = v->uv_threshold; 858 *p++ = rflags; 859 *p++ = 1; 860 *(u_int*)p = v->uv_rmt_addr; 861 p += 4; 862 datalen += 12; 863 } else { 864 for ( ; la; la = la->al_next) { 865 /* Make sure that there's room for this neighbor... */ 866 if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { 867 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, 868 htonl(MROUTED_LEVEL), datalen); 869 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 870 datalen = 0; 871 ncount = 0; 872 } 873 /* Put out the header for this neighbor list... */ 874 if (ncount == 0) { 875 *(u_int*)p = v->uv_lcl_addr; 876 p += 4; 877 *p++ = v->uv_metric; 878 *p++ = v->uv_threshold; 879 *p++ = rflags; 880 ncount = p; 881 *p++ = 0; 882 datalen += 4 + 4; 883 } 884 *(u_int*)p = la->al_addr; 885 p += 4; 886 datalen += 4; 887 (*ncount)++; 888 } 889 } 890 } 891 if (datalen != 0) 892 send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), 893 datalen); 894 } 895 896 void 897 accept_info_request(src, dst, p, datalen) 898 u_int32_t src, dst; 899 u_char *p; 900 int datalen; 901 { 902 u_char *q; 903 int len; 904 int outlen = 0; 905 906 q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); 907 908 /* To be general, this must deal properly with breaking up over-sized 909 * packets. That implies passing a length to each function, and 910 * allowing each function to request to be called again. Right now, 911 * we're only implementing the one thing we are positive will fit into 912 * a single packet, so we wimp out. 913 */ 914 while (datalen > 0) { 915 len = 0; 916 switch (*p) { 917 case DVMRP_INFO_VERSION: 918 len = info_version(q); 919 break; 920 921 case DVMRP_INFO_NEIGHBORS: 922 default: 923 log(LOG_INFO, 0, "ignoring unknown info type %d", *p); 924 break; 925 } 926 *(q+1) = len++; 927 outlen += len * 4; 928 q += len * 4; 929 len = (*(p+1) + 1) * 4; 930 p += len; 931 datalen -= len; 932 } 933 934 if (outlen != 0) 935 send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY, 936 htonl(MROUTED_LEVEL), outlen); 937 } 938 939 /* 940 * Information response -- return version string 941 */ 942 static int 943 info_version(p) 944 char *p; 945 { 946 int len; 947 extern char versionstring[]; 948 949 *p++ = DVMRP_INFO_VERSION; 950 p++; /* skip over length */ 951 *p++ = 0; /* zero out */ 952 *p++ = 0; /* reserved fields */ 953 strcpy(p, versionstring); /* XXX strncpy!!! */ 954 955 len = strlen(versionstring); 956 return ((len + 3) / 4); 957 } 958 959 /* 960 * Process an incoming neighbor-list message. 961 */ 962 void 963 accept_neighbors(src, dst, p, datalen, level) 964 u_int32_t src, dst, level; 965 u_char *p; 966 int datalen; 967 { 968 log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s", 969 inet_fmt(src, s1), inet_fmt(dst, s2)); 970 } 971 972 973 /* 974 * Process an incoming neighbor-list message. 975 */ 976 void 977 accept_neighbors2(src, dst, p, datalen, level) 978 u_int32_t src, dst, level; 979 u_char *p; 980 int datalen; 981 { 982 log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", 983 inet_fmt(src, s1), inet_fmt(dst, s2)); 984 } 985 986 /* 987 * Process an incoming info reply message. 988 */ 989 void 990 accept_info_reply(src, dst, p, datalen) 991 u_int32_t src, dst; 992 u_char *p; 993 int datalen; 994 { 995 log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s", 996 inet_fmt(src, s1), inet_fmt(dst, s2)); 997 } 998 999 1000 /* 1001 * Update the neighbor entry for neighbor 'addr' on vif 'vifi'. 1002 * 'msgtype' is the type of DVMRP message received from the neighbor. 1003 * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise. 1004 */ 1005 int 1006 update_neighbor(vifi, addr, msgtype, p, datalen, level) 1007 vifi_t vifi; 1008 u_int32_t addr; 1009 int msgtype; 1010 char *p; 1011 int datalen; 1012 u_int32_t level; 1013 { 1014 register struct uvif *v; 1015 register struct listaddr *n; 1016 u_int32_t genid = 0; 1017 u_int32_t router; 1018 u_int32_t send_tables = 0; 1019 int do_reset = FALSE; 1020 int nflags; 1021 1022 v = &uvifs[vifi]; 1023 nflags = (level >> 16) & 0xff; 1024 1025 /* 1026 * Confirm that 'addr' is a valid neighbor address on vif 'vifi'. 1027 * IT IS ASSUMED that this was preceded by a call to find_vif(), which 1028 * checks that 'addr' is either a valid remote tunnel endpoint or a 1029 * non-broadcast address belonging to a directly-connected subnet. 1030 * Therefore, here we check only that 'addr' is not our own address 1031 * (due to an impostor or erroneous loopback) or an address of the form 1032 * {subnet,0} ("the unknown host"). These checks are not performed in 1033 * find_vif() because those types of address are acceptable for some 1034 * types of IGMP message (such as group membership reports). 1035 */ 1036 if (!(v->uv_flags & VIFF_TUNNEL) && 1037 (addr == v->uv_lcl_addr || 1038 addr == v->uv_subnet )) { 1039 log(LOG_WARNING, 0, 1040 "received DVMRP message from 'the unknown host' or self: %s", 1041 inet_fmt(addr, s1)); 1042 return (FALSE); 1043 } 1044 1045 /* 1046 * Look for addr in list of neighbors. 1047 */ 1048 for (n = v->uv_neighbors; n != NULL; n = n->al_next) { 1049 if (addr == n->al_addr) { 1050 break; 1051 } 1052 } 1053 1054 /* 1055 * Found it. Reset its timer, and check for a version change 1056 */ 1057 if (n) { 1058 n->al_timer = 0; 1059 1060 /* 1061 * update the neighbors version and protocol number 1062 * if changed => router went down and came up, 1063 * so take action immediately. 1064 */ 1065 if ((n->al_pv != (level & 0xff)) || 1066 (n->al_mv != ((level >> 8) & 0xff))) { 1067 1068 do_reset = TRUE; 1069 log(LOG_DEBUG, 0, 1070 "version change neighbor %s [old:%d.%d, new:%d.%d]", 1071 inet_fmt(addr, s1), 1072 n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff); 1073 1074 n->al_pv = level & 0xff; 1075 n->al_mv = (level >> 8) & 0xff; 1076 } 1077 } else { 1078 /* 1079 * If not found, add it to the list. If the neighbor has a lower 1080 * IP address than me, yield querier duties to it. 1081 */ 1082 log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x", 1083 inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, 1084 (level >> 16) & 0xff); 1085 1086 n = (struct listaddr *)malloc(sizeof(struct listaddr)); 1087 if (n == NULL) 1088 log(LOG_ERR, 0, "ran out of memory"); /* fatal */ 1089 1090 n->al_addr = addr; 1091 n->al_pv = level & 0xff; 1092 n->al_mv = (level >> 8) & 0xff; 1093 n->al_genid = 0; 1094 1095 time(&n->al_ctime); 1096 n->al_timer = 0; 1097 n->al_next = v->uv_neighbors; 1098 1099 /* 1100 * If we thought that we had no neighbors on this vif, send a route 1101 * report to the vif. If this is just a new neighbor on the same 1102 * vif, send the route report just to the new neighbor. 1103 */ 1104 if (v->uv_neighbors == NULL) { 1105 send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group; 1106 vifs_with_neighbors++; 1107 } else { 1108 send_tables = addr; 1109 } 1110 1111 v->uv_neighbors = n; 1112 1113 if (!(v->uv_flags & VIFF_TUNNEL) && 1114 ntohl(addr) < ntohl(v->uv_lcl_addr)) 1115 v->uv_flags &= ~VIFF_QUERIER; 1116 } 1117 1118 /* 1119 * Check if the router gen-ids are the same. 1120 * Need to reset the prune state of the router if not. 1121 * Also check for one-way interfaces by seeing if we are in our 1122 * neighbor's list of known routers. 1123 */ 1124 if (msgtype == DVMRP_PROBE) { 1125 1126 /* Check genid neighbor flag. Also check version number; 3.3 and 1127 * 3.4 didn't set this flag. */ 1128 if ((((level >> 16) & 0xff) & NF_GENID) || 1129 (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) { 1130 1131 int i; 1132 1133 if (datalen < 4) { 1134 log(LOG_WARNING, 0, 1135 "received truncated probe message from %s (len %d)", 1136 inet_fmt(addr, s1), datalen); 1137 return (FALSE); 1138 } 1139 1140 for (i = 0; i < 4; i++) 1141 ((char *)&genid)[i] = *p++; 1142 datalen -= 4; 1143 1144 if (n->al_genid == 0) 1145 n->al_genid = genid; 1146 else if (n->al_genid != genid) { 1147 log(LOG_DEBUG, 0, 1148 "new genid neigbor %s on vif %d [old:%x, new:%x]", 1149 inet_fmt(addr, s1), vifi, n->al_genid, genid); 1150 1151 n->al_genid = genid; 1152 do_reset = TRUE; 1153 } 1154 1155 /* 1156 * loop through router list and check for one-way ifs. 1157 */ 1158 1159 v->uv_flags |= VIFF_ONEWAY; 1160 1161 while (datalen > 0) { 1162 if (datalen < 4) { 1163 log(LOG_WARNING, 0, 1164 "received truncated probe message from %s (len %d)", 1165 inet_fmt(addr, s1), datalen); 1166 return (FALSE); 1167 } 1168 for (i = 0; i < 4; i++) 1169 ((char *)&router)[i] = *p++; 1170 datalen -= 4; 1171 if (router == v->uv_lcl_addr) { 1172 v->uv_flags &= ~VIFF_ONEWAY; 1173 break; 1174 } 1175 } 1176 } 1177 } 1178 if (n->al_flags != nflags) { 1179 n->al_flags = nflags; 1180 1181 if (n->al_flags & NF_LEAF) { 1182 /*XXX If we have non-leaf neighbors then we know we shouldn't 1183 * mark this vif as a leaf. For now we just count on other 1184 * probes and/or reports resetting the timer. */ 1185 if (!v->uv_leaf_timer) 1186 v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; 1187 } else { 1188 /* If we get a leaf to non-leaf transition, we *must* update 1189 * the routing table. */ 1190 if (v->uv_flags & VIFF_LEAF && send_tables == 0) 1191 send_tables = addr; 1192 v->uv_flags &= ~VIFF_LEAF; 1193 v->uv_leaf_timer = 0; 1194 } 1195 } 1196 if (do_reset) { 1197 reset_neighbor_state(vifi, addr); 1198 if (!send_tables) 1199 send_tables = addr; 1200 } 1201 if (send_tables) 1202 report(ALL_ROUTES, vifi, send_tables); 1203 1204 return (TRUE); 1205 } 1206 1207 1208 /* 1209 * On every timer interrupt, advance the timer in each neighbor and 1210 * group entry on every vif. 1211 */ 1212 void 1213 age_vifs() 1214 { 1215 register vifi_t vifi; 1216 register struct uvif *v; 1217 register struct listaddr *a, *prev_a, *n; 1218 register u_int32_t addr; 1219 1220 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { 1221 if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) { 1222 v->uv_flags |= VIFF_LEAF; 1223 } 1224 1225 for (prev_a = (struct listaddr *)&(v->uv_neighbors), 1226 a = v->uv_neighbors; 1227 a != NULL; 1228 prev_a = a, a = a->al_next) { 1229 1230 if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME) 1231 continue; 1232 1233 /* 1234 * Neighbor has expired; delete it from the neighbor list, 1235 * delete it from the 'dominants' and 'subordinates arrays of 1236 * any route entries and assume querier duties unless there is 1237 * another neighbor with a lower IP address than mine. 1238 */ 1239 addr = a->al_addr; 1240 prev_a->al_next = a->al_next; 1241 free((char *)a); 1242 a = prev_a; 1243 1244 delete_neighbor_from_routes(addr, vifi); 1245 1246 if (v->uv_neighbors == NULL) 1247 vifs_with_neighbors--; 1248 1249 v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; 1250 1251 if (!(v->uv_flags & VIFF_TUNNEL)) { 1252 v->uv_flags |= VIFF_QUERIER; 1253 for (n = v->uv_neighbors; n != NULL; n = n->al_next) { 1254 if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) { 1255 v->uv_flags &= ~VIFF_QUERIER; 1256 } 1257 if (!(n->al_flags & NF_LEAF)) { 1258 v->uv_leaf_timer = 0; 1259 } 1260 } 1261 } 1262 } 1263 } 1264 } 1265 1266 /* 1267 * Returns the neighbor info struct for a given neighbor 1268 */ 1269 struct listaddr * 1270 neighbor_info(vifi, addr) 1271 vifi_t vifi; 1272 u_int32_t addr; 1273 { 1274 struct listaddr *u; 1275 1276 for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next) 1277 if (u->al_addr == addr) 1278 return u; 1279 1280 return NULL; 1281 } 1282 1283 /* 1284 * Print the contents of the uvifs array on file 'fp'. 1285 */ 1286 void 1287 dump_vifs(fp) 1288 FILE *fp; 1289 { 1290 register vifi_t vifi; 1291 register struct uvif *v; 1292 register struct listaddr *a; 1293 register struct phaddr *p; 1294 struct sioc_vif_req v_req; 1295 1296 fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors); 1297 1298 if (vifs_with_neighbors == 1) 1299 fprintf(fp,"[This host is a leaf]\n\n"); 1300 1301 fprintf(fp, 1302 "\nVirtual Interface Table\n%s", 1303 "Vif Name Local-Address "); 1304 fprintf(fp, 1305 "M Thr Rate Flags\n"); 1306 1307 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { 1308 1309 fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ", 1310 vifi, 1311 v->uv_name, 1312 inet_fmt(v->uv_lcl_addr, s1), 1313 (v->uv_flags & VIFF_TUNNEL) ? 1314 "tunnel": 1315 "subnet", 1316 (v->uv_flags & VIFF_TUNNEL) ? 1317 inet_fmt(v->uv_rmt_addr, s2) : 1318 inet_fmts(v->uv_subnet, v->uv_subnetmask, s3), 1319 v->uv_metric, 1320 v->uv_threshold, 1321 v->uv_rate_limit); 1322 1323 if (v->uv_flags & VIFF_ONEWAY) fprintf(fp, " one-way"); 1324 if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down"); 1325 if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled"); 1326 if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier"); 1327 if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt"); 1328 if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf"); 1329 if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1"); 1330 fprintf(fp, "\n"); 1331 1332 if (v->uv_addrs != NULL) { 1333 fprintf(fp, " alternate subnets: %s\n", 1334 inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1)); 1335 for (p = v->uv_addrs->pa_next; p; p = p->pa_next) { 1336 fprintf(fp, " %s\n", 1337 inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); 1338 } 1339 } 1340 1341 if (v->uv_neighbors != NULL) { 1342 fprintf(fp, " peers: %s (%d.%d) (0x%x)\n", 1343 inet_fmt(v->uv_neighbors->al_addr, s1), 1344 v->uv_neighbors->al_pv, v->uv_neighbors->al_mv, 1345 v->uv_neighbors->al_flags); 1346 for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) { 1347 fprintf(fp, " %s (%d.%d) (0x%x)\n", 1348 inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, 1349 a->al_flags); 1350 } 1351 } 1352 1353 if (v->uv_groups != NULL) { 1354 fprintf(fp, " groups: %-15s\n", 1355 inet_fmt(v->uv_groups->al_addr, s1)); 1356 for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) { 1357 fprintf(fp, " %-15s\n", 1358 inet_fmt(a->al_addr, s1)); 1359 } 1360 } 1361 if (v->uv_acl != NULL) { 1362 struct vif_acl *acl; 1363 1364 fprintf(fp, " boundaries: %-18s\n", 1365 inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1)); 1366 for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) { 1367 fprintf(fp, " : %-18s\n", 1368 inet_fmts(acl->acl_addr, acl->acl_mask, s1)); 1369 } 1370 } 1371 v_req.vifi = vifi; 1372 if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { 1373 log(LOG_WARNING, 0, 1374 "SIOCGETVIFCNT fails"); 1375 } 1376 else { 1377 fprintf(fp, " pkts in : %ld\n", 1378 v_req.icount); 1379 fprintf(fp, " pkts out: %ld\n", 1380 v_req.ocount); 1381 } 1382 fprintf(fp, "\n"); 1383 } 1384 fprintf(fp, "\n"); 1385 } 1386 1387 /* 1388 * Time out record of a group membership on a vif 1389 */ 1390 static void 1391 DelVif(arg) 1392 void *arg; 1393 { 1394 cbk_t *cbk = (cbk_t *)arg; 1395 vifi_t vifi = cbk->vifi; 1396 struct uvif *v = &uvifs[vifi]; 1397 struct listaddr *a, **anp, *g = cbk->g; 1398 1399 /* 1400 * Group has expired 1401 * delete all kernel cache entries with this group 1402 */ 1403 if (g->al_query) 1404 DeleteTimer(g->al_query); 1405 1406 delete_lclgrp(vifi, g->al_addr); 1407 1408 anp = &(v->uv_groups); 1409 while ((a = *anp) != NULL) { 1410 if (a == g) { 1411 *anp = a->al_next; 1412 free((char *)a); 1413 } else { 1414 anp = &a->al_next; 1415 } 1416 } 1417 1418 free(cbk); 1419 } 1420 1421 /* 1422 * Set a timer to delete the record of a group membership on a vif. 1423 */ 1424 static int 1425 SetTimer(vifi, g) 1426 vifi_t vifi; 1427 struct listaddr *g; 1428 { 1429 cbk_t *cbk; 1430 1431 cbk = (cbk_t *) malloc(sizeof(cbk_t)); 1432 cbk->g = g; 1433 cbk->vifi = vifi; 1434 return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk); 1435 } 1436 1437 /* 1438 * Delete a timer that was set above. 1439 */ 1440 static int 1441 DeleteTimer(id) 1442 int id; 1443 { 1444 timer_clearTimer(id); 1445 return 0; 1446 } 1447 1448 /* 1449 * Send a group-specific query. 1450 */ 1451 static void 1452 SendQuery(arg) 1453 void *arg; 1454 { 1455 cbk_t *cbk = (cbk_t *)arg; 1456 register struct uvif *v = &uvifs[cbk->vifi]; 1457 1458 send_igmp(v->uv_lcl_addr, cbk->g->al_addr, 1459 IGMP_HOST_MEMBERSHIP_QUERY, 1460 cbk->q_time, cbk->g->al_addr, 0); 1461 cbk->g->al_query = 0; 1462 free(cbk); 1463 } 1464 1465 /* 1466 * Set a timer to send a group-specific query. 1467 */ 1468 static int 1469 SetQueryTimer(g, vifi, to_expire, q_time) 1470 struct listaddr *g; 1471 vifi_t vifi; 1472 int to_expire, q_time; 1473 { 1474 cbk_t *cbk; 1475 1476 cbk = (cbk_t *) malloc(sizeof(cbk_t)); 1477 cbk->g = g; 1478 cbk->q_time = q_time; 1479 cbk->vifi = vifi; 1480 return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk); 1481 } 1482