Annotation of embedaddon/mrouted/vif.c, revision 1.1
1.1 ! misho 1: /*
! 2: * The mrouted program is covered by the license in the accompanying file
! 3: * named "LICENSE". Use of the mrouted program represents acceptance of
! 4: * the terms and conditions listed in that file.
! 5: *
! 6: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
! 7: * Leland Stanford Junior University.
! 8: */
! 9:
! 10: #include "defs.h"
! 11: #include <fcntl.h>
! 12:
! 13: /*
! 14: * Exported variables.
! 15: */
! 16: struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
! 17: vifi_t numvifs; /* number of vifs in use */
! 18: int vifs_down; /* 1=>some interfaces are down */
! 19: int phys_vif; /* An enabled vif */
! 20: int udp_socket; /* Since the honkin' kernel doesn't support */
! 21: /* ioctls on raw IP sockets, we need a UDP */
! 22: /* socket as well as our IGMP (raw) socket. */
! 23: /* How dumb. */
! 24: int vifs_with_neighbors; /* == 1 if I am a leaf */
! 25:
! 26: /*
! 27: * Private variables.
! 28: */
! 29: struct listaddr *nbrs[MAXNBRS]; /* array of neighbors */
! 30:
! 31: typedef struct {
! 32: vifi_t vifi;
! 33: struct listaddr *g;
! 34: int q_time;
! 35: } cbk_t;
! 36:
! 37: /*
! 38: * Forward declarations.
! 39: */
! 40: static void start_vif(vifi_t vifi);
! 41: static void start_vif2(vifi_t vifi);
! 42: static void stop_vif(vifi_t vifi);
! 43: static void age_old_hosts(void);
! 44: static void send_probe_on_vif(struct uvif *v);
! 45: static void send_query(struct uvif *v);
! 46: static int info_version(u_char *p);
! 47: static void DelVif(void *arg);
! 48: static int SetTimer(vifi_t vifi, struct listaddr *g);
! 49: static int DeleteTimer(int id);
! 50: static void SendQuery(void *arg);
! 51: static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time);
! 52:
! 53: /*
! 54: * Initialize the virtual interfaces, but do not install
! 55: * them in the kernel. Start routing on all vifs that are
! 56: * not down or disabled.
! 57: */
! 58: void init_vifs(void)
! 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 if
! 73: * the kernel can't handle IOCTL's on the IGMP socket.)
! 74: */
! 75: #ifdef IOCTL_OK_ON_RAW_SOCKET
! 76: udp_socket = igmp_socket;
! 77: #else
! 78: if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
! 79: logit(LOG_ERR, errno, "UDP socket");
! 80: #endif
! 81: logit(LOG_INFO,0,"Getting vifs from kernel interfaces");
! 82: config_vifs_from_kernel();
! 83: logit(LOG_INFO,0,"Getting vifs from %s",configfilename);
! 84: config_vifs_from_file();
! 85:
! 86: /*
! 87: * Quit if there are fewer than two enabled vifs.
! 88: */
! 89: enabled_vifs = 0;
! 90: enabled_phyints = 0;
! 91: phys_vif = -1;
! 92: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 93: if (!(v->uv_flags & VIFF_DISABLED)) {
! 94: ++enabled_vifs;
! 95: if (!(v->uv_flags & VIFF_TUNNEL)) {
! 96: if (phys_vif == -1)
! 97: phys_vif = vifi;
! 98: ++enabled_phyints;
! 99: }
! 100: }
! 101: }
! 102: if (enabled_vifs < 2)
! 103: logit(LOG_ERR, 0, "Cannot forward: %s",
! 104: enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
! 105:
! 106: if (enabled_phyints == 0)
! 107: logit(LOG_WARNING, 0, "No enabled interfaces, forwarding via tunnels only");
! 108:
! 109: logit(LOG_INFO, 0, "Installing vifs in mrouted...");
! 110: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 111: if (!(v->uv_flags & VIFF_DISABLED)) {
! 112: if (!(v->uv_flags & VIFF_DOWN)) {
! 113: if (v->uv_flags & VIFF_TUNNEL)
! 114: logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
! 115: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
! 116: inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
! 117: else
! 118: logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
! 119: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 120: start_vif2(vifi);
! 121: } else logit(LOG_INFO, 0,
! 122: "%s is not yet up; vif #%u not in service",
! 123: v->uv_name, vifi);
! 124: }
! 125: }
! 126: }
! 127:
! 128: /*
! 129: * Initialize the passed vif with all appropriate default values.
! 130: * "t" is true if a tunnel, or false if a phyint.
! 131: */
! 132: void zero_vif(struct uvif *v, int t)
! 133: {
! 134: v->uv_flags = 0;
! 135: v->uv_metric = DEFAULT_METRIC;
! 136: v->uv_admetric = 0;
! 137: v->uv_threshold = DEFAULT_THRESHOLD;
! 138: v->uv_rate_limit = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT;
! 139: v->uv_lcl_addr = 0;
! 140: v->uv_rmt_addr = 0;
! 141: v->uv_dst_addr = t ? 0 : dvmrp_group;
! 142: v->uv_subnet = 0;
! 143: v->uv_subnetmask = 0;
! 144: v->uv_subnetbcast = 0;
! 145: v->uv_name[0] = '\0';
! 146: v->uv_groups = NULL;
! 147: v->uv_neighbors = NULL;
! 148: NBRM_CLRALL(v->uv_nbrmap);
! 149: v->uv_querier = NULL;
! 150: v->uv_igmpv1_warn = 0;
! 151: v->uv_prune_lifetime = 0;
! 152: v->uv_leaf_timer = 0;
! 153: v->uv_acl = NULL;
! 154: v->uv_addrs = NULL;
! 155: v->uv_filter = NULL;
! 156: v->uv_blasterbuf = NULL;
! 157: v->uv_blastercur = NULL;
! 158: v->uv_blasterend = NULL;
! 159: v->uv_blasterlen = 0;
! 160: v->uv_blastertimer = 0;
! 161: v->uv_nbrup = 0;
! 162: v->uv_icmp_warn = 0;
! 163: v->uv_nroutes = 0;
! 164: }
! 165:
! 166: /*
! 167: * Start routing on all virtual interfaces that are not down or
! 168: * administratively disabled.
! 169: */
! 170: void init_installvifs(void)
! 171: {
! 172: vifi_t vifi;
! 173: struct uvif *v;
! 174:
! 175: logit(LOG_INFO, 0, "Installing vifs in kernel...");
! 176: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 177: if (!(v->uv_flags & VIFF_DISABLED)) {
! 178: if (!(v->uv_flags & VIFF_DOWN)) {
! 179: if (v->uv_flags & VIFF_TUNNEL) {
! 180: logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
! 181: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
! 182: inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
! 183: } else {
! 184: logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
! 185: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 186: }
! 187: k_add_vif(vifi, &uvifs[vifi]);
! 188: } else {
! 189: logit(LOG_INFO, 0, "%s is not yet up; vif #%u not in service",
! 190: v->uv_name, vifi);
! 191: }
! 192: }
! 193: }
! 194: }
! 195:
! 196: /*
! 197: * See if any interfaces have changed from up state to down, or vice versa,
! 198: * including any non-multicast-capable interfaces that are in use as local
! 199: * tunnel end-points. Ignore interfaces that have been administratively
! 200: * disabled.
! 201: */
! 202: void check_vif_state(void)
! 203: {
! 204: register vifi_t vifi;
! 205: register struct uvif *v;
! 206: struct ifreq ifr;
! 207: static int checking_vifs = 0;
! 208:
! 209: /*
! 210: * If we get an error while checking, (e.g. two interfaces go down
! 211: * at once, and we decide to send a prune out one of the failed ones)
! 212: * then don't go into an infinite loop!
! 213: */
! 214: if (checking_vifs)
! 215: return;
! 216:
! 217: vifs_down = FALSE;
! 218: checking_vifs = 1;
! 219: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 220:
! 221: if (v->uv_flags & VIFF_DISABLED) continue;
! 222:
! 223: strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
! 224: if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
! 225: logit(LOG_ERR, errno, "Failed ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
! 226:
! 227: if (v->uv_flags & VIFF_DOWN) {
! 228: if (ifr.ifr_flags & IFF_UP) {
! 229: logit(LOG_NOTICE, 0, "%s has come up; vif #%u now in service",
! 230: v->uv_name, vifi);
! 231: v->uv_flags &= ~VIFF_DOWN;
! 232: start_vif(vifi);
! 233: }
! 234: else vifs_down = TRUE;
! 235: }
! 236: else {
! 237: if (!(ifr.ifr_flags & IFF_UP)) {
! 238: logit(LOG_NOTICE, 0, "%s has gone down; vif #%u taken out of service",
! 239: v->uv_name, vifi);
! 240: stop_vif(vifi);
! 241: v->uv_flags |= VIFF_DOWN;
! 242: vifs_down = TRUE;
! 243: }
! 244: }
! 245: }
! 246: checking_vifs = 0;
! 247: }
! 248:
! 249: /*
! 250: * Send a DVMRP message on the specified vif. If DVMRP messages are
! 251: * to be encapsulated and sent "inside" the tunnel, use the special
! 252: * encapsulator. If it's not a tunnel or DVMRP messages are to be
! 253: * sent "beside" the tunnel, as required by earlier versions of mrouted,
! 254: * then just send the message.
! 255: */
! 256: void send_on_vif(struct uvif *v, u_int32 dst, int code, size_t datalen)
! 257: {
! 258: u_int32 group = htonl(MROUTED_LEVEL |
! 259: ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS));
! 260:
! 261: /*
! 262: * The UNIX kernel will not decapsulate unicasts.
! 263: * Therefore, we don't send encapsulated unicasts.
! 264: */
! 265: if ((v->uv_flags & (VIFF_TUNNEL|VIFF_OTUNNEL)) == VIFF_TUNNEL &&
! 266: ((dst == 0) || IN_MULTICAST(ntohl(dst))))
! 267: send_ipip(v->uv_lcl_addr, dst ? dst : dvmrp_group, IGMP_DVMRP,
! 268: code, group, datalen, v);
! 269: else
! 270: send_igmp(v->uv_lcl_addr, dst ? dst : v->uv_dst_addr, IGMP_DVMRP,
! 271: code, group, datalen);
! 272: }
! 273:
! 274:
! 275: /*
! 276: * Send a probe message on vif v
! 277: */
! 278: static void send_probe_on_vif(struct uvif *v)
! 279: {
! 280: char *p;
! 281: size_t datalen = 0;
! 282: struct listaddr *nbr;
! 283: int i;
! 284:
! 285: if ((v->uv_flags & VIFF_PASSIVE && v->uv_neighbors == NULL) ||
! 286: (v->uv_flags & VIFF_FORCE_LEAF))
! 287: return;
! 288:
! 289: p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
! 290:
! 291: for (i = 0; i < 4; i++)
! 292: *p++ = ((char *)&(dvmrp_genid))[i];
! 293: datalen += 4;
! 294:
! 295: /*
! 296: * add the neighbor list on the interface to the message
! 297: */
! 298: nbr = v->uv_neighbors;
! 299:
! 300: while (nbr) {
! 301: for (i = 0; i < 4; i++)
! 302: *p++ = ((char *)&nbr->al_addr)[i];
! 303: datalen +=4;
! 304: nbr = nbr->al_next;
! 305: }
! 306:
! 307: send_on_vif(v, 0, DVMRP_PROBE, datalen);
! 308: }
! 309:
! 310: static void send_query(struct uvif *v)
! 311: {
! 312: IF_DEBUG(DEBUG_IGMP) {
! 313: logit(LOG_DEBUG, 0, "Sending %squery on vif %d",
! 314: (v->uv_flags & VIFF_IGMPV1) ? "v1 " : "",
! 315: v - uvifs);
! 316: }
! 317:
! 318: send_igmp(v->uv_lcl_addr, allhosts_group,
! 319: IGMP_MEMBERSHIP_QUERY,
! 320: (v->uv_flags & VIFF_IGMPV1) ? 0 :
! 321: IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
! 322: }
! 323:
! 324: /*
! 325: * Add a vifi to the kernel and start routing on it.
! 326: */
! 327: static void start_vif(vifi_t vifi)
! 328: {
! 329: /*
! 330: * Install the interface in the kernel's vif structure.
! 331: */
! 332: k_add_vif(vifi, &uvifs[vifi]);
! 333:
! 334: start_vif2(vifi);
! 335: }
! 336:
! 337: /*
! 338: * Add a vifi to all the user-level data structures but don't add
! 339: * it to the kernel yet.
! 340: */
! 341: static void start_vif2(vifi_t vifi)
! 342: {
! 343: struct uvif *v;
! 344: u_int32 src;
! 345: struct phaddr *p;
! 346:
! 347: v = &uvifs[vifi];
! 348: src = v->uv_lcl_addr;
! 349:
! 350: /*
! 351: * Update the existing route entries to take into account the new vif.
! 352: */
! 353: add_vif_to_routes(vifi);
! 354:
! 355: if (!(v->uv_flags & VIFF_TUNNEL)) {
! 356: /*
! 357: * Join the DVMRP multicast group on the interface.
! 358: * (This is not strictly necessary, since the kernel promiscuously
! 359: * receives IGMP packets addressed to ANY IP multicast group while
! 360: * multicast routing is enabled. However, joining the group allows
! 361: * this host to receive non-IGMP packets as well, such as 'pings'.)
! 362: */
! 363: k_join(dvmrp_group, src);
! 364:
! 365: /*
! 366: * Join the ALL-ROUTERS multicast group on the interface.
! 367: * This allows mtrace requests to loop back if they are run
! 368: * on the multicast router.
! 369: */
! 370: k_join(allrtrs_group, src);
! 371:
! 372: /*
! 373: * Install an entry in the routing table for the subnet to which
! 374: * the interface is connected.
! 375: */
! 376: start_route_updates();
! 377: update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL);
! 378: for (p = v->uv_addrs; p; p = p->pa_next) {
! 379: start_route_updates();
! 380: update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL);
! 381: }
! 382:
! 383: /*
! 384: * Until neighbors are discovered, assume responsibility for sending
! 385: * periodic group membership queries to the subnet. Send the first
! 386: * query.
! 387: */
! 388: v->uv_flags |= VIFF_QUERIER;
! 389: IF_DEBUG(DEBUG_IGMP) {
! 390: logit(LOG_DEBUG, 0, "Assuming querier duties on vif %d", vifi);
! 391: }
! 392: send_query(v);
! 393: }
! 394:
! 395: v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
! 396:
! 397: /*
! 398: * Send a probe via the new vif to look for neighbors.
! 399: */
! 400: send_probe_on_vif(v);
! 401: }
! 402:
! 403: /*
! 404: * Stop routing on the specified virtual interface.
! 405: */
! 406: static void stop_vif(vifi_t vifi)
! 407: {
! 408: struct uvif *v;
! 409: struct listaddr *a;
! 410: struct phaddr *p;
! 411:
! 412: v = &uvifs[vifi];
! 413:
! 414: if (!(v->uv_flags & VIFF_TUNNEL)) {
! 415: /*
! 416: * Depart from the DVMRP multicast group on the interface.
! 417: */
! 418: k_leave(dvmrp_group, v->uv_lcl_addr);
! 419:
! 420: /*
! 421: * Depart from the ALL-ROUTERS multicast group on the interface.
! 422: */
! 423: k_leave(allrtrs_group, v->uv_lcl_addr);
! 424:
! 425: /*
! 426: * Update the entry in the routing table for the subnet to which
! 427: * the interface is connected, to take into account the interface
! 428: * failure.
! 429: */
! 430: start_route_updates();
! 431: update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL);
! 432: for (p = v->uv_addrs; p; p = p->pa_next) {
! 433: start_route_updates();
! 434: update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL);
! 435: }
! 436:
! 437: /*
! 438: * Discard all group addresses. (No need to tell kernel;
! 439: * the k_del_vif() call, below, will clean up kernel state.)
! 440: */
! 441: while (v->uv_groups != NULL) {
! 442: a = v->uv_groups;
! 443: v->uv_groups = a->al_next;
! 444: free((char *)a);
! 445: }
! 446:
! 447: IF_DEBUG(DEBUG_IGMP) {
! 448: logit(LOG_DEBUG, 0, "Releasing querier duties on vif %d", vifi);
! 449: }
! 450: v->uv_flags &= ~VIFF_QUERIER;
! 451: }
! 452:
! 453: /*
! 454: * Update the existing route entries to take into account the vif failure.
! 455: */
! 456: delete_vif_from_routes(vifi);
! 457:
! 458: /*
! 459: * Delete the interface from the kernel's vif structure.
! 460: */
! 461: k_del_vif(vifi, v);
! 462:
! 463: /*
! 464: * Discard all neighbor addresses.
! 465: */
! 466: if (!NBRM_ISEMPTY(v->uv_nbrmap))
! 467: vifs_with_neighbors--;
! 468:
! 469: while (v->uv_neighbors != NULL) {
! 470: a = v->uv_neighbors;
! 471: v->uv_neighbors = a->al_next;
! 472: nbrs[a->al_index] = NULL;
! 473: free((char *)a);
! 474: }
! 475: NBRM_CLRALL(v->uv_nbrmap);
! 476: }
! 477:
! 478:
! 479: /*
! 480: * stop routing on all vifs
! 481: */
! 482: void stop_all_vifs(void)
! 483: {
! 484: vifi_t vifi;
! 485: struct uvif *v;
! 486: struct listaddr *a;
! 487: struct vif_acl *acl;
! 488:
! 489: for (vifi = 0; vifi < numvifs; vifi++) {
! 490: v = &uvifs[vifi];
! 491: while (v->uv_groups != NULL) {
! 492: a = v->uv_groups;
! 493: v->uv_groups = a->al_next;
! 494: free((char *)a);
! 495: }
! 496: while (v->uv_neighbors != NULL) {
! 497: a = v->uv_neighbors;
! 498: v->uv_neighbors = a->al_next;
! 499: nbrs[a->al_index] = NULL;
! 500: free((char *)a);
! 501: }
! 502: while (v->uv_acl != NULL) {
! 503: acl = v->uv_acl;
! 504: v->uv_acl = acl->acl_next;
! 505: free((char *)acl);
! 506: }
! 507: }
! 508: }
! 509:
! 510:
! 511: /*
! 512: * Find the virtual interface from which an incoming packet arrived,
! 513: * based on the packet's source and destination IP addresses.
! 514: */
! 515: vifi_t find_vif(u_int32 src, u_int32 dst)
! 516: {
! 517: vifi_t vifi;
! 518: struct uvif *v;
! 519: struct phaddr *p;
! 520:
! 521: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 522: if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
! 523: if (v->uv_flags & VIFF_TUNNEL) {
! 524: if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr ||
! 525: dst == dvmrp_group))
! 526: return(vifi);
! 527: }
! 528: else {
! 529: if ((src & v->uv_subnetmask) == v->uv_subnet &&
! 530: ((v->uv_subnetmask == 0xffffffff) ||
! 531: (src != v->uv_subnetbcast)))
! 532: return(vifi);
! 533: for (p=v->uv_addrs; p; p=p->pa_next) {
! 534: if ((src & p->pa_subnetmask) == p->pa_subnet &&
! 535: ((p->pa_subnetmask == 0xffffffff) ||
! 536: (src != p->pa_subnetbcast)))
! 537: return(vifi);
! 538: }
! 539: }
! 540: }
! 541: }
! 542: return (NO_VIF);
! 543: }
! 544:
! 545: static void age_old_hosts(void)
! 546: {
! 547: vifi_t vifi;
! 548: struct uvif *v;
! 549: struct listaddr *g;
! 550:
! 551: /*
! 552: * Decrement the old-hosts-present timer for each
! 553: * active group on each vif.
! 554: */
! 555: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
! 556: for (g = v->uv_groups; g != NULL; g = g->al_next)
! 557: if (g->al_old)
! 558: g->al_old--;
! 559: }
! 560:
! 561:
! 562: /*
! 563: * Send group membership queries on each interface for which I am querier.
! 564: * Note that technically, there should be a timer per interface, as the
! 565: * dynamics of querier election can cause the "right" time to send a
! 566: * query to be different on different interfaces. However, this simple
! 567: * implementation only ever sends queries sooner than the "right" time,
! 568: * so can not cause loss of membership (but can send more packets than
! 569: * necessary)
! 570: */
! 571: void query_groups(void)
! 572: {
! 573: vifi_t vifi;
! 574: struct uvif *v;
! 575:
! 576: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 577: if (v->uv_flags & VIFF_QUERIER) {
! 578: send_query(v);
! 579: }
! 580: }
! 581: age_old_hosts();
! 582: }
! 583:
! 584: /*
! 585: * Process an incoming host membership query. Warn about
! 586: * IGMP version mismatches, perform querier election, and
! 587: * handle group-specific queries when we're not the querier.
! 588: */
! 589: void accept_membership_query(u_int32 src, u_int32 dst, u_int32 group, int tmo)
! 590: {
! 591: vifi_t vifi;
! 592: struct uvif *v;
! 593:
! 594: vifi = find_vif(src, dst);
! 595: if (vifi == NO_VIF || (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
! 596: logit(LOG_INFO, 0, "Ignoring group membership query from non-adjacent host %s",
! 597: inet_fmt(src, s1, sizeof(s1)));
! 598: return;
! 599: }
! 600:
! 601: v = &uvifs[vifi];
! 602: if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) ||
! 603: (tmo != 0 && (v->uv_flags & VIFF_IGMPV1))) {
! 604: int i;
! 605:
! 606: /*
! 607: * Exponentially back-off warning rate
! 608: */
! 609: i = ++v->uv_igmpv1_warn;
! 610: while (i && !(i & 1))
! 611: i >>= 1;
! 612:
! 613: if (i == 1) {
! 614: logit(LOG_WARNING, 0, "Received IGMP%s report from %s on vif %d, %s",
! 615: tmo == 0 ? "v1" : "v2", inet_fmt(src, s1, sizeof(s1)), vifi,
! 616: tmo == 0 ? "please configure vif for IGMPv1" : "but I am configured for IGMPv1");
! 617: }
! 618: }
! 619:
! 620: if (v->uv_querier == NULL || v->uv_querier->al_addr != src) {
! 621: /*
! 622: * This might be:
! 623: * - A query from a new querier, with a lower source address
! 624: * than the current querier (who might be me)
! 625: * - A query from a new router that just started up and doesn't
! 626: * know who the querier is.
! 627: */
! 628: if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr) : ntohl(v->uv_lcl_addr))) {
! 629: IF_DEBUG(DEBUG_IGMP) {
! 630: logit(LOG_DEBUG, 0, "New querier %s (was %s) on vif %d", inet_fmt(src, s1, sizeof(s1)),
! 631: v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2, sizeof(s2)) : "me", vifi);
! 632: }
! 633:
! 634: if (!v->uv_querier) {
! 635: v->uv_querier = (struct listaddr *)malloc(sizeof(struct listaddr));
! 636: v->uv_flags &= ~VIFF_QUERIER;
! 637: }
! 638:
! 639: if (v->uv_querier) {
! 640: time(&v->uv_querier->al_ctime);
! 641: v->uv_querier->al_addr = src;
! 642: }
! 643: } else {
! 644: IF_DEBUG(DEBUG_IGMP) {
! 645: logit(LOG_DEBUG, 0, "Ignoring query from %s; querier on vif %d is still %s",
! 646: inet_fmt(src, s1, sizeof(s1)), vifi,
! 647: v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2, sizeof(s2)) : "me");
! 648: }
! 649: return;
! 650: }
! 651: }
! 652:
! 653: /*
! 654: * Reset the timer since we've received a query.
! 655: */
! 656: if (v->uv_querier && src == v->uv_querier->al_addr)
! 657: v->uv_querier->al_timer = 0;
! 658:
! 659: /*
! 660: * If this is a Group-Specific query which we did not source,
! 661: * we must set our membership timer to [Last Member Query Count] *
! 662: * the [Max Response Time] in the packet.
! 663: */
! 664: if (!(v->uv_flags & (VIFF_IGMPV1|VIFF_QUERIER))
! 665: && group != 0 && src != v->uv_lcl_addr) {
! 666: struct listaddr *g;
! 667:
! 668: IF_DEBUG(DEBUG_IGMP) {
! 669: logit(LOG_DEBUG, 0, "Group-specific membership query for %s from %s on vif %d, timer %d",
! 670: inet_fmt(group, s2, sizeof(s2)),
! 671: inet_fmt(src, s1, sizeof(s1)), vifi, tmo);
! 672: }
! 673:
! 674: for (g = v->uv_groups; g != NULL; g = g->al_next) {
! 675: if (group == g->al_addr && g->al_query == 0) {
! 676: /* setup a timeout to remove the group membership */
! 677: if (g->al_timerid)
! 678: g->al_timerid = DeleteTimer(g->al_timerid);
! 679:
! 680: /* use al_query to record our presence in last-member state */
! 681: g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT * tmo / IGMP_TIMER_SCALE;
! 682: g->al_query = -1;
! 683: g->al_timerid = SetTimer(vifi, g);
! 684:
! 685: IF_DEBUG(DEBUG_IGMP) {
! 686: logit(LOG_DEBUG, 0, "Timer for grp %s on vif %d set to %d",
! 687: inet_fmt(group, s2, sizeof(s2)), vifi, g->al_timer);
! 688: }
! 689: break;
! 690: }
! 691: }
! 692: }
! 693: }
! 694:
! 695: /*
! 696: * Process an incoming group membership report.
! 697: */
! 698: void accept_group_report(u_int32 src, u_int32 dst, u_int32 group, int r_type)
! 699: {
! 700: vifi_t vifi;
! 701: struct uvif *v;
! 702: struct listaddr *g;
! 703:
! 704: if ((vifi = find_vif(src, dst)) == NO_VIF ||
! 705: (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
! 706: logit(LOG_INFO, 0, "Ignoring group membership report from non-adjacent host %s",
! 707: inet_fmt(src, s1, sizeof(s1)));
! 708: return;
! 709: }
! 710:
! 711: v = &uvifs[vifi];
! 712:
! 713: /*
! 714: * Look for the group in our group list; if found, reset its timer.
! 715: */
! 716: for (g = v->uv_groups; g != NULL; g = g->al_next) {
! 717: if (group == g->al_addr) {
! 718: if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
! 719: g->al_old = OLD_AGE_THRESHOLD;
! 720:
! 721: g->al_reporter = src;
! 722:
! 723: /** delete old timers, set a timer for expiration **/
! 724: g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL;
! 725: if (g->al_query)
! 726: g->al_query = DeleteTimer(g->al_query);
! 727: if (g->al_timerid)
! 728: g->al_timerid = DeleteTimer(g->al_timerid);
! 729: g->al_timerid = SetTimer(vifi, g);
! 730: break;
! 731: }
! 732: }
! 733:
! 734: /*
! 735: * If not found, add it to the list and update kernel cache.
! 736: */
! 737: if (g == NULL) {
! 738: g = (struct listaddr *)malloc(sizeof(struct listaddr));
! 739: if (g == NULL) {
! 740: logit(LOG_ERR, 0, "Malloc failed in vif.c:accept_group_report()\n"); /* FATAL! */
! 741: return; /* NOTREACHED */
! 742: }
! 743:
! 744: g->al_addr = group;
! 745: if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
! 746: g->al_old = OLD_AGE_THRESHOLD;
! 747: else
! 748: g->al_old = 0;
! 749:
! 750: /** set a timer for expiration **/
! 751: g->al_query = 0;
! 752: g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL;
! 753: g->al_reporter = src;
! 754: g->al_timerid = SetTimer(vifi, g);
! 755: g->al_next = v->uv_groups;
! 756: v->uv_groups = g;
! 757: time(&g->al_ctime);
! 758:
! 759: update_lclgrp(vifi, group);
! 760: }
! 761:
! 762: /*
! 763: * Check if a graft is necessary for this group
! 764: */
! 765: chkgrp_graft(vifi, group);
! 766: }
! 767:
! 768: /*
! 769: * Process an incoming IGMPv2 Leave Group message.
! 770: */
! 771: void accept_leave_message(u_int32 src, u_int32 dst, u_int32 group)
! 772: {
! 773: vifi_t vifi;
! 774: struct uvif *v;
! 775: struct listaddr *g;
! 776:
! 777: if ((vifi = find_vif(src, dst)) == NO_VIF ||
! 778: (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
! 779: logit(LOG_INFO, 0, "Ignoring group leave report from non-adjacent host %s",
! 780: inet_fmt(src, s1, sizeof(s1)));
! 781: return;
! 782: }
! 783:
! 784: v = &uvifs[vifi];
! 785:
! 786: if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
! 787: return;
! 788:
! 789: /*
! 790: * Look for the group in our group list in order to set up a short-timeout
! 791: * query.
! 792: */
! 793: for (g = v->uv_groups; g != NULL; g = g->al_next) {
! 794: if (group == g->al_addr) {
! 795: IF_DEBUG(DEBUG_IGMP) {
! 796: logit(LOG_DEBUG, 0, "[vif.c, _accept_leave_message] %d %d \n",
! 797: g->al_old, g->al_query);
! 798: }
! 799:
! 800: /* Ignore the leave message if there are old hosts present */
! 801: if (g->al_old)
! 802: return;
! 803:
! 804: /* still waiting for a reply to a query, ignore the leave */
! 805: if (g->al_query)
! 806: return;
! 807:
! 808: /** delete old timer set a timer for expiration **/
! 809: if (g->al_timerid)
! 810: g->al_timerid = DeleteTimer(g->al_timerid);
! 811:
! 812: #if IGMP_LAST_MEMBER_QUERY_COUNT != 2
! 813: This code needs to be updated to keep a counter of the number
! 814: of queries remaining.
! 815: #endif
! 816: /** send a group specific querry **/
! 817: g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL *
! 818: (IGMP_LAST_MEMBER_QUERY_COUNT + 1);
! 819: send_igmp(v->uv_lcl_addr, g->al_addr,
! 820: IGMP_MEMBERSHIP_QUERY,
! 821: IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE,
! 822: g->al_addr, 0);
! 823: g->al_query = SetQueryTimer(g, vifi,
! 824: IGMP_LAST_MEMBER_QUERY_INTERVAL,
! 825: IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE);
! 826: g->al_timerid = SetTimer(vifi, g);
! 827: break;
! 828: }
! 829: }
! 830: }
! 831:
! 832:
! 833: /*
! 834: * Send a periodic probe on all vifs.
! 835: * Useful to determine one-way interfaces.
! 836: * Detect neighbor loss faster.
! 837: */
! 838: void probe_for_neighbors(void)
! 839: {
! 840: vifi_t vifi;
! 841: struct uvif *v;
! 842:
! 843: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 844: if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
! 845: send_probe_on_vif(v);
! 846: }
! 847: }
! 848: }
! 849:
! 850:
! 851: /*
! 852: * Send a list of all of our neighbors to the requestor, `src'.
! 853: */
! 854: void accept_neighbor_request(u_int32 src, u_int32 UNUSED dst)
! 855: {
! 856: vifi_t vifi;
! 857: struct uvif *v;
! 858: u_char *p, *ncount;
! 859: struct listaddr *la;
! 860: int datalen;
! 861: u_int32 temp_addr, them = src;
! 862:
! 863: #define PUT_ADDR(a) temp_addr = ntohl(a); \
! 864: *p++ = temp_addr >> 24; \
! 865: *p++ = (temp_addr >> 16) & 0xFF; \
! 866: *p++ = (temp_addr >> 8) & 0xFF; \
! 867: *p++ = temp_addr & 0xFF;
! 868:
! 869: p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 870: datalen = 0;
! 871:
! 872: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 873: if (v->uv_flags & VIFF_DISABLED)
! 874: continue;
! 875:
! 876: ncount = 0;
! 877:
! 878: for (la = v->uv_neighbors; la; la = la->al_next) {
! 879:
! 880: /* Make sure that there's room for this neighbor... */
! 881: if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
! 882: send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
! 883: htonl(MROUTED_LEVEL), datalen);
! 884: p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 885: datalen = 0;
! 886: ncount = 0;
! 887: }
! 888:
! 889: /* Put out the header for this neighbor list... */
! 890: if (ncount == 0) {
! 891: PUT_ADDR(v->uv_lcl_addr);
! 892: *p++ = v->uv_metric;
! 893: *p++ = v->uv_threshold;
! 894: ncount = p;
! 895: *p++ = 0;
! 896: datalen += 4 + 3;
! 897: }
! 898:
! 899: PUT_ADDR(la->al_addr);
! 900: datalen += 4;
! 901: (*ncount)++;
! 902: }
! 903: }
! 904:
! 905: if (datalen != 0)
! 906: send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
! 907: htonl(MROUTED_LEVEL), datalen);
! 908: }
! 909:
! 910: /*
! 911: * Send a list of all of our neighbors to the requestor, `src'.
! 912: */
! 913: void accept_neighbor_request2(u_int32 src, u_int32 UNUSED dst)
! 914: {
! 915: vifi_t vifi;
! 916: struct uvif *v;
! 917: u_char *p, *ncount;
! 918: struct listaddr *la;
! 919: int datalen;
! 920: u_int32 them = src;
! 921:
! 922: p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 923: datalen = 0;
! 924:
! 925: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 926: register u_int16_t vflags = v->uv_flags;
! 927: register u_char rflags = 0;
! 928: if (vflags & VIFF_TUNNEL)
! 929: rflags |= DVMRP_NF_TUNNEL;
! 930: if (vflags & VIFF_SRCRT)
! 931: rflags |= DVMRP_NF_SRCRT;
! 932: if (vflags & VIFF_DOWN)
! 933: rflags |= DVMRP_NF_DOWN;
! 934: if (vflags & VIFF_DISABLED)
! 935: rflags |= DVMRP_NF_DISABLED;
! 936: if (vflags & VIFF_QUERIER)
! 937: rflags |= DVMRP_NF_QUERIER;
! 938: if (vflags & VIFF_LEAF)
! 939: rflags |= DVMRP_NF_LEAF;
! 940: ncount = 0;
! 941: la = v->uv_neighbors;
! 942: if (la == NULL) {
! 943: /*
! 944: * include down & disabled interfaces and interfaces on
! 945: * leaf nets.
! 946: */
! 947: if (rflags & DVMRP_NF_TUNNEL)
! 948: rflags |= DVMRP_NF_DOWN;
! 949: if (datalen > MAX_DVMRP_DATA_LEN - 12) {
! 950: send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
! 951: htonl(MROUTED_LEVEL), datalen);
! 952: p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 953: datalen = 0;
! 954: }
! 955: *(u_int*)p = v->uv_lcl_addr;
! 956: p += 4;
! 957: *p++ = v->uv_metric;
! 958: *p++ = v->uv_threshold;
! 959: *p++ = rflags;
! 960: *p++ = 1;
! 961: *(u_int*)p = v->uv_rmt_addr;
! 962: p += 4;
! 963: datalen += 12;
! 964: } else {
! 965: for ( ; la; la = la->al_next) {
! 966: /* Make sure that there's room for this neighbor... */
! 967: if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
! 968: send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
! 969: htonl(MROUTED_LEVEL), datalen);
! 970: p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 971: datalen = 0;
! 972: ncount = 0;
! 973: }
! 974: /* Put out the header for this neighbor list... */
! 975: if (ncount == 0) {
! 976: /* If it's a one-way tunnel, mark it down. */
! 977: if (rflags & DVMRP_NF_TUNNEL && la->al_flags & NBRF_ONEWAY)
! 978: rflags |= DVMRP_NF_DOWN;
! 979: *(u_int*)p = v->uv_lcl_addr;
! 980: p += 4;
! 981: *p++ = v->uv_metric;
! 982: *p++ = v->uv_threshold;
! 983: *p++ = rflags;
! 984: ncount = p;
! 985: *p++ = 0;
! 986: datalen += 4 + 4;
! 987: }
! 988: /* Don't report one-way peering on phyint at all */
! 989: if (!(rflags & DVMRP_NF_TUNNEL) && la->al_flags & NBRF_ONEWAY)
! 990: continue;
! 991: *(u_int*)p = la->al_addr;
! 992: p += 4;
! 993: datalen += 4;
! 994: (*ncount)++;
! 995: }
! 996: if (*ncount == 0) {
! 997: *(u_int*)p = v->uv_rmt_addr;
! 998: p += 4;
! 999: datalen += 4;
! 1000: (*ncount)++;
! 1001: }
! 1002: }
! 1003: }
! 1004: if (datalen != 0)
! 1005: send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
! 1006: htonl(MROUTED_LEVEL), datalen);
! 1007: }
! 1008:
! 1009: void accept_info_request(u_int32 src, u_int32 UNUSED dst, u_char *p, size_t datalen)
! 1010: {
! 1011: u_char *q;
! 1012: int len;
! 1013: int outlen = 0;
! 1014:
! 1015: q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
! 1016:
! 1017: /* To be general, this must deal properly with breaking up over-sized
! 1018: * packets. That implies passing a length to each function, and
! 1019: * allowing each function to request to be called again. Right now,
! 1020: * we're only implementing the one thing we are positive will fit into
! 1021: * a single packet, so we wimp out.
! 1022: */
! 1023: while (datalen > 0) {
! 1024: len = 0;
! 1025: switch (*p) {
! 1026: case DVMRP_INFO_VERSION:
! 1027: len = info_version(q);
! 1028: break;
! 1029:
! 1030: case DVMRP_INFO_NEIGHBORS:
! 1031: default:
! 1032: logit(LOG_INFO, 0, "Ignoring unknown info type %d", *p);
! 1033: break;
! 1034: }
! 1035: *(q+1) = len++;
! 1036: outlen += len * 4;
! 1037: q += len * 4;
! 1038: len = (*(p+1) + 1) * 4;
! 1039: p += len;
! 1040: datalen -= len;
! 1041: }
! 1042:
! 1043: if (outlen != 0)
! 1044: send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
! 1045: htonl(MROUTED_LEVEL), outlen);
! 1046: }
! 1047:
! 1048: /*
! 1049: * Information response -- return version string
! 1050: */
! 1051: static int info_version(u_char *p)
! 1052: {
! 1053: int len;
! 1054:
! 1055: *p++ = DVMRP_INFO_VERSION;
! 1056: p++; /* skip over length */
! 1057: *p++ = 0; /* zero out */
! 1058: *p++ = 0; /* reserved fields */
! 1059: /* XXX: We use sizeof(versionstring) instead of the available
! 1060: * space in send_buf[] because that buffer is 8192 bytes.
! 1061: * It is not very likely our versionstring will ever be
! 1062: * as long as 100 bytes, but it's better to limit the amount
! 1063: * of data copied to send_buf since we do not want to risk
! 1064: * sending MAX size frames. */
! 1065: len = strlcpy((char *)p, versionstring, sizeof(versionstring));
! 1066:
! 1067: return ((len + 3) / 4);
! 1068: }
! 1069:
! 1070: /*
! 1071: * Process an incoming neighbor-list message.
! 1072: */
! 1073: void accept_neighbors(u_int32_t src, u_int32_t dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
! 1074: {
! 1075: logit(LOG_INFO, 0, "Ignoring spurious DVMRP neighbor list from %s to %s",
! 1076: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
! 1077: }
! 1078:
! 1079:
! 1080: /*
! 1081: * Process an incoming neighbor-list message.
! 1082: */
! 1083: void accept_neighbors2(u_int32 src, u_int32 dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32 UNUSED level)
! 1084: {
! 1085: IF_DEBUG(DEBUG_PKT) {
! 1086: logit(LOG_DEBUG, 0, "Ignoring spurious DVMRP neighbor list2 from %s to %s",
! 1087: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
! 1088: }
! 1089: }
! 1090:
! 1091: /*
! 1092: * Process an incoming info reply message.
! 1093: */
! 1094: void accept_info_reply(u_int32 src, u_int32 dst, u_char UNUSED *p, size_t UNUSED datalen)
! 1095: {
! 1096: IF_DEBUG(DEBUG_PKT) {
! 1097: logit(LOG_DEBUG, 0, "Ignoring spurious DVMRP info reply from %s to %s",
! 1098: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
! 1099: }
! 1100: }
! 1101:
! 1102:
! 1103: /*
! 1104: * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
! 1105: * 'msgtype' is the type of DVMRP message received from the neighbor.
! 1106: * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise.
! 1107: */
! 1108: struct listaddr *update_neighbor(vifi_t vifi, u_int32 addr, int msgtype, char *p, size_t datalen, u_int32 level)
! 1109: {
! 1110: struct uvif *v;
! 1111: struct listaddr *n;
! 1112: int pv = level & 0xff;
! 1113: int mv = (level >> 8) & 0xff;
! 1114: int has_genid = 0;
! 1115: int in_router_list = 0;
! 1116: int dvmrpspec = 0;
! 1117: u_int32 genid;
! 1118: u_int32 send_tables = 0;
! 1119: size_t i;
! 1120: int do_reset = FALSE;
! 1121:
! 1122: v = &uvifs[vifi];
! 1123:
! 1124: /*
! 1125: * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
! 1126: * IT IS ASSUMED that this was preceded by a call to find_vif(), which
! 1127: * checks that 'addr' is either a valid remote tunnel endpoint or a
! 1128: * non-broadcast address belonging to a directly-connected subnet.
! 1129: * Therefore, here we check only that 'addr' is not our own address
! 1130: * (due to an impostor or erroneous loopback) or an address of the form
! 1131: * {subnet,0} ("the unknown host"). These checks are not performed in
! 1132: * find_vif() because those types of address are acceptable for some
! 1133: * types of IGMP message (such as group membership reports).
! 1134: */
! 1135: if (!(v->uv_flags & VIFF_TUNNEL) && (addr == v->uv_lcl_addr || addr == v->uv_subnet )) {
! 1136: logit(LOG_WARNING, 0, "Received DVMRP message from %s: %s",
! 1137: (addr == v->uv_lcl_addr) ? "self (check device loopback)" : "'the unknown host'",
! 1138: inet_fmt(addr, s1, sizeof(s1)));
! 1139: return NULL;
! 1140: }
! 1141:
! 1142: /*
! 1143: * Ignore all neighbors on vifs forced into leaf mode
! 1144: */
! 1145: if (v->uv_flags & VIFF_FORCE_LEAF) {
! 1146: return NULL;
! 1147: }
! 1148:
! 1149: /*
! 1150: * mrouted's version 3.3 and later include the generation ID
! 1151: * and the list of neighbors on the vif in their probe messages.
! 1152: */
! 1153: if (msgtype == DVMRP_PROBE && ((pv == 3 && mv > 2) ||
! 1154: (pv > 3 && pv < 10))) {
! 1155: u_int32 router;
! 1156:
! 1157: IF_DEBUG(DEBUG_PEER) {
! 1158: logit(LOG_DEBUG, 0, "Checking probe from %s (%d.%d) on vif %d",
! 1159: inet_fmt(addr, s1, sizeof(s1)), pv, mv, vifi);
! 1160: }
! 1161:
! 1162: if (datalen < 4) {
! 1163: logit(LOG_WARNING, 0, "Received truncated probe message from %s (len %d)",
! 1164: inet_fmt(addr, s1, sizeof(s1)), datalen);
! 1165: return NULL;
! 1166: }
! 1167:
! 1168: has_genid = 1;
! 1169:
! 1170: for (i = 0; i < 4; i++)
! 1171: ((char *)&genid)[i] = *p++;
! 1172: datalen -= 4;
! 1173:
! 1174: while (datalen > 0) {
! 1175: if (datalen < 4) {
! 1176: logit(LOG_WARNING, 0, "Received truncated probe message from %s (len %d)",
! 1177: inet_fmt(addr, s1, sizeof(s1)), datalen);
! 1178: return NULL;
! 1179: }
! 1180:
! 1181: for (i = 0; i < 4; i++)
! 1182: ((char *)&router)[i] = *p++;
! 1183: datalen -= 4;
! 1184:
! 1185: if (router == v->uv_lcl_addr) {
! 1186: in_router_list = 1;
! 1187: break;
! 1188: }
! 1189: }
! 1190: }
! 1191:
! 1192: if ((pv == 3 && mv == 255) || (pv > 3 && pv < 10))
! 1193: dvmrpspec = 1;
! 1194:
! 1195: /*
! 1196: * Look for addr in list of neighbors.
! 1197: */
! 1198: for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
! 1199: if (addr == n->al_addr) {
! 1200: break;
! 1201: }
! 1202: }
! 1203:
! 1204: if (n == NULL) {
! 1205: /*
! 1206: * New neighbor.
! 1207: *
! 1208: * If this neighbor follows the DVMRP spec, start the probe
! 1209: * handshake. If not, then it doesn't require the probe
! 1210: * handshake, so establish the peering immediately.
! 1211: */
! 1212: if (dvmrpspec && (msgtype != DVMRP_PROBE))
! 1213: return NULL;
! 1214:
! 1215: for (i = 0; i < MAXNBRS; i++)
! 1216: if (nbrs[i] == NULL)
! 1217: break;
! 1218:
! 1219: if (i == MAXNBRS) {
! 1220: /* XXX This is a severe new restriction. */
! 1221: /* XXX want extensible bitmaps! */
! 1222: logit(LOG_ERR, 0, "Cannot handle %dth neighbor %s on vif %d!",
! 1223: MAXNBRS, inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1224: return NULL; /* NOTREACHED */
! 1225: }
! 1226:
! 1227: /*
! 1228: * Add it to our list of neighbors.
! 1229: */
! 1230: IF_DEBUG(DEBUG_PEER) {
! 1231: logit(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d",
! 1232: inet_fmt(addr, s1, sizeof(s1)), vifi, level & 0xff, (level >> 8) & 0xff,
! 1233: (level >> 16) & 0xff, i);
! 1234: }
! 1235:
! 1236: n = (struct listaddr *)malloc(sizeof(struct listaddr));
! 1237: if (n == NULL) {
! 1238: logit(LOG_ERR, 0, "Malloc failed in vif.c:update_neighbor()\n"); /* FATAL! */
! 1239: return NULL; /* NOTREACHED */
! 1240: }
! 1241:
! 1242: n->al_addr = addr;
! 1243: n->al_pv = pv;
! 1244: n->al_mv = mv;
! 1245: n->al_genid = has_genid ? genid : 0;
! 1246: n->al_index = i;
! 1247: nbrs[i] = n;
! 1248:
! 1249: time(&n->al_ctime);
! 1250: n->al_timer = 0;
! 1251: n->al_flags = has_genid ? NBRF_GENID : 0;
! 1252: n->al_next = v->uv_neighbors;
! 1253: v->uv_neighbors = n;
! 1254:
! 1255: /*
! 1256: * If we are not configured to peer with non-pruning routers,
! 1257: * check the deprecated "I-know-how-to-prune" bit. This bit
! 1258: * was MBZ in early mrouted implementations (<3.5) and is required
! 1259: * to be set by the DVMRPv3 specification.
! 1260: */
! 1261: if (!(v->uv_flags & VIFF_ALLOW_NONPRUNERS) &&
! 1262: !((level & 0x020000) || (pv == 3 && mv < 5))) {
! 1263: n->al_flags |= NBRF_TOOOLD;
! 1264: }
! 1265:
! 1266: /*
! 1267: * If this router implements the DVMRPv3 spec, then don't peer
! 1268: * with him if we haven't yet established a bidirectional connection.
! 1269: */
! 1270: if (dvmrpspec) {
! 1271: if (!in_router_list) {
! 1272: IF_DEBUG(DEBUG_PEER) {
! 1273: logit(LOG_DEBUG, 0, "Waiting for probe from %s with my addr",
! 1274: inet_fmt(addr, s1, sizeof(s1)));
! 1275: }
! 1276: n->al_flags |= NBRF_WAITING;
! 1277: return NULL;
! 1278: }
! 1279: }
! 1280:
! 1281: if (n->al_flags & NBRF_DONTPEER) {
! 1282: IF_DEBUG(DEBUG_PEER) {
! 1283: logit(LOG_DEBUG, 0, "Not peering with %s on vif %d because %x",
! 1284: inet_fmt(addr, s1, sizeof(s1)), vifi, n->al_flags & NBRF_DONTPEER);
! 1285: }
! 1286: return NULL;
! 1287: }
! 1288:
! 1289: /*
! 1290: * If we thought that we had no neighbors on this vif, send a route
! 1291: * report to the vif. If this is just a new neighbor on the same
! 1292: * vif, send the route report just to the new neighbor.
! 1293: */
! 1294: if (NBRM_ISEMPTY(v->uv_nbrmap)) {
! 1295: send_tables = v->uv_dst_addr;
! 1296: vifs_with_neighbors++;
! 1297: } else {
! 1298: send_tables = addr;
! 1299: }
! 1300:
! 1301:
! 1302: NBRM_SET(i, v->uv_nbrmap);
! 1303: add_neighbor_to_routes(vifi, i);
! 1304: } else {
! 1305: /*
! 1306: * Found it. Reset its timer.
! 1307: */
! 1308: n->al_timer = 0;
! 1309:
! 1310: if (n->al_flags & NBRF_WAITING && msgtype == DVMRP_PROBE) {
! 1311: n->al_flags &= ~NBRF_WAITING;
! 1312: if (!in_router_list) {
! 1313: logit(LOG_WARNING, 0, "Possible one-way peering with %s on vif %d",
! 1314: inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1315: n->al_flags |= NBRF_ONEWAY;
! 1316: return NULL;
! 1317: } else {
! 1318: if (NBRM_ISEMPTY(v->uv_nbrmap)) {
! 1319: send_tables = v->uv_dst_addr;
! 1320: vifs_with_neighbors++;
! 1321: } else {
! 1322: send_tables = addr;
! 1323: }
! 1324: NBRM_SET(n->al_index, v->uv_nbrmap);
! 1325: add_neighbor_to_routes(vifi, n->al_index);
! 1326: IF_DEBUG(DEBUG_PEER) {
! 1327: logit(LOG_DEBUG, 0, "%s on vif %d exits WAITING",
! 1328: inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1329: }
! 1330: }
! 1331: }
! 1332:
! 1333: if (n->al_flags & NBRF_ONEWAY && msgtype == DVMRP_PROBE) {
! 1334: if (in_router_list) {
! 1335: if (NBRM_ISEMPTY(v->uv_nbrmap))
! 1336: vifs_with_neighbors++;
! 1337: NBRM_SET(n->al_index, v->uv_nbrmap);
! 1338: add_neighbor_to_routes(vifi, n->al_index);
! 1339: logit(LOG_NOTICE, 0, "Peering with %s on vif %d is no longer one-way",
! 1340: inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1341: n->al_flags &= ~NBRF_ONEWAY;
! 1342: } else {
! 1343: /* XXX rate-limited warning message? */
! 1344: IF_DEBUG(DEBUG_PEER) {
! 1345: logit(LOG_DEBUG, 0, "%s on vif %d is still ONEWAY",
! 1346: inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1347: }
! 1348: }
! 1349: }
! 1350:
! 1351: /*
! 1352: * When peering with a genid-capable but pre-DVMRP spec peer,
! 1353: * we might bring up the peering with a route report and not
! 1354: * remember his genid. Assume that he doesn't send a route
! 1355: * report and then reboot before sending a probe.
! 1356: */
! 1357: if (has_genid && !(n->al_flags & NBRF_GENID)) {
! 1358: n->al_flags |= NBRF_GENID;
! 1359: n->al_genid = genid;
! 1360: }
! 1361:
! 1362: /*
! 1363: * update the neighbors version and protocol number and genid
! 1364: * if changed => router went down and came up,
! 1365: * so take action immediately.
! 1366: */
! 1367: if ((n->al_pv != pv) ||
! 1368: (n->al_mv != mv) ||
! 1369: (has_genid && n->al_genid != genid)) {
! 1370:
! 1371: do_reset = TRUE;
! 1372: IF_DEBUG(DEBUG_PEER) {
! 1373: logit(LOG_DEBUG, 0, "Version/genid change neighbor %s [old:%d.%d/%8x, new:%d.%d/%8x]",
! 1374: inet_fmt(addr, s1, sizeof(s1)),
! 1375: n->al_pv, n->al_mv, n->al_genid, pv, mv, genid);
! 1376: }
! 1377:
! 1378: n->al_pv = pv;
! 1379: n->al_mv = mv;
! 1380: n->al_genid = genid;
! 1381: time(&n->al_ctime);
! 1382: }
! 1383:
! 1384: if ((pv == 3 && mv > 2) || (pv > 3 && pv < 10)) {
! 1385: if (!(n->al_flags & VIFF_ONEWAY) && has_genid && !in_router_list &&
! 1386: (time(NULL) - n->al_ctime > 20)) {
! 1387: if (NBRM_ISSET(n->al_index, v->uv_nbrmap)) {
! 1388: NBRM_CLR(n->al_index, v->uv_nbrmap);
! 1389: if (NBRM_ISEMPTY(v->uv_nbrmap))
! 1390: vifs_with_neighbors--;
! 1391: }
! 1392: delete_neighbor_from_routes(addr, vifi, n->al_index);
! 1393: reset_neighbor_state(vifi, addr);
! 1394: logit(LOG_WARNING, 0, "Peering with %s on vif %d is one-way",
! 1395: inet_fmt(addr, s1, sizeof(s1)), vifi);
! 1396: n->al_flags |= NBRF_ONEWAY;
! 1397: }
! 1398: }
! 1399:
! 1400: if (n->al_flags & NBRF_DONTPEER) {
! 1401: IF_DEBUG(DEBUG_PEER) {
! 1402: logit(LOG_DEBUG, 0, "Not peering with %s on vif %d because %x",
! 1403: inet_fmt(addr, s1, sizeof(s1)), vifi, n->al_flags & NBRF_DONTPEER);
! 1404: }
! 1405: return NULL;
! 1406: }
! 1407:
! 1408: /* check "leaf" flag */
! 1409: }
! 1410: if (do_reset) {
! 1411: reset_neighbor_state(vifi, addr);
! 1412: if (!send_tables)
! 1413: send_tables = addr;
! 1414: }
! 1415: if (send_tables) {
! 1416: send_probe_on_vif(v);
! 1417: report(ALL_ROUTES, vifi, send_tables);
! 1418: }
! 1419: v->uv_leaf_timer = 0;
! 1420: v->uv_flags &= ~VIFF_LEAF;
! 1421:
! 1422: return n;
! 1423: }
! 1424:
! 1425:
! 1426: /*
! 1427: * On every timer interrupt, advance the timer in each neighbor and
! 1428: * group entry on every vif.
! 1429: */
! 1430: void age_vifs(void)
! 1431: {
! 1432: vifi_t vifi;
! 1433: struct uvif *v;
! 1434: struct listaddr *a, *prev_a;
! 1435: u_int32 addr;
! 1436:
! 1437: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
! 1438: if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
! 1439: v->uv_flags |= VIFF_LEAF;
! 1440: }
! 1441:
! 1442: for (prev_a = (struct listaddr *)&(v->uv_neighbors),
! 1443: a = v->uv_neighbors;
! 1444: a != NULL;
! 1445: prev_a = a, a = a->al_next) {
! 1446: u_long exp_time;
! 1447: int idx;
! 1448:
! 1449: if (((a->al_pv == 3) && (a->al_mv >= 3)) ||
! 1450: ((a->al_pv > 3) && (a->al_pv < 10)))
! 1451: exp_time = NEIGHBOR_EXPIRE_TIME;
! 1452: else
! 1453: exp_time = OLD_NEIGHBOR_EXPIRE_TIME;
! 1454:
! 1455: if ((a->al_timer += TIMER_INTERVAL) < exp_time)
! 1456: continue;
! 1457:
! 1458: IF_DEBUG(DEBUG_PEER) {
! 1459: logit(LOG_DEBUG, 0, "Neighbor %s (%d.%d) expired after %d seconds",
! 1460: inet_fmt(a->al_addr, s1, sizeof(s1)), a->al_pv, a->al_mv, exp_time);
! 1461: }
! 1462:
! 1463: /*
! 1464: * Neighbor has expired; delete it from the neighbor list,
! 1465: * delete it from the 'dominants' and 'subordinates arrays of
! 1466: * any route entries.
! 1467: */
! 1468: NBRM_CLR(a->al_index, v->uv_nbrmap);
! 1469: nbrs[a->al_index] = NULL; /* XXX is it a good idea to reuse indxs? */
! 1470: idx = a->al_index;
! 1471: addr = a->al_addr;
! 1472: prev_a->al_next = a->al_next;
! 1473: free((char *)a);
! 1474: a = prev_a;/*XXX use ** */
! 1475:
! 1476: delete_neighbor_from_routes(addr, vifi, idx);
! 1477: reset_neighbor_state(vifi, addr);
! 1478:
! 1479: if (NBRM_ISEMPTY(v->uv_nbrmap))
! 1480: vifs_with_neighbors--;
! 1481:
! 1482: v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
! 1483: }
! 1484:
! 1485: if (v->uv_querier &&
! 1486: (v->uv_querier->al_timer += TIMER_INTERVAL) >
! 1487: IGMP_OTHER_QUERIER_PRESENT_INTERVAL) {
! 1488: /*
! 1489: * The current querier has timed out. We must become the
! 1490: * querier.
! 1491: */
! 1492: IF_DEBUG(DEBUG_IGMP) {
! 1493: logit(LOG_DEBUG, 0, "Querier %s timed out",
! 1494: inet_fmt(v->uv_querier->al_addr, s1, sizeof(s1)));
! 1495: }
! 1496: free(v->uv_querier);
! 1497: v->uv_querier = NULL;
! 1498: v->uv_flags |= VIFF_QUERIER;
! 1499: send_query(v);
! 1500: }
! 1501: }
! 1502: }
! 1503:
! 1504: /*
! 1505: * Returns the neighbor info struct for a given neighbor
! 1506: */
! 1507: struct listaddr *neighbor_info(vifi_t vifi, u_int32 addr)
! 1508: {
! 1509: struct listaddr *u;
! 1510:
! 1511: for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
! 1512: if (u->al_addr == addr)
! 1513: return u;
! 1514:
! 1515: return NULL;
! 1516: }
! 1517:
! 1518: static struct vnflags {
! 1519: int vn_flag;
! 1520: char *vn_name;
! 1521: } vifflags[] = {
! 1522: { VIFF_DOWN, "down" },
! 1523: { VIFF_DISABLED, "disabled" },
! 1524: { VIFF_QUERIER, "querier" },
! 1525: { VIFF_ONEWAY, "one-way" },
! 1526: { VIFF_LEAF, "leaf" },
! 1527: { VIFF_IGMPV1, "IGMPv1" },
! 1528: { VIFF_REXMIT_PRUNES, "rexmit_prunes" },
! 1529: { VIFF_PASSIVE, "passive" },
! 1530: { VIFF_ALLOW_NONPRUNERS,"allow_nonpruners" },
! 1531: { VIFF_NOFLOOD, "noflood" },
! 1532: { VIFF_NOTRANSIT, "notransit" },
! 1533: { VIFF_BLASTER, "blaster" },
! 1534: { VIFF_FORCE_LEAF, "force_leaf" },
! 1535: { VIFF_OTUNNEL, "old-tunnel" },
! 1536: };
! 1537:
! 1538: static struct vnflags nbrflags[] = {
! 1539: { NBRF_LEAF, "leaf" },
! 1540: { NBRF_GENID, "have-genid" },
! 1541: { NBRF_WAITING, "waiting" },
! 1542: { NBRF_ONEWAY, "one-way" },
! 1543: { NBRF_TOOOLD, "too old" },
! 1544: { NBRF_TOOMANYROUTES, "too many routes" },
! 1545: { NBRF_NOTPRUNING, "not pruning?" },
! 1546: };
! 1547:
! 1548: /*
! 1549: * Print the contents of the uvifs array on file 'fp'.
! 1550: */
! 1551: void dump_vifs(FILE *fp)
! 1552: {
! 1553: vifi_t vifi;
! 1554: struct uvif *v;
! 1555: struct listaddr *a;
! 1556: struct phaddr *p;
! 1557: struct vif_acl *acl;
! 1558: size_t i;
! 1559: struct sioc_vif_req v_req;
! 1560: time_t now;
! 1561: char *label;
! 1562:
! 1563: time(&now);
! 1564: fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
! 1565:
! 1566: if (vifs_with_neighbors == 1)
! 1567: fprintf(fp,"[This host is a leaf]\n\n");
! 1568:
! 1569: fprintf(fp,
! 1570: "\nVirtual Interface Table\n%s",
! 1571: "Vif Name Local-Address ");
! 1572: fprintf(fp,
! 1573: "M Thr Rate Flags\n");
! 1574:
! 1575: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
! 1576:
! 1577: fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ",
! 1578: vifi,
! 1579: v->uv_name,
! 1580: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
! 1581: (v->uv_flags & VIFF_TUNNEL) ?
! 1582: "tunnel":
! 1583: "subnet",
! 1584: (v->uv_flags & VIFF_TUNNEL) ?
! 1585: inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)) :
! 1586: inet_fmts(v->uv_subnet, v->uv_subnetmask, s3, sizeof(s3)),
! 1587: v->uv_metric,
! 1588: v->uv_threshold,
! 1589: v->uv_rate_limit);
! 1590:
! 1591: for (i = 0; i < sizeof(vifflags) / sizeof(struct vnflags); i++)
! 1592: if (v->uv_flags & vifflags[i].vn_flag)
! 1593: fprintf(fp, " %s", vifflags[i].vn_name);
! 1594:
! 1595: fprintf(fp, "\n");
! 1596: /*
! 1597: fprintf(fp, " #routes: %d\n", v->uv_nroutes);
! 1598: */
! 1599: if (v->uv_admetric != 0)
! 1600: fprintf(fp, " advert-metric %2u\n",
! 1601: v->uv_admetric);
! 1602:
! 1603: label = "alternate subnets:";
! 1604: for (p = v->uv_addrs; p; p = p->pa_next) {
! 1605: fprintf(fp, " %18s %s\n", label,
! 1606: inet_fmts(p->pa_subnet, p->pa_subnetmask, s1, sizeof(s1)));
! 1607: label = "";
! 1608: }
! 1609:
! 1610: label = "peers:";
! 1611: for (a = v->uv_neighbors; a != NULL; a = a->al_next) {
! 1612: fprintf(fp, " %6s %s (%d.%d) [%d]",
! 1613: label, inet_fmt(a->al_addr, s1, sizeof(s1)), a->al_pv, a->al_mv,
! 1614: a->al_index);
! 1615: for (i = 0; i < sizeof(nbrflags) / sizeof(struct vnflags); i++)
! 1616: if (a->al_flags & nbrflags[i].vn_flag)
! 1617: fprintf(fp, " %s", nbrflags[i].vn_name);
! 1618: fprintf(fp, " up %s\n", scaletime(now - a->al_ctime));
! 1619: /*fprintf(fp, " #routes %d\n", a->al_nroutes);*/
! 1620: label = "";
! 1621: }
! 1622:
! 1623: label = "group host (time left):";
! 1624: for (a = v->uv_groups; a != NULL; a = a->al_next) {
! 1625: fprintf(fp, " %23s %-15s %-15s (%s)\n",
! 1626: label,
! 1627: inet_fmt(a->al_addr, s1, sizeof(s1)),
! 1628: inet_fmt(a->al_reporter, s2, sizeof(s2)),
! 1629: scaletime(timer_leftTimer(a->al_timerid)));
! 1630: label = "";
! 1631: }
! 1632: label = "boundaries:";
! 1633: for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) {
! 1634: fprintf(fp, " %11s %-18s\n", label,
! 1635: inet_fmts(acl->acl_addr, acl->acl_mask, s1, sizeof(s1)));
! 1636: label = "";
! 1637: }
! 1638: if (v->uv_filter) {
! 1639: struct vf_element *vfe;
! 1640: char lbuf[100];
! 1641:
! 1642: snprintf(lbuf, sizeof(lbuf), "%5s %7s filter:",
! 1643: v->uv_filter->vf_flags & VFF_BIDIR ? "bidir" : " ",
! 1644: v->uv_filter->vf_type == VFT_ACCEPT ? "accept" : "deny");
! 1645: label = lbuf;
! 1646: for (vfe = v->uv_filter->vf_filter;
! 1647: vfe != NULL; vfe = vfe->vfe_next) {
! 1648: fprintf(fp, " %23s %-18s%s\n",
! 1649: label,
! 1650: inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s1, sizeof(s1)),
! 1651: vfe->vfe_flags & VFEF_EXACT ? " (exact)" : "");
! 1652: label = "";
! 1653: }
! 1654: }
! 1655: if (!(v->uv_flags & (VIFF_TUNNEL|VIFF_DOWN|VIFF_DISABLED))) {
! 1656: fprintf(fp, " IGMP querier: ");
! 1657: if (v->uv_querier == NULL)
! 1658: if (v->uv_flags & VIFF_QUERIER)
! 1659: fprintf(fp, "%-18s (this system)\n",
! 1660: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 1661: else
! 1662: fprintf(fp, "NONE - querier election failure?\n");
! 1663: else
! 1664: fprintf(fp, "%-18s up %s last heard %s ago\n",
! 1665: inet_fmt(v->uv_querier->al_addr, s1, sizeof(s1)),
! 1666: scaletime(now - v->uv_querier->al_ctime),
! 1667: scaletime(v->uv_querier->al_timer));
! 1668: }
! 1669: if (v->uv_flags & VIFF_BLASTER)
! 1670: fprintf(fp, " blasterbuf size: %dk\n",
! 1671: v->uv_blasterlen / 1024);
! 1672: fprintf(fp, " Nbr bitmaps: 0x%08lx%08lx\n",/*XXX*/
! 1673: v->uv_nbrmap.hi, v->uv_nbrmap.lo);
! 1674: if (v->uv_prune_lifetime != 0)
! 1675: fprintf(fp, " Prune Lifetime: %d seconds\n",
! 1676: v->uv_prune_lifetime);
! 1677:
! 1678: v_req.vifi = vifi;
! 1679: if (did_final_init) {
! 1680: if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
! 1681: logit(LOG_WARNING, errno, "Failed ioctl SIOCGETVIFCNT on vif %d", vifi);
! 1682: } else {
! 1683: fprintf(fp, " pkts/bytes in : %lu/%lu\n",
! 1684: v_req.icount, v_req.ibytes);
! 1685: fprintf(fp, " pkts/bytes out: %lu/%lu\n",
! 1686: v_req.ocount, v_req.obytes);
! 1687: }
! 1688: }
! 1689: fprintf(fp, "\n");
! 1690: }
! 1691: fprintf(fp, "\n");
! 1692: }
! 1693:
! 1694: /*
! 1695: * Time out record of a group membership on a vif
! 1696: */
! 1697: static void DelVif(void *arg)
! 1698: {
! 1699: cbk_t *cbk = (cbk_t *)arg;
! 1700: vifi_t vifi = cbk->vifi;
! 1701: struct uvif *v = &uvifs[vifi];
! 1702: struct listaddr *a, **anp, *g = cbk->g;
! 1703:
! 1704: /*
! 1705: * Group has expired
! 1706: * delete all kernel cache entries with this group
! 1707: */
! 1708: if (g->al_query)
! 1709: DeleteTimer(g->al_query);
! 1710:
! 1711: delete_lclgrp(vifi, g->al_addr);
! 1712:
! 1713: anp = &(v->uv_groups);
! 1714: while ((a = *anp) != NULL) {
! 1715: if (a == g) {
! 1716: *anp = a->al_next;
! 1717: free((char *)a);
! 1718: } else {
! 1719: anp = &a->al_next;
! 1720: }
! 1721: }
! 1722:
! 1723: free(cbk);
! 1724: }
! 1725:
! 1726: /*
! 1727: * Set a timer to delete the record of a group membership on a vif.
! 1728: */
! 1729: static int SetTimer(vifi_t vifi, struct listaddr *g)
! 1730: {
! 1731: cbk_t *cbk;
! 1732:
! 1733: cbk = (cbk_t *)malloc(sizeof(cbk_t));
! 1734: if (!cbk) {
! 1735: logit(LOG_ERR, 0, "Malloc failed in vif.c:SetTimer()\n");
! 1736: return -1; /* NOTREACHED */
! 1737: }
! 1738:
! 1739: cbk->g = g;
! 1740: cbk->vifi = vifi;
! 1741:
! 1742: return timer_setTimer(g->al_timer, DelVif, cbk);
! 1743: }
! 1744:
! 1745: /*
! 1746: * Delete a timer that was set above.
! 1747: */
! 1748: static int DeleteTimer(int id)
! 1749: {
! 1750: timer_clearTimer(id);
! 1751:
! 1752: return 0;
! 1753: }
! 1754:
! 1755: /*
! 1756: * Send a group-specific query.
! 1757: */
! 1758: static void SendQuery(void *arg)
! 1759: {
! 1760: cbk_t *cbk = (cbk_t *)arg;
! 1761: struct uvif *v = &uvifs[cbk->vifi];
! 1762:
! 1763: send_igmp(v->uv_lcl_addr, cbk->g->al_addr, IGMP_MEMBERSHIP_QUERY,
! 1764: cbk->q_time, cbk->g->al_addr, 0);
! 1765: cbk->g->al_query = 0;
! 1766: free(cbk);
! 1767: }
! 1768:
! 1769: /*
! 1770: * Set a timer to send a group-specific query.
! 1771: */
! 1772: static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time)
! 1773: {
! 1774: cbk_t *cbk;
! 1775:
! 1776: cbk = (cbk_t *)malloc(sizeof(cbk_t));
! 1777: if (!cbk) {
! 1778: logit(LOG_WARNING, 0, "Malloc failed in vif.c:setQueryTimer()\n");
! 1779: return -1;
! 1780: }
! 1781:
! 1782: cbk->g = g;
! 1783: cbk->q_time = q_time;
! 1784: cbk->vifi = vifi;
! 1785:
! 1786: return timer_setTimer(to_expire, SendQuery, cbk);
! 1787: }
! 1788:
! 1789: /**
! 1790: * Local Variables:
! 1791: * version-control: t
! 1792: * indent-tabs-mode: t
! 1793: * c-file-style: "ellemtel"
! 1794: * c-basic-offset: 4
! 1795: * End:
! 1796: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>