NetBSD/usr.sbin/pim6sd/config.c

1611 lines
37 KiB
C

/* $NetBSD: config.c,v 1.1 2000/01/28 19:32:46 itojun Exp $ */
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <sys/ioctl.h>
#include <syslog.h>
#include <stdlib.h>
#include "vif.h"
#include "pim6.h"
#include "inet6.h"
#include "rp.h"
#include "pimd.h"
#include "timer.h"
#include "route.h"
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <net/if_var.h>
#endif
#include <netinet6/in6_var.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "config.h"
#include <arpa/inet.h>
#include <stdio.h>
#include "debug.h"
void add_phaddr(struct uvif *v , struct sockaddr_in6 *addr,struct in6_addr *mask);
char *next_word(char **s);
int wordToOption(char *word);
int parse_phyint(char *s);
int parse_candidateRP(char *s);
int parse_group_prefix(char *s);
int parseBSR(char *s);
int parse_reg_threshold(char *s);
int parse_data_threshold(char *s);
int parse_default_source_metric(char *s);
int parse_default_source_preference(char *s);
int parse_hello_period(char *s);
int parse_granularity(char *s);
int parse_jp_period(char *s);
int parse_data_timeout(char *s);
int parse_register_suppression_timeout(char *s);
int parse_probe_time(char *s);
int parse_assert_timeout(char *s);
void
config_vifs_from_kernel()
{
struct ifreq *ifrp,*ifend;
register struct uvif *v;
register vifi_t vifi;
int n,i;
struct sockaddr_in6 addr;
struct in6_addr mask;
short flags;
int num_ifreq = 64;
struct ifconf ifc;
total_interfaces= 0; /* The total number of physical interfaces */
ifc.ifc_len = num_ifreq * sizeof (struct ifreq);
ifc.ifc_buf = calloc(ifc.ifc_len,sizeof(char));
while (ifc.ifc_buf) {
caddr_t newbuf;
if (ioctl(udp_socket,SIOCGIFCONF,(char *)&ifc) <0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
/*
* If the buffer was large enough to hold all the addresses
* then break out, otherwise increase the buffer size and
* try again.
*
* The only way to know that we definitely had enough space
* is to know that there was enough space for at least one
* more struct ifreq. ???
*/
if( (num_ifreq * sizeof (struct ifreq)) >=
ifc.ifc_len + sizeof(struct ifreq))
break;
num_ifreq *= 2;
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
newbuf = realloc(ifc.ifc_buf, ifc.ifc_len);
if (newbuf == NULL)
free(ifc.ifc_buf);
ifc.ifc_buf = newbuf;
}
if (ifc.ifc_buf == NULL)
log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
ifrp = (struct ifreq *) ifc.ifc_buf;
ifend = (struct ifreq * ) (ifc.ifc_buf + ifc.ifc_len);
/*
* Loop through all of the interfaces.
*/
for(;ifrp < ifend;ifrp = (struct ifreq *)((char *)ifrp+n))
{
struct ifreq ifr;
struct in6_ifreq ifr6;
#ifdef HAVE_SA_LEN
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if(n < sizeof(*ifrp))
n=sizeof(*ifrp);
#else
n=sizeof(*ifrp);
#endif
/*
* Ignore any interface for an address family other than IPv6.
*/
if ( ifrp->ifr_addr.sa_family != AF_INET6)
{
/* Eventually may have IP address later */
total_interfaces++;
continue;
}
memcpy(&addr,&ifrp->ifr_addr,sizeof(struct sockaddr_in6));
/*
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
* SIOCGIFFLAGS stomps over it because the requests
* are returned in a union.)
*/
memcpy(ifr.ifr_name,ifrp->ifr_name,sizeof(ifr.ifr_name));
memcpy(ifr6.ifr_name,ifrp->ifr_name,sizeof(ifr6.ifr_name));
if(ioctl(udp_socket,SIOCGIFFLAGS,(char *)&ifr) <0)
log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
flags = ifr.ifr_flags;
#if 0
/*
* Ignore loopback interfaces and interfaces that do not
* support multicast.
*/
if((flags & (IFF_LOOPBACK | IFF_MULTICAST ))!= IFF_MULTICAST)
continue;
#endif
/*
* Get netmask of the address.
*/
ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr;
if(ioctl(udp_socket, SIOCGIFNETMASK_IN6, (char *)&ifr6) <0)
log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK_IN6 for %s",
inet6_fmt(&ifr6.ifr_addr.sin6_addr));
memcpy(&mask,&ifr6.ifr_addr.sin6_addr,sizeof(mask));
/*
* Get IPv6 specific flags, and ignore an anycast address.
* XXX: how about a deprecated, tentative, duplicated or
* detached address?
*/
ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr;
if (ioctl(udp_socket, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
log(LOG_ERR, errno, "ioctl SIOCGIFAFLAG_IN6 for %s",
inet6_fmt(&ifr6.ifr_addr.sin6_addr));
}
else {
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) {
log(LOG_DEBUG, 0, "config_vifs_from_kernel: "
"%s on %s is an anycast address, ignored",
inet6_fmt(&ifr6.ifr_addr.sin6_addr),
ifr.ifr_name);
continue;
}
}
if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr))
{
addr.sin6_scope_id = if_nametoindex(ifrp->ifr_name);
#ifdef __KAME__
/*
* Hack for KAME kernel.
* Set sin6_scope_id field of a link local address and clear
* the index embedded in the address.
*/
/* clear interface index */
addr.sin6_addr.s6_addr[2] = 0;
addr.sin6_addr.s6_addr[3] = 0;
#endif
}
/*
* If the address is connected to the same subnet as one
* already installed in the uvifs array, just add the address
* to the list of addresses of the uvif.
*/
for(vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
{
if( strcmp(v->uv_name , ifr.ifr_name) == 0 )
{
add_phaddr(v, &addr,&mask);
break;
}
}
if( vifi != numvifs )
continue;
/*
* If there is room in the uvifs array, install this interface.
*/
if( numvifs == MAXMIFS )
{
log(LOG_WARNING, 0,
"too many vifs, ignoring %s", ifr.ifr_name);
continue;
}
/*
* Everyone below is a potential vif interface.
* We don't care if it has wrong configuration or not
* configured at all.
*/
total_interfaces++;
v = &uvifs[numvifs];
v->uv_dst_addr = allpim6routers_group;
v->uv_subnetmask = mask;
strncpy ( v->uv_name , ifr.ifr_name,IFNAMSIZ);
v->uv_ifindex = if_nametoindex(v->uv_name);
add_phaddr(v,&addr,&mask);
/* prefix local calc. (and what about add_phaddr?...) */
for (i = 0; i < sizeof(struct in6_addr); i++)
v->uv_prefix.sin6_addr.s6_addr[i] =
addr.sin6_addr.s6_addr[i] & mask.s6_addr[i];
if(flags & IFF_POINTOPOINT)
v->uv_flags |=(VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
/*
* Disable multicast routing on loopback interfaces and
* interfaces that do not support multicast. But they are
* still necessary, since global addresses maybe assigned only
* on such interfaces.
*/
if ((flags & IFF_LOOPBACK) != 0 || (flags & IFF_MULTICAST) == 0)
v->uv_flags |= VIFF_DISABLED;
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,
"Installing %s (%s on subnet %s) ,"
"as vif #%u - rate = %d",
v->uv_name,inet6_fmt(&addr.sin6_addr),
net6name(&v->uv_prefix.sin6_addr,&mask),
numvifs,v->uv_rate_limit);
++numvifs;
if( !(flags & IFF_UP))
{
v->uv_flags |= VIFF_DOWN;
vifs_down = TRUE;
}
}
}
void
add_phaddr(struct uvif *v,struct sockaddr_in6 *addr,struct in6_addr *mask)
{
struct phaddr *pa;
int i;
if( (pa=malloc(sizeof(*pa))) == NULL)
log(LOG_ERR, 0, "add_phaddr: memory exhausted");
memset(pa,0,sizeof(*pa));
pa->pa_addr= *addr;
pa->pa_subnetmask = *mask;
for(i = 0; i < sizeof(struct in6_addr); i++)
pa->pa_prefix.sin6_addr.s6_addr[i] =
addr->sin6_addr.s6_addr[i] & mask->s6_addr[i];
pa->pa_prefix.sin6_scope_id = addr->sin6_scope_id;
if(IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
if(v->uv_linklocal)
log(LOG_WARNING, 0,
"add_phaddr: found more than one link-local "
"address on %s",
v->uv_name);
v->uv_linklocal = pa;
}
pa->pa_next = v->uv_addrs;
v->uv_addrs = pa;
}
void
config_vifs_from_file()
{
FILE *f;
char linebuf[100];
char *w,*s;
struct ifconf ifc;
int option;
char ifbuf[BUFSIZ];
u_int8 *data_ptr;
if((f=fopen(configfilename,"r"))==NULL)
{
if( errno != ENOENT)
log(LOG_ERR,errno,"Can't open %s",configfilename);
log(LOG_WARNING,errno,"Can't open %s",configfilename);
return;
}
/*
* Note that sizeof(pim6_enocd_uni_addr_t) might be larger than
* the length of the Encoded-Unicast-address field(18 byte) due to
* some padding put in the compiler. However, it doesn't matter
* since we use the space just as a buffer(i.e not as the message).
*/
cand_rp_adv_message.buffer = (u_int8 *)malloc( 4 + sizeof(pim6_encod_uni_addr_t) +
255*sizeof(pim6_encod_grp_addr_t));
if(cand_rp_adv_message.buffer == NULL)
log(LOG_ERR,errno,"Candrpadv Buffer allocation");
cand_rp_adv_message.prefix_cnt_ptr = cand_rp_adv_message.buffer;
/* By default, if no group_prefix configured, then prefix_cnt == 0
* implies group_prefix = ff::/8 and masklen = 8.
*/
*cand_rp_adv_message.prefix_cnt_ptr = 0;
cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
/* TODO: XXX: HARDCODING!!! */
cand_rp_adv_message.insert_data_ptr += (4 + 18);
ifc.ifc_buf = ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if(ioctl(udp_socket,SIOCGIFCONF,(char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
while( fgets(linebuf, sizeof(linebuf),f) != NULL )
{
s = linebuf;
w = next_word(&s);
option = wordToOption(w);
switch(option)
{
case EMPTY:
continue;
break;
case PHYINT:
parse_phyint(s);
break;
case CANDIDATE_RP:
parse_candidateRP(s);
break;
case GROUP_PREFIX:
parse_group_prefix(s);
break;
case BOOTSTRAP_RP:
parseBSR(s);
break;
case REG_THRESHOLD:
parse_reg_threshold(s);
break;
case DATA_THRESHOLD:
parse_data_threshold(s);
break;
case DEFAULT_SOURCE_METRIC:
parse_default_source_metric(s);
break;
case DEFAULT_SOURCE_PREFERENCE :
parse_default_source_preference(s);
break;
case HELLO_PERIOD :
parse_hello_period(s);
break;
case GRANULARITY :
parse_granularity(s);
break;
case JOIN_PRUNE_PERIOD :
parse_jp_period(s);
break;
case DATA_TIMEOUT :
parse_data_timeout(s);
break;
case REGISTER_SUPPRESSION_TIMEOUT :
parse_register_suppression_timeout(s);
break;
case PROBE_TIME :
parse_probe_time(s);
break;
case ASSERT_TIMEOUT:
parse_assert_timeout(s);
break;
default:
log(LOG_WARNING, 0, "unknown command '%s' in %s",
w, configfilename);
}
}
cand_rp_adv_message.message_size = cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
if (cand_rp_flag != FALSE)
{
my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
/* TODO: HARDCODING! */
data_ptr = cand_rp_adv_message.buffer + 1; /* WARNING */
PUT_BYTE(my_cand_rp_priority,data_ptr);
PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
PUT_EUADDR6(my_cand_rp_address.sin6_addr,data_ptr);
IF_DEBUG(DEBUG_PIM_CAND_RP)
{
log(LOG_DEBUG, 0,
"Local Cand-RP address is : %s",
inet6_fmt(&my_cand_rp_address.sin6_addr));
log(LOG_DEBUG, 0,
"Local Cand-RP priority is : %u",my_cand_rp_priority);
log(LOG_DEBUG, 0,
"Local Cand-RP advertisement period is : %u sec.",
my_cand_rp_adv_period);
}
}
if( cand_bsr_flag!=FALSE)
{
IF_DEBUG(DEBUG_PIM_BOOTSTRAP)
{
log(LOG_DEBUG, 0,
"Local BSR address: %s",
inet6_fmt(&my_bsr_address.sin6_addr));
log(LOG_DEBUG, 0,
"Local BSR priority : %u",my_bsr_priority);
log(LOG_DEBUG,0,
"Local BSR period is : %u sec.",
my_bsr_period);
}
}
IF_DEBUG(DEBUG_SWITCH)
{
log(LOG_DEBUG,0,"reg_rate_limit set to %u (bits/s)" , pim_reg_rate_bytes);
log(LOG_DEBUG,0,"reg_rate_interval set to %u s.",pim_reg_rate_check_interval);
log(LOG_DEBUG,0,"data_rate_limit set to %u (bits/s)" , pim_data_rate_bytes);
log(LOG_DEBUG,0,"data_rate_interval set to %u s.",pim_data_rate_check_interval);
}
IF_DEBUG(DEBUG_PIM_HELLO)
{
log(LOG_DEBUG,0, "pim_hello_period set to: %u", pim_hello_period);
log(LOG_DEBUG,0, "pim_hello_holdtime set to: %u", pim_hello_holdtime);
}
IF_DEBUG(DEBUG_PIM_JOIN_PRUNE)
{
log(LOG_DEBUG,0, "pim_join_prune_period set to: %u", pim_join_prune_period);
log(LOG_DEBUG,0, "pim_join_prune_holdtime set to: %u", pim_join_prune_holdtime);
}
fclose(f);
}
/*
* function name: wordToOption
* input: char *word, a pointer to the word
* output: int; a number corresponding to the code of the word
* operation: converts the result of the string comparisons into numerics.
* comments: called by config_vifs_from_file()
*/
int wordToOption(char *word)
{
if (EQUAL(word, ""))
return EMPTY;
if (EQUAL(word, "phyint"))
return PHYINT;
if (EQUAL(word, "cand_rp"))
return CANDIDATE_RP;
if (EQUAL(word, "group_prefix"))
return GROUP_PREFIX;
if (EQUAL(word, "cand_bootstrap_router"))
return BOOTSTRAP_RP;
if (EQUAL(word, "switch_register_threshold"))
return REG_THRESHOLD;
if (EQUAL(word, "switch_data_threshold"))
return DATA_THRESHOLD;
if (EQUAL(word, "default_source_metric"))
return DEFAULT_SOURCE_METRIC;
if (EQUAL(word, "default_source_preference"))
return DEFAULT_SOURCE_PREFERENCE;
if (EQUAL(word, "hello_period"))
return HELLO_PERIOD;
if (EQUAL(word, "granularity"))
return GRANULARITY;
if (EQUAL(word, "join_prune_period"))
return JOIN_PRUNE_PERIOD;
if (EQUAL(word, "data_timeout"))
return DATA_TIMEOUT;
if (EQUAL(word, "register_suppression_timeout"))
return REGISTER_SUPPRESSION_TIMEOUT;
if (EQUAL(word, "probe_time"))
return PROBE_TIME;
if (EQUAL(word, "assert_timeout"))
return PROBE_TIME;
return UNKNOWN;
}
/*
* function name: parse_phyint
* input: char *s, pointing to the parsing point of the file
* output: int (TRUE if the parsing was successful, o.w. FALSE)
* operation: parses the physical interface file configurations, if any.
* The general form is:
* phyint <ifname> [disable] [preference <p>] [metric <m>]
*/
int parse_phyint(char *s)
{
char *w,c,*ifname;
vifi_t vifi;
struct uvif *v;
u_int n;
if(EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING, 0, "Missing phyint name in %s", configfilename);
return FALSE;
}
ifname = w;
for (vifi = 0,v=uvifs;vifi <= numvifs ; ++vifi , ++v)
{
if(vifi == numvifs)
{
log(LOG_WARNING, 0,
"Invalid phyint name (maybe not configured..) '%s' "
"in %s", w, configfilename);
return FALSE;
}
if(strcmp(v->uv_name,ifname))
continue;
while(!EQUAL((w = next_word(&s)),""))
{
if(EQUAL(w,"disable"))
v->uv_flags |=VIFF_DISABLED;
else if (EQUAL(w, "nolistener"))
v->uv_flags |= VIFF_NOLISTENER;
else
{
if(EQUAL(w,"preference"))
{
if(EQUAL((w=next_word(&s)),""))
{
log(LOG_WARNING, 0,
"Missing preference for "
"phyint %s in %s",
ifname, configfilename);
}
else
{
if (sscanf(w,"%u%c",&n,&c) != 1 ||
n < 1 || n > 255 )
{
log(LOG_WARNING, 0,
"Invalid preference "
"'%s' for phyint %s "
"in %s",
w, ifname,
configfilename);
}
else
{
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG, 0,"Config setting default local preference on %d to %s",n,ifname);
v->uv_local_pref = n;
}
}
}
else
{
if(EQUAL(w, "metric"))
{
if(EQUAL((w = next_word(&s)), ""))
{
log(LOG_WARNING,0,
"Missing metric for "
"phyint %s in %s",
ifname,
configfilename);
}
else
{
if (sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n > 1024 )
{
log(LOG_WARNING,0,
"Invalid metric '%s' for phyint %s in %s",
w, ifname,configfilename);
}
else
{
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG,0,
"Config setting default local metric on %d to %s.",
n,ifname);
v->uv_local_metric = n;
}
}
}
}
}
}
break;
}
return(TRUE);
}
/*
* function name: parse_candidateRP
* input: char *s
* output: int (TRUE if the parsing was successful, o.w. FALSE)
* operation: parses the candidate RP information.
* The general form is:
* 'cand_rp <ifname> [priority <number>] [time <number>]'.
*/
int
parse_candidateRP(char *s)
{
char *w;
struct sockaddr_in6 *sa6_rp;
u_int time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY;
sa6_rp = NULL;
cand_rp_flag = FALSE;
my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
while(!EQUAL((w = next_word(&s)),""))
{
if((!EQUAL(w,"priority")) && (!EQUAL(w,"time")))
{
/*
* if the interface is specified and is valid
* we take the max global address of the interface
* (aliasing) else look at the end of the function.
*/
sa6_rp = local_iface(w);
if(!sa6_rp)
log(LOG_WARNING, 0,
"cand_rp '%s' in %s is not configured."
"take the max local address the router..",
w, configfilename);
}
else
{
if (EQUAL(w,"priority"))
{
if (EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing priority ; set to default "
": %d (0 is highest )",priority);
}
else
{
if (sscanf(w,"%u",&priority)!= 1 )
{
priority = PIM_DEFAULT_CAND_RP_PRIORITY;
log(LOG_WARNING, 0,
"Invalid priority '%' "
"for cand_rp;set to default "
"(0 is highest) : %d",
w, priority);
}
}
}
else
{
if (EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING, 0,
"Missing cand_adv period ;"
"set to default : %d",time);
}
else
{
if (sscanf(w,"%u",&time)!= 1 )
{
time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
log(LOG_WARNING, 0,
"Invalid cand_adv_period "
"'%s';set to default : %d",
w,time);
}
else
{
if( time > (my_cand_rp_adv_period = ~0))
time = my_cand_rp_adv_period;
else
if(time <10)
time = 10;
else
if (time > PIM_DEFAULT_CAND_RP_ADV_PERIOD)
time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
my_cand_rp_adv_period = time;
}
}
}
}
}
if(!sa6_rp)
sa6_rp= max_global_address();
my_cand_rp_address=*sa6_rp;
my_cand_rp_priority = priority;
my_cand_rp_adv_period = time;
cand_rp_flag = TRUE;
return TRUE;
}
/*
* function name: parse_group_prefix
* input: char *s
* output: int
* operation: parse group_prefix configured information.
* General form: 'group_prefix <group-addr>/<prefix_len>'.
*/
int
parse_group_prefix(char *s)
{
char *w;
struct in6_addr group_addr;
u_int32 masklen=PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
w=next_word(&s);
if (EQUAL(w,""))
{
log(LOG_WARNING, 0,
"Configuration error for 'group_prefix' in %s: no group_addr. "
"Ignoring...", configfilename);
return FALSE;
}
w=strtok(w,"/");
if ( inet_pton(AF_INET6,w,(void *)&group_addr) != 1 )
{
log(LOG_WARNING, 0,
"Config error in %s : Bad ddress formatt.Ignoring..",
configfilename);
return FALSE;
}
if (!IN6_IS_ADDR_MULTICAST(&group_addr))
{
log(LOG_WARNING,0,
"Config error in %s: '%s' is not a mcast addr.Ignoring",
configfilename,
inet6_fmt(&group_addr));
return FALSE;
}
if (!(~(*cand_rp_adv_message.prefix_cnt_ptr)))
{
log(LOG_WARNING, 0,
"Too many group_prefix configured. Truncating...");
return FALSE;
}
w=strtok(NULL,"/");
if(w==NULL)
{
log(LOG_WARNING,0,
"Config error in %s : missing group prefix.Ignoring..",
configfilename);
return FALSE;
}
if ( sscanf(w,"%u",&masklen) ==1 )
{
if (masklen > (sizeof(group_addr) * 8))
masklen = (sizeof(group_addr)*8);
else
if (masklen <PIM_GROUP_PREFIX_DEFAULT_MASKLEN)
masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
}
PUT_EGADDR6(group_addr, (u_int8)masklen, 0,
cand_rp_adv_message.insert_data_ptr);
(*cand_rp_adv_message.prefix_cnt_ptr)++;
return TRUE;
}
/*
* function name: parseBSR
* input: char *s
* output: int
* operation: parse the candidate BSR configured information.
* General form:
* 'cand_bootstrap_router <ifname> [priority <number>]'.
* this function is similar to parse_candrp
*/
int
parseBSR(char *s)
{
char *w;
struct sockaddr_in6 *sa6_bsr;
u_int32 priority = PIM_DEFAULT_BSR_PRIORITY;
u_int time = PIM_DEFAULT_BOOTSTRAP_PERIOD;
my_bsr_period = PIM_DEFAULT_BOOTSTRAP_PERIOD;
sa6_bsr = NULL;
cand_bsr_flag = FALSE;
while(!EQUAL((w = next_word(&s)),""))
{
if((!EQUAL(w,"priority")) && (!EQUAL(w,"time")))
{
sa6_bsr = local_iface(w);
if(!sa6_bsr)
{
log(LOG_WARNING,0,
"cand_bootstrap_router '%s' in %s is not "
"configured.Take the max router address.",
w,configfilename);
}
}
else
{
if(EQUAL(w,"priority"))
{
if (EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING, 0,
"Missing priority for the bsr;set to "
"default (0 is lowest): %d",priority);
}
else
{
if (sscanf(w,"%u",&priority)!= 1 )
{
priority = PIM_DEFAULT_BSR_PRIORITY;
log(LOG_WARNING, 0,
"Invalid priority '%s'for "
"the bsr;set to default : %d",
w, priority);
}
else
{
if( priority > (my_bsr_priority = ~0))
priority = my_bsr_priority;
my_bsr_priority = (u_int8)priority;
}
}
}
else
{
if( EQUAL((w=next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing bsr period ;"
"set to default : %d ",time);
}
else
{
if(sscanf(w,"%u",&time)!=1)
{
time=PIM_DEFAULT_BOOTSTRAP_PERIOD;
log(LOG_WARNING,0,
"Invalid bsr period"
"'%s';set to default : %d",
w,time);
}
else
my_bsr_period=time;
}
}
}
}
if(!sa6_bsr)
sa6_bsr = max_global_address();
my_bsr_address=*sa6_bsr;
my_bsr_priority = priority;
MASKLEN_TO_MASK6(RP_DEFAULT_IPV6_HASHMASKLEN,my_bsr_hash_mask);
cand_bsr_flag = TRUE;
return TRUE;
}
/*
* function name: parse_reg_threshold
* input: char *s
* output: int (TRUE if successful, FALSE o.w.)
* operation: reads and assigns the switch to the spt threshold
* due to registers for the router, if used as RP.
* Maybe extended to support different thresholds
* for different groups(prefixes).
* General form:
* 'switch_register_threshold [rate <number> interval <number>]'.
* comments: called by config_vifs_from_file()
*/
int parse_reg_threshold(char *s)
{
char *w;
u_int rate=PIM_DEFAULT_REG_RATE;
u_int interval= PIM_DEFAULT_REG_RATE_INTERVAL;
while(!EQUAL((w=next_word(&s)),""))
{
if(EQUAL(w,"rate"))
{
if(EQUAL((w=next_word(&s)),""))
{
log(LOG_WARNING,0,
"switch_register_threshold : missing rate ; "
"set to default : %u (bits/s)",
rate);
}
else
{
if(sscanf(w,"%u",&rate)!=1)
{
rate = PIM_DEFAULT_REG_RATE;
log(LOG_WARNING, 0,
"switch_register_threshold : "
"Invalid rate '%s' , set to defaut :"
" %u (bits/s)",
w,rate);
}
}
}
else
{
if(EQUAL(w,"interval"))
{
if(EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING,0,"switch_register_threshold : missing interval ; set to default : %u s.",
interval);
}
else
{
if(sscanf(w,"%u",&interval) != 1)
{
interval = PIM_DEFAULT_REG_RATE_INTERVAL;
log(LOG_WARNING,0,"switch_register_threshold : Invalid interval '%s' ; set to default : %u s.",
w,interval);
}
}
}
else
{
log(LOG_WARNING,0,"swhitch_register_threshold : Invalid parameter %s",w);
}
}
}
if( interval < timer_interval)
{
interval = timer_interval;
log(LOG_WARNING,0,"switch_register_threshold : Interval too short , set to default : %u s.",
interval);
}
pim_reg_rate_bytes = (rate * interval ) /10;
pim_reg_rate_check_interval = interval;
return TRUE;
}
/*
* function name: parse_data_threshold
* input: char *s
* output: int
* operation: reads and assigns the switch to the spt threshold
* due to data packets, if used as DR.
* General form:
* 'switch_data_threshold [rate <number> interval <number>]'.
* similar to register_threshold...
*/
int parse_data_threshold(char *s)
{
char *w;
u_int rate=PIM_DEFAULT_DATA_RATE;
u_int interval= PIM_DEFAULT_DATA_RATE_INTERVAL;
while(!EQUAL((w=next_word(&s)),""))
{
if(EQUAL(w,"rate"))
{
if(EQUAL((w=next_word(&s)),""))
{
log(LOG_WARNING,0,"switch_data_threshold : missing rate value ; set to defaut : %u (bits/s)",
rate);
}
else
{
if(sscanf(w,"%u",&rate)!=1)
{
rate = PIM_DEFAULT_DATA_RATE;
log(LOG_WARNING,0,"switch_data_threshold : Invalid rate '%s' ; set to default : %u (bits/s)",
w,rate);
}
}
}
else
{
if(EQUAL(w,"interval"))
{
if(EQUAL((w = next_word(&s)),""))
{
log(LOG_WARNING,0,"switch_data_threshold : missing interval value ; set to default : %u s.",
interval);
}
else
{
if(sscanf(w,"%u",&interval) != 1)
{
interval = PIM_DEFAULT_DATA_RATE_INTERVAL;
log(LOG_WARNING,0,"switch_data_threshold : Invalid interval '%s' ; set to default : %u s.",
w,interval);
}
}
}
else
{
log(LOG_WARNING,0,"swhitch_data_threshold :Invalid Parameter %s",w);
}
}
}
if( interval < timer_interval)
{
interval = timer_interval;
log(LOG_WARNING,0,"switch_data_threshold : interval too short set to default : %u s.",
interval);
}
pim_data_rate_bytes = (rate * interval ) /10;
pim_data_rate_check_interval = interval;
return TRUE;
}
/*
* function name: parse_default_source_metric
* input: char *s
* output: int
* operation: reads and assigns the default source metric, if no reliable
* unicast routing information available.
* General form:
* 'default_source_metric <number>'.
* default pref and metric statements should precede all phyint
* statements in the config file.
*/
int parse_default_source_metric(char *s)
{
char *w;
u_int value;
vifi_t vifi;
struct uvif *v;
value = DEFAULT_LOCAL_METRIC;
if (EQUAL((w = next_word(&s)), ""))
{
log(LOG_WARNING,0,
"Missing source metric value ; set to default %u",
value);
}
else
{
if (sscanf(w, "%u", &value) != 1)
{
value = DEFAULT_LOCAL_METRIC;
log(LOG_WARNING,0,
"Invalid source metric value '%s' ;set to default %u",
w,value);
}
default_source_metric = value;
log(LOG_INFO,0, "Default_source_metric is : %u", default_source_metric);
for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
{
v->uv_local_metric = default_source_metric;
}
}
return(TRUE);
}
/*
* function name: parse_default_source_preference
* input: char *s
* output: int
* operation: reads and assigns the default source preference, if no reliable
* unicast routing information available.
* General form:
* 'default_source_preference <number>'.
* default pref and metric statements should precede all phyint
* statements in the config file.
*/
int parse_default_source_preference(char *s)
{
char *w;
u_int value;
vifi_t vifi;
struct uvif *v;
value = DEFAULT_LOCAL_PREF;
if (EQUAL((w = next_word(&s)), ""))
{
log(LOG_WARNING,0,
"Missing source preference ; set to default %u",
value);
}
else
{
if (sscanf(w, "%u", &value) != 1)
{
value = DEFAULT_LOCAL_PREF;
log(LOG_WARNING,0,
"Invalid source preference value '%s' ;set to default %u",
w,value);
}
default_source_preference = value;
log(LOG_INFO,0, "default_source_preference set to: %u", default_source_preference);
for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
{
v->uv_local_pref = default_source_preference;
}
}
return(TRUE);
}
/*
* function name: parse_hello_period
* input: char *s
* output: int
* operation: reads and assigns the hello period for a pim router
* General form:
* 'hello_period <number> <coef>'.
* number is the period in second between 2 hello messages
* and coef is the coef to deterimine the hello holdtime
* default : 3.5
*/
int parse_hello_period(char *s)
{
char *w;
u_int hellop;
float coef;
hellop = PIM_TIMER_HELLO_PERIOD;
coef = 3.5;
if (EQUAL((w = next_word(&s)), ""))
{
log(LOG_WARNING,0,
"Missing hello period ; set to default %u",
hellop);
}
else
{
if (sscanf(w, "%u", &hellop) != 1)
{
hellop = PIM_TIMER_HELLO_PERIOD;
log(LOG_WARNING,0,
"Invalid hello period value '%s' ;set to default %u",
w,hellop);
}
pim_hello_period = hellop;
if (!EQUAL((w=next_word(&s)),""))
{
if (sscanf(w, "%f", &coef) != 1)
{
coef = 3.5;
log(LOG_WARNING,0,
"Invalid hello period coef '%s' ;set to default %.1f",
w,coef);
}
if(coef<=1)
{
coef = 3.5;
log(LOG_WARNING,0,
"for hello period coef must be > 1;set to default %.1f",
coef);
}
}
}
pim_hello_holdtime = coef*pim_hello_period;
return(TRUE);
}
/*
* function name: parse_jp_period
* input: char *s
* output: int
* operation: reads and assigns the join/prune period for a pim router
* General form:
* 'join_prune_period <number> <coef>'.
* number is the period in second between 2 join/prune messages
* and coef is the coef to deterimine the join/prune holdtime
* default : 3.5
* This function is similar to the function above
*/
int parse_jp_period(char *s)
{
char *w;
u_int jpp;
float coef;
jpp = PIM_JOIN_PRUNE_PERIOD;
coef = 3.5;
if (EQUAL((w = next_word(&s)), ""))
{
log(LOG_WARNING,0,
"Missing join/prune period ; set to default %u",
jpp);
}
else
{
if (sscanf(w, "%u", &jpp) != 1)
{
jpp = PIM_JOIN_PRUNE_PERIOD;
log(LOG_WARNING,0,
"Invalid join/prune period value '%s' ;set to default %u",
w,jpp);
}
pim_join_prune_period = jpp;
if (!EQUAL((w=next_word(&s)),""))
{
if (sscanf(w, "%f", &coef) != 1)
{
coef = 3.5;
log(LOG_WARNING,0,
"Invalid join/prune period coef '%s' ;set to default %.1f",
w,coef);
}
if(coef<=1)
{
coef = 3.5;
log(LOG_WARNING,0,
"for join/prune period coef must be > 1;set to default %.1f",
coef);
}
}
}
pim_join_prune_holdtime = coef*pim_join_prune_period;
return(TRUE);
}
/* function name : parse_granularity
* input char *s
* output int
* operation : reads and assigns the granularity of the demon's timer
* General form :
* 'granularity <number>
* number is the period in seconds between each "tics" of the virtual time.
* default : 5 s.
*/
int parse_granularity(char *s)
{
char *w;
u_int granu;
granu = DEFAULT_TIMER_INTERVAL;
if( EQUAL((w= next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing timer granularity ; set to default %u",
granu);
return FALSE;
}
else
{
if( sscanf(w,"%u",&granu)!=1)
{
granu=DEFAULT_TIMER_INTERVAL;
log(LOG_WARNING,0,
"Invalid timer granularity value '%s' ; set to default %u",
w,granu);
}
timer_interval = granu;
if(granu < 1)
{
granu = DEFAULT_TIMER_INTERVAL;
log(LOG_WARNING,0,
"Timer granularity MUST be > 1! ; set to default %u",
granu);
}
}
timer_interval = granu;
return TRUE;
}
/* function name : parse_data_timeout
* input char *s
* output int
* operation : reads and assigns the data_timeout of each (S,G)
* General form :
* 'data_timeout <number>
* default : 210 s.
*/
int parse_data_timeout(char *s)
{
char *w;
u_int time;
time = PIM_DATA_TIMEOUT;
if( EQUAL((w= next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing data timeout ; set to default %u",
time);
return FALSE;
}
else
{
if( sscanf(w,"%u",&time)!=1)
{
time=PIM_DATA_TIMEOUT;
log(LOG_WARNING,0,
"Invalid data timeout value '%s' ; set to default %u",
w,time);
}
pim_data_timeout = time;
if(time < 1)
{
time = PIM_DATA_TIMEOUT;
log(LOG_WARNING,0,
"Data timeout must be > 1! ; set to default %u",
time);
}
}
pim_data_timeout = time;
return TRUE;
}
/* function name : parse_register_suppression_timeout
* input char *s
* output int
* operation : reads and assigns the register_suppression_timeout
* General form :
* 'register_suppression_timeout <number>
* default : 60 s.
*/
int parse_register_suppression_timeout(char *s)
{
char *w;
u_int time;
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
if( EQUAL((w= next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing register suppression timeout ; set to default %u",
time);
return FALSE;
}
else
{
if( sscanf(w,"%u",&time)!=1)
{
time=PIM_REGISTER_SUPPRESSION_TIMEOUT;
log(LOG_WARNING,0,
"Invalid register suppression timeout value '%s' ; set to default %u",
w,time);
}
pim_register_suppression_timeout = time;
if(time < 1)
{
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
log(LOG_WARNING,0,
"Register suppression timeout must be > 1! ; set to default %u",
time);
}
}
pim_register_suppression_timeout = time;
return TRUE;
}
/* function name : parse_probe_time
* input char *s
* output int
* operation : reads and assigns the probe_time for null-register
* General form :
* 'probe_time <number>
* default : 5 s.
*/
int parse_probe_time(char *s)
{
char *w;
u_int time;
time = PIM_REGISTER_PROBE_TIME;
if( EQUAL((w= next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing register probe time ; set to default %u",
time);
return FALSE;
}
else
{
if( sscanf(w,"%u",&time)!=1)
{
time=PIM_REGISTER_PROBE_TIME;
log(LOG_WARNING,0,
"Invalid register probe time value '%s' ; set to default %u",
w,time);
}
pim_register_probe_time = time;
if(time < 1)
{
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
log(LOG_WARNING,0,
"Register probe time must be > 1! ; set to default %u",
time);
}
}
pim_register_probe_time = time;
return TRUE;
}
/* function name : parse_assert_timeout
* input char *s
* output int
* operation : reads and assigns the assert timeout
* General form :
* 'assert_timeout <number>
* default : 180 s.
*/
int parse_assert_timeout(char *s)
{
char *w;
u_int time;
time = PIM_ASSERT_TIMEOUT;
if( EQUAL((w= next_word(&s)),""))
{
log(LOG_WARNING,0,
"Missing assert time out; set to default %u",
time);
return FALSE;
}
else
{
if( sscanf(w,"%u",&time)!=1)
{
time=PIM_ASSERT_TIMEOUT;
log(LOG_WARNING,0,
"Invalid assert time out value '%s' ; set to default %u",
w,time);
}
pim_assert_timeout = time;
if(time < 1)
{
time = PIM_ASSERT_TIMEOUT;
log(LOG_WARNING,0,
"Assert time out must be > 1! ; set to default %u",
time);
}
}
pim_assert_timeout = time;
return TRUE;
}
char *next_word(char **s)
{
char *w;
w = *s;
while (*w == ' ' || *w == '\t')
w++;
*s = w;
for(;;) {
switch (**s) {
case ' ' :
case '\t' :
**s = '\0';
(*s)++;
return(w);
case '\n' :
case '#' :
**s = '\0';
return(w);
case '\0' :
return(w);
default :
if (isascii(**s) && isupper(**s))
**s = tolower(**s);
(*s)++;
}
}
}