Annotation of embedaddon/pimd/config.c, revision 1.1

1.1     ! misho       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>