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