Annotation of embedaddon/pimdd/config.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998 by the University of Southern California.
! 3: * All rights reserved.
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software and
! 6: * its documentation in source and binary forms for lawful
! 7: * purposes and without fee is hereby granted, provided
! 8: * that the above copyright notice appear in all copies and that both
! 9: * the copyright notice and this permission notice appear in supporting
! 10: * documentation, and that any documentation, advertising materials,
! 11: * and other materials related to such distribution and use acknowledge
! 12: * that the software was developed by the University of Southern
! 13: * California and/or Information Sciences Institute.
! 14: * The name of the University of Southern California may not
! 15: * be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
! 19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
! 20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
! 21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
! 22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
! 23: * NON-INFRINGEMENT.
! 24: *
! 25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
! 26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
! 27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
! 28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 29: *
! 30: * Other copyrights might apply to parts of this software and are so
! 31: * noted when applicable.
! 32: */
! 33: /*
! 34: * Questions concerning this software should be directed to
! 35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
! 36: *
! 37: * $Id: config.c,v 1.8 1998/12/22 21:50:16 kurtw Exp $
! 38: */
! 39: /*
! 40: * Part of this program has been derived from mrouted.
! 41: * The mrouted program is covered by the license in the accompanying file
! 42: * named "LICENSE.mrouted".
! 43: *
! 44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
! 45: * Leland Stanford Junior University.
! 46: *
! 47: */
! 48:
! 49: #include "defs.h"
! 50:
! 51:
! 52: /*
! 53: * Forward declarations.
! 54: */
! 55: static char *next_word __P((char **));
! 56: static int parse_phyint __P((char *s));
! 57:
! 58:
! 59: /*
! 60: * Query the kernel to find network interfaces that are multicast-capable
! 61: * and install them in the uvifs array.
! 62: */
! 63: void
! 64: config_vifs_from_kernel()
! 65: {
! 66: struct ifreq *ifrp, *ifend;
! 67: register struct uvif *v;
! 68: register vifi_t vifi;
! 69: int n;
! 70: u_int32 addr, mask, subnet;
! 71: short flags;
! 72: int num_ifreq = 32;
! 73: struct ifconf ifc;
! 74:
! 75: total_interfaces = 0; /* The total number of physical interfaces */
! 76:
! 77: ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
! 78: ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char));
! 79: while (ifc.ifc_buf) {
! 80: if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
! 81: log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
! 82:
! 83: /*
! 84: * If the buffer was large enough to hold all the addresses
! 85: * then break out, otherwise increase the buffer size and
! 86: * try again.
! 87: *
! 88: * The only way to know that we definitely had enough space
! 89: * is to know that there was enough space for at least one
! 90: * more struct ifreq. ???
! 91: */
! 92: if ((num_ifreq * sizeof(struct ifreq)) >=
! 93: ifc.ifc_len + sizeof(struct ifreq))
! 94: break;
! 95:
! 96: num_ifreq *= 2;
! 97: ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
! 98: ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
! 99: }
! 100: if (ifc.ifc_buf == NULL)
! 101: log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
! 102:
! 103: ifrp = (struct ifreq *)ifc.ifc_buf;
! 104: ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
! 105: /*
! 106: * Loop through all of the interfaces.
! 107: */
! 108: for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
! 109: struct ifreq ifr;
! 110: #ifdef HAVE_SA_LEN
! 111: n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
! 112: if (n < sizeof(*ifrp))
! 113: n = sizeof(*ifrp);
! 114: #else
! 115: n = sizeof(*ifrp);
! 116: #endif /* HAVE_SA_LEN */
! 117:
! 118: /*
! 119: * Ignore any interface for an address family other than IP.
! 120: */
! 121: if (ifrp->ifr_addr.sa_family != AF_INET) {
! 122: total_interfaces++; /* Eventually may have IP address later */
! 123: continue;
! 124: }
! 125:
! 126: addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
! 127:
! 128: /*
! 129: * Need a template to preserve address info that is
! 130: * used below to locate the next entry. (Otherwise,
! 131: * SIOCGIFFLAGS stomps over it because the requests
! 132: * are returned in a union.)
! 133: */
! 134: bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
! 135:
! 136: /*
! 137: * Ignore loopback interfaces and interfaces that do not
! 138: * support multicast.
! 139: */
! 140: if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
! 141: log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
! 142: flags = ifr.ifr_flags;
! 143: if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST)
! 144: continue;
! 145:
! 146: /*
! 147: * Everyone below is a potential vif interface.
! 148: * We don't care if it has wrong configuration or not configured
! 149: * at all.
! 150: */
! 151: total_interfaces++;
! 152:
! 153: /*
! 154: * Ignore any interface whose address and mask do not define a
! 155: * valid subnet number, or whose address is of the form
! 156: * {subnet,0} or {subnet,-1}.
! 157: */
! 158: if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
! 159: log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s",
! 160: ifr.ifr_name);
! 161: mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
! 162: subnet = addr & mask;
! 163: if ((!inet_valid_subnet(subnet, mask))
! 164: || (addr == subnet) || addr == (subnet | ~mask)) {
! 165: log(LOG_WARNING, 0,
! 166: "ignoring %s, has invalid address (%s) and/or mask (%s)",
! 167: ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
! 168: continue;
! 169: }
! 170:
! 171: /*
! 172: * Ignore any interface that is connected to the same subnet as
! 173: * one already installed in the uvifs array.
! 174: */
! 175: /*
! 176: * TODO: XXX: bug or "feature" is to allow only one interface per
! 177: * subnet?
! 178: */
! 179:
! 180: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 181: if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
! 182: log(LOG_DEBUG, 0,
! 183: "skipping %s (%s on subnet %s) (alias for vif#%u?)",
! 184: v->uv_name, inet_fmt(addr, s1),
! 185: netname(subnet, mask), vifi);
! 186: break;
! 187: }
! 188: if ((addr & v->uv_subnetmask) == v->uv_subnet ||
! 189: (v->uv_subnet & mask) == subnet) {
! 190: log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
! 191: ifr.ifr_name, v->uv_name);
! 192: break;
! 193: }
! 194: }
! 195: if (vifi != numvifs)
! 196: continue;
! 197:
! 198: /*
! 199: * If there is room in the uvifs array, install this interface.
! 200: */
! 201: if (numvifs == MAXVIFS) {
! 202: log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
! 203: continue;
! 204: }
! 205: v = &uvifs[numvifs];
! 206: v->uv_flags = 0;
! 207: v->uv_metric = DEFAULT_METRIC;
! 208: v->uv_admetric = 0;
! 209: v->uv_threshold = DEFAULT_THRESHOLD;
! 210: v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
! 211: v->uv_lcl_addr = addr;
! 212: v->uv_rmt_addr = INADDR_ANY_N;
! 213: v->uv_dst_addr = allpimrouters_group;
! 214: v->uv_subnet = subnet;
! 215: v->uv_subnetmask = mask;
! 216: v->uv_subnetbcast = subnet | ~mask;
! 217: strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
! 218: v->uv_groups = (struct listaddr *)NULL;
! 219: v->uv_dvmrp_neighbors = (struct listaddr *)NULL;
! 220: NBRM_CLRALL(v->uv_nbrmap);
! 221: v->uv_querier = (struct listaddr *)NULL;
! 222: v->uv_igmpv1_warn = 0;
! 223: v->uv_prune_lifetime = 0;
! 224: v->uv_acl = (struct vif_acl *)NULL;
! 225: RESET_TIMER(v->uv_leaf_timer);
! 226: v->uv_addrs = (struct phaddr *)NULL;
! 227: v->uv_filter = (struct vif_filter *)NULL;
! 228: RESET_TIMER(v->uv_pim_hello_timer);
! 229: RESET_TIMER(v->uv_gq_timer);
! 230: v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL;
! 231: v->uv_local_pref = default_source_preference;
! 232: v->uv_local_metric = default_source_metric;
! 233:
! 234: if (flags & IFF_POINTOPOINT)
! 235: v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
! 236: log(LOG_INFO, 0,
! 237: "installing %s (%s on subnet %s) as vif #%u - rate=%d",
! 238: v->uv_name, inet_fmt(addr, s1), netname(subnet, mask),
! 239: numvifs, v->uv_rate_limit);
! 240: ++numvifs;
! 241:
! 242: /*
! 243: * If the interface is not yet up, set the vifs_down flag to
! 244: * remind us to check again later.
! 245: */
! 246: if (!(flags & IFF_UP)) {
! 247: v->uv_flags |= VIFF_DOWN;
! 248: vifs_down = TRUE;
! 249: }
! 250: }
! 251: }
! 252:
! 253:
! 254: #define UNKNOWN -1
! 255: #define EMPTY 1
! 256: #define PHYINT 2
! 257: #define DEFAULT_SOURCE_METRIC 3
! 258: #define DEFAULT_SOURCE_PREFERENCE 4
! 259:
! 260: /*
! 261: * function name: wordToOption
! 262: * input: char *word, a pointer to the word
! 263: * output: int; a number corresponding to the code of the word
! 264: * operation: converts the result of the string comparisons into numerics.
! 265: * comments: called by config_vifs_from_file()
! 266: */
! 267: int
! 268: wordToOption(word)
! 269: char *word;
! 270: {
! 271: if (EQUAL(word, ""))
! 272: return EMPTY;
! 273: if (EQUAL(word, "phyint"))
! 274: return PHYINT;
! 275: if (EQUAL(word, "default_source_metric"))
! 276: return DEFAULT_SOURCE_METRIC;
! 277: if (EQUAL(word, "default_source_preference"))
! 278: return DEFAULT_SOURCE_PREFERENCE;
! 279:
! 280: return UNKNOWN;
! 281: }
! 282:
! 283: /*
! 284: * function name: parse_phyint
! 285: * input: char *s, pointing to the parsing point of the file
! 286: * output: int (TRUE if the parsing was successful, o.w. FALSE)
! 287: * operation: parses the physical interface file configurations, if any.
! 288: * The general form is:
! 289: * phyint <local-addr> [disable]
! 290: */
! 291: static int
! 292: parse_phyint(s)
! 293: char *s;
! 294: {
! 295: char *w, c;
! 296: u_int32 local;
! 297: vifi_t vifi;
! 298: struct uvif *v;
! 299: u_int n;
! 300:
! 301: if (EQUAL((w = next_word(&s)), "")) {
! 302: log(LOG_WARNING, 0, "Missing phyint address in %s", configfilename);
! 303: return(FALSE);
! 304: } /* if empty */
! 305:
! 306: local = inet_parse(w, 4);
! 307: if (!inet_valid_host(local)) {
! 308: log(LOG_WARNING, 0, "Invalid phyint address '%s' in %s", w,
! 309: configfilename);
! 310: return(FALSE);
! 311: } /* invalid address */
! 312:
! 313: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 314: if (vifi == numvifs) {
! 315: log(LOG_WARNING, 0,
! 316: "phyint %s in %s is not a configured interface",
! 317: inet_fmt(local, s1), configfilename);
! 318: return(FALSE);
! 319: } /* if vifi == numvifs */
! 320:
! 321: if (local != v->uv_lcl_addr)
! 322: continue;
! 323:
! 324: while (!EQUAL((w = next_word(&s)), "")) {
! 325: if (EQUAL(w, "disable"))
! 326: v->uv_flags |= VIFF_DISABLED;
! 327: else if(EQUAL(w, "preference"))
! 328: if(EQUAL((w = next_word(&s)), ""))
! 329: log(LOG_WARNING, 0,
! 330: "Missing preference for phyint %s in %s",
! 331: inet_fmt(local, s1), configfilename);
! 332: else if (sscanf(w, "%u%c", &n, &c) != 1 ||
! 333: n < 1 || n > 255 )
! 334: log(LOG_WARNING, 0,
! 335: "Invalid preference '%s' for phyint %s in %s",
! 336: w, inet_fmt(local, s1),
! 337: configfilename);
! 338: else {
! 339: IF_DEBUG(DEBUG_ASSERT)
! 340: log(LOG_DEBUG, 0,
! 341: "Config setting default local preference on %s to %d.",
! 342: inet_fmt(local, s1), n);
! 343: v->uv_local_pref = n;
! 344: }
! 345:
! 346: else if(EQUAL(w, "metric"))
! 347: if(EQUAL((w = next_word(&s)), ""))
! 348: log(LOG_WARNING, 0,
! 349: "Missing metric for phyint %s in %s",
! 350: inet_fmt(local, s1), configfilename);
! 351: else if (sscanf(w, "%u%c", &n, &c) != 1 ||
! 352: n < 1 || n > 1024 )
! 353: log(LOG_WARNING, 0,
! 354: "Invalid metric '%s' for phyint %s in %s",
! 355: w, inet_fmt(local, s1),
! 356: configfilename);
! 357: else {
! 358: IF_DEBUG(DEBUG_ASSERT)
! 359: log(LOG_DEBUG, 0,
! 360: "Config setting default local metric on %s to %d.",
! 361: inet_fmt(local, s1), n);
! 362: v->uv_local_metric = n;
! 363: }
! 364:
! 365: } /* if not empty */
! 366: break;
! 367: }
! 368: return(TRUE);
! 369: }
! 370:
! 371:
! 372: /*
! 373: * function name: parse_default_source_metric
! 374: * input: char *s
! 375: * output: int
! 376: * operation: reads and assigns the default source metric, if no reliable
! 377: * unicast routing information available.
! 378: * General form:
! 379: * 'default_source_metric <number>'.
! 380: * default pref and metric statements should precede all phyint
! 381: * statements in the config file.
! 382: */
! 383: int
! 384: parse_default_source_metric(s)
! 385: char *s;
! 386: {
! 387: char *w;
! 388: u_int value;
! 389: vifi_t vifi;
! 390: struct uvif *v;
! 391:
! 392: value = DEFAULT_LOCAL_METRIC;
! 393: if (EQUAL((w = next_word(&s)), "")) {
! 394: log(LOG_WARNING, 0,
! 395: "Missing default source metric; set to default %u",
! 396: DEFAULT_LOCAL_METRIC);
! 397: } else if (sscanf(w, "%u", &value) != 1) {
! 398: log(LOG_WARNING, 0,
! 399: "Invalid default source metric; set to default %u",
! 400: DEFAULT_LOCAL_METRIC);
! 401: value = DEFAULT_LOCAL_METRIC;
! 402: }
! 403: default_source_metric = value;
! 404: log(LOG_INFO, 0, "default_source_metric is %u", value);
! 405:
! 406: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
! 407: v->uv_local_metric = default_source_metric;
! 408: }
! 409:
! 410: return(TRUE);
! 411: }
! 412:
! 413:
! 414: /*
! 415: * function name: parse_default_source_preference
! 416: * input: char *s
! 417: * output: int
! 418: * operation: reads and assigns the default source preference, if no reliable
! 419: * unicast routing information available.
! 420: * General form:
! 421: * 'default_source_preference <number>'.
! 422: * default pref and metric statements should precede all phyint
! 423: * statements in the config file.
! 424: */
! 425: int
! 426: parse_default_source_preference(s)
! 427: char *s;
! 428: {
! 429: char *w;
! 430: u_int value;
! 431: vifi_t vifi;
! 432: struct uvif *v;
! 433:
! 434: value = DEFAULT_LOCAL_PREF;
! 435: if (EQUAL((w = next_word(&s)), "")) {
! 436: log(LOG_WARNING, 0,
! 437: "Missing default source preference; set to default %u",
! 438: DEFAULT_LOCAL_PREF);
! 439: } else if (sscanf(w, "%u", &value) != 1) {
! 440: log(LOG_WARNING, 0,
! 441: "Invalid default source preference; set to default %u",
! 442: DEFAULT_LOCAL_PREF);
! 443: value = DEFAULT_LOCAL_PREF;
! 444: }
! 445: default_source_preference = value;
! 446: log(LOG_INFO, 0, "default_source_preference is %u", value);
! 447:
! 448: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
! 449: v->uv_local_pref = default_source_preference;
! 450: }
! 451:
! 452: return(TRUE);
! 453: }
! 454:
! 455:
! 456:
! 457:
! 458: void
! 459: config_vifs_from_file()
! 460: {
! 461: FILE *f;
! 462: char linebuf[100];
! 463: char *w, *s;
! 464: struct ifconf ifc;
! 465: int option;
! 466: char ifbuf[BUFSIZ];
! 467:
! 468: if ((f = fopen(configfilename, "r")) == NULL) {
! 469: if (errno != ENOENT) log(LOG_WARNING, errno, "can't open %s",
! 470: configfilename);
! 471: return;
! 472: }
! 473:
! 474: ifc.ifc_buf = ifbuf;
! 475: ifc.ifc_len = sizeof(ifbuf);
! 476: if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
! 477: log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
! 478:
! 479: while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
! 480: s = linebuf;
! 481: w = next_word(&s);
! 482: option = wordToOption(w);
! 483: switch(option) {
! 484: case EMPTY:
! 485: continue;
! 486: break;
! 487: case PHYINT:
! 488: parse_phyint(s);
! 489: break;
! 490: default:
! 491: log(LOG_WARNING, 0, "unknown command '%s' in %s",
! 492: w, configfilename);
! 493: }
! 494: }
! 495: fclose(f);
! 496: }
! 497:
! 498:
! 499: static char *
! 500: next_word(s)
! 501: char **s;
! 502: {
! 503: char *w;
! 504:
! 505: w = *s;
! 506: while (*w == ' ' || *w == '\t')
! 507: w++;
! 508:
! 509: *s = w;
! 510: for(;;) {
! 511: switch (**s) {
! 512: case ' ' :
! 513: case '\t' :
! 514: **s = '\0';
! 515: (*s)++;
! 516: return(w);
! 517: case '\n' :
! 518: case '#' :
! 519: **s = '\0';
! 520: return(w);
! 521: case '\0' :
! 522: return(w);
! 523: default :
! 524: if (isascii(**s) && isupper(**s))
! 525: **s = tolower(**s);
! 526: (*s)++;
! 527: }
! 528: }
! 529: }
! 530:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>