Annotation of embedaddon/pimd/config.c, revision 1.1.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>