File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / vif.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:10:48 2012 UTC (12 years, 3 months ago) by misho
Branches: mrouted, MAIN
CVS tags: v3_9_6p0, v3_9_6, v3_9_5, HEAD
mrouted

    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>