File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / config.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    1: /*
    2:  * Copyright (c) 1998-2001
    3:  * University of Southern California/Information Sciences Institute.
    4:  * All rights reserved.
    5:  *
    6:  * Redistribution and use in source and binary forms, with or without
    7:  * modification, are permitted provided that the following conditions
    8:  * are met:
    9:  * 1. Redistributions of source code must retain the above copyright
   10:  *    notice, this list of conditions and the following disclaimer.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  * 3. Neither the name of the project nor the names of its contributors
   15:  *    may be used to endorse or promote products derived from this software
   16:  *    without specific prior written permission.
   17:  *
   18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28:  * SUCH DAMAGE.
   29:  */
   30: /*
   31:  * Part of this program has been derived from mrouted.
   32:  * The mrouted program is covered by the license in the accompanying file
   33:  * named "LICENSE.mrouted".
   34:  *
   35:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
   36:  * Leland Stanford Junior University.
   37:  *
   38:  */
   39: 
   40: #include "defs.h"
   41: 
   42: #define WARN(fmt, args...)    logit(LOG_WARNING, 0, "%s:%u - " fmt, config_file, lineno, ##args)
   43: #define BAILOUT(msg, arg...)  { WARN(msg ", bailing out!", ##arg); return FALSE; }
   44: #define IGNORING(msg, arg...) { WARN(msg ", ignoring ...", ##arg); continue; }
   45: 
   46: /* Helper macros */
   47: #define QUERIER_TIMEOUT(qintv) (IGMP_ROBUSTNESS_VARIABLE * (qintv) + IGMP_QUERY_RESPONSE_INTERVAL / 2)
   48: 
   49: #define LINE_BUFSIZ 1024	/* Max. line length of the config file */
   50: 
   51: #define CONF_UNKNOWN                           -1
   52: #define CONF_EMPTY                              1
   53: #define CONF_PHYINT                             2
   54: #define CONF_CANDIDATE_RP                       3
   55: #define CONF_RP_ADDRESS                         4
   56: #define CONF_GROUP_PREFIX                       5
   57: #define CONF_BOOTSTRAP_RP                       6
   58: #define CONF_COMPAT_THRESHOLD                   7
   59: #define CONF_SPT_THRESHOLD                      8
   60: #define CONF_DEFAULT_ROUTE_METRIC               9
   61: #define CONF_DEFAULT_ROUTE_DISTANCE             10
   62: #define CONF_ALTNET                             11
   63: #define CONF_MASKLEN                            12
   64: #define CONF_SCOPED                             13
   65: #define CONF_IGMP_QUERY_INTERVAL                14
   66: #define CONF_IGMP_QUERIER_TIMEOUT               15
   67: #define CONF_HELLO_INTERVAL                     16
   68: 
   69: /*
   70:  * Global settings
   71:  */
   72: uint16_t pim_timer_hello_interval = PIM_TIMER_HELLO_INTERVAL;
   73: uint16_t pim_timer_hello_holdtime = PIM_TIMER_HELLO_HOLDTIME;
   74: 
   75: /*
   76:  * Forward declarations.
   77:  */
   78: static char	*next_word	(char **);
   79: static int	 parse_phyint	(char *s);
   80: static uint32_t	 ifname2addr	(char *s);
   81: 
   82: static uint32_t        lineno;
   83: extern struct rp_hold *g_rp_hold;
   84: 
   85: /*
   86:  * Query the kernel to find network interfaces that are multicast-capable
   87:  * and install them in the uvifs array.
   88:  */
   89: void config_vifs_from_kernel(void)
   90: {
   91:     struct ifreq *ifrp, *ifend;
   92:     struct uvif *v;
   93:     vifi_t vifi;
   94:     uint32_t n;
   95:     uint32_t addr, mask, subnet;
   96:     short flags;
   97:     int num_ifreq = 64;
   98:     struct ifconf ifc;
   99:     char *newbuf;
  100: 
  101:     total_interfaces = 0; /* The total number of physical interfaces */
  102: 
  103:     ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
  104:     ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char));
  105:     while (ifc.ifc_buf) {
  106: 	if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
  107: 	    logit(LOG_ERR, errno, "Failed querying kernel network interfaces");
  108: 
  109: 	/*
  110: 	 * If the buffer was large enough to hold all the addresses
  111: 	 * then break out, otherwise increase the buffer size and
  112: 	 * try again.
  113: 	 *
  114: 	 * The only way to know that we definitely had enough space
  115: 	 * is to know that there was enough space for at least one
  116: 	 * more struct ifreq. ???
  117: 	 */
  118: 	if ((num_ifreq * sizeof(struct ifreq)) >= ifc.ifc_len + sizeof(struct ifreq))
  119: 	    break;
  120: 
  121: 	num_ifreq *= 2;
  122: 	ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
  123: 	newbuf = realloc(ifc.ifc_buf, ifc.ifc_len);
  124: 	if (newbuf == NULL)
  125: 	    free(ifc.ifc_buf);
  126: 	ifc.ifc_buf = newbuf;
  127:     }
  128:     if (ifc.ifc_buf == NULL)
  129: 	logit(LOG_ERR, 0, "config_vifs_from_kernel() ran out of memory");
  130: 
  131:     ifrp = (struct ifreq *)ifc.ifc_buf;
  132:     ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
  133:     /*
  134:      * Loop through all of the interfaces.
  135:      */
  136:     for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
  137: 	struct ifreq ifr;
  138: 
  139: 	memset (&ifr, 0, sizeof (ifr));
  140: 
  141: #ifdef HAVE_SA_LEN
  142: 	n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
  143: 	if (n < sizeof(*ifrp))
  144: 	    n = sizeof(*ifrp);
  145: #else
  146: 	n = sizeof(*ifrp);
  147: #endif /* HAVE_SA_LEN */
  148: 
  149: 	/*
  150: 	 * Ignore any interface for an address family other than IP.
  151: 	 */
  152: 	if (ifrp->ifr_addr.sa_family != AF_INET) {
  153: 	    total_interfaces++;  /* Eventually may have IP address later */
  154: 	    continue;
  155: 	}
  156: 
  157: 	addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
  158: 
  159: 	/*
  160: 	 * Need a template to preserve address info that is
  161: 	 * used below to locate the next entry.  (Otherwise,
  162: 	 * SIOCGIFFLAGS stomps over it because the requests
  163: 	 * are returned in a union.)
  164: 	 */
  165: 	memcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
  166: 
  167: 	/*
  168: 	 * Ignore loopback interfaces and interfaces that do not
  169: 	 * support multicast.
  170: 	 */
  171: 	if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
  172: 	    logit(LOG_ERR, errno, "Failed reading interface flags for phyint %s", ifr.ifr_name);
  173: 
  174: 	flags = ifr.ifr_flags;
  175: 	if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST)
  176: 	    continue;
  177: 
  178: 	/*
  179: 	 * Everyone below is a potential vif interface.
  180: 	 * We don't care if it has wrong configuration or not configured
  181: 	 * at all.
  182: 	 */
  183: 	total_interfaces++;
  184: 
  185: 	/*
  186: 	 * Ignore any interface whose address and mask do not define a
  187: 	 * valid subnet number, or whose address is of the form
  188: 	 * {subnet,0} or {subnet,-1}.
  189: 	 */
  190: 	if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0) {
  191: 	    if (!(flags & IFF_POINTOPOINT))
  192: 		logit(LOG_ERR, errno, "Failed reading interface netmask for phyint %s", ifr.ifr_name);
  193: 
  194: 	    mask = 0xffffffff;
  195: 	} else {
  196: 	    mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  197: 	}
  198: 
  199: 	subnet = addr & mask;
  200: #ifdef DISABLE_MASKLEN_CHECK
  201: 	if (mask != 0xffffffff) {
  202: #endif
  203: 		if ((!inet_valid_subnet(subnet, mask)) || (addr == subnet) || addr == (subnet | ~mask)) {
  204: 			if (!(inet_valid_host(addr) && ((mask == htonl(0xfffffffe)) || (flags & IFF_POINTOPOINT)))) {
  205: 				logit(LOG_WARNING, 0, "Ignoring %s, has invalid address %s and/or netmask %s",
  206: 				ifr.ifr_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(mask, s2, sizeof(s2)));
  207: 				continue;
  208: 			}
  209: 		}
  210: #ifdef DISABLE_MASKLEN_CHECK
  211: 	}
  212: #endif
  213: 
  214: 	/*
  215: 	 * Ignore any interface that is connected to the same subnet as
  216: 	 * one already installed in the uvifs array.
  217: 	 */
  218: 	/*
  219: 	 * TODO: XXX: bug or "feature" is to allow only one interface per
  220: 	 * subnet?
  221: 	 */
  222: 	for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  223: 	    if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
  224: 		logit(LOG_DEBUG, 0, "Ignoring %s (%s on subnet %s) (alias for vif#%u?)",
  225: 		      v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask), vifi);
  226: 		break;
  227: 	    }
  228: 	    /* we don't care about point-to-point links in same subnet */
  229: 	    if (flags & IFF_POINTOPOINT)
  230: 		continue;
  231: 	    if (v->uv_flags & VIFF_POINT_TO_POINT)
  232: 		continue;
  233: #if 0
  234: 	    /*
  235: 	     * TODO: to allow different interfaces belong to
  236: 	     * overlapping subnet addresses, use this version instead
  237: 	     */
  238: 	    if (((addr & mask ) == v->uv_subnet) && (v->uv_subnetmask == mask)) {
  239: 		logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name);
  240: 		break;
  241: 	    }
  242: #else
  243: 	    if ((addr & v->uv_subnetmask) == v->uv_subnet || (v->uv_subnet & mask) == subnet) {
  244: 		logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name);
  245: 		break;
  246: 	    }
  247: #endif /* 0 */
  248: 	}
  249: 	if (vifi != numvifs)
  250: 	    continue;
  251: 
  252: 	/*
  253: 	 * If there is room in the uvifs array, install this interface.
  254: 	 */
  255: 	if (numvifs == MAXVIFS) {
  256: 	    logit(LOG_WARNING, 0, "Too many vifs, ignoring %s", ifr.ifr_name);
  257: 	    continue;
  258: 	}
  259: 	v = &uvifs[numvifs];
  260: 	zero_vif(v, FALSE);
  261: 	v->uv_lcl_addr		= addr;
  262: 	v->uv_subnet		= subnet;
  263: 	v->uv_subnetmask	= mask;
  264: 	if (mask != htonl(0xfffffffe))
  265: 		v->uv_subnetbcast = subnet | ~mask;
  266: 	else
  267: 		v->uv_subnetbcast = 0xffffffff;
  268: 
  269: 	strlcpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
  270: 
  271: 	/*
  272: 	 * Figure out MTU of interface, needed as a seed value when
  273: 	 * fragmenting PIM register messages.  We should really do
  274: 	 * a PMTU check on initial PIM register send to a new RP...
  275: 	 */
  276: 	if (ioctl(udp_socket, SIOCGIFMTU, &ifr) < 0)
  277: 	    v->uv_mtu = 1500;
  278: 	else
  279: 	    v->uv_mtu = ifr.ifr_mtu;
  280: 
  281: 	if (flags & IFF_POINTOPOINT) {
  282: 	    v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
  283: 	    if (ioctl(udp_socket, SIOCGIFDSTADDR, (char *)&ifr) < 0)
  284: 		logit(LOG_ERR, errno, "Failed reading point-to-point address for %s", v->uv_name);
  285: 	    else
  286: 		v->uv_rmt_addr = ((struct sockaddr_in *)(&ifr.ifr_dstaddr))->sin_addr.s_addr;
  287: 	} else if (mask == htonl(0xfffffffe)) {
  288: 	    /*
  289: 	     * Handle RFC 3021 /31 netmasks as point-to-point links
  290: 	     */
  291: 	    v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
  292: 	    if (addr == subnet)
  293: 		v->uv_rmt_addr = addr + htonl(1);
  294: 	    else
  295: 		v->uv_rmt_addr = subnet;
  296: 	}
  297: #ifdef __linux__
  298: 	{
  299: 	    struct ifreq ifridx;
  300: 
  301: 	    memset(&ifridx, 0, sizeof(ifridx));
  302: 	    strlcpy(ifridx.ifr_name,v->uv_name, IFNAMSIZ);
  303: 	    if (ioctl(udp_socket, SIOGIFINDEX, (char *) &ifridx) < 0)
  304: 		logit(LOG_ERR, errno, "Failed reading interface index for %s", ifridx.ifr_name);
  305: 	    v->uv_ifindex = ifridx.ifr_ifindex;
  306: 	}
  307: 	if (v->uv_flags & VIFF_POINT_TO_POINT) {
  308: 	    logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u-%d - rate %d",
  309: 		  v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)),
  310: 		  numvifs, v->uv_ifindex, v->uv_rate_limit);
  311: 	} else {
  312: 	    logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u-%d - rate %d",
  313: 		  v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask),
  314: 		  numvifs, v->uv_ifindex, v->uv_rate_limit);
  315: 	}
  316: #else /* !__linux__ */
  317: 	if (v->uv_flags & VIFF_POINT_TO_POINT) {
  318: 	    logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u - rate=%d",
  319: 		  v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)),
  320: 		  numvifs, v->uv_rate_limit);
  321: 	} else {
  322: 	    logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u - rate %d",
  323: 		  v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask),
  324: 		  numvifs, v->uv_rate_limit);
  325: 	}
  326: #endif /* __linux__ */
  327: 
  328: 	++numvifs;
  329: 
  330: 	/*
  331: 	 * If the interface is not yet up, set the vifs_down flag to
  332: 	 * remind us to check again later.
  333: 	 */
  334: 	if (!(flags & IFF_UP)) {
  335: 	    v->uv_flags |= VIFF_DOWN;
  336: 	    vifs_down = TRUE;
  337: 	}
  338:     }
  339: }
  340: 
  341: static int deprecated(char *word, char *new_word, int code)
  342: {
  343:     WARN("The %s option is deprecated, replaced with %s", word, new_word);
  344:     WARN("Please update your configuration file!");
  345: 
  346:     return code;
  347: }
  348: 
  349: /**
  350:  * parse_option - Convert result of string comparisons into numerics.
  351:  * @input: Pointer to the word
  352:  *
  353:  * This function is called by config_vifs_from_file().
  354:  *
  355:  * Returns:
  356:  * A number corresponding to the code of the word, or %CONF_UNKNOWN.
  357:  */
  358: static int parse_option(char *word)
  359: {
  360:     if (EQUAL(word, ""))
  361: 	return CONF_EMPTY;
  362:     if (EQUAL(word, "phyint"))
  363: 	return CONF_PHYINT;
  364:     if (EQUAL(word, "bsr-candidate"))
  365: 	return CONF_BOOTSTRAP_RP;
  366:     if (EQUAL(word, "rp-candidate"))
  367: 	return CONF_CANDIDATE_RP;
  368:     if (EQUAL(word, "rp-address"))
  369: 	return CONF_RP_ADDRESS;
  370:     if (EQUAL(word, "group-prefix"))
  371: 	return CONF_GROUP_PREFIX;
  372:     if (EQUAL(word, "spt-threshold"))
  373: 	return CONF_SPT_THRESHOLD;
  374:     if (EQUAL(word, "default-route-metric"))
  375: 	return CONF_DEFAULT_ROUTE_METRIC;
  376:     if (EQUAL(word, "default-route-distance"))
  377: 	return CONF_DEFAULT_ROUTE_DISTANCE;
  378:     if (EQUAL(word, "igmp-query-interval"))
  379: 	return CONF_IGMP_QUERY_INTERVAL;
  380:     if (EQUAL(word, "igmp-querier-timeout"))
  381: 	return CONF_IGMP_QUERIER_TIMEOUT;
  382:     if (EQUAL(word, "altnet"))
  383: 	return CONF_ALTNET;
  384:     if  (EQUAL(word, "masklen"))
  385: 	return CONF_MASKLEN;
  386:     if  (EQUAL(word, "scoped"))
  387: 	return CONF_SCOPED;
  388:     if (EQUAL(word, "hello-interval"))
  389: 	return CONF_HELLO_INTERVAL;
  390: 
  391:     /* Compatibility with old config files that use _ instead of - */
  392:     if (EQUAL(word, "cand_bootstrap_router"))
  393: 	return CONF_BOOTSTRAP_RP;
  394:     if (EQUAL(word, "cand_rp"))
  395: 	return CONF_CANDIDATE_RP;
  396:     if (EQUAL(word, "group_prefix"))
  397: 	return CONF_GROUP_PREFIX;
  398:     if (EQUAL(word, "rp_address"))
  399: 	return CONF_RP_ADDRESS;
  400:     if (EQUAL(word, "switch_register_threshold"))
  401: 	return deprecated(word, "spt-threshold", CONF_COMPAT_THRESHOLD);
  402:     if (EQUAL(word, "switch_data_threshold"))
  403: 	return deprecated(word, "spt-threshold", CONF_COMPAT_THRESHOLD);
  404:     if (EQUAL(word, "spt_threshold"))
  405: 	return CONF_SPT_THRESHOLD;
  406:     if (EQUAL(word, "default_source_metric"))
  407: 	return CONF_DEFAULT_ROUTE_METRIC;
  408:     if (EQUAL(word, "default_source_preference"))
  409: 	return CONF_DEFAULT_ROUTE_DISTANCE;
  410:     if (EQUAL(word, "default_igmp_query_interval"))  /* compat */
  411: 	return CONF_IGMP_QUERY_INTERVAL;
  412:     if (EQUAL(word, "default_igmp_querier_timeout")) /* compat */
  413: 	return CONF_IGMP_QUERIER_TIMEOUT;
  414:     if (EQUAL(word, "hello_period"))
  415: 	return CONF_HELLO_INTERVAL;
  416: 
  417:     return CONF_UNKNOWN;
  418: }
  419: 
  420: /* Check for optional /PREFIXLEN suffix to the address/group */
  421: static void parse_prefix_len(char *token, uint32_t *len)
  422: {
  423:     char *masklen = strchr(token, '/');
  424: 
  425:     if (masklen) {
  426: 	*masklen = 0;
  427: 	masklen++;
  428: 	if (!sscanf(masklen, "%u", len)) {
  429: 	    WARN("Invalid masklen '%s'", masklen);
  430: 	    *len = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
  431: 	}
  432:     }
  433: }
  434: 
  435: static void validate_prefix_len(uint32_t *len)
  436: {
  437:     if (*len > (sizeof(uint32_t) * 8)) {
  438: 	*len = (sizeof(uint32_t) * 8);
  439:     } else if (*len < PIM_GROUP_PREFIX_MIN_MASKLEN) {
  440: 	WARN("Too small masklen %u. Defaulting to %d", *len, PIM_GROUP_PREFIX_MIN_MASKLEN);
  441: 	*len = PIM_GROUP_PREFIX_MIN_MASKLEN;
  442:     }
  443: }
  444: 
  445: 
  446: /**
  447:  * parse_phyint - Parse physical interface configuration, if any.
  448:  * @s: String token
  449:  *
  450:  * Syntax:
  451:  * phyint <local-addr | ifname> [disable | enable]
  452:  *                              [igmpv2  | igmpv3]
  453:  *                              [dr-priority <1-4294967294>]
  454:  *                              [ttl-threshold <1-255>]
  455:  *                              [distance <1-255>] [metric <1-1024>]
  456:  *                              [altnet <net-addr>/<masklen>]
  457:  *                              [altnet <net-addr> masklen <masklen>]
  458:  *                              [scoped <net-addr>/<masklen>]
  459:  *                              [scoped <net-addr> masklen <masklen>]
  460:  *
  461:  * Returns:
  462:  * %TRUE if the parsing was successful, o.w. %FALSE
  463:  */
  464: static int parse_phyint(char *s)
  465: {
  466:     char *w, c;
  467:     uint32_t local, altnet_addr, scoped_addr;
  468:     vifi_t vifi;
  469:     struct uvif *v;
  470:     uint32_t n, altnet_masklen = 0, scoped_masklen = 0;
  471:     struct phaddr *ph;
  472:     struct vif_acl *v_acl;
  473: 
  474:     if (EQUAL((w = next_word(&s)), "")) {
  475: 	WARN("Missing phyint address");
  476: 	return FALSE;
  477:     }
  478: 
  479:     local = ifname2addr(w);
  480:     if (!local) {
  481: 	local = inet_parse(w, 4);
  482: 	if (!inet_valid_host(local)) {
  483: 	    WARN("Invalid phyint address '%s'", w);
  484: 	    return FALSE;
  485: 	}
  486:     }
  487: 
  488:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  489: 	if (vifi == numvifs) {
  490: 	    WARN("phyint %s is not a valid interface", inet_fmt(local, s1, sizeof(s1)));
  491: 	    return FALSE;
  492: 	}
  493: 
  494: 	if (local != v->uv_lcl_addr)
  495: 	    continue;
  496: 
  497: 	while (!EQUAL((w = next_word(&s)), "")) {
  498: 	    if (EQUAL(w, "disable")) {
  499: 		v->uv_flags |= VIFF_DISABLED;
  500: 		continue;
  501: 	    }
  502: 
  503: 	    if (EQUAL(w, "enable")) {
  504: 		v->uv_flags &= ~VIFF_DISABLED;
  505: 		continue;
  506: 	    }
  507: 
  508: 	    if (EQUAL(w, "igmpv2")) {
  509: 		v->uv_flags &= ~VIFF_IGMPV1;
  510: 		v->uv_flags |=  VIFF_IGMPV2;
  511: 		continue;
  512: 	    }
  513: 
  514: 	    if (EQUAL(w, "igmpv3")) {
  515: 		v->uv_flags &= ~VIFF_IGMPV1;
  516: 		v->uv_flags &= ~VIFF_IGMPV2;
  517: 		continue;
  518: 	    }
  519: 
  520: 	    if (EQUAL(w, "altnet")) {
  521: 		if (EQUAL((w = next_word(&s)), "")) {
  522: 		    WARN("Missing ALTNET for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  523: 		    continue;
  524: 		}
  525: 
  526: 		parse_prefix_len (w, &altnet_masklen);
  527: 
  528: 		altnet_addr = ifname2addr(w);
  529: 		if (!altnet_addr) {
  530: 		    altnet_addr = inet_parse(w, 4);
  531: 		    if (!inet_valid_host(altnet_addr)) {
  532: 			WARN("Invalid altnet address '%s'", w);
  533: 			return FALSE;
  534: 		    }
  535: 		}
  536: 
  537: 		if (EQUAL((w = next_word(&s)), "masklen")) {
  538: 		    if (EQUAL((w = next_word(&s)), "")) {
  539: 			WARN("Missing ALTNET masklen for phyint %s", inet_fmt(local, s1, sizeof (s1)));
  540: 			continue;
  541: 		    }
  542: 
  543: 		    if (!sscanf(w, "%u", &altnet_masklen)) {
  544: 			WARN("Invalid altnet masklen '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  545: 			continue;
  546: 		    }
  547: 		}
  548: 
  549: 		ph = (struct phaddr *)calloc(1, sizeof(struct phaddr));
  550: 		if (!ph)
  551: 		    return FALSE;
  552: 
  553: 		if (altnet_masklen) {
  554: 		    VAL_TO_MASK(ph->pa_subnetmask, altnet_masklen);
  555: 		} else {
  556: 		    ph->pa_subnetmask = v->uv_subnetmask;
  557: 		}
  558: 
  559: 		ph->pa_subnet = altnet_addr & ph->pa_subnetmask;
  560: 		ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
  561: 		if (altnet_addr & ~ph->pa_subnetmask)
  562: 		    WARN("Extra subnet %s/%d has host bits set", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen);
  563: 
  564: 		ph->pa_next = v->uv_addrs;
  565: 		v->uv_addrs = ph;
  566: 		logit(LOG_DEBUG, 0, "ALTNET: %s/%d", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen);
  567: 	    } /* altnet */
  568: 
  569: 	    /* scoped mcast groups/masklen */
  570: 	    if (EQUAL(w, "scoped")) {
  571: 		if (EQUAL((w = next_word(&s)), "")) {
  572: 		    WARN("Missing SCOPED for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  573: 		    continue;
  574: 		}
  575: 
  576: 		parse_prefix_len (w, &scoped_masklen);
  577: 
  578: 		scoped_addr = ifname2addr(w);
  579: 		if (!scoped_addr) {
  580: 		    scoped_addr = inet_parse(w, 4);
  581: 		    if (!IN_MULTICAST(ntohl(scoped_addr))) {
  582: 			WARN("Invalid scoped address '%s'", w);
  583: 			return FALSE;
  584: 		    }
  585: 		}
  586: 
  587: 		if (EQUAL((w = next_word(&s)), "masklen")) {
  588: 		    if (EQUAL((w = next_word(&s)), "")) {
  589: 			WARN("Missing SCOPED masklen for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  590: 			continue;
  591: 		    }
  592: 		    if (sscanf(w, "%u", &scoped_masklen) != 1) {
  593: 			WARN("Invalid scoped masklen '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  594: 			continue;
  595: 		    }
  596: 		}
  597: 
  598: 		/* Invalid config. VAL_TO_MASK() also requires len > 0 or shift op will fail. */
  599: 		if (!scoped_masklen) {
  600: 		    WARN("Too small (0) scoped masklen for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  601: 		    continue;
  602: 		}
  603: 
  604: 		v_acl = (struct vif_acl *)calloc(1, sizeof(struct vif_acl));
  605: 		if (!v_acl)
  606: 		    return FALSE;
  607: 
  608: 		VAL_TO_MASK(v_acl->acl_mask, scoped_masklen);
  609: 		v_acl->acl_addr = scoped_addr & v_acl->acl_mask;
  610: 		if (scoped_addr & ~v_acl->acl_mask)
  611: 		    WARN("Boundary spec %s/%d has host bits set", inet_fmt(scoped_addr, s1, sizeof(s1)), scoped_masklen);
  612: 
  613: 		v_acl->acl_next = v->uv_acl;
  614: 		v->uv_acl = v_acl;
  615: 		logit(LOG_DEBUG, 0, "SCOPED %s/%x", inet_fmt(v_acl->acl_addr, s1, sizeof(s1)), v_acl->acl_mask);
  616: 	    } /* scoped */
  617: 
  618: 	    if (EQUAL(w, "ttl-threshold") || EQUAL(w, "threshold")) {
  619: 		if (EQUAL((w = next_word(&s)), "")) {
  620: 		    WARN("Missing threshold for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  621: 		    continue;
  622: 		}
  623: 
  624: 		if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) {
  625: 		    WARN("Invalid threshold '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  626: 		    continue;
  627: 		}
  628: 
  629: 		v->uv_threshold = n;
  630: 		continue;
  631: 	    } /* threshold */
  632: 
  633: 	    if (EQUAL(w, "distance") || EQUAL(w, "preference")) {
  634: 		if (EQUAL((w = next_word(&s)), "")) {
  635: 		    WARN("Missing distance value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  636: 		    continue;
  637: 		}
  638: 
  639: 		if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) {
  640: 		    WARN("Invalid distance value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  641: 		    continue;
  642: 		}
  643: 
  644: 		IF_DEBUG(DEBUG_ASSERT)
  645: 		    logit(LOG_DEBUG, 0, "Config setting default local preference on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
  646: 
  647: 		v->uv_local_pref = n;
  648: 		continue;
  649: 	    }
  650: 
  651: 	    if (EQUAL(w, "metric")) {
  652: 		if (EQUAL((w = next_word(&s)), "")) {
  653: 		    WARN("Missing metric value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  654: 		    continue;
  655: 		}
  656: 
  657: 		if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 1024 ) {
  658: 		    WARN("Invalid metric value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  659: 		    continue;
  660: 		}
  661: 
  662: 		IF_DEBUG(DEBUG_ASSERT)
  663: 		    logit(LOG_DEBUG, 0, "Setting default local metric on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
  664: 
  665: 		v->uv_local_metric = n;
  666: 		continue;
  667: 	    }
  668: 
  669: 	    if (EQUAL(w, "dr-priority")) {
  670: 		if (EQUAL((w = next_word(&s)), "")) {
  671: 		    WARN("Missing dr-priority value for phyint %s", inet_fmt(local, s1, sizeof(s1)));
  672: 		    continue;
  673: 		}
  674: 
  675: 		if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 4294967294u) {
  676: 		    WARN("Invalid dr-priority value '%s' for phyint %s", w, inet_fmt(local, s1, sizeof(s1)));
  677: 		    continue;
  678: 		}
  679: 
  680: 		IF_DEBUG(DEBUG_PIM_HELLO)
  681: 		    logit(LOG_DEBUG, 0, "Setting dr-priority on %s to %d", inet_fmt(local, s1, sizeof(s1)), n);
  682: 
  683: 		v->uv_dr_prio = n;
  684: 		continue;
  685: 	    }
  686: 	} /* while(... != "") */
  687: 
  688: 	break;
  689:     }
  690: 
  691:     return TRUE;
  692: }
  693: 
  694: 
  695: /**
  696:  * parse_rp_candidate - Parse candidate Rendez-Vous Point information.
  697:  * @s: String token
  698:  *
  699:  * Syntax:
  700:  * rp-candidate [address | ifname] [priority <0-255>] [time <10-16383>]
  701:  *
  702:  * Returns:
  703:  * %TRUE if the parsing was successful, o.w. %FALSE
  704:  */
  705: int parse_rp_candidate(char *s)
  706: {
  707:     u_int time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
  708:     u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY;
  709:     char *w;
  710:     uint32_t local = INADDR_ANY_N;
  711: 
  712:     cand_rp_flag = FALSE;
  713:     my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
  714:     while (!EQUAL((w = next_word(&s)), "")) {
  715: 	if (EQUAL(w, "priority")) {
  716: 	    if (EQUAL((w = next_word(&s)), "")) {
  717: 		WARN("Missing priority, defaulting to %u", w, PIM_DEFAULT_CAND_RP_PRIORITY);
  718: 		priority = PIM_DEFAULT_CAND_RP_PRIORITY;
  719: 		continue;
  720: 	    }
  721: 
  722: 	    if (sscanf(w, "%u", &priority) != 1) {
  723: 		WARN("Invalid priority %s, defaulting to %u", w, PIM_DEFAULT_CAND_RP_PRIORITY);
  724: 		priority = PIM_DEFAULT_CAND_RP_PRIORITY;
  725: 	    }
  726: 
  727: 	    if (priority > PIM_MAX_CAND_RP_PRIORITY) {
  728: 		WARN("Too high Cand-RP priority %u, defaulting to %d", priority, PIM_MAX_CAND_RP_PRIORITY);
  729: 		priority = PIM_MAX_CAND_RP_PRIORITY;
  730: 	    }
  731: 
  732: 	    continue;
  733: 	}
  734: 
  735: 	if (EQUAL(w, "time")) {
  736: 	    if (EQUAL((w = next_word(&s)), "")) {
  737: 		WARN("Missing Cand-RP announce interval, defaulting to %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD);
  738: 		time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
  739: 		continue;
  740: 	    }
  741: 
  742: 	    if (sscanf(w, "%u", &time) != 1) {
  743: 		WARN("Invalid Cand-RP announce interval, defaulting to %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD);
  744: 		time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
  745: 		continue;
  746: 	    }
  747: 
  748: 	    if (time < PIM_MIN_CAND_RP_ADV_PERIOD)
  749: 		time = PIM_MIN_CAND_RP_ADV_PERIOD;
  750: 
  751: 	    if (time > PIM_MAX_CAND_RP_ADV_PERIOD)
  752: 		time = PIM_MAX_CAND_RP_ADV_PERIOD;
  753: 
  754: 	    my_cand_rp_adv_period = time;
  755: 	    continue;
  756: 	}
  757: 
  758: 	/* Cand-RP interface or address */
  759: 	local = ifname2addr(w);
  760: 	if (!local)
  761: 	    local = inet_parse(w, 4);
  762: 
  763: 	if (!inet_valid_host(local)) {
  764: 	    local = max_local_address();
  765: 	    WARN("Invalid Cand-RP address '%s', defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
  766: 	} else if (local_address(local) == NO_VIF) {
  767: 	    local = max_local_address();
  768: 	    WARN("Cand-RP address '%s' is not local, defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
  769: 	}
  770:     }
  771: 
  772:     if (local == INADDR_ANY_N) {
  773: 	/* If address not provided, use the max. local */
  774: 	local = max_local_address();
  775:     }
  776: 
  777:     my_cand_rp_address = local;
  778:     my_cand_rp_priority = priority;
  779:     my_cand_rp_adv_period = time;
  780:     cand_rp_flag = TRUE;
  781: 
  782:     logit(LOG_INFO, 0, "Local Cand-RP address %s, priority %u, interval %u sec",
  783: 	  inet_fmt(local, s1, sizeof(s1)), priority, time);
  784: 
  785:     return TRUE;
  786: }
  787: 
  788: 
  789: /**
  790:  * parse_group_prefix - Parse group-prefix configured information.
  791:  * @s: String token
  792: 
  793:  * Syntax:
  794:  * group-prefix <group>[/<masklen>]
  795:  *              <group> [masklen <masklen>]
  796:  *
  797:  * Returns:
  798:  * %TRUE if the parsing was successful, o.w. %FALSE
  799:  */
  800: int parse_group_prefix(char *s)
  801: {
  802:     char *w;
  803:     uint32_t group_addr;
  804:     uint32_t  masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
  805: 
  806:     w = next_word(&s);
  807:     if (EQUAL(w, "")) {
  808: 	WARN("Missing group-prefix address");
  809: 	return FALSE;
  810:     }
  811: 
  812:     parse_prefix_len (w, &masklen);
  813: 
  814:     group_addr = inet_parse(w, 4);
  815:     if (!IN_MULTICAST(ntohl(group_addr))) {
  816: 	WARN("Group address '%s' is not a valid multicast address", inet_fmt(group_addr, s1, sizeof(s1)));
  817: 	return FALSE;
  818:     }
  819: 
  820:     /* Was if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) which Arm GCC 4.4.2 dislikes:
  821:      *  --> "config.c:693: warning: promoted ~unsigned is always non-zero"
  822:      * The prefix_cnt_ptr is a uint8_t so it seems this check was to prevent overruns.
  823:      * I've changed the check to see if we've already read 255 entries, if so the cnt
  824:      * is maximized and we need to tell the user. --Joachim Nilsson 2010-01-16 */
  825:     if (*cand_rp_adv_message.prefix_cnt_ptr == 255) {
  826: 	WARN("Too many multicast groups configured!");
  827: 	return FALSE;
  828:     }
  829: 
  830:     if (EQUAL((w = next_word(&s)), "masklen")) {
  831: 	w = next_word(&s);
  832: 	if (!sscanf(w, "%u", &masklen))
  833: 	    masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
  834:     }
  835: 
  836:     validate_prefix_len(&masklen);
  837: 
  838:     PUT_EGADDR(group_addr, (uint8_t)masklen, 0, cand_rp_adv_message.insert_data_ptr);
  839:     (*cand_rp_adv_message.prefix_cnt_ptr)++;
  840: 
  841:     logit(LOG_INFO, 0, "Adding Cand-RP group prefix %s/%d", inet_fmt(group_addr, s1, sizeof(s1)), masklen);
  842: 
  843:     return TRUE;
  844: }
  845: 
  846: 
  847: /**
  848:  * parse_bsr_candidate - Parse the candidate BSR configured information.
  849:  * @s: String token
  850:  *
  851:  * Syntax:
  852:  * bsr-candidate [address | ifname] [priority <0-255>]
  853:  */
  854: int parse_bsr_candidate(char *s)
  855: {
  856:     char *w;
  857:     uint32_t local    = INADDR_ANY_N;
  858:     uint32_t priority = PIM_DEFAULT_BSR_PRIORITY;
  859: 
  860:     cand_bsr_flag = FALSE;
  861:     while (!EQUAL((w = next_word(&s)), "")) {
  862: 	if (EQUAL(w, "priority")) {
  863: 	    if (EQUAL((w = next_word(&s)), "")) {
  864: 		WARN("Missing Cand-BSR priority, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
  865: 		priority = PIM_DEFAULT_BSR_PRIORITY;
  866: 		continue;
  867: 	    }
  868: 
  869: 	    if (sscanf(w, "%u", &priority) != 1) {
  870: 		WARN("Invalid Cand-BSR priority %s, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
  871: 		priority = PIM_DEFAULT_BSR_PRIORITY;
  872: 		continue;
  873: 	    }
  874: 
  875: 	    if (priority > PIM_MAX_CAND_BSR_PRIORITY) {
  876: 		WARN("Too high Cand-BSR priority %u, defaulting to %d", priority, PIM_MAX_CAND_BSR_PRIORITY);
  877: 		priority = PIM_MAX_CAND_BSR_PRIORITY;
  878: 	    }
  879: 
  880: 	    my_bsr_priority = (uint8_t)priority;
  881: 	    continue;
  882: 	}
  883: 
  884: 	/* Cand-BSR interface or address */
  885: 	local = ifname2addr(w);
  886: 	if (!local)
  887: 	    local = inet_parse(w, 4);
  888: 
  889: 	if (!inet_valid_host(local)) {
  890: 	    local = max_local_address();
  891: 	    WARN("Invalid Cand-BSR address '%s', defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
  892: 	    continue;
  893: 	}
  894: 
  895: 	if (local_address(local) == NO_VIF) {
  896: 	    local = max_local_address();
  897: 	    WARN("Cand-BSR address '%s' is not local, defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
  898: 	}
  899:     }
  900: 
  901:     if (local == INADDR_ANY_N) {
  902: 	/* If address not provided, use the max. local */
  903: 	local = max_local_address();
  904:     }
  905: 
  906:     my_bsr_address  = local;
  907:     my_bsr_priority = priority;
  908:     MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, my_bsr_hash_mask);
  909:     cand_bsr_flag   = TRUE;
  910:     logit(LOG_INFO, 0, "Local Cand-BSR address %s, priority %u", inet_fmt(local, s1, sizeof(s1)), priority);
  911: 
  912:     return TRUE;
  913: }
  914: 
  915: /**
  916:  * parse_rp_address - Parse rp-address config option.
  917:  * @s: String token.
  918:  *
  919:  * This is an extension to the original pimd to add pimd.conf support for static
  920:  * Rendez-Vous Point addresses.
  921:  *
  922:  * The function has been extended by pjf@asn.pl, of Lintrack, to allow specifying
  923:  * multicast group addresses as well.
  924:  *
  925:  * Syntax:
  926:  * rp-address <ADDRESS> [<GROUP>[</LENGTH> masklen <LENGTH>]
  927:  *
  928:  * Returns:
  929:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
  930:  */
  931: int parse_rp_address(char *s)
  932: {
  933:     char *w;
  934:     uint32_t local = 0xffffff;
  935:     uint32_t group_addr = htonl(INADDR_UNSPEC_GROUP);
  936:     uint32_t masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
  937:     struct rp_hold *rph;
  938: 
  939:     /* next is RP addr */
  940:     w = next_word(&s);
  941:     if (EQUAL(w, "")) {
  942: 	logit(LOG_WARNING, 0, "Missing rp-address argument");
  943: 	return FALSE;
  944:     }
  945: 
  946:     local = inet_parse(w, 4);
  947:     if (local == 0xffffff) {
  948: 	WARN("Invalid rp-address %s", w);
  949: 	return FALSE;
  950:     }
  951: 
  952:     /* next is group addr if exist */
  953:     w = next_word(&s);
  954:     if (!EQUAL(w, "")) {
  955: 	parse_prefix_len (w, &masklen);
  956: 
  957: 	group_addr = inet_parse(w, 4);
  958: 	if (!IN_MULTICAST(ntohl(group_addr))) {
  959: 	    WARN("%s is not a valid multicast address", inet_fmt(group_addr, s1, sizeof(s1)));
  960: 	    return FALSE;
  961: 	}
  962: 
  963: 	/* next is prefix or priority if exist */
  964: 	while (!EQUAL((w = next_word(&s)), "")) {
  965: 	    if (EQUAL(w, "masklen")) {
  966: 		w = next_word(&s);
  967: 		if (!sscanf(w, "%u", &masklen)) {
  968: 		    WARN("Invalid masklen %s. Defaulting to %d)", w, PIM_GROUP_PREFIX_DEFAULT_MASKLEN);
  969: 		    masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
  970: 		}
  971: 	    }
  972: 
  973: 	    /* Unused, but keeping for backwards compatibility for people who
  974: 	     * may still have this option in their pimd.conf
  975: 	     * The priority of a static RP is hardcoded to always be 1, see Juniper's
  976: 	     * configuration or similar sources for reference. */
  977: 	    if (EQUAL(w, "priority")) {
  978: 		w = next_word(&s);
  979: 		WARN("The priority of static RP's is, as of pimd 2.2.0, always 1.");
  980: 	    }
  981: 	}
  982:     } else {
  983: 	group_addr = htonl(INADDR_UNSPEC_GROUP);
  984: 	masklen = PIM_GROUP_PREFIX_MIN_MASKLEN;
  985:     }
  986: 
  987:     validate_prefix_len(&masklen);
  988: 
  989:     rph = calloc(1, sizeof(*rph));
  990:     if (!rph) {
  991: 	logit(LOG_WARNING, 0, "Out of memory when parsing rp-address %s",
  992: 	      inet_fmt(local, s1, sizeof(s1)));
  993: 	return FALSE;
  994:     }
  995: 
  996:     rph->address = local;
  997:     rph->group = group_addr;
  998:     VAL_TO_MASK(rph->mask, masklen);
  999: 
 1000:     /* attach at the beginning */
 1001:     rph->next = g_rp_hold;
 1002:     g_rp_hold = rph;
 1003: 
 1004:     logit(LOG_INFO, 0, "Local static RP: %s, group %s/%d",
 1005: 	  inet_fmt(local, s1, sizeof(s1)), inet_fmt(group_addr, s2, sizeof(s2)), masklen);
 1006: 
 1007:     return TRUE;
 1008: }
 1009: 
 1010: 
 1011: /**
 1012:  * parse_compat_threshold - Parse old deprecated pimd.conf thresholds
 1013:  * @line:
 1014:  *
 1015:  * This is a backwards compatible parser for the two older threshold
 1016:  * settings used in pimd prior to v2.2.0.  The switchover mechanism has
 1017:  * been completely changed, however, so we simply read the settings as
 1018:  * if they where the same as the new spt-threshold, only converting the
 1019:  * rate argument differently (bps vs kbps).  Last line to be read is
 1020:  * what is activated in pimd as spt-threshold.
 1021:  *
 1022:  * Note, previously the parser was very lenient to errors, but since the
 1023:  * default has changed it is much more strict. Any syntax error and pimd
 1024:  * bails out ignoring the line.
 1025:  *
 1026:  * Syntax:
 1027:  * switch_register_threshold [rate <BPS> interval <SEC>]
 1028:  * switch_data_threshold     [rate <BPS> interval <SEC>]
 1029:  *
 1030:  * Returns:
 1031:  * When parsing @line is successful, returns %TRUE, otherwise %FALSE.
 1032:  */
 1033: static int parse_compat_threshold(char *line)
 1034: {
 1035:     char *w;
 1036:     int rate     = -1;
 1037:     int interval = -1;
 1038: 
 1039:     while (!EQUAL((w = next_word(&line)), "")) {
 1040: 	if (EQUAL(w, "rate")) {
 1041: 	    if (EQUAL((w = next_word(&line)), ""))
 1042: 		BAILOUT("Missing rate value in compat threshold parser");
 1043: 
 1044: 	    /* 10 --> 1,000,000,000 == 100 Gbps */
 1045: 	    if (sscanf(w, "%10d", &rate) != 1)
 1046: 		BAILOUT("Invalid rate value %s in compat threshold parser", w);
 1047: 
 1048: 	    continue;
 1049: 	}
 1050: 
 1051: 	if (EQUAL(w, "interval")) {
 1052: 	    if (EQUAL((w = next_word(&line)), ""))
 1053: 		IGNORING("Missing interval value in compat threshold parser");
 1054: 
 1055: 	    /* 5 --> 99,999 ~= 27h */
 1056: 	    if (sscanf(w, "%5d", &interval) != 1)
 1057: 		IGNORING("Invalid interval %s in compat threshold parser", w);
 1058: 
 1059: 	    continue;
 1060: 	}
 1061:     }
 1062: 
 1063:     /* Set polling mode */
 1064:     spt_threshold.mode = SPT_RATE;
 1065: 
 1066:     /* Only accept values if they don't messup for new spt-threshold */
 1067:     if (interval >= TIMER_INTERVAL)
 1068: 	spt_threshold.interval = interval;
 1069: 
 1070:     /* Accounting for headers we can approximate 1 byte/s == 10 bits/s (bps) */
 1071:     spt_threshold.bytes = rate * spt_threshold.interval / 10;
 1072: 
 1073:     logit(LOG_INFO, 0, "Compatibility set spt-treshold rate %u kbps with interval %u sec",
 1074: 	  spt_threshold.bytes, spt_threshold.interval);
 1075: 
 1076:     return TRUE;
 1077: }
 1078: 
 1079: 
 1080: /**
 1081:  * parse_hello_interval - Parse and assign the hello interval
 1082:  * @s: Input data
 1083:  *
 1084:  * Syntax:
 1085:  *	    hello-interval <SEC>
 1086:  *
 1087:  * Returns:
 1088:  * %TRUE if successful, otherwise %FALSE.
 1089:  */
 1090: int parse_hello_interval(char *s)
 1091: {
 1092:     char *w;
 1093:     u_int period;
 1094:     u_int holdtime;
 1095: 
 1096:     if (!EQUAL((w = next_word(&s)), "")) {
 1097: 	if (sscanf(w, "%u", &period) != 1) {
 1098: 	    logit(LOG_WARNING, 0, "Invalid hello-interval %s; defaulting to %u", w, PIM_TIMER_HELLO_INTERVAL);
 1099: 	    period = PIM_TIMER_HELLO_INTERVAL;
 1100: 	    holdtime = PIM_TIMER_HELLO_HOLDTIME;
 1101: 	} else {
 1102: 	    if (period <= (u_int)(UINT16_MAX / 3.5)) {
 1103: 		holdtime = period * 3.5;
 1104: 	    } else {
 1105: 		logit(LOG_WARNING, 0, "Too large hello-interval %s; defaulting to %u", w, PIM_TIMER_HELLO_INTERVAL);
 1106: 		period = PIM_TIMER_HELLO_INTERVAL;
 1107: 		holdtime = PIM_TIMER_HELLO_HOLDTIME;
 1108: 	    }
 1109: 	}
 1110:     } else {
 1111: 	logit(LOG_WARNING, 0, "Missing hello-interval value; defaulting to %u", PIM_TIMER_HELLO_INTERVAL);
 1112: 	period = PIM_TIMER_HELLO_INTERVAL;
 1113: 	holdtime = PIM_TIMER_HELLO_HOLDTIME;
 1114:     }
 1115: 
 1116:     logit(LOG_INFO, 0, "hello-interval is %u", period);
 1117:     pim_timer_hello_interval = period;
 1118:     pim_timer_hello_holdtime = holdtime;
 1119: 
 1120:     return TRUE;
 1121: }
 1122: 
 1123: 
 1124: /**
 1125:  * parse_spt_threshold - Parse spt-threshold option
 1126:  * @s: String token
 1127:  *
 1128:  * This configuration setting replaces the switch_register_threshold and
 1129:  * switch_data_threshold.  It is more intuitive and more in line with
 1130:  * what major vendors are also using.
 1131:  *
 1132:  * Note that the rate is in kbps instead of bps, compared to the old
 1133:  * syntax.  Both the above parse_compat_threshold() and this function
 1134:  * target the same backend.
 1135:  *
 1136:  * Syntax:
 1137:  * spt-threshold [rate <KBPS> | packets <NUM> | infinity] [interval <SEC>]
 1138:  *
 1139:  * Returns:
 1140:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
 1141:  */
 1142: static int parse_spt_threshold(char *s)
 1143: {
 1144:     char *w;
 1145:     uint32_t rate     = SPT_THRESHOLD_DEFAULT_RATE;
 1146:     uint32_t packets  = SPT_THRESHOLD_DEFAULT_PACKETS;
 1147:     uint32_t interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
 1148:     spt_mode_t mode  = SPT_THRESHOLD_DEFAULT_MODE;
 1149: 
 1150:     while (!EQUAL((w = next_word(&s)), "")) {
 1151: 	if (EQUAL(w, "rate")) {
 1152: 	    mode = SPT_RATE;
 1153: 
 1154: 	    if (EQUAL((w = next_word(&s)), "")) {
 1155: 		WARN("Missing spt-threshold rate argument, defaulting to %u", SPT_THRESHOLD_DEFAULT_RATE);
 1156: 		rate = SPT_THRESHOLD_DEFAULT_RATE;
 1157: 		continue;
 1158: 	    }
 1159: 
 1160: 	    /* 10 --> 1,000,000,000 == 100 Gbps */
 1161: 	    if (sscanf(w, "%10u", &rate) != 1) {
 1162: 		WARN("Invalid spt-threshold rate %s, defaulting to %u", w, SPT_THRESHOLD_DEFAULT_RATE);
 1163: 		rate = SPT_THRESHOLD_DEFAULT_RATE;
 1164: 	    }
 1165: 
 1166: 	    continue;
 1167: 	}
 1168: 
 1169: 	if (EQUAL(w, "interval")) {
 1170: 	    if (EQUAL((w = next_word(&s)), "")) {
 1171: 		WARN("Missing spt-threshold interval; defaulting to %u sec",  SPT_THRESHOLD_DEFAULT_INTERVAL);
 1172: 		interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
 1173: 		continue;
 1174: 	    }
 1175: 
 1176: 	    /* 5 --> 99,999 ~= 27h */
 1177: 	    if (sscanf(w, "%5u", &interval) != 1) {
 1178: 		WARN("Invalid spt-threshold interval %s; defaulting to %u sec", w, SPT_THRESHOLD_DEFAULT_INTERVAL);
 1179: 		interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
 1180: 	    }
 1181: 
 1182: 	    if (interval < TIMER_INTERVAL) {
 1183: 		WARN("Too low spt-threshold interval %s; defaulting to %u sec", w, TIMER_INTERVAL);
 1184: 		interval = TIMER_INTERVAL;
 1185: 	    }
 1186: 
 1187: 	    continue;
 1188: 	}
 1189: 
 1190: 	if (EQUAL(w, "packets")) {
 1191: 	    mode = SPT_PACKETS;
 1192: 
 1193: 	    if (EQUAL((w = next_word(&s)), "")) {
 1194: 		WARN("Missing spt-threshold number of packets; defaulting to %u", SPT_THRESHOLD_DEFAULT_PACKETS);
 1195: 		packets = SPT_THRESHOLD_DEFAULT_PACKETS;
 1196: 		continue;
 1197: 	    }
 1198: 
 1199: 	    /* 10 --> 4294967295, which is max of uint32_t */
 1200: 	    if (sscanf(w, "%10u", &packets) != 1) {
 1201: 		WARN("Invalid spt-threshold packets %s; defaulting to %u",
 1202: 		     w, SPT_THRESHOLD_DEFAULT_PACKETS);
 1203: 		packets = SPT_THRESHOLD_DEFAULT_INTERVAL;
 1204: 	    }
 1205: 
 1206: 	    continue;
 1207: 	}
 1208: 
 1209: 	if (EQUAL(w, "infinity")) {
 1210: 	    mode = SPT_INF;
 1211: 	    continue;
 1212: 	}
 1213: 
 1214: 	WARN("Invalid spt-threshold parameter %s; reverting to defaults.", w);
 1215: 	mode     = SPT_THRESHOLD_DEFAULT_MODE;
 1216: 	rate     = SPT_THRESHOLD_DEFAULT_RATE;
 1217: 	packets  = SPT_THRESHOLD_DEFAULT_PACKETS;
 1218: 	interval = SPT_THRESHOLD_DEFAULT_INTERVAL;
 1219: 	break;
 1220:     }
 1221: 
 1222:     spt_threshold.mode = mode;
 1223:     switch (mode) {
 1224: 	case SPT_INF:
 1225: 	    logit(LOG_INFO, 0, "spt-threshold infinity => RP and lasthop router will never switch to SPT.");
 1226: 	    break;
 1227: 
 1228: 	case SPT_RATE:
 1229: 	    /* Accounting for headers we can approximate 1 byte/s == 10 bits/s (bps)
 1230: 	     * Note, in the new spt_threshold setting the rate is in kbps as well! */
 1231: 	    spt_threshold.bytes    = rate * interval / 10 * 1000;
 1232: 	    spt_threshold.interval = interval;
 1233: 	    logit(LOG_INFO, 0, "spt-threshold rate %u interval %u", rate, interval);
 1234: 	    break;
 1235: 
 1236: 	case SPT_PACKETS:
 1237: 	    spt_threshold.packets  = packets;
 1238: 	    spt_threshold.interval = interval;
 1239: 	    logit(LOG_INFO, 0, "spt-threshold packets %u interval %u", packets, interval);
 1240: 	    break;
 1241: 
 1242:     }
 1243: 
 1244:     return TRUE;
 1245: }
 1246: 
 1247: 
 1248: /**
 1249:  * parse_default_route_metric - Parse default-route-metric option
 1250:  * @s: String token
 1251:  *
 1252:  * Reads and assigns the route metric used for PIM Asserts by default.
 1253:  * This is used if pimd cannot read unicast route metrics from the
 1254:  * OS/kernel.
 1255:  *
 1256:  * Syntax:
 1257:  * default-route-metric <1-1024>
 1258:  *
 1259:  * Default routing protocol distance and route metric statements should
 1260:  * precede all phyint statements in the config file.
 1261:  *
 1262:  * Returns:
 1263:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
 1264:  */
 1265: int parse_default_route_metric(char *s)
 1266: {
 1267:     char *w;
 1268:     u_int value;
 1269:     vifi_t vifi;
 1270:     struct uvif *v;
 1271: 
 1272:     value = UCAST_DEFAULT_ROUTE_METRIC;
 1273:     if (EQUAL((w = next_word(&s)), "")) {
 1274: 	WARN("Missing route metric default; defaulting to %u", UCAST_DEFAULT_ROUTE_METRIC);
 1275:     } else if (sscanf(w, "%u", &value) != 1) {
 1276: 	WARN("Invalid route metric default; defaulting to %u", UCAST_DEFAULT_ROUTE_METRIC);
 1277: 	value = UCAST_DEFAULT_ROUTE_METRIC;
 1278:     }
 1279: 
 1280:     default_route_metric = value;
 1281:     logit(LOG_INFO, 0, "default-route-metric is %u", value);
 1282: 
 1283:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
 1284: 	v->uv_local_metric = default_route_metric;
 1285: 
 1286:     return TRUE;
 1287: }
 1288: 
 1289: 
 1290: /**
 1291:  * parse_default_route_distance - Parse default-route-distance option
 1292:  * @s: String token
 1293:  *
 1294:  * Reads and assigns the default source metric preference, i.e. routing
 1295:  * protocol distance.  This is used if pimd cannot read unicast routing
 1296:  * protocol information from the OS/kernel.
 1297:  *
 1298:  * Syntax:
 1299:  * default-route-distance <1-255>
 1300:  *
 1301:  * Default routing protocol distance and route metric statements should
 1302:  * precede all phyint statements in the config file.
 1303:  *
 1304:  * Returns:
 1305:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
 1306:  */
 1307: int parse_default_route_distance(char *s)
 1308: {
 1309:     char *w;
 1310:     u_int value;
 1311:     vifi_t vifi;
 1312:     struct uvif *v;
 1313: 
 1314:     value = UCAST_DEFAULT_ROUTE_DISTANCE;
 1315:     if (EQUAL((w = next_word(&s)), "")) {
 1316: 	WARN("Missing default routing protocol distance; defaulting to %u", UCAST_DEFAULT_ROUTE_DISTANCE);
 1317:     } else if (sscanf(w, "%u", &value) != 1) {
 1318: 	WARN("Invalid default routing protocol distance; defaulting to %u", UCAST_DEFAULT_ROUTE_DISTANCE);
 1319: 	value = UCAST_DEFAULT_ROUTE_DISTANCE;
 1320:     }
 1321: 
 1322:     default_route_distance = value;
 1323:     logit(LOG_INFO, 0, "default-route-distance is %u", value);
 1324:     for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
 1325: 	v->uv_local_pref = default_route_distance;
 1326: 
 1327:     return TRUE;
 1328: }
 1329: 
 1330: /**
 1331:  * parse_igmp_query_interval - Parse igmp-query-interval option
 1332:  * @s: String token
 1333:  *
 1334:  * Reads and assigns the default IGMP query interval.  If the argument
 1335:  * is missing or invalid the parser defaults to %IGMP_QUERY_INTERVAL
 1336:  *
 1337:  * Syntax:
 1338:  * igmp-query-interval <SEC>
 1339:  *
 1340:  * Returns:
 1341:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
 1342:  */
 1343: static int parse_igmp_query_interval(char *s)
 1344: {
 1345:     char *w;
 1346:     uint32_t value = IGMP_QUERY_INTERVAL;
 1347: 
 1348:     if (EQUAL((w = next_word(&s)), "")) {
 1349: 	WARN("Missing argument to igmp-query-interval; defaulting to %u", IGMP_QUERY_INTERVAL);
 1350:     } else if (sscanf(w, "%u", &value) != 1) {
 1351: 	WARN("Invalid default igmp-query-interval; defaulting to %u", IGMP_QUERY_INTERVAL);
 1352: 	value = IGMP_QUERY_INTERVAL;
 1353:     }
 1354: 
 1355:     igmp_query_interval = value;
 1356: 
 1357:     /* Calculate new querier timeout, or expect config option after this. */
 1358:     igmp_querier_timeout = 0;
 1359: 
 1360:     return TRUE;
 1361: }
 1362: 
 1363: /**
 1364:  * parse_igmp_querier_timeout - Parse igmp-querier-timeout option
 1365:  * @s: String token
 1366:  *
 1367:  * Reads and assigns default querier timeout for an active IGMP querier.
 1368:  * This is the time it takes before pimd tries to take over as the
 1369:  * active querier.  If the argument is missing or invalid the system
 1370:  * will calculate a fallback based on the query interval.
 1371:  *
 1372:  * Syntax:
 1373:  * igmp-querier-timeout <SEC>
 1374:  *
 1375:  * Returns:
 1376:  * When parsing @s is successful this function returns %TRUE, otherwise %FALSE.
 1377:  */
 1378: static int parse_igmp_querier_timeout(char *s)
 1379: {
 1380:     char *w;
 1381:     uint32_t value = 0;
 1382:     uint32_t recommended = QUERIER_TIMEOUT(igmp_query_interval);
 1383: 
 1384:     if (EQUAL((w = next_word(&s)), "")) {
 1385: 	WARN("Missing argument to igmp-querier-timeout!");
 1386:     } else if (sscanf(w, "%u", &value) != 1) {
 1387: 	WARN("Invalid default igmp-querier-timeout!");
 1388: 	value = 0;
 1389:     }
 1390: 
 1391:     /* Do some sanity checks to prevent invalid configuration and to recommend
 1392:      * better settings, see GitHub issue troglobit/pimd#31 for details. */
 1393:     if (value != 0) {
 1394: 	/* 1) Prevent invalid configuration */
 1395: 	if (value <= igmp_query_interval) {
 1396: 	    WARN("IGMP querier timeout %d must be larger than the query interval %d, forcing default!",
 1397: 		 value, igmp_query_interval);
 1398: 	    value = recommended;
 1399: 	}
 1400: 
 1401: 	/* 2) Warn power user of potentially too low setting. */
 1402: 	if (value < recommended)
 1403: 	    WARN("The IGMP querier timeout %d is smaller than the recommended value %d, allowing ...",
 1404: 		 value, recommended);
 1405: 
 1406: 	logit(LOG_WARNING, 0, "Recommended querier timeout = Robustness x query-interval + response-time / 2 = %d x %d + %d / 2 = %d",
 1407: 	      IGMP_ROBUSTNESS_VARIABLE, igmp_query_interval, IGMP_QUERY_RESPONSE_INTERVAL, recommended);
 1408:     }
 1409: 
 1410:     igmp_querier_timeout = value;
 1411: 
 1412:     return TRUE;
 1413: }
 1414: 
 1415: static void fallback_config(void)
 1416: {
 1417:     char buf[LINE_BUFSIZ], *s = buf;
 1418: 
 1419:     logit(LOG_NOTICE, 0, "Using built-in defaults, including RP/BSR candidate.");
 1420: 
 1421:     snprintf(buf, sizeof(buf), "priority 20 time 30");
 1422:     parse_rp_candidate(s);
 1423: 
 1424:     snprintf(buf, sizeof(buf), "priority 5");
 1425:     parse_bsr_candidate(s);
 1426: }
 1427: 
 1428: void config_vifs_from_file(void)
 1429: {
 1430:     FILE *fp;
 1431:     char linebuf[LINE_BUFSIZ];
 1432:     char *w, *s;
 1433:     int option;
 1434:     uint8_t *data_ptr;
 1435:     int error_flag;
 1436: 
 1437:     error_flag = FALSE;
 1438:     lineno = 0;
 1439: 
 1440:     /* TODO: HARDCODING!!! */
 1441:     cand_rp_adv_message.buffer = calloc(1, 4 + sizeof(pim_encod_uni_addr_t) +
 1442: 					255 * sizeof(pim_encod_grp_addr_t));
 1443:     if (!cand_rp_adv_message.buffer)
 1444: 	logit(LOG_ERR, errno, "Ran out of memory in config_vifs_from_file()");
 1445: 
 1446:     cand_rp_adv_message.prefix_cnt_ptr  = cand_rp_adv_message.buffer;
 1447:     /* By default, if no group-prefix configured, then prefix_cnt == 0
 1448:      * implies group-prefix = 224.0.0.0 and masklen = 4.
 1449:      */
 1450:     *cand_rp_adv_message.prefix_cnt_ptr = 0;
 1451:     cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
 1452:     /* TODO: XXX: HARDCODING!!! */
 1453:     cand_rp_adv_message.insert_data_ptr += (4 + 6);
 1454: 
 1455:     fp = fopen(config_file, "r");
 1456:     if (!fp) {
 1457: 	logit(LOG_WARNING, errno, "Cannot open configuration file %s", config_file);
 1458: 	fallback_config();
 1459: 	goto nofile;
 1460:     }
 1461: 
 1462:     while (fgets(linebuf, sizeof(linebuf), fp)) {
 1463: 	if (strlen(linebuf) >= (LINE_BUFSIZ - 1)) {
 1464: 	    WARN("Line length must be shorter than %d", LINE_BUFSIZ);
 1465: 	    error_flag = TRUE;
 1466: 	}
 1467: 	lineno++;
 1468: 
 1469: 	s = linebuf;
 1470: 	w = next_word(&s);
 1471: 	option = parse_option(w);
 1472: 
 1473: 	switch (option) {
 1474: 	    case CONF_EMPTY:
 1475: 		continue;
 1476: 		break;
 1477: 
 1478: 	    case CONF_PHYINT:
 1479: 		parse_phyint(s);
 1480: 		break;
 1481: 
 1482: 	    case CONF_CANDIDATE_RP:
 1483: 		parse_rp_candidate(s);
 1484: 		break;
 1485: 
 1486: 	    case CONF_RP_ADDRESS:
 1487: 		parse_rp_address(s);
 1488: 		break;
 1489: 
 1490: 	    case CONF_GROUP_PREFIX:
 1491: 		parse_group_prefix(s);
 1492: 		break;
 1493: 
 1494: 	    case CONF_BOOTSTRAP_RP:
 1495: 		parse_bsr_candidate(s);
 1496: 		break;
 1497: 
 1498: 	    case CONF_COMPAT_THRESHOLD:
 1499: 		parse_compat_threshold(s);
 1500: 		break;
 1501: 
 1502: 	    case CONF_SPT_THRESHOLD:
 1503: 		parse_spt_threshold(s);
 1504: 		break;
 1505: 
 1506: 	    case CONF_DEFAULT_ROUTE_METRIC:
 1507: 		parse_default_route_metric(s);
 1508: 		break;
 1509: 
 1510: 	    case CONF_DEFAULT_ROUTE_DISTANCE:
 1511: 		parse_default_route_distance(s);
 1512: 		break;
 1513: 
 1514: 	    case CONF_IGMP_QUERY_INTERVAL:
 1515: 		parse_igmp_query_interval(s);
 1516: 		break;
 1517: 
 1518: 	    case CONF_IGMP_QUERIER_TIMEOUT:
 1519: 		parse_igmp_querier_timeout(s);
 1520: 		break;
 1521: 
 1522: 	    case CONF_HELLO_INTERVAL:
 1523: 		parse_hello_interval(s);
 1524: 		break;
 1525: 
 1526: 	    default:
 1527: 		logit(LOG_WARNING, 0, "%s:%u - Unknown command '%s'", config_file, lineno, w);
 1528: 		error_flag = TRUE;
 1529: 	}
 1530:     }
 1531: 
 1532:     fclose(fp);
 1533: 
 1534:   nofile:
 1535:     /* A static RP address is needed for SSM.  We use a link-local
 1536:      * address. It is not required to be configured on any interface. */
 1537:     strncpy(linebuf, "169.254.0.1 232.0.0.0/8\n", sizeof(linebuf));
 1538:     s = linebuf;
 1539:     parse_rp_address(s);
 1540: 
 1541:     if (error_flag)
 1542: 	logit(LOG_ERR, 0, "%s:%u - Syntax error", config_file, lineno);
 1543: 
 1544:     cand_rp_adv_message.message_size = cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
 1545:     if (cand_rp_flag != FALSE) {
 1546: 	/* Prepare the RP info */
 1547: 	my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
 1548: 
 1549: 	/* TODO: HARDCODING! */
 1550: 	data_ptr = cand_rp_adv_message.buffer + 1;
 1551: 	PUT_BYTE(my_cand_rp_priority, data_ptr);
 1552: 	PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
 1553: 	PUT_EUADDR(my_cand_rp_address, data_ptr);
 1554:     }
 1555: 
 1556:     /* If no IGMP querier timeout was set, calculate from query interval */
 1557:     if (!igmp_querier_timeout)
 1558: 	igmp_querier_timeout = QUERIER_TIMEOUT(igmp_query_interval);
 1559: 
 1560:     IF_DEBUG(DEBUG_IGMP) {
 1561: 	logit(LOG_INFO, 0, "IGMP query interval  : %u sec", igmp_query_interval);
 1562: 	logit(LOG_INFO, 0, "IGMP querier timeout : %u sec", igmp_querier_timeout);
 1563:     }
 1564: }
 1565: 
 1566: 
 1567: static uint32_t ifname2addr(char *s)
 1568: {
 1569:     vifi_t vifi;
 1570:     struct uvif *v;
 1571: 
 1572:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
 1573: 	if (!strcmp(v->uv_name, s))
 1574: 	    return v->uv_lcl_addr;
 1575:     }
 1576: 
 1577:     return 0;
 1578: }
 1579: 
 1580: static char *next_word(char **s)
 1581: {
 1582:     char *w;
 1583: 
 1584:     w = *s;
 1585:     while (*w == ' ' || *w == '\t')
 1586: 	w++;
 1587: 
 1588:     *s = w;
 1589:     while (**s != 0) {
 1590: 	switch (**s) {
 1591: 	    case ' ':
 1592: 	    case '\t':
 1593: 		**s = '\0';
 1594: 	    (*s)++;
 1595: 	    return w;
 1596: 
 1597: 	    case '\n':
 1598: 	    case '#':
 1599: 		**s = '\0';
 1600: 	    return w;
 1601: 
 1602: 	    default:
 1603: 		if (isascii((int)**s) && isupper((int)**s))
 1604: 		    **s = tolower((int)**s);
 1605: 		(*s)++;
 1606: 	}
 1607:     }
 1608: 
 1609:     return w;
 1610: }
 1611: 
 1612: /**
 1613:  * Local Variables:
 1614:  *  version-control: t
 1615:  *  indent-tabs-mode: t
 1616:  *  c-file-style: "ellemtel"
 1617:  *  c-basic-offset: 4
 1618:  * End:
 1619:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>