pimd-2.1.8/0000755000000000000000000000000011700261371007337 5ustar pimd-2.1.8/callout.c0000644000000000000000000001161611700261371011153 0ustar /* * The mrouted program is covered by the license in the accompanying file * named "LICENSE.mrouted". Use of the mrouted program represents acceptance * of the terms and conditions listed in that file. * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. * * * callout.c,v 3.8.4.5 1997/05/16 20:18:25 fenner Exp */ #include "defs.h" /* the code below implements a callout queue */ static int id = 0; static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */ struct timeout_q { struct timeout_q *next; /* next event */ int id; cfunc_t func; /* function to call */ void *data; /* func's data */ int time; /* time offset to next event*/ }; #if 0 #define CALLOUT_DEBUG 1 #define CALLOUT_DEBUG2 1 #endif /* 0 */ #ifdef CALLOUT_DEBUG2 static void print_Q((void); #else #define print_Q() #endif void callout_init() { Q = (struct timeout_q *) 0; } void free_all_callouts() { struct timeout_q *p; while (Q) { p = Q; Q = Q->next; free(p); } } /* * elapsed_time seconds have passed; perform all the events that should * happen. */ void age_callout_queue(elapsed_time) int elapsed_time; { struct timeout_q *ptr, *expQ; #ifdef CALLOUT_DEBUG IF_DEBUG(DEBUG_TIMEOUT) logit(LOG_DEBUG, 0, "aging queue (elapsed time %d):", elapsed_time); print_Q(); #endif expQ = Q; ptr = NULL; while (Q) { if (Q->time > elapsed_time) { Q->time -= elapsed_time; if (ptr) { ptr->next = NULL; break; } return; } else { elapsed_time -= Q->time; ptr = Q; Q = Q->next; } } /* handle queue of expired timers */ while (expQ) { ptr = expQ; if (ptr->func) ptr->func(ptr->data); expQ = expQ->next; free(ptr); } } /* * Return in how many seconds age_callout_queue() would like to be called. * Return -1 if there are no events pending. */ int timer_nextTimer() { if (Q) { if (Q->time < 0) { logit(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", Q->time); return 0; } return Q->time; } return -1; } /* * sets the timer */ int timer_setTimer(delay, action, data) int delay; /* number of units for timeout */ cfunc_t action; /* function to be called on timeout */ void *data; /* what to call the timeout function with */ { struct timeout_q *ptr, *node, *prev; #ifdef CALLOUT_DEBUG IF_DEBUG(DEBUG_TIMEOUT) logit(LOG_DEBUG, 0, "setting timer:"); print_Q(); #endif /* create a node */ node = (struct timeout_q *)calloc(1, sizeof(struct timeout_q)); if (!node) { logit(LOG_ERR, 0, "Failed calloc() in timer_settimer\n"); return -1; } node->func = action; node->data = data; node->time = delay; node->next = 0; node->id = ++id; prev = ptr = Q; /* insert node in the queue */ /* if the queue is empty, insert the node and return */ if (!Q) Q = node; else { /* chase the pointer looking for the right place */ while (ptr) { if (delay < ptr->time) { /* right place */ node->next = ptr; if (ptr == Q) Q = node; else prev->next = node; ptr->time -= node->time; print_Q(); return node->id; } else { /* keep moving */ delay -= ptr->time; node->time = delay; prev = ptr; ptr = ptr->next; } } prev->next = node; } print_Q(); return node->id; } /* returns the time until the timer is scheduled */ int timer_leftTimer(timer_id) int timer_id; { struct timeout_q *ptr; int left = 0; if (!timer_id) return -1; for (ptr = Q; ptr; ptr = ptr->next) { left += ptr->time; if (ptr->id == timer_id) return left; } return -1; } /* clears the associated timer */ void timer_clearTimer(timer_id) int timer_id; { struct timeout_q *ptr, *prev; if (!timer_id) return; prev = ptr = Q; /* * find the right node, delete it. the subsequent node's time * gets bumped up */ print_Q(); while (ptr) { if (ptr->id == timer_id) { /* got the right node */ /* unlink it from the queue */ if (ptr == Q) Q = Q->next; else prev->next = ptr->next; /* increment next node if any */ if (ptr->next != 0) (ptr->next)->time += ptr->time; if (ptr->data) free(ptr->data); free(ptr); print_Q(); return; } prev = ptr; ptr = ptr->next; } print_Q(); } #ifdef CALLOUT_DEBUG2 /* * debugging utility */ static void print_Q() { struct timeout_q *ptr; IF_DEBUG(DEBUG_TIMEOUT) for (ptr = Q; ptr; ptr = ptr->next) logit(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time); } #endif /* CALLOUT_DEBUG2 */ /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/rsrr_var.h0000644000000000000000000000370311700261371011353 0ustar /* * Copyright (c) 1993, 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, Information * Sciences Institute. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no 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. * * Other copyrights might apply to parts of this software and are so * noted when applicable. */ #ifndef __RSRR_VAR_H__ #define __RSRR_VAR_H__ /* RSRR things that are only needed by mrouted. */ /* Cache of Route Query messages, distinguished by source, * destination, and client addresses. Cache is flushed by RSRR client * -- it sends notification when an unwanted Route Reply is received. * Since this only happens during route changes, it is more likely * that the cache will be flushed when the kernel table entry is * deleted. */ struct rsrr_cache { struct rsrr_rq route_query; /* Cached Route Query */ struct sockaddr_un client_addr; /* Client address */ int client_length; /* Length of client */ struct rsrr_cache *next; /* next cache item */ }; #endif /* __RSRR_VAR_H__ */ pimd-2.1.8/main.c0000644000000000000000000005437011700261371010440 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: main.c,v 1.19 2003/02/12 21:56:04 pavlin Exp $ */ /* * 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 "defs.h" #include #include #include #ifdef SNMP #include "snmp.h" #endif char versionstring[100]; int disable_all_by_default = 0; int haveterminal = 1; struct rp_hold *g_rp_hold = NULL; char *configfilename = _PATH_PIMD_CONF; extern char todaysversion[]; static int sighandled = 0; #define GOT_SIGINT 0x01 #define GOT_SIGHUP 0x02 #define GOT_SIGUSR1 0x04 #define GOT_SIGUSR2 0x08 #define GOT_SIGALRM 0x10 #ifdef SNMP #define NHANDLERS 34 #else #define NHANDLERS 3 #endif static struct ihandler { int fd; /* File descriptor */ ihfunc_t func; /* Function to call with &fd_set */ } ihandlers[NHANDLERS]; static int nhandlers = 0; static struct debugname { char *name; uint32_t level; size_t nchars; } debugnames[] = { { "dvmrp_detail", DEBUG_DVMRP_DETAIL, 5 }, { "dvmrp_prunes", DEBUG_DVMRP_PRUNE, 8 }, { "dvmrp_pruning", DEBUG_DVMRP_PRUNE, 8 }, { "dvmrp_routes", DEBUG_DVMRP_ROUTE, 7 }, { "dvmrp_routing", DEBUG_DVMRP_ROUTE, 7 }, { "dvmrp_mrt", DEBUG_DVMRP_ROUTE, 7 }, { "dvmrp_neighbors", DEBUG_DVMRP_PEER, 7 }, { "dvmrp_peers", DEBUG_DVMRP_PEER, 8 }, { "dvmrp_hello", DEBUG_DVMRP_PEER, 7 }, { "dvmrp_timers", DEBUG_DVMRP_TIMER, 7 }, { "dvmrp", DEBUG_DVMRP, 1 }, { "igmp_proto", DEBUG_IGMP_PROTO, 6 }, { "igmp_timers", DEBUG_IGMP_TIMER, 6 }, { "igmp_members", DEBUG_IGMP_MEMBER, 6 }, { "groups", DEBUG_MEMBER, 1 }, { "membership", DEBUG_MEMBER, 2 }, { "igmp", DEBUG_IGMP, 1 }, { "trace", DEBUG_TRACE, 2 }, { "mtrace", DEBUG_TRACE, 2 }, { "traceroute", DEBUG_TRACE, 2 }, { "timeout", DEBUG_TIMEOUT, 2 }, { "callout", DEBUG_TIMEOUT, 3 }, { "packets", DEBUG_PKT, 2 }, { "pkt", DEBUG_PKT, 2 }, { "interfaces", DEBUG_IF, 2 }, { "vif", DEBUG_IF, 1 }, { "kernel", DEBUG_KERN, 2 }, { "cache", DEBUG_MFC, 1 }, { "mfc", DEBUG_MFC, 2 }, { "k_cache", DEBUG_MFC, 2 }, { "k_mfc", DEBUG_MFC, 2 }, { "rsrr", DEBUG_RSRR, 2 }, { "pim_detail", DEBUG_PIM_DETAIL, 5 }, { "pim_hello", DEBUG_PIM_HELLO, 5 }, { "pim_neighbors", DEBUG_PIM_HELLO, 5 }, { "pim_peers", DEBUG_PIM_HELLO, 5 }, { "pim_register", DEBUG_PIM_REGISTER, 5 }, { "registers", DEBUG_PIM_REGISTER, 2 }, { "pim_join_prune", DEBUG_PIM_JOIN_PRUNE, 5 }, { "pim_j_p", DEBUG_PIM_JOIN_PRUNE, 5 }, { "pim_jp", DEBUG_PIM_JOIN_PRUNE, 5 }, { "pim_bootstrap", DEBUG_PIM_BOOTSTRAP, 5 }, { "pim_bsr", DEBUG_PIM_BOOTSTRAP, 5 }, { "bsr", DEBUG_PIM_BOOTSTRAP, 1 }, { "bootstrap", DEBUG_PIM_BOOTSTRAP, 1 }, { "pim_asserts", DEBUG_PIM_ASSERT, 5 }, { "pim_cand_rp", DEBUG_PIM_CAND_RP, 5 }, { "pim_c_rp", DEBUG_PIM_CAND_RP, 5 }, { "pim_rp", DEBUG_PIM_CAND_RP, 6 }, { "rp", DEBUG_PIM_CAND_RP, 2 }, { "pim_routes", DEBUG_PIM_MRT, 6 }, { "pim_routing", DEBUG_PIM_MRT, 6 }, { "pim_mrt", DEBUG_PIM_MRT, 5 }, { "pim_timers", DEBUG_PIM_TIMER, 5 }, { "pim_rpf", DEBUG_PIM_RPF, 6 }, { "rpf", DEBUG_RPF, 3 }, { "pim", DEBUG_PIM, 1 }, { "routes", DEBUG_MRT, 1 }, { "routing", DEBUG_MRT, 1 }, { "mrt", DEBUG_MRT, 1 }, { "neighbors", DEBUG_NEIGHBORS, 1 }, { "routers", DEBUG_NEIGHBORS, 6 }, { "mrouters", DEBUG_NEIGHBORS, 7 }, { "peers", DEBUG_NEIGHBORS, 1 }, { "timers", DEBUG_TIMER, 1 }, { "asserts", DEBUG_ASSERT, 1 }, { "all", DEBUG_ALL, 2 }, { "3", 0xffffffff, 1 } /* compat. */ }; /* * Forward declarations. */ static void handler (int); static void timer (void *); static void cleanup (void); static void restart (int); static void resetlogging (void *); int register_input_handler(int fd, ihfunc_t func) { if (nhandlers >= NHANDLERS) return -1; ihandlers[nhandlers].fd = fd; ihandlers[nhandlers++].func = func; return 0; } static void do_randomize(void) { #define rol32(data,shift) ((data) >> (shift)) | ((data) << (32 - (shift))) int fd; unsigned int seed; /* Setup a fallback seed based on quasi random. */ #ifdef SYSV seed = time(NULL); #else seed = time(NULL) ^ gethostid(); #endif seed = rol32(seed, seed); fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { if (-1 == read(fd, &seed, sizeof(seed))) warn("Failed reading entropy from /dev/urandom"); close(fd); } #ifdef SYSV srand48(seed); #else srandom(seed); #endif } /* Figure out the PID of a running daemon. */ static pid_t daemon_pid(void) { int result; char *path = NULL; FILE *fp; pid_t pid = -1; result = asprintf(&path, "%s%s.pid", _PATH_VARRUN, __progname); if (result == -1 || path == NULL) return -1; fp = fopen(path, "r"); if (!fp) { free(path); return -1; } result = fscanf(fp, "%d", &pid); fclose(fp); free(path); return pid; } /* Send signal to running daemon and the show resulting file. */ static void killshow(int signo, char *file) { pid_t pid = daemon_pid(); char buf[100]; if (pid > 0) { if (file) remove(file); kill(pid, signo); if (file) { usleep(200); snprintf(buf, sizeof(buf), "cat %s", file); if (-1 == system(buf)) { warnx("Failed listing file %s\n", file); } } } } static int usage(void) { size_t i, j, k; struct debugname *d; fprintf(stderr, "Usage: %s [-fhlNqrv] [-c FILE] [-d [LEVEL][,LEVEL...]]\n\n", __progname); fputs(" -c, --config=FILE Configuration file to use, default /etc/pimd.conf\n", stderr); fputs(" -d, --debug[=LEVEL] Debug level, see below for valid levels\n", stderr); fputs(" -f, --foreground Run in foreground, do not detach from calling terminal\n", stderr); fputs(" -h, --help Show this help text\n", stderr); /* fputs(" -i, --show-cache Show internal cache tables\n", stderr); */ fputs(" -l, --reload-config Tell a running pimd to reload its configuration\n", stderr); fputs(" -N, --disable-vifs Disable all virtual interfaces (phyint) by default\n", stderr); /* fputs(" -p,--show-debug Show debug dump, only if debug is enabled\n", stderr); */ fputs(" -q, --quit-daemon Send SIGTERM to a running pimd\n", stderr); fputs(" -r, --show-routes Show state of VIFs and multicast routing tables\n", stderr); fprintf(stderr, " -v, --version Show %s version\n", __progname); fputs("\n", stderr); j = 0xffffffff; k = 0; fputs("Valid debug levels:\n ", stderr); for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) { if ((j & d->level) == d->level) { if (k++) { if (!(k % 5)) fputs("\n ", stderr); else fputs(", ", stderr); } fputs(d->name, stderr); j &= ~d->level; } } fputc('\n', stderr); return 1; } int main(int argc, char *argv[]) { int dummysigalrm, foreground = 0; struct timeval tv, difftime, curtime, lasttime, *timeout; fd_set rfds, readers; int nfds, n, i, secs, ch; struct sigaction sa; time_t boottime; struct option long_options[] = { {"config", 1, 0, 'c'}, {"debug", 2, 0, 'd'}, {"foreground", 0, 0, 'f'}, {"disable-vifs", 0, 0, 'N'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"quit-daemon", 0, 0, 'q'}, {"reload-config", 0, 0, 'l'}, {"show-routes", 0, 0, 'r'}, /* {"show-cache", 0, 0, 'i'}, */ /* {"show-debug", 0, 0, 'p'}, */ {0, 0, 0, 0} }; snprintf(versionstring, sizeof (versionstring), "pimd version %s", todaysversion); while ((ch = getopt_long (argc, argv, "c:d::fhlNP::vqr", long_options, NULL)) != EOF) { switch (ch) { case 'c': configfilename = optarg; break; case 'd': if (!optarg) { debug = DEBUG_DEFAULT; } else { char *p,*q; size_t i, len; struct debugname *d; debug = 0; p = optarg; q = NULL; while (p) { q = strchr(p, ','); if (q) *q++ = '\0'; len = strlen(p); for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) if (len >= d->nchars && strncmp(d->name, p, len) == 0) break; if (i == ARRAY_LEN(debugnames)) return usage(); debug |= d->level; p = q; } } break; case 'f': foreground = 1; break; case 'h': return usage(); case 'l': killshow(SIGHUP, NULL); return 0; case 'N': disable_all_by_default = 1; break; case 'P': #ifdef SNMP if (!optarg) dest_port = DEFAULT_PORT; else { dest_port = strtonum(optarg, 1, 65535, &errstr); if (errstr) { warnx("destination port %s", errstr); dest_port = DEFAULT_PORT; } } #else warnx("SNMP support missing, please feel free to submit a patch."); #endif break; case 'v': printf("%s\n", versionstring); return 0; case 'q': killshow(SIGTERM, NULL); return 0; case 'r': killshow(SIGUSR1, _PATH_PIMD_DUMP); return 0; #if 0 /* XXX: TODO */ case 'i': killshow(SIGUSR2, _PATH_PIMD_CACHE); return 0; case 'p': killshow(SIGQUIT, NULL); return 0; #endif default: return usage(); } } argc -= optind; argv += optind; if (argc > 0) { return usage(); } if (geteuid() != 0) { fprintf(stderr, "%s: must be root\n", __progname); exit(1); } setlinebuf(stderr); if (debug != 0) { struct debugname *d; char c; int tmpd = debug; fprintf(stderr, "debug level 0x%lx ", debug); c = '('; for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) { if ((tmpd & d->level) == d->level) { tmpd &= ~d->level; fprintf(stderr, "%c%s", c, d->name); c = ','; } } fprintf(stderr, ")\n"); } /* * Create directory for runtime files */ mkdir(_PATH_PIMD_RUNDIR, 0755); /* * Setup logging */ #ifdef LOG_DAEMON (void)openlog("pimd", LOG_PID, LOG_DAEMON); (void)setlogmask(LOG_UPTO(LOG_NOTICE)); #else (void)openlog("pimd", LOG_PID); #endif /* LOG_DAEMON */ logit(LOG_DEBUG, 0, "%s starting", versionstring); do_randomize(); time(&boottime); /* Start up the log rate-limiter */ resetlogging(NULL); callout_init(); init_igmp(); init_pim(); #ifdef HAVE_ROUTING_SOCKETS init_routesock(); #endif /* HAVE_ROUTING_SOCKETS */ init_pim_mrt(); init_timers(); /* TODO: check the kernel DVMRP/MROUTED/PIM support version */ #ifdef SNMP if (i = snmp_init()) return i; #endif /* SNMP */ init_vifs(); init_rp_and_bsr(); /* Must be after init_vifs() */ #ifdef RSRR rsrr_init(); #endif /* RSRR */ sa.sa_handler = handler; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); sigaction(SIGALRM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); FD_ZERO(&readers); FD_SET(igmp_socket, &readers); nfds = igmp_socket + 1; for (i = 0; i < nhandlers; i++) { FD_SET(ihandlers[i].fd, &readers); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } IF_DEBUG(DEBUG_IF) dump_vifs(stderr); IF_DEBUG(DEBUG_PIM_MRT) dump_pim_mrt(stderr); /* schedule first timer interrupt */ timer_setTimer(TIMER_INTERVAL, timer, NULL); if (!debug && !foreground) { /* Detach from the terminal */ haveterminal = 0; if (fork()) exit(0); (void)close(0); (void)close(1); (void)close(2); (void)open("/", 0); (void)dup2(0, 1); (void)dup2(0, 2); #ifdef SYSV (void)setpgrp(); #else #ifdef TIOCNOTTY n = open("/dev/tty", 2); if (n >= 0) { (void)ioctl(n, TIOCNOTTY, (char *)0); (void)close(n); } #else if (setsid() < 0) perror("setsid"); #endif /* TIOCNOTTY */ #endif /* SYSV */ } /* End of child process code */ if (pidfile(NULL)) { warn("Cannot create pidfile"); } /* * Main receive loop. */ dummysigalrm = SIGALRM; difftime.tv_usec = 0; gettimeofday(&curtime, NULL); lasttime = curtime; while (1) { memcpy(&rfds, &readers, sizeof(rfds)); secs = timer_nextTimer(); if (secs == -1) timeout = NULL; else { timeout = &tv; timeout->tv_sec = secs; timeout->tv_usec = 0; } if (boottime) { time_t n; time(&n); if (n > boottime + 15) { struct rp_hold *rph = g_rp_hold; while(rph) { add_rp_grp_entry(&cand_rp_list, &grp_mask_list, rph->address, 1, (u_int16)0xffffff, rph->group, rph->mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); rph = rph->next; } boottime = 0; } } if (sighandled) { if (sighandled & GOT_SIGINT) { sighandled &= ~GOT_SIGINT; break; } if (sighandled & GOT_SIGHUP) { sighandled &= ~GOT_SIGHUP; restart(SIGHUP); /* reconstruct readers and nfds */ FD_ZERO(&readers); FD_SET(igmp_socket, &readers); nfds = igmp_socket + 1; for (i = 0; i < nhandlers; i++) { FD_SET(ihandlers[i].fd, &readers); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } memcpy(&rfds, &readers, sizeof(rfds)); } if (sighandled & GOT_SIGUSR1) { sighandled &= ~GOT_SIGUSR1; fdump(SIGUSR1); } if (sighandled & GOT_SIGUSR2) { sighandled &= ~GOT_SIGUSR2; cdump(SIGUSR2); } if (sighandled & GOT_SIGALRM) { sighandled &= ~GOT_SIGALRM; timer(&dummysigalrm); } } if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) { if (errno != EINTR) /* SIGALRM is expected */ logit(LOG_WARNING, errno, "select failed"); continue; } if (n > 0) { /* TODO: shall check first igmp_socket for better performance? */ for (i = 0; i < nhandlers; i++) { if (FD_ISSET(ihandlers[i].fd, &rfds)) { (*ihandlers[i].func)(ihandlers[i].fd, &rfds); } } } /* * Handle timeout queue. * * If select + packet processing took more than 1 second, * or if there is a timeout pending, age the timeout queue. * * If not, collect usec in difftime to make sure that the * time doesn't drift too badly. * * If the timeout handlers took more than 1 second, * age the timeout queue again. XXX This introduces the * potential for infinite loops! */ do { /* * If the select timed out, then there's no other * activity to account for and we don't need to * call gettimeofday. */ if (n == 0) { curtime.tv_sec = lasttime.tv_sec + secs; curtime.tv_usec = lasttime.tv_usec; n = -1; /* don't do this next time through the loop */ } else gettimeofday(&curtime, NULL); difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec; while (difftime.tv_usec >= 1000000) { difftime.tv_sec++; difftime.tv_usec -= 1000000; } if (difftime.tv_usec < 0) { difftime.tv_sec--; difftime.tv_usec += 1000000; } lasttime = curtime; if (secs == 0 || difftime.tv_sec > 0) age_callout_queue(difftime.tv_sec); secs = -1; } while (difftime.tv_sec > 0); } /* Main loop */ logit(LOG_NOTICE, 0, "%s exiting", versionstring); cleanup(); exit(0); } /* * The 'virtual_time' variable is initialized to a value that will cause the * first invocation of timer() to send a probe or route report to all vifs * and send group membership queries to all subnets for which this router is * querier. This first invocation occurs approximately TIMER_INTERVAL seconds * after the router starts up. Note that probes for neighbors and queries * for group memberships are also sent at start-up time, as part of initial- * ization. This repetition after a short interval is desirable for quickly * building up topology and membership information in the presence of possible * packet loss. * * 'virtual_time' advances at a rate that is only a crude approximation of * real time, because it does not take into account any time spent processing, * and because the timer intervals are sometimes shrunk by a random amount to * avoid unwanted synchronization with other routers. */ u_long virtual_time = 0; /* * Timer routine. Performs all perodic functions: * aging interfaces, quering neighbors and members, etc... The granularity * is equal to TIMER_INTERVAL. */ static void timer(void *i __attribute__((unused))) { age_vifs(); /* Timeout neighbors and groups */ age_routes(); /* Timeout routing entries */ age_misc(); /* Timeout the rest (Cand-RP list, etc) */ virtual_time += TIMER_INTERVAL; timer_setTimer(TIMER_INTERVAL, timer, NULL); } /* * Performs all necessary functions to quit gracefully */ /* TODO: implement all necessary stuff */ static void cleanup(void) { vifi_t vifi; struct uvif *v; /* inform all neighbors that I'm going to die */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if ((v->uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER | VIFF_TUNNEL)) == 0) send_pim_hello(v, 0); } #ifdef RSRR rsrr_clean(); #endif /* RSRR */ /* TODO: XXX (not in the spec): if I am the BSR, somehow inform the * other routers I am going down and need to elect another BSR? * (probably by sending a the Cand-RP-set with my_priority=LOWEST?) */ k_stop_pim(igmp_socket); } /* * Signal handler. Take note of the fact that the signal arrived * so that the main loop can take care of it. */ static void handler(int sig) { switch (sig) { case SIGALRM: sighandled |= GOT_SIGALRM; case SIGINT: case SIGTERM: sighandled |= GOT_SIGINT; break; case SIGHUP: sighandled |= GOT_SIGHUP; break; case SIGUSR1: sighandled |= GOT_SIGUSR1; break; case SIGUSR2: sighandled |= GOT_SIGUSR2; break; } } /* TODO: not verified */ /* * Restart the daemon */ static void restart(int i __attribute__((unused))) { #ifdef SNMP int s; #endif /* SNMP */ logit(LOG_NOTICE, 0, "%s % restart", versionstring); /* * reset all the entries */ /* TODO: delete? free_all_routes(); */ free_all_callouts(); stop_all_vifs(); k_stop_pim(igmp_socket); nhandlers = 0; close(igmp_socket); close(pim_socket); /* * When IOCTL_OK_ON_RAW_SOCKET is defined, 'udp_socket' is equal * 'to igmp_socket'. Therefore, 'udp_socket' should be closed only * if they are different. */ #ifndef IOCTL_OK_ON_RAW_SOCKET close(udp_socket); #endif #ifdef HAVE_ROUTING_SOCKETS close(routing_socket); #endif /* HAVE_ROUTING_SOCKETS */ /* * start processing again */ init_igmp(); init_pim(); #ifdef HAVE_ROUTING_SOCKETS init_routesock(); #endif /* HAVE_ROUTING_SOCKETS */ init_pim_mrt(); #ifdef SNMP if ( s = snmp_init()) exit(s); #endif /* SNMP */ init_vifs(); /* schedule timer interrupts */ timer_setTimer(TIMER_INTERVAL, timer, NULL); } static void resetlogging(void *arg) { int nxttime = 60; void *narg = NULL; if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) { nxttime = LOG_SHUT_UP; narg = (void *)&log_nmsgs; /* just need some valid void * */ syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes", LOG_SHUT_UP / 60); } else { log_nmsgs = 0; } timer_setTimer(nxttime, resetlogging, narg); } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/AUTHORS0000644000000000000000000000034411700261371010410 0ustar Current Maintainer(s): * Joachim Nilsson Original Author(s): * Ahmed Helmy * George Edmond "Rusty" Eddy * Pavlin Ivanov Radoslavov pimd-2.1.8/ChangeLog0000644000000000000000000010430511700261371011114 0ustar #+TITLE: pimd | Change Log #+AUTHOR: Ahmed Helmy, George Edmond Eddy, Pavlin Ivanov Radoslavov * Version 2.1.8: October 22, 2011 ** Changes & New Features - Update docs of static Rendez-Vous Point, rp_address, configuration in man page and example pimd.conf. Thanks to Andriy Senkovych and YAMAMOTO Shigeru - Replaced malloc() with calloc() to mitigate risk of accessing junk data and ease debugging. Thanks to YAMAMOTO Shigeru - Extend .conf file 'rp_address' option with 'priority' field. Code changes and documentation updates by YAMAMOTO Shigeru ** Bug Fixes - A serious bug in pim_proto.c:receive_pim_register() was found and fixed by Jean-Pascal Billaud. In essence, the RP check was broken since the code only looked at my_cand_rp_address, which is not set when using the rp_address config. Everything works fine with auto-RP mode though. This issue completely breaks the register path since the JOIN(S,G) is never sent back... - Fix FTBFS issues reported from Debian. Later GCC versions trigger unused variable warnings. Patches and cleanup Antonin Kral * Version 2.1.7: January 9, 2011 ** Changes & New Features - The previous move of runtime dump files to /var/lib/misc have been changed to /var/run/pimd instead. This to accomodate *BSD systems that do not have the /var/lib tree, and also recommended in the Filesystem Hierarchy Standard, http://www.pathname.com/fhs/pub/fhs-2.3.html#VARRUNRUNTIMEVARIABLEDATA * Version 2.1.6: January 8, 2011 ** Changes & New Features - Debian package now conflicts with smcroute, in addition to mrouted. It is only possible to run one multicast routing daemon at a time, kernel limitation. - The location of the dump file(s) have been moved from /var/tmp to /var/lib/misc due to the insecure nature of /var/tmp. See more below. ** Bug Fixes - kern.c:k_del_vif(): Fix build error on GNU/kFreeBSD - CVE-2011-0007: Insecure file creation in /var/tmp. "On USR1, pimd will write to /var/tmp/pimd.dump a dump of the multicast route table. Since /var/tmp is writable by any user, a user can create a symlink to any file he wants to destroy with the content of the multicast routing table." * Version 2.1.5: November 21, 2010 ** Changes & New Features - Improved error messages in kern.c - Renamed CHANGES to ChangeLog ** Bug Fixes - Import mrouted fix: on GNU/Linux systems (only!) the call to ~kern.c:k_del_vif()~ fails with: ="setsockopt MRT_DEL_VIF on vif 3: Invalid argument"=. This is due to differences in the Linux and *BSD ~MRT_DEL_VIF~ API. The Linux kernel expects to receive a ~struct vifctl~ associated with the VIF to be deleted, *BSD systems on the other hand expect to receive the index of that VIF. Bug reported and fixed on mrouted by Dan Kruchinin * Version 2.1.4: September 25, 2010 ** Changes & New Features - Updates for support on Debian GNU/kFreeBSD, FreeBSD kernel with GNU userland. ** Bug Fixes - Lior Dotan reports that pimd 2.1.2 and 2.1.3 are severely broken w.r.t. uninformed systematic replace of ~bcopy()~ with ~memcpy()~ API. * Version 2.1.3: September 8, 2010 ** Changes & New Features - ~debug.c:syslog()~: Removed GNU:ism %m, use =strerror(errno)= instead. - Cleanup and ansification of a couple of files: rp.c, mrt.c, vif.c, route.c - Initialize stack variables to silence overzealous GCC on PowerPC and S/390. Debian bug 595584, this closes pimd issue #3 on GitHub. ** Bug Fixes - Merge bug fix for static-rp configurations from Kame's pim6sd route.c r1.28 - Close TODO item by merging in relevant changes from Kame's pim6sd vif.c r1.3 - Tried fixing ~debug.c:logit()~ build failure on Sparc due to mixup in headers for ~tv_usec~ type. * Version 2.1.2: September 4, 2010 ** Changes & New Features - License change on mrouted code from OpenBSD team => pimd fully free under 3-clause BSD! This was also covered in v2.1.0-alpha29.17, but now all files have been updated, including LICENSE.mrouted. - Code cleanup and ansification. - Simplified Makefile so that it works seamlessly on GNU Make and BSD PMake. - Replaced all calls to ~bzero()~ and ~bcopy()~ with ~memset()~ and ~memcpy()~. - Use ~getopt_long()~ for argument parsing. - Add, and improve, -h,--help output. - Add -f,--foreground option. - Add -v,--version option. - Add -l,--reload-config which sends SIGHUP to a running daemon. - Add -r,--show-routes which sends SIGUSR1 to a running daemon. - Add -q,--quit-daemon which sends SIGTERM to a running daemon. - Make it possible to call pimd as a regular user, for --help and --version. - Man page cleaned up, a lot, and updated with new options. ** Bug Fixes - Replaced dangerous old string functions with safer ~snprintf()~ and ~strlcpy()~ - Added checks for ~malloc()~ return values, all over the code base. - Fixed issues reported by Sparse (CC=cgcc). - Make sure to retry syscalls ~recvfrom()~ and ~sendto()~ on signal (SIGINT). - Fix build issues on OpenBSD 4.7 and FreeBSD 8.1 thanks to Guillaume Sellier. - Kernel include issues on Ubuntu 8.04, Linux <= 2.6.25, by Nikola Knežević - Fix build issues on NetBSD * Version 2.1.1: January 17, 2010 ** Changes & New Features - Bumping version again to celebrate the changes and make it easier for distributions to handle the upgrade. ** Bug Fixes Merged all patches from http://lintrack.org. - ~001-debian-6.diff~: Already merged, no-op - only documenting in case anyone wonders about it. - ~002-better-rp_address.diff~: Support multicast group address in static Rendez-Vous Point .conf option. - ~003-ltfixes.diff~: Various bug fixes and error handling improvements. - ~004-disableall.diff~: Add -N option to pimd. - ~005-vifenable.diff~: Add enable keyword to phyint .conf option. - ~006-dot19.diff~: The lost alpha29.18 and alpha29.19 fixes by Pavlin Radoslavov. * Version 2.1.0, January 16, 2010 ** Changes & New Features - Integrated the latest Debian patches from ~pimd_2.1.0-alpha29.17-9.diff.gz~ - Fixed the new file include/linux/netinet/in-my.h (Debian) so that the #else fallback uses the system netinet/in.h, which seems to work now. - Bumped version number, this code has been available for a while now. * Version 2.1.0-alpha29.19: January 14, 2005 ** Bug Fixes - Don't ignore PIM Null Register messages if the IP version of the inner header is not valid. - Add a missing bracket inside rsrr.c (a bug report and a fix by ) * Version 2.1.0-alpha29.18: May 21, 2003 ** Changes & New Features - Compilation fix for Solaris 8. Though, no guarantee pimd still works on that platform. - Define ~BYTE_ORDER~ if missing. - Update include/netinet/pim.h file with its lastest version - Update the copyright message of ~include/netinet/pim_var.h~ * Version 2.1.0-alpha29.17: March 20, 2003 ** Changes & New Features - The mrouted license, LICENSE.mrouted, updated with BSD-like license!! Thanks to the OpenBSD folks for the 2 years of hard work to make this happen: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/mrouted/LICENSE - Moved the pimd contact email address upfront in README. Let me repeat that here: If you have any questions, suggestions, bug reports, etc., do NOT send them to the PIM IETF Working Group mailing list! Instead, use the contact email address specified in README. * Version 2.1.0-alpha29.16: February 18, 2003 ** Bug Fixes - Compilation bugfix for Linux. Bug report by Serdar Uezuemcue * Version 2.1.0-alpha29.15: February 12, 2003 ** Bug Fixes - Routing socket descriptor leak. Bug report and fix by SUZUKI Shinsuke ; incorporated back from pim6sd. - PIM join does not go upstream. Bug report and fix by SUZUKI Shinsuke ; incorporated back from pim6sd. #+BEGIN_EXAMPLE [problem] PIM join does not go upstream in the following topology, because oif-list is NULL after subtracting iif from oif-list. receiver---rtr1---| rtr2---|---rtr3----sender rtr1's nexthop to sender = rtr2 rtr2's nexthop to sender = rtr3 [reason] Owing to a difference between RFC2362 and the new pim-sm draft. [solution] Prunes iif from oiflist when installing it into kernel, instead of PIM route calculation time. #+END_EXAMPLE * Version 2.1.0-alpha29.14: February 10, 2003 ** Bug Fixes - Bugfix in calculating the netmask for POINTOPOINT interface in config.c. Bug report by J.W. (Bill) Atwood - ~rp.c:rp_grp_match()~: SERIOUS bugfix in calculating the RP per group when there are a number of group prefixes in the Cand-RP set. Bug report by Eva Pless * Version 2.1.0-alpha29.13: November 7, 2002 ** Bug Fixes - Bugfix in rp.c ~bootstrap_initial_delay()~ in calculating BSR election delay. Fix by SAKAI Hiroaki * Version 2.1.0-alpha29.12: September 26, 2002 ** Bug Fixes - Increase size of send buffers in the kernel. Bug report by Andrea Gambirasio * Version 2.1.0-alpha29.11: July 8, 2002 ** Bug Fixes Bug reports and fixes by SAKAI Hiroaki - ~init_routesock()~: Bugfix: initializing a forgotten variable. The particular code related to that variable is commented-out by default, but a bug is a bug. - ~main.c:restart()~: Bugfix: close the ~udp_socket~ only when it is is different from ~igmp_socket~. - ~main.c:main()~: if SIGHUP signal is received, reconstruct readers and nfds - Three serious bug fixes thanks to Jiahao Wang and Bo Cheng : - ~pim_proto.c:receive_pim_join_prune()~: two bugfixes related to the processing of (*,*,RP) - ~pim_proto.c:add_jp_entry()~: Bugfix regarding adding prune entries - Remove the FTP URL from the various README files, and replace it with an HTTP URL, because the FTP server on catarina.usc.edu is not operational anymore. * Version 2.1.0-alpha29.10: April 26, 2002 ** Bug Fixes - Widen the space for "Subnet" addresses printed under "Virtual Interface Table" - Added (commented-out code) to enable different interfaces to belong to overlapping subnets. See around line 200 in config.c - Bugfix in handling of Join/Prune messages when there is one join and one prune for the same group. Thanks to Xiaofeng Liu . * Version 2.1.0-alpha29.9: November 13, 2001 ** Changes & New Features First three entries contributed by Hiroyuki Komatsu - Print line number if there is conf file error. - If there is an error in the conf file, pimd won't start. - GRE configuration examples added to README.config. - New file README.debug (still very short though). ** Bug Fixes - Increase the config line buffer size to 1024. Bug fix by Hiroyuki Komatsu * Version 2.1.0-alpha29.8: September 16, 2001 ** Changes & New Features - Better log messages for point-to-point links in config.c. Thanks to Hitoshi Asaeda * Version 2.1.0-alpha29.7: September 10, 2001 ** Changes & New Features - Added "phyint altnet" (see pimd.conf for usage) for allowing some senders look like directly connected to a local subnet. Implemented by Marian Stagarescu - Added "phyint scoped" (see pimd.conf for usage) for administartively disabling the forwarding of multicast groups. Implemented by Marian Stagarescu - The License has changed from the original USC to the more familiar BSD-like (the KAME+OpenBSD guys brought to my attention that the original working in the USC license "...and without fee..." is ambiguous and makes it sound that noone can distribute pimd as part of some other software distribution and charge for that distribution. - RSRR disabled by default in Makefile ** Bug Fixes - Memory leaks bugs fixed in rp.c, thanks to Sri V - Compilation problems for RedHat-7.1 fixed. Bug report by Philip Ho - PID computation fixed (it should be recomputed after a child ~fork()~). Thanks to Marian Stagarescu - ~find_route()~-related bug fixes (always explicitly check for NULL return). Bug report by Marian Stagarescu - Bug fix re. adding a local member with older ciscos (in ~add_leaf()~). Bug report by Marian Stagarescu - Added explicit check whether ~BYTE_ORDER~ in pimd.h is defined. Bug report by * Version 2.1.0-alpha29.6: May 4, 2001 ** Bug Fixes - Bug fixes in processing Join/Prune messages. Thanks to Sri V * Version 2.1.0-alpha29.5: February 22, 2001 ** Changes & New Features - ~VIFM_FORWARDER()~ macro renamed to ~VIFM_LASTHOP_ROUTER~. - Mini-FAQ entries added to README. ** Bug Fixes - When there is a new member, ~add_leaf()~ is called by IGMP code for any router, not only for a DR. The reason is because not only the DR must know about local members, but the last-hop router as well (so eventually it will initiate a SPT switch). Similar fixes to ~add_leaf()~ inside route.c as well. Problem reported by Hitoshi Asaeda . XXX: Note the lenghty comment in the beginning of ~add_leaf()~ about a pimd desing problem that may result in SPT switch not initiated immediately by the last-hop router. - DR entry timer bug fix in timer.c: When (*,G)'s iif and (S,G)'s iif are not same, (S,G)'s timer for the DR doesn't increase. Reported indirectly by * Version 2.1.0-alpha29.4: December 1, 2000 ** Changes & New Features - README cleanup + Mini-FAQ added - ~igmp_proto.c~: printf argument cleanup (courtesy KAME) - ~main.c:restart()~: forgotten printf argument added (courtesy KAME) ** Bug Fixes - ~kern.c:k_stop_pim()~: Fix the ordering of ~MRT_PIM~ and ~MRT_DONE~, thanks to Hitoshi Asaeda . - ~route.c:add_leaf()~: mrtentry creation logic bug fix. If the router is not a DR, a mrtentry is never created. Tanks to Hitoshi Asaeda & (indirectly) - ~pim_proto.c~: Two critical bug fixes. J/P prune suppression related message and J/P message with (*,*,RP) entry inside. Thanks to Azzurra Pantella and Nicola Dicosmo from University of Pisa - ~pim_proto.c:receive_pim_bootstrap()~: BSR-related fix from Kame's pim6sd. Even when the BSR changes, just schedule an immediate advertisemnet of C-RP-ADV, instead of sending message, in order to avoid sending the advertisement to the old BSR. In response to comment from * Version 2.1.0-alpha29.3: October 13, 2000 ** Bug Fixes - ~ADVANCE()~ bug fix in routesock.c (if your system doesn't have ~SA_LEN~) thanks to Eric S. Johnson * Version 2.1.0-alpha29.2: October 13, 2000 NB: THIS pimd VERSION WON'T WORK WITH OLDER PIM-SM KERNEL PATCHES (kernel patches released prior to this version)! ** Changes & New Features - The daemon that the kernel will prepare completely the inner multicast packet for PIM register messages that the kernel is supposed to encapsulate and send to the RP. - Now pimd compiles on OpenBSD-2.7. PIM control messages exchange test passed. Ddon't have the infrastructure to perform more complete testing. - ~main.c:cleanup()~: Send ~PIM_HELLO~ with holdtime of '0' if pimd is going away, thanks to JINMEI Tatuya - =include/netinet/pim.h= updated - pimd code adapted to the new =struct pim= definition. - Added ~PIM_OLD_KERNEL~ and ~BROKEN_CISCO_CHECKSUM~ entries in the Makefile. - Don't ignore kernel signals if any of src or dst are NULL. - Don't touch ~ip_id~ on a PIM register message - README cleanup: kernel patches location, obsoleted systems clarification, etc. - ~k_stop_pim()~ added to ~cleanup()~ in ~main.c~ (courtesy Kame) ** Bug Fixes - ~RANDOM()~-related bug fix re. ~jp_value~ calculation in ~pim_proto.c~, thanks to JINMEI Tatuya - ~realloc()~ related memory leak bug in ~config_vifs_from_kernel()~ in config.c courtesy Kame's pim6sd code. - Solaris-8 fixes thanks to Eric S. Johnson - ~BROKEN_CISCO_CHECKSUM~ bug fix thanks to Eric S. Johnson and Hitoshi Asaeda. - ~main.c~: 1000000 usec -> 1 sec 0 usec. Fix courtesy of the Kame project - ~main.c:restart()~ fixup courtesy of the Kame project - various min. message length check for the received control messages courtesy of the Kame project. XXX: the pimd check is not enough! - VIF name string comparison fix in ~routesock.c:getmsg()~ courtesy of the Kame project - missing brackets added inside ~age_routes()~ (a bug that will show up only if ~KERNEL_MFC_WC_G~ was defined); courtesy of the Kame project * Version 2.1.0-alpha28: March 15, 2000 ** Changes & New Features - added #ifdef ~BROKEN_CISCO_CHECKSUM~ (disabled by default) to make cisco RPs happy (read the comments in pim.c) - added #ifdef ~PIM_TYPEVERS_DECL~ in netinet/pim.h as a workaround that ANSI-C doesn't guarantee that bit-fields are tightly packed together (although all modern C compilers should not create a problem). ** Bug Fixes - Fixes to enable point-to-point interfaces being added correctly, thanks to Roger Venning - A number of minor bug fixes * Version 2.1.0-alpha27: January 21, 2000 NB: this release may the the last one from 2.1.0. The next release will be 2.2.0 and there will be lots of changes inside. ** Bug Fixes - Bug fix in ~rp.c:add_grp_mask()~ and ~rp.c:delete_grp_mask()~: in some cases if the RPs are configured with nested multicast prefixes, the add/delete may fail. Thanks to Hitoshi Asaeda and the KAME team for pointing out this one. * Version 2.1.0-alpha26: October 28, 1999 ** Bug Fixes - Bug fix in ~receive_pim_register()~ in ~pim_proto.c:ntohl()~ was missing inside ~IN_MULTICAST()~. Thanks to Fred Griffoul - Bug report and fix by Hitoshi Asaeda in ~pim_proto.c:receive_pim_cand_rp_adv()~ (if a router is not a BSR). Another bug in ~rp.c:delete_grp_mask_entry()~: an entry not in the head of the list was not deleted propertly. - Some ~VIFF_TUNNEL~ checks added or deleted in various places. Slowly preparing pimd to be able to work with GRE tunnels... * Version 2.1.0-alpha25: August 30, 1999 Bug reports and fixes by Hitoshi Asaeda inside ~parse_reg_threshold()~ and ~parse_data_threshold()~ in config.c ** Changes & New Features - Successfully added multicast prefixes configured in pimd.conf are displayed at startup - Use =include/freebsd= as FreeBSD-3.x include files and =include/freebsd2= for FreeBSD-2.x. ** Bug Fixes - Test is performed whether a ~PIM_REGISTER~ has invalid source and/or group address of the internal packet. * Version 2.1.0-alpha24: August 9, 1999 ** Changes & New Features - ~PIM_DEFAULT_CAND_RP_ADV_PERIOD~ definition set to 60, but default 'time' value for inter Cand-RP messages is set in pimd.conf to 30 sec. - ~PIM_REGISTER~ checksum verification in ~receive_pim_register()~ relaxed for compatibility with some older routers. The checksum has to be computed only over the first 8 bytes of the PIM Register (i.e. only over the header), but some older routers might compute it over the whole packet. Hence, the checksum verification is over the first 8 bytes first, and if if it fails, then over the whole packet. Thus, pimd that is RP should still work with older routers that act as DR, but if an older router is the RP, then pimd cannot be the DR. Sorry, don't know which particular routers and models create the checksum over the whole PIM Register (if there are still any left). * Version 2.1.0-alpha23: May 24, 1999 ** Changes & New Features - Finally pimd works under Linux (probably 2.1.126, 2.2.x and 2.3.x). However, a small fix in the kernel ~linux/net/ipv4/ipmr.c~ is necessary. In function ~pim_rcv()~, remove the call to ~ip_compute_csum()~: #+BEGIN_SRC c --- linux/net/ipv4/ipmr.c.org Thu Mar 25 09:23:34 1999 +++ linux/net/ipv4/ipmr.c Mon May 24 15:42:45 1999 @@ -1342,8 +1342,7 @@ if (len < sizeof(*pim) + sizeof(*encap) || pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || - reg_dev == NULL || - ip_compute_csum((void *)pim, len)) { + reg_dev == NULL) { kfree_skb(skb); return -EINVAL; } #+END_SRC - in pimd.conf "phyint" can be specified not only by IP address, but by name too (e.g. "phyint de1 disable") - in pimd.conf 'preference' and 'metric' can be specified per "phyint" Note that these 'preference' and 'metric' are like per iif. - ~MRT_PIM~ used (again) instead of ~MRT_ASSERT~ in kern.c. The problem is that Linux has both ~MRT_ASSERT~ and ~MRT_PIM~, while *BSD has only ~MRT_ASSERT~. #+BEGIN_SRC c #ifndef MRT_PIM #define MRT_PIM MRT_ASSERT #endif #+END_SRC - Rely on ~__bsdi__~, which is defined by the OS, instead of -DBSDI in Makefile, change by Hitoshi Asaeda. Similarly, use ~__FreeBSD__~ instead of -DFreeBSD - Linux patches by Fred Griffoul including a ~netlink.c~ instead of ~routesock.c~ - ~vif.c:zero_vif()~: New function ** Bug Fixes All bug reports thanks to Kaifu Wu - Linux-related bug fixes regarding raw IP packets byte ordering - Join/Prune message bug fixed if the message contains several groups joined/pruned * Version 2.1.0-alpha22: November 11, 1998 Bug reports by Jonathan Day ** Bug Fixes - Bug fixes to compile under newer Linux kernel (linux-2.1.127) To compile for older kernels ( ver < ???), add ~-Dold_Linux~ to the Makefile - For convenience, the ~include/linux/netinet/{in.h,mroute.h}~ files are added, with few modifications applied. * Version 2.1.0-alpha21: November 4, 1998 ** Bug Fixes - ~pim_proto.c:join_or_prune()~: Bug fixes in case of (S,G) overlapping with (*,G). Bug report by Dirk Ooms - ~route.c:change_interfaces()~: Join/Prune (*,G), (*,*,RP) fire timer optimization/fix. * Version 2.1.0-alpha20: August 26, 1998 ** Changes & New Features - (Almost) all timers manipulation now use macros - ~pim.h~ and ~pim_var.h~ are in separate common directory - Added BSDI definition to ~pim_var.h~, thanks to Hitoshi Asaeda. ** Bug Fixes - fix TIMEOUT definitions in difs.h (bug report by Nidhi Bhaskar) (originally, if timer value less than 5 seconds, it won't become 0) It is HIGHLY recommended to apply that fix, so here it is: #+BEGIN_SRC c -------------BEGIN BUG FIX------------------- 1) Add the following lines to defs.h (after #define FALSE): #ifndef MAX #define MAX(a,b) (((a) >= (b))? (a) : (b)) #define MIN(a,b) (((a) <= (b))? (a) : (b)) #endif /* MAX & MIN */ 2) Change the listed below TIMEOUT macros to: #define IF_TIMEOUT(timer) \ if (!((timer) -= (MIN(timer, TIMER_INTERVAL)))) #define IF_NOT_TIMEOUT(timer) \ if ((timer) -= (MIN(timer, TIMER_INTERVAL))) #define TIMEOUT(timer) \ (!((timer) -= (MIN(timer, TIMER_INTERVAL)))) #define NOT_TIMEOUT(timer) \ ((timer) -= (MIN(timer, TIMER_INTERVAL))) ---------------END BUG FIX------- #+END_SRC * Version 2.1.0-alpha19: July 29, 1998 Both bug reports by Chirayu Shah - ** Bug Fixes - bug fix in ~find_route()~ when searching for (*,*,RP) - bug fix in ~move_kernel_cache()~: no need to do ~move_kernel_cache()~ from (*,*,R) to (*,G) first when we call ~move_kernel_cache()~ for (S,G) * Version 2.1.0-alpha18: May 29, 1998 ** Changes & New Features - Now compiles under Linux (haven't checked whether the PIMv2 kernel support in linux-2.1.103 works) ** Bug Fixes - ~parse_default_source*()~ bug fix (bug reports by Nidhi Bhaskar) - allpimrouters deleted from igmp.c (already defined in pim.c) - igmpmsg defined for IRIX * Version 2.1.0-alpha17: May 21, 1998 ** Changes & New Features - (*,G) MFC kernel support completed and verified. Compile with ~KERNEL_MFC_WC_G~ defined in Makefile, but then must use it only with a kernel that supports (*,G), e.g. =pimkern-PATCH_7=. Currently, kernel patches available for FreeBSD and SunOS only. ** Bug Fixes - ~MRTF_MFC_CLONE_SG~ flag set after ~delete_single_kernel_cache()~ is called * Version 2.1.0-alpha16: May 19, 1998 ** Changes & New Features - PIM registers kernel encapsulation support. Build with ~PIM_REG_KERNEL_ENCAP~ defined in Makefile. - (*,G) MFC support. Build with ~KERNEL_MFC_WC_G~ defined in Makefile. However, ~MFC_WC_G~ is still not supported with ~pimkern-PATCH_6~, must disable it for now. - ~mrt.c:delete_single_kernel_cache_addr()~: New function, uses source, group to specify an MFC to be deleted * Version 2.1.0-alpha15: May 14, 1998 - Another few bug fixes related to NetBSD definitions thanks to Heiko W.Rupp * Version 2.1.0-alpha14: May 12, 1998 - A few bug fixes related to NetBSD definitions thanks to Heiko W.Rupp * Version 2.1.0-alpha13: May 11, 1998 ** Changes & New Features - If the RP changes, the necessary actions are taken to pass the new RP address to the kernel. To be used for kernel register encap. support. Wnat needs to be done is: (a) add =rp_addr= entry to the mfcctl structure, and then just set it in ~kern.c:k_chf_mfc()~. Obviously, the kernel needs to support the register encapsulation (instead of sending WHOLEPKT to the user level). In the near few days will make the necessary kernel changes. - ~change_interfaces()~: Added "flags" argument. The only valid flag is ~MFC_UPDATE_FORCE~, used for forcing kernel call when only the RP changes. - ~k_chg_mfc()~ has a new argument: rp_addr. To be used for kernel register encapsulation support - ~MRT_PIM~ completely replaced by ~MRT_ASSERT~ - ~move_kernel_cache()~: Argument ~MFC_MOVE_FORCE~ is a flag instead of TRUE/FALSE - ~process_cache_miss()~: removed unneeded piece of code * Version 2.1.0-alpha12: May 10, 1998 ** Changes & New Features - Use the cleaned up ~netinet/pim.h~ - Remove the no needed anymore pim header definition in ~pimd.h~ - Don't use ~MRT_PIM~ in in kern.c anymore, replaced back with ~MRT_ASSERT~. - ~added default_source_metric~ and ~default_source_preference~ (1024) because the kernel's unicast routing table is not a good source of info; configurable in pimd.conf - Can now compile under NetBSD-1.3, thanks to Heiko W.Rupp ** Bug Fixes - Incorrect setup of the borderBit and nullRegisterBit (different for big and little endian machines) fixed; ~*_BORDER_BIT~ and ~*NULL_REGISTER_BIT~ redefined - don't send ~pim_assert~ on tunnels or register vifs (if for whatever reason we receive on such interface) - ignore ~WRONGVIF~ messages for register and tunnel vifs (the cleaned up kernel mods dont send such signal, but the older (before May 9 '98) pimd mods that signaling was enabled * Version 2.1.0-alpha11: March 16, 1998 ** Changes & New Features - ~vif.c:find_vif_direct_local()~: New function, used in ~routesock.c~, ~igmp_proto.c~ - Use ~MFC_MOVE_FORCE/MFC_MOVE_DONT_FORCE~ flag in ~mrt.c~, ~route.c~, ~pim_proto.c~, when need to move the kernel cache entries between (*,*,RP), (*,G), (S,G) - new timer related macros: ~SET_TIMER()~, ~FIRE_TIMER()~, ~IF_TIMER_SET()~, ~IF_TIMER_NOT_SET()~ ** Bug Fixes - ~timer.c:age_routes()~: bunch of fixes regarding J/P message fragmentation - ~route.c:process_wrong_iif()~: (S,G) SPT switch bug fix: ANDed =MRTF_RP= fixed to =~MRTF_RP= - ~pim_proto.c~ & ~timer.c~: (S,G) Prune now is sent toward RP, when iif toward S and iif toward RP are different - ~pim_proto.c:join_or_prune()~ bug fixes - ~pim_proto.c~: (S,G)Prune entry's timer now set to J/P message holdtime - ~pim_proto.c:receive_pim_join_prune()~: Ensure pruned interfaces are correctly reestablished - ~timer.c:age_routes()~: now (S,G) entry with local members (inherited from (*,G)) is timeout propertly - ~timer.c:age_routes()~: (S,G) J/P timer restarted propertly - ~timer.c:age_routes()~: check also the (S,G)RPbit entries in the forwarders and RP and eventually switch to the shortest path if data rate too high - ~route.c:process_wrong_vif()~ fire J/P timer - ~route.c:switch_shortest_path()~: reset the iif toward S if there is already (S,G)RPbit entry * Version 2.1.0-alpha10: March 3, 1998 Temp. non-public release. ** Changes & New Features - `interval` can be applied for data rate check. The statement in ~pimd.conf~ that only the default value will be used is not true anymore. - The RP-initiated and the forwarder-initiated (S,G) switch threshold rate can be different. - ~pim_proto.c:receive_pim_register()~: check if I am the RP for that group, and if "no", send ~PIM_REGISTER_STOP~ (XXX: not in the spec, but should be!) - ~pim_proto.c:receive_pim_register_stop()~: check if the ~PIM_REGISTER_STOP~ originator is really the RP, before suppressing the sending of the PIM registers. (XXX: not in the spec but should be there) - ~rp.c:check_mrtentry_rp()~: new function added to check whether the RP address is the corresponding one for the given mrtentry - ~debug.c:dump_mrt()~ timer values added - ~route.c~: ~add_leaf()~, ~process_cache_miss()~, ~process_wrong_iif()~ no routing entries created for the LAN scoped addresses - ~DEBUG_DVMRP_DETAIL~ and ~DEBUG_PIM_DETAIL~ added ** Bug Fixes - ~mrt.c:add_kernel_cache()~: no kernel cache duplicates - ~mrt.c:move_kernel_cache()~: if the iif of the (*,*,R) (or (*,G)) and (S,G) are different, dont move the cache entry "UP" - ~timer.c:age_routes()~: (S,G) ~add_jp_entry()~ flag fixed, SPT switch related. - ~kern.c:k_get_sg_cnt()~: modified to compensate for the kernel's return code bug for getting (S,G) byte count (~SIOCGETSGCNT~) - ~pim_proto.c:receive_pim_register()~: if the (S,G) oif is NULL, now checks whether the iif is ~register_vif~ * Version 2.1.0-alpha9: February 18, 1997 ** Changes & New Features - "non-commersial" statement deleted from the copyright message - mrinfo support added - mtrace support added (not completed and not enough tested) - if invalid local address for =cand_rp= or =cand_bootstrap_router= in =pimd.conf=, automatically will use the largest local multicast enabled address - "include" directory for FreeBSD and SunOS added, so now pimd can be compiled without having the necesary "include" files added to your system. Probably a bad idea and may remove it later. - some default values for the IP headers of the IGMP and PIM packets are fixed - ~VIFF_PIM_NBR~ and ~VIFF_DVMRP_NBR~ flags added - ~VIFF_REGISTER~ now included in the RSRR vifs report - ~find_route()~ debug messages removed - #ifdef for ~HAVE_SA_LEN~ corrected - ~debug.c~: small fixes * Version 2.1.0-alpha8: November 23, 1997 ** Bug Fixes - BSDI related bug fix in defs.h - small changes in Makefile * Version 2.1.0-alpha7: November 23, 1997 ** Changes & New Features - RSRR support for (*,G) completed - BSDI 3.0/3.1 support by Hitoshi Asaeda (the kernel patches will be available soon) - Improved debug messages format (thanks to Hitoshi Asaeda) - A new function ~netname()~ for network IP address print instead of ~inet_fmts()~, thanks to Hitoshi Asaeda. - ~pimd.conf~: format changed * Version 2.1.0-alpha6: November 20, 1997 ** Bug Fixes - Remove the inherited leaves from (S,G) when a receiver drops membership - some parameters when calling ~change_interface()~ fixed - use ~send_pim_null_register~ + take the appropriate action when the register suppression timer expires - bug fix related to choosing the largest local IP address for little endian machines. * Version 2.1.0-alpha5 ** Bug Fixes - ~main.c:main()~: startup message fix - ~timer.c:age_routes()~: bug fix in debug code * Version 2.1.0-alpha4: October 31, 1997 ** Changes & New Features - Minor changes, so pimd now compiles for SunOS 4.1.3 (cc, gcc) ** Bug Fixes - ~pim_proto.csend_periodic_pim_join_prune()~: bug fix thanks to SunOS cc warning(!), only affects the (*,*,RP) stuff. - ~pimd.conf~: two errors, related to the rate limit fixed * Version 2.1.0-alpha3: October 13, 1997 ** Changes & New Features - ~Makefile~: cleanup - ~defs.h~: cleanup - ~routesock.c~: cleanup ** Bug Fixes - ~igmp_proto.c:accept_group_report()~: bug fixes - ~pim_proto.c:receive_pim_hello()~: bug fixes - ~route.c:change_interfaces()~: bug fixes - ~rp.c~: bug fixes in ~init_rp_and_bsr()~, ~add_cand_rp()~, and ~create_pim_bootstrap_message()~ * Version 2.1.0-alpha2: September 23, 1997 ** Changes & New Features - ~Makefile~: "make diff" code added - ~debug.c~: debug output slightly changed ** Bug Fixes - ~defs.h:*TIMEOUT()~: definitions fixed - ~route.c~: bugs fixed in ~change_interface()~ and ~switch_shortest_path()~ - ~timer.c:age_routes()~: number of bugs fixed * Version 2.1.0-alpha1: August 26, 1997 ** Changes & New Features First alpha version of the "new, up to date" pimd. RSRR support + Solaris support added. Many functions rewritten and/or modified. # Local Variables: # mode: org # End: pimd-2.1.8/debian/0000755000000000000000000000000011700261371010561 5ustar pimd-2.1.8/debian/changelog0000644000000000000000000001272011700261371012435 0ustar pimd (2.1.8-2) unstable; urgency=low * use dpkg-buildflags for build flags (CFLAGS, LDFLAGS, CPPFLAGS), patch from Moritz Muehlenh (Closes: Bug#654081) -- Antonin Kral Mon, 02 Jan 2012 08:52:37 +0100 pimd (2.1.8-1) unstable; urgency=low * New upstream * merges fixes addressing existence of several unused variables and handling of CFLAGS, Closes: Bug#634393 -- Antonin Kral Mon, 24 Oct 2011 08:41:57 +0200 pimd (2.1.7-1) unstable; urgency=low * New upstream -- Antonin Kral Mon, 05 Sep 2011 11:54:53 +0200 pimd (2.1.6-1) unstable; urgency=low * New upstream version changing location of dump file(s) to /var/lib/misc, CVE-2011-0007, Closes: Bug#609304 -- Antonin Kral Sat, 08 Jan 2011 23:54:41 +0100 pimd (2.1.5-4) unstable; urgency=low * Added oknodo to s-s-d in init.d script for stop action Closes: Bug#609116 -- Antonin Kral Sat, 08 Jan 2011 17:56:48 +0100 pimd (2.1.5-3) unstable; urgency=low * fix for regression of unused parameter on *bsd, Closes: Bug#608711 (commit 6eaff4dc495ff67933a4) * add -Werror to debian/rules -- Antonin Kral Mon, 03 Jan 2011 09:22:25 +0100 pimd (2.1.5-2) unstable; urgency=low * make package a conflict to smcroute https://bugs.launchpad.net/ubuntu/+source/pimd/+bug/362274 -- Antonin Kral Fri, 10 Dec 2010 13:26:10 +0100 pimd (2.1.5-1) unstable; urgency=low * New upstream release. * Fix pimd exiting with "setsockopt MRT_DEL_VIF on vif 3: Invalid argument" when an interface goes down. Caused by invalid argument to MRT_DEL_VIF on Linux kernels. *BSD systems not affected. -- Antonin Kral Sun, 21 Nov 2010 09:53:57 +0100 pimd (2.1.4-1) unstable; urgency=low * New upstream release * A serious bcopy()/memcpy() replacement bug in 2.1.3 was fixed. * More updates were made for Debian GNU/kFreeBSD. -- Antonin Kral Sat, 25 Sep 2010 19:26:34 +0200 pimd (2.1.3-1) unstable; urgency=low * New upstream release (Closes: #596117) -- Antonin Kral Fri, 10 Sep 2010 13:51:47 +0200 pimd (2.1.2-2) unstable; urgency=low * Patch from Joachim to fix FTBFS issue (Closes: #595584) -- Antonin Kral Sun, 05 Sep 2010 21:06:41 +0200 pimd (2.1.2-1) unstable; urgency=low * New upstream release * updated to the latest Debian policies * lintian cleanup -- Antonin Kral Sun, 05 Sep 2010 07:56:40 +0200 pimd (2.1.1-2) unstable; urgency=low * Update rules file with new section for pimd man page. Moved to section 8 from 1. -- Joachim Nilsson Thu, 27 May 2010 00:19:31 +0100 pimd (2.1.1-1) unstable; urgency=low * New upstream maintainer - Joachim Nilsson * Package built to follow upstream, Closes: #565716 * updated to the latest Debian policies * added lintian override for empty-debian-diff as debian dir is maintained along the upstream sources -- Antonin Kral Mon, 18 Jan 2010 18:38:39 +0100 pimd (2.1.0-alpha29.17-9) unstable; urgency=low * fixed rp_address handling on big endian machines, many thanks to Alexander Clouter for providing patch (Closes: #503116) * fixed Lintian warning debian-rules-ignores-make-clean-error * fixed Lintian warning package-uses-deprecated-debhelper-compat-version -- Antonin Kral Sun, 08 Feb 2009 15:26:23 +0100 pimd (2.1.0-alpha29.17-8.1) unstable; urgency=low * Non-maintainer upload. * Added LSB formatted dependency info in init.d script (closes: #469226) -- Peter Eisentraut Thu, 03 Apr 2008 14:15:02 +0200 pimd (2.1.0-alpha29.17-8) unstable; urgency=low * explicit removal of removed include/linux/netinet/in.h removed include/linux/netinet/in-slackware.h thanks Julien, Closes: #423516, #422591 -- Antonin Kral Mon, 06 Aug 2007 02:04:31 +0000 pimd (2.1.0-alpha29.17-7) unstable; urgency=high * included patch from Prasanna Krishnamoorthy, Closes #422591 removed include/linux/netinet/in.h removed include/linux/netinet/in-slackware.h goal is to fix missing reference to ntohl() * init script works with newer kernels, Closes #231677 -- Antonin Kral Mon, 07 May 2007 19:14:32 +0000 pimd (2.1.0-alpha29.17-6) unstable; urgency=low * #287318 is not a bug since previsou release, closes #287318 * rules correction, closes #268475 * int pid removed from defs.h, closes #287915 -- Antonin Kral Fri, 28 Jan 2005 11:11:18 +0100 pimd (2.1.0-alpha29.17-5) unstable; urgency=low * /etc/pimd.conf added to conffiles, closes #287318 -- Antonin Kral Thu, 6 Jan 2005 23:18:36 +0100 pimd (2.1.0-alpha29.17-4) unstable; urgency=low * Addapted patch for staticRP support by Peter Mann, please refer to README.Debian -- Antonin Kral Tue, 10 Aug 2004 10:53:15 +0200 pimd (2.1.0-alpha29.17-3) unstable; urgency=low * Changed description, kernel patch is not longer needed -- Antonin Kral Sat, 31 May 2003 08:48:11 +0200 pimd (2.1.0-alpha29.17-2) unstable; urgency=low * Changed path of pid file -- Antonin Kral Mon, 7 Apr 2003 19:50:09 +0200 pimd (2.1.0-alpha29.17-1) unstable; urgency=low * Initial Release, closes #186454 -- Antonin Kral Thu, 27 Mar 2003 10:12:47 +0100 pimd-2.1.8/debian/addons/0000755000000000000000000000000011700261371012031 5ustar pimd-2.1.8/debian/addons/pimd.conf0000644000000000000000000001014211700261371013627 0ustar # This is the configuration file for "pimd", an IP multicast router. # pimd looks for it in "/etc/pimd.conf". # # $Id: pimd.conf,v 1.17 2001/09/10 20:31:37 pavlin Exp $ # # Command formats: ########## # default_source_preference # default_source_metric # # phyint [disable] [threshold ] [preference

] [metric ] [altnet masklen ] [scoped masklen ] # # cand_rp [] [priority ] [time ] # cand_bootstrap_router [] [priority ] # # group_prefix [masklen ] # group_prefix [masklen ] # . # . # group_prefix [masklen ] # # # switch_data_threshold [rate interval ] # # switch_register_threshold [rate interval ] ########## # By default PIM will be activated on all interfaces. Use phyint to # disable on interfaces where PIM should not be run. # # Preferences are used by assert elections to determine upstream routers. # Currently pimd cannot reliably obtain preferences and metrics from the # unicast routing protocols, so a default preference may be configured. # In an assert election, the router advertising the lowest assert preference # will be selected as the forwarder and upstream router for the LAN. # 101 should be sufficiently high so that asserts from Cisco or GateD # routers are prefered over poor-little pimd. # # It is reccommended that preferences be set such that metrics are never # consulted. However, default metrics may also be set and will default to # 1024. # # # A "phyint" can be specified by either its IP address or interface name. # # `preference` and `metric` after "phyint" are used to configure manually # the default preference and metric for the Assert messages sent on that # interface. Usually you don't need this, but if you do, think of them # like `preference` and `metric` defined per iif, but used by the # Asserts on the oifs. # # If you want to add "alternative (sub)net" to a physical interface, # e.g., if you want to make incoming traffic with a non-local source address # to appear as it is coming from a local subnet, then use the command: # phyint altnet masklen # XXX: if you use this command, make sure you know what you are doing!! # # If you want administrative scoped multicast filtering, use the # following command: # phyint scoped masklen # This allows interfaces to be configured as an administrative boundary # for the specified scoped address. Packets belonging to the scoped # address will not be forwarded. To use this compile with -DSCOPED_ACL # option (in Makefile). # # `local-addr` after "cand_rp" and "cand_bootstrap_router" specifies # the local address to be used in the Cand-RP and Cand-BSR messages. # If not specified, the largest local IP address will be used (excluding # the disabled interfaces) # # `time` after `cand_rp` specifies how often to send the Cand-RP messages. # Its default value should be 60 seconds. Use smaller value for faster # convergence. # # `group_prefix` is/are the prefix(es) advertised if cand_rp # # `rate` specifies the minimum rate in bits/s before the last hop # router or the RP switch to the shortest path (`switch_data_threshold` # and `switch_register_threshold` respectively) # `interval` specifies the interval for periodical testing of the rate # Currently, `interval` must be at least 5 (seconds) # XXX: Both intervals should be the same # # #default_source_preference 101 # smaller is better #default_source_metric 1024 # smaller is better #phyint de1 disable # phyint MUST BE AFTER default_source_* # BUT MUST BE BEFORE everything else cand_rp time 30 priority 20 # Smaller value means "higher" priority cand_bootstrap_router priority 5 # Bigger value means "higher" priority group_prefix 224.0.0.0 masklen 4 # All multicast groups # switch_data_threshold rate 50000 interval 20 # 50kbps (approx.) switch_register_threshold rate 50000 interval 20 # 50kbps (approx.) pimd-2.1.8/debian/source/0000755000000000000000000000000011700261371012061 5ustar pimd-2.1.8/debian/source/lintian-overrides0000644000000000000000000000011511700261371015437 0ustar pimd source: empty-debian-diff pimd source: native-package-with-dash-version pimd-2.1.8/debian/source/format0000644000000000000000000000001511700261371013270 0ustar 3.0 (native) pimd-2.1.8/debian/copyright0000644000000000000000000001025111700261371012513 0ustar This package was debianized by Antonin Kral on Thu, 27 Mar 2003 10:12:47 +0100. It was originally downloaded from http://netweb.usc.edu/pim/pimd/ The current versions are hosted at GitHub: http://github.com/troglobit/pimd Current Upstream Maintainers and Authors: * Joachim Nilsson Original Upstream Authors: * Ahmed Helmy * Rusty Eddy * Pavlin Radoslavov Copyright: /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: LICENSE,v 1.5 2001/09/10 20:31:36 pavlin Exp $ */ /* * 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. * */ Additionally, pimd uses some code from mrouted. Mrouted Copyright statement (from file 'LICENSE.mrouted') follows: Copyright (c) 2002 The Board of Trustees of the Leland Stanford Junior University Permission is hereby granted to STANFORD's rights, free of charge, to any person obtaining a copy of this Software and associated documentation files ( "MROUTED"), to deal in MROUTED without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of MROUTED , and to permit persons to whom MROUTED is furnished to do so, subject to the following conditions: 1) The above copyright notice and this permission notice shall be included in all copies or substantial portions of the MROUTED . 2) Neither the STANFORD name nor the names of its contributors may be used in any promotional advertising or other promotional materials to be disseminated to the public or any portion thereof nor to use the name of any STANFORD faculty member, employee, or student, or any trademark, service mark, trade name, or symbol of STANFORD or Stanford Hospitals and Clinics, nor any that is associated with any of them, without STANFORD's prior written consent. Any use of STANFORD's name shall be limited to statements of fact and shall not imply endorsement of any products or services. 3) MROUTED IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH MROUTED OR THE USE OR OTHER DEALINGS IN THE MROUTED . pimd-2.1.8/debian/compat0000644000000000000000000000000211700261371011757 0ustar 7 pimd-2.1.8/debian/README.Debian0000644000000000000000000000233311700261371012623 0ustar pimd for Debian --------------- You need to enable multicast and multicast-routing in your kernel: CONFIG_IP_MULTICAST=y CONFIG_IP_MROUTE=y you have also enable support for PIM-SM v2 in kernel: CONFIG_IP_PIMSM_V2=y If you want to build a multicast tunnel via an unicast connection, you have to enable ip-tunneling to: CONFIG_NET_IPIP=m (or =y) The default configuration of pimd is to route between two and more interfaces, and start AutoRP. For more details see the manpage and program documentation. Support for staticRP is available since pimd_2.1.0-alpha29.17-4. Patch provided by Peter Mann . There is new configuratation parameter: rp_address The future of pimd ------------------ pimd was abandoned since 2005 but resurrected by Joachim Nilsson at the beginning of the 2010. Sources are now hosted at http://github.com/troglobit/pimd Other implementations of PIM ---------------------------- http://netweb.usc.edu/pim/ has a list. And http://www.xorp.org/ looks promising. -- Antonin Kral , Thu, 27 Mar 2003 10:12:47 +0100 -- Antonin Kral , Tue, 10 Aug 2004 10:51:12 +0100 -- Antonin Kral , Mon, 18 Jan 2010 22:28:01 +0100 pimd-2.1.8/debian/docs0000644000000000000000000000006311700261371011433 0ustar README README.config README.config.jp README.debug pimd-2.1.8/debian/pimd.conf0000644000000000000000000001014211700261371012357 0ustar # This is the configuration file for "pimd", an IP multicast router. # pimd looks for it in "/etc/pimd.conf". # # $Id: pimd.conf,v 1.17 2001/09/10 20:31:37 pavlin Exp $ # # Command formats: ########## # default_source_preference # default_source_metric # # phyint [disable] [threshold ] [preference

] [metric ] [altnet masklen ] [scoped masklen ] # # cand_rp [] [priority ] [time ] # cand_bootstrap_router [] [priority ] # # group_prefix [masklen ] # group_prefix [masklen ] # . # . # group_prefix [masklen ] # # # switch_data_threshold [rate interval ] # # switch_register_threshold [rate interval ] ########## # By default PIM will be activated on all interfaces. Use phyint to # disable on interfaces where PIM should not be run. # # Preferences are used by assert elections to determine upstream routers. # Currently pimd cannot reliably obtain preferences and metrics from the # unicast routing protocols, so a default preference may be configured. # In an assert election, the router advertising the lowest assert preference # will be selected as the forwarder and upstream router for the LAN. # 101 should be sufficiently high so that asserts from Cisco or GateD # routers are prefered over poor-little pimd. # # It is reccommended that preferences be set such that metrics are never # consulted. However, default metrics may also be set and will default to # 1024. # # # A "phyint" can be specified by either its IP address or interface name. # # `preference` and `metric` after "phyint" are used to configure manually # the default preference and metric for the Assert messages sent on that # interface. Usually you don't need this, but if you do, think of them # like `preference` and `metric` defined per iif, but used by the # Asserts on the oifs. # # If you want to add "alternative (sub)net" to a physical interface, # e.g., if you want to make incoming traffic with a non-local source address # to appear as it is coming from a local subnet, then use the command: # phyint altnet masklen # XXX: if you use this command, make sure you know what you are doing!! # # If you want administrative scoped multicast filtering, use the # following command: # phyint scoped masklen # This allows interfaces to be configured as an administrative boundary # for the specified scoped address. Packets belonging to the scoped # address will not be forwarded. To use this compile with -DSCOPED_ACL # option (in Makefile). # # `local-addr` after "cand_rp" and "cand_bootstrap_router" specifies # the local address to be used in the Cand-RP and Cand-BSR messages. # If not specified, the largest local IP address will be used (excluding # the disabled interfaces) # # `time` after `cand_rp` specifies how often to send the Cand-RP messages. # Its default value should be 60 seconds. Use smaller value for faster # convergence. # # `group_prefix` is/are the prefix(es) advertised if cand_rp # # `rate` specifies the minimum rate in bits/s before the last hop # router or the RP switch to the shortest path (`switch_data_threshold` # and `switch_register_threshold` respectively) # `interval` specifies the interval for periodical testing of the rate # Currently, `interval` must be at least 5 (seconds) # XXX: Both intervals should be the same # # #default_source_preference 101 # smaller is better #default_source_metric 1024 # smaller is better #phyint de1 disable # phyint MUST BE AFTER default_source_* # BUT MUST BE BEFORE everything else cand_rp time 30 priority 20 # Smaller value means "higher" priority cand_bootstrap_router priority 5 # Bigger value means "higher" priority group_prefix 224.0.0.0 masklen 4 # All multicast groups # switch_data_threshold rate 50000 interval 20 # 50kbps (approx.) switch_register_threshold rate 50000 interval 20 # 50kbps (approx.) pimd-2.1.8/debian/rules0000755000000000000000000000420711700261371011644 0ustar #!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 CFLAGS = `dpkg-buildflags --get CFLAGS` CFLAGS += -Wall -Werror LDFLAGS = `dpkg-buildflags --get LDFLAGS` CPPFLAGS = `dpkg-buildflags --get CPPFLAGS` export CFLAGS export LDFLAGS export CPPFLAGS ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. touch configure-stamp build: build-arch build-indep build-arch: build-stamp build-indep: build-stamp build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. $(MAKE) #/usr/bin/docbook-to-man debian/pimd.sgml > pimd.8 touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp # Add here commands to clean up after the build process. [ ! -f Makefile ] || $(MAKE) clean [ ! -f Makefile ] || $(MAKE) distclean dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs # Add here commands to install the package into debian/pimd. $(MAKE) install DESTDIR=$(CURDIR)/debian/pimd/ prefix=/usr rm -f $(CURDIR)/debian/pimd/usr/share/doc/pimd/INSTALL rm -f $(CURDIR)/debian/pimd/usr/share/doc/pimd/LICENSE rm -f $(CURDIR)/debian/pimd/usr/share/doc/pimd/LICENSE.mrouted rm -f $(CURDIR)/debian/pimd/usr/share/doc/pimd/ChangeLog* # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs ChangeLog dh_installdocs dh_installexamples # dh_install # dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime dh_installinit # dh_installcron # dh_installinfo dh_installman pimd.8 dh_link dh_strip dh_compress dh_fixperms # dh_perl # dh_python # dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure pimd-2.1.8/debian/control0000644000000000000000000000100411700261371012157 0ustar Source: pimd Section: net Priority: optional Maintainer: Antonin Kral Build-Depends: debhelper (>= 7) Standards-Version: 3.9.2 Package: pimd Architecture: any Homepage: http://github.com/troglobit/pimd Depends: ${shlibs:Depends}, ${misc:Depends} Conflicts: mrouted, smcroute Description: multicast routing daemon (PIMv2) pimd is implementation of Protocol Independent Multicast routing daemon. It supports PIMv2-SM on FreeBSD, NetBSD, OpenBSD, Linux. Enabled PIM support in kernel is needed. pimd-2.1.8/debian/examples0000644000000000000000000000003011700261371012313 0ustar debian/addons/pimd.conf pimd-2.1.8/debian/init.d0000644000000000000000000000176011700261371011675 0ustar #! /bin/sh ### BEGIN INIT INFO # Provides: pimd # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/pimd NAME=pimd DESC=pimd test -x $DAEMON || exit 0 set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON sleep 1 start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 pimd-2.1.8/debian/substvars0000644000000000000000000000004011700261371012532 0ustar shlibs:Depends=libc6 (>= 2.7-1) pimd-2.1.8/debian/dirs0000644000000000000000000000001511700261371011441 0ustar etc usr/sbin pimd-2.1.8/CREDITS0000644000000000000000000000626211700261371010365 0ustar Credits ======= Apologies if your names is not included, please contact us to be included. * The pimd maintainer until January 14, 2005, when the project was officially retired: Pavlin Ivanov Radoslavov * The PIM kernel modifications and pimd itself were originally written by Ahmed Helmy (ahelmy@catarina.usc.edu) as a summer intern in SGI. * The PIM-SM implementation for gated, George Edmond "Rusty" Eddy * The "up to the March '97 I-D spec" + RSVP support pimd version was done by Pavlin Radoslavov during his summer'97 intern in Sun Microsystems under Michael Speer's supervision. * BSDI 3.0/3.1 support + various improvements and bug reports by Hitoshi Asaeda (asaeda@yamato.ibm.co.jp). * Bug reports and SGI tests by Nidhi Bhaskar (nidhi@cho-oyu.engr.sgi.com). * Bug reports and SunOS tests by Isabelle Girard (girardi@rc.bel.alcatel.be) and Dirk Ooms (oomsd@rc.bel.alcatel.be) * NetBSD-1.3 compilation support (both for pimd and the kernel mods) and bug reports by Heiko W.Rupp * Bug reports by Chirayu Shah (shahzad@torrentnet.com) * A number of changes copied back from pimdd (PIM-DM) stand-alone implementation by Kurt Windisch (kurtw@antc.uoregon.edu) * Linux patches by "Jonathan Day" and Fred Griffoul * Bug reports and Linux tests by Kaifu Wu * Linux kernel internals help by Alexey Kuznetsov * Bug reports by Fred Griffoul * Bug reports and fixes for Linux by "Venning, Roger" * Various patches and bug fixes by JINMEI Tatuya * Solaris 8 fixes by "Eric S. Johnson" * Bug reports by Azzurra Pantella and Nicola Dicosmo from University of Pisa. * Bug reports and fixes by Sri V * Bug reports, fixes and new features (ALTNET, SCOPED traffic) by Marian Stagarescu and Ashok Rao * Bug reports by Philip Ho * Bug reports by * GRE configuration examples, bug fixes, and code contribution by Hiroyuki Komatsu * Bug report and fix by Xiaofeng Liu * Bug reports and fixes by SAKAI Hiroaki * Bug reports and fixes by "Jiahao Wang" and "Bo Cheng" ) * Bug report by Andrea Gambirasio * Bug reports by "J.W. (Bill) Atwood" * Bug report by "Eva Pless" * Bug reports and fixes by SUZUKI Shinsuke * Bug report by Serdar Uezuemcue * Bug reports and fixes by * All alpha testers who were brave enough to try it and then sent me feedbacks (apology for not keeping the list). * Thanks to the FreeBSD team and particularly to the freebsd-hackers mailing list participants for the help with the real-time debugging of the FreeBSD kernel. pimd-2.1.8/pimd.h0000644000000000000000000004530711700261371010452 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: pimd.h,v 1.27 2003/05/21 10:40:28 pavlin Exp $ */ #include #include #define PIM_PROTOCOL_VERSION 2 #define PIMD_VERSION PIM_PROTOCOL_VERSION #define PIMD_SUBVERSION 1 #if 0 #define PIM_CONSTANT 0x000eff00 /* constant portion of 'group' field */ #endif #define PIM_CONSTANT 0 #define PIMD_LEVEL (PIM_CONSTANT | PIMD_VERSION | (PIMD_SUBVERSION << 8)) #define INADDR_ALL_PIM_ROUTERS (u_int32)0xe000000D /* 224.0.0.13 */ #if !defined(INADDR_UNSPEC_GROUP) #define INADDR_UNSPEC_GROUP (u_int32)0xe0000000 /* 224.0.0.0 */ #endif /* !defined(INADDR_UNSPEC_GROUP) */ /* PIM protocol timers (in seconds) */ #ifndef TIMER_INTERVAL #define TIMER_INTERVAL 5 /* virtual timer granularity */ #endif /* TIMER_INTERVAL */ #define PIM_REGISTER_SUPPRESSION_TIMEOUT 60 #define PIM_REGISTER_PROBE_TIME 5 /* Used to send NULL_REGISTER */ #define PIM_DATA_TIMEOUT 210 #define PIM_TIMER_HELLO_PERIOD 30 #define PIM_JOIN_PRUNE_PERIOD 60 #define PIM_JOIN_PRUNE_HOLDTIME (3.5 * PIM_JOIN_PRUNE_PERIOD) #define PIM_RANDOM_DELAY_JOIN_TIMEOUT 4.5 #define PIM_DEFAULT_CAND_RP_ADV_PERIOD 60 /* TODO: 60 is the original value. Temporarily set to 30 for debugging. #define PIM_BOOTSTRAP_PERIOD 60 */ #define PIM_BOOTSTRAP_PERIOD 30 #define PIM_BOOTSTRAP_TIMEOUT (2.5 * PIM_BOOTSTRAP_PERIOD + 10) #define PIM_TIMER_HELLO_HOLDTIME (3.5 * PIM_TIMER_HELLO_PERIOD) #define PIM_ASSERT_TIMEOUT 180 /* Misc definitions */ #define PIM_DEFAULT_CAND_RP_PRIORITY 0 /* 0 is the highest. Don't know * why this is the default. * See the PS version (Mar' 97), * pp.22 bottom of the spec. */ #define PIM_MAX_CAND_RP_PRIORITY 255 /* 255 is the highest. */ #define PIM_DEFAULT_BSR_PRIORITY 0 /* 0 is the lowest */ #define RP_DEFAULT_IPV4_HASHMASKLEN 30 /* the default group msklen used * by the hash function to * calculate the group-to-RP * mapping */ #define SINGLE_SRC_MSKLEN 32 /* the single source mask length */ #define SINGLE_GRP_MSKLEN 32 /* the single group mask length */ #define PIM_GROUP_PREFIX_DEFAULT_MASKLEN 16 /* The default group masklen if * omitted in the config file. * XXX: not set to 4, because * a small mis-configuration * may concentrate all multicast * traffic in a single RP */ #define PIM_GROUP_PREFIX_MIN_MASKLEN 4 /* group prefix minimum length */ /* Datarate related definitions */ /* REG_RATE is used by the RP to switch to the shortest path instead of * decapsulating Registers. * DATA_RATE is the threshold for the last hop router to initiate * switching to the shortest path. */ /* TODO: XXX: probably no need for two different intervals. */ #define PIM_DEFAULT_REG_RATE 50000 /* max # of register bits/s */ #define PIM_DEFAULT_REG_RATE_INTERVAL 20 /* regrate probe interval */ #define PIM_DEFAULT_DATA_RATE 50000 /* max # of data bits/s */ #define PIM_DEFAULT_DATA_RATE_INTERVAL 20 /* datarate check interval */ #define DATA_RATE_CHECK_INTERVAL 20 /* Data rate check interval */ #define REG_RATE_CHECK_INTERVAL 20 /* PIM Reg. rate check interval*/ #define UCAST_ROUTING_CHECK_INTERVAL 20 /* Unfortunately, if the unicast * routing changes, the kernel * or any of the existing * unicast routing daemons * don't send us a signal. * Have to ask periodically the * kernel for any route changes. * Default: every 20 seconds. * Sigh. */ #define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */ #define DEFAULT_REG_RATE_LIMIT 0 /* default register_vif rate limit */ /************************************************************************** * PIM Encoded-Unicast, Encoded-Group and Encoded-Source Address formats * *************************************************************************/ /* Address families definition */ #define ADDRF_RESERVED 0 #define ADDRF_IPv4 1 #define ADDRF_IPv6 2 #define ADDRF_NSAP 3 #define ADDRF_HDLC 4 #define ADDRF_BBN1822 5 #define ADDRF_802 6 #define ADDRF_ETHERNET ADDRF_802 #define ADDRF_E163 7 #define ADDRF_E164 8 #define ADDRF_SMDS ADDRF_E164 #define ADDRF_ATM ADDRF_E164 #define ADDRF_F69 9 #define ADDRF_TELEX ADDRF_F69 #define ADDRF_X121 10 #define ADDRF_X25 ADDRF_X121 #define ADDRF_IPX 11 #define ADDRF_APPLETALK 12 #define ADDRF_DECNET_IV 13 #define ADDRF_BANYAN 14 #define ADDRF_E164_NSAP 15 /* Addresses Encoding Type (specific for each Address Family */ #define ADDRT_IPv4 0 /* Encoded-Unicast: 6 bytes long */ typedef struct pim_encod_uni_addr_ { u_int8 addr_family; u_int8 encod_type; u_int32 unicast_addr; /* XXX: Note the 32-bit boundary * misalignment for the unicast * address when placed in the * memory. Must read it byte-by-byte! */ } pim_encod_uni_addr_t; #define PIM_ENCODE_UNI_ADDR_LEN 6 /* Encoded-Group */ typedef struct pim_encod_grp_addr_ { u_int8 addr_family; u_int8 encod_type; u_int8 reserved; u_int8 masklen; u_int32 mcast_addr; } pim_encod_grp_addr_t; /* Encoded-Source */ typedef struct pim_encod_src_addr_ { u_int8 addr_family; u_int8 encod_type; u_int8 flags; u_int8 masklen; u_int32 src_addr; } pim_encod_src_addr_t; #define USADDR_RP_BIT 0x1 #define USADDR_WC_BIT 0x2 #define USADDR_S_BIT 0x4 /************************************************************************** * PIM Messages formats * *************************************************************************/ /* TODO: XXX: some structures are probably not used at all */ typedef struct pim pim_header_t; /* PIM Hello */ typedef struct pim_hello_ { u_int16 option_type; /* Option type */ u_int16 option_length; /* Length of the Option Value field in bytes */ } pim_hello_t; /* PIM Register */ typedef struct pim_register_ { u_int32 reg_flags; } pim_register_t; /* PIM Register-Stop */ typedef struct pim_register_stop_ { pim_encod_grp_addr_t encod_grp; pim_encod_uni_addr_t encod_src; /* XXX: 6 bytes long, misaligned */ } pim_register_stop_t; /* PIM Join/Prune: XXX: all 32-bit addresses misaligned! */ typedef struct pim_jp_header_ { pim_encod_uni_addr_t encod_upstream_nbr; u_int8 reserved; u_int8 num_groups; u_int16 holdtime; } pim_jp_header_t; typedef struct pim_jp_encod_grp_ { pim_encod_grp_addr_t encod_grp; u_int16 number_join_src; u_int16 number_prune_src; } pim_jp_encod_grp_t; #define PIM_ACTION_NOTHING 0 #define PIM_ACTION_JOIN 1 #define PIM_ACTION_PRUNE 2 #define PIM_IIF_SOURCE 1 #define PIM_IIF_RP 2 #define PIM_ASSERT_RPT_BIT 0x80000000 /* PIM messages type */ #ifndef PIM_HELLO #define PIM_HELLO 0 #endif #ifndef PIM_REGISTER #define PIM_REGISTER 1 #endif #ifndef PIM_REGISTER_STOP #define PIM_REGISTER_STOP 2 #endif #ifndef PIM_JOIN_PRUNE #define PIM_JOIN_PRUNE 3 #endif #ifndef PIM_BOOTSTRAP #define PIM_BOOTSTRAP 4 #endif #ifndef PIM_ASSERT #define PIM_ASSERT 5 #endif #ifndef PIM_GRAFT #define PIM_GRAFT 6 #endif #ifndef PIM_GRAFT_ACK #define PIM_GRAFT_ACK 7 #endif #ifndef PIM_CAND_RP_ADV #define PIM_CAND_RP_ADV 8 #endif #define PIM_V2_HELLO PIM_HELLO #define PIM_V2_REGISTER PIM_REGISTER #define PIM_V2_REGISTER_STOP PIM_REGISTER_STOP #define PIM_V2_JOIN_PRUNE PIM_JOIN_PRUNE #define PIM_V2_BOOTSTRAP PIM_BOOTSTRAP #define PIM_V2_ASSERT PIM_ASSERT #define PIM_V2_GRAFT PIM_GRAFT #define PIM_V2_GRAFT_ACK PIM_GRAFT_ACK #define PIM_V2_CAND_RP_ADV PIM_CAND_RP_ADV #define PIM_V1_QUERY 0 #define PIM_V1_REGISTER 1 #define PIM_V1_REGISTER_STOP 2 #define PIM_V1_JOIN_PRUNE 3 #define PIM_V1_RP_REACHABILITY 4 #define PIM_V1_ASSERT 5 #define PIM_V1_GRAFT 6 #define PIM_V1_GRAFT_ACK 7 /* Vartious options from PIM messages definitions */ /* PIM_HELLO definitions */ #define PIM_MESSAGE_HELLO_HOLDTIME 1 #define PIM_MESSAGE_HELLO_HOLDTIME_LENGTH 2 #define PIM_MESSAGE_HELLO_HOLDTIME_FOREVER 0xffff /* PIM_REGISTER definitions */ #define PIM_MESSAGE_REGISTER_BORDER_BIT 0x80000000 #define PIM_MESSAGE_REGISTER_NULL_REGISTER_BIT 0x40000000 #define MASK_TO_MASKLEN(mask, masklen) \ do { \ register u_int32 tmp_mask = ntohl((mask)); \ register u_int8 tmp_masklen = sizeof((mask)) << 3; \ for ( ; tmp_masklen > 0; tmp_masklen--, tmp_mask >>= 1) \ if (tmp_mask & 0x1) \ break; \ (masklen) = tmp_masklen; \ } while (0) #define MASKLEN_TO_MASK(masklen, mask) \ do { \ (mask) = (masklen)? htonl(~0 << ((sizeof((mask)) << 3) - (masklen))) : 0;\ } while (0) /* * A bunch of macros because of the lack of 32-bit boundary alignment. * All because of one misalligned address format. Hopefully this will be * fixed in PIMv3. (cp) must be (u_int8 *) . */ /* Originates from Eddy Rusty's (eddy@isi.edu) PIM-SM implementation for * gated. */ #include #ifdef HOST_OS_WINDOWS #define LITTLE_ENDIAN 1234 #define BYTE_ORDER LITTLE_ENDIAN #endif /* HOST_OS_WINDOWS */ #if !defined(BYTE_ORDER) #if defined(__BYTE_ORDER) #define BYTE_ORDER __BYTE_ORDER #define LITTLE_ENDIAN __LITTLE_ENDIAN #define BIG_ENDIAN __BIG_ENDIAN #else #error "BYTE_ORDER not defined! Define it to either LITTLE_ENDIAN (e.g. i386, vax) or BIG_ENDIAN (e.g. 68000, ibm, net) based on your architecture!" #endif #endif /* PUT_NETLONG puts "network ordered" data to the datastream. * PUT_HOSTLONG puts "host ordered" data to the datastream. * GET_NETLONG gets the data and keeps it in "network order" in the memory * GET_HOSTLONG gets the data, but in the memory it is in "host order" * The same for all {PUT,GET}_{NET,HOST}{SHORT,LONG} */ #define GET_BYTE(val, cp) ((val) = *(cp)++) #define PUT_BYTE(val, cp) (*(cp)++ = (u_int8)(val)) #define GET_HOSTSHORT(val, cp) \ do { \ register u_int16 Xv; \ Xv = (*(cp)++) << 8; \ Xv |= *(cp)++; \ (val) = Xv; \ } while (0) #define PUT_HOSTSHORT(val, cp) \ do { \ register u_int16 Xv; \ Xv = (u_int16)(val); \ *(cp)++ = (u_int8)(Xv >> 8); \ *(cp)++ = (u_int8)Xv; \ } while (0) #if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) #define GET_NETSHORT(val, cp) \ do { \ register u_int16 Xv; \ Xv = *(cp)++; \ Xv |= (*(cp)++) << 8; \ (val) = Xv; \ } while (0) #define PUT_NETSHORT(val, cp) \ do { \ register u_int16 Xv; \ Xv = (u_int16)(val); \ *(cp)++ = (u_int8)Xv; \ *(cp)++ = (u_int8)(Xv >> 8); \ } while (0) #else #define GET_NETSHORT(val, cp) GET_HOSTSHORT(val, cp) #define PUT_NETSHORT(val, cp) PUT_HOSTSHORT(val, cp) #endif /* {GET,PUT}_NETSHORT */ #define GET_HOSTLONG(val, cp) \ do { \ register u_long Xv; \ Xv = (*(cp)++) << 24; \ Xv |= (*(cp)++) << 16; \ Xv |= (*(cp)++) << 8; \ Xv |= *(cp)++; \ (val) = Xv; \ } while (0) #define PUT_HOSTLONG(val, cp) \ do { \ register u_int32 Xv; \ Xv = (u_int32)(val); \ *(cp)++ = (u_int8)(Xv >> 24); \ *(cp)++ = (u_int8)(Xv >> 16); \ *(cp)++ = (u_int8)(Xv >> 8); \ *(cp)++ = (u_int8)Xv; \ } while (0) #if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) #define GET_NETLONG(val, cp) \ do { \ register u_long Xv; \ Xv = *(cp)++; \ Xv |= (*(cp)++) << 8; \ Xv |= (*(cp)++) << 16; \ Xv |= (*(cp)++) << 24; \ (val) = Xv; \ } while (0) #define PUT_NETLONG(val, cp) \ do { \ register u_int32 Xv; \ Xv = (u_int32)(val); \ *(cp)++ = (u_int8)Xv; \ *(cp)++ = (u_int8)(Xv >> 8); \ *(cp)++ = (u_int8)(Xv >> 16); \ *(cp)++ = (u_int8)(Xv >> 24); \ } while (0) #else #define GET_NETLONG(val, cp) GET_HOSTLONG(val, cp) #define PUT_NETLONG(val, cp) PUT_HOSTLONG(val, cp) #endif /* {GET,PUT}_HOSTLONG */ #define GET_ESADDR(esa, cp) \ do { \ (esa)->addr_family = *(cp)++; \ (esa)->encod_type = *(cp)++; \ (esa)->flags = *(cp)++; \ (esa)->masklen = *(cp)++; \ GET_NETLONG((esa)->src_addr, (cp)); \ } while(0) #define PUT_ESADDR(addr, masklen, flags, cp) \ do { \ u_int32 mask; \ MASKLEN_TO_MASK((masklen), mask); \ *(cp)++ = ADDRF_IPv4; /* family */ \ *(cp)++ = ADDRT_IPv4; /* type */ \ *(cp)++ = (flags); /* flags */ \ *(cp)++ = (masklen); \ PUT_NETLONG((addr) & mask, (cp)); \ } while(0) #define GET_EGADDR(ega, cp) \ do { \ (ega)->addr_family = *(cp)++; \ (ega)->encod_type = *(cp)++; \ (ega)->reserved = *(cp)++; \ (ega)->masklen = *(cp)++; \ GET_NETLONG((ega)->mcast_addr, (cp)); \ } while(0) #define PUT_EGADDR(addr, masklen, reserved, cp) \ do { \ u_int32 mask; \ MASKLEN_TO_MASK((masklen), mask); \ *(cp)++ = ADDRF_IPv4; /* family */ \ *(cp)++ = ADDRT_IPv4; /* type */ \ *(cp)++ = (reserved); /* reserved; should be 0 */ \ *(cp)++ = (masklen); \ PUT_NETLONG((addr) & mask, (cp)); \ } while(0) #define GET_EUADDR(eua, cp) \ do { \ (eua)->addr_family = *(cp)++; \ (eua)->encod_type = *(cp)++; \ GET_NETLONG((eua)->unicast_addr, (cp)); \ } while(0) #define PUT_EUADDR(addr, cp) \ do { \ *(cp)++ = ADDRF_IPv4; /* family */ \ *(cp)++ = ADDRT_IPv4; /* type */ \ PUT_NETLONG((addr), (cp)); \ } while(0) /* TODO: Currently not used. Probably not need at all. Delete! */ #if 0 /* This is completely IGMP related stuff? */ #define PIM_LEAF_TIMEOUT (3.5 * IGMP_QUERY_INTERVAL) #define PIM_REGISTER_BIT_TIMEOUT 30 /* TODO: check if need to be 60 */ #define PIM_ASSERT_RATE_TIMER 15 #endif /* 0 */ #if (defined(__bsdi__) || defined(NetBSD) || defined(OpenBSD) || defined(IRIX)) /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IP packet */ struct igmpmsg { u_long unused1; u_long unused2; u_char im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 #define IGMPMSG_WRONGVIF 2 #define IGMPMSG_WHOLEPKT 3 /* used for user level encap*/ u_char im_mbz; /* must be zero */ u_char im_vif; /* vif rec'd on */ u_char unused3; struct in_addr im_src, im_dst; }; #endif pimd-2.1.8/dvmrp_proto.c0000644000000000000000000001314211700261371012057 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: dvmrp_proto.c,v 1.10 2001/09/10 20:31:36 pavlin Exp $ */ #include "defs.h" /* TODO */ /* * Process an incoming neighbor probe message. */ void dvmrp_accept_probe(src, dst, p, datalen, level) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); u_int32 level __attribute__((unused)); { return; } /* TODO */ /* * Process an incoming route report message. */ void dvmrp_accept_report(src, dst, p, datalen, level) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); u_int32 level __attribute__((unused)); { return; } /* TODO */ void dvmrp_accept_info_request(src, dst, p, datalen) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); { return; } /* * Process an incoming info reply message. */ void dvmrp_accept_info_reply(src, dst, p, datalen) u_int32 src; u_int32 dst; u_char *p __attribute__((unused)); int datalen __attribute__((unused)); { IF_DEBUG(DEBUG_PKT) logit(LOG_DEBUG, 0, "ignoring spurious DVMRP info reply from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } /* * Process an incoming neighbor-list message. */ void dvmrp_accept_neighbors(src, dst, p, datalen, level) u_int32 src; u_int32 dst; u_char *p __attribute__((unused)); int datalen __attribute__((unused)); u_int32 level __attribute__((unused)); { logit(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } /* * Process an incoming neighbor-list message. */ void dvmrp_accept_neighbors2(src, dst, p, datalen, level) u_int32 src; u_int32 dst; u_char *p __attribute__((unused)); int datalen __attribute__((unused)); u_int32 level __attribute__((unused)); { IF_DEBUG(DEBUG_PKT) logit(LOG_DEBUG, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } /* TODO */ /* * Takes the prune message received and then strips it to * determine the (src, grp) pair to be pruned. * * Adds the router to the (src, grp) entry then. * * Determines if further packets have to be sent down that vif * * Determines if a corresponding prune message has to be generated */ void dvmrp_accept_prune(src, dst, p, datalen) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); { return; } /* TODO */ /* determine the multicast group and src * * if it does, then determine if a prune was sent * upstream. * if prune sent upstream, send graft upstream and send * ack downstream. * * if no prune sent upstream, change the forwarding bit * for this interface and send ack downstream. * * if no entry exists for this group send ack downstream. */ void dvmrp_accept_graft(src, dst, p, datalen) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); { return; } /* TODO */ /* * find out which group is involved first of all * then determine if a graft was sent. * if no graft sent, ignore the message * if graft was sent and the ack is from the right * source, remove the graft timer so that we don't * have send a graft again */ void dvmrp_accept_g_ack(src, dst, p, datalen) u_int32 src __attribute__((unused)); u_int32 dst __attribute__((unused)); u_char *p __attribute__((unused)); int datalen __attribute__((unused)); { return; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/rp.c0000644000000000000000000007000611700261371010127 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "defs.h" /* * The hash function. Stollen from Eddy's (eddy@isi.edu) * implementation (for compatibility ;) */ #define SEED1 1103515245 #define SEED2 12345 #define RP_HASH_VALUE(G, M, C) (((SEED1) * (((SEED1) * ((G) & (M)) + (SEED2)) ^ (C)) + (SEED2)) % 0x80000000) cand_rp_t *cand_rp_list; grp_mask_t *grp_mask_list; cand_rp_t *segmented_cand_rp_list; grp_mask_t *segmented_grp_mask_list; u_int16 curr_bsr_fragment_tag; u_int8 curr_bsr_priority; u_int32 curr_bsr_address; u_int32 curr_bsr_hash_mask; u_int16 pim_bootstrap_timer; /* For electing the BSR and * sending Cand-RP-set msgs */ u_int8 my_bsr_priority; u_int32 my_bsr_address; u_int32 my_bsr_hash_mask; u_int8 cand_bsr_flag = FALSE; /* Set to TRUE if I am * a candidate BSR */ u_int32 my_cand_rp_address; u_int8 my_cand_rp_priority; u_int16 my_cand_rp_holdtime; u_int16 my_cand_rp_adv_period; /* The locally configured * Cand-RP adv. period. */ u_int16 pim_cand_rp_adv_timer; u_int8 cand_rp_flag = FALSE; /* Candidate RP flag */ struct cand_rp_adv_message_ cand_rp_adv_message; u_int32 rp_my_ipv4_hashmask; /* * Local functions definition. */ static cand_rp_t *add_cand_rp (cand_rp_t **used_cand_rp_list, u_int32 address); static grp_mask_t *add_grp_mask (grp_mask_t **used_grp_mask_list, u_int32 group_addr, u_int32 group_mask, u_int32 hash_mask); static void delete_grp_mask_entry (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, grp_mask_t *grp_mask_delete); static void delete_rp_entry (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, cand_rp_t *cand_rp_ptr); void init_rp_and_bsr(void) { /* TODO: if the grplist is not NULL, remap all groups ASAP! */ delete_rp_list(&cand_rp_list, &grp_mask_list); delete_rp_list(&segmented_cand_rp_list, &segmented_grp_mask_list); if (cand_bsr_flag == FALSE) { /* * If I am not candidat BSR, initialize the "current BSR" * as having the lowest priority. */ curr_bsr_fragment_tag = 0; curr_bsr_priority = 0; /* Lowest priority */ curr_bsr_address = INADDR_ANY_N; /* Lowest priority */ MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, curr_bsr_hash_mask); SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT); } else { curr_bsr_fragment_tag = RANDOM(); curr_bsr_priority = my_bsr_priority; curr_bsr_address = my_bsr_address; curr_bsr_hash_mask = my_bsr_hash_mask; SET_TIMER(pim_bootstrap_timer, bootstrap_initial_delay()); } if (cand_rp_flag != FALSE) { MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, rp_my_ipv4_hashmask); /* Setup the Cand-RP-Adv-Timer */ SET_TIMER(pim_cand_rp_adv_timer, RANDOM() % my_cand_rp_adv_period); } } u_int16 bootstrap_initial_delay(void) { long addr_delay; long delay; long log_mask; int log_of_2; u_int8 best_priority; /* * The bootstrap timer initial value (if Cand-BSR). * It depends of the bootstrap router priority: * higher priority has shorter value: * * delay = 5 + 2 * log_2(1 + best_priority - myPriority) + addr_delay; * * best_priority = Max(storedPriority, myPriority); * if (best_priority == myPriority) * addr_delay = log_2(bestAddr - myAddr)/16; * else * addr_delay = 2 - (myAddr/2^31); */ best_priority = max(curr_bsr_priority, my_bsr_priority); if (best_priority == my_bsr_priority) { addr_delay = ntohl(curr_bsr_address) - ntohl(my_bsr_address); /* Calculate the integer part of log_2 of (bestAddr - myAddr) */ /* To do so, have to find the position number of the first bit * from left which is `1` */ log_mask = sizeof(addr_delay) << 3; log_mask = (1 << (log_mask - 1)); /* Set the leftmost bit to `1` */ for (log_of_2 = (sizeof(addr_delay) << 3) - 1 ; log_of_2; log_of_2--) { if (addr_delay & log_mask) break; else log_mask >>= 1; /* Start shifting `1` on right */ } addr_delay = log_of_2 / 16; } else { addr_delay = 2 - (ntohl(my_bsr_address) / ( 1 << 31)); } delay = 1 + best_priority - my_bsr_priority; /* Calculate log_2(delay) */ log_mask = sizeof(delay) << 3; log_mask = (1 << (log_mask - 1)); /* Set the leftmost bit to `1` */ for (log_of_2 = (sizeof(delay) << 3) - 1 ; log_of_2; log_of_2--) { if (delay & log_mask) break; else log_mask >>= 1; /* Start shifting `1` on right */ } delay = 5 + 2 * log_of_2 + addr_delay; return (u_int16)delay; } static cand_rp_t *add_cand_rp(cand_rp_t **used_cand_rp_list, u_int32 address) { cand_rp_t *prev = NULL; cand_rp_t *next; cand_rp_t *ptr; rpentry_t *entry; u_int32 addr_h = ntohl(address); /* The ordering is the bigger first */ for (next = *used_cand_rp_list; next; prev = next, next = next->next) { if (ntohl(next->rpentry->address) > addr_h) continue; if (next->rpentry->address == address) return next; else break; } /* Create and insert the new entry between prev and next */ ptr = (cand_rp_t *)calloc(1, sizeof(cand_rp_t)); if (!ptr) logit(LOG_ERR, 0, "Ran out of memory in add_cand_rp()"); ptr->rp_grp_next = NULL; ptr->next = next; ptr->prev = prev; if (next) next->prev = ptr; if (prev == NULL) *used_cand_rp_list = ptr; else prev->next = ptr; entry = (rpentry_t *)calloc(1, sizeof(rpentry_t)); if (!entry) logit(LOG_ERR, 0, "Ran out of memory in add_cand_rp()"); ptr->rpentry = entry; entry->next = NULL; entry->prev = NULL; entry->address = address; entry->mrtlink = NULL; entry->incoming = NO_VIF; entry->upstream = NULL; /* TODO: setup the metric and the preference as ~0 (the lowest)? */ entry->metric = ~0; entry->preference = ~0; RESET_TIMER(entry->timer); entry->cand_rp = ptr; /* TODO: XXX: check whether there is a route to that RP: if return value * is FALSE, then no route. */ if (local_address(entry->address) == NO_VIF) /* TODO: check for error and delete */ set_incoming(entry, PIM_IIF_RP); else /* TODO: XXX: CHECK!!! */ entry->incoming = reg_vif_num; return ptr; } static grp_mask_t *add_grp_mask(grp_mask_t **used_grp_mask_list, u_int32 group_addr, u_int32 group_mask, u_int32 hash_mask) { grp_mask_t *prev = NULL; grp_mask_t *next; grp_mask_t *ptr; u_int32 prefix_h = ntohl(group_addr & group_mask); /* The ordering of group_addr is: bigger first */ for (next = *used_grp_mask_list; next; prev = next, next = next->next) { if (ntohl(next->group_addr & next->group_mask) > prefix_h) continue; /* The ordering of group_mask is: bigger (longer) first */ if ((next->group_addr & next->group_mask) == (group_addr & group_mask)) { if (ntohl(next->group_mask) > ntohl(group_mask)) continue; else if (next->group_mask == group_mask) return next; else break; } } ptr = (grp_mask_t *)calloc(1, sizeof(grp_mask_t)); if (!ptr) logit(LOG_ERR, 0, "Ran out of memory in add_grp_mask()"); ptr->grp_rp_next = (rp_grp_entry_t *)NULL; ptr->next = next; ptr->prev = prev; if (next) next->prev = ptr; if (prev == NULL) *used_grp_mask_list = ptr; else prev->next = ptr; ptr->group_addr = group_addr; ptr->group_mask = group_mask; ptr->hash_mask = hash_mask; ptr->group_rp_number = 0; ptr->fragment_tag = 0; return ptr; } /* TODO: XXX: BUG: a remapping for some groups currently using some other * grp_mask may be required by the addition of the new entry!!! * Remapping all groups might be a costly process... */ rp_grp_entry_t *add_rp_grp_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 rp_addr, u_int8 rp_priority, u_int16 rp_holdtime, u_int32 group_addr, u_int32 group_mask, u_int32 bsr_hash_mask, u_int16 fragment_tag) { cand_rp_t *cand_rp_ptr; grp_mask_t *mask_ptr; rpentry_t *rpentry_ptr; rp_grp_entry_t *entry_next; rp_grp_entry_t *entry_new; rp_grp_entry_t *entry_prev = NULL; grpentry_t *grpentry_ptr_prev; grpentry_t *grpentry_ptr_next; u_int32 rp_addr_h; u_int8 old_highest_priority = ~0; /* Smaller value means "higher" */ /* Input data verification */ if (!inet_valid_host(rp_addr)) return NULL; if (!IN_CLASSD(ntohl(group_addr))) return NULL; mask_ptr = add_grp_mask(used_grp_mask_list, group_addr, group_mask, bsr_hash_mask); if (mask_ptr == NULL) return NULL; /* TODO: delete */ #if 0 if (mask_ptr->grp_rp_next) { /* Check for obsolete grp_rp chain */ if ((my_bsr_address != curr_bsr_address) && (mask_ptr->grp_rp_next->fragment_tag != fragment_tag)) { /* This grp_rp chain is obsolete. Delete it. */ delete_grp_mask(used_cand_rp_list, used_grp_mask_list, group_addr, group_mask); mask_ptr = add_grp_mask(used_grp_mask_list, group_addr, group_mask, bsr_hash_mask); if (mask_ptr == NULL) return NULL; } } #endif /* 0 */ cand_rp_ptr = add_cand_rp(used_cand_rp_list, rp_addr); if (cand_rp_ptr == NULL) { if (mask_ptr->grp_rp_next == NULL) delete_grp_mask(used_cand_rp_list, used_grp_mask_list, group_addr, group_mask); return NULL; } rpentry_ptr = cand_rp_ptr->rpentry; SET_TIMER(rpentry_ptr->timer, rp_holdtime); rp_addr_h = ntohl(rp_addr); mask_ptr->fragment_tag = fragment_tag; /* For garbage collection */ entry_prev = NULL; entry_next = mask_ptr->grp_rp_next; /* TODO: improve it */ if (entry_next != NULL) old_highest_priority = entry_next->priority; for ( ; entry_next; entry_prev = entry_next, entry_next = entry_next->grp_rp_next) { /* Smaller value means higher priority. The entries are * sorted with the highest priority first. */ if (entry_next->priority < rp_priority) continue; if (entry_next->priority > rp_priority) break; /* * Here we don't care about higher/lower addresses, because * higher address does not guarantee higher hash_value, * but anyway we do order with the higher address first, * so it will be easier to find an existing entry and update the * holdtime. */ if (ntohl(entry_next->rp->rpentry->address) > rp_addr_h) continue; if (ntohl(entry_next->rp->rpentry->address) < rp_addr_h) break; /* We already have this entry. Update the holdtime */ /* TODO: We shoudn't have old existing entry, because with the * current implementation all of them will be deleted * (different fragment_tag). Debug and check and eventually * delete. */ entry_next->holdtime = rp_holdtime; entry_next->fragment_tag = fragment_tag; return entry_next; } /* Create and link the new entry */ entry_new = (rp_grp_entry_t *)calloc(1, sizeof(rp_grp_entry_t)); if (!entry_new) logit(LOG_ERR, 0, "Ran out of memory in add_rp_grp_entry()"); entry_new->grp_rp_next = entry_next; entry_new->grp_rp_prev = entry_prev; if (entry_next) entry_next->grp_rp_prev = entry_new; if (entry_prev == NULL) mask_ptr->grp_rp_next = entry_new; else entry_prev->grp_rp_next = entry_new; /* * The rp_grp_entry chain is not ordered, so just plug * the new entry at the head. */ entry_new->rp_grp_next = cand_rp_ptr->rp_grp_next; if (cand_rp_ptr->rp_grp_next) cand_rp_ptr->rp_grp_next->rp_grp_prev = entry_new; entry_new->rp_grp_prev = NULL; cand_rp_ptr->rp_grp_next = entry_new; entry_new->holdtime = rp_holdtime; entry_new->fragment_tag = fragment_tag; entry_new->priority = rp_priority; entry_new->group = mask_ptr; entry_new->rp = cand_rp_ptr; entry_new->grplink = NULL; mask_ptr->group_rp_number++; if (mask_ptr->grp_rp_next->priority == rp_priority) { /* The first entries are with the best priority. */ /* Adding this rp_grp_entry may result in group_to_rp remapping */ for (entry_next = mask_ptr->grp_rp_next; entry_next; entry_next = entry_next->grp_rp_next) { if (entry_next->priority > old_highest_priority) break; for (grpentry_ptr_prev = entry_next->grplink; grpentry_ptr_prev; ) { grpentry_ptr_next = grpentry_ptr_prev->rpnext; remap_grpentry(grpentry_ptr_prev); grpentry_ptr_prev = grpentry_ptr_next; } } } return entry_new; } void delete_rp_grp_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, rp_grp_entry_t *entry) { grpentry_t *ptr; grpentry_t *ptr_next; if (entry == NULL) return; entry->group->group_rp_number--; /* Free the rp_grp* and grp_rp* links */ if (entry->rp_grp_prev) entry->rp_grp_prev->rp_grp_next = entry->rp_grp_next; else entry->rp->rp_grp_next = entry->rp_grp_next; if (entry->rp_grp_next) entry->rp_grp_next->rp_grp_prev = entry->rp_grp_prev; if (entry->grp_rp_prev) entry->grp_rp_prev->grp_rp_next = entry->grp_rp_next; else entry->group->grp_rp_next = entry->grp_rp_next; if (entry->grp_rp_next) entry->grp_rp_next->grp_rp_prev = entry->grp_rp_prev; /* Delete Cand-RP or Group-prefix if useless */ if (entry->group->grp_rp_next == NULL) delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, entry->group); if (entry->rp->rp_grp_next == NULL) delete_rp_entry(used_cand_rp_list, used_grp_mask_list, entry->rp); /* Remap all affected groups */ for (ptr = entry->grplink; ptr; ptr = ptr_next) { ptr_next = ptr->rpnext; remap_grpentry(ptr); } free((char *)entry); } /* TODO: XXX: the affected group entries will be partially * setup, because may have group routing entry, but NULL pointers to RP. * After the call to this function, must remap all group entries ASAP. */ void delete_rp_list(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list) { cand_rp_t *cand_ptr, *cand_next; rp_grp_entry_t *entry_ptr, *entry_next; grp_mask_t *mask_ptr, *mask_next; grpentry_t *gentry_ptr, *gentry_ptr_next; for (cand_ptr = *used_cand_rp_list; cand_ptr; ) { cand_next = cand_ptr->next; /* Free the mrtentry (if any) for this RP */ if (cand_ptr->rpentry->mrtlink) { if (cand_ptr->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(cand_ptr->rpentry->mrtlink); FREE_MRTENTRY(cand_ptr->rpentry->mrtlink); } free(cand_ptr->rpentry); /* Free the whole chain of entry for this RP */ for (entry_ptr = cand_ptr->rp_grp_next; entry_ptr; entry_ptr = entry_next) { entry_next = entry_ptr->rp_grp_next; /* Clear the RP related invalid pointers for all group entries */ for (gentry_ptr = entry_ptr->grplink; gentry_ptr; gentry_ptr = gentry_ptr_next) { gentry_ptr_next = gentry_ptr->rpnext; gentry_ptr->rpnext = NULL; gentry_ptr->rpprev = NULL; gentry_ptr->active_rp_grp = NULL; gentry_ptr->rpaddr = INADDR_ANY_N; } free(entry_ptr); } free(cand_ptr); cand_ptr = cand_next; } *used_cand_rp_list = NULL; for (mask_ptr = *used_grp_mask_list; mask_ptr; mask_ptr = mask_next) { mask_next = mask_ptr->next; free(mask_ptr); } *used_grp_mask_list = NULL; } void delete_grp_mask(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 group_addr, u_int32 group_mask) { grp_mask_t *ptr; u_int32 prefix_h = ntohl(group_addr & group_mask); for (ptr = *used_grp_mask_list; ptr; ptr = ptr->next) { if (ntohl(ptr->group_addr & ptr->group_mask) > prefix_h) continue; if (ptr->group_addr == group_addr) { if (ntohl(ptr->group_mask) > ntohl(group_mask)) continue; else if (ptr->group_mask == group_mask) break; else return; /* Not found */ } } if (ptr == (grp_mask_t *)NULL) return; /* Not found */ delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, ptr); } static void delete_grp_mask_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, grp_mask_t *grp_mask_delete) { grpentry_t *grp_ptr, *grp_ptr_next; rp_grp_entry_t *entry_ptr; rp_grp_entry_t *entry_next; if (grp_mask_delete == NULL) return; /* Remove from the grp_mask_list first */ if (grp_mask_delete->prev) grp_mask_delete->prev->next = grp_mask_delete->next; else *used_grp_mask_list = grp_mask_delete->next; if (grp_mask_delete->next) grp_mask_delete->next->prev = grp_mask_delete->prev; /* Remove all grp_rp entries for this grp_mask */ for (entry_ptr = grp_mask_delete->grp_rp_next; entry_ptr; entry_ptr = entry_next) { entry_next = entry_ptr->grp_rp_next; /* Remap all related grpentry */ for (grp_ptr = entry_ptr->grplink; grp_ptr; grp_ptr = grp_ptr_next) { grp_ptr_next = grp_ptr->rpnext; remap_grpentry(grp_ptr); } if (entry_ptr->rp_grp_prev != (rp_grp_entry_t *)NULL) entry_ptr->rp_grp_prev->rp_grp_next = entry_ptr->rp_grp_next; else entry_ptr->rp->rp_grp_next = entry_ptr->rp_grp_next; if (entry_ptr->rp_grp_next != NULL) entry_ptr->rp_grp_next->rp_grp_prev = entry_ptr->rp_grp_prev; /* Delete the RP entry */ if (entry_ptr->rp->rp_grp_next == NULL) delete_rp_entry(used_cand_rp_list, used_grp_mask_list, entry_ptr->rp); free(entry_ptr); } free(grp_mask_delete); } /* * TODO: currently not used. */ void delete_rp(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 rp_addr) { cand_rp_t *ptr; u_int32 rp_addr_h = ntohl(rp_addr); for(ptr = *used_cand_rp_list; ptr != NULL; ptr = ptr->next) { if (ntohl(ptr->rpentry->address) > rp_addr_h) continue; if (ptr->rpentry->address == rp_addr) break; else return; /* Not found */ } if (ptr == NULL) return; /* Not found */ delete_rp_entry(used_cand_rp_list, used_grp_mask_list, ptr); } static void delete_rp_entry(cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, cand_rp_t *cand_rp_delete) { rp_grp_entry_t *entry_ptr; rp_grp_entry_t *entry_next; grpentry_t *grp_ptr; grpentry_t *grp_ptr_next; if (cand_rp_delete == NULL) return; /* Remove from the cand-RP chain */ if (cand_rp_delete->prev) cand_rp_delete->prev->next = cand_rp_delete->next; else *used_cand_rp_list = cand_rp_delete->next; if (cand_rp_delete->next) cand_rp_delete->next->prev = cand_rp_delete->prev; if (cand_rp_delete->rpentry->mrtlink) { if (cand_rp_delete->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(cand_rp_delete->rpentry->mrtlink); FREE_MRTENTRY(cand_rp_delete->rpentry->mrtlink); } free ((char *)cand_rp_delete->rpentry); /* Remove all rp_grp entries for this RP */ for (entry_ptr = cand_rp_delete->rp_grp_next; entry_ptr; entry_ptr = entry_next) { entry_next = entry_ptr->rp_grp_next; entry_ptr->group->group_rp_number--; /* First take care of the grp_rp chain */ if (entry_ptr->grp_rp_prev) entry_ptr->grp_rp_prev->grp_rp_next = entry_ptr->grp_rp_next; else entry_ptr->group->grp_rp_next = entry_ptr->grp_rp_next; if (entry_ptr->grp_rp_next) entry_ptr->grp_rp_next->grp_rp_prev = entry_ptr->grp_rp_prev; if (entry_ptr->grp_rp_next == NULL) delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, entry_ptr->group); /* Remap the related groups */ for (grp_ptr = entry_ptr->grplink; grp_ptr; grp_ptr = grp_ptr_next) { grp_ptr_next = grp_ptr->rpnext; remap_grpentry(grp_ptr); } free(entry_ptr); } free((char *)cand_rp_delete); } /* * Rehash the RP for the group. * XXX: currently, every time when remap_grpentry() is called, there has * being a good reason to change the RP, so for performancy reasons * no check is performed whether the RP will be really different one. */ int remap_grpentry(grpentry_t *grpentry_ptr) { rpentry_t *rpentry_ptr; rp_grp_entry_t *entry_ptr; mrtentry_t *grp_route; mrtentry_t *mrtentry_ptr; if (grpentry_ptr == NULL) return FALSE; /* Remove from the list of all groups matching to the same RP */ if (grpentry_ptr->rpprev) { grpentry_ptr->rpprev->rpnext = grpentry_ptr->rpnext; } else { if (grpentry_ptr->active_rp_grp) grpentry_ptr->active_rp_grp->grplink = grpentry_ptr->rpnext; } if (grpentry_ptr->rpnext) grpentry_ptr->rpnext->rpprev = grpentry_ptr->rpprev; entry_ptr = rp_grp_match(grpentry_ptr->group); if (entry_ptr == NULL) { /* If cannot remap, delete the group */ delete_grpentry(grpentry_ptr); return FALSE; } rpentry_ptr = entry_ptr->rp->rpentry; /* Add to the new chain of all groups mapping to the same RP */ grpentry_ptr->rpaddr = rpentry_ptr->address; grpentry_ptr->active_rp_grp = entry_ptr; grpentry_ptr->rpnext = entry_ptr->grplink; if (grpentry_ptr->rpnext) grpentry_ptr->rpnext->rpprev = grpentry_ptr; grpentry_ptr->rpprev = NULL; entry_ptr->grplink = grpentry_ptr; grp_route = grpentry_ptr->grp_route; if (grp_route) { grp_route->upstream = rpentry_ptr->upstream; grp_route->metric = rpentry_ptr->metric; grp_route->preference = rpentry_ptr->preference; change_interfaces(grp_route, rpentry_ptr->incoming, grp_route->joined_oifs, grp_route->pruned_oifs, grp_route->leaves, grp_route->asserted_oifs, MFC_UPDATE_FORCE); } for (mrtentry_ptr = grpentry_ptr->mrtlink; mrtentry_ptr; mrtentry_ptr = mrtentry_ptr->grpnext) { if (!(mrtentry_ptr->flags & MRTF_RP)) continue; mrtentry_ptr->upstream = rpentry_ptr->upstream; mrtentry_ptr->metric = rpentry_ptr->metric; mrtentry_ptr->preference = rpentry_ptr->preference; change_interfaces(mrtentry_ptr, rpentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, MFC_UPDATE_FORCE); } return TRUE; } rpentry_t *rp_match(u_int32 group) { rp_grp_entry_t *ptr; ptr = rp_grp_match(group); if (ptr) return ptr->rp->rpentry; return NULL; } rp_grp_entry_t *rp_grp_match(u_int32 group) { grp_mask_t *mask_ptr; rp_grp_entry_t *entry_ptr; rp_grp_entry_t *best_entry = NULL; u_int8 best_priority = ~0; /* Smaller is better */ u_int32 best_hash_value = 0; /* Bigger is better */ u_int32 best_address_h = 0; /* Bigger is better */ u_int32 curr_hash_value = 0; u_int32 curr_address_h = 0; u_int32 group_h = ntohl(group); if (grp_mask_list == NULL) return NULL; for (mask_ptr = grp_mask_list; mask_ptr; mask_ptr = mask_ptr->next) { /* Search the grp_mask (group_prefix) list */ if ((group_h & ntohl(mask_ptr->group_mask)) != ntohl(mask_ptr->group_mask & mask_ptr->group_addr)) continue; for (entry_ptr = mask_ptr->grp_rp_next; entry_ptr; entry_ptr = entry_ptr->grp_rp_next) { if (best_priority < entry_ptr->priority) break; curr_hash_value = RP_HASH_VALUE(group_h, mask_ptr->hash_mask, curr_address_h); curr_address_h = ntohl(entry_ptr->rp->rpentry->address); if (best_priority == entry_ptr->priority) { /* Compare the hash_value and then the addresses */ if (curr_hash_value < best_hash_value) continue; if (curr_hash_value == best_hash_value) { if (curr_address_h < best_address_h) continue; } } /* The current entry in the loop is preferred */ best_entry = entry_ptr; best_priority = best_entry->priority; best_address_h = curr_address_h; best_hash_value = curr_hash_value; } } return best_entry; } rpentry_t *rp_find(u_int32 rp_address) { cand_rp_t *cand_rp_ptr; u_int32 address_h = ntohl(rp_address); for(cand_rp_ptr = cand_rp_list; cand_rp_ptr != NULL; cand_rp_ptr = cand_rp_ptr->next) { if (ntohl(cand_rp_ptr->rpentry->address) > address_h) continue; if (cand_rp_ptr->rpentry->address == rp_address) return cand_rp_ptr->rpentry; return NULL; } return NULL; } /* * Create a bootstrap message in "send_buff" and returns the data size * (excluding the IP header and the PIM header) Can be used both by the * Bootstrap router to multicast the RP-set or by the DR to unicast it to * a new neighbor. It DOES NOT change any timers. */ int create_pim_bootstrap_message(char *send_buff) { u_int8 *data_ptr; grp_mask_t *mask_ptr; rp_grp_entry_t *entry_ptr; int datalen; u_int8 masklen; if (curr_bsr_address == INADDR_ANY_N) return 0; data_ptr = (u_int8 *)(send_buff + sizeof(struct ip) + sizeof(pim_header_t)); if (curr_bsr_address == my_bsr_address) curr_bsr_fragment_tag++; PUT_HOSTSHORT(curr_bsr_fragment_tag, data_ptr); MASK_TO_MASKLEN(curr_bsr_hash_mask, masklen); PUT_BYTE(masklen, data_ptr); PUT_BYTE(curr_bsr_priority, data_ptr); PUT_EUADDR(curr_bsr_address, data_ptr); /* TODO: XXX: No fragmentation support (yet) */ for (mask_ptr = grp_mask_list; mask_ptr; mask_ptr = mask_ptr->next) { MASK_TO_MASKLEN(mask_ptr->group_mask, masklen); PUT_EGADDR(mask_ptr->group_addr, masklen, 0, data_ptr); PUT_BYTE(mask_ptr->group_rp_number, data_ptr); PUT_BYTE(mask_ptr->group_rp_number, data_ptr); /* TODO: if frag.*/ PUT_HOSTSHORT(0, data_ptr); for (entry_ptr = mask_ptr->grp_rp_next; entry_ptr; entry_ptr = entry_ptr->grp_rp_next) { PUT_EUADDR(entry_ptr->rp->rpentry->address, data_ptr); PUT_HOSTSHORT(entry_ptr->holdtime, data_ptr); PUT_BYTE(entry_ptr->priority, data_ptr); PUT_BYTE(0, data_ptr); /* The reserved field */ } } datalen = (data_ptr - (u_int8 *)send_buff) - sizeof(struct ip) - sizeof(pim_header_t); return datalen; } /* * Check if the rp_addr is the RP for the group corresponding to mrtentry_ptr. * Return TRUE or FALSE. */ int check_mrtentry_rp(mrtentry_t *mrtentry_ptr, u_int32 rp_addr) { rp_grp_entry_t *ptr; if (mrtentry_ptr == NULL) return FALSE; if (rp_addr == INADDR_ANY_N) return FALSE; ptr = mrtentry_ptr->group->active_rp_grp; if (ptr == NULL) return FALSE; if (mrtentry_ptr->group->rpaddr == rp_addr) return TRUE; return FALSE; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/Makefile0000644000000000000000000001032311700261371010776 0ustar # -*-Makefile-*- # # Protocol Independent Multicast, Sparse-Mode version 2.0 # # 2010-08-21 Joachim Nilsson # * Cleanup unportable rules.mk and simplify for build # using BSD make, and similar. # # 2010-01-16 Joachim Nilsson # * Cleanup and refactoring for cross building. # # 2003-03-27 Antonin Kral # * Modified for Debian # # 2001-11-13 Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu) # * Original Makefile # # VERSION ?= $(shell git tag -l | tail -1) VERSION ?= 2.1.8 EXEC = pimd CONFIG = $(EXEC).conf PKG = $(EXEC)-$(VERSION) ARCHIVE = $(PKG).tar.bz2 ROOTDIR ?= $(dir $(shell pwd)) RM ?= rm -f CC ?= $(CROSS)gcc prefix ?= /usr/local sysconfdir ?= /etc datadir = $(prefix)/share/doc/pimd mandir = $(prefix)/share/man/man8 # Uncomment the following line if you want to use RSRR (Routing # Support for Resource Reservations), currently used by RSVP. #RSRRDEF = -DRSRR RSRR_OBJS = rsrr.o IGMP_OBJS = igmp.o igmp_proto.o trace.o ROUTER_OBJS = inet.o kern.o main.o config.o debug.o netlink.o routesock.o \ vers.o callout.o PIM_OBJS = route.o vif.o timer.o mrt.o pim.o pim_proto.o rp.o DVMRP_OBJS = dvmrp_proto.o # This magic trick looks like a comment, but works on BSD PMake #include include config.mk #include include snmp.mk ## Common CFLAGS += $(MCAST_INCLUDE) $(SNMPDEF) $(RSRRDEF) $(INCLUDES) $(DEFS) $(USERCOMPILE) CFLAGS += -O2 -W -Wall -Werror -fno-strict-aliasing #CFLAGS += -O -g LDLIBS = $(SNMPLIBDIR) $(SNMPLIBS) $(EXTRA_LIBS) OBJS = $(IGMP_OBJS) $(ROUTER_OBJS) $(PIM_OBJS) $(DVMRP_OBJS) \ $(SNMP_OBJS) $(RSRR_OBJS) $(EXTRA_OBJS) SRCS = $(OBJS:.o=.c) DEPS = $(addprefix .,$(SRCS:.c=.d)) MANS = $(addsuffix .8,$(EXEC)) DISTFILES = README README.config README.config.jp README.debug \ ChangeLog INSTALL LICENSE LICENSE.mrouted \ TODO CREDITS FAQ AUTHORS LINT = splint LINTFLAGS = $(MCAST_INCLUDE) $(filter-out -W -Wall -Werror, $(CFLAGS)) -posix-lib -weak -skipposixheaders PURIFY = purify PURIFYFLAGS = -cache-dir=/tmp -collector=/import/pkgs/gcc/lib/gcc-lib/sparc-sun-sunos4.1.3_U1/2.7.2.2/ld all: $(EXEC) .c.o: @printf " CC $@\n" @$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< $(EXEC): $(OBJS) @printf " LINK $@\n" @$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $(OBJS) $(LDLIBS) purify: $(OBJS) @$(PURIFY) $(PURIFYFLAGS) $(CC) $(LDFLAGS) -o $(EXEC) $(CFLAGS) $(OBJS) $(LDLIBS) vers.c: @echo $(VERSION) | sed -e 's/.*/char todaysversion[]="&";/' > vers.c install: $(EXEC) @install -d $(DESTDIR)$(prefix)/sbin @install -d $(DESTDIR)$(sysconfdir) @install -d $(DESTDIR)$(datadir) @install -d $(DESTDIR)$(mandir) @install -m 0755 $(EXEC) $(DESTDIR)$(prefix)/sbin/$(EXEC) @install -b -m 0644 $(CONFIG) $(DESTDIR)$(sysconfdir)/$(CONFIG) @for file in $(DISTFILES); do \ install -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \ done @for file in $(MANS); do \ install -m 0644 $$file $(DESTDIR)$(mandir)/$$file; \ done uninstall: -@$(RM) $(DESTDIR)$(prefix)/sbin/$(EXEC) -@$(RM) $(DESTDIR)$(sysconfdir)/$(CONFIG) -@$(RM) -r $(DESTDIR)$(datadir) -@for file in $(MANS); do \ $(RM) $(DESTDIR)$(mandir)/$$file; \ done clean: $(SNMPCLEAN) -@$(RM) $(OBJS) $(EXEC) distclean: -@$(RM) $(OBJS) core $(EXEC) vers.c tags TAGS *.o *.map .*.d *.out tags TAGS dist: @echo "Building bzip2 tarball of $(PKG) in parent dir..." git archive --format=tar --prefix=$(PKG)/ $(VERSION) | bzip2 >../$(ARCHIVE) @(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5) build-deb: @echo "Building .deb if $(PKG)..." git-buildpackage --git-ignore-new --git-upstream-branch=master lint: @$(LINT) $(LINTFLAGS) $(SRCS) tags: $(SRCS) @ctags $(SRCS) cflow: @cflow $(MCAST_INCLUDE) $(SRCS) > cflow.out cflow2: @cflow -ix $(MCAST_INCLUDE) $(SRCS) > cflow2.out rcflow: @cflow -r $(MCAST_INCLUDE) $(SRCS) > rcflow.out rcflow2: @cflow -r -ix $(MCAST_INCLUDE) $(SRCS) > rcflow2.out TAGS: @etags $(SRCS) snmpd/libsnmpd.a: @make -C snmpd snmplib/libsnmp.a: @make -C snmplib snmpclean: @for dir in snmpd snmplib; do \ make -C $$dir clean; \ done pimd-2.1.8/snmp.mk0000644000000000000000000000053011700261371010643 0ustar # TODO: XXX: CURRENTLY SNMP NOT SUPPORTED!!!! # # Uncomment the following eight lines if you want to use David Thaler's # CMU SNMP daemon support. # #SNMPDEF= -DSNMP #SNMPLIBDIR= -Lsnmpd -Lsnmplib #SNMPLIBS= -lsnmpd -lsnmp #CMULIBS= snmpd/libsnmpd.a snmplib/libsnmp.a #MSTAT= mstat #SNMP_SRCS= snmp.c #SNMP_OBJS= snmp.o #SNMPCLEAN= snmpclean pimd-2.1.8/pim.c0000644000000000000000000003207511700261371010277 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: pim.c,v 1.24 2002/09/26 00:59:30 pavlin Exp $ */ #include "defs.h" /* * Exported variables. */ char *pim_recv_buf; /* input packet buffer */ char *pim_send_buf; /* output packet buffer */ u_int32 allpimrouters_group; /* ALL_PIM_ROUTERS address in net order */ int pim_socket; /* socket for PIM control msgs */ #ifdef RAW_OUTPUT_IS_RAW extern int curttl; #endif /* RAW_OUTPUT_IS_RAW */ /* * Local function definitions. */ static void pim_read (int f, fd_set *rfd); static void accept_pim (ssize_t recvlen); void init_pim(void) { struct ip *ip; /* Setup the PIM raw socket */ if ((pim_socket = socket(AF_INET, SOCK_RAW, IPPROTO_PIM)) < 0) logit(LOG_ERR, errno, "Failed creating PIM socket"); k_hdr_include(pim_socket, TRUE); /* include IP header when sending */ k_set_sndbuf(pim_socket, SO_SEND_BUF_SIZE_MAX, SO_SEND_BUF_SIZE_MIN); /* lots of output buffering */ k_set_rcvbuf(pim_socket, SO_RECV_BUF_SIZE_MAX, SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */ k_set_ttl(pim_socket, MINTTL); /* restrict multicasts to one hop */ k_set_loop(pim_socket, FALSE); /* disable multicast loopback */ allpimrouters_group = htonl(INADDR_ALL_PIM_ROUTERS); pim_recv_buf = calloc(1, RECV_BUF_SIZE); pim_send_buf = calloc(1, SEND_BUF_SIZE); if (!pim_recv_buf || !pim_send_buf) logit(LOG_ERR, 0, "Ran out of memory in init_pim()"); /* One time setup in the buffers */ ip = (struct ip *)pim_send_buf; memset(ip, 0, sizeof(*ip)); ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); ip->ip_tos = 0; /* TODO: setup?? */ ip->ip_id = 0; /* let kernel fill in */ ip->ip_off = 0; ip->ip_p = IPPROTO_PIM; #ifdef old_Linux ip->ip_csum = 0; /* let kernel fill in */ #else ip->ip_sum = 0; /* let kernel fill in */ #endif /* old_Linux */ if (register_input_handler(pim_socket, pim_read) < 0) logit(LOG_ERR, 0, "Failed registering pim_read() as an input handler"); /* Initialize the building Join/Prune messages working area */ build_jp_message_pool = (build_jp_message_t *)NULL; build_jp_message_pool_counter = 0; } /* Read a PIM message */ static void pim_read(int f __attribute__((unused)), fd_set *rfd __attribute__((unused))) { ssize_t len; socklen_t dummy = 0; #if defined(SYSV) || defined(__USE_SVID) sigset_t block, oblock; #else int omask; #endif while ((len = recvfrom(pim_socket, pim_recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_ERR, errno, "Failed recvfrom() in pim_read()"); return; } #if defined(SYSV) || defined(__USE_SVID) (void)sigemptyset(&block); (void)sigaddset(&block, SIGALRM); if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0) logit(LOG_ERR, errno, "sigprocmask"); #else /* Use of omask taken from main() */ omask = sigblock(sigmask(SIGALRM)); #endif /* SYSV */ accept_pim(len); #if defined(SYSV) || defined(__USE_SVID) (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL); #else (void)sigsetmask(omask); #endif /* SYSV */ } static void accept_pim(ssize_t recvlen) { u_int32 src, dst; struct ip *ip; pim_header_t *pim; int iphdrlen, pimlen; if (recvlen < (ssize_t)sizeof(struct ip)) { logit(LOG_WARNING, 0, "packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)pim_recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; iphdrlen = ip->ip_hl << 2; pim = (pim_header_t *)(pim_recv_buf + iphdrlen); pimlen = recvlen - iphdrlen; if (pimlen < (ssize_t)sizeof(*pim)) { logit(LOG_WARNING, 0, "IP data field too short (%u bytes) for PIM header, from %s to %s", pimlen, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return; } #if 0 /* TODO: delete. Too noisy */ IF_DEBUG(DEBUG_PIM_DETAIL) { IF_DEBUG(DEBUG_PIM) { logit(LOG_DEBUG, 0, "Receiving %s from %-15s to %s ", packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); logit(LOG_DEBUG, 0, "PIM type is %u", pim->pim_type); } } #endif /* 0 */ /* TODO: Check PIM version */ /* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address) */ /* TODO: Checksum verification is done in each of the processing functions. * No need for checksum, if already done in the kernel? */ switch (pim->pim_type) { case PIM_HELLO: receive_pim_hello(src, dst, (char *)(pim), pimlen); break; case PIM_REGISTER: receive_pim_register(src, dst, (char *)(pim), pimlen); break; case PIM_REGISTER_STOP: receive_pim_register_stop(src, dst, (char *)(pim), pimlen); break; case PIM_JOIN_PRUNE: receive_pim_join_prune(src, dst, (char *)(pim), pimlen); break; case PIM_BOOTSTRAP: receive_pim_bootstrap(src, dst, (char *)(pim), pimlen); break; case PIM_ASSERT: receive_pim_assert(src, dst, (char *)(pim), pimlen); break; case PIM_GRAFT: case PIM_GRAFT_ACK: logit(LOG_INFO, 0, "ignore %s from %s to %s", packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); case PIM_CAND_RP_ADV: receive_pim_cand_rp_adv(src, dst, (char *)(pim), pimlen); break; default: logit(LOG_INFO, 0, "ignore unknown PIM message code %u from %s to %s", pim->pim_type, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); break; } } /* * Send a multicast PIM packet from src to dst, PIM message type = "type" * and data length (after the PIM header) = "datalen" */ void send_pim(char *buf, u_int32 src, u_int32 dst, int type, int datalen) { struct sockaddr_in sdst; struct ip *ip; pim_header_t *pim; int sendlen; int setloop = 0; /* Prepare the IP header */ ip = (struct ip *)buf; ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; ip->ip_ttl = MAXTTL; /* applies to unicast only */ sendlen = ip->ip_len; #if defined(RAW_OUTPUT_IS_RAW) || defined(OpenBSD) ip->ip_len = htons(ip->ip_len); #endif /* RAW_OUTPUT_IS_RAW || OpenBSD */ /* Prepare the PIM packet */ pim = (pim_header_t *)(buf + sizeof(struct ip)); pim->pim_type = type; pim->pim_vers = PIM_PROTOCOL_VERSION; pim->pim_reserved = 0; pim->pim_cksum = 0; /* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the * encapsulated packet from the checsum. */ pim->pim_cksum = inet_cksum((u_int16 *)pim, sizeof(pim_header_t) + datalen); if (IN_MULTICAST(ntohl(dst))) { k_set_if(pim_socket, src); if ((dst == allhosts_group) || (dst == allrouters_group) || (dst == allpimrouters_group)) { setloop = 1; k_set_loop(pim_socket, TRUE); } #ifdef RAW_OUTPUT_IS_RAW ip->ip_ttl = curttl; } else { ip->ip_ttl = MAXTTL; #endif /* RAW_OUTPUT_IS_RAW */ } memset(&sdst, 0, sizeof(sdst)); sdst.sin_family = AF_INET; #ifdef HAVE_SA_LEN sdst.sin_len = sizeof(sdst); #endif sdst.sin_addr.s_addr = dst; while (sendto(pim_socket, buf, sendlen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ else if (errno == ENETDOWN) check_vif_state(); else logit(LOG_WARNING, errno, "sendto from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); if (setloop) k_set_loop(pim_socket, FALSE); return; } if (setloop) k_set_loop(pim_socket, FALSE); IF_DEBUG(DEBUG_PIM_DETAIL) { IF_DEBUG(DEBUG_PIM) { logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s", packet_kind(IPPROTO_PIM, type, 0), src == INADDR_ANY_N ? "INADDR_ANY" : inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } } } u_int pim_send_cnt = 0; #define SEND_DEBUG_NUMBER 50 /* TODO: This can be merged with the above procedure */ /* * Send an unicast PIM packet from src to dst, PIM message type = "type" * and data length (after the PIM common header) = "datalen" */ void send_pim_unicast(char *buf, u_int32 src, u_int32 dst, int type, int datalen) { struct sockaddr_in sdst; struct ip *ip; pim_header_t *pim; int sendlen; /* Prepare the IP header */ ip = (struct ip *)buf; ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; sendlen = ip->ip_len; /* TODO: XXX: setup the TTL from the inner mcast packet? */ ip->ip_ttl = MAXTTL; #if defined(RAW_OUTPUT_IS_RAW) || defined(OpenBSD) ip->ip_len = htons(ip->ip_len); #endif /* RAW_OUTPUT_IS_RAW || OpenBSD */ /* Prepare the PIM packet */ pim = (pim_header_t *)(buf + sizeof(struct ip)); pim->pim_vers = PIM_PROTOCOL_VERSION; pim->pim_type = type; pim->pim_reserved = 0; pim->pim_cksum = 0; /* XXX: The PIM_REGISTERs don't include the encapsulated * inner packet in the checksum. * Well, try to explain this to cisco... * If your RP is cisco and if it shows many PIM_REGISTER checksum * errors from this router, then #define BROKEN_CISCO_CHECKSUM here * or in your Makefile. * Note that such checksum is not in the spec, and such PIM_REGISTERS * may be dropped by some implementations (pimd should be OK). */ #ifdef BROKEN_CISCO_CHECKSUM pim->pim_cksum = inet_cksum((u_int16 *)pim, sizeof(pim_header_t) + datalen); #else /* !BROKEN_CISCO_CHECKSUM */ if (PIM_REGISTER == type) { pim->pim_cksum = inet_cksum((u_int16 *)pim, sizeof(pim_header_t) + sizeof(pim_register_t)); } else { pim->pim_cksum = inet_cksum((u_int16 *)pim, sizeof(pim_header_t) + datalen); } #endif /* !BROKEN_CISCO_CHECKSUM */ memset(&sdst, 0, sizeof(sdst)); sdst.sin_family = AF_INET; #ifdef HAVE_SA_LEN sdst.sin_len = sizeof(sdst); #endif sdst.sin_addr.s_addr = dst; while (sendto(pim_socket, buf, sendlen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ else if (errno == ENETDOWN) check_vif_state(); else logit(LOG_WARNING, errno, "sendto from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } IF_DEBUG(DEBUG_PIM_DETAIL) { IF_DEBUG(DEBUG_PIM) { /* TODO: use pim_send_cnt ? if (++pim_send_cnt > SEND_DEBUG_NUMBER) { pim_send_cnt = 0; logit(LOG_DEBUG, 0, "sending %s from %-15s to %s", packet_kind(IPPROTO_PIM, type, 0), inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } */ logit(LOG_DEBUG, 0, "sending %s from %-15s to %s", packet_kind(IPPROTO_PIM, type, 0), inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } } } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/LICENSE0000644000000000000000000000364111700261371010350 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: LICENSE,v 1.5 2001/09/10 20:31:36 pavlin Exp $ */ /* * 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. * */ pimd-2.1.8/README.config0000644000000000000000000001065011700261371011465 0ustar $Id: README.config,v 1.4 2002/06/13 17:39:19 pavlin Exp $ This is README.config for pimd, the PIM multicast daemon. PIM-SM version: 2 Check http://netweb.usc.edu/pim/pimd/ for lastest pimd version. This file describes the pimd configuration. For a Japanese version of this file, see README.config.jp XXX: currently, this file is very incomplete. If something is missing and/or is unclear, send email to the current maintainer of pimd (see file README for email address). 1. Configuring GRE tunnels for multicast routing (based on information contributed by Hiroyuki Komatsu ) On Linux (Debian) try the following: (If you are configuring the particular gre interfaces for first time, ignore the errors after "ip link set gre1 down" and "ip tunnel del gre1") 1.1 GRE tunnel between two machines (host 11.11.11.11 and 33.33.33.33) Physical interfaces: [11.11.11.11] [33.33.33.33] GRE tunnel: 22.22.22.11<--------->22.22.22.33 ==== host 11.11.11.11 (GRE interface 22.22.22.11) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip link set gre1 down ip tunnel del gre1 ip tunnel add gre1 mode gre remote 33.33.33.33 local 11.11.11.11 ttl 127 ip addr add 22.22.22.11/24 peer 22.22.22.33/24 dev gre1 ip link set gre1 up multicast on ==== host 33.33.33.33 (GRE interface 22.22.22.33) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip link set gre1 down ip tunnel del gre1 ip tunnel add gre1 mode gre remote 11.11.11.11 local 33.33.33.33 ttl 127 ip addr add 22.22.22.33/24 peer 22.22.22.11/24 dev gre1 ip link set gre1 up multicast on 1.2 GRE tunnels with three machines STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!! IF YOU ADD MORE THAN TWO GRE TUNNELS IN A CHAIN, IT IS VERY EASY TO CREATE UNICAST ROUTING LOOPS, AND THIS MAY LEAD TO MULTICAST ROUTING LOOPS. MULTICAST ROUTING LOOP IS A DISASTER THAT MAY BRING YOUR WHOLE NETWORK DOWN. BEFORE ATTEMPTING THIS CONFIGURATION, MAKE SURE YOU UNDERSTAND VERY WELL WHAT YOU ARE DOING, AND WHAT MAY HAPPEN. IF YOU ARE READING THIS, THE CHANCES ARE THAT YOU DON'T KNOW, SO THINK AGAIN!! THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!! Physical interfaces: [11.11.11.11] [33.33.33.33] [55.55.55.55] GRE tunnels: 22.22.22.11 <--> 22.22.22.33 44.44.44.33 <--> 44.44.44.55 ==== host 33.33.33.33 (GRE interfaces 22.22.22.33 and 44.44.44.33) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 11.11.11.11 local 33.33.33.33 ttl 127 ip addr add 22.22.22.33/24 peer 22.22.22.11/24 dev gre1 ip link set gre1 up multicast on ip tunnel add gre2 mode gre remote 55.55.55.55 local 33.33.33.33 ttl 127 ip addr add 44.44.44.33/24 peer 44.44.44.55/24 dev gre2 ip link set gre2 up multicast on ==== host 55.55.55.55 (GRE interface 44.44.44.55) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 33.33.33.33 local 55.55.55.55 ttl 127 ip addr add 44.44.44.55/24 peer 44.44.44.33/24 dev gre1 ip link set gre1 up multicast on route add -net 22.22.22.0 netmask 255.255.255.0 gw 44.44.44.33 gre1 ==== host 11.11.11.11 (GRE interface 22.22.22.11) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 33.33.33.33 local 11.11.11.11 ttl 127 ip addr add 22.22.22.11/24 peer 22.22.22.33/24 dev gre1 ip link set gre1 up multicast on route add -net 44.44.44.0 netmask 255.255.255.0 gw 22.22.22.33 gre1 2. Configuring pimd For a complete list of all available options, see pimd.conf 2.1. How to disable pimd being Cand-RP? Comment-out the "cand_rp" and "group_prefix" lines 2.2. How to disable pimd being Cand-BSR? Comment-out the "cand_bootstrap_router" line 2.3. How to prevent a prefix of multicast addresses being routed through my multicast router? If you want to scope, say, prefixes 238.0.0.0/8 and 239.0.0.0/8, add the following lines to pimd.conf: phyint eth1 scoped 238.0.0.0 masklen 8 phyint eth1 scoped 239.0.0.0 masklen 8 2.4. How to create a scope zone and stop multicast packets for some multicast prefix being propagated beyond the boundary of my network? Add scoping filters on your border routers for each prefix you want to scope. E.g.: phyint eth1 scoped 239.0.0.0 masklen 8 pimd-2.1.8/debug.c0000644000000000000000000006750311700261371010604 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: debug.c,v 1.22 2001/11/28 00:13:50 pavlin Exp $ */ /* * 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 "defs.h" #include #include int log_nmsgs = 0; unsigned long debug = 0x00000000; /* If (long) is smaller than * 4 bytes, then we are in * trouble. */ static char dumpfilename[] = _PATH_PIMD_DUMP; static char cachefilename[] = _PATH_PIMD_CACHE; /* TODO: notused */ char *packet_kind(u_int proto, u_int type, u_int code) { static char unknown[60]; switch (proto) { case IPPROTO_IGMP: switch (type) { case IGMP_MEMBERSHIP_QUERY: return "IGMP Membership Query "; case IGMP_V1_MEMBERSHIP_REPORT:return "IGMP v1 Member Report "; case IGMP_V2_MEMBERSHIP_REPORT:return "IGMP v2 Member Report "; case IGMP_V2_LEAVE_GROUP: return "IGMP Leave message "; case IGMP_DVMRP: switch (code) { case DVMRP_PROBE: return "DVMRP Neighbor Probe "; case DVMRP_REPORT: return "DVMRP Route Report "; case DVMRP_ASK_NEIGHBORS: return "DVMRP Neighbor Request "; case DVMRP_NEIGHBORS: return "DVMRP Neighbor List "; case DVMRP_ASK_NEIGHBORS2: return "DVMRP Neighbor request 2 "; case DVMRP_NEIGHBORS2: return "DVMRP Neighbor list 2 "; case DVMRP_PRUNE: return "DVMRP Prune message "; case DVMRP_GRAFT: return "DVMRP Graft message "; case DVMRP_GRAFT_ACK: return "DVMRP Graft message ack "; case DVMRP_INFO_REQUEST: return "DVMRP Info Request "; case DVMRP_INFO_REPLY: return "DVMRP Info Reply "; default: snprintf(unknown, sizeof(unknown), "UNKNOWN DVMRP message code = %3d ", code); return unknown; } case IGMP_PIM: /* The old style (PIM v1) encapsulation of PIM messages * inside IGMP messages. */ /* PIM v1 is not implemented but we just inform that a message * has arrived. */ switch (code) { case PIM_V1_QUERY: return "PIM v1 Router-Query "; case PIM_V1_REGISTER: return "PIM v1 Register "; case PIM_V1_REGISTER_STOP: return "PIM v1 Register-Stop "; case PIM_V1_JOIN_PRUNE: return "PIM v1 Join/Prune "; case PIM_V1_RP_REACHABILITY: return "PIM v1 RP-Reachability "; case PIM_V1_ASSERT: return "PIM v1 Assert "; case PIM_V1_GRAFT: return "PIM v1 Graft "; case PIM_V1_GRAFT_ACK: return "PIM v1 Graft_Ack "; default: snprintf(unknown, sizeof(unknown), "UNKNOWN PIM v1 message type =%3d ", code); return unknown; } case IGMP_MTRACE: return "IGMP trace query "; case IGMP_MTRACE_RESP: return "IGMP trace reply "; default: snprintf(unknown, sizeof (unknown), "UNKNOWN IGMP message: type = 0x%02x, code = 0x%02x ", type, code); return unknown; } case IPPROTO_PIM: /* PIM v2 */ switch (type) { case PIM_V2_HELLO: return "PIM v2 Hello "; case PIM_V2_REGISTER: return "PIM v2 Register "; case PIM_V2_REGISTER_STOP: return "PIM v2 Register_Stop "; case PIM_V2_JOIN_PRUNE: return "PIM v2 Join/Prune "; case PIM_V2_BOOTSTRAP: return "PIM v2 Bootstrap "; case PIM_V2_ASSERT: return "PIM v2 Assert "; case PIM_V2_GRAFT: return "PIM-DM v2 Graft "; case PIM_V2_GRAFT_ACK: return "PIM-DM v2 Graft_Ack "; case PIM_V2_CAND_RP_ADV: return "PIM v2 Cand. RP Adv. "; default: snprintf(unknown, sizeof(unknown), "UNKNOWN PIM v2 message type =%3d ", type); return unknown; } default: snprintf(unknown, sizeof(unknown), "UNKNOWN proto =%3d ", proto); return unknown; } } /* * Used for debugging particular type of messages. */ int debug_kind(u_int proto, u_int type, u_int code) { switch (proto) { case IPPROTO_IGMP: switch (type) { case IGMP_MEMBERSHIP_QUERY: return DEBUG_IGMP; case IGMP_V1_MEMBERSHIP_REPORT: return DEBUG_IGMP; case IGMP_V2_MEMBERSHIP_REPORT: return DEBUG_IGMP; case IGMP_V2_LEAVE_GROUP: return DEBUG_IGMP; case IGMP_DVMRP: switch (code) { case DVMRP_PROBE: return DEBUG_DVMRP_PEER; case DVMRP_REPORT: return DEBUG_DVMRP_ROUTE; case DVMRP_ASK_NEIGHBORS: return 0; case DVMRP_NEIGHBORS: return 0; case DVMRP_ASK_NEIGHBORS2: return 0; case DVMRP_NEIGHBORS2: return 0; case DVMRP_PRUNE: return DEBUG_DVMRP_PRUNE; case DVMRP_GRAFT: return DEBUG_DVMRP_PRUNE; case DVMRP_GRAFT_ACK: return DEBUG_DVMRP_PRUNE; case DVMRP_INFO_REQUEST: return 0; case DVMRP_INFO_REPLY: return 0; default: return 0; } case IGMP_PIM: /* PIM v1 is not implemented */ switch (code) { case PIM_V1_QUERY: return DEBUG_PIM; case PIM_V1_REGISTER: return DEBUG_PIM; case PIM_V1_REGISTER_STOP: return DEBUG_PIM; case PIM_V1_JOIN_PRUNE: return DEBUG_PIM; case PIM_V1_RP_REACHABILITY: return DEBUG_PIM; case PIM_V1_ASSERT: return DEBUG_PIM; case PIM_V1_GRAFT: return DEBUG_PIM; case PIM_V1_GRAFT_ACK: return DEBUG_PIM; default: return DEBUG_PIM; } case IGMP_MTRACE: return DEBUG_TRACE; case IGMP_MTRACE_RESP: return DEBUG_TRACE; default: return DEBUG_IGMP; } case IPPROTO_PIM: /* PIM v2 */ /* TODO: modify? */ switch (type) { case PIM_V2_HELLO: return DEBUG_PIM; case PIM_V2_REGISTER: return DEBUG_PIM_REGISTER; case PIM_V2_REGISTER_STOP: return DEBUG_PIM_REGISTER; case PIM_V2_JOIN_PRUNE: return DEBUG_PIM; case PIM_V2_BOOTSTRAP: return DEBUG_PIM_BOOTSTRAP; case PIM_V2_ASSERT: return DEBUG_PIM; case PIM_V2_GRAFT: return DEBUG_PIM; case PIM_V2_GRAFT_ACK: return DEBUG_PIM; case PIM_V2_CAND_RP_ADV: return DEBUG_PIM_CAND_RP; default: return DEBUG_PIM; } default: return 0; } return 0; } /* * Some messages are more important than others. This routine * determines the logging level at which to log a send error (often * "No route to host"). This is important when there is asymmetric * reachability and someone is trying to, i.e., mrinfo me periodically. */ int log_level(proto, type, code) u_int proto, type, code; { switch (proto) { case IPPROTO_IGMP: switch (type) { case IGMP_MTRACE_RESP: return LOG_INFO; case IGMP_DVMRP: switch (code) { case DVMRP_NEIGHBORS: case DVMRP_NEIGHBORS2: return LOG_INFO; } case IGMP_PIM: /* PIM v1 */ switch (code) { default: return LOG_INFO; } default: return LOG_WARNING; } case IPPROTO_PIM: /* PIM v2 */ switch (type) { default: return LOG_INFO; } default: return LOG_WARNING; } return LOG_WARNING; } /* * Dump internal data structures to stderr. */ /* TODO: currently not used void dump(int i) { dump_vifs(stderr); dump_pim_mrt(stderr); } */ /* * Dump internal data structures to a file. */ void fdump(int i __attribute__((unused))) { FILE *fp; fp = fopen(dumpfilename, "w"); if (fp != NULL) { dump_vifs(fp); dump_pim_mrt(fp); (void) fclose(fp); } } /* TODO: dummy, to be used in the future. */ /* * Dump local cache contents to a file. */ void cdump(int i __attribute__((unused))) { FILE *fp; fp = fopen(cachefilename, "w"); if (fp != NULL) { /* XXX: TODO: implement it: dump_cache(fp); */ (void) fclose(fp); } } void dump_vifs(FILE *fp) { vifi_t vifi; register struct uvif *v; pim_nbr_entry_t *n; int width; int i; fprintf(fp, "\nVirtual Interface Table\n %-3s %-15s %-20s %-8s %-14s %s", "Vif", "Local-Address", "Subnet", "Thresh", "Flags", "Neighbors\n"); for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { fprintf(fp, " %3u %-15s ", vifi, inet_fmt(v->uv_lcl_addr, s1, sizeof(s1))); if (v->uv_flags & VIFF_REGISTER) fprintf(fp, "%-20s ", v->uv_name); else fprintf(fp,"%-20.20s ", netname(v->uv_subnet, v->uv_subnetmask)); fprintf(fp, "%-5u ", v->uv_threshold); /* TODO: XXX: Print VIFF_TUNNEL? */ width = 0; if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " DISABLED"); if (v->uv_flags & VIFF_DOWN) fprintf(fp, " DOWN"); if (v->uv_flags & VIFF_DR) { fprintf(fp, " DR"); width += 3; } if (v->uv_flags & VIFF_PIM_NBR) { fprintf(fp, " PIM"); width += 4; } if (v->uv_flags & VIFF_DVMRP_NBR) { fprintf(fp, " DVMRP"); width += 6; } if (v->uv_flags & VIFF_NONBRS) { fprintf(fp, " %-12s", "NO-NBR"); width += 6; } if ((n = v->uv_pim_neighbors) != NULL) { /* Print the first neighbor on the same line */ for (i = width; i <= 15; i++) fprintf(fp, " "); fprintf(fp, "%-15s\n", inet_fmt(n->address, s1, sizeof(s1))); for (n = n->next; n != NULL; n = n->next) fprintf(fp, "%64s %-15s\n", "", inet_fmt(n->address, s1, sizeof(s1))); } else fprintf(fp, "\n"); } fprintf(fp, "\n"); } /* * Log errors and other messages to the system log daemon and to stderr, * according to the severity of the message and the current debug level. * For errors of severity LOG_ERR or worse, terminate the program. */ void logit(int severity, int syserr, const char *format, ...) { va_list ap; static char fmt[211] = "warning - "; char *msg; struct timeval now; struct tm *thyme; time_t lt; va_start(ap, format); vsnprintf(&fmt[10], sizeof(fmt) - 10, format, ap); va_end(ap); msg = (severity == LOG_WARNING) ? fmt : &fmt[10]; /* * Log to stderr if we haven't forked yet and it's a warning or worse, * or if we're debugging. */ if (haveterminal && (debug || severity <= LOG_WARNING)) { gettimeofday(&now, NULL); lt = now.tv_sec; thyme = localtime(<); if (!debug) fprintf(stderr, "%s: ", __progname); fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour, thyme->tm_min, thyme->tm_sec, (long int)(now.tv_usec / 1000), msg); if (syserr == 0) fprintf(stderr, "\n"); else fprintf(stderr, ":(error %d): %s\n", syserr, strerror(syserr)); } /* * Always log things that are worse than warnings, no matter what * the log_nmsgs rate limiter says. * Only count things worse than debugging in the rate limiter * (since if you put daemon.debug in syslog.conf you probably * actually want to log the debugging messages so they shouldn't * be rate-limited) */ if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) { if (severity < LOG_DEBUG) log_nmsgs++; if (syserr != 0) { errno = syserr; syslog(severity, "%s: %s", msg, strerror(syserr)); } else { syslog(severity, "%s", msg); } } if (severity <= LOG_ERR) exit(-1); } /* TODO: format the output for better readability */ void dump_pim_mrt(FILE *fp) { grpentry_t *g; register mrtentry_t *r; register vifi_t vifi; u_int number_of_cache_mirrors = 0; u_int number_of_groups = 0; char oifs[(sizeof(vifbitmap_t)<<3)+1]; char joined_oifs[(sizeof(vifbitmap_t)<<3)+1]; char pruned_oifs[(sizeof(vifbitmap_t)<<3)+1]; char leaves_oifs[(sizeof(vifbitmap_t)<<3)+1]; char asserted_oifs[(sizeof(vifbitmap_t)<<3)+1]; char incoming_iif[(sizeof(vifbitmap_t)<<3)+1]; cand_rp_t *rp; kernel_cache_t *kernel_cache; fprintf(fp, "Multicast Routing Table\n%s", " Source Group RP-addr Flags\n"); /* TODO: remove the dummy 0.0.0.0 group (first in the chain) */ for (g = grplist->next; g != (grpentry_t *)NULL; g = g->next) { number_of_groups++; if ((r = g->grp_route) != (mrtentry_t *)NULL) { if (r->flags & MRTF_KERNEL_CACHE) { for (kernel_cache = r->kernel_cache; kernel_cache != (kernel_cache_t *)NULL; kernel_cache = kernel_cache->next) number_of_cache_mirrors++; } /* Print the (*,G) routing info */ fprintf(fp, "---------------------------(*,G)----------------------------\n"); fprintf(fp, " %-15s", "INADDR_ANY"); fprintf(fp, " %-15s", inet_fmt(g->group, s1, sizeof(s1))); fprintf(fp, " %-15s", g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"); for (vifi = 0; vifi < numvifs; vifi++) { oifs[vifi] = VIFM_ISSET(vifi, r->oifs) ? 'o' : '.'; joined_oifs[vifi] = VIFM_ISSET(vifi, r->joined_oifs) ? 'j' : '.'; pruned_oifs[vifi] = VIFM_ISSET(vifi, r->pruned_oifs) ? 'p' : '.'; leaves_oifs[vifi] = VIFM_ISSET(vifi, r->leaves) ? 'l' : '.'; asserted_oifs[vifi] = VIFM_ISSET(vifi, r->asserted_oifs) ? 'a' : '.'; incoming_iif[vifi] = '.'; } oifs[vifi] = 0x0; /* End of string */ joined_oifs[vifi] = 0x0; pruned_oifs[vifi] = 0x0; leaves_oifs[vifi] = 0x0; asserted_oifs[vifi] = 0x0; incoming_iif[vifi] = 0x0; incoming_iif[r->incoming] = 'I'; /* TODO: don't need some of the flags */ if (r->flags & MRTF_SPT) fprintf(fp, " SPT"); if (r->flags & MRTF_WC) fprintf(fp, " WC"); if (r->flags & MRTF_RP) fprintf(fp, " RP"); if (r->flags & MRTF_REGISTER) fprintf(fp, " REG"); if (r->flags & MRTF_IIF_REGISTER) fprintf(fp, " IIF_REG"); if (r->flags & MRTF_NULL_OIF) fprintf(fp, " NULL_OIF"); if (r->flags & MRTF_KERNEL_CACHE) fprintf(fp, " CACHE"); if (r->flags & MRTF_ASSERTED) fprintf(fp, " ASSERTED"); if (r->flags & MRTF_REG_SUPP) fprintf(fp, " REG_SUPP"); if (r->flags & MRTF_SG) fprintf(fp, " SG"); if (r->flags & MRTF_PMBR) fprintf(fp, " PMBR"); fprintf(fp, "\n"); fprintf(fp, "Joined oifs: %-20s\n", joined_oifs); fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs); fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs); fprintf(fp, "Asserted oifs: %-20s\n", asserted_oifs); fprintf(fp, "Outgoing oifs: %-20s\n", oifs); fprintf(fp, "Incoming : %-20s\n", incoming_iif); fprintf(fp, "\nTIMERS: Entry JP RS Assert VIFS:"); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", vifi); fprintf(fp, "\n %d %d %d %d ", r->timer, r->jp_timer, r->rs_timer, r->assert_timer); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", r->vif_timers[vifi]); fprintf(fp, "\n"); } /* Print all (S,G) routing info */ for (r = g->mrtlink; r != (mrtentry_t *)NULL; r = r->grpnext) { fprintf(fp, "---------------------------(S,G)----------------------------\n"); if (r->flags & MRTF_KERNEL_CACHE) number_of_cache_mirrors++; /* Print the routing info */ fprintf(fp, " %-15s", inet_fmt(r->source->address, s1, sizeof(s1))); fprintf(fp, " %-15s", inet_fmt(g->group, s2, sizeof(s2))); fprintf(fp, " %-15s", g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"); for (vifi = 0; vifi < numvifs; vifi++) { oifs[vifi] = VIFM_ISSET(vifi, r->oifs) ? 'o' : '.'; joined_oifs[vifi] = VIFM_ISSET(vifi, r->joined_oifs) ? 'j' : '.'; pruned_oifs[vifi] = VIFM_ISSET(vifi, r->pruned_oifs) ? 'p' : '.'; leaves_oifs[vifi] = VIFM_ISSET(vifi, r->leaves) ? 'l' : '.'; asserted_oifs[vifi] = VIFM_ISSET(vifi, r->asserted_oifs) ? 'a' : '.'; incoming_iif[vifi] = '.'; } oifs[vifi] = 0x0; /* End of string */ joined_oifs[vifi] = 0x0; pruned_oifs[vifi] = 0x0; leaves_oifs[vifi] = 0x0; asserted_oifs[vifi] = 0x0; incoming_iif[vifi] = 0x0; incoming_iif[r->incoming] = 'I'; /* TODO: don't need some of the flags */ if (r->flags & MRTF_SPT) fprintf(fp, " SPT"); if (r->flags & MRTF_WC) fprintf(fp, " WC"); if (r->flags & MRTF_RP) fprintf(fp, " RP"); if (r->flags & MRTF_REGISTER) fprintf(fp, " REG"); if (r->flags & MRTF_IIF_REGISTER) fprintf(fp, " IIF_REG"); if (r->flags & MRTF_NULL_OIF) fprintf(fp, " NULL_OIF"); if (r->flags & MRTF_KERNEL_CACHE) fprintf(fp, " CACHE"); if (r->flags & MRTF_ASSERTED) fprintf(fp, " ASSERTED"); if (r->flags & MRTF_REG_SUPP) fprintf(fp, " REG_SUPP"); if (r->flags & MRTF_SG) fprintf(fp, " SG"); if (r->flags & MRTF_PMBR) fprintf(fp, " PMBR"); fprintf(fp, "\n"); fprintf(fp, "Joined oifs: %-20s\n", joined_oifs); fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs); fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs); fprintf(fp, "Asserted oifs: %-20s\n", asserted_oifs); fprintf(fp, "Outgoing oifs: %-20s\n", oifs); fprintf(fp, "Incoming : %-20s\n", incoming_iif); fprintf(fp, "\nTIMERS: Entry JP RS Assert VIFS:"); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", vifi); fprintf(fp, "\n %d %d %d %d ", r->timer, r->jp_timer, r->rs_timer, r->assert_timer); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", r->vif_timers[vifi]); fprintf(fp, "\n"); } }/* for all groups */ /* Print the (*,*,R) routing entries */ fprintf(fp, "--------------------------(*,*,RP)--------------------------\n"); for (rp = cand_rp_list; rp != (cand_rp_t *)NULL; rp = rp->next) { if ((r = rp->rpentry->mrtlink) != (mrtentry_t *)NULL) { if (r->flags & MRTF_KERNEL_CACHE) { for (kernel_cache = r->kernel_cache; kernel_cache != (kernel_cache_t *)NULL; kernel_cache = kernel_cache->next) number_of_cache_mirrors++; } /* Print the (*,*,RP) routing info */ fprintf(fp, " RP = %-15s", inet_fmt(r->source->address, s1, sizeof(s1))); fprintf(fp, " %-15s", "INADDR_ANY"); for (vifi = 0; vifi < numvifs; vifi++) { oifs[vifi] = VIFM_ISSET(vifi, r->oifs) ? 'o' : '.'; joined_oifs[vifi] = VIFM_ISSET(vifi, r->joined_oifs) ? 'j' : '.'; pruned_oifs[vifi] = VIFM_ISSET(vifi, r->pruned_oifs) ? 'p' : '.'; leaves_oifs[vifi] = VIFM_ISSET(vifi, r->leaves) ? 'l' : '.'; asserted_oifs[vifi] = VIFM_ISSET(vifi, r->asserted_oifs) ? 'a' : '.'; incoming_iif[vifi] = '.'; } oifs[vifi] = 0x0; /* End of string */ joined_oifs[vifi] = 0x0; pruned_oifs[vifi] = 0x0; leaves_oifs[vifi] = 0x0; asserted_oifs[vifi] = 0x0; incoming_iif[vifi] = 0x0; incoming_iif[r->incoming] = 'I'; /* TODO: don't need some of the flags */ if (r->flags & MRTF_SPT) fprintf(fp, " SPT"); if (r->flags & MRTF_WC) fprintf(fp, " WC"); if (r->flags & MRTF_RP) fprintf(fp, " RP"); if (r->flags & MRTF_REGISTER) fprintf(fp, " REG"); if (r->flags & MRTF_IIF_REGISTER) fprintf(fp, " IIF_REG"); if (r->flags & MRTF_NULL_OIF) fprintf(fp, " NULL_OIF"); if (r->flags & MRTF_KERNEL_CACHE) fprintf(fp, " CACHE"); if (r->flags & MRTF_ASSERTED) fprintf(fp, " ASSERTED"); if (r->flags & MRTF_REG_SUPP) fprintf(fp, " REG_SUPP"); if (r->flags & MRTF_SG) fprintf(fp, " SG"); if (r->flags & MRTF_PMBR) fprintf(fp, " PMBR"); fprintf(fp, "\n"); fprintf(fp, "Joined oifs: %-20s\n", joined_oifs); fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs); fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs); fprintf(fp, "Asserted oifs: %-20s\n", asserted_oifs); fprintf(fp, "Outgoing oifs: %-20s\n", oifs); fprintf(fp, "Incoming : %-20s\n", incoming_iif); fprintf(fp, "\nTIMERS: Entry JP RS Assert VIFS:"); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", vifi); fprintf(fp, "\n %d %d %d %d ", r->timer, r->jp_timer, r->rs_timer, r->assert_timer); for (vifi = 0; vifi < numvifs; vifi++) fprintf(fp, " %d", r->vif_timers[vifi]); fprintf(fp, "\n"); } } /* For all (*,*,RP) */ fprintf(fp, "Number of Groups: %u\n", number_of_groups); fprintf(fp, "Number of Cache MIRRORs: %u\n\n", number_of_cache_mirrors); } /* TODO: modify the output for better redability */ /* * Dumps the local Cand-RP-set */ int dump_rp_set(FILE *fp) { cand_rp_t *rp; rp_grp_entry_t *rp_grp_entry; grp_mask_t *grp_mask; fprintf(fp, "---------------------------RP-Set----------------------------\n"); fprintf(fp, "Current BSR address: %s\n", inet_fmt(curr_bsr_address, s1, sizeof(s1))); fprintf(fp, "RP-address Incoming Group prefix Priority Holdtime \n"); for (rp = cand_rp_list; rp != (cand_rp_t *)NULL; rp = rp->next) { fprintf(fp, "%-15s %-3d ", inet_fmt(rp->rpentry->address, s1, sizeof(s1)), rp->rpentry->incoming); if ((rp_grp_entry = rp->rp_grp_next) != (rp_grp_entry_t *)NULL) { grp_mask = rp_grp_entry->group; fprintf(fp, "%-14.14s %-3u %-3u\n", netname(grp_mask->group_addr, grp_mask->group_mask), rp_grp_entry->priority, rp_grp_entry->holdtime); for (rp_grp_entry = rp_grp_entry->rp_grp_next; rp_grp_entry != (rp_grp_entry_t *)NULL; rp_grp_entry = rp_grp_entry->rp_grp_next) { grp_mask = rp_grp_entry->group; fprintf(fp, "%-14.14s %-3u %-3u\n", netname(grp_mask->group_addr, grp_mask->group_mask), rp_grp_entry->priority, rp_grp_entry->holdtime); } } } return TRUE; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/mrt.c0000644000000000000000000012377511700261371010324 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: mrt.c,v 1.27 2001/09/10 20:31:36 pavlin Exp $ */ #include "defs.h" srcentry_t *srclist; grpentry_t *grplist; /* * Local functions definition */ static srcentry_t *create_srcentry (u_int32 source); static int search_srclist (u_int32 source, srcentry_t **sourceEntry); static int search_srcmrtlink (srcentry_t *srcentry_ptr, u_int32 group, mrtentry_t **mrtPtr); static void insert_srcmrtlink (mrtentry_t *elementPtr, mrtentry_t *insertPtr, srcentry_t *srcListPtr); static grpentry_t *create_grpentry (u_int32 group); static int search_grplist (u_int32 group, grpentry_t **groupEntry); static int search_grpmrtlink (grpentry_t *grpentry_ptr, u_int32 source, mrtentry_t **mrtPtr); static void insert_grpmrtlink (mrtentry_t *elementPtr, mrtentry_t *insertPtr, grpentry_t *grpListPtr); static mrtentry_t *alloc_mrtentry (srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr); static mrtentry_t *create_mrtentry (srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr, u_int16 flags); static void move_kernel_cache (mrtentry_t *mrtentry_ptr, u_int16 flags); void init_pim_mrt(void) { /* TODO: delete any existing routing table */ /* Initialize the source list */ /* The first entry has address 'INADDR_ANY' and is not used */ /* The order is the smallest address first. */ srclist = (srcentry_t *)calloc(1, sizeof(srcentry_t)); if (!srclist) logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()"); srclist->next = NULL; srclist->prev = NULL; srclist->address = INADDR_ANY_N; srclist->mrtlink = NULL; srclist->incoming = NO_VIF; srclist->upstream = NULL; srclist->metric = 0; srclist->preference = 0; RESET_TIMER(srclist->timer); srclist->cand_rp = NULL; /* Initialize the group list */ /* The first entry has address 'INADDR_ANY' and is not used */ /* The order is the smallest address first. */ grplist = (grpentry_t *)calloc(1, sizeof(grpentry_t)); if (!grplist) logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()"); grplist->next = NULL; grplist->prev = NULL; grplist->rpnext = NULL; grplist->rpprev = NULL; grplist->group = INADDR_ANY_N; grplist->rpaddr = INADDR_ANY_N; grplist->mrtlink = NULL; grplist->active_rp_grp = NULL; grplist->grp_route = NULL; } grpentry_t *find_group(u_int32 group) { grpentry_t *grpentry_ptr; if (!IN_MULTICAST(ntohl(group))) return NULL; if (search_grplist(group, &grpentry_ptr) == TRUE) { /* Group found! */ return grpentry_ptr; } return NULL; } srcentry_t *find_source(u_int32 source) { srcentry_t *srcentry_ptr; if (!inet_valid_host(source)) return NULL; if (search_srclist(source, &srcentry_ptr) == TRUE) { /* Source found! */ return srcentry_ptr; } return NULL; } mrtentry_t *find_route(u_int32 source, u_int32 group, u_int16 flags, char create) { srcentry_t *srcentry_ptr = NULL; grpentry_t *grpentry_ptr = NULL; mrtentry_t *mrtentry_ptr = NULL; mrtentry_t *mrtentry_ptr_wc = NULL; mrtentry_t *mrtentry_ptr_pmbr = NULL; mrtentry_t *mrtentry_ptr_2 = NULL; rpentry_t *rpentry_ptr = NULL; rp_grp_entry_t *rp_grp_entry_ptr = NULL; if (flags & (MRTF_SG | MRTF_WC)) { if (!IN_MULTICAST(ntohl(group))) return NULL; } if (flags & MRTF_SG) { if (!inet_valid_host(source)) return NULL; } if (create == DONT_CREATE) { if (flags & (MRTF_SG | MRTF_WC)) { if (search_grplist(group, &grpentry_ptr) == FALSE) { /* Group not found. Return the (*,*,RP) entry */ if (flags & MRTF_PMBR) { rpentry_ptr = rp_match(group); if (rpentry_ptr) return rpentry_ptr->mrtlink; } return NULL; } /* Search for the source */ if (flags & MRTF_SG) { if (search_grpmrtlink(grpentry_ptr, source, &mrtentry_ptr) == TRUE) { /* Exact (S,G) entry found */ return mrtentry_ptr; } } /* No (S,G) entry. Return the (*,G) entry (if exist) */ if ((flags & MRTF_WC) && grpentry_ptr->grp_route) return grpentry_ptr->grp_route; } /* Return the (*,*,RP) entry */ if (flags & MRTF_PMBR) { rpentry_ptr = NULL; if (group != INADDR_ANY_N) rpentry_ptr = rp_match(group); else if (source != INADDR_ANY_N) rpentry_ptr = rp_find(source); if (rpentry_ptr) return rpentry_ptr->mrtlink; } return NULL; } /* Creation allowed */ if (flags & (MRTF_SG | MRTF_WC)) { grpentry_ptr = create_grpentry(group); if (!grpentry_ptr) return NULL; if (!grpentry_ptr->active_rp_grp) { rp_grp_entry_ptr = rp_grp_match(group); if (!rp_grp_entry_ptr) { if (!grpentry_ptr->mrtlink && !grpentry_ptr->grp_route) { /* New created grpentry. Delete it. */ delete_grpentry(grpentry_ptr); } return NULL; } rpentry_ptr = rp_grp_entry_ptr->rp->rpentry; grpentry_ptr->active_rp_grp = rp_grp_entry_ptr; grpentry_ptr->rpaddr = rpentry_ptr->address; /* Link to the top of the rp_grp_chain */ grpentry_ptr->rpnext = rp_grp_entry_ptr->grplink; rp_grp_entry_ptr->grplink = grpentry_ptr; if (grpentry_ptr->rpnext) grpentry_ptr->rpnext->rpprev = grpentry_ptr; } else { rpentry_ptr = grpentry_ptr->active_rp_grp->rp->rpentry; } } mrtentry_ptr_wc = mrtentry_ptr_pmbr = NULL; if (flags & MRTF_WC) { /* Setup the (*,G) routing entry */ mrtentry_ptr_wc = create_mrtentry(NULL, grpentry_ptr, MRTF_WC); if (!mrtentry_ptr_wc) { if (!grpentry_ptr->mrtlink) { /* New created grpentry. Delete it. */ delete_grpentry(grpentry_ptr); } return NULL; } if (mrtentry_ptr_wc->flags & MRTF_NEW) { mrtentry_ptr_pmbr = rpentry_ptr->mrtlink; /* Copy the oif list from the (*,*,RP) entry */ if (mrtentry_ptr_pmbr) { VOIF_COPY(mrtentry_ptr_pmbr, mrtentry_ptr_wc); } mrtentry_ptr_wc->incoming = rpentry_ptr->incoming; mrtentry_ptr_wc->upstream = rpentry_ptr->upstream; mrtentry_ptr_wc->metric = rpentry_ptr->metric; mrtentry_ptr_wc->preference = rpentry_ptr->preference; move_kernel_cache(mrtentry_ptr_wc, 0); #ifdef RSRR rsrr_cache_bring_up(mrtentry_ptr_wc); #endif /* RSRR */ } if (!(flags & MRTF_SG)) { return mrtentry_ptr_wc; } } if (flags & MRTF_SG) { /* Setup the (S,G) routing entry */ srcentry_ptr = create_srcentry(source); if (!srcentry_ptr) { /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */ if ((!grpentry_ptr->grp_route || (grpentry_ptr->grp_route && (grpentry_ptr->grp_route->flags & MRTF_NEW))) && !grpentry_ptr->mrtlink) { /* New created grpentry. Delete it. */ delete_grpentry(grpentry_ptr); } return NULL; } mrtentry_ptr = create_mrtentry(srcentry_ptr, grpentry_ptr, MRTF_SG); if (!mrtentry_ptr) { if ((!grpentry_ptr->grp_route || (grpentry_ptr->grp_route && (grpentry_ptr->grp_route->flags & MRTF_NEW))) && !grpentry_ptr->mrtlink) { /* New created grpentry. Delete it. */ delete_grpentry(grpentry_ptr); } if (!srcentry_ptr->mrtlink) { /* New created srcentry. Delete it. */ delete_srcentry(srcentry_ptr); } return NULL; } if (mrtentry_ptr->flags & MRTF_NEW) { mrtentry_ptr_2 = grpentry_ptr->grp_route; if (!mrtentry_ptr_2) { mrtentry_ptr_2 = rpentry_ptr->mrtlink; } /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */ if (mrtentry_ptr_2) { VOIF_COPY(mrtentry_ptr_2, mrtentry_ptr); if (flags & MRTF_RP) { /* ~(S,G) prune entry */ mrtentry_ptr->incoming = mrtentry_ptr_2->incoming; mrtentry_ptr->upstream = mrtentry_ptr_2->upstream; mrtentry_ptr->metric = mrtentry_ptr_2->metric; mrtentry_ptr->preference = mrtentry_ptr_2->preference; mrtentry_ptr->flags |= MRTF_RP; } } if (!(mrtentry_ptr->flags & MRTF_RP)) { mrtentry_ptr->incoming = srcentry_ptr->incoming; mrtentry_ptr->upstream = srcentry_ptr->upstream; mrtentry_ptr->metric = srcentry_ptr->metric; mrtentry_ptr->preference = srcentry_ptr->preference; } move_kernel_cache(mrtentry_ptr, 0); #ifdef RSRR rsrr_cache_bring_up(mrtentry_ptr); #endif /* RSRR */ } return mrtentry_ptr; } if (flags & MRTF_PMBR) { /* Get/return the (*,*,RP) routing entry */ if (group != INADDR_ANY_N) { rpentry_ptr = rp_match(group); } else if (source != INADDR_ANY_N) { rpentry_ptr = rp_find(source); if (!rpentry_ptr) return NULL; } else { return NULL; /* source == group == INADDR_ANY */ } if (rpentry_ptr->mrtlink) return rpentry_ptr->mrtlink; mrtentry_ptr = create_mrtentry(rpentry_ptr, NULL, MRTF_PMBR); if (!mrtentry_ptr) return NULL; mrtentry_ptr->incoming = rpentry_ptr->incoming; mrtentry_ptr->upstream = rpentry_ptr->upstream; mrtentry_ptr->metric = rpentry_ptr->metric; mrtentry_ptr->preference = rpentry_ptr->preference; return mrtentry_ptr; } return NULL; } void delete_srcentry(srcentry_t *srcentry_ptr) { mrtentry_t *ptr; mrtentry_t *next; if (!srcentry_ptr) return; /* TODO: XXX: the first entry is unused and always there */ srcentry_ptr->prev->next = srcentry_ptr->next; if (srcentry_ptr->next) srcentry_ptr->next->prev = srcentry_ptr->prev; for (ptr = srcentry_ptr->mrtlink; ptr; ptr = next) { next = ptr->srcnext; if (ptr->flags & MRTF_KERNEL_CACHE) /* Delete the kernel cache first */ delete_mrtentry_all_kernel_cache(ptr); if (ptr->grpprev) { ptr->grpprev->grpnext = ptr->grpnext; } else { ptr->group->mrtlink = ptr->grpnext; if (!ptr->grpnext && !ptr->group->grp_route) { /* Delete the group entry if it has no (*,G) routing entry */ delete_grpentry(ptr->group); } } if (ptr->grpnext) ptr->grpnext->grpprev = ptr->grpprev; FREE_MRTENTRY(ptr); } free((char *)srcentry_ptr); } void delete_grpentry(grpentry_t *grpentry_ptr) { mrtentry_t *ptr; mrtentry_t *next; if (!grpentry_ptr) return; /* TODO: XXX: the first entry is unused and always there */ grpentry_ptr->prev->next = grpentry_ptr->next; if (grpentry_ptr->next) grpentry_ptr->next->prev = grpentry_ptr->prev; if (grpentry_ptr->grp_route) { if (grpentry_ptr->grp_route->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(grpentry_ptr->grp_route); FREE_MRTENTRY(grpentry_ptr->grp_route); } /* Delete from the rp_grp_entry chain */ if (grpentry_ptr->active_rp_grp != NULL) { if (grpentry_ptr->rpnext != NULL) grpentry_ptr->rpnext->rpprev = grpentry_ptr->rpprev; if (grpentry_ptr->rpprev != NULL) grpentry_ptr->rpprev->rpnext = grpentry_ptr->rpnext; else grpentry_ptr->active_rp_grp->grplink = grpentry_ptr->rpnext; } for (ptr = grpentry_ptr->mrtlink; ptr; ptr = next) { next = ptr->grpnext; if (ptr->flags & MRTF_KERNEL_CACHE) /* Delete the kernel cache first */ delete_mrtentry_all_kernel_cache(ptr); if (ptr->srcprev) { ptr->srcprev->srcnext = ptr->srcnext; } else { ptr->source->mrtlink = ptr->srcnext; if (!ptr->srcnext) { /* Delete the srcentry if this was the last routing entry */ delete_srcentry(ptr->source); } } if (ptr->srcnext) ptr->srcnext->srcprev = ptr->srcprev; FREE_MRTENTRY(ptr); } free((char *)grpentry_ptr); } void delete_mrtentry(mrtentry_t *mrtentry_ptr) { grpentry_t *grpentry_ptr; mrtentry_t *mrtentry_wc; mrtentry_t *mrtentry_rp; if (mrtentry_ptr == NULL) return; /* Delete the kernel cache first */ if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(mrtentry_ptr); #ifdef RSRR /* Tell the reservation daemon */ rsrr_cache_clean(mrtentry_ptr); #endif /* RSRR */ if (mrtentry_ptr->flags & MRTF_PMBR) { /* (*,*,RP) mrtentry */ mrtentry_ptr->source->mrtlink = NULL; } else if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) mrtentry */ /* Delete from the grpentry MRT chain */ if (mrtentry_ptr->grpprev != NULL) { mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext; } else { mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext; if (mrtentry_ptr->grpnext == NULL) { /* All (S,G) MRT entries are gone. Allow creating (*,G) MFC * entries. */ mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; mrtentry_wc = mrtentry_ptr->group->grp_route; if (mrtentry_rp != NULL) mrtentry_rp->flags &= ~MRTF_MFC_CLONE_SG; if (mrtentry_wc != NULL) { mrtentry_wc->flags &= ~MRTF_MFC_CLONE_SG; } else { /* Delete the group entry if it has no (*,G) * routing entry */ delete_grpentry(mrtentry_ptr->group); } } } if (mrtentry_ptr->grpnext != NULL) mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev; /* Delete from the srcentry MRT chain */ if (mrtentry_ptr->srcprev != NULL) { mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext; } else { mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext; if (mrtentry_ptr->srcnext == NULL) { /* Delete the srcentry if this was the last routing entry */ delete_srcentry(mrtentry_ptr->source); } } if (mrtentry_ptr->srcnext != NULL) mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev; } else { /* This mrtentry should be (*,G) */ grpentry_ptr = mrtentry_ptr->group; grpentry_ptr->grp_route = NULL; if (grpentry_ptr->mrtlink == NULL) /* Delete the group entry if it has no (S,G) entries */ delete_grpentry(grpentry_ptr); } FREE_MRTENTRY(mrtentry_ptr); } static int search_srclist(u_int32 source, srcentry_t **sourceEntry) { srcentry_t *s_prev,*s; u_int32 source_h = ntohl(source); for (s_prev = srclist, s = s_prev->next; s != NULL; s_prev = s, s = s->next) { /* The srclist is ordered with the smallest addresses first. * The first entry is not used. */ if (ntohl(s->address) < source_h) continue; if (s->address == source) { *sourceEntry = s; return TRUE; } break; } *sourceEntry = s_prev; /* The insertion point is between s_prev and s */ return FALSE; } static int search_grplist(u_int32 group, grpentry_t **groupEntry) { grpentry_t *g_prev, *g; u_int32 group_h = ntohl(group); for (g_prev = grplist, g = g_prev->next; g != NULL; g_prev = g, g = g->next) { /* The grplist is ordered with the smallest address first. * The first entry is not used. */ if (ntohl(g->group) < group_h) continue; if (g->group == group) { *groupEntry = g; return TRUE; } break; } *groupEntry = g_prev; /* The insertion point is between g_prev and g */ return FALSE; } static srcentry_t *create_srcentry(u_int32 source) { srcentry_t *srcentry_ptr; srcentry_t *srcentry_prev; if (search_srclist(source, &srcentry_prev) == TRUE) return srcentry_prev; srcentry_ptr = (srcentry_t *)calloc(1, sizeof(srcentry_t)); if (!srcentry_ptr) { logit(LOG_WARNING, 0, "Memory allocation error for srcentry %s", inet_fmt(source, s1, sizeof(s1))); return NULL; } srcentry_ptr->address = source; /* * Free the memory if there is error getting the iif and * the next hop (upstream) router. */ if (set_incoming(srcentry_ptr, PIM_IIF_SOURCE) == FALSE) { free((char *)srcentry_ptr); return NULL; } RESET_TIMER(srcentry_ptr->timer); srcentry_ptr->mrtlink = NULL; srcentry_ptr->cand_rp = NULL; srcentry_ptr->next = srcentry_prev->next; srcentry_prev->next = srcentry_ptr; srcentry_ptr->prev = srcentry_prev; if (srcentry_ptr->next) srcentry_ptr->next->prev = srcentry_ptr; IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "create source entry, source %s", inet_fmt(source, s1, sizeof(s1))); } return srcentry_ptr; } static grpentry_t *create_grpentry(u_int32 group) { grpentry_t *grpentry_ptr; grpentry_t *grpentry_prev; /* If already exists, return it. Otheriwse search_grplist() returns the * insertion point in grpentry_prev. */ if (search_grplist(group, &grpentry_prev) == TRUE) return grpentry_prev; grpentry_ptr = (grpentry_t *)calloc(1, sizeof(grpentry_t)); if (!grpentry_ptr) { logit(LOG_WARNING, 0, "Memory allocation error for grpentry %s", inet_fmt(group, s1, sizeof(s1))); return NULL; } /* * TODO: XXX: Note that this is NOT a (*,G) routing entry, but simply * a group entry, probably used to search the routing table (to find * (S,G) entries for example.) * To become (*,G) routing entry, we must setup grpentry_ptr->grp_route */ grpentry_ptr->group = group; grpentry_ptr->rpaddr = INADDR_ANY_N; grpentry_ptr->mrtlink = NULL; grpentry_ptr->active_rp_grp = NULL; grpentry_ptr->grp_route = NULL; grpentry_ptr->rpnext = NULL; grpentry_ptr->rpprev = NULL; /* Now it is safe to include the new group entry */ grpentry_ptr->next = grpentry_prev->next; grpentry_prev->next = grpentry_ptr; grpentry_ptr->prev = grpentry_prev; if (grpentry_ptr->next) grpentry_ptr->next->prev = grpentry_ptr; IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "create group entry, group %s", inet_fmt(group, s1, sizeof(s1))); } return grpentry_ptr; } /* * Return TRUE if the entry is found and then *mrtPtr is set to point to that * entry. Otherwise return FALSE and *mrtPtr points the previous entry * (or NULL if first in the chain. */ static int search_srcmrtlink(srcentry_t *srcentry_ptr, u_int32 group, mrtentry_t **mrtPtr) { mrtentry_t *mrtentry_ptr; mrtentry_t *m_prev = NULL; u_int32 group_h = ntohl(group); for (mrtentry_ptr = srcentry_ptr->mrtlink; mrtentry_ptr != NULL; m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->srcnext) { /* The entries are ordered with the smaller group address first. * The addresses are in network order. */ if (ntohl(mrtentry_ptr->group->group) < group_h) continue; if (mrtentry_ptr->group->group == group) { *mrtPtr = mrtentry_ptr; return TRUE; } break; } *mrtPtr = m_prev; return FALSE; } /* * Return TRUE if the entry is found and then *mrtPtr is set to point to that * entry. Otherwise return FALSE and *mrtPtr points the previous entry * (or NULL if first in the chain. */ static int search_grpmrtlink(grpentry_t *grpentry_ptr, u_int32 source, mrtentry_t **mrtPtr) { mrtentry_t *mrtentry_ptr; mrtentry_t *m_prev = NULL; u_int32 source_h = ntohl(source); for (mrtentry_ptr = grpentry_ptr->mrtlink; mrtentry_ptr != NULL; m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->grpnext) { /* The entries are ordered with the smaller source address first. * The addresses are in network order. */ if (ntohl(mrtentry_ptr->source->address) < source_h) continue; if (source == mrtentry_ptr->source->address) { *mrtPtr = mrtentry_ptr; return TRUE; } break; } *mrtPtr = m_prev; return FALSE; } static void insert_srcmrtlink(mrtentry_t *mrtentry_new, mrtentry_t *mrtentry_prev, srcentry_t *srcentry_ptr) { if (mrtentry_prev == NULL) { /* Has to be insert as the head entry for this source */ mrtentry_new->srcnext = srcentry_ptr->mrtlink; mrtentry_new->srcprev = NULL; srcentry_ptr->mrtlink = mrtentry_new; } else { /* Insert right after the mrtentry_prev */ mrtentry_new->srcnext = mrtentry_prev->srcnext; mrtentry_new->srcprev = mrtentry_prev; mrtentry_prev->srcnext = mrtentry_new; } if (mrtentry_new->srcnext != NULL) mrtentry_new->srcnext->srcprev = mrtentry_new; } static void insert_grpmrtlink(mrtentry_t *mrtentry_new, mrtentry_t *mrtentry_prev, grpentry_t *grpentry_ptr) { if (mrtentry_prev == NULL) { /* Has to be insert as the head entry for this group */ mrtentry_new->grpnext = grpentry_ptr->mrtlink; mrtentry_new->grpprev = NULL; grpentry_ptr->mrtlink = mrtentry_new; } else { /* Insert right after the mrtentry_prev */ mrtentry_new->grpnext = mrtentry_prev->grpnext; mrtentry_new->grpprev = mrtentry_prev; mrtentry_prev->grpnext = mrtentry_new; } if (mrtentry_new->grpnext != NULL) mrtentry_new->grpnext->grpprev = mrtentry_new; } static mrtentry_t *alloc_mrtentry(srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr) { mrtentry_t *mrtentry_ptr; u_int16 i, *i_ptr; u_int8 vif_numbers; mrtentry_ptr = (mrtentry_t *)calloc(1, sizeof(mrtentry_t)); if (mrtentry_ptr == NULL) { logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory"); return NULL; } /* * grpnext, grpprev, srcnext, srcprev will be setup when we link the * mrtentry to the source and group chains */ mrtentry_ptr->source = srcentry_ptr; mrtentry_ptr->group = grpentry_ptr; mrtentry_ptr->incoming = NO_VIF; VIFM_CLRALL(mrtentry_ptr->joined_oifs); VIFM_CLRALL(mrtentry_ptr->leaves); VIFM_CLRALL(mrtentry_ptr->pruned_oifs); VIFM_CLRALL(mrtentry_ptr->asserted_oifs); VIFM_CLRALL(mrtentry_ptr->oifs); mrtentry_ptr->upstream = NULL; mrtentry_ptr->metric = 0; mrtentry_ptr->preference = 0; mrtentry_ptr->pmbr_addr = INADDR_ANY_N; #ifdef RSRR mrtentry_ptr->rsrr_cache = NULL; #endif /* RSRR */ /* XXX: TODO: if we are short in memory, we can reserve as few as possible * space for vif timers (per group and/or routing entry), but then everytime * when a new interfaces is configured, the router will be restarted and * will delete the whole routing table. The "memory is cheap" solution is * to reserve timer space for all potential vifs in advance and then no * need to delete the routing table and disturb the forwarding. */ #ifdef SAVE_MEMORY mrtentry_ptr->vif_timers = (u_int16 *)calloc(1, sizeof(u_int16) * numvifs); mrtentry_ptr->vif_deletion_delay = (u_int16 *)calloc(1, sizeof(u_int16) * numvifs); vif_numbers = numvifs; #else mrtentry_ptr->vif_timers = (u_int16 *)calloc(1, sizeof(u_int16) * total_interfaces); mrtentry_ptr->vif_deletion_delay = (u_int16 *)calloc(1, sizeof(u_int16) * total_interfaces); vif_numbers = total_interfaces; #endif /* SAVE_MEMORY */ if ((mrtentry_ptr->vif_timers == NULL) || (mrtentry_ptr->vif_deletion_delay == NULL)) { logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory"); FREE_MRTENTRY(mrtentry_ptr); return NULL; } /* Reset the timers */ for (i = 0, i_ptr = mrtentry_ptr->vif_timers; i < vif_numbers; i++, i_ptr++) { RESET_TIMER(*i_ptr); } for (i = 0, i_ptr = mrtentry_ptr->vif_deletion_delay; i < vif_numbers; i++, i_ptr++) { RESET_TIMER(*i_ptr); } mrtentry_ptr->flags = MRTF_NEW; RESET_TIMER(mrtentry_ptr->timer); RESET_TIMER(mrtentry_ptr->jp_timer); RESET_TIMER(mrtentry_ptr->rs_timer); RESET_TIMER(mrtentry_ptr->assert_timer); RESET_TIMER(mrtentry_ptr->assert_rate_timer); mrtentry_ptr->kernel_cache = NULL; return mrtentry_ptr; } static mrtentry_t *create_mrtentry(srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr, u_int16 flags) { mrtentry_t *r_new; mrtentry_t *r_grp_insert, *r_src_insert; /* pointers to insert */ u_int32 source; u_int32 group; if (flags & MRTF_SG) { /* (S,G) entry */ source = srcentry_ptr->address; group = grpentry_ptr->group; if (search_grpmrtlink(grpentry_ptr, source, &r_grp_insert) == TRUE) { return r_grp_insert; } if (search_srcmrtlink(srcentry_ptr, group, &r_src_insert) == TRUE) { /* * Hmmm, search_grpmrtlink() didn't find the entry, but * search_srcmrtlink() did find it! Shoudn't happen. Panic! */ logit(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n", inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2))); /* not reached but to make lint happy */ return NULL; } /* * Create and insert in group mrtlink and source mrtlink chains. */ r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr); if (r_new == NULL) return NULL; /* * r_new has to be insert right after r_grp_insert in the * grp mrtlink chain and right after r_src_insert in the * src mrtlink chain */ insert_grpmrtlink(r_new, r_grp_insert, grpentry_ptr); insert_srcmrtlink(r_new, r_src_insert, srcentry_ptr); r_new->flags |= MRTF_SG; return r_new; } if (flags & MRTF_WC) { /* (*,G) entry */ if (grpentry_ptr->grp_route != NULL) return grpentry_ptr->grp_route; r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr); if (r_new == NULL) return NULL; grpentry_ptr->grp_route = r_new; r_new->flags |= (MRTF_WC | MRTF_RP); return r_new; } if (flags & MRTF_PMBR) { /* (*,*,RP) entry */ if (srcentry_ptr->mrtlink != NULL) return srcentry_ptr->mrtlink; r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr); if (r_new == NULL) return NULL; srcentry_ptr->mrtlink = r_new; r_new->flags |= (MRTF_PMBR | MRTF_RP); return r_new; } return NULL; } /* * Delete all kernel cache for this mrtentry */ void delete_mrtentry_all_kernel_cache(mrtentry_t *mrtentry_ptr) { kernel_cache_t *kernel_cache_prev; kernel_cache_t *kernel_cache_ptr; if (!(mrtentry_ptr->flags & MRTF_KERNEL_CACHE)) { return; } /* Free all kernel_cache entries */ for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; ) { kernel_cache_prev = kernel_cache_ptr; kernel_cache_ptr = kernel_cache_ptr->next; k_del_mfc(igmp_socket, kernel_cache_prev->source, kernel_cache_prev->group); free((char *)kernel_cache_prev); } mrtentry_ptr->kernel_cache = NULL; /* turn off the cache flag(s) */ mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG); } void delete_single_kernel_cache(mrtentry_t *mrtentry_ptr, kernel_cache_t *kernel_cache_ptr) { if (kernel_cache_ptr->prev == NULL) { mrtentry_ptr->kernel_cache = kernel_cache_ptr->next; if (mrtentry_ptr->kernel_cache == NULL) mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG); } else { kernel_cache_ptr->prev->next = kernel_cache_ptr->next; } if (kernel_cache_ptr->next != NULL) kernel_cache_ptr->next->prev = kernel_cache_ptr->prev; IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s", inet_fmt(kernel_cache_ptr->source, s1, sizeof(s1)), inet_fmt(kernel_cache_ptr->group, s2, sizeof(s2))); } k_del_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group); free((char *)kernel_cache_ptr); } void delete_single_kernel_cache_addr(mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group) { u_int32 source_h; u_int32 group_h; kernel_cache_t *kernel_cache_ptr; if (mrtentry_ptr == NULL) return; source_h = ntohl(source); group_h = ntohl(group); /* Find the exact (S,G) kernel_cache entry */ for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) { if (ntohl(kernel_cache_ptr->group) < group_h) continue; if (ntohl(kernel_cache_ptr->group) > group_h) return; /* Not found */ if (ntohl(kernel_cache_ptr->source) < source_h) continue; if (ntohl(kernel_cache_ptr->source) > source_h) return; /* Not found */ /* Found exact match */ break; } if (kernel_cache_ptr == NULL) return; /* Found. Delete it */ if (kernel_cache_ptr->prev == NULL) { mrtentry_ptr->kernel_cache = kernel_cache_ptr->next; if (mrtentry_ptr->kernel_cache == NULL) mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG); } else{ kernel_cache_ptr->prev->next = kernel_cache_ptr->next; } if (kernel_cache_ptr->next != NULL) kernel_cache_ptr->next->prev = kernel_cache_ptr->prev; IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s", inet_fmt(kernel_cache_ptr->source, s1, sizeof(s1)), inet_fmt(kernel_cache_ptr->group, s2, sizeof(s2))); } k_del_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group); free((char *)kernel_cache_ptr); } /* * Installs kernel cache for (source, group). Assumes mrtentry_ptr * is the correct entry. */ void add_kernel_cache(mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group, u_int16 flags) { u_int32 source_h; u_int32 group_h; kernel_cache_t *kernel_cache_next; kernel_cache_t *kernel_cache_prev; kernel_cache_t *kernel_cache_new; if (mrtentry_ptr == NULL) return; move_kernel_cache(mrtentry_ptr, flags); if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) */ if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) return; kernel_cache_new = (kernel_cache_t *)calloc(1, sizeof(kernel_cache_t)); kernel_cache_new->next = NULL; kernel_cache_new->prev = NULL; kernel_cache_new->source = source; kernel_cache_new->group = group; kernel_cache_new->sg_count.pktcnt = 0; kernel_cache_new->sg_count.bytecnt = 0; kernel_cache_new->sg_count.wrong_if = 0; mrtentry_ptr->kernel_cache = kernel_cache_new; mrtentry_ptr->flags |= MRTF_KERNEL_CACHE; return; } source_h = ntohl(source); group_h = ntohl(group); kernel_cache_prev = NULL; for (kernel_cache_next = mrtentry_ptr->kernel_cache; kernel_cache_next != NULL; kernel_cache_prev = kernel_cache_next, kernel_cache_next = kernel_cache_next->next) { if (ntohl(kernel_cache_next->group) < group_h) continue; if (ntohl(kernel_cache_next->group) > group_h) break; if (ntohl(kernel_cache_next->source) < source_h) continue; if (ntohl(kernel_cache_next->source) > source_h) break; /* Found exact match. Nothing to change. */ return; } /* * The new entry must be placed between kernel_cache_prev and * kernel_cache_next */ kernel_cache_new = (kernel_cache_t *)calloc(1, sizeof(kernel_cache_t)); if (kernel_cache_prev != NULL) kernel_cache_prev->next = kernel_cache_new; else mrtentry_ptr->kernel_cache = kernel_cache_new; if (kernel_cache_next != NULL) kernel_cache_next->prev = kernel_cache_new; kernel_cache_new->prev = kernel_cache_prev; kernel_cache_new->next = kernel_cache_next; kernel_cache_new->source = source; kernel_cache_new->group = group; kernel_cache_new->sg_count.pktcnt = 0; kernel_cache_new->sg_count.bytecnt = 0; kernel_cache_new->sg_count.wrong_if = 0; mrtentry_ptr->flags |= MRTF_KERNEL_CACHE; } /* * Bring the kernel cache "UP": from the (*,*,RP) to (*,G) or (S,G) */ static void move_kernel_cache(mrtentry_t *mrtentry_ptr, u_int16 flags) { kernel_cache_t *kernel_cache_ptr; kernel_cache_t *insert_kernel_cache_ptr; kernel_cache_t *first_kernel_cache_ptr; kernel_cache_t *last_kernel_cache_ptr; kernel_cache_t *prev_kernel_cache_ptr; mrtentry_t *mrtentry_pmbr; mrtentry_t *mrtentry_rp; u_int32 group_h; u_int32 source_h; int found; if (mrtentry_ptr == NULL) return; if (mrtentry_ptr->flags & MRTF_PMBR) return; if (mrtentry_ptr->flags & MRTF_WC) { /* Move the cache info from (*,*,RP) to (*,G) */ group_h = ntohl(mrtentry_ptr->group->group); mrtentry_pmbr = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (mrtentry_pmbr == NULL) return; /* Nothing to move */ first_kernel_cache_ptr = last_kernel_cache_ptr = NULL; for (kernel_cache_ptr = mrtentry_pmbr->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) { /* * The order is: (1) smaller group; * (2) smaller source within group */ if (ntohl(kernel_cache_ptr->group) < group_h) continue; if (ntohl(kernel_cache_ptr->group) != group_h) break; /* Select the kernel_cache entries to move */ if (first_kernel_cache_ptr == NULL) { first_kernel_cache_ptr = last_kernel_cache_ptr = kernel_cache_ptr; } else { last_kernel_cache_ptr = kernel_cache_ptr; } } if (first_kernel_cache_ptr != NULL) { /* Fix the old chain */ if (first_kernel_cache_ptr->prev != NULL) { first_kernel_cache_ptr->prev->next = last_kernel_cache_ptr->next; } else { mrtentry_pmbr->kernel_cache = last_kernel_cache_ptr->next; } if (last_kernel_cache_ptr->next != NULL) last_kernel_cache_ptr->next->prev = first_kernel_cache_ptr->prev; if (mrtentry_pmbr->kernel_cache == NULL) mrtentry_pmbr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG); /* Insert in the new place */ prev_kernel_cache_ptr = NULL; last_kernel_cache_ptr->next = NULL; mrtentry_ptr->flags |= MRTF_KERNEL_CACHE; for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; ) { if (first_kernel_cache_ptr == NULL) break; /* All entries have been inserted */ if (ntohl(kernel_cache_ptr->source) > ntohl(first_kernel_cache_ptr->source)) { /* Insert the entry before kernel_cache_ptr */ insert_kernel_cache_ptr = first_kernel_cache_ptr; first_kernel_cache_ptr = first_kernel_cache_ptr->next; if (kernel_cache_ptr->prev != NULL) kernel_cache_ptr->prev->next = insert_kernel_cache_ptr; else mrtentry_ptr->kernel_cache = insert_kernel_cache_ptr; insert_kernel_cache_ptr->prev = kernel_cache_ptr->prev; insert_kernel_cache_ptr->next = kernel_cache_ptr; kernel_cache_ptr->prev = insert_kernel_cache_ptr; } prev_kernel_cache_ptr = kernel_cache_ptr; kernel_cache_ptr = kernel_cache_ptr->next; } if (first_kernel_cache_ptr != NULL) { /* Place all at the end after prev_kernel_cache_ptr */ if (prev_kernel_cache_ptr != NULL) prev_kernel_cache_ptr->next = first_kernel_cache_ptr; else mrtentry_ptr->kernel_cache = first_kernel_cache_ptr; first_kernel_cache_ptr->prev = prev_kernel_cache_ptr; } } return; } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) entry. Move the whole group cache from (*,*,RP) to (*,G) and * then get the necessary entry from (*,G). * TODO: Not optimized! The particular entry is moved first to (*,G), * then we have to search again (*,G) to find it and move to (S,G). */ /* TODO: XXX: No need for this? Thinking.... */ /* move_kernel_cache(mrtentry_ptr->group->grp_route, flags); */ if ((mrtentry_rp = mrtentry_ptr->group->grp_route) == NULL) mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (mrtentry_rp == NULL) return; if (mrtentry_rp->incoming != mrtentry_ptr->incoming) { /* XXX: the (*,*,RP) (or (*,G)) iif is different from the * (S,G) iif. No need to move the cache, because (S,G) don't * need it. After the first packet arrives on the shortest path, * the correct cache entry will be created. * If (flags & MFC_MOVE_FORCE) then we must move the cache. * This usually happens when switching to the shortest path. * The calling function will immediately call k_chg_mfc() * to modify the kernel cache. */ if (!(flags & MFC_MOVE_FORCE)) return; } /* Find the exact entry */ source_h = ntohl(mrtentry_ptr->source->address); group_h = ntohl(mrtentry_ptr->group->group); found = FALSE; for (kernel_cache_ptr = mrtentry_rp->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) { if (ntohl(kernel_cache_ptr->group) < group_h) continue; if (ntohl(kernel_cache_ptr->group) > group_h) break; if (ntohl(kernel_cache_ptr->source) < source_h) continue; if (ntohl(kernel_cache_ptr->source) > source_h) break; /* We found it! */ if (kernel_cache_ptr->prev != NULL){ kernel_cache_ptr->prev->next = kernel_cache_ptr->next; } else { mrtentry_rp->kernel_cache = kernel_cache_ptr->next; } if (kernel_cache_ptr->next != NULL) kernel_cache_ptr->next->prev = kernel_cache_ptr->prev; found = TRUE; break; } if (found == TRUE) { if (mrtentry_rp->kernel_cache == NULL) mrtentry_rp->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG); if (mrtentry_ptr->kernel_cache != NULL) free ((char *)mrtentry_ptr->kernel_cache); mrtentry_ptr->flags |= MRTF_KERNEL_CACHE; mrtentry_ptr->kernel_cache = kernel_cache_ptr; kernel_cache_ptr->prev = NULL; kernel_cache_ptr->next = NULL; } } } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/LICENSE.mrouted0000644000000000000000000000324411700261371012025 0ustar Copyright © 2002 The Board of Trustees of the Leland Stanford Junior University Permission is hereby granted to STANFORD's rights, free of charge, to any person obtaining a copy of this Software and associated documentation files ( "MROUTED"), to deal in MROUTED without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of MROUTED , and to permit persons to whom MROUTED is furnished to do so, subject to the following conditions: 1) The above copyright notice and this permission notice shall be included in all copies or substantial portions of the MROUTED . 2) Neither the STANFORD name nor the names of its contributors may be used in any promotional advertising or other promotional materials to be disseminated to the public or any portion thereof nor to use the name of any STANFORD faculty member, employee, or student, or any trademark, service mark, trade name, or symbol of STANFORD or Stanford Hospitals and Clinics, nor any that is associated with any of them, without STANFORD's prior written consent. Any use of STANFORD's name shall be limited to statements of fact and shall not imply endorsement of any products or services. 3) MROUTED IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH MROUTED OR THE USE OR OTHER DEALINGS IN THE MROUTED . pimd-2.1.8/vif.h0000644000000000000000000002662111700261371010303 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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. * */ /* * Bitmap handling functions. * These should be fast but generic. bytes can be slow to zero and compare, * words are hard to make generic. Thus two sets of macros (yuk). */ /* * The VIFM_ functions should migrate out of , since * the kernel no longer uses vifbitmaps. */ #ifndef VIFM_SET typedef u_int32 vifbitmap_t; #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) #endif /* * And was missing some required functions anyway */ #if !defined(VIFM_SETALL) #define VIFM_SETALL(m) ((m) = ~0) #endif #define VIFM_ISSET_ONLY(n, m) ((m) == (1 << (n))) #define VIFM_ISEMPTY(m) ((m) == 0) #define VIFM_CLR_MASK(m, mask) ((m) &= ~(mask)) #define VIFM_SET_MASK(m, mask) ((m) |= (mask)) #define VIFM_MERGE(m1, m2, result) ((result) = (m1) | (m2)) /* Check whether I am the last hop on some LAN */ #define VIFM_LASTHOP_ROUTER(leaves, oifs) ((leaves) & (oifs)) /* * Neighbor bitmaps are, for efficiency, implemented as a struct * containing two variables of a native machine type. If you * have a native type that's bigger than a long, define it below. */ #define NBRTYPE u_long #define NBRBITS sizeof(NBRTYPE) * 8 typedef struct { NBRTYPE hi; NBRTYPE lo; } nbrbitmap_t; #define MAXNBRS 2 * NBRBITS #define NBRM_SET(n, m) (((n) < NBRBITS) ? ((m).lo |= (1 << (n))) : \ ((m).hi |= (1 << (n - NBRBITS)))) #define NBRM_CLR(n, m) (((n) < NBRBITS) ? ((m).lo &= ~(1 << (n))) : \ ((m).hi &= ~(1 << (n - NBRBITS)))) #define NBRM_ISSET(n, m) (((n) < NBRBITS) ? ((m).lo & (1 << (n))) : \ ((m).hi & (1 << ((n) - NBRBITS)))) #define NBRM_CLRALL(m) ((m).lo = (m).hi = 0) #define NBRM_COPY(mfrom, mto) ((mto).lo = (mfrom).lo, (mto).hi = (mfrom).hi) #define NBRM_SAME(m1, m2) (((m1).lo == (m2).lo) && ((m1).hi == (m2).hi)) #define NBRM_ISEMPTY(m) (((m).lo == 0) && ((m).hi == 0)) #define NBRM_SETMASK(m, mask) (((m).lo |= (mask).lo),((m).hi |= (mask).hi)) #define NBRM_CLRMASK(m, mask) (((m).lo &= ~(mask).lo),((m).hi &= ~(mask).hi)) #define NBRM_MASK(m, mask) (((m).lo &= (mask).lo),((m).hi &= (mask).hi)) #define NBRM_ISSETMASK(m, mask) (((m).lo & (mask).lo) || ((m).hi & (mask).hi)) #define NBRM_ISSETALLMASK(m, mask)\ ((((m).lo & (mask).lo) == (mask).lo) && \ (((m).hi & (mask).hi) == (mask).hi)) /* * This macro is TRUE if all the subordinates have been pruned, or if * there are no subordinates on this vif. * The arguments is the map of subordinates, the map of neighbors on the * vif, and the map of received prunes. */ #define SUBS_ARE_PRUNED(sub, vifmask, prunes) \ (((sub).lo & (vifmask).lo) == ((prunes).lo & (vifmask).lo & (sub).lo) && \ ((sub).hi & (vifmask).hi) == ((prunes).hi & (vifmask).hi & (sub).hi)) /* * User level Virtual Interface structure * * A "virtual interface" is either a physical, multicast-capable interface * (called a "phyint"), a virtual point-to-point link (called a "tunnel") * or a "register vif" used by PIM. The register vif is used by the * Designated Router (DR) to send encapsulated data packets to the * Rendevous Point (RP) for a particular group. The data packets are * encapsulated in PIM messages (IPPROTO_PIM = 103) and then unicast to * the RP. * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) */ struct uvif { u_int uv_flags; /* VIFF_ flags defined below */ u_char uv_metric; /* cost of this vif */ u_char uv_admetric; /* advertised cost of this vif */ u_char uv_threshold; /* min ttl required to forward on vif */ u_int uv_rate_limit; /* rate limit on this vif */ u_int32 uv_lcl_addr; /* local address of this vif */ u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */ u_int32 uv_dst_addr; /* destination for DVMRP/PIM messages */ u_int32 uv_subnet; /* subnet number (phyints only) */ u_int32 uv_subnetmask; /* subnet mask (phyints only) */ u_int32 uv_subnetbcast;/* subnet broadcast addr (phyints only) */ char uv_name[IFNAMSIZ]; /* interface name */ struct listaddr *uv_groups; /* list of local groups (phyints only) */ struct listaddr *uv_dvmrp_neighbors; /* list of neighboring routers */ nbrbitmap_t uv_nbrmap; /* bitmap of active neighboring routers */ struct listaddr *uv_querier; /* IGMP querier on vif */ int uv_igmpv1_warn;/* To rate-limit IGMPv1 warnings */ int uv_prune_lifetime; /* Prune lifetime or 0 for default */ struct vif_acl *uv_acl; /* access control list of groups */ int uv_leaf_timer; /* time until this vif is considrd leaf */ struct phaddr *uv_addrs; /* Additional subnets on this vif */ struct vif_filter *uv_filter; /* Route filters on this vif */ u_int16 uv_pim_hello_timer;/* timer for sending PIM hello msgs */ u_int16 uv_gq_timer; /* Group Query timer */ u_int16 uv_jp_timer; /* The Join/Prune timer */ int uv_local_pref; /* default local preference for assert */ int uv_local_metric;/* default local metric for assert */ struct pim_nbr_entry *uv_pim_neighbors; /* list of PIM neighbor routers */ #ifdef __linux__ int uv_ifindex; /* because RTNETLINK returns only index */ #endif /* __linux__ */ }; /* TODO: define VIFF_KERNEL_FLAGS */ #define VIFF_KERNEL_FLAGS (VIFF_TUNNEL | VIFF_SRCRT) #define VIFF_DOWN 0x000100 /* kernel state of interface */ #define VIFF_DISABLED 0x000200 /* administratively disabled */ #define VIFF_QUERIER 0x000400 /* I am the subnet's querier */ #define VIFF_ONEWAY 0x000800 /* Maybe one way interface */ #define VIFF_LEAF 0x001000 /* all neighbors are leaves */ #define VIFF_IGMPV1 0x002000 /* Act as an IGMPv1 Router */ #define VIFF_REXMIT_PRUNES 0x004000 /* retransmit prunes */ #define VIFF_PASSIVE 0x008000 /* passive tunnel */ #define VIFF_ALLOW_NONPRUNERS 0x010000 /* ok to peer with nonprunrs */ #define VIFF_NOFLOOD 0x020000 /* don't flood on this vif */ #define VIFF_DR 0x040000 /* designated router */ /* TODO: VIFF_NONBRS == VIFF_ONEWAY? */ #define VIFF_NONBRS 0x080000 /* no neighbor on vif */ #define VIFF_POINT_TO_POINT 0x100000 /* point-to-point link */ #define VIFF_PIM_NBR 0x200000 /* PIM neighbor */ #define VIFF_DVMRP_NBR 0x400000 /* DVMRP neighbor */ struct phaddr { struct phaddr *pa_next; u_int32 pa_subnet; /* extra subnet */ u_int32 pa_subnetmask; /* netmask of extra subnet */ u_int32 pa_subnetbcast; /* broadcast of extra subnet */ }; /* The Access Control List (list with scoped addresses) member */ struct vif_acl { struct vif_acl *acl_next; /* next acl member */ u_int32 acl_addr; /* Group address */ u_int32 acl_mask; /* Group addr. mask */ }; struct vif_filter { int vf_type; #define VFT_ACCEPT 1 #define VFT_DENY 2 int vf_flags; #define VFF_BIDIR 1 struct vf_element *vf_filter; }; struct vf_element { struct vf_element *vfe_next; u_int32 vfe_addr; u_int32 vfe_mask; int vfe_flags; #define VFEF_EXACT 0x0001 }; struct listaddr { struct listaddr *al_next; /* link to next addr, MUST BE FIRST */ u_int32 al_addr; /* local group or neighbor address */ u_long al_timer; /* for timing out group or neighbor */ time_t al_ctime; /* entry creation time */ union { u_int32 alu_genid; /* generation id for neighbor */ u_int32 alu_reporter; /* a host which reported membership */ } al_alu; u_char al_pv; /* router protocol version */ u_char al_mv; /* router mrouted version */ u_char al_old; /* time since heard old report */ u_char al_index; /* neighbor index */ u_long al_timerid; /* timer for group membership */ u_long al_query; /* timer for repeated leave query */ u_int16 al_flags; /* flags related to this neighbor */ }; #define al_genid al_alu.alu_genid #define al_reporter al_alu.alu_reporter #define NBRF_LEAF 0x0001 /* This neighbor is a leaf */ #define NBRF_GENID 0x0100 /* I know this neighbor's genid */ #define NBRF_WAITING 0x0200 /* Waiting for peering to come up */ #define NBRF_ONEWAY 0x0400 /* One-way peering */ #define NBRF_TOOOLD 0x0800 /* Too old (policy decision) */ #define NBRF_TOOMANYROUTES 0x1000 /* Neighbor is spouting routes */ #define NBRF_NOTPRUNING 0x2000 /* Neighbor doesn't appear to prune */ /* * Don't peer with neighbors with any of these flags set */ #define NBRF_DONTPEER (NBRF_WAITING|NBRF_ONEWAY|NBRF_TOOOLD| \ NBRF_TOOMANYROUTES|NBRF_NOTPRUNING) #define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */ /* * Used to get the RPF neighbor and IIF info * for a given source from the unicast routing table. */ struct rpfctl { struct in_addr source; /* the source for which we want iif and rpfnbr */ struct in_addr rpfneighbor;/* next hop towards the source */ vifi_t iif; /* the incoming interface to reach the next hop */ }; pimd-2.1.8/routesock.c0000644000000000000000000002345311700261371011530 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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. * */ #ifndef __linux__ /* XXX: netlink.c is for Linux; both files will merge in the future */ #include #include #include "defs.h" #include #include #ifdef HAVE_ROUTING_SOCKETS #include #endif #include #include #include #ifdef HAVE_ROUTING_SOCKETS union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_dl sdl; } so_dst, so_ifp; typedef union sockunion *sup; int routing_socket = -1; int rtm_addrs; static pid_t pid; struct rt_metrics rt_metrics; u_long rtm_inits; struct { struct rt_msghdr m_rtm; char m_space[512]; } m_rtmsg; /* * Local functions definitions. */ static int getmsg(struct rt_msghdr *, int, struct rpfctl *rpfinfo); /* * TODO: check again! */ #ifdef IRIX #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ : sizeof(__uint64_t)) #else #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ : sizeof(long)) #endif /* IRIX */ #ifdef HAVE_SA_LEN #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) #else #define ADVANCE(x, n) (x += ROUNDUP(sizeof(*(n)))) /* XXX: sizeof(struct sockaddr) */ #endif /* Open and initialize the routing socket */ int init_routesock(void) { #if 0 int on = 0; #endif pid = getpid(); routing_socket = socket(PF_ROUTE, SOCK_RAW, 0); if (routing_socket < 0) { logit(LOG_ERR, 0, "\nRouting socket error"); return -1; } if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1) { logit(LOG_ERR, 0, "\n Routing socket error"); return -1; } #if 0 /* XXX: if it is OFF, no queries will succeed (!?) */ if (setsockopt(routing_socket, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, sizeof(on)) < 0) { logit(LOG_ERR, 0 , "\n setsockopt(SO_USELOOPBACK, 0)"); return -1; } #endif return 0; } /* get the rpf neighbor info */ int k_req_incoming(u_int32 source, struct rpfctl *rpfp) { int rlen, l, flags = RTF_STATIC; sup su; static int seq; char *cp = m_rtmsg.m_space; struct rpfctl rpfinfo; /* TODO: a hack!!!! */ #ifdef HAVE_SA_LEN #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) { \ l = ROUNDUP(u.sa.sa_len); \ memcpy(cp, &(u), l); \ cp += l; \ } #else #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) { \ l = ROUNDUP(sizeof(struct sockaddr)); \ memcpy(cp, &(u), l); \ cp += l; \ } #endif /* HAVE_SA_LEN */ /* initialize */ rpfp->rpfneighbor.s_addr = INADDR_ANY_N; rpfp->source.s_addr = source; /* check if local address or directly connected before calling the * routing socket */ if ((rpfp->iif = find_vif_direct_local(source)) != NO_VIF) { rpfp->rpfneighbor.s_addr = source; return TRUE; } /* prepare the routing socket params */ rtm_addrs |= RTA_DST; rtm_addrs |= RTA_IFP; su = &so_dst; su->sin.sin_family = AF_INET; #ifdef HAVE_SA_LEN su->sin.sin_len = sizeof(struct sockaddr_in); #endif su->sin.sin_addr.s_addr = source; if (inet_lnaof(su->sin.sin_addr) == INADDR_ANY) { IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, "k_req_incoming: Invalid source %s", inet_fmt(source, s1, sizeof(s1))); } return FALSE; } so_ifp.sa.sa_family = AF_LINK; #ifdef HAVE_SA_LEN so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); #endif flags |= RTF_UP; flags |= RTF_HOST; flags |= RTF_GATEWAY; errno = 0; memset (&m_rtmsg, 0, sizeof(m_rtmsg)); #define rtm m_rtmsg.m_rtm rtm.rtm_type = RTM_GET; rtm.rtm_flags = flags; rtm.rtm_version = RTM_VERSION; rtm.rtm_seq = ++seq; rtm.rtm_addrs = rtm_addrs; rtm.rtm_rmx = rt_metrics; rtm.rtm_inits = rtm_inits; NEXTADDR(RTA_DST, so_dst); NEXTADDR(RTA_IFP, so_ifp); rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; if ((rlen = write(routing_socket, (char *)&m_rtmsg, l)) < 0) { IF_DEBUG(DEBUG_RPF | DEBUG_KERN) { if (errno == ESRCH) logit(LOG_DEBUG, 0, "Writing to routing socket: no such route\n"); else logit(LOG_DEBUG, 0, "Error writing to routing socket"); } return FALSE; } do { l = read(routing_socket, (char *)&m_rtmsg, sizeof(m_rtmsg)); } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); if (l < 0) { IF_DEBUG(DEBUG_RPF | DEBUG_KERN) { logit(LOG_DEBUG, errno, "Read from routing socket failed"); } return FALSE; } memset(&rpfinfo, 0, sizeof(rpfinfo)); if (getmsg(&rtm, l, &rpfinfo)) { rpfp->rpfneighbor.s_addr = rpfinfo.rpfneighbor.s_addr; rpfp->iif = rpfinfo.iif; } #undef rtm return TRUE; } static void find_sockaddrs(struct rt_msghdr *rtm, struct sockaddr **dst, struct sockaddr **gate, struct sockaddr **mask, struct sockaddr_dl **ifp) { int i; char *cp = (char *)(rtm + 1); struct sockaddr *sa; if (rtm->rtm_addrs) { for (i = 1; i; i <<= 1) { if (i & rtm->rtm_addrs) { sa = (struct sockaddr *)cp; switch (i) { case RTA_DST: *dst = sa; break; case RTA_GATEWAY: *gate = sa; break; case RTA_NETMASK: *mask = sa; break; case RTA_IFP: if (sa->sa_family == AF_LINK && ((struct sockaddr_dl *)sa)->sdl_nlen) *ifp = (struct sockaddr_dl *)sa; break; } ADVANCE(cp, sa); } } } } /* * Returns TRUE on success, FALSE otherwise. rpfinfo contains the result. */ int getmsg(struct rt_msghdr *rtm, int msglen __attribute__((unused)), struct rpfctl *rpfinfop) { struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; struct sockaddr_dl *ifp = NULL; struct in_addr in; vifi_t vifi; struct uvif *v; if (rpfinfop == (struct rpfctl *)NULL) return FALSE; in = ((struct sockaddr_in *)&so_dst)->sin_addr; IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, "route to: %s", inet_fmt(in.s_addr, s1, sizeof(s1))); } find_sockaddrs(rtm, &dst, &gate, &mask, &ifp); if (!ifp) { /* No incoming interface */ IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, "No incoming interface for destination %s", inet_fmt(in.s_addr, s1, sizeof(s1))); } return FALSE; } if (dst && mask) mask->sa_family = dst->sa_family; if (dst) { in = ((struct sockaddr_in *)dst)->sin_addr; IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, " destination is: %s", inet_fmt(in.s_addr, s1, sizeof(s1))); } } if (gate && (rtm->rtm_flags & RTF_GATEWAY)) { in = ((struct sockaddr_in *)gate)->sin_addr; IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, " gateway is: %s", inet_fmt(in.s_addr, s1, sizeof(s1))); } rpfinfop->rpfneighbor = in; } for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* get the number of the interface by matching the name */ if ((strlen(v->uv_name) == ifp->sdl_nlen) && !(strncmp(v->uv_name, ifp->sdl_data, ifp->sdl_nlen))) break; } IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, " iif is %d", vifi); } rpfinfop->iif = vifi; if (vifi >= numvifs) { IF_DEBUG(DEBUG_RPF) { logit(LOG_DEBUG, 0, "Invalid incoming interface for destination %s, because of invalid virtual interface", inet_fmt(in.s_addr, s1, sizeof(s1))); } return FALSE; /* invalid iif */ } return TRUE; } #else /* !HAVE_ROUTING_SOCKETS */ /* * Return in rpfcinfo the incoming interface and the next hop router * toward source. */ /* TODO: check whether next hop router address is in network or host order */ int k_req_incoming(u_int32 source, struct rpfctl *rpfcinfo) { rpfcinfo->source.s_addr = source; rpfcinfo->iif = NO_VIF; /* just initialized, will be */ /* changed in kernel */ rpfcinfo->rpfneighbor.s_addr = INADDR_ANY; /* initialized */ if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0) { logit(LOG_ERR, errno, "ioctl SIOCGETRPF k_req_incoming"); return FALSE; } return TRUE; } #endif /* HAVE_ROUTING_SOCKETS */ #else /* Linux */ static int dummy __attribute__((unused)); #endif /* !__linux__ */ /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/pimd.conf0000644000000000000000000001113311700261371011136 0ustar # This is the configuration file for "pimd", an IP multicast router. # pimd looks for it in "/etc/pimd.conf". # # $Id: pimd.conf,v 1.17 2001/09/10 20:31:37 pavlin Exp $ # # Command formats: ########## # default_source_preference # default_source_metric # # phyint [disable|enable] [threshold ] [preference

] # [metric ] # [altnet masklen ] # [scoped masklen ] # # cand_rp [] [priority ] [time ] # cand_bootstrap_router [] [priority ] # rp_address [ [masklen ] [priority ]] # # group_prefix [masklen ] # group_prefix [masklen ] # . # . # group_prefix [masklen ] # # # switch_data_threshold [rate interval ] # # switch_register_threshold [rate interval ] ########## # By default PIM will be activated on all interfaces. Use phyint to # disable on interfaces where PIM should not be run. # # Preferences are used by assert elections to determine upstream routers. # Currently pimd cannot reliably obtain preferences and metrics from the # unicast routing protocols, so a default preference may be configured. # In an assert election, the router advertising the lowest assert preference # will be selected as the forwarder and upstream router for the LAN. # 101 should be sufficiently high so that asserts from Cisco or GateD # routers are prefered over poor-little pimd. # # It is reccommended that preferences be set such that metrics are never # consulted. However, default metrics may also be set and will default to # 1024. # # # A "phyint" can be specified by either its IP address or interface name. # # `preference` and `metric` after "phyint" are used to configure manually # the default preference and metric for the Assert messages sent on that # interface. Usually you don't need this, but if you do, think of them # like `preference` and `metric` defined per iif, but used by the # Asserts on the oifs. # # If you want to add "alternative (sub)net" to a physical interface, # e.g., if you want to make incoming traffic with a non-local source address # to appear as it is coming from a local subnet, then use the command: # phyint altnet masklen # XXX: if you use this command, make sure you know what you are doing!! # # If you want administrative scoped multicast filtering, use the # following command: # phyint scoped masklen # This allows interfaces to be configured as an administrative boundary # for the specified scoped address. Packets belonging to the scoped # address will not be forwarded. To use this compile with -DSCOPED_ACL # option (in Makefile). # # `local-addr` after "cand_rp" and "cand_bootstrap_router" specifies # the local address to be used in the Cand-RP and Cand-BSR messages. # If not specified, the largest local IP address will be used (excluding # the disabled interfaces) # # `time` after `cand_rp` specifies how often to send the Cand-RP messages. # Its default value should be 60 seconds. Use smaller value for faster # convergence. # # `group_prefix` is/are the prefix(es) advertised if cand_rp # # It is possible to set a static Rendez-Vous Point using the "rp_address" # setting. The argument can be either a unicast or a multicast address # followed by an optional group address and optional masklen to that. # # `rate` specifies the minimum rate in bits/s before the last hop # router or the RP switch to the shortest path (`switch_data_threshold` # and `switch_register_threshold` respectively) # `interval` specifies the interval for periodical testing of the rate # Currently, `interval` must be at least 5 (seconds) # XXX: Both intervals should be the same # # #default_source_preference 101 # smaller is better #default_source_metric 1024 # smaller is better # The phyint setting MUST BE AFTER default_source_*, # BUT MUST BE BEFORE everything else # By default, all non-loopback multicast capable interfaces are enabled. #phyint de1 disable # Smaller value means "higher" priority cand_rp time 30 priority 20 # Bigger value means "higher" priority cand_bootstrap_router priority 5 # Static rendez-vous point #rp_address 192.168.10.1 224.0.0.0 masklen 8 priority 5 # All multicast groups group_prefix 224.0.0.0 masklen 4 # switch_data_threshold rate 50000 interval 20 # 50kbps (approx.) switch_register_threshold rate 50000 interval 20 # 50kbps (approx.) pimd-2.1.8/mrt.h0000644000000000000000000003071511700261371010320 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: mrt.h,v 1.16 2001/09/10 20:31:36 pavlin Exp $ */ #define MRTF_SPT 0x0001 /* iif toward source */ #define MRTF_WC 0x0002 /* (*,G) entry */ #define MRTF_RP 0x0004 /* iif toward RP */ #define MRTF_NEW 0x0008 /* new created routing entry */ #define MRTF_IIF_REGISTER 0x0020 /* ??? */ #define MRTF_REGISTER 0x0080 /* ??? */ #define MRTF_KERNEL_CACHE 0x0200 /* a mirror for the kernel cache */ #define MRTF_NULL_OIF 0x0400 /* null oif cache.. ??? */ #define MRTF_REG_SUPP 0x0800 /* register suppress ??? */ #define MRTF_ASSERTED 0x1000 /* upstream is not that of src ??? */ #define MRTF_SG 0x2000 /* (S,G) pure, not hanging off of (*,G)*/ #define MRTF_PMBR 0x4000 /* (*,*,RP) entry (for interop) */ #define MRTF_MFC_CLONE_SG 0x8000 /* clone (S,G) MFC from (*,G) or (*,*,RP) */ /* Macro to duplicate oif info (oif bits, timers) */ #define VOIF_COPY(from, to) \ do { \ VIFM_COPY((from)->joined_oifs, (to)->joined_oifs); \ VIFM_COPY((from)->oifs, (to)->oifs); \ VIFM_COPY((from)->leaves, (to)->leaves); \ VIFM_COPY((from)->pruned_oifs, (to)->pruned_oifs); \ VIFM_COPY((from)->asserted_oifs, (to)->asserted_oifs); \ memcpy((to)->vif_timers, (from)->vif_timers, \ numvifs * sizeof((from)->vif_timers[0])); \ memcpy((to)->vif_deletion_delay, (from)->vif_deletion_delay, \ numvifs * sizeof((from)->vif_deletion_delay[0])); \ } while (0) #define FREE_MRTENTRY(mrtentry_ptr) \ do { \ kernel_cache_t *prev; \ kernel_cache_t *next; \ \ free((char *)((mrtentry_ptr)->vif_timers)); \ free((char *)((mrtentry_ptr)->vif_deletion_delay)); \ for (next = (mrtentry_ptr)->kernel_cache; \ next != (kernel_cache_t *)NULL; ) { \ prev = next; next = next->next; \ free(prev); \ } \ free((char *)((mrtentry_ptr)->kernel_cache)); \ free((char *)(mrtentry_ptr)); \ } while (0) /* * The complicated structure used by the more complicated Join/Prune * message building */ typedef struct build_jp_message_ { struct build_jp_message_ *next; /* Used to chain the free entries */ u_int8 *jp_message; /* The Join/Prune message */ u_int32 jp_message_size; /* Size of the Join/Prune message (in bytes) */ u_int16 holdtime; /* Join/Prune message holdtime field */ u_int32 curr_group; /* Current group address */ u_int8 curr_group_msklen;/* Current group masklen */ u_int8 *join_list; /* The working area for the join addresses */ u_int32 join_list_size; /* The size of the join_list (in bytes) */ u_int16 join_addr_number; /* Number of the join addresses in join_list */ u_int8 *prune_list; /* The working area for the prune addresses */ u_int32 prune_list_size; /* The size of the prune_list (in bytes) */ u_int16 prune_addr_number;/* Number of the prune addresses in prune_list*/ u_int8 *rp_list_join; /* The working area for RP join addresses */ u_int32 rp_list_join_size;/* The size of the rp_list_join (in bytes) */ u_int16 rp_list_join_number;/* Number of RP addresses in rp_list_join */ u_int8 *rp_list_prune; /* The working area for RP prune addresses */ u_int32 rp_list_prune_size;/* The size of the rp_list_prune (in bytes) */ u_int16 rp_list_prune_number;/* Number of RP addresses in rp_list_prune */ u_int8 *num_groups_ptr; /* Pointer to number_of_groups in jp_message */ } build_jp_message_t; typedef struct pim_nbr_entry { struct pim_nbr_entry *next; /* link to next neighbor */ struct pim_nbr_entry *prev; /* link to prev neighbor */ u_int32 address; /* neighbor address */ vifi_t vifi; /* which interface */ u_int16 timer; /* for timing out neighbor */ build_jp_message_t *build_jp_message; /* A structure for fairly * complicated Join/Prune * message construction. */ } pim_nbr_entry_t; typedef struct srcentry { struct srcentry *next; /* link to next entry */ struct srcentry *prev; /* link to prev entry */ u_int32 address; /* source or RP address */ struct mrtentry *mrtlink; /* link to routing entries */ vifi_t incoming; /* incoming vif */ struct pim_nbr_entry *upstream; /* upstream router */ u_int32 metric; /* Unicast Routing Metric to the source */ u_int32 preference; /* The metric preference (for assers)*/ u_int16 timer; /* Entry timer??? Delete? */ struct cand_rp *cand_rp; /* Used if this is rpentry_t */ } srcentry_t; typedef srcentry_t rpentry_t; /* (RP<->group) matching table related structures */ typedef struct cand_rp { struct cand_rp *next; /* Next candidate RP */ struct cand_rp *prev; /* Previous candidate RP */ struct rp_grp_entry *rp_grp_next; /* The rp_grp_entry chain for that RP*/ rpentry_t *rpentry; /* Pointer to the RP entry */ } cand_rp_t; typedef struct grp_mask { struct grp_mask *next; struct grp_mask *prev; struct rp_grp_entry *grp_rp_next; u_int32 group_addr; u_int32 group_mask; u_int32 hash_mask; u_int16 fragment_tag; /* Used for garbage collection */ u_int8 group_rp_number; /* Used when assembling segments */ } grp_mask_t; typedef struct rp_grp_entry { struct rp_grp_entry *rp_grp_next;/* Next entry for same RP */ struct rp_grp_entry *rp_grp_prev;/* Prev entry for same RP */ struct rp_grp_entry *grp_rp_next;/* Next entry for same grp prefix */ struct rp_grp_entry *grp_rp_prev;/* Prev entry for same grp prefix */ struct grpentry *grplink; /* Link to all grps via this entry*/ u_int16 holdtime; /* The RP holdtime */ u_int16 fragment_tag; /* The fragment tag from the * received BSR message */ u_int8 priority; /* The RP priority */ grp_mask_t *group; /* Pointer to (group,mask) entry */ cand_rp_t *rp; /* Pointer to the RP */ } rp_grp_entry_t; typedef struct grpentry { struct grpentry *next; /* link to next entry */ struct grpentry *prev; /* link to prev entry */ struct grpentry *rpnext; /* next grp for the same RP */ struct grpentry *rpprev; /* prev grp for the same RP */ u_int32 group; /* subnet group of multicasts */ u_int32 rpaddr; /* The IP address of the RP */ struct mrtentry *mrtlink; /* link to (S,G) routing entries */ rp_grp_entry_t *active_rp_grp;/* Pointer to the active rp_grp entry*/ struct mrtentry *grp_route; /* Pointer to the (*,G) routing entry*/ } grpentry_t; typedef struct mrtentry { struct mrtentry *grpnext; /* next entry of same group */ struct mrtentry *grpprev; /* prev entry of same group */ struct mrtentry *srcnext; /* next entry of same source */ struct mrtentry *srcprev; /* prev entry of same source */ struct grpentry *group; /* pointer to group entry */ struct srcentry *source; /* pointer to source entry (or RP) */ vifi_t incoming; /* the iif (either toward S or RP) */ vifbitmap_t oifs; /* The current result oifs */ vifbitmap_t joined_oifs; /* The joined oifs (Join received) */ vifbitmap_t pruned_oifs; /* The pruned oifs (Prune received) */ vifbitmap_t asserted_oifs; /* The asserted oifs (lost Assert) */ vifbitmap_t leaves; /* Has directly connected members */ struct pim_nbr_entry *upstream; /* upstream router, needed because * of the asserts it may be different * than the source (or RP) upstream * router. */ u_int32 metric; /* Routing Metric for this entry */ u_int32 preference; /* The metric preference value */ u_int32 pmbr_addr; /* The PMBR address (for interop) */ u_int16 *vif_timers; /* vifs timer list */ u_int16 *vif_deletion_delay; /* vifs deletion delay list */ u_int16 flags; /* The MRTF_* flags */ u_int16 timer; /* entry timer */ u_int16 jp_timer; /* The Join/Prune timer */ u_int16 rs_timer; /* Register-Suppression Timer */ u_int assert_timer; u_int assert_rate_timer; struct kernel_cache *kernel_cache; /* List of the kernel cache entries */ #ifdef RSRR struct rsrr_cache *rsrr_cache; /* Used to save RSRR requests for * routes change notification. */ #endif /* RSRR */ } mrtentry_t; /* * Used to get forwarded data related counts (number of packet, number of * bits, etc) */ struct sg_count { u_long pktcnt; /* Number of packets for (s,g) */ u_long bytecnt; /* Number of bytes for (s,g) */ u_long wrong_if; /* Number of packets received on wrong iif for (s,g) */ }; struct vif_count { u_long icount; /* Input packet count on vif */ u_long ocount; /* Output packet count on vif */ u_long ibytes; /* Input byte count on vif */ u_long obytes; /* Output byte count on vif */ }; /* * Structure to keep track of existing (S,G) MFC entries in the kernel * for particular (*,G) or (*,*,RP) entry. We must keep track for * each active source which doesn't have (S,G) entry in the daemon's * routing table. We need to keep track of such sources for two reasons: * * (1) If the kernel does not support (*,G) MFC entries (currently, the * "official" mcast code doesn't), we must know all installed (s,G) entries * in the kernel and modify them if the iif or oif for the (*,G) changes. * * (2) By checking periodically the traffic coming from the shared tree, * we can either delete the idle sources or switch to the shortest path. * * Note that even if we have (*,G) implemented in the kernel, we still * need to have this structure because of (2) */ typedef struct kernel_cache { struct kernel_cache *next; struct kernel_cache *prev; u_int32 source; u_int32 group; struct sg_count sg_count; /* The (s,g) data retated counters (see above) */ } kernel_cache_t; /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/debug.h0000644000000000000000000001024211700261371010575 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: debug.h,v 1.8 2001/09/10 20:31:36 pavlin Exp $ */ /* * 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. * */ extern unsigned long debug; extern int log_nmsgs; #define IF_DEBUG(l) if (debug && debug & (l)) #define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */ #define LOG_SHUT_UP 600 /* shut up for 10 minutes */ /* Debug values definition */ /* DVMRP reserved for future use */ #define DEBUG_DVMRP_PRUNE 0x00000001 #define DEBUG_DVMRP_ROUTE 0x00000002 #define DEBUG_DVMRP_PEER 0x00000004 #define DEBUG_DVMRP_TIMER 0x00000008 #define DEBUG_DVMRP_DETAIL 0x01000000 #define DEBUG_DVMRP ( DEBUG_DVMRP_PRUNE | DEBUG_DVMRP_ROUTE | \ DEBUG_DVMRP_PEER ) /* IGMP related */ #define DEBUG_IGMP_PROTO 0x00000010 #define DEBUG_IGMP_TIMER 0x00000020 #define DEBUG_IGMP_MEMBER 0x00000040 #define DEBUG_MEMBER DEBUG_IGMP_MEMBER #define DEBUG_IGMP ( DEBUG_IGMP_PROTO | DEBUG_IGMP_TIMER | \ DEBUG_IGMP_MEMBER ) /* Misc */ #define DEBUG_TRACE 0x00000080 #define DEBUG_TIMEOUT 0x00000100 #define DEBUG_PKT 0x00000200 /* Kernel related */ #define DEBUG_IF 0x00000400 #define DEBUG_KERN 0x00000800 #define DEBUG_MFC 0x00001000 #define DEBUG_RSRR 0x00002000 /* PIM related */ #define DEBUG_PIM_HELLO 0x00004000 #define DEBUG_PIM_REGISTER 0x00008000 #define DEBUG_PIM_JOIN_PRUNE 0x00010000 #define DEBUG_PIM_BOOTSTRAP 0x00020000 #define DEBUG_PIM_ASSERT 0x00040000 #define DEBUG_PIM_CAND_RP 0x00080000 #define DEBUG_PIM_MRT 0x00100000 #define DEBUG_PIM_TIMER 0x00200000 #define DEBUG_PIM_RPF 0x00400000 #define DEBUG_RPF DEBUG_PIM_RPF #define DEBUG_PIM_DETAIL 0x00800000 #define DEBUG_PIM ( DEBUG_PIM_HELLO | DEBUG_PIM_REGISTER | \ DEBUG_PIM_JOIN_PRUNE | DEBUG_PIM_BOOTSTRAP | \ DEBUG_PIM_ASSERT | DEBUG_PIM_CAND_RP | \ DEBUG_PIM_MRT | DEBUG_PIM_TIMER | \ DEBUG_PIM_RPF ) #define DEBUG_MRT ( DEBUG_DVMRP_ROUTE | DEBUG_PIM_MRT ) #define DEBUG_NEIGHBORS ( DEBUG_DVMRP_PEER | DEBUG_PIM_HELLO ) #define DEBUG_TIMER ( DEBUG_IGMP_TIMER | DEBUG_DVMRP_TIMER | \ DEBUG_PIM_TIMER ) #define DEBUG_ASSERT ( DEBUG_PIM_ASSERT ) #define DEBUG_ALL 0xffffffff #define DEBUG_DEFAULT 0xffffffff/* default if "-d" given without value */ pimd-2.1.8/pimd.80000644000000000000000000002502711700261371010367 0ustar .\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .Dd $Mdocdate: Aug 22 2010 $ .\" Please adjust this date whenever revising the manpage. .Dt PIMD 8 SMM .Os .Sh NAME .Nm pimd .Nd PIM-SM v2 dynamic multicast routing daemon .Sh SYNOPSIS .Nm pimd .Op Fl fhlNqr .Op Fl c Ar FILE .Op Fl d Op Ar [LEVEL[,LEVEL,...] .Sh DESCRIPTION .Nm is a lightweight stand-alone PIM-SM v2 multicast routing daemon. This is the original USC (netweb/catarina) implementation of the protocol, which nowadays is fully free to use under the 3-clause BSD license. .Pp Protocol Independent Multicast - Sparse Mode (PIM-SM): .Bl -bullet -compact .It maintains the traditional IP multicast service model of receiver-initiated membership; .It uses explicit joins that propagate hop-by-hop from members' directly connected routers toward the distribution tree. .It builds a shared multicast distribution tree centered at a Rendezvous Point, and then builds source-specific trees for those sources whose data traffic warrants it. .It is not dependent on a specific unicast routing protocol; and .It uses soft-state mechanisms to adapt to underlying network conditions and group dynamics. .El .Pp The robustness, flexibility, and scaling properties of this architecture make it well suited to large heterogeneous internetworks. .Pp .Nm implements RFC 2362, which has been obsoleted by RFC 4601. Please see the TODO file for more information on this. .Sh OPTIONS This program follows the usual UNIX command line syntax, with long options starting with two dashes (`-'). The options are as follows: .Bl -tag -width Ds .It Fl h, -help Print a help message and exit. .It Fl c, -config=FILE Specify an alternative configuration file, instead of the default .Pa /etc/pimd.conf . .It Fl d, -debug[=LEVEL[,LEVEL...] By default, .Nm detaches from the invoking terminal. If this option is specified, .Nm it runs in foreground of the starting terminal and responds to signals. If .Fl d is given with no argument, the debug level defaults to .Nm igmp, cache, interface, groups, prunes, routes and peers . .sp Regardless of the debug level, .Nm always writes warning and error messages to the system log daemon. Debug levels have the following effects: .Pp .Bl -tag -width TERM -compact -offset indent .It Cm packet Debug inbound/outbout packets .It Cm prunes Pruning operations, or pruned routes .It Cm routes Routing messages .It Cm rtdetail Detailed routing information .It Cm peers Neighbor gossip .It Cm cache Debug routing cache .It Cm timeout Debug timeouts .It Cm interface Show interface, or vif, debug messages .It Cm groups Debug group memberships .It Cm mtrace Multicast traceroute information .It Cm igmp Debug IGMP messages .It Cm icmp Debug ICMP messages .It Cm rsrr Debug RSRR messages .It Cm pim All PIM messages .It Cm pim_routes PIM routing messages .It Cm pim_bsr PIM bootstrap router messages .It Cm pim_detail Detailed PIM debug .It Cm pim_hello Debug hello messages to/from neighbors .El .It Fl f, -foreground Run in foreground, do not detach from calling terminal .It Fl l, -reload-config Tell a running pimd to reload its configuration. This is done by sending a SIGHUP to the PID listed in .Pa /var/run/pimd.pid . .It Fl N, -disable-vifs This prevents .Nm from being activated on all interfaces by default. Use `phyint enable` to selectively activate it. .It Fl q, -quit-daemon Tell a running pimd to quit. Similar to --reload-config but this command sends SIGTERM. .It Fl r, -show-routes Show state of VIFs and multicast routing tables. This is command sends SIGUSR1 to a running pimd, similar to --reload-config. .It Fl v, -version Show .Nm version .El .Sh CONFIGURATION The configuration is kept in the file .Pa /etc/pimd.conf . The file format is free-form: whitespace (including newlines) is not significant. There are eight different types of configuration commands: .Bl -item -offset indent .It .Cm default_source_preference .Ar .It .Cm default_source_metric .Ar .It .Cm phyint .Ar .Oo .Cm disable Ns | Ns Cm enable .Oc .br .Oo .Cm altnet .Ar Cm masklen Ar .Oc .br .Oo .Cm scoped .Ar Cm masklen Ar .Oc .br .Op Cm threshold Ar thr .Op Cm preference Ar pref .Op Cm metric Ar cost .It .Cm cand_rp .Op .Op Cm priority Ar .Op Cm time Ar .It .Cm cand_bootstrap_router .Op .Op Cm priority Ar .It .Cm rp_address .Ar [ [masklen ]] .It .Cm group_prefix .Ar .Op Cm masklen Ar .Op Cm priority Ar .It .Cm switch_data_threshold .Op Cm rate Ar Cm interval Ar .It .Cm switch_register_threshold .Op Cm rate Ar Cm interval Ar .El .Pp By default, .Nm will be activated on all multicast capable interfaces. The .Cm phyint setting and the .Fl N command line option control this behaviour. More on .Cm phyint below. .Pp The .Cm default_source_preference option is used by assert elections to determine upstream routers. Currently pimd cannot reliably obtain preferences and metrics from the unicast routing protocols, so a default preference may be configured. In an assert election, the router advertising the lowest assert preference will be selected as the forwarder and upstream router for the LAN. Setting 101 should be sufficiently high so that asserts from Cisco or GateD routers are prefered over poor-little pimd. .Pp It is reccommended that preferences be set such that metrics are never consulted. However, default metrics may also be set using the .Cm default_source_metric option. This item sets the cost for sending data through this router. You want only PIM-SM data to go to this daemon; so once again, a high value is recommended to prevent accidental usage. The preferred default value is 1024. .Pp The .Nm phyint option refers to a physical interface and must come after .Cm default_source_metric . Select the interface either by its IP address .Ar local-addr or interface name .Ar ifname (e.g. le0). If you just want to activate this interface with default values, you don't need to put anything else on the line. However, there are some additional settings: .Bl -bullet -compact .It .Nm disable . Do not send PIM-SM traffic through this interface nor listen for PIM-SM traffic from this interface. Default: enable. .Nm enable . Selectively enable which interfaces to send PIM-SM traffic through. Useful with the .Fl N command line option. .It .Nm preference pref . This interface's value in an election. It will have the .Nm default_source_preference if not assigned. .It .Nm metric cost . The cost of sending data through this interface. It will have the .Nm default_source_metric if not assigned. .El .Pp Add one .Nm phyint line per interface on this router. If you don't do this, .Nm pimd will either be completely silent (if you provide the .Fl N command line option), or simply assume that you want it to utilize all interfaces using default settings. .Pp The .Nm cand_rp setting refers to Candidate Rendez-vous Point (CRP). It specifies which interface on this machine should be included in RP elections. .Bl -bullet -compact .It .Nm local-addr . The default is the highest active IP address. .It .Nm time number . The number of seconds to wait between advertising this CRP. The default value is 60 seconds. .It .Nm priority number . How important this CRP is compared to others. The lower the value here, the more important the CRP. .El .Pp The .Nm cand_bootstrap_router setting is similar to CRP. Only difference is the lack of a .Nm time option. .Pp The .Nm group_prefix statement outlines the set of multicast addresses that the CRP, if it wins an election, will advertise to other routers. .Bl -bullet -compact .It .Nm group-addr . A specific multicast group or network range this router will handle. .It .Nm masklen len . The number of IP address segments taken up by the netmask. Remember that a multicast address is a Class D and has a netmask of 240.0.0.0, which means its length is 4. .El .Pp Max .Nm group_prefix multicast addresses supported in pimd is 255. .Pp The .Nm rp_address setting is for static Rendez-vous Point configurations. The argument can either be a unicast address or a multicast group, with an optional group address, mask length, and priority arguments. .Pp The .Nm switch_data_threshold setting defines the threshold at which transmission rates trigger the changeover from the shared tree to the RP tree; starting the line with .Nm switch_register_threshold does the opposite in the same format. Regardless of which of these you choose, the rate option is for transmission rate in bits per second, interval is the sample rate in seconds -- with a recommended minimum of five seconds. It is recommended to have the same interval if both settings are used. .Sh SIGNALS .Nm responds to the following signals: .Pp .Bl -tag -width TERM -compact .It HUP Restarts .Nm . The configuration file is reread every time this signal is evoked. .It TERM Terminates execution gracefully (i.e. by sending good-bye messages to all neighboring routers). .It INT The same as TERM. .It USR1 Dumps the internal state of VIFs and multicast routing tables to .Pa /var/run/pimd/pimd.dump . See also the --show-routes option above. .\" Not implemented yet, still TODO .\" .It USR2 .\" Dumps the internal cache tables to .\" .Pa /var/run/pimd/pimd.cache . .\" Also not implemented yet, TODO .\" .It QUIT .\" Dumps the internal routing tables to stderr (only if .\" .Nm .\" was invoked with a non-zero debug level). .El .Pp For convenience in sending signals, .Nm writes its process ID to .Pa /var/run/pimd.pid upon startup. .Sh FILES .Bl -tag -width /var/run/pimd/pimd.cache -compact .It Pa /etc/pimd.conf .\" .It Pa /var/run/pimd/pimd.cache .It Pa /var/run/pimd/pimd.dump .It Pa /var/run/pimd.pid .El .Sh SEE ALSO .Xr mrouted 8 , .Xr smcroute 8 , .Xr /usr/share/doc/pimd/ .Pp PIM-SM is described in, the now obsolete RFC 2362, and the current RFC 4601, with additions in RFC 5059 and RFC 5796. .Pp The pages at USC, http://netweb.usc.edu/pim/, are unfortunately no longer available. The wiki pages at http://github.com/troglobit/pimd/, the new GitHub project, are an attempt to gather as much info as possible. .Sh AUTHORS .Nm was written by Ahmed Helmy, George Edmond "Rusty" Eddy, and Pavlin Ivanov Radoslavov. With contributions by many others. .Pp This manual page was initially written by Antonín Král for the Debian GNU/Linux system, and then updated by Joachim Nilsson for the GitHub pimd project. pimd-2.1.8/route.c0000644000000000000000000011644211700261371010651 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: route.c,v 1.39 2003/02/12 21:56:55 pavlin Exp $ */ #include "defs.h" /* Marian Stagarescu : 07/31/01: * * Administrative scoped multicast filtering im PIMD. This allows an * interface to be configured as an administrative boundary for the * specified scoped address. Packets belonging to the scoped address will * not be forwarded. * * Please note the in order to minimize the search for the matching groups * the implementation is limited to: * * Packets are stopped from being forwarded by installing a NULL outgoing * interface; the user space (pimd) is not up-call-ed any more for * these packets which are dropped by kernel (nil oif) except for * when we de-install the route are re-create it (timer 3 minute). * uses the VIF acl that was installed via config scoped statements. * * this is not an all-purpose packet filtering mechanism. * we tried here to achieve the filtering with minimal processing * (inspect (g) when we are about to install a route for it). * * to use it edit pimd.conf and compile with -DSCOPED_ACL */ static void process_cache_miss (struct igmpmsg *igmpctl); static void process_wrong_iif (struct igmpmsg *igmpctl); static void process_whole_pkt (char *buf); u_int32 default_source_metric = UCAST_DEFAULT_SOURCE_METRIC; u_int32 default_source_preference = UCAST_DEFAULT_SOURCE_PREFERENCE; #ifdef SCOPED_ACL /* from mrouted. Contributed by Marian Stagarescu */ static int scoped_addr(vifi_t vifi, u_int32 addr) { struct vif_acl *acl; for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next) { if ((addr & acl->acl_mask) == acl->acl_addr) return 1; } return 0; } /* Contributed by Marian Stagarescu * adapted from mrouted: check for scoped multicast addresses * install null oif if matched */ #define APPLY_SCOPE(g,mp) { \ vifi_t i; \ for (i = 0; i < numvifs; i++) \ if (scoped_addr(i, g)) \ (mp)->oifs = NULL; \ } #endif /* SCOPED_ACL */ /* Return the iif for given address */ vifi_t get_iif(u_int32 address) { struct rpfctl rpfc; k_req_incoming(address, &rpfc); if (rpfc.rpfneighbor.s_addr == INADDR_ANY_N) return (NO_VIF); return (rpfc.iif); } /* Return the PIM neighbor toward a source */ /* If route not found or if a local source or if a directly connected source, * but is not PIM router, or if the first hop router is not a PIM router, * then return NULL. */ pim_nbr_entry_t *find_pim_nbr(u_int32 source) { struct rpfctl rpfc; pim_nbr_entry_t *pim_nbr; u_int32 next_hop_router_addr; if (local_address(source) != NO_VIF) return NULL; k_req_incoming(source, &rpfc); if ((rpfc.rpfneighbor.s_addr == INADDR_ANY_N) || (rpfc.iif == NO_VIF)) return NULL; next_hop_router_addr = rpfc.rpfneighbor.s_addr; for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors; pim_nbr != NULL; pim_nbr = pim_nbr->next) if (pim_nbr->address == next_hop_router_addr) return(pim_nbr); return NULL; } /* TODO: check again the exact setup if the source is local or directly * connected!!! */ /* TODO: XXX: change the metric and preference for all (S,G) entries per * source or RP? */ /* TODO - If possible, this would be the place to correct set the * source's preference and metric to that obtained from the kernel * and/or unicast routing protocol. For now, set it to the configured * default for local pref/metric. */ /* * Set the iif, upstream router, preference and metric for the route * toward the source. Return TRUE is the route was found, othewise FALSE. * If srctype==PIM_IIF_SOURCE and if the source is directly connected * then the "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then * "upstream" in case of directly connected "source" will be that "source" * (if it is also PIM router)., */ int set_incoming(srcentry_t *srcentry_ptr, int srctype) { struct rpfctl rpfc; u_int32 source = srcentry_ptr->address; u_int32 neighbor_addr; struct uvif *v; pim_nbr_entry_t *n; /* Preference will be 0 if directly connected */ srcentry_ptr->metric = 0; srcentry_ptr->preference = 0; /* The source is a local address */ if ((srcentry_ptr->incoming = local_address(source)) != NO_VIF) { /* iif of (*,G) at RP has to be register_if */ if (srctype == PIM_IIF_RP) srcentry_ptr->incoming = reg_vif_num; /* TODO: set the upstream to myself? */ srcentry_ptr->upstream = NULL; return TRUE; } if ((srcentry_ptr->incoming = find_vif_direct(source)) != NO_VIF) { /* The source is directly connected. Check whether we are * looking for real source or RP */ if (srctype == PIM_IIF_SOURCE) { srcentry_ptr->upstream = NULL; return (TRUE); } else { /* PIM_IIF_RP */ neighbor_addr = source; } } else { /* TODO: probably need to check the case if the iif is disabled */ /* Use the lastest resource: the kernel unicast routing table */ k_req_incoming(source, &rpfc); if ((rpfc.iif == NO_VIF) || rpfc.rpfneighbor.s_addr == INADDR_ANY_N) { /* couldn't find a route */ IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF) logit(LOG_DEBUG, 0, "NO ROUTE found for %s", inet_fmt(source, s1, sizeof(s1))); return FALSE; } srcentry_ptr->incoming = rpfc.iif; neighbor_addr = rpfc.rpfneighbor.s_addr; /* set the preference for sources that aren't directly connected. */ v = &uvifs[srcentry_ptr->incoming]; srcentry_ptr->preference = v->uv_local_pref; srcentry_ptr->metric = v->uv_local_metric; } /* * The upstream router must be a (PIM router) neighbor, otherwise we * are in big trouble ;-) */ v = &uvifs[srcentry_ptr->incoming]; for (n = v->uv_pim_neighbors; n != NULL; n = n->next) { if (ntohl(neighbor_addr) < ntohl(n->address)) continue; if (neighbor_addr == n->address) { /* *The upstream router is found in the list of neighbors. * We are safe! */ srcentry_ptr->upstream = n; IF_DEBUG(DEBUG_RPF) logit(LOG_DEBUG, 0, "For src %s, iif is %d, next hop router is %s", inet_fmt(source, s1, sizeof(s1)), srcentry_ptr->incoming, inet_fmt(neighbor_addr, s2, sizeof(s2))); return TRUE; } break; } /* TODO: control the number of messages! */ logit(LOG_INFO, 0, "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER", inet_fmt(source, s1, sizeof(s1)), srcentry_ptr->incoming, inet_fmt(neighbor_addr, s2, sizeof(s2))); srcentry_ptr->upstream = NULL; return FALSE; } /* * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where * we have source-specific Join/Prune. */ void add_leaf(vifi_t vifi, u_int32 source __attribute__((unused)), u_int32 group) { mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_srcs; vifbitmap_t old_oifs; vifbitmap_t new_oifs; vifbitmap_t new_leaves; if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP) return; /* Don't create routing entries for the LAN scoped addresses */ /* * XXX: only if I am a DR, the IGMP Join should result in creating * a PIM MRT state. * XXX: Each router must know if it has local members, i.e., whether * it is a last-hop router as well. This info is needed so it will * know whether is allowed to initiate a SPT switch by sending * a PIM (S,G) Join to the high datarate source. * However, if a non-DR last-hop router has not received * a PIM Join, it should not create a PIM state, otherwise later * this state may incorrectly trigger PIM joins. * There is a design flow in pimd, so without making major changes * the best we can do is that the non-DR last-hop router will * record the local members only after it receives PIM Join from the DR * (i.e. after the second or third IGMP Join by the local member). * The downside is that a last-hop router may delay the initiation * of the SPT switch. Sigh... */ if (uvifs[vifi].uv_flags & VIFF_DR) mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE); else mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE); if (mrtentry_ptr == NULL) return; IF_DEBUG(DEBUG_MRT) logit(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi, inet_fmt(group, s1, sizeof(s1))); if (VIFM_ISSET(vifi, mrtentry_ptr->leaves)) return; /* Already a leaf */ calc_oifs(mrtentry_ptr, &old_oifs); VIFM_COPY(mrtentry_ptr->leaves, new_leaves); VIFM_SET(vifi, new_leaves); /* Add the leaf */ change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, new_leaves, mrtentry_ptr->asserted_oifs, 0); calc_oifs(mrtentry_ptr, &new_oifs); /* Only if I am the DR for that subnet, eventually initiate a Join */ if (!(uvifs[vifi].uv_flags & VIFF_DR)) return; if ((mrtentry_ptr->flags & MRTF_NEW) || (VIFM_ISEMPTY(old_oifs) && (!VIFM_ISEMPTY(new_oifs)))) { /* A new created entry or the oifs have changed * from NULL to non-NULL. */ mrtentry_ptr->flags &= ~MRTF_NEW; FIRE_TIMER(mrtentry_ptr->jp_timer); /* Timeout the Join/Prune timer */ /* TODO: explicitly call the function below? send_pim_join_prune(mrtentry_ptr->upstream->vifi, mrtentry_ptr->upstream, PIM_JOIN_PRUNE_HOLDTIME); */ } /* Check all (S,G) entries and set the inherited "leaf" flag. * TODO: XXX: This won't work for IGMPv3, because there we don't know * whether the (S,G) leaf oif was inherited from the (*,G) entry or * was created by source specific IGMP join. */ for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { VIFM_COPY(mrtentry_srcs->leaves, new_leaves); VIFM_SET(vifi, new_leaves); change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, new_leaves, mrtentry_srcs->asserted_oifs, 0); } } /* * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where * we have source-specific joins/prunes. */ void delete_leaf(vifi_t vifi, u_int32 source __attribute__((unused)), u_int32 group) { mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_srcs; vifbitmap_t new_oifs; vifbitmap_t old_oifs; vifbitmap_t new_leaves; mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE); if (mrtentry_ptr == NULL) return; if (!VIFM_ISSET(vifi, mrtentry_ptr->leaves)) return; /* This interface wasn't leaf */ calc_oifs(mrtentry_ptr, &old_oifs); VIFM_COPY(mrtentry_ptr->leaves, new_leaves); VIFM_CLR(vifi, new_leaves); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, new_leaves, mrtentry_ptr->asserted_oifs, 0); calc_oifs(mrtentry_ptr, &new_oifs); if ((!VIFM_ISEMPTY(old_oifs)) && VIFM_ISEMPTY(new_oifs)) { /* The result oifs have changed from non-NULL to NULL */ FIRE_TIMER(mrtentry_ptr->jp_timer); /* Timeout the Join/Prune timer */ /* TODO: explicitly call the function? send_pim_join_prune(mrtentry_ptr->upstream->vifi, mrtentry_ptr->upstream, PIM_JOIN_PRUNE_HOLDTIME); */ } /* Check all (S,G) entries and clear the inherited "leaf" flag. * TODO: XXX: This won't work for IGMPv3, because there we don't know * whether the (S,G) leaf oif was inherited from the (*,G) entry or * was created by source specific IGMP join. */ for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { VIFM_COPY(mrtentry_srcs->leaves, new_leaves); VIFM_CLR(vifi, new_leaves); change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, new_leaves, mrtentry_srcs->asserted_oifs, 0); } } void calc_oifs(mrtentry_t *mrtentry_ptr, vifbitmap_t *oifs_ptr) { vifbitmap_t oifs; mrtentry_t *grp_route; mrtentry_t *rp_route; /* * oifs = * (((copied_outgoing + my_join) - my_prune) + my_leaves) * - my_asserted_oifs - incoming_interface, * i.e. `leaves` have higher priority than `prunes`, but lower priority * than `asserted`. The incoming interface is always deleted from the oifs */ if (mrtentry_ptr == NULL) { VIFM_CLRALL(*oifs_ptr); return; } VIFM_CLRALL(oifs); if (!(mrtentry_ptr->flags & MRTF_PMBR)) { /* Either (*,G) or (S,G). Merge with the oifs from the (*,*,RP) */ if ((rp_route = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink) != NULL) { VIFM_MERGE(oifs, rp_route->joined_oifs, oifs); VIFM_CLR_MASK(oifs, rp_route->pruned_oifs); VIFM_MERGE(oifs, rp_route->leaves, oifs); VIFM_CLR_MASK(oifs, rp_route->asserted_oifs); } } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) entry. Merge with the oifs from (*,G) */ if ((grp_route = mrtentry_ptr->group->grp_route) != NULL) { VIFM_MERGE(oifs, grp_route->joined_oifs, oifs); VIFM_CLR_MASK(oifs, grp_route->pruned_oifs); VIFM_MERGE(oifs, grp_route->leaves, oifs); VIFM_CLR_MASK(oifs, grp_route->asserted_oifs); } } /* Calculate my own stuff */ VIFM_MERGE(oifs, mrtentry_ptr->joined_oifs, oifs); VIFM_CLR_MASK(oifs, mrtentry_ptr->pruned_oifs); VIFM_MERGE(oifs, mrtentry_ptr->leaves, oifs); VIFM_CLR_MASK(oifs, mrtentry_ptr->asserted_oifs); VIFM_COPY(oifs, *oifs_ptr); } /* * Set the iif, join/prune/leaves/asserted interfaces. Calculate and * set the oifs. * Return 1 if oifs change from NULL to not-NULL. * Return -1 if oifs change from non-NULL to NULL * else return 0 * If the iif change or if the oifs change from NULL to non-NULL * or vice-versa, then schedule that mrtentry join/prune timer to * timeout immediately. */ int change_interfaces(mrtentry_t *mrtentry_ptr, vifi_t new_iif, vifbitmap_t new_joined_oifs_, vifbitmap_t new_pruned_oifs, vifbitmap_t new_leaves_, vifbitmap_t new_asserted_oifs, u_int16 flags) { vifbitmap_t new_joined_oifs; /* The oifs for that particular mrtentry */ vifbitmap_t old_joined_oifs __attribute__ ((unused)); vifbitmap_t old_pruned_oifs __attribute__ ((unused)); vifbitmap_t old_leaves __attribute__ ((unused)); vifbitmap_t new_leaves; vifbitmap_t old_asserted_oifs __attribute__ ((unused)); vifbitmap_t new_real_oifs; /* The result oifs */ vifbitmap_t old_real_oifs; vifi_t old_iif; rpentry_t *rpentry_ptr; cand_rp_t *cand_rp_ptr; kernel_cache_t *kernel_cache_ptr; rp_grp_entry_t *rp_grp_entry_ptr; grpentry_t *grpentry_ptr; mrtentry_t *mrtentry_srcs; mrtentry_t *mrtentry_wc; mrtentry_t *mrtentry_rp; int delete_mrtentry_flag; int return_value; int fire_timer_flag; if (mrtentry_ptr == NULL) return 0; VIFM_COPY(new_joined_oifs_, new_joined_oifs); VIFM_COPY(new_leaves_, new_leaves); old_iif = mrtentry_ptr->incoming; VIFM_COPY(mrtentry_ptr->joined_oifs, old_joined_oifs); VIFM_COPY(mrtentry_ptr->leaves, old_leaves); VIFM_COPY(mrtentry_ptr->pruned_oifs, old_pruned_oifs); VIFM_COPY(mrtentry_ptr->asserted_oifs, old_asserted_oifs); VIFM_COPY(mrtentry_ptr->oifs, old_real_oifs); mrtentry_ptr->incoming = new_iif; VIFM_COPY(new_joined_oifs, mrtentry_ptr->joined_oifs); VIFM_COPY(new_pruned_oifs, mrtentry_ptr->pruned_oifs); VIFM_COPY(new_leaves, mrtentry_ptr->leaves); VIFM_COPY(new_asserted_oifs, mrtentry_ptr->asserted_oifs); calc_oifs(mrtentry_ptr, &new_real_oifs); if (VIFM_ISEMPTY(old_real_oifs)) { if (VIFM_ISEMPTY(new_real_oifs)) return_value = 0; else return_value = 1; } else { if (VIFM_ISEMPTY(new_real_oifs)) return_value = -1; else return_value = 0; } if ((VIFM_SAME(new_real_oifs, old_real_oifs)) && (new_iif == old_iif) && !(flags & MFC_UPDATE_FORCE)) return 0; /* Nothing to change */ if ((return_value != 0) || (new_iif != old_iif) || (flags & MFC_UPDATE_FORCE)) { FIRE_TIMER(mrtentry_ptr->jp_timer); } VIFM_COPY(new_real_oifs, mrtentry_ptr->oifs); if (mrtentry_ptr->flags & MRTF_PMBR) { /* (*,*,RP) entry */ rpentry_ptr = mrtentry_ptr->source; if (rpentry_ptr == NULL) return 0; /* Shouldn't happen */ rpentry_ptr->incoming = new_iif; cand_rp_ptr = rpentry_ptr->cand_rp; if (VIFM_ISEMPTY(new_real_oifs)) { delete_mrtentry_flag = TRUE; } else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { /* Update the kernel MFC entries */ if (delete_mrtentry_flag == TRUE) { /* XXX: no need to send RSRR message. Will do it when * delete the mrtentry. */ for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) delete_mrtentry_all_kernel_cache(mrtentry_ptr); } else { for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) /* here mrtentry_ptr->source->address is the RP address */ k_chg_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, new_iif, new_real_oifs, mrtentry_ptr->source->address); } } /* * Update all (*,G) entries associated with this RP. * The particular (*,G) outgoing are not changed, but the change * in the (*,*,RP) oifs may have affect the real oifs. */ fire_timer_flag = FALSE; for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next; rp_grp_entry_ptr != NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != NULL; grpentry_ptr = grpentry_ptr->rpnext) { if (grpentry_ptr->grp_route != NULL) { if (change_interfaces(grpentry_ptr->grp_route, new_iif, grpentry_ptr->grp_route->joined_oifs, grpentry_ptr->grp_route->pruned_oifs, grpentry_ptr->grp_route->leaves, grpentry_ptr->grp_route->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { /* Change all (S,G) entries if no (*,G) */ for (mrtentry_srcs = grpentry_ptr->mrtlink; mrtentry_srcs != NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { if (mrtentry_srcs->flags & MRTF_RP) { if (change_interfaces(mrtentry_srcs, new_iif, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } } } } } if (fire_timer_flag == TRUE) FIRE_TIMER(mrtentry_ptr->jp_timer); if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: trigger a Prune message? Don't delete now, it will * be automatically timed out. If want to delete now, don't * reference to it anymore! delete_mrtentry(mrtentry_ptr); */ } return return_value; /* (*,*,RP) */ } if (mrtentry_ptr->flags & MRTF_WC) { /* (*,G) entry */ if (VIFM_ISEMPTY(new_real_oifs)) { delete_mrtentry_flag = TRUE; } else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { if (delete_mrtentry_flag == TRUE) { delete_mrtentry_all_kernel_cache(mrtentry_ptr); } else { for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; kernel_cache_ptr = kernel_cache_ptr->next) k_chg_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, new_iif, new_real_oifs, mrtentry_ptr->group->rpaddr); } } /* Update all (S,G) entries for this group. * For the (S,G)RPbit entries the iif is the iif toward the RP; * The particular (S,G) oifs are not changed, but the change in the * (*,G) oifs may affect the real oifs. */ fire_timer_flag = FALSE; for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs; mrtentry_srcs = mrtentry_srcs->grpnext) { if (mrtentry_srcs->flags & MRTF_RP) { if (change_interfaces(mrtentry_srcs, new_iif, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } } if (fire_timer_flag == TRUE) FIRE_TIMER(mrtentry_ptr->jp_timer); if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: the oifs are NULL. Send a Prune message? */ } return return_value; /* (*,G) */ } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) entry */ #ifdef KERNEL_MFC_WC_G vifbitmap_t tmp_oifs; mrtentry_t *mrtentry_tmp; #endif /* KERNEL_MFC_WC_G */ mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; mrtentry_wc = mrtentry_ptr->group->grp_route; #ifdef KERNEL_MFC_WC_G /* Check whether (*,*,RP) or (*,G) have different (iif,oifs) from * the (S,G). If "yes", then forbid creating (*,G) MFC. */ for (mrtentry_tmp = mrtentry_rp; 1; mrtentry_tmp = mrtentry_wc) { while (1) { if (mrtentry_tmp == NULL) break; if (mrtentry_tmp->flags & MRTF_MFC_CLONE_SG) break; if (mrtentry_tmp->incoming != mrtentry_ptr->incoming) { delete_single_kernel_cache_addr(mrtentry_tmp, INADDR_ANY_N, mrtentry_ptr->group->group); mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG; break; } calc_oifs(mrtentry_tmp, &tmp_oifs); if (!(VIFM_SAME(new_real_oifs, tmp_oifs))) mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG; break; } if (mrtentry_tmp == mrtentry_wc) break; } #endif /* KERNEL_MFC_WC_G */ if (VIFM_ISEMPTY(new_real_oifs)) { delete_mrtentry_flag = TRUE; } else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { if (delete_mrtentry_flag == TRUE) delete_mrtentry_all_kernel_cache(mrtentry_ptr); else k_chg_mfc(igmp_socket, mrtentry_ptr->source->address, mrtentry_ptr->group->group, new_iif, new_real_oifs, mrtentry_ptr->group->rpaddr); } if (old_iif != new_iif) { if (new_iif == mrtentry_ptr->source->incoming) { /* For example, if this was (S,G)RPbit with iif toward the RP, * and now switch to the Shortest Path. * The setup of MRTF_SPT flag must be * done by the external calling function (triggered only * by receiving of a data from the source.) */ mrtentry_ptr->flags &= ~MRTF_RP; /* TODO: XXX: delete? Check again where will be the best * place to set it. mrtentry_ptr->flags |= MRTF_SPT; */ } if (((mrtentry_wc != NULL) && (mrtentry_wc->incoming == new_iif)) || ((mrtentry_rp != NULL) && (mrtentry_rp->incoming == new_iif))) { /* If the new iif points toward the RP, reset the SPT flag. * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first * paragraph. */ /* TODO: XXX: check again! */ mrtentry_ptr->flags &= ~MRTF_SPT; mrtentry_ptr->flags |= MRTF_RP; } } /* TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs, * then delete the (S,G) entry?? The same if we have (*,*,RP) ? */ if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: the oifs are NULL. Send a Prune message ? */ } /* TODO: XXX: have the feeling something is missing.... */ return return_value; /* (S,G) */ } return return_value; } /* TODO: implement it. Required to allow changing of the physical interfaces * configuration without need to restart pimd. */ int delete_vif_from_mrt(vifi_t vifi __attribute__((unused))) { return TRUE; } void process_kernel_call(void) { struct igmpmsg *igmpctl; /* igmpmsg control struct */ igmpctl = (struct igmpmsg *) igmp_recv_buf; switch (igmpctl->im_msgtype) { case IGMPMSG_NOCACHE: process_cache_miss(igmpctl); break; case IGMPMSG_WRONGVIF: process_wrong_iif(igmpctl); break; case IGMPMSG_WHOLEPKT: process_whole_pkt(igmp_recv_buf); break; default: IF_DEBUG(DEBUG_KERN) logit(LOG_DEBUG, 0, "Unknown kernel_call code"); break; } } /* * TODO: when cache miss, check the iif, because probably ASSERTS * shoult take place */ static void process_cache_miss(struct igmpmsg *igmpctl) { u_int32 source, mfc_source; u_int32 group; u_int32 rp_addr; vifi_t iif; mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_rp; /* * When there is a cache miss, we check only the header of the packet * (and only it should be sent up by the kernel. */ group = igmpctl->im_dst.s_addr; source = mfc_source = igmpctl->im_src.s_addr; iif = igmpctl->im_vif; IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d", inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif); } /* TODO: XXX: check whether the kernel generates cache miss for the LAN scoped addresses */ if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP) return; /* Don't create routing entries for the LAN scoped addresses */ /* TODO: check if correct in case the source is one of my addresses */ /* If I am the DR for this source, create (S,G) and add the register_vif * to the oifs. */ if ((uvifs[iif].uv_flags & VIFF_DR) && (find_vif_direct_local(source) == iif)) { mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE); if (mrtentry_ptr == NULL) return; mrtentry_ptr->flags &= ~MRTF_NEW; /* set reg_vif_num as outgoing interface ONLY if I am not the RP */ if (mrtentry_ptr->group->rpaddr != my_cand_rp_address) VIFM_SET(reg_vif_num, mrtentry_ptr->joined_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } else { mrtentry_ptr = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr == NULL) return; } /* TODO: if there are too many cache miss for the same (S,G), install * negative cache entry in the kernel (oif==NULL) to prevent too * many upcalls. */ if (mrtentry_ptr->incoming == iif) { if (!VIFM_ISEMPTY(mrtentry_ptr->oifs)) { if (mrtentry_ptr->flags & MRTF_SG) { /* TODO: check that the RPbit is not set? */ /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->timer < PIM_DATA_TIMEOUT) SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT); if (!(mrtentry_ptr->flags & MRTF_SPT)) { if ((mrtentry_rp = mrtentry_ptr->group->grp_route) == NULL) mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (mrtentry_rp != NULL) { /* Check if the (S,G) iif is different from * the (*,G) or (*,*,RP) iif */ if ((mrtentry_ptr->incoming != mrtentry_rp->incoming) || (mrtentry_ptr->upstream != mrtentry_rp->upstream)) { mrtentry_ptr->flags |= MRTF_SPT; mrtentry_ptr->flags &= ~MRTF_RP; } } } } if (mrtentry_ptr->flags & MRTF_PMBR) rp_addr = mrtentry_ptr->source->address; else rp_addr = mrtentry_ptr->group->rpaddr; mfc_source = source; #ifdef KERNEL_MFC_WC_G if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR)) if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG)) mfc_source = INADDR_ANY_N; #endif /* KERNEL_MFC_WC_G */ add_kernel_cache(mrtentry_ptr, mfc_source, group, MFC_MOVE_FORCE); #ifdef SCOPED_ACL APPLY_SCOPE(group,mrtentry_ptr); #endif k_chg_mfc(igmp_socket, mfc_source, group, iif, mrtentry_ptr->oifs, rp_addr); /* TODO: XXX: No need for RSRR message, because nothing has * changed. */ } return; /* iif match */ } /* The iif doesn't match */ if (mrtentry_ptr->flags & MRTF_SG) { /* Arrived on wrong interface */ if (mrtentry_ptr->flags & MRTF_SPT) return; if ((mrtentry_rp = mrtentry_ptr->group->grp_route) == NULL) mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (mrtentry_rp != NULL) { if (mrtentry_rp->incoming == iif) { /* Forward on (*,G) or (*,*,RP) */ #ifdef KERNEL_MFC_WC_G if (!(mrtentry_rp->flags & MRTF_MFC_CLONE_SG)) mfc_source = INADDR_ANY_N; #endif /* KERNEL_MFC_WC_G */ add_kernel_cache(mrtentry_rp, mfc_source, group, 0); /* marian: not sure if we are going to reach here for our scoped traffic */ #ifdef SCOPED_ACL APPLY_SCOPE(group,mrtentry_ptr); #endif k_chg_mfc(igmp_socket, mfc_source, group, iif, mrtentry_rp->oifs, mrtentry_ptr->group->rpaddr); #ifdef RSRR rsrr_cache_send(mrtentry_rp, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } } } } /* * A multicast packet has been received on wrong iif by the kernel. * Check for a matching entry. If there is (S,G) with reset SPTbit and * the packet was received on the iif toward the source, this completes * the switch to the shortest path and triggers (S,G) prune toward the RP * (unless I am the RP). * Otherwise, if the packet's iif is in the oiflist of the routing entry, * trigger an Assert. */ static void process_wrong_iif(struct igmpmsg *igmpctl) { u_int32 source; u_int32 group; vifi_t iif; mrtentry_t *mrtentry_ptr; group = igmpctl->im_dst.s_addr; source = igmpctl->im_src.s_addr; iif = igmpctl->im_vif; /* Don't create routing entries for the LAN scoped addresses */ if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP) return; /* Ignore if it comes on register vif. register vif is neither SPT iif, * neither is used to send asserts out. */ if (uvifs[iif].uv_flags & VIFF_REGISTER) return; mrtentry_ptr = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr == NULL) return; /* * TODO: check again! */ if (mrtentry_ptr->flags & MRTF_SG) { if (!(mrtentry_ptr->flags & MRTF_SPT)) { if (mrtentry_ptr->source->incoming == iif) { /* Switch to the Shortest Path */ mrtentry_ptr->flags |= MRTF_SPT; mrtentry_ptr->flags &= ~MRTF_RP; add_kernel_cache(mrtentry_ptr, source, group, MFC_MOVE_FORCE); k_chg_mfc(igmp_socket, source, group, iif, mrtentry_ptr->oifs, mrtentry_ptr->group->rpaddr); FIRE_TIMER(mrtentry_ptr->jp_timer); #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ return; } } } /* Trigger an Assert */ if (VIFM_ISSET(iif, mrtentry_ptr->oifs)) send_pim_assert(source, group, iif, mrtentry_ptr); } /* * Receives whole packets from the register vif entries * in the kernel, and calls the send_pim_register procedure to * encapsulate the packets and unicasts them to the RP. */ static void process_whole_pkt(char *buf) { send_pim_register((char *)(buf + sizeof(struct igmpmsg))); } mrtentry_t *switch_shortest_path(u_int32 source, u_int32 group) { mrtentry_t *mrtentry_ptr; /* TODO: XXX: prepare and send immediately the (S,G) join? */ if ((mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE)) != NULL) { if (mrtentry_ptr->flags & MRTF_NEW) { mrtentry_ptr->flags &= ~MRTF_NEW; } else if (mrtentry_ptr->flags & MRTF_RP) { /* (S,G)RPbit with iif toward RP. Reset to (S,G) with iif * toward S. Delete the kernel cache (if any), because * change_interfaces() will reset it with iif toward S * and no data will arrive from RP before the switch * really occurs. */ mrtentry_ptr->flags &= ~MRTF_RP; mrtentry_ptr->incoming = mrtentry_ptr->source->incoming; mrtentry_ptr->upstream = mrtentry_ptr->source->upstream; delete_mrtentry_all_kernel_cache(mrtentry_ptr); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT); FIRE_TIMER(mrtentry_ptr->jp_timer); } return mrtentry_ptr; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/rsrr.c0000644000000000000000000005760311700261371010506 0ustar /* * Copyright (c) 1993, 1998-2001. * The University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* RSRR code written by Daniel Zappala, USC Information Sciences Institute, * April 1995. */ /* May 1995 -- Added support for Route Change Notification */ #ifdef RSRR #include "defs.h" #include #ifdef HAVE_SA_LEN #include /* for offsetof */ #endif /* * Local RSRR variables. */ static int rsrr_socket; /* interface to reservation protocol */ static char *rsrr_recv_buf; /* RSRR receive buffer */ static char *rsrr_send_buf; /* RSRR send buffer */ static struct sockaddr_un client_addr; static socklen_t client_length = sizeof(client_addr); /* * Procedure definitions needed internally. */ static void rsrr_accept (size_t recvlen); static void rsrr_accept_iq (void); static int rsrr_accept_rq (struct rsrr_rq *route_query, u_int8 flags, struct gtable *gt_notify); static void rsrr_read (int, fd_set *); static int rsrr_send (int sendlen); static void rsrr_cache (struct gtable *gt, struct rsrr_rq *route_query); /* Initialize RSRR socket */ void rsrr_init(void) { int servlen; struct sockaddr_un serv_addr; rsrr_recv_buf = (char *)calloc(1, RSRR_MAX_LEN); rsrr_send_buf = (char *)calloc(1, RSRR_MAX_LEN); if (!rsrr_recv_buf || !rsrr_send_buf) logit(LOG_ERR, 0, "Ran out of memory in rsrr_init()"); if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) logit(LOG_ERR, errno, "Cannot create RSRR socket"); unlink(RSRR_SERV_PATH); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof(serv_addr.sun_path)); #ifdef HAVE_SA_LEN servlen = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path); serv_addr.sun_len = servlen; #else servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path); #endif if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0) logit(LOG_ERR, errno, "Cannot bind RSRR socket"); if (register_input_handler(rsrr_socket, rsrr_read) < 0) logit(LOG_ERR, 0, "Could not register RSRR as an input handler"); } /* Read a message from the RSRR socket */ static void rsrr_read(int fd, fd_set *rfd __attribute__ ((unused))) { ssize_t len; memset(&client_addr, 0, sizeof(client_addr)); while ((len = recvfrom(fd, rsrr_recv_buf, sizeof(rsrr_recv_buf), 0, (struct sockaddr *)&client_addr, &client_length)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_ERR, errno, "Failed recvfrom() in rsrr_read()"); return; } rsrr_accept(len); } /* Accept a message from the reservation protocol and take * appropriate action. */ static void rsrr_accept(size_t recvlen) { struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf; struct rsrr_rq *route_query; if (recvlen < RSRR_HEADER_LEN) { logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.", recvlen, RSRR_HEADER_LEN); return; } if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) { logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand", rsrr->version); return; } switch (rsrr->type) { case RSRR_INITIAL_QUERY: /* Send Initial Reply to client */ IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Received Initial Query\n"); } rsrr_accept_iq(); break; case RSRR_ROUTE_QUERY: /* Check size */ if (recvlen < RSRR_RQ_LEN) { logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen); break; } /* Get the query */ route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN); IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Received Route Query for src %s grp %s notification %d", inet_fmt(route_query->source_addr, s1, sizeof(s1)), inet_fmt(route_query->dest_addr, s2, sizeof(s2)), BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); } /* Send Route Reply to client */ rsrr_accept_rq(route_query, rsrr->flags, NULL); break; default: logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type); break; } } /* Send an Initial Reply to the reservation protocol. */ /* * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing * daemon automatically include it, have to inform the RSVP daemon. * However, this is not in the RSRRv1 draft (just expired and is not * available anymore from the internet-draft ftp sites). Probably has to * be included in RSRRv2. */ static void rsrr_accept_iq(void) { struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf; struct rsrr_vif *vif_list; struct uvif *v; vifi_t vifi; int sendlen; /* Check for space. There should be room for plenty of vifs, * but we should check anyway. */ if (numvifs > RSRR_MAX_VIFS) { logit(LOG_WARNING, 0, "Cannot send RSRR Route Reply because %d is too many vifs %d", numvifs); return; } /* Set up message */ rsrr->version = 1; rsrr->type = RSRR_INITIAL_REPLY; rsrr->flags = 0; rsrr->num = numvifs; vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN); /* Include the vif list. */ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { vif_list[vifi].id = vifi; vif_list[vifi].status = 0; if (v->uv_flags & VIFF_DISABLED) BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT); vif_list[vifi].threshold = v->uv_threshold; vif_list[vifi].local_addr = v->uv_lcl_addr; } /* Get the size. */ sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN; /* Send it. */ IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Send RSRR Initial Reply"); } rsrr_send(sendlen); } /* Send a Route Reply to the reservation protocol. The Route Query * contains the query to which we are responding. The flags contain * the incoming flags from the query or, for route change * notification, the flags that should be set for the reply. The * kernel table entry contains the routing info to use for a route * change notification. */ /* XXX: must modify if your routing table structure/search is different */ static int rsrr_accept_rq(struct rsrr_rq *route_query, u_int8 flags, struct gtable *gt_notify) { struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf; struct rsrr_rr *route_reply; int sendlen; struct gtable *gt; int status_ok; #ifdef PIM int found; u_int8 tmp_flags; rp_grp_entry_t *rp_grp_entry; grpentry_t *grpentry_ptr; #else struct gtable local_g; struct rtentry *r; u_int32 mcastgrp; #endif /* PIM */ /* Set up message */ rsrr->version = 1; rsrr->type = RSRR_ROUTE_REPLY; rsrr->flags = flags; rsrr->num = 0; route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN); route_reply->dest_addr = route_query->dest_addr; route_reply->source_addr = route_query->source_addr; route_reply->query_id = route_query->query_id; /* Blank routing entry for error. */ route_reply->in_vif = 0; route_reply->reserved = 0; route_reply->out_vif_bm = 0; /* Get the size. */ sendlen = RSRR_RR_LEN; /* If routing table entry is defined, then we are sending a Route Reply * due to a Route Change Notification event. Use the routing table entry * to supply the routing info. */ status_ok = FALSE; #ifdef PIM if (gt_notify) { /* Include the routing entry. */ route_reply->in_vif = gt_notify->incoming; route_reply->out_vif_bm = gt_notify->oifs; gt = gt_notify; status_ok = TRUE; } else if ((gt = find_route(route_query->source_addr, route_query->dest_addr, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE)) != (struct gtable *)NULL) { status_ok = TRUE; route_reply->in_vif = gt->incoming; route_reply->out_vif_bm = gt->oifs; } if (status_ok != TRUE) { /* Set error bit. */ rsrr->flags = 0; BIT_SET(rsrr->flags, RSRR_ERROR_BIT); } else { if (gt->flags & (MRTF_WC | MRTF_PMBR)) { tmp_flags = 0; BIT_SET(tmp_flags, RSRR_THIS_SENDER_SHARED_TREE); BIT_SET(tmp_flags, RSRR_ALL_SENDERS_SHARED_TREE); if (!(flags & tmp_flags)) { /* Check whether need to setup the (*,G) related flags */ found = FALSE; if (gt->flags & MRTF_PMBR) { /* Check whether there is at least one (S,G) entry which is * a longer match than this (*,*,RP) entry. */ for (rp_grp_entry = gt->source->cand_rp->rp_grp_next; rp_grp_entry != (rp_grp_entry_t *)NULL; rp_grp_entry = rp_grp_entry->rp_grp_next) { for (grpentry_ptr = rp_grp_entry->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { if (grpentry_ptr->mrtlink != (mrtentry_t *)NULL) { found = TRUE; break; } } if (found == TRUE) break; } } else if (gt->flags & MRTF_WC) { if (gt->group->mrtlink != (mrtentry_t *)NULL) found = TRUE; } if (found == TRUE) { RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(rsrr->flags); } else { RSRR_SET_ALL_SENDERS_SHARED_TREE(rsrr->flags); } } } /* Cache reply if using route change notification. */ if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) { /* TODO: XXX: Originally the rsrr_cache() call was first, but * I think this is incorrect, because rsrr_cache() checks the * rsrr_send_buf "flag" first. */ BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT); rsrr_cache(gt, route_query); } } #else /* Not PIM */ if (gt_notify) { /* Set flags */ rsrr->flags = flags; /* Include the routing entry. */ /* The original code from mrouted-3.9b2 */ route_reply->in_vif = gt_notify->gt_route->rt_parent; /* TODO: XXX: bug? See the PIM code above */ if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) route_reply->out_vif_bm = gt_notify->gt_grpmems; else route_reply->out_vif_bm = 0; } else if (find_src_grp(route_query->source_addr, 0, route_query->dest_addr)) { /* Found kernel entry. Code taken from add_table_entry() */ gt = gtp ? gtp->gt_gnext : kernel_table; /* Include the routing entry. */ route_reply->in_vif = gt->gt_route->rt_parent; route_reply->out_vif_bm = gt->gt_grpmems; /* Cache reply if using route change notification. */ if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) { /* TODO: XXX: Originally the rsrr_cache() call was first, but * I think this is incorrect, because rsrr_cache() checks the * rsrr_send_buf "flag" first. */ BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT); rsrr_cache(gt, route_query); } } else { /* No kernel entry; use routing table. */ r = determine_route(route_query->source_addr); if (r != NULL) { /* We need to mimic what will happen if a data packet * is forwarded by multicast routing -- the kernel will * make an upcall and mrouted will install a route in the kernel. * Our outgoing vif bitmap should reflect what that table * will look like. Grab code from add_table_entry(). * This is gross, but it's probably better to be accurate. */ gt = &local_g; mcastgrp = route_query->dest_addr; gt->gt_mcastgrp = mcastgrp; gt->gt_grpmems = 0; gt->gt_scope = 0; gt->gt_route = r; /* obtain the multicast group membership list */ determine_forwvifs(gt); /* Include the routing entry. */ route_reply->in_vif = gt->gt_route->rt_parent; route_reply->out_vif_bm = gt->gt_grpmems; } else { /* Set error bit. */ BIT_SET(rsrr->flags, RSRR_ERROR_BIT); } } #endif /* pimd - mrouted specific code */ IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n", gt_notify ? "Route Change: " : "", inet_fmt(route_reply->source_addr, s1, sizeof(s1)), inet_fmt(route_reply->dest_addr, s2, sizeof(s2)), route_reply->in_vif,route_reply->out_vif_bm); } /* Send it. */ return rsrr_send(sendlen); } /* Send an RSRR message. */ static int rsrr_send(int sendlen) { int error; while ((error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, (struct sockaddr *)&client_addr, client_length)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_WARNING, errno, "Failed sendto() in rsrr_send()"); return error; } if (error != sendlen) logit(LOG_WARNING, 0, "Sent only %d out of %d bytes on RSRR socket", error, sendlen); return error; } /* TODO: need to sort the rsrr_cache entries for faster access */ /* Cache a message being sent to a client. Currently only used for * caching Route Reply messages for route change notification. */ static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query) { struct rsrr_cache *rc, **rcnp; struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf; #ifdef PIM rcnp = >->rsrr_cache; #else rcnp = >->gt_rsrr_cache; #endif /* PIM */ while ((rc = *rcnp) != NULL) { if ((rc->route_query.source_addr == route_query->source_addr) && (rc->route_query.dest_addr == route_query->dest_addr) && (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) { /* Cache entry already exists. * Check if route notification bit has been cleared. */ if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) { /* Delete cache entry. */ *rcnp = rc->next; free(rc); } else { /* Update */ /* TODO: XXX: No need to update iif, oifs, flags */ rc->route_query.query_id = route_query->query_id; IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Update cached query id %ld from client %s\n", rc->route_query.query_id, rc->client_addr.sun_path); } } return; } rcnp = &rc->next; } /* Cache entry doesn't already exist. Create one and insert at * front of list. */ rc = (struct rsrr_cache *)calloc(1, sizeof(struct rsrr_cache)); if (rc == NULL) logit(LOG_ERR, 0, "Ran out of memory in rsrr_cache()"); rc->route_query.source_addr = route_query->source_addr; rc->route_query.dest_addr = route_query->dest_addr; rc->route_query.query_id = route_query->query_id; strlcpy(rc->client_addr.sun_path, client_addr.sun_path, sizeof(rc->client_addr.sun_path)); rc->client_length = client_length; #ifdef PIM rc->next = gt->rsrr_cache; gt->rsrr_cache = rc; #else rc->next = gt->gt_rsrr_cache; gt->gt_rsrr_cache = rc; #endif /* PIM */ IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n", rc->route_query.query_id, rc->client_addr.sun_path); } } /* Send all the messages in the cache for particular routing entry. * Currently this is used to send all the cached Route Reply messages * for route change notification. */ void rsrr_cache_send(struct gtable *gt, int notify) { struct rsrr_cache *rc, **rcnp; u_int8 flags = 0; if (notify) { BIT_SET(flags, RSRR_NOTIFICATION_BIT); } #ifdef PIM rcnp = >->rsrr_cache; #else rcnp = >->gt_rsrr_cache; #endif /* PIM */ while ((rc = *rcnp) != NULL) { if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) { IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", rc->route_query.query_id,rc->client_addr.sun_path); } /* Delete cache entry. */ *rcnp = rc->next; free(rc); } else { rcnp = &rc->next; } } } /* Bring "up" the RSRR cache entries: the (S,G) entry brings up any * matching entry from (*,*,RP) or (*,G). The (*,G) entry brings up * any matching entries from (*,*,RP) */ void rsrr_cache_bring_up(struct gtable *gt) { struct gtable *gt_rp, *gt_wide; u_int8 flags = 0; struct rsrr_cache *rc, **rcnp; if (gt == (struct gtable *)NULL) return; if (gt->flags & MRTF_PMBR) /* (*,*,RP) */ return; if (gt->flags & MRTF_WC) { /* (*,G) */ if (((gt_rp = gt->group->active_rp_grp->rp->rpentry->mrtlink) == (struct gtable *)NULL) || (gt_rp->rsrr_cache == (struct rsrr_cache *)NULL)) return; if ((gt_rp->incoming == gt->incoming) && (VIFM_SAME(gt->oifs, gt_rp->oifs))) { /* The (iif, oifs) are the same. Just link to the new routing * table entry. No need to send message to rsvpd */ rcnp = >_rp->rsrr_cache; while ((rc = *rcnp) != NULL) { if (rc->route_query.dest_addr == gt->group->group) { *rcnp = rc->next; rc->next = gt->rsrr_cache; gt->rsrr_cache = rc; } else { rcnp = &rc->next; } } } else { /* Have to move the entries and at the same time * send an update message to rsvpd for each of them. */ /* TODO: XXX: this can be done faster */ rcnp = >_rp->rsrr_cache; BIT_SET(flags, RSRR_NOTIFICATION_BIT); if (gt->group->mrtlink != (mrtentry_t *)NULL) { RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(flags); } else { RSRR_SET_ALL_SENDERS_SHARED_TREE(flags); } while ((rc = *rcnp) != NULL) { if (rc->route_query.dest_addr == gt->group->group) { *rcnp = rc->next; if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) { IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", rc->route_query.query_id, rc->client_addr.sun_path); } } /* Even on success have to delete it. */ *rcnp = rc->next; free(rc); } } } return; } /* end of (*,G) */ if (gt->flags & MRTF_SG) { /* (S,G) */ /* Check first (*,*,RP) */ if (((gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink) == (struct gtable *)NULL) || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL)) { if (((gt_wide = gt->group->grp_route) == (struct gtable *)NULL) || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL)) return; } BIT_SET(flags, RSRR_NOTIFICATION_BIT); try_again: rcnp = >_wide->rsrr_cache; while((rc = *rcnp) != NULL) { if ((rc->route_query.dest_addr == gt->group->group) && (rc->route_query.source_addr == gt->source->address)) { /* Found it. Need just this entry */ *rcnp = rc->next; /* Free from the original chain */ if ((gt_wide->incoming == gt->incoming) && (VIFM_SAME(gt_wide->oifs, gt->oifs))) { /* The (iif, oifs) are the same. Just link to the * new routing table entry. No need to send * message to rsvpd */ rc->next = gt->rsrr_cache; gt->rsrr_cache = rc; } else { /* The iif and/or oifs are different. Send a message * to rsvpd */ if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) { IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", rc->route_query.query_id, rc->client_addr.sun_path); } } /* Even on success have to delete it. */ free(rc); } return; } } if (gt_wide->flags & MRTF_PMBR) { if (((gt_wide = gt->group->grp_route) == (struct gtable *)NULL) || (gt_wide->rsrr_cache == (struct rsrr_cache *)NULL)) return; goto try_again; } } } /* Clean the cache by deleting or moving all entries. */ /* XXX: for PIM, if the routing entry is (S,G), will try first to * "transfer" the RSRR cache entry to the (*,G) or (*,*,RP) routing entry * (if any). If the current routing entry is (*,G), it will move the * cache entries to the (*,*,RP) routing entry (if existing). * If the old and the new (iif, oifs) are the same, then no need to send * route change message to the reservation daemon: just plug all entries at * the front of the rsrr_cache chain. */ void rsrr_cache_clean(struct gtable *gt) { struct rsrr_cache *rc, *rc_next, **rcnp; struct gtable *gt_wide; #ifdef PIM u_int8 flags = 0; IF_DEBUG(DEBUG_RSRR) { if (gt->flags & MRTF_SG) logit(LOG_DEBUG, 0, "cleaning cache for source %s and group %s", inet_fmt(gt->source->address, s1, sizeof(s1)), inet_fmt(gt->group->group, s2, sizeof(s2))); else if (gt->flags & MRTF_WC) logit(LOG_DEBUG, 0, "cleaning cache for group %s and ANY sources", inet_fmt(gt->group->group, s1, sizeof(s1))); else if (gt->flags & MRTF_PMBR) logit(LOG_DEBUG, 0, "cleaning cache for ALL groups matching to RP %s", inet_fmt(gt->source->address, s1, sizeof(s1))); } rc = gt->rsrr_cache; if (rc == (struct rsrr_cache *)NULL) return; if (gt->flags & MRTF_SG) { if ((gt_wide = gt->group->grp_route) == (struct gtable *)NULL) gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink; } else if (gt->flags & MRTF_WC) gt_wide = gt->group->active_rp_grp->rp->rpentry->mrtlink; else gt_wide = (struct gtable *)NULL; if (gt_wide == (struct gtable *)NULL) { /* No routing entry where to move down the rsrr cache entry. * Send a message with "cannot_notify" bit set. */ rsrr_cache_send(gt, 0); while (rc) { rc_next = rc->next; free(rc); rc = rc_next; } } else if ((gt_wide->incoming == gt->incoming) && (VIFM_SAME(gt->oifs, gt_wide->oifs))) { /* The (iif, oifs) are the same. Just move to the beginning of the * RSRR cache chain. No need to send message */ while (rc->next != (struct rsrr_cache *)NULL) rc = rc->next; rc->next = gt_wide->rsrr_cache; gt_wide->rsrr_cache = gt->rsrr_cache; } else { /* Have to move to the RSRR cache entries and at the same time * send an update for each of them. */ rcnp = >->rsrr_cache; BIT_SET(flags, RSRR_NOTIFICATION_BIT); if (gt->group->mrtlink != (mrtentry_t *)NULL) { RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(flags); } else { RSRR_SET_ALL_SENDERS_SHARED_TREE(flags); } while ((rc = *rcnp) != NULL) { if (rsrr_accept_rq(&rc->route_query, flags, gt_wide) < 0) { IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", rc->route_query.query_id, rc->client_addr.sun_path); } /* Delete cache entry. */ *rcnp = rc->next; free(rc); } else { rcnp = &rc->next; } } } gt->rsrr_cache = (struct rsrr_cache *)NULL; #else IF_DEBUG(DEBUG_RSRR) { logit(LOG_DEBUG, 0, "cleaning cache for group %s\n", inet_fmt(gt->gt_mcastgrp, s1, sizeof(s1))); } rc = gt->gt_rsrr_cache; while (rc) { rc_next = rc->next; free(rc); rc = rc_next; } gt->gt_rsrr_cache = NULL; #endif /* PIM */ } void rsrr_clean(void) { unlink(RSRR_SERV_PATH); } #else /* !RSRR */ static int dummy __attribute__((unused)); #endif /* RSRR */ /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/config.mk0000644000000000000000000001104611700261371011137 0ustar # config.mk -*-Makefile-*- # This is the pimd build configuration file. See the below description for details # on each build option. # -D_GNU_SOURCE : Use GNU extensions, where possible # -D_BSD_SOURCE : Use functions derived from 4.3 BSD Unix rather than POSIX.1 # -DPIM : Enable PIM extensions in RSRR DEFS = -D__BSD_SOURCE -D_GNU_SOURCE -DPIM # EXTRA_OBJS= For locally provided objects missing on some platforms, e.g., strlcpy.o # EXTRA_LIBS= For platform specific libraries, e.g., -lutil # Misc. definitions # -DBROKEN_CISCO_CHECKSUM : # If your RP is buggy cisco PIM-SMv2 implementation that computes # the PIM-Register checksum over the whole pkt instead only over # the header, you need to define this. Otherwise, all your PIM-Register # may be dropped by the cisco-RP. #DEFS += -DBROKEN_CISCO_CHECKSUM # # -DPIM_OLD_KERNEL : older PIM kernels don't prepare the inner encapsulated # pkt, and the daemon had to take care of the details # (prior to pimd-2.1.0-alpha29). Newer kernels will prepare everything, # and then the daemon should not touch anything. Unfortunately, both # kernels are not compatible. If you still have one of those old kernels # around and want to use it, then define PIM_OLD_KERNEL here. #DEFS += -DPIM_OLD_KERNEL # # -DPIM_REG_KERNEL_ENCAP : Register kernel encapsulation. Your kernel must # support registers kernel encapsulation to be able to use it. #DEFS += -DPIM_REG_KERNEL_ENCAP # # -DKERNEL_MFC_WC_G : (*,G) kernel MFC support. Use it ONLY with (*,G) # capable kernel #DEFS += -DKERNEL_MFC_WC_G # # -DSAVE_MEMORY : saves 4 bytes per unconfigured interface # per routing entry. If set, configuring such interface will restart the # daemon and will flush the routing table. #DEFS += -DSAVE_MEMORY # # -DSCOPED_ACL : # Scoped access control list support in pimd.conf, by Marian Stagarescu # If you want to install NUL OIF for the "scoped groups", use the following syntax: # "phyint IFNAME [scoped masklen ]", e.g. # phyint fxp0 scoped "addr" masklen "len" #DEFS += -DSCOPED_ACL # ## # Compilation flags for different platforms. # Uncomment only one of them. Default: Linux # If the multicast header files are not in the standard place on your system, # define MCAST_INCLUDE to be an appropriate `-I' options for the C compiler. #MCAST_INCLUDE= -I/sys ## FreeBSD -D__FreeBSD__ is defined by the OS ## FreeBSD-3.x, FreeBSD-4.x # Seems to already have ip_mroute.h and pim.h, add -Iinclude/freebsd if # ip_mroute.h or in.h is missing on your system and -Iinclude for pim.h #INCLUDES = #DEFS += -DHAVE_STRTONUM -DHAVE_STRLCPY #EXTRA_OBJS = pidfile.o #EXTRA_LIBS = ## FreeBSD-2.x #INCLUDES = -Iinclude -Iinclude/freebsd2 #DEFS += #EXTRA_OBJS = strlcpy.o pidfile.o ## NetBSD -DNetBSD is defined by the OS # Seems to already have ip_mroute.h and pim.h, add -Iinclude/netbsd if # ip_mroute.h or in.h is missing on your system and -Iinclude for pim.h #INCLUDES = #DEFS += -DHAVE_STRTONUM -DHAVE_STRLCPY -DHAVE_PIDFILE #EXTRA_OBJS = #EXTRA_LIBS = -lutil ## OpenBSD -DOpenBSD is defined by the OS # Seems to already have ip_mroute.h and pim.h, add -Iinclude/openbsd if # ip_mroute.h or in.h is missing on your system and -Iinclude for pim.h #INCLUDES = #DEFS += -DHAVE_STRTONUM -DHAVE_STRLCPY -DHAVE_PIDFILE #EXTRA_OBJS = #EXTRA_LIBS = -lutil ## BSDI -D__bsdi__ is defined by the OS #INCLUDES = -Iinclude #DEFS += #EXTRA_OBJS = strlcpy.o pidfile.o ## SunOS, OSF1, gcc #INCLUDES = -Iinclude -Iinclude/sunos-gcc #DEFS += -DSunOS=43 #EXTRA_OBJS = strlcpy.o pidfile.o ## SunOS, OSF1, cc #INCLUDES = -Iinclude -Iinclude/sunos-cc #DEFS += -DSunOS=43 #EXTRA_OBJS = strlcpy.o pidfile.o ## IRIX #INCLUDES = -Iinclude #DEFS += -D_BSD_SIGNALS -DIRIX #EXTRA_OBJS = strlcpy.o pidfile.o ## Solaris 2.5, gcc #INCLUDES = -Iinclude #DEFS += -DSYSV -DSunOS=55 ## Solaris 2.5, cc #INCLUDES = -Iinclude #DEFS += -DSYSV -DSunOS=55 ## Solaris 2.6 #INCLUDES = -Iinclude #DEFS += -DSYSV -DSunOS=56 ## Solaris 2.x #EXTRA_OBJS = strlcpy.o pidfile.o #EXTRA_LIBS = -L/usr/ucblib -lucb -L/usr/lib -lsocket -lnsl ## Linux -D__linux__ is defined by the OS # GNU/Linux systems do not seem to ship pim.h and pim_var.h, # use local include/netinet # For uClibc based Linux systems, add -DHAVE_STRLCPY to DEFS INCLUDES = -Iinclude DEFS += -DRAW_INPUT_IS_RAW -DRAW_OUTPUT_IS_RAW -DIOCTL_OK_ON_RAW_SOCKET EXTRA_OBJS = strlcpy.o pidfile.o pimd-2.1.8/trace.c0000644000000000000000000004400111700261371010600 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: trace.c,v 1.13 2002/09/26 00:59:30 pavlin Exp $ */ /* * 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 "defs.h" #include "trace.h" /* TODO: XXX: implementation incompleted and buggy; check Kame's pim6sd */ /* * Traceroute function which returns traceroute replies to the requesting * router. Also forwards the request to downstream routers. */ void accept_mtrace(src, dst, group, data, no, datalen) u_int32 src; u_int32 dst; u_int32 group; char *data; u_int no; /* promoted u_char */ int datalen; { u_char type; mrtentry_t *mrt; struct tr_query *qry; struct tr_resp *resp; int vifi; char *p; u_int rcount; int errcode = TR_NO_ERR; int resptype; struct timeval tp; struct sioc_vif_req v_req; #if 0 /* TODO */ struct sioc_sg_req sg_req; #endif /* 0 */ u_int32 parent_address = INADDR_ANY; /* Remember qid across invocations */ static u_int32 oqid = 0; /* timestamp the request/response */ gettimeofday(&tp, 0); /* * Check if it is a query or a response */ if (datalen == QLEN) { type = QUERY; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } else if ((datalen - QLEN) % RLEN == 0) { type = RESP; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); if (IN_MULTICAST(ntohl(dst))) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Dropping multicast response"); return; } } else { logit(LOG_WARNING, 0, "%s from %s to %s", "Non decipherable traceroute request recieved", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return; } qry = (struct tr_query *)data; /* * if it is a packet with all reports filled, drop it */ if ((rcount = (datalen - QLEN)/RLEN) == no) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "packet with all reports filled in"); return; } IF_DEBUG(DEBUG_TRACE) { logit(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), inet_fmt(qry->tr_dst, s3, sizeof(s3))); logit(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl, inet_fmt(qry->tr_raddr, s1, sizeof(s1))); logit(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid); } /* determine the routing table entry for this traceroute */ mrt = find_route(qry->tr_src, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); IF_DEBUG(DEBUG_TRACE) { if (mrt != (mrtentry_t *)NULL) { if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; logit(LOG_DEBUG, 0, "mrt parent vif: %d rtr: %s metric: %d", mrt->incoming, inet_fmt(parent_address, s1, sizeof(s1)), mrt->metric); /* TODO logit(LOG_DEBUG, 0, "mrt origin %s", RT_FMT(rt, s1)); */ } else { logit(LOG_DEBUG, 0, "...no route"); } } /* * Query type packet - check if rte exists * Check if the query destination is a vif connected to me. * and if so, whether I should start response back */ if (type == QUERY) { if (oqid == qry->tr_qid) { /* * If the multicast router is a member of the group being * queried, and the query is multicasted, then the router can * recieve multiple copies of the same query. If we have already * replied to this traceroute, just ignore it this time. * * This is not a total solution, but since if this fails you * only get N copies, N <= the number of interfaces on the router, * it is not fatal. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "ignoring duplicate traceroute packet"); return; } if (mrt == (mrtentry_t *)NULL) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s", inet_fmt(qry->tr_src, s1, sizeof(s1))); if (IN_MULTICAST(ntohl(dst))) return; } vifi = find_vif_direct(qry->tr_dst); if (vifi == NO_VIF) { /* The traceroute destination is not on one of my subnet vifs. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not an interface", inet_fmt(qry->tr_dst, s1, sizeof(s1))); if (IN_MULTICAST(ntohl(dst))) return; errcode = TR_WRONG_IF; } else if (mrt != (mrtentry_t *)NULL && !VIFM_ISSET(vifi, mrt->oifs)) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2))); if (IN_MULTICAST(ntohl(dst))) return; errcode = TR_WRONG_IF; } } else { /* * determine which interface the packet came in on * RESP packets travel hop-by-hop so this either traversed * a tunnel or came from a directly attached mrouter. */ if ((vifi = find_vif_direct(src)) == NO_VIF) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Wrong interface for packet"); errcode = TR_WRONG_IF; } } /* Now that we've decided to send a response, save the qid */ oqid = qry->tr_qid; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending traceroute response"); /* copy the packet to the sending buffer */ p = igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; bcopy(data, p, datalen); p += datalen; /* * If there is no room to insert our reply, coopt the previous hop * error indication to relay this fact. */ if (p + sizeof(struct tr_resp) > igmp_send_buf + SEND_BUF_SIZE) { resp = (struct tr_resp *)p - 1; resp->tr_rflags = TR_NO_SPACE; mrt = NULL; goto sendit; } /* * fill in initial response fields */ resp = (struct tr_resp *)p; memset(resp, 0, sizeof(struct tr_resp)); datalen += RLEN; resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) + ((tp.tv_usec << 10) / 15625)); resp->tr_rproto = PROTO_PIM; resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr; resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold; resp->tr_rflags = errcode; /* * obtain # of packets out on interface */ v_req.vifi = vifi; if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) resp->tr_vifout = htonl(v_req.ocount); else resp->tr_vifout = 0xffffffff; /* * fill in scoping & pruning information */ /* TODO */ #if 0 if (mrt != (mrtentry_t *)NULL) for (gt = rt->rt_groups; gt; gt = gt->gt_next) { if (gt->gt_mcastgrp >= group) break; } else gt = NULL; if (gt && gt->gt_mcastgrp == group) { struct stable *st; for (st = gt->gt_srctbl; st; st = st->st_next) if (qry->tr_src == st->st_origin) break; sg_req.src.s_addr = qry->tr_src; sg_req.grp.s_addr = group; if (st && st->st_ctime != 0 && ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0) resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt); else resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff); if (VIFM_ISSET(vifi, gt->gt_scope)) resp->tr_rflags = TR_SCOPED; else if (gt->gt_prsent_timer) resp->tr_rflags = TR_PRUNED; else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) if (VIFM_ISSET(vifi, rt->rt_children) && NBRM_ISSETMASK(uvifs[vifi].uv_nbrmap, rt->rt_subordinates)) /*XXX*/ resp->tr_rflags = TR_OPRUNED; else resp->tr_rflags = TR_NO_FWD; } else { if (scoped_addr(vifi, group)) resp->tr_rflags = TR_SCOPED; else if (rt && !VIFM_ISSET(vifi, rt->rt_children)) resp->tr_rflags = TR_NO_FWD; } #endif /* 0 */ /* * if no rte exists, set NO_RTE error */ if (mrt == (mrtentry_t *)NULL) { src = dst; /* the dst address of resp. pkt */ resp->tr_inaddr = 0; resp->tr_rflags = TR_NO_RTE; resp->tr_rmtaddr = 0; } else { /* get # of packets in on interface */ v_req.vifi = mrt->incoming; if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) resp->tr_vifin = htonl(v_req.icount); else resp->tr_vifin = 0xffffffff; /* TODO MASK_TO_VAL(rt->rt_originmask, resp->tr_smask); */ src = uvifs[mrt->incoming].uv_lcl_addr; resp->tr_inaddr = src; if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; resp->tr_rmtaddr = parent_address; if (!VIFM_ISSET(vifi, mrt->oifs)) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2))); resp->tr_rflags = TR_WRONG_IF; } #if 0 if (rt->rt_metric >= UNREACHABLE) { resp->tr_rflags = TR_NO_RTE; /* Hack to send reply directly */ rt = NULL; } #endif /* 0 */ } sendit: /* * if metric is 1 or no. of reports is 1, send response to requestor * else send to upstream router. If the upstream router can't handle * mtrace, set an error code and send to requestor anyway. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no); if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) { resptype = IGMP_MTRACE_RESP; dst = qry->tr_raddr; } else #if 0 /* TODO */ if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) { dst = qry->tr_raddr; resp->tr_rflags = TR_OLD_ROUTER; resptype = IGMP_MTRACE_RESP; } else { #endif /* 0 */ if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; dst = parent_address; resptype = IGMP_MTRACE; #if 0 /* TODO */ } #endif if (IN_MULTICAST(ntohl(dst))) { /* * Send the reply on a known multicast capable vif. * If we don't have one, we can't source any multicasts anyway. */ if (phys_vif != -1) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending reply to %s from %s", inet_fmt(dst, s1, sizeof(s1)), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2, sizeof(s2))); k_set_ttl(igmp_socket, qry->tr_rttl); send_igmp(igmp_send_buf, uvifs[phys_vif].uv_lcl_addr, dst, resptype, no, group, datalen); k_set_ttl(igmp_socket, 1); } else logit(LOG_INFO, 0, "No enabled phyints -- %s", "dropping traceroute reply"); } else { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending %s to %s from %s", resptype == IGMP_MTRACE_RESP ? "reply" : "request on", inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2))); send_igmp(igmp_send_buf, src, dst, resptype, no, group, datalen); } } /* * accept_neighbor_request() supports some old DVMRP messages from mrinfo. * Haven't tested it, because I have only the new mrinfo. */ void accept_neighbor_request(u_int32 src, u_int32 dst __attribute__((unused))) { vifi_t vifi; struct uvif *v; u_char *p, *ncount; /* struct listaddr *la; */ pim_nbr_entry_t *pim_nbr; int datalen; u_int32 temp_addr, them = src; #define PUT_ADDR(a) temp_addr = ntohl(a); \ *p++ = temp_addr >> 24; \ *p++ = (temp_addr >> 16) & 0xFF; \ *p++ = (temp_addr >> 8) & 0xFF; \ *p++ = temp_addr & 0xFF; p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { if (v->uv_flags & VIFF_DISABLED) continue; ncount = 0; /* TODO: XXX: if we are PMBR, then check the DVMRP interfaces too */ for (pim_nbr = v->uv_pim_neighbors; pim_nbr != (pim_nbr_entry_t *)NULL; pim_nbr = pim_nbr->next) { /* Make sure that there's room for this neighbor... */ if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(PIMD_LEVEL), datalen); p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; ncount = 0; } /* Put out the header for this neighbor list... */ if (ncount == 0) { PUT_ADDR(v->uv_lcl_addr); *p++ = v->uv_metric; *p++ = v->uv_threshold; ncount = p; *p++ = 0; datalen += 4 + 3; } PUT_ADDR(pim_nbr->address); datalen += 4; (*ncount)++; } } if (datalen != 0) send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(PIMD_LEVEL), datalen); } /* * Send a list of all of our neighbors to the requestor, `src'. * Used for mrinfo support. * XXX: currently, we cannot specify the used multicast routing protocol; * only a protocol version is returned. */ void accept_neighbor_request2(u_int32 src, u_int32 dst __attribute__((unused))) { vifi_t vifi; struct uvif *v; u_char *p, *ncount; /* struct listaddr *la; */ pim_nbr_entry_t *pim_nbr; int datalen; u_int32 them = src; p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { register u_int32 vflags = v->uv_flags; register u_char rflags = 0; if (vflags & VIFF_TUNNEL) rflags |= DVMRP_NF_TUNNEL; if (vflags & VIFF_SRCRT) rflags |= DVMRP_NF_SRCRT; if (vflags & VIFF_PIM_NBR) rflags |= DVMRP_NF_PIM; if (vflags & VIFF_DOWN) rflags |= DVMRP_NF_DOWN; if (vflags & VIFF_DISABLED) rflags |= DVMRP_NF_DISABLED; if (vflags & VIFF_QUERIER) rflags |= DVMRP_NF_QUERIER; if (vflags & VIFF_LEAF) rflags |= DVMRP_NF_LEAF; ncount = 0; pim_nbr = v->uv_pim_neighbors; if (pim_nbr == (pim_nbr_entry_t *)NULL) { /* * include down & disabled interfaces and interfaces on * leaf nets. */ if (rflags & DVMRP_NF_TUNNEL) rflags |= DVMRP_NF_DOWN; if (datalen > MAX_DVMRP_DATA_LEN - 12) { send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen); p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; } *(u_int*)p = v->uv_lcl_addr; p += 4; *p++ = v->uv_metric; *p++ = v->uv_threshold; *p++ = rflags; *p++ = 1; *(u_int*)p = v->uv_rmt_addr; p += 4; datalen += 12; } else { for ( ; pim_nbr; pim_nbr = pim_nbr->next) { /* Make sure that there's room for this neighbor... */ if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen); p = (u_char *) (igmp_send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); datalen = 0; ncount = 0; } /* Put out the header for this neighbor list... */ if (ncount == 0) { *(u_int*)p = v->uv_lcl_addr; p += 4; *p++ = v->uv_metric; *p++ = v->uv_threshold; *p++ = rflags; ncount = p; *p++ = 0; datalen += 4 + 4; } *(u_int*)p = pim_nbr->address; p += 4; datalen += 4; (*ncount)++; } } } if (datalen != 0) send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen); } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/dvmrp.h0000644000000000000000000001625211700261371010646 0ustar /* * The mrouted program is covered by the license in the accompanying file * named "LICENSE.mrouted". Use of the mrouted program represents acceptance of * the terms and conditions listed in that file. * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. * * * dvmrp.h,v 3.8.4.3 1997/03/14 00:28:47 fenner Exp */ /* * A DVMRP message consists of an IP header + an IGMP header + (for some types) * zero or more bytes of data. * * For REPORT messages, the data is route information; the route information * consists of one or more lists of the following form: * * (mask, (origin, metric), (origin, metric), ...) * * where: * * "mask" is the subnet mask for all the origins in the list. * It is always THREE bytes long, containing the low-order * three bytes of the mask (the high-order byte is always * 0xff and therefore need not be transmitted). * * "origin" is the number of a subnet from which multicast datagrams * may originate. It is from one to four bytes long, * depending on the value of "mask": * if all bytes of the mask are zero * the subnet number is one byte long * else if the low-order two bytes of the mask are zero * the subnet number is two bytes long * else if the lowest-order byte of the mask is zero * the subnet number is three bytes long, * else * the subnet number is four bytes long. * * "metric" is a one-byte value consisting of two subfields: * - the high-order bit is a flag which, when set, indicates * the last (origin, metric) pair of a list. * - the low-order seven bits contain the routing metric for * the corresponding origin, relative to the sender of the * DVMRP report. The metric may have the value of UNREACHABLE * added to it as a "split horizon" indication (so called * "poisoned reverse"). * * Within a list, the origin subnet numbers must be in ascending order, and * the lists themselves are in order of increasing mask value. A message may * not exceed 576 bytes, the default maximum IP reassembly size, including * the IP and IGMP headers; the route information may be split across more * than one message if necessary, by terminating a list in one message and * starting a new list in the next message (repeating the same mask value, * if necessary). * * For NEIGHBORS messages, the data is neighboring-router information * consisting of one or more lists of the following form: * * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...) * * where: * * "local-addr" is the sending router's address as seen by the neighbors * in this list; it is always four bytes long. * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding * packets to any of the neighbors on this list. * "threshold" is a one-byte unsigned value, a lower bound on the TTL a * packet must have to be forwarded to any of the neighbors on * this list. * "ncount" is the number of neighbors in this list. * "neighbor" is the address of a neighboring router, four bytes long. * * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes, * including the IP and IGMP headers; split longer messages by terminating the * list in one and continuing in another, repeating the local-addr, etc., if * necessary. * * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except * there is a flags byte before the neighbor count: * * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...) */ /* * DVMRP message types (carried in the "code" field of an IGMP header) */ #define DVMRP_PROBE 1 /* for finding neighbors */ #define DVMRP_REPORT 2 /* for reporting some or all routes */ #define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ /* of this router's neighbors. */ #define DVMRP_NEIGHBORS 4 /* response to such a request */ #define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ #define DVMRP_NEIGHBORS2 6 #define DVMRP_PRUNE 7 /* prune message */ #define DVMRP_GRAFT 8 /* graft message */ #define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */ #define DVMRP_INFO_REQUEST 10 /* information request */ #define DVMRP_INFO_REPLY 11 /* information reply */ /* * 'flags' byte values in DVMRP_NEIGHBORS2 reply. */ #define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ #define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ #define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */ #define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ #define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ #define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ #define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */ /* * Request/reply types for info queries/replies */ #define DVMRP_INFO_VERSION 1 /* version string */ #define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */ /* * Limit on length of route data */ /* TODO: now in defs.h #define MAX_IP_PACKET_LEN 576 #define MIN_IP_HEADER_LEN 20 #define MAX_IP_HEADER_LEN 60 */ #define MAX_DVMRP_DATA_LEN \ ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN ) /* * Various protocol constants (all times in seconds) */ /* address for multicast DVMRP msgs */ #define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */ #define DVMRP_ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */ /* (This is the timer interrupt */ /* interval; all times must be */ /* multiples of this value.) */ #define DVMRP_ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */ #define DVMRP_ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */ #define DVMRP_ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */ #define DVMRP_ROUTE_DISCARD_TIME 340 /* time to garbage collect route */ #define DVMRP_LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */ #define DVMRP_NEIGHBOR_PROBE_INTERVAL 10 /* periodic neighbor probe interval */ #define DVMRP_NEIGHBOR_EXPIRE_TIME 30 /* time to consider neighbor gone */ #define DVMRP_OLD_NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */ #define DVMRP_UNREACHABLE 32 /* "infinity" metric, must be <= 64 */ /* TODO: remove the DVMRP prefix and merge it with the PIM code? */ #define DVMRP_MAX_RATE_LIMIT 100000 /* max rate limit */ #define DVMRP_DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */ #define DVMRP_DEFAULT_TUN_RATE_LIMIT 500 /* default tunnel rate limit */ #define DVMRP_DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */ #define DVMRP_MIN_CACHE_LIFETIME 60 /* minimum allowed cache lifetime */ #define DVMRP_AVERAGE_PRUNE_LIFETIME 7200 /* average lifetime of prunes sent */ #define DVMRP_MIN_PRUNE_LIFETIME 120 /* minimum allowed prune lifetime */ #define DVMRP_GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */ #define DVMRP_PRUNE_REXMIT_VAL 3 /* initial time for prune rexmission*/ #define DVMRP_OLD_AGE_THRESHOLD 2 /* # of query intervals to remember */ /* presence of IGMPv1 member */ /* XXX NOTE that this technically */ /* violates IGMPv2 draft as the */ /* timer is 5 seconds too short */ pimd-2.1.8/config.c0000644000000000000000000012757211700261371010766 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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 "defs.h" #define LINE_BUFSIZ 1024 /* Max. line length of the config file */ /* * Forward declarations. */ static char *next_word (char **); static int parse_phyint (char *s); static u_int32 ifname2addr (char *s); extern struct rp_hold *g_rp_hold; /* * Query the kernel to find network interfaces that are multicast-capable * and install them in the uvifs array. */ void config_vifs_from_kernel(void) { struct ifreq *ifrp, *ifend; struct uvif *v; vifi_t vifi; u_int32 n; u_int32 addr, mask, subnet; short flags; int num_ifreq = 64; struct ifconf ifc; char *newbuf; 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) { if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) logit(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) logit(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; #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 /* HAVE_SA_LEN */ /* * Ignore any interface for an address family other than IP. */ if (ifrp->ifr_addr.sa_family != AF_INET) { total_interfaces++; /* Eventually may have IP address later */ continue; } addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr; /* * 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)); /* * Ignore loopback interfaces and interfaces that do not * support multicast. */ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) logit(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); flags = ifr.ifr_flags; if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST) continue; /* * Everyone below is a potential vif interface. * We don't care if it has wrong configuration or not configured * at all. */ total_interfaces++; /* * Ignore any interface whose address and mask do not define a * valid subnet number, or whose address is of the form * {subnet,0} or {subnet,-1}. */ if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0) { if (!(flags & IFF_POINTOPOINT)) { logit(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name); } mask = 0xffffffff; } else { mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; } subnet = addr & mask; if ((!inet_valid_subnet(subnet, mask)) || (addr == subnet) || addr == (subnet | ~mask)) { if (!(inet_valid_host(addr) && (flags & IFF_POINTOPOINT))) { logit(LOG_WARNING, 0, "ignoring %s, has invalid address (%s) and/or mask (%s)", ifr.ifr_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(mask, s2, sizeof(s2))); continue; } } /* * Ignore any interface that is connected to the same subnet as * one already installed in the uvifs array. */ /* * TODO: XXX: bug or "feature" is to allow only one interface per * subnet? */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (strcmp(v->uv_name, ifr.ifr_name) == 0) { logit(LOG_DEBUG, 0, "Skipping %s (%s on subnet %s) (alias for vif#%u?)", v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask), vifi); break; } /* we don't care about point-to-point links in same subnet */ if (flags & IFF_POINTOPOINT) continue; if (v->uv_flags & VIFF_POINT_TO_POINT) continue; #if 0 /* * TODO: to allow different interfaces belong to * overlapping subnet addresses, use this version instead */ if (((addr & mask ) == v->uv_subnet) && (v->uv_subnetmask == mask)) { logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name); break; } #else if ((addr & v->uv_subnetmask) == v->uv_subnet || (v->uv_subnet & mask) == subnet) { logit(LOG_WARNING, 0, "Ignoring %s, same subnet as %s", ifr.ifr_name, v->uv_name); break; } #endif /* 0 */ } if (vifi != numvifs) continue; /* * If there is room in the uvifs array, install this interface. */ if (numvifs == MAXVIFS) { logit(LOG_WARNING, 0, "Too many vifs, ignoring %s", ifr.ifr_name); continue; } v = &uvifs[numvifs]; zero_vif(v, FALSE); v->uv_lcl_addr = addr; v->uv_subnet = subnet; v->uv_subnetmask = mask; v->uv_subnetbcast = subnet | ~mask; strlcpy(v->uv_name, ifr.ifr_name, IFNAMSIZ); if (flags & IFF_POINTOPOINT) { v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT); if (ioctl(udp_socket, SIOCGIFDSTADDR, (char *)&ifr) < 0) { logit(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", v->uv_name); } else { v->uv_rmt_addr = ((struct sockaddr_in *)(&ifr.ifr_dstaddr))->sin_addr.s_addr; } } #ifdef __linux__ { struct ifreq ifridx; memset(&ifridx, 0, sizeof(ifridx)); strlcpy(ifridx.ifr_name,v->uv_name, IFNAMSIZ); if (ioctl(udp_socket, SIOGIFINDEX, (char *) &ifridx) < 0) { logit(LOG_ERR, errno, "ioctl SIOGIFINDEX for %s", ifridx.ifr_name); /* Not reached */ return; } v->uv_ifindex = ifridx.ifr_ifindex; } if (flags & IFF_POINTOPOINT) { logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u-%d - rate=%d", v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)), numvifs, v->uv_ifindex, v->uv_rate_limit); } else { logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u-%d - rate=%d", v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask), numvifs, v->uv_ifindex, v->uv_rate_limit); } #else /* !__linux__ */ if (flags & IFF_POINTOPOINT) { logit(LOG_INFO, 0, "Installing %s (%s -> %s) as vif #%u - rate=%d", v->uv_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)), numvifs, v->uv_rate_limit); } else { logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as vif #%u - rate=%d", v->uv_name, inet_fmt(addr, s1, sizeof(s1)), netname(subnet, mask), numvifs, v->uv_rate_limit); } #endif /* __linux__ */ ++numvifs; /* * If the interface is not yet up, set the vifs_down flag to * remind us to check again later. */ if (!(flags & IFF_UP)) { v->uv_flags |= VIFF_DOWN; vifs_down = TRUE; } } } #define CONF_UNKNOWN -1 #define CONF_EMPTY 1 #define CONF_PHYINT 2 #define CONF_CANDIDATE_RP 3 #define CONF_RP_ADDRESS 64 #define CONF_GROUP_PREFIX 4 #define CONF_BOOTSTRAP_RP 5 #define CONF_REG_THRESHOLD 6 #define CONF_DATA_THRESHOLD 7 #define CONF_DEFAULT_SOURCE_METRIC 8 #define CONF_DEFAULT_SOURCE_PREFERENCE 9 #define CONF_ALTNET 10 #define CONF_MASKLEN 11 #define CONF_SCOPED 12 /* * 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() */ static int wordToOption(char *word) { if (EQUAL(word, "")) return CONF_EMPTY; if (EQUAL(word, "phyint")) return CONF_PHYINT; if (EQUAL(word, "cand_rp")) return CONF_CANDIDATE_RP; if (EQUAL(word, "rp_address")) return CONF_RP_ADDRESS; if (EQUAL(word, "group_prefix")) return CONF_GROUP_PREFIX; if (EQUAL(word, "cand_bootstrap_router")) return CONF_BOOTSTRAP_RP; if (EQUAL(word, "switch_register_threshold")) return CONF_REG_THRESHOLD; if (EQUAL(word, "switch_data_threshold")) return CONF_DATA_THRESHOLD; if (EQUAL(word, "default_source_metric")) return CONF_DEFAULT_SOURCE_METRIC; if (EQUAL(word, "default_source_preference")) return CONF_DEFAULT_SOURCE_PREFERENCE; if (EQUAL(word, "altnet")) return CONF_ALTNET; if (EQUAL(word, "masklen")) return CONF_MASKLEN; if (EQUAL(word, "scoped")) return CONF_SCOPED; return CONF_UNKNOWN; } /** * parse_phyint - parses the physical interface file configurations, if any. * @s: pointing to the parsing point of the file * * Syntax: * phyint [disable|enable] * [threshold ] [preference

] [metric ] * [altnet masklen ] * [scoped masklen ] * * Returns: * %TRUE if the parsing was successful, o.w. %FALSE */ static int parse_phyint(char *s) { char *w, c; u_int32 local, altnet_addr, scoped_addr; vifi_t vifi; struct uvif *v; u_int n, altnet_masklen, scoped_masklen; struct phaddr *ph; struct vif_acl *v_acl; if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing phyint address in %s", configfilename); return(FALSE); } /* if empty */ local = ifname2addr(w); if (!local) { local = inet_parse(w, 4); if (!inet_valid_host(local)) { logit(LOG_WARNING, 0, "Invalid phyint address '%s' in %s", w, configfilename); return(FALSE); } /* invalid address */ } for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (vifi == numvifs) { logit(LOG_WARNING, 0, "phyint %s in %s is not a configured interface", inet_fmt(local, s1, sizeof(s1)), configfilename); return(FALSE); } /* if vifi == numvifs */ if (local != v->uv_lcl_addr) continue; while (!EQUAL((w = next_word(&s)), "")) { if (EQUAL(w, "disable")) { v->uv_flags |= VIFF_DISABLED; continue; } if (EQUAL(w, "enable")) { v->uv_flags &= ~VIFF_DISABLED; continue; } if (EQUAL(w, "altnet")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing ALTNET for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } altnet_addr = ifname2addr(w); if (!altnet_addr) { altnet_addr = inet_parse(w, 4); if (!inet_valid_host(altnet_addr)) { logit(LOG_WARNING, 0, "Invalid altnet address '%s' in %s", w, configfilename); return(FALSE); } /* invalid address */ } if (EQUAL((w = next_word(&s)), "masklen")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing ALTNET masklen for phyint %s in %s", inet_fmt(local, s1, sizeof (s1)), configfilename); continue; } if (sscanf(w, "%u", &altnet_masklen) != 1) { logit(LOG_WARNING, 0, "Invalid altnet masklen '%s' for phyint %s in %s", w, inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } } ph = (struct phaddr *)calloc(1, sizeof(struct phaddr)); if (ph == NULL) return(FALSE); if (altnet_masklen) { VAL_TO_MASK(ph->pa_subnetmask, altnet_masklen); } else { ph->pa_subnetmask = v->uv_subnetmask; } ph->pa_subnet = altnet_addr & ph->pa_subnetmask; ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask; if (altnet_addr & ~ph->pa_subnetmask) logit(LOG_WARNING,0, "Extra subnet %s/%d has host bits set", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen); ph->pa_next = v->uv_addrs; v->uv_addrs = ph; logit(LOG_DEBUG, 0, "ALTNET: %s/%d", inet_fmt(altnet_addr, s1, sizeof(s1)), altnet_masklen); } /* altnet */ /* scoped mcast groups/masklen */ if (EQUAL(w, "scoped")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing SCOPED for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } scoped_addr = ifname2addr(w); if (!scoped_addr) { scoped_addr = inet_parse(w, 4); if (!IN_MULTICAST(ntohl(scoped_addr))) { logit(LOG_WARNING, 0, "Invalid scoped address '%s' in %s", w, configfilename); return(FALSE); } /* invalid address */ } if (EQUAL((w = next_word(&s)), "masklen")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing SCOPED masklen for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } if (sscanf(w, "%u", &scoped_masklen) != 1) { logit(LOG_WARNING, 0, "Invalid scoped masklen '%s' for phyint %s in %s", w, inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } } v_acl = (struct vif_acl *)calloc(1, sizeof(struct vif_acl)); if (v_acl == NULL) return(FALSE); VAL_TO_MASK(v_acl->acl_mask, scoped_masklen); v_acl->acl_addr = scoped_addr & v_acl->acl_mask; if (scoped_addr & ~v_acl->acl_mask) logit(LOG_WARNING, 0, "Boundary spec %s/%d has host bits set", inet_fmt(scoped_addr, s1, sizeof(s1)),scoped_masklen); v_acl->acl_next = v->uv_acl; v->uv_acl = v_acl; logit(LOG_DEBUG, 0, "SCOPED %s/%x", inet_fmt(v_acl->acl_addr, s1, sizeof(s1)), v_acl->acl_mask); } /* scoped */ if (EQUAL(w, "threshold")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing threshold for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) { logit(LOG_WARNING, 0, "Invalid threshold '%s' for phyint %s in %s", w, inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } v->uv_threshold = n; continue; } /* threshold */ if (EQUAL(w, "preference")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing preference for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 255 ) { logit(LOG_WARNING, 0, "Invalid preference '%s' for phyint %s in %s", w, inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } IF_DEBUG(DEBUG_ASSERT) logit(LOG_DEBUG, 0, "Config setting default local preference on %s to %d.", inet_fmt(local, s1, sizeof(s1)), n); v->uv_local_pref = n; continue; } if (EQUAL(w, "metric")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing metric for phyint %s in %s", inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } if (sscanf(w, "%u%c", &n, &c) != 1 || n < 1 || n > 1024 ) { logit(LOG_WARNING, 0, "Invalid metric '%s' for phyint %s in %s", w, inet_fmt(local, s1, sizeof(s1)), configfilename); continue; } IF_DEBUG(DEBUG_ASSERT) { logit(LOG_DEBUG, 0, "Config setting default local metric on %s to %d.", inet_fmt(local, s1, sizeof(s1)), n); } v->uv_local_metric = n; continue; } } /* if not empty */ 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 [priority ] [time ]'. */ int parse_candidateRP(char *s) { u_int time = PIM_DEFAULT_CAND_RP_ADV_PERIOD; u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY; char *w; u_int32 local = INADDR_ANY_N; 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")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing priority; set to default %u (0 is highest)", PIM_DEFAULT_CAND_RP_PRIORITY); priority = PIM_DEFAULT_CAND_RP_PRIORITY; continue; } if (sscanf(w, "%u", &priority) != 1) { logit(LOG_WARNING, 0, "Invalid priority %s; set to default %u (0 is highest)", PIM_DEFAULT_CAND_RP_PRIORITY); priority = PIM_DEFAULT_CAND_RP_PRIORITY; } continue; } if (EQUAL(w, "time")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing cand_rp_adv_period value; set to default %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD); time = PIM_DEFAULT_CAND_RP_ADV_PERIOD; continue; } if (sscanf(w, "%u", &time) != 1) { logit(LOG_WARNING, 0, "Invalid cand_rp_adv_period value; set to default %u", PIM_DEFAULT_CAND_RP_ADV_PERIOD); time = PIM_DEFAULT_CAND_RP_ADV_PERIOD; continue; } if (time > (my_cand_rp_adv_period = ~0)) time = my_cand_rp_adv_period; /* TODO: XXX: cannot be shorter than 10 seconds (not in the spec)*/ if (time < 10) time = 10; #if 0 if (time > PIM_DEFAULT_CAND_RP_ADV_PERIOD) time = PIM_DEFAULT_CAND_RP_ADV_PERIOD; #endif /* 0 */ my_cand_rp_adv_period = time; continue; } /* Cand-RP address */ local = inet_parse(w, 4); if (!inet_valid_host(local)) { local = max_local_address(); logit(LOG_WARNING, 0, "Invalid Cand-RP address provided '%s' in %s. Will use the largest enabled local address.", w, configfilename); } else if (local_address(local) == NO_VIF) { local = max_local_address(); logit(LOG_WARNING, 0, "Cand-RP address is not local '%s' in %s. Will use the largest enabled local address.", w, configfilename); } } /* while not empty */ if (local == INADDR_ANY_N) { /* If address not provided, use the max. local */ local = max_local_address(); } my_cand_rp_address = local; my_cand_rp_priority = priority; my_cand_rp_adv_period = time; cand_rp_flag = TRUE; logit(LOG_INFO, 0, "Local Cand-RP address is %s", inet_fmt(local, s1, sizeof(s1))); logit(LOG_INFO, 0, "Local Cand-RP priority is %u", priority); logit(LOG_INFO, 0, "Local Cand-RP advertisement period is %u sec.", time); return TRUE; } /* * function name: parse_group_prefix * input: char *s * output: int * operation: parse group_prefix configured information. * General form: 'group_prefix [masklen ]'. */ int parse_group_prefix(char *s) { char *w; u_int32 group_addr; u_int32 masklen; w = next_word(&s); if (EQUAL(w, "")) { logit(LOG_WARNING, 0, "Configuration error for 'group_prefix' in %s: no group_addr. Ignoring...", configfilename); return FALSE; } group_addr = inet_parse(w, 4); if (!IN_MULTICAST(ntohl(group_addr))) { logit(LOG_WARNING, 0, "Config error for 'group_prefix' in %s: %s is not a mcast addr. Ignoring...", configfilename, inet_fmt(group_addr, s1, sizeof(s1))); return FALSE; } /* Was if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) which Arm GCC 4.4.2 dislikes: * --> "config.c:693: warning: promoted ~unsigned is always non-zero" * The prefix_cnt_ptr is a u_int8 so it seems this check was to prevent overruns. * I've changed the check to see if we've already read 255 entries, if so the cnt * is maximized and we need to tell the user. --Joachim Nilsson 2010-01-16 */ if (*cand_rp_adv_message.prefix_cnt_ptr == 255) { logit(LOG_WARNING, 0, "Too many group_prefix configured. Truncating..."); return FALSE; } if (EQUAL((w = next_word(&s)), "masklen")) { w = next_word(&s); if (sscanf(w, "%u", &masklen) == 1) { if (masklen > (sizeof(group_addr)*8)) masklen = (sizeof(group_addr)*8); else if (masklen < 4) masklen = 4; } else masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN; } else masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN; PUT_EGADDR(group_addr, (u_int8)masklen, 0, cand_rp_adv_message.insert_data_ptr); (*cand_rp_adv_message.prefix_cnt_ptr)++; logit(LOG_INFO, 0, "Adding prefix %s/%d", inet_fmt(group_addr, s1, sizeof(s1)), masklen); return TRUE; } /* * function name: parseBSR * input: char *s * output: int * operation: parse the candidate BSR configured information. * General form: * 'cand_bootstrap_router [priority ]'. */ int parseBSR(char *s) { char *w; u_int32 local = INADDR_ANY_N; u_int32 priority = PIM_DEFAULT_BSR_PRIORITY; cand_bsr_flag = FALSE; while (!EQUAL((w = next_word(&s)), "")) { if (EQUAL(w, "priority")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing priority; set to default %u (0 is lowest)\n", PIM_DEFAULT_BSR_PRIORITY); priority = PIM_DEFAULT_BSR_PRIORITY; continue; } if (sscanf(w, "%u", &priority) != 1) { logit(LOG_WARNING, 0, "Invalid priority %s; set to default %u (0 is lowest)", PIM_DEFAULT_BSR_PRIORITY); priority = PIM_DEFAULT_BSR_PRIORITY; continue; } if (priority > (my_bsr_priority = ~0)) priority = my_bsr_priority; my_bsr_priority = (u_int8)priority; continue; } /* BSR address */ local = inet_parse(w, 4); if (!inet_valid_host(local)) { local = max_local_address(); logit(LOG_WARNING, 0, "Invalid BSR address provided '%s' in %s. Will use the largest enabled local address.", w, configfilename); continue; } if (local_address(local) == NO_VIF) { local = max_local_address(); logit(LOG_WARNING, 0, "Cand-BSR address is not local '%s' in %s. Will use the largest enabled local address.", w, configfilename); } } /* while not empty */ if (local == INADDR_ANY_N) /* If address not provided, use the max. local */ local = max_local_address(); my_bsr_address = local; my_bsr_priority = priority; MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, my_bsr_hash_mask); cand_bsr_flag = TRUE; logit(LOG_INFO, 0, "Local Cand-BSR address is %s", inet_fmt(local, s1, sizeof(s1))); logit(LOG_INFO, 0, "Local Cand-BSR priority is %u", priority); return TRUE; } /** * parse_rp_address - Parse rp_address config option. * @s: String token. * * This is an extension to the original pimd to add pimd.conf support for static * Rendez-Vous Point addresses. * * The function has been extended by pjf@asn.pl, of Lintrack, to allow specifying * multicast group addresses as well. * * Format: * rp_address [ [masklen ] [priority ]] * * Returns: * When parsing @s is successful this function returns %TRUE, otherwise %FALSE. */ int parse_rp_address(char *s) { char *w; u_int32 local = 0xffffff; u_int32 group_addr = htonl(INADDR_UNSPEC_GROUP); u_int32 masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN; u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY; struct rp_hold * rph; /* next is RP addr */ w = next_word(&s); if (EQUAL(w, "")) { logit(LOG_WARNING, 0, "'rp_address' in %s: no - ignoring", configfilename); return FALSE; } local = inet_parse(w, 4); if (local == 0xffffff) { logit(LOG_WARNING, 0, "'rp_address' in %s: invalid provided: '%s'", configfilename, w); return FALSE; } /* next is group addr if exist */ w = next_word(&s); if (!EQUAL(w, "")) { group_addr = inet_parse(w, 4); if (!IN_MULTICAST(ntohl(group_addr))) { logit(LOG_WARNING, 0, "'rp_address' in %s: %s is not a multicast addr", configfilename, inet_fmt(group_addr, s1, sizeof(s1))); return FALSE; } masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN; priority = PIM_DEFAULT_CAND_RP_PRIORITY; /* next is prefix or priority if exist */ while (!EQUAL((w = next_word(&s)), "")) { if (EQUAL(w, "masklen")) { w = next_word(&s); if (sscanf(w, "%u", &masklen) == 1) { if (masklen > (sizeof(group_addr) * 8)) { masklen = (sizeof(group_addr) * 8); } else if (masklen < PIM_GROUP_PREFIX_MIN_MASKLEN) { logit(LOG_WARNING, 0, "'rp_address' in %s: %s is too small. set to %d.", configfilename, w, PIM_GROUP_PREFIX_MIN_MASKLEN); masklen = PIM_GROUP_PREFIX_MIN_MASKLEN; } } else { logit(LOG_WARNING, 0, "'rp_address' in %s: %s is invalid masklen. set to default(%d)", configfilename, w, PIM_GROUP_PREFIX_DEFAULT_MASKLEN); masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN; } } else if (EQUAL(w, "priority")) { w = next_word(&s); if (sscanf(w, "%u", &priority) == 1) { if (priority > PIM_MAX_CAND_RP_PRIORITY) { logit(LOG_WARNING, 0, "'rp_address' in %s: %s is too big. set to %d.", configfilename, w, PIM_MAX_CAND_RP_PRIORITY); priority = PIM_MAX_CAND_RP_PRIORITY; } } else { logit(LOG_WARNING, 0, "'rp_address' in %s: %s is invalid priority. set to default(%d)", configfilename, w, PIM_DEFAULT_CAND_RP_PRIORITY); priority = PIM_DEFAULT_CAND_RP_PRIORITY; } } } } else { group_addr = htonl(INADDR_UNSPEC_GROUP); masklen = PIM_GROUP_PREFIX_MIN_MASKLEN; priority = 1; } /* save */ rph = calloc(1, sizeof(*rph)); if (!rph) { logit(LOG_WARNING, 0, "Ran out of memory in parse_rp_address()"); return FALSE; } rph->address = local; rph->group = group_addr; VAL_TO_MASK(rph->mask, masklen); rph->priority = priority; /* attach at the beginning */ rph->next = g_rp_hold; g_rp_hold = rph; logit(LOG_INFO, 0, "Added static RP: %s, group %s/%d, prioriy %d", inet_fmt(local, s1, sizeof(s1)), inet_fmt(group_addr, s2, sizeof(s2)), masklen, priority); 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 interval ]'. * comments: called by config_vifs_from_file() */ int parse_reg_threshold(char *s) { char *w; u_int rate; u_int interval; rate = PIM_DEFAULT_REG_RATE; interval = PIM_DEFAULT_REG_RATE_INTERVAL; pim_reg_rate_bytes = (rate * interval) / 10; pim_reg_rate_check_interval = interval; while (!EQUAL((w = next_word(&s)), "")) { if (EQUAL(w, "rate")) { /* rate */ if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing reg_rate value; set to default %u (bits/s)\n", PIM_DEFAULT_REG_RATE); rate = PIM_DEFAULT_REG_RATE; continue; } if (sscanf(w, "%u", &rate) != 1) { logit(LOG_WARNING, 0, "Invalid reg_rate value %s; set to default %u (bits/s)", w, PIM_DEFAULT_REG_RATE); rate = PIM_DEFAULT_REG_RATE; } continue; } /* if rate */ if (EQUAL(w, "interval")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing reg_rate interval; set to default %u seconds", PIM_DEFAULT_REG_RATE_INTERVAL); interval = PIM_DEFAULT_REG_RATE_INTERVAL; continue; } if (sscanf(w, "%u", &interval) != 1) { logit(LOG_WARNING, 0, "Invalid reg_rate interval %s; set to default %u seconds", w, PIM_DEFAULT_REG_RATE_INTERVAL); interval = PIM_DEFAULT_REG_RATE_INTERVAL; } continue; } /* if interval */ logit(LOG_WARNING, 0, "Invalid parameter %s; setting rate and interval to default", w); rate = PIM_DEFAULT_REG_RATE; interval = PIM_DEFAULT_REG_RATE_INTERVAL; break; } /* while not empty */ if (interval < TIMER_INTERVAL) { logit(LOG_WARNING, 0, "reg_rate interval too short; set to default %u seconds", PIM_DEFAULT_REG_RATE_INTERVAL); interval = PIM_DEFAULT_REG_RATE_INTERVAL; } logit(LOG_INFO, 0, "reg_rate_limit is %u (bits/s)", rate); logit(LOG_INFO, 0, "reg_rate_interval is %u (seconds)", 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 interval ]'. */ int parse_data_threshold(char *s) { char *w; u_int rate; u_int interval; rate = PIM_DEFAULT_DATA_RATE; interval = PIM_DEFAULT_DATA_RATE_INTERVAL; pim_data_rate_bytes = (rate * interval) / 10; pim_data_rate_check_interval = interval; while (!EQUAL((w = next_word(&s)), "")) { if (EQUAL(w, "rate")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing data_rate value; set to default %u (bits/s)\n", PIM_DEFAULT_DATA_RATE); rate = PIM_DEFAULT_DATA_RATE; continue; } if (sscanf(w, "%u", &rate) != 1) { logit(LOG_WARNING, 0, "Invalid data_rate value %s; set to default %u (bits/s)", w, PIM_DEFAULT_DATA_RATE); rate = PIM_DEFAULT_DATA_RATE; } continue; } /* if rate */ if (EQUAL(w, "interval")) { if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing data_rate interval; set to default %u seconds", PIM_DEFAULT_DATA_RATE_INTERVAL); interval = PIM_DEFAULT_DATA_RATE_INTERVAL; continue; } if (sscanf(w, "%u", &interval) != 1) { logit(LOG_WARNING, 0, "Invalid data_rate interval %s; set to default %u seconds", w, PIM_DEFAULT_DATA_RATE_INTERVAL); interval = PIM_DEFAULT_DATA_RATE_INTERVAL; } continue; } /* if interval */ logit(LOG_WARNING, 0, "Invalid parameter %s; setting rate and interval to default", w); rate = PIM_DEFAULT_DATA_RATE; interval = PIM_DEFAULT_DATA_RATE_INTERVAL; break; } /* while not empty */ if (interval < TIMER_INTERVAL) { logit(LOG_WARNING, 0, "data_rate interval too short; set to default %u seconds", PIM_DEFAULT_DATA_RATE_INTERVAL); interval = PIM_DEFAULT_DATA_RATE_INTERVAL; } logit(LOG_INFO, 0, "data_rate_limit is %u (bits/s)", rate); logit(LOG_INFO, 0, "data_rate_interval is %u (seconds)", 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 '. * 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 = UCAST_DEFAULT_SOURCE_METRIC; if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing default source metric; set to default %u", UCAST_DEFAULT_SOURCE_METRIC); } else if (sscanf(w, "%u", &value) != 1) { logit(LOG_WARNING, 0, "Invalid default source metric; set to default %u", UCAST_DEFAULT_SOURCE_METRIC); value = UCAST_DEFAULT_SOURCE_METRIC; } default_source_metric = value; logit(LOG_INFO, 0, "default_source_metric is %u", value); 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 '. * 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 = UCAST_DEFAULT_SOURCE_PREFERENCE; if (EQUAL((w = next_word(&s)), "")) { logit(LOG_WARNING, 0, "Missing default source preference; set to default %u", UCAST_DEFAULT_SOURCE_PREFERENCE); } else if (sscanf(w, "%u", &value) != 1) { logit(LOG_WARNING, 0, "Invalid default source preference; set to default %u", UCAST_DEFAULT_SOURCE_PREFERENCE); value = UCAST_DEFAULT_SOURCE_PREFERENCE; } default_source_preference = value; logit(LOG_INFO, 0, "default_source_preference is %u", value); for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) v->uv_local_pref = default_source_preference; return TRUE; } void config_vifs_from_file(void) { FILE *f; char linebuf[LINE_BUFSIZ]; char *w, *s; struct ifconf ifc; int option; char ifbuf[BUFSIZ]; u_int8 *data_ptr; int error_flag; int line_num; error_flag = FALSE; line_num = 0; if ((f = fopen(configfilename, "r")) == NULL) { if (errno != ENOENT) logit(LOG_WARNING, errno, "Cannot open %s", configfilename); return; } /* TODO: HARDCODING!!! */ cand_rp_adv_message.buffer = (u_int8 *)calloc(1, 4 + sizeof(pim_encod_uni_addr_t) + 255 * sizeof(pim_encod_grp_addr_t)); if (!cand_rp_adv_message.buffer) { logit(LOG_ERR, errno, "Ran out of memory in config_vifs_from_file()"); } 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 = 224.0.0.0 and masklen = 4. */ *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 + 6); ifc.ifc_buf = ifbuf; ifc.ifc_len = sizeof(ifbuf); if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) logit(LOG_ERR, errno, "ioctl SIOCGIFCONF"); while (fgets(linebuf, sizeof(linebuf), f) != NULL) { if (strlen(linebuf) >= (LINE_BUFSIZ - 1)) { logit(LOG_WARNING, 0, "line length must be shorter than %d in %s:%d", LINE_BUFSIZ, configfilename, line_num); error_flag = TRUE; } else { line_num++; } s = linebuf; w = next_word(&s); option = wordToOption(w); switch(option) { case CONF_EMPTY: continue; break; case CONF_PHYINT: parse_phyint(s); break; case CONF_CANDIDATE_RP: parse_candidateRP(s); break; case CONF_RP_ADDRESS: parse_rp_address(s); break; case CONF_GROUP_PREFIX: parse_group_prefix(s); break; case CONF_BOOTSTRAP_RP: parseBSR(s); break; case CONF_REG_THRESHOLD: parse_reg_threshold(s); break; case CONF_DATA_THRESHOLD: parse_data_threshold(s); break; case CONF_DEFAULT_SOURCE_METRIC: parse_default_source_metric(s); break; case CONF_DEFAULT_SOURCE_PREFERENCE: parse_default_source_preference(s); break; default: logit(LOG_WARNING, 0, "unknown command '%s' in %s:%d", w, configfilename, line_num); error_flag = TRUE; } } if (error_flag) { /* * XXX: let's be pedantic even about warnings. If this is a problem, * comment out this logit(LOG_ERR). */ logit(LOG_ERR, 0, "Syntax Error in %s", configfilename); } cand_rp_adv_message.message_size = cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer; if (cand_rp_flag != FALSE) { /* Prepare the RP info */ my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period; /* TODO: HARDCODING! */ data_ptr = cand_rp_adv_message.buffer + 1; PUT_BYTE(my_cand_rp_priority, data_ptr); PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr); PUT_EUADDR(my_cand_rp_address, data_ptr); } fclose(f); } static u_int32 ifname2addr(char *s) { vifi_t vifi; struct uvif *v; for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { if (!strcmp(v->uv_name, s)) return v->uv_lcl_addr; } return 0; } static 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((int)**s) && isupper((int)**s)) **s = tolower((int)**s); (*s)++; } } } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/FAQ0000644000000000000000000000603711700261371007677 0ustar Mini-FAQ: - Q: My RP is a Cisco router, but it doesn't work with pimd A1: If your Cisco is running PIM-SMv1, it won't work with pimd which implements only PIM-SMv2. You need to upgrade/configure your Cisco to run PIM-SMv2 A2: If your Cisco is indeed running PIM-SMv2, and it is the RP, you need to recompile pimd with BROKEN_CISCO_CHECKSUM defined (see the beginning of Makefile). Note that then the PIM Register messages may not be accepted by some other vendors (pimd-to-pimd should still be OK). - Q: I have added in the past PIM patches to my *BSD kernel, but recent pimd versions (pimd-2.1.0-alpha29 and later) do not work with that kernel. A: Around the time pimd-2.1.0-alpha29 was created, the kernel PIM API was changed. Unfortunately, the result was non-compatibility. Either update your kernel to use the most recent API, or recompile pimd with PIM_OLD_KERNEL defined (see the beginning of Makefile) - Q: I have Solaris 8, but my kernel crashes when I start pimd A: There is a bug in the Solaris 8 kernel. I guess there is a patch that fixes it, but I don't know its location. - Q: Do I need to re-configure my Linux kernel to run pimd? - A: Very likely, yes, because some of the options below are not enabled by default. Make sure that you have: * enable CONFIG_IP_MULTICAST * enable CONFIG_IP_PIMSM_V2 * enable CONFIG_IP_MROUTE * You _may_ enable CONFIG_IP_PIMSM_V1 as well, but I don't think it is required if you are running only PIM-SMv2 * enable the NETLINK-related options * Make sure that those options are set to "y" to include the relevant code in the kernel; if you enable them as modules, then you may have to load that module after you boot with the new kernel. One way to find-out if multicast routing is not working, is to use command `cat /proc/sys/net/ipv4/conf/eth0/mc_forwarding' after you have started pimd (you may use other interface name instead of eth0). If it returns zero, the multicast forwarding on that interface is not working. - Q: I tried to run pimd on Linux, but I get the following error message: "netlink socket: Address family not supported by protocol" - A: You need to enable the NETLINK-related stuff in the kernel and recompile it. - Q: pimd compiled and is running on a single machines, but when I run it on 2+ machines, the multicast packets do not reach the receivers. - A: Without detailed debug information I cannot answer this question. Please send to the pimd maintainer a scheme of your network, and the debug output from each router (pimd -d all) - Q: How do I debug my multicast routing? - A: Check README.debug for some hints. - Q: How do I use pimd with GRE tunnels? - A: See file README.config - Q: How do I run pimd but without configuring it as a Cand-RP and/or a Cand-BSR? - A: See file README.config - Q: How do I configure pimd to do FOO? - A: See file README.config. If the answer is not there, send email to the current pimd maintainer. pimd-2.1.8/INSTALL0000644000000000000000000000251411700261371010372 0ustar Installation instruction for pimd ================================= 1. Apply the PIM kernel patches, recompile, reboot 2. Copy pimd.conf to /etc and edit as appropriate. Disable the interfaces you don't need. Note that you need at least 2 physical interfaces enabled. 3. Edit Makefile by uncommenting the line(s) corresponding to your platform. 4. Recompile pimd 5. Run pimd as a root. It is highly recommended to run it in debug mode. Because there are many debug messages, you can specify only a subset of the messages to be printed out: usage: pimd [-c configfile] [-d [debug_level][,debug_level]] Valid debug levels: dvmrp_prunes, dvmrp_mrt, dvmrp_neighbors, dvmrp_timers, igmp_proto, igmp_timers, igmp_members, trace,timeout, pkt, interfaces, kernel, cache, rsrr, pim_hello, pim_register, pim_join_prune, pim_bootstrap, pim_asserts, pim_cand_rp, pim_routes, pim_timers, pim_rpf If you want to see all messages, use "pimd -d all" only. 6. Note that it takes of the order of 30 seconds to 1 minute until the Bootstrap router is elected and the RP-set distributed to the PIM routers, and without the RP-set in the routers the multicast packets cannot be forwarded. 7. There are plenty of bugs, some of them known (check BUGS.TODO), some of them unknown, so your bug reports are more than welcome. pimd-2.1.8/include/0000755000000000000000000000000011700261371010762 5ustar pimd-2.1.8/include/freebsd2/0000755000000000000000000000000011700261371012456 5ustar pimd-2.1.8/include/freebsd2/netinet/0000755000000000000000000000000011700261371014124 5ustar pimd-2.1.8/include/freebsd2/netinet/in.h0000644000000000000000000003274311700261371014714 0ustar /* * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 * $Id: in.h,v 1.22.2.1 1996/11/11 23:40:37 phk Exp $ */ #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ /* * Constants and structures defined by the internet system, * Per RFC 790, September 1981, and numerous additions. */ /* * Protocols */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group mgmt protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_IPIP 4 /* IP encapsulation in IP */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ #define IPPROTO_RSVP 46 /* resource reservation */ #define IPPROTO_EON 80 /* ISO cnlp */ #define IPPROTO_ENCAP 98 /* encapsulation header */ #define IPPROTO_PIM 103 /* Protocol Independent Mcast */ #define IPPROTO_DIVERT 254 /* divert pseudo-protocol */ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 /* * Local port number conventions: * * When a user does a bind(2) or connect(2) with a port number of zero, * a non-conflicting local port address is chosen. * The default range is IPPORT_RESERVED through * IPPORT_USERRESERVED, although that is settable by sysctl. * * A user may set the IPPROTO_IP option IP_PORTRANGE to change this * default assignment range. * * The value IP_PORTRANGE_DEFAULT causes the default behavior. * * The value IP_PORTRANGE_HIGH changes the range of candidate port numbers * into the "high" range. These are reserved for client outbound connections * which do not want to be filtered by any firewalls. * * The value IP_PORTRANGE_LOW changes the range to the "low" are * that is (by convention) restricted to privileged processes. This * convention is based on "vouchsafe" principles only. It is only secure * if you trust the remote host to restrict these ports. * * The default range of ports and the high range can be changed by * sysctl(3). (net.inet.ip.port{hi,low}{first,last}_auto) * * Changing those values has bad security implications if you are * using a a stateless firewall that is allowing packets outside of that * range in order to allow transparent outgoing connections. * * Such a firewall configuration will generally depend on the use of these * default values. If you change them, you may find your Security * Administrator looking for you with a heavy object. */ /* * Ports < IPPORT_RESERVED are reserved for * privileged processes (e.g. root). (IP_PORTRANGE_LOW) * Ports > IPPORT_USERRESERVED are reserved * for servers, not necessarily privileged. (IP_PORTRANGE_DEFAULT) */ #define IPPORT_RESERVED 1024 #define IPPORT_USERRESERVED 5000 /* * Default local port range to use by setting IP_PORTRANGE_HIGH */ #define IPPORT_HIFIRSTAUTO 40000 #define IPPORT_HILASTAUTO 44999 /* * Scanning for a free reserved port return a value below IPPORT_RESERVED, * but higher than IPPORT_RESERVEDSTART. Traditionally the start value was * 512, but that conflicts with some well-known-services that firewalls may * have a fit if we use. */ #define IPPORT_RESERVEDSTART 600 /* * Internet address (a structure for historical reasons) */ struct in_addr { u_long s_addr; }; /* * Definitions of bits in internet address integers. * On subnets, the decomposition of addresses to host and net parts * is done according to subnet mask, not the masks here. */ #define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST 0x00ffffff #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST 0x0000ffff #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST 0x000000ff #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) #define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ #define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ #define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ #define IN_MULTICAST(i) IN_CLASSD(i) #define IN_EXPERIMENTAL(i) (((long)(i) & 0xf0000000) == 0xf0000000) #define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) #define INADDR_ANY (u_long)0x00000000 #define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */ #ifndef KERNEL #define INADDR_NONE 0xffffffff /* -1 return */ #endif #define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */ #define INADDR_ALLRTRS_GROUP (u_long)0xe0000002 /* 224.0.0.2 */ #define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */ #define IN_LOOPBACKNET 127 /* official! */ /* * Socket address, internet style. */ struct sockaddr_in { u_char sin_len; u_char sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; /* * Structure used to describe IP options. * Used to store options internally, to pass them to a process, * or to restore options retrieved earlier. * The ip_dst is used for the first-hop gateway when using a source route * (this gets put into the header proper). */ struct ip_opts { struct in_addr ip_dst; /* first hop, 0 w/o src rt */ char ip_opts[40]; /* actually variable in size */ }; /* * Options for use with [gs]etsockopt at the IP level. * First word of comment is data type; bool is stored in int. */ #define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ #define IP_HDRINCL 2 /* int; header is included with data */ #define IP_TOS 3 /* int; IP type of service and preced. */ #define IP_TTL 4 /* int; IP time to live */ #define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ #define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ #define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ #define IP_RETOPTS 8 /* ip_opts; set/get IP options */ #define IP_MULTICAST_IF 9 /* u_char; set/get IP multicast i/f */ #define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ #define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ #define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ #define IP_MULTICAST_VIF 14 /* set/get IP mcast virt. iface */ #define IP_RSVP_ON 15 /* enable RSVP in kernel */ #define IP_RSVP_OFF 16 /* disable RSVP in kernel */ #define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */ #define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */ #define IP_PORTRANGE 19 /* int; range to choose for unspec port */ #define IP_RECVIF 20 /* bool; receive reception if w/dgram */ #define IP_FW_ADD 50 /* add a firewall rule to chain */ #define IP_FW_DEL 51 /* delete a firewall rule from chain */ #define IP_FW_FLUSH 52 /* flush firewall rule chain */ #define IP_FW_ZERO 53 /* clear single/all firewall counter(s) */ #define IP_FW_GET 54 /* get entire firewall rule chain */ #define IP_NAT 55 /* set/get NAT opts */ /* * Defaults and limits for options */ #define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ #define IP_MAX_MEMBERSHIPS 20 /* per socket */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; /* * Argument for IP_PORTRANGE: * - which range to search when port is unspecified at bind() or connect() */ #define IP_PORTRANGE_DEFAULT 0 /* default range */ #define IP_PORTRANGE_HIGH 1 /* "high" - request firewall bypass */ #define IP_PORTRANGE_LOW 2 /* "low" - vouchsafe security */ /* * Definitions for inet sysctl operations. * * Third level is protocol number. * Fourth level is desired variable within that protocol. */ #define IPPROTO_MAXID (IPPROTO_IDP + 1) /* don't list to IPPROTO_MAX */ #define CTL_IPPROTO_NAMES { \ { "ip", CTLTYPE_NODE }, \ { "icmp", CTLTYPE_NODE }, \ { "igmp", CTLTYPE_NODE }, \ { "ggp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { "tcp", CTLTYPE_NODE }, \ { 0, 0 }, \ { "egp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pup", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "udp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "idp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pim", CTLTYPE_NODE }, \ } /* * Names for IP sysctl objects */ #define IPCTL_FORWARDING 1 /* act as router */ #define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ #define IPCTL_DEFTTL 3 /* default TTL */ #ifdef notyet #define IPCTL_DEFMTU 4 /* default MTU */ #endif #define IPCTL_RTEXPIRE 5 /* cloned route expiration time */ #define IPCTL_RTMINEXPIRE 6 /* min value for expiration time */ #define IPCTL_RTMAXCACHE 7 /* trigger level for dynamic expire */ #define IPCTL_SOURCEROUTE 8 /* may perform source routes */ #define IPCTL_DIRECTEDBROADCAST 9 /* may re-broadcast received packets */ #define IPCTL_INTRQMAXLEN 10 /* max length of netisr queue */ #define IPCTL_INTRQDROPS 11 /* number of netisr q drops */ #define IPCTL_MAXID 12 #define IPCTL_NAMES { \ { 0, 0 }, \ { "forwarding", CTLTYPE_INT }, \ { "redirect", CTLTYPE_INT }, \ { "ttl", CTLTYPE_INT }, \ { "mtu", CTLTYPE_INT }, \ { "rtexpire", CTLTYPE_INT }, \ { "rtminexpire", CTLTYPE_INT }, \ { "rtmaxcache", CTLTYPE_INT }, \ { "sourceroute", CTLTYPE_INT }, \ { "directed-broadcast", CTLTYPE_INT }, \ { "intr-queue-maxlen", CTLTYPE_INT }, \ { "intr-queue-drops", CTLTYPE_INT }, \ } #ifdef KERNEL struct ifnet; struct mbuf; /* forward declarations for Standard C */ int in_broadcast __P((struct in_addr, struct ifnet *)); int in_canforward __P((struct in_addr)); int in_cksum __P((struct mbuf *, int)); int in_localaddr __P((struct in_addr)); char *inet_ntoa __P((struct in_addr)); /* in libkern */ /* Firewall hooks */ struct ip; typedef int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, int, struct mbuf**)); typedef int ip_fw_ctl_t __P((int, struct mbuf**)); extern ip_fw_chk_t *ip_fw_chk_ptr; extern ip_fw_ctl_t *ip_fw_ctl_ptr; /* IP NAT hooks */ typedef int ip_nat_t __P((struct ip**, struct mbuf**, struct ifnet*, int)); typedef int ip_nat_ctl_t __P((int, struct mbuf**)); extern ip_nat_t *ip_nat_ptr; extern ip_nat_ctl_t *ip_nat_ctl_ptr; #define IP_NAT_IN 0x00000001 #define IP_NAT_OUT 0x00000002 #endif /* KERNEL */ #endif pimd-2.1.8/include/freebsd2/netinet/ip_mroute.h0000644000000000000000000002363611700261371016312 0ustar /* * Copyright (c) 1989 Stephen Deering. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Stephen Deering of Stanford University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_mroute.h 8.1 (Berkeley) 6/10/93 * $Id: ip_mroute.h,v 1.10.4.1 1997/02/22 19:47:28 joerg Exp $ */ #ifndef _NETINET_IP_MROUTE_H_ #define _NETINET_IP_MROUTE_H_ /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * * MROUTING Revision: 3.3.1.3 */ /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert (wrong iif) processing */ #define GET_TIME(t) microtime(&t) /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_long vifbitmap_t; typedef u_short vifi_t; /* type of a vif index */ #define ALL_VIFS (vifi_t)-1 #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_char vifc_flags; /* VIFF_ flags defined below */ u_char vifc_threshold; /* min ttl required to forward on vif */ u_int vifc_rate_limit; /* max rate */ struct in_addr vifc_lcl_addr; /* local interface address */ struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */ }; #define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ #define VIFF_SRCRT 0x2 /* tunnel uses IP source routing */ #define VIFF_REGISTER 0x4 /* vif used for register en/decap */ #ifdef PIM_REG_KERNEL_ENCAP #define VIFF_REGISTER_KERNEL_ENCAP 0x8 /* vif register with kernel encap */ #endif /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC * (mfcc_tos to be added at a future point) */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfcc_rp_addr; /* The RP address for encap. */ #endif }; /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to mrouted */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; /* * Argument structure used by mrouted to get src-grp pkt counts */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* Input packet count on vif */ u_long ocount; /* Output packet count on vif */ u_long ibytes; /* Input byte count on vif */ u_long obytes; /* Output byte count on vif */ }; /* * The kernel's virtual-interface structure. */ struct vif { u_char v_flags; /* VIFF_ flags defined above */ u_char v_threshold; /* min ttl required to forward on vif*/ u_int v_rate_limit; /* max rate */ struct tbf *v_tbf; /* token bucket structure at intf. */ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* cached route if this is a tunnel */ u_int v_rsvp_on; /* RSVP listening on this vif */ struct socket *v_rsvpd; /* RSVP daemon socket */ }; /* * The kernel's multicast forwarding cache entry structure * (A field for the type of service (mfc_tos) is to be added * at a future point) */ struct mfc { struct in_addr mfc_origin; /* IP origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated*/ vifi_t mfc_parent; /* incoming vif */ u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert*/ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfc_rp_addr; /* The RP address for encap. */ #endif }; /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IP packet */ struct igmpmsg { u_long unused1; u_long unused2; u_char im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 #define IGMPMSG_WRONGVIF 2 #define IGMPMSG_WHOLEPKT 3 /* send the whole packet */ u_char im_mbz; /* must be zero */ u_char im_vif; /* vif rec'd on */ u_char unused3; struct in_addr im_src, im_dst; }; /* * Argument structure used for pkt info. while upcall is made */ struct rtdetq { struct mbuf *m; /* A copy of the packet */ struct ifnet *ifp; /* Interface pkt came in on */ vifi_t xmt_vif; /* Saved copy of imo_multicast_vif */ #ifdef UPCALL_TIMING struct timeval t; /* Timestamp */ #endif /* UPCALL_TIMING */ }; #define MFCTBLSIZ 256 #if (MFCTBLSIZ & (MFCTBLSIZ - 1)) == 0 /* from sys:route.h */ #define MFCHASHMOD(h) ((h) & (MFCTBLSIZ - 1)) #else #define MFCHASHMOD(h) ((h) % MFCTBLSIZ) #endif #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ /* * Token Bucket filter code */ #define MAX_BKT_SIZE 10000 /* 10K bytes size */ #define MAXQSIZE 10 /* max # of pkts in queue */ /* * the token bucket filter at each vif */ struct tbf { struct timeval tbf_last_pkt_t; /* arr. time of last pkt */ u_long tbf_n_tok; /* no of tokens in bucket */ u_long tbf_q_len; /* length of queue at this vif */ u_long tbf_max_q_len; /* max. queue length */ struct mbuf *tbf_q; /* Packet queue */ struct mbuf *tbf_t; /* tail-insertion pointer */ }; #ifdef KERNEL extern int (*ip_mrouter_set) __P((int, struct socket *, struct mbuf *)); extern int (*ip_mrouter_get) __P((int, struct socket *, struct mbuf **)); extern int (*ip_mrouter_done) __P((void)); #ifdef MROUTING extern int (*mrt_ioctl) __P((int, caddr_t)); #else extern int (*mrt_ioctl) __P((int, caddr_t, struct proc *)); #endif #endif /* KERNEL */ #endif /* _NETINET_IP_MROUTE_H_ */ pimd-2.1.8/include/freebsd/0000755000000000000000000000000011700261371012374 5ustar pimd-2.1.8/include/freebsd/netinet/0000755000000000000000000000000011700261371014042 5ustar pimd-2.1.8/include/freebsd/netinet/in.h0000644000000000000000000006703011700261371014627 0ustar /*- * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 * $FreeBSD: src/sys/netinet/in.h,v 1.116 2010/08/19 11:31:03 anchie Exp $ */ #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ #include #include #include /* Protocols common to RFC 1700, POSIX, and X/Open. */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define INADDR_ANY (u_int32_t)0x00000000 #define INADDR_BROADCAST (u_int32_t)0xffffffff /* must be masked */ #ifndef _UINT8_T_DECLARED typedef __uint8_t uint8_t; #define _UINT8_T_DECLARED #endif #ifndef _UINT16_T_DECLARED typedef __uint16_t uint16_t; #define _UINT16_T_DECLARED #endif #ifndef _UINT32_T_DECLARED typedef __uint32_t uint32_t; #define _UINT32_T_DECLARED #endif #ifndef _IN_ADDR_T_DECLARED typedef uint32_t in_addr_t; #define _IN_ADDR_T_DECLARED #endif #ifndef _IN_PORT_T_DECLARED typedef uint16_t in_port_t; #define _IN_PORT_T_DECLARED #endif #ifndef _SA_FAMILY_T_DECLARED typedef __sa_family_t sa_family_t; #define _SA_FAMILY_T_DECLARED #endif /* Internet address (a structure for historical reasons). */ #ifndef _STRUCT_IN_ADDR_DECLARED struct in_addr { in_addr_t s_addr; }; #define _STRUCT_IN_ADDR_DECLARED #endif #ifndef _SOCKLEN_T_DECLARED typedef __socklen_t socklen_t; #define _SOCKLEN_T_DECLARED #endif #include /* Socket address, internet style. */ struct sockaddr_in { uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; }; #if !defined(_KERNEL) && __BSD_VISIBLE #ifndef _BYTEORDER_PROTOTYPED #define _BYTEORDER_PROTOTYPED __BEGIN_DECLS uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); __END_DECLS #endif #ifndef _BYTEORDER_FUNC_DEFINED #define _BYTEORDER_FUNC_DEFINED #define htonl(x) __htonl(x) #define htons(x) __htons(x) #define ntohl(x) __ntohl(x) #define ntohs(x) __ntohs(x) #endif #endif /* !_KERNEL && __BSD_VISIBLE */ #if __POSIX_VISIBLE >= 200112 #define IPPROTO_RAW 255 /* raw IP packet */ #define INET_ADDRSTRLEN 16 #endif #if __BSD_VISIBLE /* * Constants and structures defined by the internet system, * Per RFC 790, September 1981, and numerous additions. */ /* * Protocols (RFC 1700) */ #define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */ #define IPPROTO_IGMP 2 /* group mgmt protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_IPV4 4 /* IPv4 encapsulation */ #define IPPROTO_IPIP IPPROTO_IPV4 /* for compatibility */ #define IPPROTO_ST 7 /* Stream protocol II */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ #define IPPROTO_PIGP 9 /* private interior gateway */ #define IPPROTO_RCCMON 10 /* BBN RCC Monitoring */ #define IPPROTO_NVPII 11 /* network voice protocol*/ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_ARGUS 13 /* Argus */ #define IPPROTO_EMCON 14 /* EMCON */ #define IPPROTO_XNET 15 /* Cross Net Debugger */ #define IPPROTO_CHAOS 16 /* Chaos*/ #define IPPROTO_MUX 18 /* Multiplexing */ #define IPPROTO_MEAS 19 /* DCN Measurement Subsystems */ #define IPPROTO_HMP 20 /* Host Monitoring */ #define IPPROTO_PRM 21 /* Packet Radio Measurement */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_TRUNK1 23 /* Trunk-1 */ #define IPPROTO_TRUNK2 24 /* Trunk-2 */ #define IPPROTO_LEAF1 25 /* Leaf-1 */ #define IPPROTO_LEAF2 26 /* Leaf-2 */ #define IPPROTO_RDP 27 /* Reliable Data */ #define IPPROTO_IRTP 28 /* Reliable Transaction */ #define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ #define IPPROTO_BLT 30 /* Bulk Data Transfer */ #define IPPROTO_NSP 31 /* Network Services */ #define IPPROTO_INP 32 /* Merit Internodal */ #define IPPROTO_SEP 33 /* Sequential Exchange */ #define IPPROTO_3PC 34 /* Third Party Connect */ #define IPPROTO_IDPR 35 /* InterDomain Policy Routing */ #define IPPROTO_XTP 36 /* XTP */ #define IPPROTO_DDP 37 /* Datagram Delivery */ #define IPPROTO_CMTP 38 /* Control Message Transport */ #define IPPROTO_TPXX 39 /* TP++ Transport */ #define IPPROTO_IL 40 /* IL transport protocol */ #define IPPROTO_IPV6 41 /* IP6 header */ #define IPPROTO_SDRP 42 /* Source Demand Routing */ #define IPPROTO_ROUTING 43 /* IP6 routing header */ #define IPPROTO_FRAGMENT 44 /* IP6 fragmentation header */ #define IPPROTO_IDRP 45 /* InterDomain Routing*/ #define IPPROTO_RSVP 46 /* resource reservation */ #define IPPROTO_GRE 47 /* General Routing Encap. */ #define IPPROTO_MHRP 48 /* Mobile Host Routing */ #define IPPROTO_BHA 49 /* BHA */ #define IPPROTO_ESP 50 /* IP6 Encap Sec. Payload */ #define IPPROTO_AH 51 /* IP6 Auth Header */ #define IPPROTO_INLSP 52 /* Integ. Net Layer Security */ #define IPPROTO_SWIPE 53 /* IP with encryption */ #define IPPROTO_NHRP 54 /* Next Hop Resolution */ #define IPPROTO_MOBILE 55 /* IP Mobility */ #define IPPROTO_TLSP 56 /* Transport Layer Security */ #define IPPROTO_SKIP 57 /* SKIP */ #define IPPROTO_ICMPV6 58 /* ICMP6 */ #define IPPROTO_NONE 59 /* IP6 no next header */ #define IPPROTO_DSTOPTS 60 /* IP6 destination option */ #define IPPROTO_AHIP 61 /* any host internal protocol */ #define IPPROTO_CFTP 62 /* CFTP */ #define IPPROTO_HELLO 63 /* "hello" routing protocol */ #define IPPROTO_SATEXPAK 64 /* SATNET/Backroom EXPAK */ #define IPPROTO_KRYPTOLAN 65 /* Kryptolan */ #define IPPROTO_RVD 66 /* Remote Virtual Disk */ #define IPPROTO_IPPC 67 /* Pluribus Packet Core */ #define IPPROTO_ADFS 68 /* Any distributed FS */ #define IPPROTO_SATMON 69 /* Satnet Monitoring */ #define IPPROTO_VISA 70 /* VISA Protocol */ #define IPPROTO_IPCV 71 /* Packet Core Utility */ #define IPPROTO_CPNX 72 /* Comp. Prot. Net. Executive */ #define IPPROTO_CPHB 73 /* Comp. Prot. HeartBeat */ #define IPPROTO_WSN 74 /* Wang Span Network */ #define IPPROTO_PVP 75 /* Packet Video Protocol */ #define IPPROTO_BRSATMON 76 /* BackRoom SATNET Monitoring */ #define IPPROTO_ND 77 /* Sun net disk proto (temp.) */ #define IPPROTO_WBMON 78 /* WIDEBAND Monitoring */ #define IPPROTO_WBEXPAK 79 /* WIDEBAND EXPAK */ #define IPPROTO_EON 80 /* ISO cnlp */ #define IPPROTO_VMTP 81 /* VMTP */ #define IPPROTO_SVMTP 82 /* Secure VMTP */ #define IPPROTO_VINES 83 /* Banyon VINES */ #define IPPROTO_TTP 84 /* TTP */ #define IPPROTO_IGP 85 /* NSFNET-IGP */ #define IPPROTO_DGP 86 /* dissimilar gateway prot. */ #define IPPROTO_TCF 87 /* TCF */ #define IPPROTO_IGRP 88 /* Cisco/GXS IGRP */ #define IPPROTO_OSPFIGP 89 /* OSPFIGP */ #define IPPROTO_SRPC 90 /* Strite RPC protocol */ #define IPPROTO_LARP 91 /* Locus Address Resoloution */ #define IPPROTO_MTP 92 /* Multicast Transport */ #define IPPROTO_AX25 93 /* AX.25 Frames */ #define IPPROTO_IPEIP 94 /* IP encapsulated in IP */ #define IPPROTO_MICP 95 /* Mobile Int.ing control */ #define IPPROTO_SCCSP 96 /* Semaphore Comm. security */ #define IPPROTO_ETHERIP 97 /* Ethernet IP encapsulation */ #define IPPROTO_ENCAP 98 /* encapsulation header */ #define IPPROTO_APES 99 /* any private encr. scheme */ #define IPPROTO_GMTP 100 /* GMTP*/ #define IPPROTO_IPCOMP 108 /* payload compression (IPComp) */ #define IPPROTO_SCTP 132 /* SCTP */ #define IPPROTO_MH 135 /* IPv6 Mobility Header */ /* 101-254: Partly Unassigned */ #define IPPROTO_PIM 103 /* Protocol Independent Mcast */ #define IPPROTO_CARP 112 /* CARP */ #define IPPROTO_PGM 113 /* PGM */ #define IPPROTO_PFSYNC 240 /* PFSYNC */ /* 255: Reserved */ /* BSD Private, local use, namespace incursion, no longer used */ #define IPPROTO_OLD_DIVERT 254 /* OLD divert pseudo-proto */ #define IPPROTO_MAX 256 /* last return value of *_input(), meaning "all job for this pkt is done". */ #define IPPROTO_DONE 257 /* Only used internally, so can be outside the range of valid IP protocols. */ #define IPPROTO_DIVERT 258 /* divert pseudo-protocol */ #define IPPROTO_SEND 259 /* SeND pseudo-protocol */ /* * Defined to avoid confusion. The master value is defined by * PROTO_SPACER in sys/protosw.h. */ #define IPPROTO_SPACER 32767 /* spacer for loadable protos */ /* * Local port number conventions: * * When a user does a bind(2) or connect(2) with a port number of zero, * a non-conflicting local port address is chosen. * The default range is IPPORT_HIFIRSTAUTO through * IPPORT_HILASTAUTO, although that is settable by sysctl. * * A user may set the IPPROTO_IP option IP_PORTRANGE to change this * default assignment range. * * The value IP_PORTRANGE_DEFAULT causes the default behavior. * * The value IP_PORTRANGE_HIGH changes the range of candidate port numbers * into the "high" range. These are reserved for client outbound connections * which do not want to be filtered by any firewalls. * * The value IP_PORTRANGE_LOW changes the range to the "low" are * that is (by convention) restricted to privileged processes. This * convention is based on "vouchsafe" principles only. It is only secure * if you trust the remote host to restrict these ports. * * The default range of ports and the high range can be changed by * sysctl(3). (net.inet.ip.port{hi,low}{first,last}_auto) * * Changing those values has bad security implications if you are * using a stateless firewall that is allowing packets outside of that * range in order to allow transparent outgoing connections. * * Such a firewall configuration will generally depend on the use of these * default values. If you change them, you may find your Security * Administrator looking for you with a heavy object. * * For a slightly more orthodox text view on this: * * ftp://ftp.isi.edu/in-notes/iana/assignments/port-numbers * * port numbers are divided into three ranges: * * 0 - 1023 Well Known Ports * 1024 - 49151 Registered Ports * 49152 - 65535 Dynamic and/or Private Ports * */ /* * Ports < IPPORT_RESERVED are reserved for * privileged processes (e.g. root). (IP_PORTRANGE_LOW) */ #define IPPORT_RESERVED 1024 /* * Default local port range, used by IP_PORTRANGE_DEFAULT */ #define IPPORT_EPHEMERALFIRST 10000 #define IPPORT_EPHEMERALLAST 65535 /* * Dynamic port range, used by IP_PORTRANGE_HIGH. */ #define IPPORT_HIFIRSTAUTO 49152 #define IPPORT_HILASTAUTO 65535 /* * Scanning for a free reserved port return a value below IPPORT_RESERVED, * but higher than IPPORT_RESERVEDSTART. Traditionally the start value was * 512, but that conflicts with some well-known-services that firewalls may * have a fit if we use. */ #define IPPORT_RESERVEDSTART 600 #define IPPORT_MAX 65535 /* * Definitions of bits in internet address integers. * On subnets, the decomposition of addresses to host and net parts * is done according to subnet mask, not the masks here. */ #define IN_CLASSA(i) (((u_int32_t)(i) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST 0x00ffffff #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((u_int32_t)(i) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST 0x0000ffff #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((u_int32_t)(i) & 0xe0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST 0x000000ff #define IN_CLASSD(i) (((u_int32_t)(i) & 0xf0000000) == 0xe0000000) #define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ #define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ #define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ #define IN_MULTICAST(i) IN_CLASSD(i) #define IN_EXPERIMENTAL(i) (((u_int32_t)(i) & 0xf0000000) == 0xf0000000) #define IN_BADCLASS(i) (((u_int32_t)(i) & 0xf0000000) == 0xf0000000) #define IN_LINKLOCAL(i) (((u_int32_t)(i) & 0xffff0000) == 0xa9fe0000) #define IN_LOOPBACK(i) (((u_int32_t)(i) & 0xff000000) == 0x7f000000) #define IN_ZERONET(i) (((u_int32_t)(i) & 0xff000000) == 0) #define IN_PRIVATE(i) ((((u_int32_t)(i) & 0xff000000) == 0x0a000000) || \ (((u_int32_t)(i) & 0xfff00000) == 0xac100000) || \ (((u_int32_t)(i) & 0xffff0000) == 0xc0a80000)) #define IN_LOCAL_GROUP(i) (((u_int32_t)(i) & 0xffffff00) == 0xe0000000) #define IN_ANY_LOCAL(i) (IN_LINKLOCAL(i) || IN_LOCAL_GROUP(i)) #define INADDR_LOOPBACK (u_int32_t)0x7f000001 #ifndef _KERNEL #define INADDR_NONE 0xffffffff /* -1 return */ #endif #define INADDR_UNSPEC_GROUP (u_int32_t)0xe0000000 /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP (u_int32_t)0xe0000001 /* 224.0.0.1 */ #define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */ #define INADDR_ALLRPTS_GROUP (u_int32_t)0xe0000016 /* 224.0.0.22, IGMPv3 */ #define INADDR_CARP_GROUP (u_int32_t)0xe0000012 /* 224.0.0.18 */ #define INADDR_PFSYNC_GROUP (u_int32_t)0xe00000f0 /* 224.0.0.240 */ #define INADDR_ALLMDNS_GROUP (u_int32_t)0xe00000fb /* 224.0.0.251 */ #define INADDR_MAX_LOCAL_GROUP (u_int32_t)0xe00000ff /* 224.0.0.255 */ #define IN_LOOPBACKNET 127 /* official! */ /* * Options for use with [gs]etsockopt at the IP level. * First word of comment is data type; bool is stored in int. */ #define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ #define IP_HDRINCL 2 /* int; header is included with data */ #define IP_TOS 3 /* int; IP type of service and preced. */ #define IP_TTL 4 /* int; IP time to live */ #define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ #define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ #define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ #define IP_SENDSRCADDR IP_RECVDSTADDR /* cmsg_type to set src addr */ #define IP_RETOPTS 8 /* ip_opts; set/get IP options */ #define IP_MULTICAST_IF 9 /* struct in_addr *or* struct ip_mreqn; * set/get IP multicast i/f */ #define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ #define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ #define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ #define IP_MULTICAST_VIF 14 /* set/get IP mcast virt. iface */ #define IP_RSVP_ON 15 /* enable RSVP in kernel */ #define IP_RSVP_OFF 16 /* disable RSVP in kernel */ #define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */ #define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */ #define IP_PORTRANGE 19 /* int; range to choose for unspec port */ #define IP_RECVIF 20 /* bool; receive reception if w/dgram */ /* for IPSEC */ #define IP_IPSEC_POLICY 21 /* int; set/get security policy */ #define IP_FAITH 22 /* bool; accept FAITH'ed connections */ #define IP_ONESBCAST 23 /* bool: send all-ones broadcast */ #define IP_BINDANY 24 /* bool: allow bind to any address */ /* * Options for controlling the firewall and dummynet. * Historical options (from 40 to 64) will eventually be * replaced by only two options, IP_FW3 and IP_DUMMYNET3. */ #define IP_FW_TABLE_ADD 40 /* add entry */ #define IP_FW_TABLE_DEL 41 /* delete entry */ #define IP_FW_TABLE_FLUSH 42 /* flush table */ #define IP_FW_TABLE_GETSIZE 43 /* get table size */ #define IP_FW_TABLE_LIST 44 /* list table contents */ #define IP_FW3 48 /* generic ipfw v.3 sockopts */ #define IP_DUMMYNET3 49 /* generic dummynet v.3 sockopts */ #define IP_FW_ADD 50 /* add a firewall rule to chain */ #define IP_FW_DEL 51 /* delete a firewall rule from chain */ #define IP_FW_FLUSH 52 /* flush firewall rule chain */ #define IP_FW_ZERO 53 /* clear single/all firewall counter(s) */ #define IP_FW_GET 54 /* get entire firewall rule chain */ #define IP_FW_RESETLOG 55 /* reset logging counters */ #define IP_FW_NAT_CFG 56 /* add/config a nat rule */ #define IP_FW_NAT_DEL 57 /* delete a nat rule */ #define IP_FW_NAT_GET_CONFIG 58 /* get configuration of a nat rule */ #define IP_FW_NAT_GET_LOG 59 /* get log of a nat rule */ #define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ #define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ #define IP_DUMMYNET_FLUSH 62 /* flush dummynet */ #define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */ #define IP_RECVTTL 65 /* bool; receive IP TTL w/dgram */ #define IP_MINTTL 66 /* minimum TTL for packet or drop */ #define IP_DONTFRAG 67 /* don't fragment packet */ /* IPv4 Source Filter Multicast API [RFC3678] */ #define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */ #define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */ #define IP_BLOCK_SOURCE 72 /* block a source */ #define IP_UNBLOCK_SOURCE 73 /* unblock a source */ /* The following option is private; do not use it from user applications. */ #define IP_MSFILTER 74 /* set/get filter list */ /* Protocol Independent Multicast API [RFC3678] */ #define MCAST_JOIN_GROUP 80 /* join an any-source group */ #define MCAST_LEAVE_GROUP 81 /* leave all sources for group */ #define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */ #define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */ #define MCAST_BLOCK_SOURCE 84 /* block a source */ #define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */ /* * Defaults and limits for options */ #define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ /* * The imo_membership vector for each socket is now dynamically allocated at * run-time, bounded by USHRT_MAX, and is reallocated when needed, sized * according to a power-of-two increment. */ #define IP_MIN_MEMBERSHIPS 31 #define IP_MAX_MEMBERSHIPS 4095 #define IP_MAX_SOURCE_FILTER 1024 /* XXX to be unused */ /* * Default resource limits for IPv4 multicast source filtering. * These may be modified by sysctl. */ #define IP_MAX_GROUP_SRC_FILTER 512 /* sources per group */ #define IP_MAX_SOCK_SRC_FILTER 128 /* sources per socket/group */ #define IP_MAX_SOCK_MUTE_FILTER 128 /* XXX no longer used */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; /* * Modified argument structure for IP_MULTICAST_IF, obtained from Linux. * This is used to specify an interface index for multicast sends, as * the IPv4 legacy APIs do not support this (unless IP_SENDIF is available). */ struct ip_mreqn { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_address; /* local IP address of interface */ int imr_ifindex; /* Interface index; cast to uint32_t */ }; /* * Argument structure for IPv4 Multicast Source Filter APIs. [RFC3678] */ struct ip_mreq_source { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_sourceaddr; /* IP address of source */ struct in_addr imr_interface; /* local IP address of interface */ }; /* * Argument structures for Protocol-Independent Multicast Source * Filter APIs. [RFC3678] */ struct group_req { uint32_t gr_interface; /* interface index */ struct sockaddr_storage gr_group; /* group address */ }; struct group_source_req { uint32_t gsr_interface; /* interface index */ struct sockaddr_storage gsr_group; /* group address */ struct sockaddr_storage gsr_source; /* source address */ }; #ifndef __MSFILTERREQ_DEFINED #define __MSFILTERREQ_DEFINED /* * The following structure is private; do not use it from user applications. * It is used to communicate IP_MSFILTER/IPV6_MSFILTER information between * the RFC 3678 libc functions and the kernel. */ struct __msfilterreq { uint32_t msfr_ifindex; /* interface index */ uint32_t msfr_fmode; /* filter mode for group */ uint32_t msfr_nsrcs; /* # of sources in msfr_srcs */ struct sockaddr_storage msfr_group; /* group address */ struct sockaddr_storage *msfr_srcs; /* pointer to the first member * of a contiguous array of * sources to filter in full. */ }; #endif struct sockaddr; /* * Advanced (Full-state) APIs [RFC3678] * The RFC specifies uint_t for the 6th argument to [sg]etsourcefilter(). * We use uint32_t here to be consistent. */ int setipv4sourcefilter(int, struct in_addr, struct in_addr, uint32_t, uint32_t, struct in_addr *); int getipv4sourcefilter(int, struct in_addr, struct in_addr, uint32_t *, uint32_t *, struct in_addr *); int setsourcefilter(int, uint32_t, struct sockaddr *, socklen_t, uint32_t, uint32_t, struct sockaddr_storage *); int getsourcefilter(int, uint32_t, struct sockaddr *, socklen_t, uint32_t *, uint32_t *, struct sockaddr_storage *); /* * Filter modes; also used to represent per-socket filter mode internally. */ #define MCAST_UNDEFINED 0 /* fmode: not yet defined */ #define MCAST_INCLUDE 1 /* fmode: include these source(s) */ #define MCAST_EXCLUDE 2 /* fmode: exclude these source(s) */ /* * Argument for IP_PORTRANGE: * - which range to search when port is unspecified at bind() or connect() */ #define IP_PORTRANGE_DEFAULT 0 /* default range */ #define IP_PORTRANGE_HIGH 1 /* "high" - request firewall bypass */ #define IP_PORTRANGE_LOW 2 /* "low" - vouchsafe security */ /* * Definitions for inet sysctl operations. * * Third level is protocol number. * Fourth level is desired variable within that protocol. */ #define IPPROTO_MAXID (IPPROTO_AH + 1) /* don't list to IPPROTO_MAX */ #define CTL_IPPROTO_NAMES { \ { "ip", CTLTYPE_NODE }, \ { "icmp", CTLTYPE_NODE }, \ { "igmp", CTLTYPE_NODE }, \ { "ggp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { "tcp", CTLTYPE_NODE }, \ { 0, 0 }, \ { "egp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pup", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "udp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "idp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "ipsec", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pim", CTLTYPE_NODE }, \ } /* * Names for IP sysctl objects */ #define IPCTL_FORWARDING 1 /* act as router */ #define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ #define IPCTL_DEFTTL 3 /* default TTL */ #ifdef notyet #define IPCTL_DEFMTU 4 /* default MTU */ #endif #define IPCTL_RTEXPIRE 5 /* cloned route expiration time */ #define IPCTL_RTMINEXPIRE 6 /* min value for expiration time */ #define IPCTL_RTMAXCACHE 7 /* trigger level for dynamic expire */ #define IPCTL_SOURCEROUTE 8 /* may perform source routes */ #define IPCTL_DIRECTEDBROADCAST 9 /* may re-broadcast received packets */ #define IPCTL_INTRQMAXLEN 10 /* max length of netisr queue */ #define IPCTL_INTRQDROPS 11 /* number of netisr q drops */ #define IPCTL_STATS 12 /* ipstat structure */ #define IPCTL_ACCEPTSOURCEROUTE 13 /* may accept source routed packets */ #define IPCTL_FASTFORWARDING 14 /* use fast IP forwarding code */ #define IPCTL_KEEPFAITH 15 /* FAITH IPv4->IPv6 translater ctl */ #define IPCTL_GIF_TTL 16 /* default TTL for gif encap packet */ #define IPCTL_MAXID 17 #define IPCTL_NAMES { \ { 0, 0 }, \ { "forwarding", CTLTYPE_INT }, \ { "redirect", CTLTYPE_INT }, \ { "ttl", CTLTYPE_INT }, \ { "mtu", CTLTYPE_INT }, \ { "rtexpire", CTLTYPE_INT }, \ { "rtminexpire", CTLTYPE_INT }, \ { "rtmaxcache", CTLTYPE_INT }, \ { "sourceroute", CTLTYPE_INT }, \ { "directed-broadcast", CTLTYPE_INT }, \ { "intr-queue-maxlen", CTLTYPE_INT }, \ { "intr-queue-drops", CTLTYPE_INT }, \ { "stats", CTLTYPE_STRUCT }, \ { "accept_sourceroute", CTLTYPE_INT }, \ { "fastforwarding", CTLTYPE_INT }, \ } #endif /* __BSD_VISIBLE */ #ifdef _KERNEL struct ifnet; struct mbuf; /* forward declarations for Standard C */ int in_broadcast(struct in_addr, struct ifnet *); int in_canforward(struct in_addr); int in_localaddr(struct in_addr); int in_localip(struct in_addr); int inet_aton(const char *, struct in_addr *); /* in libkern */ char *inet_ntoa(struct in_addr); /* in libkern */ char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */ void in_ifdetach(struct ifnet *); #define in_hosteq(s, t) ((s).s_addr == (t).s_addr) #define in_nullhost(x) ((x).s_addr == INADDR_ANY) #define in_allhosts(x) ((x).s_addr == htonl(INADDR_ALLHOSTS_GROUP)) #define satosin(sa) ((struct sockaddr_in *)(sa)) #define sintosa(sin) ((struct sockaddr *)(sin)) #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) /* * Historically, BSD keeps ip_len and ip_off in host format * when doing layer 3 processing, and this often requires * to translate the format back and forth. * To make the process explicit, we define a couple of macros * that also take into account the fact that at some point * we may want to keep those fields always in net format. */ #if (BYTE_ORDER == BIG_ENDIAN) || defined(HAVE_NET_IPLEN) #define SET_NET_IPLEN(p) do {} while (0) #define SET_HOST_IPLEN(p) do {} while (0) #else #define SET_NET_IPLEN(p) do { \ struct ip *h_ip = (p); \ h_ip->ip_len = htons(h_ip->ip_len); \ h_ip->ip_off = htons(h_ip->ip_off); \ } while (0) #define SET_HOST_IPLEN(p) do { \ struct ip *h_ip = (p); \ h_ip->ip_len = ntohs(h_ip->ip_len); \ h_ip->ip_off = ntohs(h_ip->ip_off); \ } while (0) #endif /* !HAVE_NET_IPLEN */ #endif /* _KERNEL */ /* INET6 stuff */ #if __POSIX_VISIBLE >= 200112 #define __KAME_NETINET_IN_H_INCLUDED_ #include #undef __KAME_NETINET_IN_H_INCLUDED_ #endif #endif /* !_NETINET_IN_H_*/ pimd-2.1.8/include/freebsd/netinet/ip_mroute.h0000644000000000000000000003324411700261371016224 0ustar /*- * Copyright (c) 1989 Stephen Deering. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Stephen Deering of Stanford University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_mroute.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/netinet/ip_mroute.h,v 1.37 2010/06/02 15:44:43 zec Exp $ */ #ifndef _NETINET_IP_MROUTE_H_ #define _NETINET_IP_MROUTE_H_ /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * Modified by Ahmed Helmy, SGI, June 1996. * Modified by Pavlin Radoslavov, ICSI, October 2002. * * MROUTING Revision: 3.3.1.3 * and PIM-SMv2 and PIM-DM support, advanced API support, * bandwidth metering and signaling. */ /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert processing */ #define MRT_PIM MRT_ASSERT /* enable PIM processing */ #define MRT_API_SUPPORT 109 /* supported MRT API */ #define MRT_API_CONFIG 110 /* config MRT API */ #define MRT_ADD_BW_UPCALL 111 /* create bandwidth monitor */ #define MRT_DEL_BW_UPCALL 112 /* delete bandwidth monitor */ /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_long vifbitmap_t; typedef u_short vifi_t; /* type of a vif index */ #define ALL_VIFS (vifi_t)-1 #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) struct mfc; /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_char vifc_flags; /* VIFF_ flags defined below */ u_char vifc_threshold; /* min ttl required to forward on vif */ u_int vifc_rate_limit; /* max rate */ struct in_addr vifc_lcl_addr; /* local interface address */ struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */ }; #define VIFF_TUNNEL 0x1 /* no-op; retained for old source */ #define VIFF_SRCRT 0x2 /* no-op; retained for old source */ #define VIFF_REGISTER 0x4 /* used for PIM Register encap/decap */ /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC * XXX if you change this, make sure to change struct mfcctl2 as well. */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ }; /* * The new argument structure for MRT_ADD_MFC and MRT_DEL_MFC overlays * and extends the old struct mfcctl. */ struct mfcctl2 { /* the mfcctl fields */ struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ /* extension fields */ uint8_t mfcc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfcc_rp; /* the RP address */ }; /* * The advanced-API flags. * * The MRT_MFC_FLAGS_XXX API flags are also used as flags * for the mfcc_flags field. */ #define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 << 0) /* disable WRONGVIF signals */ #define MRT_MFC_FLAGS_BORDER_VIF (1 << 1) /* border vif */ #define MRT_MFC_RP (1 << 8) /* enable RP address */ #define MRT_MFC_BW_UPCALL (1 << 9) /* enable bw upcalls */ #define MRT_MFC_FLAGS_ALL (MRT_MFC_FLAGS_DISABLE_WRONGVIF | \ MRT_MFC_FLAGS_BORDER_VIF) #define MRT_API_FLAGS_ALL (MRT_MFC_FLAGS_ALL | \ MRT_MFC_RP | \ MRT_MFC_BW_UPCALL) /* * Structure for installing or delivering an upcall if the * measured bandwidth is above or below a threshold. * * User programs (e.g. daemons) may have a need to know when the * bandwidth used by some data flow is above or below some threshold. * This interface allows the userland to specify the threshold (in * bytes and/or packets) and the measurement interval. Flows are * all packet with the same source and destination IP address. * At the moment the code is only used for multicast destinations * but there is nothing that prevents its use for unicast. * * The measurement interval cannot be shorter than some Tmin (currently, 3s). * The threshold is set in packets and/or bytes per_interval. * * Measurement works as follows: * * For >= measurements: * The first packet marks the start of a measurement interval. * During an interval we count packets and bytes, and when we * pass the threshold we deliver an upcall and we are done. * The first packet after the end of the interval resets the * count and restarts the measurement. * * For <= measurement: * We start a timer to fire at the end of the interval, and * then for each incoming packet we count packets and bytes. * When the timer fires, we compare the value with the threshold, * schedule an upcall if we are below, and restart the measurement * (reschedule timer and zero counters). */ struct bw_data { struct timeval b_time; uint64_t b_packets; uint64_t b_bytes; }; struct bw_upcall { struct in_addr bu_src; /* source address */ struct in_addr bu_dst; /* destination address */ uint32_t bu_flags; /* misc flags (see below) */ #define BW_UPCALL_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_UPCALL_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_UPCALL_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_UPCALL_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_UPCALL_DELETE_ALL (1 << 4) /* delete all upcalls for s,d*/ struct bw_data bu_threshold; /* the bw threshold */ struct bw_data bu_measured; /* the measured bw */ }; /* max. number of upcalls to deliver together */ #define BW_UPCALLS_MAX 128 /* min. threshold time interval for bandwidth measurement */ #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3 #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0 /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to multicast routing daemon */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; #ifdef _KERNEL #define MRTSTAT_ADD(name, val) V_mrtstat.name += (val) #define MRTSTAT_INC(name) MRTSTAT_ADD(name, 1) #endif /* * Argument structure used by mrouted to get src-grp pkt counts */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* Input packet count on vif */ u_long ocount; /* Output packet count on vif */ u_long ibytes; /* Input byte count on vif */ u_long obytes; /* Output byte count on vif */ }; /* * The kernel's virtual-interface structure. */ struct vif { u_char v_flags; /* VIFF_ flags defined above */ u_char v_threshold; /* min ttl required to forward on vif*/ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* cached route */ }; #ifdef _KERNEL /* * The kernel's multicast forwarding cache entry structure */ struct mfc { LIST_ENTRY(mfc) mfc_hash; struct in_addr mfc_origin; /* IP origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated*/ vifi_t mfc_parent; /* incoming vif */ u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert*/ uint8_t mfc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfc_rp; /* the RP address */ struct bw_meter *mfc_bw_meter; /* list of bandwidth meters */ u_long mfc_nstall; /* # of packets awaiting mfc */ TAILQ_HEAD(, rtdetq) mfc_stall; /* q of packets awaiting mfc */ }; #endif /* _KERNEL */ /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IP packet */ struct igmpmsg { uint32_t unused1; uint32_t unused2; u_char im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 /* no MFC in the kernel */ #define IGMPMSG_WRONGVIF 2 /* packet came from wrong interface */ #define IGMPMSG_WHOLEPKT 3 /* PIM pkt for user level encap. */ #define IGMPMSG_BW_UPCALL 4 /* BW monitoring upcall */ u_char im_mbz; /* must be zero */ u_char im_vif; /* vif rec'd on */ u_char unused3; struct in_addr im_src, im_dst; }; #ifdef _KERNEL /* * Argument structure used for pkt info. while upcall is made */ struct rtdetq { TAILQ_ENTRY(rtdetq) rte_link; struct mbuf *m; /* A copy of the packet */ struct ifnet *ifp; /* Interface pkt came in on */ vifi_t xmt_vif; /* Saved copy of imo_multicast_vif */ }; #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ #endif /* _KERNEL */ /* * Structure for measuring the bandwidth and sending an upcall if the * measured bandwidth is above or below a threshold. */ struct bw_meter { struct bw_meter *bm_mfc_next; /* next bw meter (same mfc) */ struct bw_meter *bm_time_next; /* next bw meter (same time) */ uint32_t bm_time_hash; /* the time hash value */ struct mfc *bm_mfc; /* the corresponding mfc */ uint32_t bm_flags; /* misc flags (see below) */ #define BW_METER_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_METER_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_METER_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_METER_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_METER_USER_FLAGS (BW_METER_UNIT_PACKETS | \ BW_METER_UNIT_BYTES | \ BW_METER_GEQ | \ BW_METER_LEQ) #define BW_METER_UPCALL_DELIVERED (1 << 24) /* upcall was delivered */ struct bw_data bm_threshold; /* the upcall threshold */ struct bw_data bm_measured; /* the measured bw */ struct timeval bm_start_time; /* abs. time */ }; #ifdef _KERNEL struct sockopt; extern int (*ip_mrouter_set)(struct socket *, struct sockopt *); extern int (*ip_mrouter_get)(struct socket *, struct sockopt *); extern int (*ip_mrouter_done)(void); extern int (*mrt_ioctl)(u_long, caddr_t, int); #endif /* _KERNEL */ #endif /* _NETINET_IP_MROUTE_H_ */ pimd-2.1.8/include/linux/0000755000000000000000000000000011700261371012121 5ustar pimd-2.1.8/include/linux/netinet/0000755000000000000000000000000011700261371013567 5ustar pimd-2.1.8/include/linux/netinet/in-glibc-2.1.h0000644000000000000000000002453511700261371015733 0ustar /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _NETINET_IN_H #define _NETINET_IN_H 1 #include #include #include #include __BEGIN_DECLS /* Standard well-defined IP protocols. */ enum { IPPROTO_IP = 0, /* Dummy protocol for TCP. */ IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */ IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */ IPPROTO_TCP = 6, /* Transmission Control Protocol. */ IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */ IPPROTO_PUP = 12, /* PUP protocol. */ IPPROTO_UDP = 17, /* User Datagram Protocol. */ IPPROTO_IDP = 22, /* XNS IDP protocol. */ IPPROTO_IPV6 = 41, /* IPv6 header. */ IPPROTO_ROUTING = 43, /* IPv6 routing header. */ IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */ IPPROTO_RSVP = 46, /* RSVP Protocol. */ IPPROTO_GRE = 47, /* Cisco tunneling protocol. */ IPPROTO_ESP = 50, /* encapsulating security payload. */ IPPROTO_AH = 51, /* authentication header. */ IPPROTO_ICMPV6 = 58, /* ICMPv6. */ IPPROTO_NONE = 59, /* IPv6 no next header. */ IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */ IPPROTO_PIM = 103, /* Protocol Independent Multicast. */ IPPROTO_RAW = 255, /* Raw IP packets. */ IPPROTO_MAX }; /* Standard well-known ports. */ enum { IPPORT_ECHO = 7, /* Echo service. */ IPPORT_DISCARD = 9, /* Discard transmissions service. */ IPPORT_SYSTAT = 11, /* System status service. */ IPPORT_DAYTIME = 13, /* Time of day service. */ IPPORT_NETSTAT = 15, /* Network status service. */ IPPORT_FTP = 21, /* File Transfer Protocol. */ IPPORT_TELNET = 23, /* Telnet protocol. */ IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ IPPORT_TIMESERVER = 37, /* Timeserver service. */ IPPORT_NAMESERVER = 42, /* Domain Name Service. */ IPPORT_WHOIS = 43, /* Internet Whois service. */ IPPORT_MTP = 57, IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ IPPORT_RJE = 77, IPPORT_FINGER = 79, /* Finger service. */ IPPORT_TTYLINK = 87, IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ IPPORT_EXECSERVER = 512, /* execd service. */ IPPORT_LOGINSERVER = 513, /* rlogind service. */ IPPORT_CMDSERVER = 514, IPPORT_EFSSERVER = 520, /* UDP ports. */ IPPORT_BIFFUDP = 512, IPPORT_WHOSERVER = 513, IPPORT_ROUTESERVER = 520, /* Ports less than this value are reserved for privileged processes. */ IPPORT_RESERVED = 1024, /* Ports greater this value are reserved for (non-privileged) servers. */ IPPORT_USERRESERVED = 5000 }; /* Internet address. */ struct in_addr { uint32_t s_addr; }; /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to the subnet mask, not these masks. */ #define IN_CLASSA(a) ((((uint32_t) (a)) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) #define IN_CLASSA_MAX 128 #define IN_CLASSB(a) ((((uint32_t) (a)) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) #define IN_CLASSB_MAX 65536 #define IN_CLASSC(a) ((((uint32_t) (a)) & 0xe0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) #define IN_CLASSD(a) ((((uint32_t) (a)) & 0xf0000000) == 0xe0000000) #define IN_MULTICAST(a) IN_CLASSD(a) #define IN_EXPERIMENTAL(a) ((((uint32_t) (a)) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(a) ((((uint32_t) (a)) & 0xf0000000) == 0xf0000000) /* Address to accept any incoming messages. */ #define INADDR_ANY ((uint32_t) 0x00000000) /* Address to send to all hosts. */ #define INADDR_BROADCAST ((uint32_t) 0xffffffff) /* Address indicating an error return. */ #define INADDR_NONE ((uint32_t) 0xffffffff) /* Network number for local host loopback. */ #define IN_LOOPBACKNET 127 /* Address to loopback in software to local host. */ #ifndef INADDR_LOOPBACK # define INADDR_LOOPBACK ((uint32_t) 0x7f000001) /* Inet 127.0.0.1. */ #endif /* Defines for Multicast INADDR. */ #define INADDR_UNSPEC_GROUP ((uint32_t) 0xe0000000) /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP ((uint32_t) 0xe0000001) /* 224.0.0.1 */ #define INADDR_ALLRTRS_GROUP ((uint32_t) 0xe0000002) /* 224.0.0.2 */ #define INADDR_MAX_LOCAL_GROUP ((uint32_t) 0xe00000ff) /* 224.0.0.255 */ /* IPv6 address */ struct in6_addr { union { uint8_t u6_addr8[16]; uint16_t u6_addr16[8]; uint32_t u6_addr32[4]; #if (~0UL) > 0xffffffff uint64_t u6_addr64[2]; #endif } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 #define s6_addr64 in6_u.u6_addr64 }; extern const struct in6_addr in6addr_any; /* :: */ extern const struct in6_addr in6addr_loopback; /* ::1 */ #define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } #define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } #define INET_ADDRSTRLEN 16 #define INET6_ADDRSTRLEN 46 /* Get the definition of the macro to define the common sockaddr members. */ #include /* Structure describing an Internet socket address. */ struct sockaddr_in { __SOCKADDR_COMMON (sin_); uint16_t sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (uint16_t) - sizeof (struct in_addr)]; }; /* Ditto, for IPv6. */ struct sockaddr_in6 { __SOCKADDR_COMMON (sin6_); uint16_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; /* IPv6 multicast request. */ struct ipv6_mreq { /* IPv6 multicast address of group */ struct in6_addr ipv6mr_multiaddr; /* local interface */ unsigned int ipv6mr_ifindex; }; /* Get system-specific definitions. */ #include /* Functions to convert between host and network byte order. Please note that these functions normally take `unsigned long int' or `unsigned short int' values as arguments and also return them. But this was a short-sighted decision since on different systems the types may have different representations but the values are always the same. */ extern uint32_t ntohl __P ((uint32_t __netlong)); extern uint16_t ntohs __P ((uint16_t __netshort)); extern uint32_t htonl __P ((uint32_t __hostlong)); extern uint16_t htons __P ((uint16_t __hostshort)); #include /* Get machine dependent optimized versions of byte swapping functions. */ #include #if __BYTE_ORDER == __BIG_ENDIAN && defined __OPTIMIZE__ /* The host byte order is the same as network byte order, so these functions are all just identity. */ # define ntohl(x) (x) # define ntohs(x) (x) # define htonl(x) (x) # define htons(x) (x) #else # if __BYTE_ORDER == __LITTLE_ENDIAN && defined __OPTIMIZE__ # define ntohl(x) __bswap_32 (x) # define ntohs(x) __bswap_16 (x) # define htonl(x) __bswap_32 (x) # define htons(x) __bswap_16 (x) # endif #endif #define IN6_IS_ADDR_UNSPECIFIED(a) \ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0) #define IN6_IS_ADDR_LOOPBACK(a) \ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == htonl (1)) #define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) #define IN6_IS_ADDR_LINKLOCAL(a) \ ((((uint32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) #define IN6_IS_ADDR_SITELOCAL(a) \ ((((uint32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfec00000)) #define IN6_IS_ADDR_V4MAPPED(a) \ ((((uint32_t *) (a))[0] == 0) && (((uint32_t *) (a))[1] == 0) && \ (((uint32_t *) (a))[2] == htonl (0xffff))) #define IN6_IS_ADDR_V4COMPAT(a) \ ((((uint32_t *) (a))[0] == 0) && (((uint32_t *) (a))[1] == 0) && \ (((uint32_t *) (a))[2] == 0) && (ntohl (((uint32_t *) (a))[3]) > 1)) #define IN6_ARE_ADDR_EQUAL(a,b) \ ((((uint32_t *) (a))[0] == ((uint32_t *) (b))[0]) && \ (((uint32_t *) (a))[1] == ((uint32_t *) (b))[2]) && \ (((uint32_t *) (a))[2] == ((uint32_t *) (b))[1]) && \ (((uint32_t *) (a))[3] == ((uint32_t *) (b))[3])) /* Bind socket to a privileged IP port. */ extern int bindresvport __P ((int __sockfd, struct sockaddr_in *__sock_in)); #define IN6_IS_ADDR_MC_NODELOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x1)) #define IN6_IS_ADDR_MC_LINKLOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x2)) #define IN6_IS_ADDR_MC_SITELOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x5)) #define IN6_IS_ADDR_MC_ORGLOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x8)) #define IN6_IS_ADDR_MC_GLOBAL(a) \ (IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0xe)) /* IPv6 packet information. */ struct in6_pktinfo { struct in6_addr ipi6_addr; /* src/dst IPv6 address */ unsigned int ipi6_ifindex; /* send/recv interface index */ }; __END_DECLS #endif /* netinet/in.h */ pimd-2.1.8/include/linux/netinet/ip_mroute.h0000644000000000000000000000002511700261371015740 0ustar #include "mroute.h" pimd-2.1.8/include/linux/netinet/in-glibc-2.0.h0000644000000000000000000002153611700261371015730 0ustar /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _NETINET_IN_H #define _NETINET_IN_H 1 #include #include #include __BEGIN_DECLS /* Standard well-defined IP protocols. */ enum { IPPROTO_IP = 0, /* Dummy protocol for TCP. */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */ IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */ IPPROTO_TCP = 6, /* Transmission Control Protocol. */ IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */ IPPROTO_PUP = 12, /* PUP protocol. */ IPPROTO_UDP = 17, /* User Datagram Protocol. */ IPPROTO_IDP = 22, /* XNS IDP protocol. */ IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling. */ IPPROTO_RSVP = 46, /* RSVP Protocol. */ IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702). */ IPPROTO_ICMPV6 = 58, /* ICMPv6. */ IPPROTO_PIM = 103, /* Protocol Independent Multicast. */ IPPROTO_RAW = 255, /* Raw IP packets. */ IPPROTO_MAX }; /* Standard well-known ports. */ enum { IPPORT_ECHO = 7, /* Echo service. */ IPPORT_DISCARD = 9, /* Discard transmissions service. */ IPPORT_SYSTAT = 11, /* System status service. */ IPPORT_DAYTIME = 13, /* Time of day service. */ IPPORT_NETSTAT = 15, /* Network status service. */ IPPORT_FTP = 21, /* File Transfer Protocol. */ IPPORT_TELNET = 23, /* Telnet protocol. */ IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ IPPORT_TIMESERVER = 37, /* Timeserver service. */ IPPORT_NAMESERVER = 42, /* Domain Name Service. */ IPPORT_WHOIS = 43, /* Internet Whois service. */ IPPORT_MTP = 57, IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ IPPORT_RJE = 77, IPPORT_FINGER = 79, /* Finger service. */ IPPORT_TTYLINK = 87, IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ IPPORT_EXECSERVER = 512, /* execd service. */ IPPORT_LOGINSERVER = 513, /* rlogind service. */ IPPORT_CMDSERVER = 514, IPPORT_EFSSERVER = 520, /* UDP ports. */ IPPORT_BIFFUDP = 512, IPPORT_WHOSERVER = 513, IPPORT_ROUTESERVER = 520, /* Ports less than this value are reserved for privileged processes. */ IPPORT_RESERVED = 1024, /* Ports greater this value are reserved for (non-privileged) servers. */ IPPORT_USERRESERVED = 5000 }; /* Internet address. */ struct in_addr { unsigned int s_addr; }; /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to the subnet mask, not these masks. */ #define IN_CLASSA(a) ((((unsigned) (a)) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) #define IN_CLASSA_MAX 128 #define IN_CLASSB(a) ((((unsigned) (a)) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) #define IN_CLASSB_MAX 65536 #define IN_CLASSC(a) ((((unsigned) (a)) & 0xc0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) #define IN_CLASSD(a) ((((unsigned) (a)) & 0xf0000000) == 0xe0000000) #define IN_MULTICAST(a) IN_CLASSD(a) #define IN_EXPERIMENTAL(a) ((((unsigned) (a)) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(a) ((((unsigned) (a)) & 0xf0000000) == 0xf0000000) /* Address to accept any incoming messages. */ #define INADDR_ANY ((unsigned) 0x00000000) /* Address to send to all hosts. */ #define INADDR_BROADCAST ((unsigned) 0xffffffff) /* Address indicating an error return. */ #define INADDR_NONE 0xffffffff /* Network number for local host loopback. */ #define IN_LOOPBACKNET 127 /* Address to loopback in software to local host. */ #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif /* Defines for Multicast INADDR. */ #define INADDR_UNSPEC_GROUP ((u_int32_t) 0xe0000000U) /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP ((u_int32_t) 0xe0000001U) /* 224.0.0.1 */ #define INADDR_ALLRTRS_GROUP ((u_int32_t) 0xe0000002U) /* 224.0.0.2 */ #define INADDR_MAX_LOCAL_GROUP ((u_int32_t) 0xe00000ffU) /* 224.0.0.255 */ /* Get the definition of the macro to define the common sockaddr members. */ #include /* Structure describing an Internet socket address. */ struct sockaddr_in { __SOCKADDR_COMMON (sin_); unsigned short int sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[sizeof(struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof(unsigned short int) - sizeof(struct in_addr)]; }; /* Options for use with `getsockopt' and `setsockopt' at the IP level. The first word in the comment at the right is the data type used; "bool" means a boolean value stored in an `int'. */ #define IP_TOS 1 /* int; IP type of service and precedence. */ #define IP_TTL 2 /* int; IP time to live. */ #define IP_HDRINCL 3 /* int; Header is included with data. */ #define IP_OPTIONS 4 /* ip_opts; IP per-packet options. */ #define IP_ROUTER_ALERT 5 /* not sure. defined in linux kernel. */ #define IP_RECVOPTS 6 /* not sure. defined in linux kernel. */ #define IP_RETOPTS 7 /* not sure. defined in linux kernel. */ #define IP_PKTINFO 8 /* not sure. defined in linux kernel. */ #define IP_PKTOPTIONS 9 /* not sure. defined in linux kernel. */ #define IP_MTU_DISCOVER 10 /* not sure. defined in linux kernel. */ #define IP_RECVERR 11 /* not sure. defined in linux kernel. */ #define IP_RECVTTL 12 /* not sure. defined in linux kernel. */ #define IP_RECVTOS 13 /* not sure. defined in linux kernel. */ #define IP_MTU 14 /* not sure. defined in linux kernel. */ #define IP_MULTICAST_IF 32 /* in_addr; set/get IP multicast i/f */ #define IP_MULTICAST_TTL 33 /* u_char; set/get IP multicast ttl */ #define IP_MULTICAST_LOOP 34 /* i_char; set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 35 /* ip_mreq; add an IP group membership */ #define IP_DROP_MEMBERSHIP 36 /* ip_mreq; drop an IP group membership */ /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS /* IP_MTU_DISCOVER values */ #define IP_PMTUDISC_DONT 0 /* Never send DF frames */ #define IP_PMTUDISC_WANT 1 /* Use per route hints */ #define IP_PMTUDISC_DO 2 /* Always DF */ /* To select the IP level. */ #define SOL_IP 0 /* Structure used to describe IP options for IP_OPTIONS. The `ip_dst' field is used for the first-hop gateway when using a source route (this gets put into the header proper). */ struct ip_opts { struct in_addr ip_dst; /* First hop; zero without source route. */ char ip_opts[40]; /* Actually variable in size. */ }; /* Structure used for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; /* Functions to convert between host and network byte order. Please note that these functions normally take `unsigned long int' or `unsigned short int' values as arguments and also return them. But this was a short-sighted decision since on different systems the types may have different representations but the values are always the same. */ extern u_int32_t ntohl __P ((u_int32_t __netlong)); extern u_int16_t ntohs __P ((u_int16_t __netshort)); extern u_int32_t htonl __P ((u_int32_t __hostlong)); extern u_int16_t htons __P ((u_int16_t __hostshort)); #include #if __BYTE_ORDER == __BIG_ENDIAN /* The host byte order is the same as network byte order, so these functions are all just identity. */ #define ntohl(x) (x) #define ntohs(x) (x) #define htonl(x) (x) #define htons(x) (x) #endif /* Bind socket to a priviledged IP port. */ extern int bindresvport __P ((int __sockfd, struct sockaddr_in *__sock_in)); __END_DECLS #endif /* netinet/in.h */ pimd-2.1.8/include/linux/netinet/mroute.h0000644000000000000000000000725311700261371015262 0ustar #ifndef __LINUX_MROUTE_H #define __LINUX_MROUTE_H #include #include /* * Based on the MROUTING 3.5 defines primarily to keep * source compatibility with BSD. * * See the mrouted code for the original history. * * Protocol Independent Multicast (PIM) data structures included * Carlos Picoto (cap@di.fc.ul.pt) * */ #define MRT_BASE 200 #define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ #define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ #define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ #define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ #define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ #define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ #define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ #define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) #define MAXVIFS 32 typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */ typedef unsigned short vifi_t; #define ALL_VIFS ((vifi_t)(-1)) /* * Same idea as select */ #define VIFM_SET(n,m) ((m)|=(1<<(n))) #define VIFM_CLR(n,m) ((m)&=~(1<<(n))) #define VIFM_ISSET(n,m) ((m)&(1<<(n))) #define VIFM_CLRALL(m) ((m)=0) #define VIFM_COPY(mfrom,mto) ((mto)=(mfrom)) #define VIFM_SAME(m1,m2) ((m1)==(m2)) /* * Passed by mrouted for an MRT_ADD_VIF - again we use the * mrouted 3.6 structures for compatibility */ struct vifctl { vifi_t vifc_vifi; /* Index of VIF */ unsigned char vifc_flags; /* VIFF_ flags */ unsigned char vifc_threshold; /* ttl limit */ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ struct in_addr vifc_lcl_addr; /* Our address */ struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ }; #define VIFF_TUNNEL 0x1 /* IPIP tunnel */ #define VIFF_SRCRT 0x2 /* NI */ #define VIFF_REGISTER 0x4 /* register vif */ /* * Cache manipulation structures for mrouted and PIMd */ struct mfcctl { struct in_addr mfcc_origin; /* Origin of mcast */ struct in_addr mfcc_mcastgrp; /* Group in question */ vifi_t mfcc_parent; /* Where it arrived */ unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ unsigned int mfcc_byte_cnt; unsigned int mfcc_wrong_if; int mfcc_expire; }; /* * Group count retrieval for mrouted */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; unsigned long pktcnt; unsigned long bytecnt; unsigned long wrong_if; }; /* * To get vif packet counts */ struct sioc_vif_req { vifi_t vifi; /* Which iface */ unsigned long icount; /* In packets */ unsigned long ocount; /* Out packets */ unsigned long ibytes; /* In bytes */ unsigned long obytes; /* Out bytes */ }; /* * This is the format the mroute daemon expects to see IGMP control * data. Magically happens to be like an IP packet as per the original */ struct igmpmsg { uint32_t unused1,unused2; unsigned char im_msgtype; /* What is this */ unsigned char im_mbz; /* Must be zero */ unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ unsigned char unused3; struct in_addr im_src,im_dst; }; /* * That's all usermode folks */ #define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ /* * Pseudo messages used by mrouted */ #define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ #define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ #endif pimd-2.1.8/include/linux/netinet/in-my.h0000644000000000000000000000146111700261371014773 0ustar /* * Dummy header file to include the appropriate in.h for Linux * The situation is pretty messy, and no guarantee it will work. * Use your skills and imagination at your own risk :) * * Thanks to Jonathan Day for the problem report and the solution * */ /* * Questions concerning this software should be directed to * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu) * * $Id: in.h,v 1.8 2000/03/08 09:12:45 pavlin Exp $ */ #include #if (defined(__GLIBC__) && (defined(__GLIBC_MINOR__))) # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) # include "in-glibc-2.0.h" # elif (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 1) # include "in-glibc-2.1.h" # else # include # include # endif /* __GLIBC__ */ #else # include # include #endif pimd-2.1.8/include/openbsd/0000755000000000000000000000000011700261371012414 5ustar pimd-2.1.8/include/openbsd/netinet/0000755000000000000000000000000011700261371014062 5ustar pimd-2.1.8/include/openbsd/netinet/ip_mroute.h0000644000000000000000000003041611700261371016242 0ustar /* $OpenBSD: ip_mroute.h,v 1.15 2009/07/13 19:14:29 michele Exp $ */ /* $NetBSD: ip_mroute.h,v 1.23 2004/04/21 17:49:46 itojun Exp $ */ #ifndef _NETINET_IP_MROUTE_H_ #define _NETINET_IP_MROUTE_H_ /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * Modified by Ahmed Helmy, SGI, June 1996. * Modified by Pavlin Radoslavov, ICSI, October 2002. * * MROUTING Revision: 1.2 * and PIM-SMv2 and PIM-DM support, advanced API support, * bandwidth metering and signaling. */ #include #include /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert processing */ #define MRT_PIM MRT_ASSERT /* enable PIM processing */ #define MRT_API_SUPPORT 109 /* supported MRT API */ #define MRT_API_CONFIG 110 /* config MRT API */ #define MRT_ADD_BW_UPCALL 111 /* create bandwidth monitor */ #define MRT_DEL_BW_UPCALL 112 /* delete bandwidth monitor */ /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_int32_t vifbitmap_t; typedef u_int16_t vifi_t; /* type of a vif index */ #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_SETALL(m) ((m) = 0xffffffff) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) #define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ #define VIFF_SRCRT 0x2 /* tunnel uses IP src routing */ #define VIFF_REGISTER 0x4 /* used for PIM Register encap/decap */ /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_int8_t vifc_flags; /* VIFF_ flags defined above */ u_int8_t vifc_threshold; /* min ttl required to forward on vif */ u_int32_t vifc_rate_limit; /* ignored */ struct in_addr vifc_lcl_addr;/* local interface address */ struct in_addr vifc_rmt_addr;/* remote address (tunnels only) */ }; /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC. * XXX if you change this, make sure to change struct mfcctl2 as well. */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated */ vifi_t mfcc_parent; /* incoming vif */ u_int8_t mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ }; /* * The new argument structure for MRT_ADD_MFC and MRT_DEL_MFC overlays * and extends the old struct mfcctl. */ struct mfcctl2 { /* the mfcctl fields */ struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_int8_t mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ /* extension fields */ u_int8_t mfcc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfcc_rp; /* the RP address */ }; /* * The advanced-API flags. * * The MRT_MFC_FLAGS_XXX API flags are also used as flags * for the mfcc_flags field. */ #define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 << 0) /* disable WRONGVIF signals */ #define MRT_MFC_FLAGS_BORDER_VIF (1 << 1) /* border vif */ #define MRT_MFC_RP (1 << 8) /* enable RP address */ #define MRT_MFC_BW_UPCALL (1 << 9) /* enable bw upcalls */ #define MRT_MFC_FLAGS_ALL (MRT_MFC_FLAGS_DISABLE_WRONGVIF | \ MRT_MFC_FLAGS_BORDER_VIF) #define MRT_API_FLAGS_ALL (MRT_MFC_FLAGS_ALL | \ MRT_MFC_RP | \ MRT_MFC_BW_UPCALL) /* * Structure for installing or delivering an upcall if the * measured bandwidth is above or below a threshold. * * User programs (e.g. daemons) may have a need to know when the * bandwidth used by some data flow is above or below some threshold. * This interface allows the userland to specify the threshold (in * bytes and/or packets) and the measurement interval. Flows are * all packet with the same source and destination IP address. * At the moment the code is only used for multicast destinations * but there is nothing that prevents its use for unicast. * * The measurement interval cannot be shorter than some Tmin (currently, 3s). * The threshold is set in packets and/or bytes per_interval. * * Measurement works as follows: * * For >= measurements: * The first packet marks the start of a measurement interval. * During an interval we count packets and bytes, and when we * pass the threshold we deliver an upcall and we are done. * The first packet after the end of the interval resets the * count and restarts the measurement. * * For <= measurement: * We start a timer to fire at the end of the interval, and * then for each incoming packet we count packets and bytes. * When the timer fires, we compare the value with the threshold, * schedule an upcall if we are below, and restart the measurement * (reschedule timer and zero counters). */ struct bw_data { struct timeval b_time; u_int64_t b_packets; u_int64_t b_bytes; }; struct bw_upcall { struct in_addr bu_src; /* source address */ struct in_addr bu_dst; /* destination address */ u_int32_t bu_flags; /* misc flags (see below) */ #define BW_UPCALL_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_UPCALL_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_UPCALL_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_UPCALL_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_UPCALL_DELETE_ALL (1 << 4) /* delete all upcalls for s,d*/ struct bw_data bu_threshold; /* the bw threshold */ struct bw_data bu_measured; /* the measured bw */ }; /* max. number of upcalls to deliver together */ #define BW_UPCALLS_MAX 128 /* min. threshold time interval for bandwidth measurement */ #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3 #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0 /* * Argument structure used by mrouted to get src-grp pkt counts. */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts. */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* input packet count on vif */ u_long ocount; /* output packet count on vif */ u_long ibytes; /* input byte count on vif */ u_long obytes; /* output byte count on vif */ }; /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to mrouted */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; #ifdef _KERNEL /* * The kernel's virtual-interface structure. */ struct vif { u_int8_t v_flags; /* VIFF_ flags defined above */ u_int8_t v_threshold; /* min ttl required to forward on vif */ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* cached route if this is a tunnel */ struct timeout v_repq_ch; /* for tbf_reprocess_q() */ #ifdef RSVP_ISI int v_rsvp_on; /* # RSVP listening on this vif */ struct socket *v_rsvpd; /* # RSVPD daemon */ #endif /* RSVP_ISI */ }; /* * The kernel's multicast forwarding cache entry structure. * (A field for the type of service (mfc_tos) is to be added * at a future point.) */ struct mfc { LIST_ENTRY(mfc) mfc_hash; struct in_addr mfc_origin; /* ip origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated */ vifi_t mfc_parent; /* incoming vif */ u_int8_t mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert */ struct rtdetq *mfc_stall; /* pkts waiting for route */ u_int8_t mfc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfc_rp; /* the RP address */ struct bw_meter *mfc_bw_meter; /* list of bandwidth meters */ }; /* * Structure used to communicate from kernel to multicast router. * (Note the convenient similarity to an IP packet.) */ struct igmpmsg { u_int32_t unused1; u_int32_t unused2; u_int8_t im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 /* no MFC in the kernel */ #define IGMPMSG_WRONGVIF 2 /* packet came from wrong interface */ #define IGMPMSG_WHOLEPKT 3 /* PIM pkt for user level encap. */ #define IGMPMSG_BW_UPCALL 4 /* BW monitoring upcall */ u_int8_t im_mbz; /* must be zero */ u_int8_t im_vif; /* vif rec'd on */ u_int8_t unused3; struct in_addr im_src, im_dst; }; /* * Argument structure used for pkt info. while upcall is made. */ struct rtdetq { struct mbuf *m; /* a copy of the packet */ struct ifnet *ifp; /* interface pkt came in on */ #ifdef UPCALL_TIMING struct timeval t; /* timestamp */ #endif /* UPCALL_TIMING */ struct rtdetq *next; }; #define MFCTBLSIZ 256 #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ /* * Structure for measuring the bandwidth and sending an upcall if the * measured bandwidth is above or below a threshold. */ struct bw_meter { struct bw_meter *bm_mfc_next; /* next bw meter (same mfc) */ struct bw_meter *bm_time_next; /* next bw meter (same time) */ uint32_t bm_time_hash; /* the time hash value */ struct mfc *bm_mfc; /* the corresponding mfc */ uint32_t bm_flags; /* misc flags (see below) */ #define BW_METER_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_METER_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_METER_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_METER_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_METER_USER_FLAGS (BW_METER_UNIT_PACKETS | \ BW_METER_UNIT_BYTES | \ BW_METER_GEQ | \ BW_METER_LEQ) #define BW_METER_UPCALL_DELIVERED (1 << 24) /* upcall was delivered */ struct bw_data bm_threshold; /* the upcall threshold */ struct bw_data bm_measured; /* the measured bw */ struct timeval bm_start_time; /* abs. time */ }; int ip_mrouter_set(struct socket *, int, struct mbuf **); int ip_mrouter_get(struct socket *, int, struct mbuf **); int mrt_ioctl(struct socket *, u_long, caddr_t); int ip_mrouter_done(void); void ip_mrouter_detach(struct ifnet *); void reset_vif(struct vif *); void vif_delete(struct ifnet *); #ifdef RSVP_ISI int ip_mforward(struct mbuf *, struct ifnet *, struct ip_moptions *); int legal_vif_num(int); int ip_rsvp_vif_init(struct socket *, struct mbuf *); int ip_rsvp_vif_done(struct socket *, struct mbuf *); void ip_rsvp_force_done(struct socket *); void rsvp_input(struct mbuf *, int, int); #else int ip_mforward(struct mbuf *, struct ifnet *); #endif /* RSVP_ISI */ #endif /* _KERNEL */ #endif /* _NETINET_IP_MROUTE_H_ */ pimd-2.1.8/include/netinet/0000755000000000000000000000000011700261371012430 5ustar pimd-2.1.8/include/netinet/pim_var.h0000644000000000000000000000773011700261371014245 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _NETINET_PIM_VAR_H_ #define _NETINET_PIM_VAR_H_ /* * Protocol Independent Multicast (PIM), * kernel variables and implementation-specific definitions. * * Written by George Edmond Eddy (Rusty), ISI, February 1998. * Modified by Pavlin Radoslavov, USC/ISI, May 1998, Aug 1999, October 2000. * Modified by Hitoshi Asaeda, WIDE, August 1998. */ /* * PIM statistics kept in the kernel */ struct pimstat { u_quad_t pims_rcv_total_msgs; /* total PIM messages received */ u_quad_t pims_rcv_total_bytes; /* total PIM bytes received */ u_quad_t pims_rcv_tooshort; /* rcvd with too few bytes */ u_quad_t pims_rcv_badsum; /* rcvd with bad checksum */ u_quad_t pims_rcv_badversion; /* rcvd bad PIM version */ u_quad_t pims_rcv_registers_msgs; /* rcvd regs. msgs (data only) */ u_quad_t pims_rcv_registers_bytes; /* rcvd regs. bytes (data only) */ u_quad_t pims_rcv_registers_wrongiif; /* rcvd regs. on wrong iif */ u_quad_t pims_rcv_badregisters; /* rcvd invalid registers */ u_quad_t pims_snd_registers_msgs; /* sent regs. msgs (data only) */ u_quad_t pims_snd_registers_bytes; /* sent regs. bytes (data only) */ }; #if (defined(KERNEL)) || (defined(_KERNEL)) extern struct pimstat pimstat; #if defined(NetBSD) || defined(__OpenBSD__) void pim_input(struct mbuf *, ...); #elif (defined(__FreeBSD__) && (__FreeBSD_version >= 400000)) || defined(__FreeBSD_kernel__) void pim_input(struct mbuf *, int, int); #else void pim_input(struct mbuf *, int); #endif /* ! (NetBSD || OpenBSD) */ #endif /* KERNEL */ /* * Names for PIM sysctl objects */ #if (defined(__FreeBSD__)) || (defined(NetBSD)) || defined(__OpenBSD__) || (defined(__bsdi__)) #define PIMCTL_STATS 1 /* statistics (read-only) */ #define PIMCTL_MAXID 2 #define PIMCTL_NAMES { \ { 0, 0 }, \ { "stats", CTLTYPE_STRUCT }, \ } #endif /* FreeBSD || NetBSD || OpenBSD || bsdi */ #if (defined(__FreeBSD__) && (__FreeBSD_version >= 400000)) || defined(__FreeBSD_kernel__) #if ((defined(KERNEL)) || (defined(_KERNEL))) #if defined(SYSCTL_DECL) SYSCTL_DECL(_net_inet_pim); #endif /* SYSCTL_DECL */ #endif /* KERNEL */ #endif /* FreeBSD >= 4.0 */ #if (defined(NetBSD) || defined(__OpenBSD__) || defined(__bsdi__)) #define PIMCTL_VARS { \ 0, \ 0, \ } int pim_sysctl(int *, u_int, void *, size_t *, void *, size_t); #endif /* NetBSD || OpenBSD || bsdi */ #endif /* _NETINET_PIM_VAR_H_ */ pimd-2.1.8/include/netinet/pim.h0000644000000000000000000001026111700261371013366 0ustar /* * Copyright (c) 1996-2000 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _NETINET_PIM_H_ #define _NETINET_PIM_H_ /* * Protocol Independent Multicast (PIM) definitions. * RFC 2362, June 1998. * * Written by Ahmed Helmy, USC/SGI, July 1996. * Modified by George Edmond Eddy (Rusty), ISI, February 1998. * Modified by Pavlin Radoslavov, USC/ISI, May 1998, October 2000. */ #ifndef _PIM_VT #ifndef BYTE_ORDER # error BYTE_ORDER is not defined! #endif #if (BYTE_ORDER != BIG_ENDIAN) && (BYTE_ORDER != LITTLE_ENDIAN) # error BYTE_ORDER must be defined to either BIG_ENDIAN or LITTLE_ENDIAN #endif #endif /* ! _PIM_VT */ /* * PIM packet header */ struct pim { #ifdef _PIM_VT uint8_t pim_vt; /* PIM version and message type */ #else /* ! _PIM_VT */ #if BYTE_ORDER == BIG_ENDIAN u_int pim_vers:4, /* PIM protocol version */ pim_type:4; /* PIM message type */ #endif #if BYTE_ORDER == LITTLE_ENDIAN u_int pim_type:4, /* PIM message type */ pim_vers:4; /* PIM protocol version */ #endif #endif /* ! _PIM_VT */ uint8_t pim_reserved; /* Reserved */ uint16_t pim_cksum; /* IP-style checksum */ }; /* KAME-related name backward compatibility */ #define pim_ver pim_vers #define pim_rsv pim_reserved #ifdef _PIM_VT #define PIM_MAKE_VT(v, t) (0xff & (((v) << 4) | (0x0f & (t)))) #define PIM_VT_V(x) (((x) >> 4) & 0x0f) #define PIM_VT_T(x) ((x) & 0x0f) #endif /* _PIM_VT */ #define PIM_VERSION 2 #define PIM_MINLEN 8 /* PIM message min. length */ #define PIM_REG_MINLEN (PIM_MINLEN+20) /* PIM Register hdr + inner IPv4 hdr */ #define PIM6_REG_MINLEN (PIM_MINLEN+40) /* PIM Register hdr + inner IPv6 hdr */ /* * PIM message types */ #define PIM_HELLO 0x0 /* PIM-SM and PIM-DM */ #define PIM_REGISTER 0x1 /* PIM-SM only */ #define PIM_REGISTER_STOP 0x2 /* PIM-SM only */ #define PIM_JOIN_PRUNE 0x3 /* PIM-SM and PIM-DM */ #define PIM_BOOTSTRAP 0x4 /* PIM-SM only */ #define PIM_ASSERT 0x5 /* PIM-SM and PIM-DM */ #define PIM_GRAFT 0x6 /* PIM-DM only */ #define PIM_GRAFT_ACK 0x7 /* PIM-DM only */ #define PIM_CAND_RP_ADV 0x8 /* PIM-SM only */ #define PIM_ALL_DF_ELECTION 0xa /* Bidir-PIM-SM only */ /* * PIM-Register message flags */ #define PIM_BORDER_REGISTER 0x80000000U /* The Border bit (host-order) */ #define PIM_NULL_REGISTER 0x40000000U /* The Null-Register bit (host-order)*/ /* * All-PIM-Routers IPv4 and IPv6 multicast addresses */ #define INADDR_ALLPIM_ROUTERS_GROUP (uint32_t)0xe000000dU /* 224.0.0.13 */ #define IN6ADDR_LINKLOCAL_ALLPIM_ROUTERS "ff02::d" #define IN6ADDR_LINKLOCAL_ALLPIM_ROUTERS_INIT \ {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d }}} #endif /* _NETINET_PIM_H_ */ pimd-2.1.8/include/netbsd/0000755000000000000000000000000011700261371012241 5ustar pimd-2.1.8/include/netbsd/netinet/0000755000000000000000000000000011700261371013707 5ustar pimd-2.1.8/include/netbsd/netinet/in.h0000644000000000000000000004410211700261371014467 0ustar /* $NetBSD: in.h,v 1.86 2009/09/14 10:36:50 degroote Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 */ /* * Constants and structures defined by the internet system, * Per RFC 790, September 1981, and numerous additions. */ #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ #include #ifndef uint8_t typedef __uint8_t uint8_t; #define uint8_t __uint8_t #endif #ifndef uint32_t typedef __uint32_t uint32_t; #define uint32_t __uint32_t #endif #include #ifndef in_addr_t typedef __in_addr_t in_addr_t; #define in_addr_t __in_addr_t #endif #ifndef in_port_t typedef __in_port_t in_port_t; #define in_port_t __in_port_t #endif #ifndef sa_family_t typedef __sa_family_t sa_family_t; #define sa_family_t __sa_family_t #endif /* * Protocols */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group mgmt protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_IPV4 4 /* IP header */ #define IPPROTO_IPIP 4 /* IP inside IP */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ #define IPPROTO_IPV6 41 /* IP6 header */ #define IPPROTO_ROUTING 43 /* IP6 routing header */ #define IPPROTO_FRAGMENT 44 /* IP6 fragmentation header */ #define IPPROTO_RSVP 46 /* resource reservation */ #define IPPROTO_GRE 47 /* GRE encaps RFC 1701 */ #define IPPROTO_ESP 50 /* encap. security payload */ #define IPPROTO_AH 51 /* authentication header */ #define IPPROTO_MOBILE 55 /* IP Mobility RFC 2004 */ #define IPPROTO_IPV6_ICMP 58 /* IPv6 ICMP */ #define IPPROTO_ICMPV6 58 /* ICMP6 */ #define IPPROTO_NONE 59 /* IP6 no next header */ #define IPPROTO_DSTOPTS 60 /* IP6 destination option */ #define IPPROTO_EON 80 /* ISO cnlp */ #define IPPROTO_ETHERIP 97 /* Ethernet-in-IP */ #define IPPROTO_ENCAP 98 /* encapsulation header */ #define IPPROTO_PIM 103 /* Protocol indep. multicast */ #define IPPROTO_IPCOMP 108 /* IP Payload Comp. Protocol */ #define IPPROTO_VRRP 112 /* VRRP RFC 2338 */ #define IPPROTO_CARP 112 /* Common Address Resolution Protocol */ #define IPPROTO_PFSYNC 240 /* PFSYNC */ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 /* last return value of *_input(), meaning "all job for this pkt is done". */ #define IPPROTO_DONE 257 /* sysctl placeholder for (FAST_)IPSEC */ #define CTL_IPPROTO_IPSEC 258 /* * Local port number conventions: * * Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root), * unless a kernel is compiled with IPNOPRIVPORTS defined. * * When a user does a bind(2) or connect(2) with a port number of zero, * a non-conflicting local port address is chosen. * * The default range is IPPORT_ANONMIN to IPPORT_ANONMAX, although * that is settable by sysctl(3); net.inet.ip.anonportmin and * net.inet.ip.anonportmax respectively. * * A user may set the IPPROTO_IP option IP_PORTRANGE to change this * default assignment range. * * The value IP_PORTRANGE_DEFAULT causes the default behavior. * * The value IP_PORTRANGE_HIGH is the same as IP_PORTRANGE_DEFAULT, * and exists only for FreeBSD compatibility purposes. * * The value IP_PORTRANGE_LOW changes the range to the "low" are * that is (by convention) restricted to privileged processes. * This convention is based on "vouchsafe" principles only. * It is only secure if you trust the remote host to restrict these ports. * The range is IPPORT_RESERVEDMIN to IPPORT_RESERVEDMAX. */ #define IPPORT_RESERVED 1024 #define IPPORT_ANONMIN 49152 #define IPPORT_ANONMAX 65535 #define IPPORT_RESERVEDMIN 600 #define IPPORT_RESERVEDMAX (IPPORT_RESERVED-1) /* * Internet address (a structure for historical reasons) */ struct in_addr { in_addr_t s_addr; } __packed; /* * Definitions of bits in internet address integers. * On subnets, the decomposition of addresses to host and net parts * is done according to subnet mask, not the masks here. * * By byte-swapping the constants, we avoid ever having to byte-swap IP * addresses inside the kernel. Unfortunately, user-level programs rely * on these macros not doing byte-swapping. */ #ifdef _KERNEL #define __IPADDR(x) ((uint32_t) htonl((uint32_t)(x))) #else #define __IPADDR(x) ((uint32_t)(x)) #endif #define IN_CLASSA(i) (((uint32_t)(i) & __IPADDR(0x80000000)) == \ __IPADDR(0x00000000)) #define IN_CLASSA_NET __IPADDR(0xff000000) #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST __IPADDR(0x00ffffff) #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((uint32_t)(i) & __IPADDR(0xc0000000)) == \ __IPADDR(0x80000000)) #define IN_CLASSB_NET __IPADDR(0xffff0000) #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST __IPADDR(0x0000ffff) #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((uint32_t)(i) & __IPADDR(0xe0000000)) == \ __IPADDR(0xc0000000)) #define IN_CLASSC_NET __IPADDR(0xffffff00) #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST __IPADDR(0x000000ff) #define IN_CLASSD(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ __IPADDR(0xe0000000)) /* These ones aren't really net and host fields, but routing needn't know. */ #define IN_CLASSD_NET __IPADDR(0xf0000000) #define IN_CLASSD_NSHIFT 28 #define IN_CLASSD_HOST __IPADDR(0x0fffffff) #define IN_MULTICAST(i) IN_CLASSD(i) #define IN_EXPERIMENTAL(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ __IPADDR(0xf0000000)) #define IN_BADCLASS(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ __IPADDR(0xf0000000)) #define IN_LINKLOCAL(i) (((uint32_t)(i) & __IPADDR(0xffff0000)) == \ __IPADDR(0xa9fe0000)) #define IN_PRIVATE(i) ((((uint32_t)(i) & __IPADDR(0xff000000)) == \ __IPADDR(0x0a000000)) || \ (((uint32_t)(i) & __IPADDR(0xfff00000)) == \ __IPADDR(0xac100000)) || \ (((uint32_t)(i) & __IPADDR(0xffff0000)) == \ __IPADDR(0xc0a80000))) #define IN_LOCAL_GROUP(i) (((uint32_t)(i) & __IPADDR(0xffffff00)) == \ __IPADDR(0xe0000000)) #define IN_ANY_LOCAL(i) (IN_LINKLOCAL(i) || IN_LOCAL_GROUP(i)) #define INADDR_ANY __IPADDR(0x00000000) #define INADDR_LOOPBACK __IPADDR(0x7f000001) #define INADDR_BROADCAST __IPADDR(0xffffffff) /* must be masked */ #define INADDR_NONE __IPADDR(0xffffffff) /* -1 return */ #define INADDR_UNSPEC_GROUP __IPADDR(0xe0000000) /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP __IPADDR(0xe0000001) /* 224.0.0.1 */ #define INADDR_ALLRTRS_GROUP __IPADDR(0xe0000002) /* 224.0.0.2 */ #define INADDR_CARP_GROUP __IPADDR(0xe0000012) /* 224.0.0.18 */ #define INADDR_MAX_LOCAL_GROUP __IPADDR(0xe00000ff) /* 224.0.0.255 */ #define IN_LOOPBACKNET 127 /* official! */ /* * Socket address, internet style. */ struct sockaddr_in { uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; __int8_t sin_zero[8]; }; #define INET_ADDRSTRLEN 16 /* * Structure used to describe IP options. * Used to store options internally, to pass them to a process, * or to restore options retrieved earlier. * The ip_dst is used for the first-hop gateway when using a source route * (this gets put into the header proper). */ struct ip_opts { struct in_addr ip_dst; /* first hop, 0 w/o src rt */ #if defined(__cplusplus) __int8_t Ip_opts[40]; /* actually variable in size */ #else __int8_t ip_opts[40]; /* actually variable in size */ #endif }; /* * Options for use with [gs]etsockopt at the IP level. * First word of comment is data type; bool is stored in int. */ #define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ #define IP_HDRINCL 2 /* int; header is included with data */ #define IP_TOS 3 /* int; IP type of service and preced. */ #define IP_TTL 4 /* int; IP time to live */ #define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ #define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ #define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ #define IP_RETOPTS 8 /* ip_opts; set/get IP options */ #define IP_MULTICAST_IF 9 /* in_addr; set/get IP multicast i/f */ #define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ #define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ #define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ #define IP_PORTRANGE 19 /* int; range to use for ephemeral port */ #define IP_RECVIF 20 /* bool; receive reception if w/dgram */ #define IP_ERRORMTU 21 /* int; get MTU of last xmit = EMSGSIZE */ #if 1 /*IPSEC*/ #define IP_IPSEC_POLICY 22 /* struct; get/set security policy */ #endif #define IP_RECVTTL 23 /* bool; receive IP TTL w/dgram */ #define IP_MINTTL 24 /* minimum TTL for packet or drop */ /* * Defaults and limits for options */ #define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ #define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; /* * Argument for IP_PORTRANGE: * - which range to search when port is unspecified at bind() or connect() */ #define IP_PORTRANGE_DEFAULT 0 /* default range */ #define IP_PORTRANGE_HIGH 1 /* same as DEFAULT (FreeBSD compat) */ #define IP_PORTRANGE_LOW 2 /* use privileged range */ #if defined(_NETBSD_SOURCE) /* * Definitions for inet sysctl operations. * * Third level is protocol number. * Fourth level is desired variable within that protocol. */ #define IPPROTO_MAXID (IPPROTO_AH + 1) /* don't list to IPPROTO_MAX */ #define CTL_IPPROTO_NAMES { \ { "ip", CTLTYPE_NODE }, \ { "icmp", CTLTYPE_NODE }, \ { "igmp", CTLTYPE_NODE }, \ { "ggp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { "tcp", CTLTYPE_NODE }, \ { 0, 0 }, \ { "egp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pup", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "udp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "idp", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "ipsec", CTLTYPE_NODE }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { 0, 0 }, \ { "pim", CTLTYPE_NODE }, \ } /* * Names for IP sysctl objects */ #define IPCTL_FORWARDING 1 /* act as router */ #define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ #define IPCTL_DEFTTL 3 /* default TTL */ #ifdef notyet #define IPCTL_DEFMTU 4 /* default MTU */ #endif #define IPCTL_FORWSRCRT 5 /* forward source-routed packets */ #define IPCTL_DIRECTEDBCAST 6 /* default broadcast behavior */ #define IPCTL_ALLOWSRCRT 7 /* allow/drop all source-routed pkts */ #define IPCTL_SUBNETSARELOCAL 8 /* treat subnets as local addresses */ #define IPCTL_MTUDISC 9 /* allow path MTU discovery */ #define IPCTL_ANONPORTMIN 10 /* minimum ephemeral port */ #define IPCTL_ANONPORTMAX 11 /* maximum ephemeral port */ #define IPCTL_MTUDISCTIMEOUT 12 /* allow path MTU discovery */ #define IPCTL_MAXFLOWS 13 /* maximum ip flows allowed */ #define IPCTL_HOSTZEROBROADCAST 14 /* is host zero a broadcast addr? */ #define IPCTL_GIF_TTL 15 /* default TTL for gif encap packet */ #define IPCTL_LOWPORTMIN 16 /* minimum reserved port */ #define IPCTL_LOWPORTMAX 17 /* maximum reserved port */ #define IPCTL_MAXFRAGPACKETS 18 /* max packets reassembly queue */ #define IPCTL_GRE_TTL 19 /* default TTL for gre encap packet */ #define IPCTL_CHECKINTERFACE 20 /* drop pkts in from 'wrong' iface */ #define IPCTL_IFQ 21 /* ipintrq node */ #define IPCTL_RANDOMID 22 /* use random IP ids (if configured) */ #define IPCTL_LOOPBACKCKSUM 23 /* do IP checksum on loopback */ #define IPCTL_STATS 24 /* IP statistics */ #define IPCTL_MAXID 25 #define IPCTL_NAMES { \ { 0, 0 }, \ { "forwarding", CTLTYPE_INT }, \ { "redirect", CTLTYPE_INT }, \ { "ttl", CTLTYPE_INT }, \ { "mtu", CTLTYPE_INT }, \ { "forwsrcrt", CTLTYPE_INT }, \ { "directed-broadcast", CTLTYPE_INT }, \ { "allowsrcrt", CTLTYPE_INT }, \ { "subnetsarelocal", CTLTYPE_INT }, \ { "mtudisc", CTLTYPE_INT }, \ { "anonportmin", CTLTYPE_INT }, \ { "anonportmax", CTLTYPE_INT }, \ { "mtudisctimeout", CTLTYPE_INT }, \ { "maxflows", CTLTYPE_INT }, \ { "hostzerobroadcast", CTLTYPE_INT }, \ { "gifttl", CTLTYPE_INT }, \ { "lowportmin", CTLTYPE_INT }, \ { "lowportmax", CTLTYPE_INT }, \ { "maxfragpackets", CTLTYPE_INT }, \ { "grettl", CTLTYPE_INT }, \ { "checkinterface", CTLTYPE_INT }, \ { "ifq", CTLTYPE_NODE }, \ { "random_id", CTLTYPE_INT }, \ { "do_loopback_cksum", CTLTYPE_INT }, \ { "stats", CTLTYPE_STRUCT }, \ } #endif /* _NETBSD_SOURCE */ /* INET6 stuff */ #define __KAME_NETINET_IN_H_INCLUDED_ #include #undef __KAME_NETINET_IN_H_INCLUDED_ #ifdef _KERNEL /* * in_cksum_phdr: * * Compute significant parts of the IPv4 checksum pseudo-header * for use in a delayed TCP/UDP checksum calculation. * * Args: * * src Source IP address * dst Destination IP address * lenproto htons(proto-hdr-len + proto-number) */ static __inline u_int16_t __unused in_cksum_phdr(u_int32_t src, u_int32_t dst, u_int32_t lenproto) { u_int32_t sum; sum = lenproto + (u_int16_t)(src >> 16) + (u_int16_t)(src /*& 0xffff*/) + (u_int16_t)(dst >> 16) + (u_int16_t)(dst /*& 0xffff*/); sum = (u_int16_t)(sum >> 16) + (u_int16_t)(sum /*& 0xffff*/); if (sum > 0xffff) sum -= 0xffff; return (sum); } /* * in_cksum_addword: * * Add the two 16-bit network-order values, carry, and return. */ static __inline u_int16_t __unused in_cksum_addword(u_int16_t a, u_int16_t b) { u_int32_t sum = a + b; if (sum > 0xffff) sum -= 0xffff; return (sum); } extern struct in_addr zeroin_addr; extern u_char ip_protox[]; extern const struct sockaddr_in in_any; int in_broadcast(struct in_addr, struct ifnet *); int in_canforward(struct in_addr); int cpu_in_cksum(struct mbuf *, int, int, uint32_t); int in_cksum(struct mbuf *, int); int in4_cksum(struct mbuf *, u_int8_t, int, int); void in_delayed_cksum(struct mbuf *); int in_localaddr(struct in_addr); void in_socktrim(struct sockaddr_in *); #define in_hosteq(s,t) ((s).s_addr == (t).s_addr) #define in_nullhost(x) ((x).s_addr == INADDR_ANY) #define satosin(sa) ((struct sockaddr_in *)(sa)) #define satocsin(sa) ((const struct sockaddr_in *)(sa)) #define sintosa(sin) ((struct sockaddr *)(sin)) #define sintocsa(sin) ((const struct sockaddr *)(sin)) #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) int sockaddr_in_cmp(const struct sockaddr *, const struct sockaddr *); const void *sockaddr_in_const_addr(const struct sockaddr *, socklen_t *); void *sockaddr_in_addr(struct sockaddr *, socklen_t *); static inline void sockaddr_in_init1(struct sockaddr_in *sin, const struct in_addr *addr, in_port_t port) { sin->sin_port = port; sin->sin_addr = *addr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); } static inline void sockaddr_in_init(struct sockaddr_in *sin, const struct in_addr *addr, in_port_t port) { sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sockaddr_in_init1(sin, addr, port); } static inline struct sockaddr * sockaddr_in_alloc(const struct in_addr *addr, in_port_t port, int flags) { struct sockaddr *sa; sa = sockaddr_alloc(AF_INET, sizeof(struct sockaddr_in), flags); if (sa == NULL) return NULL; sockaddr_in_init1(satosin(sa), addr, port); return sa; } #endif /* _KERNEL */ #endif /* !_NETINET_IN_H_ */ pimd-2.1.8/include/netbsd/netinet/ip_mroute.h0000644000000000000000000003134711700261371016073 0ustar /* $NetBSD: ip_mroute.h,v 1.31 2008/08/07 06:20:14 cegger Exp $ */ #ifndef _NETINET_IP_MROUTE_H_ #define _NETINET_IP_MROUTE_H_ /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * Modified by Ahmed Helmy, SGI, June 1996. * Modified by Pavlin Radoslavov, ICSI, October 2002. * * MROUTING Revision: 1.2 * and PIM-SMv2 and PIM-DM support, advanced API support, * bandwidth metering and signaling. */ #include #include #ifdef _KERNEL struct sockopt; /* from */ #endif /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert processing */ #define MRT_PIM MRT_ASSERT /* enable PIM processing */ #define MRT_API_SUPPORT 109 /* supported MRT API */ #define MRT_API_CONFIG 110 /* config MRT API */ #define MRT_ADD_BW_UPCALL 111 /* create bandwidth monitor */ #define MRT_DEL_BW_UPCALL 112 /* delete bandwidth monitor */ /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_int32_t vifbitmap_t; typedef u_int16_t vifi_t; /* type of a vif index */ #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_SETALL(m) ((m) = 0xffffffff) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) #define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ #define VIFF_SRCRT 0x2 /* tunnel uses IP src routing */ #define VIFF_REGISTER 0x4 /* used for PIM Register encap/decap */ /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_int8_t vifc_flags; /* VIFF_ flags defined below */ u_int8_t vifc_threshold; /* min ttl required to forward on vif */ u_int32_t vifc_rate_limit; /* max rate */ struct in_addr vifc_lcl_addr;/* local interface address */ struct in_addr vifc_rmt_addr;/* remote address (tunnels only) */ }; /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC. * XXX if you change this, make sure to change struct mfcctl2 as well. */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated */ vifi_t mfcc_parent; /* incoming vif */ u_int8_t mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ }; /* * The new argument structure for MRT_ADD_MFC and MRT_DEL_MFC overlays * and extends the old struct mfcctl. */ struct mfcctl2 { /* the mfcctl fields */ struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_int8_t mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ /* extension fields */ u_int8_t mfcc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfcc_rp; /* the RP address */ }; /* * The advanced-API flags. * * The MRT_MFC_FLAGS_XXX API flags are also used as flags * for the mfcc_flags field. */ #define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 << 0) /* disable WRONGVIF signals */ #define MRT_MFC_FLAGS_BORDER_VIF (1 << 1) /* border vif */ #define MRT_MFC_RP (1 << 8) /* enable RP address */ #define MRT_MFC_BW_UPCALL (1 << 9) /* enable bw upcalls */ #define MRT_MFC_FLAGS_ALL (MRT_MFC_FLAGS_DISABLE_WRONGVIF | \ MRT_MFC_FLAGS_BORDER_VIF) #define MRT_API_FLAGS_ALL (MRT_MFC_FLAGS_ALL | \ MRT_MFC_RP | \ MRT_MFC_BW_UPCALL) /* * Structure for installing or delivering an upcall if the * measured bandwidth is above or below a threshold. * * User programs (e.g. daemons) may have a need to know when the * bandwidth used by some data flow is above or below some threshold. * This interface allows the userland to specify the threshold (in * bytes and/or packets) and the measurement interval. Flows are * all packet with the same source and destination IP address. * At the moment the code is only used for multicast destinations * but there is nothing that prevents its use for unicast. * * The measurement interval cannot be shorter than some Tmin (currently, 3s). * The threshold is set in packets and/or bytes per_interval. * * Measurement works as follows: * * For >= measurements: * The first packet marks the start of a measurement interval. * During an interval we count packets and bytes, and when we * pass the threshold we deliver an upcall and we are done. * The first packet after the end of the interval resets the * count and restarts the measurement. * * For <= measurement: * We start a timer to fire at the end of the interval, and * then for each incoming packet we count packets and bytes. * When the timer fires, we compare the value with the threshold, * schedule an upcall if we are below, and restart the measurement * (reschedule timer and zero counters). */ struct bw_data { struct timeval b_time; u_int64_t b_packets; u_int64_t b_bytes; }; struct bw_upcall { struct in_addr bu_src; /* source address */ struct in_addr bu_dst; /* destination address */ u_int32_t bu_flags; /* misc flags (see below) */ #define BW_UPCALL_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_UPCALL_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_UPCALL_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_UPCALL_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_UPCALL_DELETE_ALL (1 << 4) /* delete all upcalls for s,d*/ struct bw_data bu_threshold; /* the bw threshold */ struct bw_data bu_measured; /* the measured bw */ }; /* max. number of upcalls to deliver together */ #define BW_UPCALLS_MAX 128 /* min. threshold time interval for bandwidth measurement */ #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3 #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0 /* * Argument structure used by mrouted to get src-grp pkt counts. */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts. */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* input packet count on vif */ u_long ocount; /* output packet count on vif */ u_long ibytes; /* input byte count on vif */ u_long obytes; /* output byte count on vif */ }; /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to mrouted */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; #ifdef _KERNEL /* * The kernel's virtual-interface structure. */ struct encaptab; struct vif { struct mbuf *tbf_q, **tbf_t; /* packet queue */ struct timeval tbf_last_pkt_t; /* arr. time of last pkt */ u_int32_t tbf_n_tok; /* no of tokens in bucket */ u_int32_t tbf_q_len; /* length of queue at this vif */ u_int32_t tbf_max_q_len; /* max. queue length */ u_int8_t v_flags; /* VIFF_ flags defined above */ u_int8_t v_threshold; /* min ttl required to forward on vif */ u_int32_t v_rate_limit; /* max rate */ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* cached route if this is a tunnel */ callout_t v_repq_ch; /* for tbf_reprocess_q() */ #ifdef RSVP_ISI int v_rsvp_on; /* # RSVP listening on this vif */ struct socket *v_rsvpd; /* # RSVPD daemon */ #endif /* RSVP_ISI */ const struct encaptab *v_encap_cookie; }; /* * The kernel's multicast forwarding cache entry structure. * (A field for the type of service (mfc_tos) is to be added * at a future point.) */ struct mfc { LIST_ENTRY(mfc) mfc_hash; struct in_addr mfc_origin; /* ip origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated */ vifi_t mfc_parent; /* incoming vif */ u_int8_t mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert */ struct rtdetq *mfc_stall; /* pkts waiting for route */ u_int8_t mfc_flags[MAXVIFS]; /* the MRT_MFC_FLAGS_* flags */ struct in_addr mfc_rp; /* the RP address */ struct bw_meter *mfc_bw_meter; /* list of bandwidth meters */ }; /* * Structure used to communicate from kernel to multicast router. * (Note the convenient similarity to an IP packet.) */ struct igmpmsg { u_int32_t unused1; u_int32_t unused2; u_int8_t im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 /* no MFC in the kernel */ #define IGMPMSG_WRONGVIF 2 /* packet came from wrong interface */ #define IGMPMSG_WHOLEPKT 3 /* PIM pkt for user level encap. */ #define IGMPMSG_BW_UPCALL 4 /* BW monitoring upcall */ u_int8_t im_mbz; /* must be zero */ u_int8_t im_vif; /* vif rec'd on */ u_int8_t unused3; struct in_addr im_src, im_dst; } __packed; /* * Argument structure used for pkt info. while upcall is made. */ struct rtdetq { struct mbuf *m; /* a copy of the packet */ struct ifnet *ifp; /* interface pkt came in on */ #ifdef UPCALL_TIMING struct timeval t; /* timestamp */ #endif /* UPCALL_TIMING */ struct rtdetq *next; }; #define MFCTBLSIZ 256 #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ /* * Token bucket filter code */ #define MAX_BKT_SIZE 10000 /* 10K bytes size */ #define MAXQSIZE 10 /* max. no of pkts in token queue */ /* * Structure for measuring the bandwidth and sending an upcall if the * measured bandwidth is above or below a threshold. */ struct bw_meter { struct bw_meter *bm_mfc_next; /* next bw meter (same mfc) */ struct bw_meter *bm_time_next; /* next bw meter (same time) */ uint32_t bm_time_hash; /* the time hash value */ struct mfc *bm_mfc; /* the corresponding mfc */ uint32_t bm_flags; /* misc flags (see below) */ #define BW_METER_UNIT_PACKETS (1 << 0) /* threshold (in packets) */ #define BW_METER_UNIT_BYTES (1 << 1) /* threshold (in bytes) */ #define BW_METER_GEQ (1 << 2) /* upcall if bw >= threshold */ #define BW_METER_LEQ (1 << 3) /* upcall if bw <= threshold */ #define BW_METER_USER_FLAGS (BW_METER_UNIT_PACKETS | \ BW_METER_UNIT_BYTES | \ BW_METER_GEQ | \ BW_METER_LEQ) #define BW_METER_UPCALL_DELIVERED (1 << 24) /* upcall was delivered */ struct bw_data bm_threshold; /* the upcall threshold */ struct bw_data bm_measured; /* the measured bw */ struct timeval bm_start_time; /* abs. time */ }; int ip_mrouter_set(struct socket *, struct sockopt *); int ip_mrouter_get(struct socket *, struct sockopt *); int mrt_ioctl(struct socket *, u_long, void *); int ip_mrouter_done(void); void ip_mrouter_detach(struct ifnet *); void reset_vif(struct vif *); #ifdef RSVP_ISI int ip_mforward(struct mbuf *, struct ifnet *, struct ip_moptions *); int legal_vif_num(int); int ip_rsvp_vif_init(struct socket *, struct mbuf *); int ip_rsvp_vif_done(struct socket *, struct mbuf *); void ip_rsvp_force_done(struct socket *); void rsvp_input(struct mbuf *, int, int); #else int ip_mforward(struct mbuf *, struct ifnet *); #endif #endif /* _KERNEL */ #endif /* !_NETINET_IP_MROUTE_H_ */ pimd-2.1.8/include/sunos-cc/0000755000000000000000000000000011700261371012514 5ustar pimd-2.1.8/include/sunos-cc/sys/0000755000000000000000000000000011700261371013332 5ustar pimd-2.1.8/include/sunos-cc/sys/sockio.h0000644000000000000000000001050011700261371014766 0ustar /* @(#)sockio.h 1.7 88/12/06 SMI; from UCB ioctl.h 7.1 6/4/86 */ /* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ /* * General socket ioctl definitions. */ #ifndef _sys_sockio_h #define _sys_sockio_h #include /* socket i/o controls */ #define SIOCSHIWAT _IOW(s, 0, int) /* set high watermark */ #define SIOCGHIWAT _IOR(s, 1, int) /* get high watermark */ #define SIOCSLOWAT _IOW(s, 2, int) /* set low watermark */ #define SIOCGLOWAT _IOR(s, 3, int) /* get low watermark */ #define SIOCATMARK _IOR(s, 7, int) /* at oob mark? */ #define SIOCSPGRP _IOW(s, 8, int) /* set process group */ #define SIOCGPGRP _IOR(s, 9, int) /* get process group */ #define SIOCADDRT _IOW(r, 10, struct rtentry) /* add route */ #define SIOCDELRT _IOW(r, 11, struct rtentry) /* delete route */ #define SIOCSETRTINFO _IOWR(r, 12, struct fullrtentry) /* change aux info */ #define SIOCGETRTINFO _IOWR(r, 13, struct fullrtentry) /* read aux info */ #define SIOCGETVIFCNT _IOWR(r, 20, struct sioc_vif_req)/* get vif pkt cnt */ #define SIOCGETSGCNT _IOWR(r, 21, struct sioc_sg_req) /* get s,g pkt cnt */ /* AH 96/9/23 added GETRPF for PIM support */ #define SIOCGETRPF _IOWR(r, 22, struct rpfctl) /* get rpf info */ #ifdef RSVP_ISI #define SIOCGETVIFINF _IOWR(r, 15, struct vif_conf) /* read m/c vifs */ #endif RSVP_ISI #define SIOCSIFADDR _IOW(i, 12, struct ifreq) /* set ifnet address */ #define SIOCGIFADDR _IOWR(i,13, struct ifreq) /* get ifnet address */ #define SIOCSIFDSTADDR _IOW(i, 14, struct ifreq) /* set p-p address */ #define SIOCGIFDSTADDR _IOWR(i,15, struct ifreq) /* get p-p address */ #define SIOCSIFFLAGS _IOW(i, 16, struct ifreq) /* set ifnet flags */ #define SIOCGIFFLAGS _IOWR(i,17, struct ifreq) /* get ifnet flags */ #define SIOCSIFMEM _IOW(i, 18, struct ifreq) /* set interface mem */ #define SIOCGIFMEM _IOWR(i,19, struct ifreq) /* get interface mem */ #define SIOCGIFCONF _IOWR(i,20, struct ifconf) /* get ifnet list */ #define SIOCSIFMTU _IOW(i, 21, struct ifreq) /* set if_mtu */ #define SIOCGIFMTU _IOWR(i,22, struct ifreq) /* get if_mtu */ /* from 4.3BSD */ #define SIOCGIFBRDADDR _IOWR(i,23, struct ifreq) /* get broadcast addr */ #define SIOCSIFBRDADDR _IOW(i,24, struct ifreq) /* set broadcast addr */ #define SIOCGIFNETMASK _IOWR(i,25, struct ifreq) /* get net addr mask */ #define SIOCSIFNETMASK _IOW(i,26, struct ifreq) /* set net addr mask */ #define SIOCGIFMETRIC _IOWR(i,27, struct ifreq) /* get IF metric */ #define SIOCSIFMETRIC _IOW(i,28, struct ifreq) /* set IF metric */ #define SIOCSARP _IOW(i, 30, struct arpreq) /* set arp entry */ #define SIOCGARP _IOWR(i,31, struct arpreq) /* get arp entry */ #define SIOCDARP _IOW(i, 32, struct arpreq) /* delete arp entry */ #define SIOCUPPER _IOW(i, 40, struct ifreq) /* attach upper layer */ #define SIOCLOWER _IOW(i, 41, struct ifreq) /* attach lower layer */ #define SIOCSETSYNC _IOW(i, 44, struct ifreq) /* set syncmode */ #define SIOCGETSYNC _IOWR(i, 45, struct ifreq) /* get syncmode */ #define SIOCSSDSTATS _IOWR(i, 46, struct ifreq) /* sync data stats */ #define SIOCSSESTATS _IOWR(i, 47, struct ifreq) /* sync error stats */ #define SIOCSPROMISC _IOW(i, 48, int) /* request promisc mode on/off */ #define SIOCADDMULTI _IOW(i, 49, struct ifreq) /* set m/c address */ #define SIOCDELMULTI _IOW(i, 50, struct ifreq) /* clr m/c address */ /* FDDI controls */ #define SIOCFDRESET _IOW(i, 51, struct ifreq) /* Reset FDDI */ #define SIOCFDSLEEP _IOW(i, 52, struct ifreq) /* Sleep until next dnld req */ #define SIOCSTRTFMWAR _IOW(i, 53, struct ifreq) /* Start FW at an addr */ #define SIOCLDNSTRTFW _IOW(i, 54, struct ifreq) /* Load the shared memory */ #define SIOCGETFDSTAT _IOW(i, 55, struct ifreq) /* Get FDDI stats */ #define SIOCFDNMIINT _IOW(i, 56, struct ifreq) /* NMI to fddi */ #define SIOCFDEXUSER _IOW(i, 57, struct ifreq) /* Exec in user mode */ #define SIOCFDGNETMAP _IOW(i, 58, struct ifreq) /* Get a netmap entry */ #define SIOCFDGIOCTL _IOW(i, 59, struct ifreq) /* Generic ioctl for fddi */ /* protocol i/o controls */ #define SIOCSNIT _IOW(p, 0, struct nit_ioc) /* set nit modes */ #define SIOCGNIT _IOWR(p, 1, struct nit_ioc) /* get nit modes */ #endif /*!_sys_sockio_h*/ pimd-2.1.8/include/sunos-cc/netinet/0000755000000000000000000000000011700261371014162 5ustar pimd-2.1.8/include/sunos-cc/netinet/in.h0000644000000000000000000001562511700261371014752 0ustar /* @(#)in.h 1.19 90/07/27 SMI; from UCB 7.5 2/22/88 */ /* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* * Constants and structures defined by the internet system, * Per RFC 790, September 1981. */ #ifndef _netinet_in_h #define _netinet_in_h /* * Protocols */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group control protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_IPIP 4 /* IP inside IP */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_HELLO 63 /* "hello" routing protocol */ #define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */ #define IPPROTO_RSVP 46 /* resource reservation proto*/ #define IPPROTO_PIM 103 /* Protocol Independent Mcast*/ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 /* * Port/socket numbers: network standard functions */ #define IPPORT_ECHO 7 #define IPPORT_DISCARD 9 #define IPPORT_SYSTAT 11 #define IPPORT_DAYTIME 13 #define IPPORT_NETSTAT 15 #define IPPORT_FTP 21 #define IPPORT_TELNET 23 #define IPPORT_SMTP 25 #define IPPORT_TIMESERVER 37 #define IPPORT_NAMESERVER 42 #define IPPORT_WHOIS 43 #define IPPORT_MTP 57 /* * Port/socket numbers: host specific functions */ #define IPPORT_TFTP 69 #define IPPORT_RJE 77 #define IPPORT_FINGER 79 #define IPPORT_TTYLINK 87 #define IPPORT_SUPDUP 95 /* * UNIX TCP sockets */ #define IPPORT_EXECSERVER 512 #define IPPORT_LOGINSERVER 513 #define IPPORT_CMDSERVER 514 #define IPPORT_EFSSERVER 520 /* * UNIX UDP sockets */ #define IPPORT_BIFFUDP 512 #define IPPORT_WHOSERVER 513 #define IPPORT_ROUTESERVER 520 /* 520+1 also used */ /* * Ports < IPPORT_RESERVED are reserved for * privileged processes (e.g. root). * Ports > IPPORT_USERRESERVED are reserved * for servers, not necessarily privileged. */ #define IPPORT_RESERVED 1024 #define IPPORT_USERRESERVED 5000 /* * Link numbers */ #define IMPLINK_IP 155 #define IMPLINK_LOWEXPER 156 #define IMPLINK_HIGHEXPER 158 /* * Internet address * This definition contains obsolete fields for compatibility * with SunOS 3.x and 4.2bsd. The presence of subnets renders * divisions into fixed fields misleading at best. New code * should use only the s_addr field. */ struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; #define s_addr S_un.S_addr /* should be used for all code */ #define s_host S_un.S_un_b.s_b2 /* OBSOLETE: host on imp */ #define s_net S_un.S_un_b.s_b1 /* OBSOLETE: network */ #define s_imp S_un.S_un_w.s_w2 /* OBSOLETE: imp */ #define s_impno S_un.S_un_b.s_b4 /* OBSOLETE: imp # */ #define s_lh S_un.S_un_b.s_b3 /* OBSOLETE: logical host */ }; /* * Definitions of bits in internet address integers. * On subnets, the decomposition of addresses to host and net parts * is done according to subnet mask, not the masks here. */ #define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST 0x00ffffff #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST 0x0000ffff #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST 0x000000ff #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) #define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ #define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ #define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ #define IN_MULTICAST(i) IN_CLASSD(i) #define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) #define INADDR_ANY (u_long)0x00000000 #define INADDR_LOOPBACK (u_long)0x7F000001 #define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */ #define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */ #define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */ #define IN_LOOPBACKNET 127 /* official! */ /* * Define a macro to stuff the loopback address into an Internet address */ #define IN_SET_LOOPBACK_ADDR(a) {(a)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); \ (a)->sin_family = AF_INET;} /* * Socket address, internet style. */ struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; /* * Options for use with [gs]etsockopt at the IP level. */ #define IP_OPTIONS 1 /* set/get IP per-packet options */ #define IP_MULTICAST_IF 2 /* set/get IP multicast interface */ #define IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */ #define IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 5 /* add an IP group membership */ #define IP_DROP_MEMBERSHIP 6 /* drop an IP group membership */ #define IP_MULTICAST_VIF 7 /* set/get IP mcast vir. interface */ #define IP_RSVP_ON 8 /* set rsvp var. in kernel */ #define IP_RSVP_OFF 9 /* unset rsvp var in kernel */ #define IP_RSVP_VIF_ON 10 /* set rsvp per-vif socket */ #define IP_RSVP_VIF_OFF 11 /* unset rsvp per-vif socket */ #define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ #define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; #if !defined(vax) && !defined(ntohl) && !defined(i386) /* * Macros for number representation conversion. */ #define ntohl(x) (x) #define ntohs(x) (x) #define htonl(x) (x) #define htons(x) (x) #endif #if !defined(ntohl) && (defined(vax) || defined(i386)) u_short ntohs(), htons(); u_long ntohl(), htonl(); #endif #ifdef KERNEL extern struct domain inetdomain; extern struct protosw inetsw[]; struct in_addr in_makeaddr(); u_long in_netof(), in_lnaof(); #endif #endif /*!_netinet_in_h*/ pimd-2.1.8/include/sunos-cc/netinet/ip_mroute.h0000644000000000000000000002046711700261371016347 0ustar /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * Modified by Ahmed Helmy, USC, September 1996. * * MROUTING $Revision: 3.5 $ */ /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert (wrong iif) processing */ #if BSD >= 199103 #define GET_TIME(t) microtime(&t) #elif defined(sun) #define GET_TIME(t) uniqtime(&t) #else #define GET_TIME(t) ((t) = time) #endif /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_long vifbitmap_t; typedef u_short vifi_t; /* type of a vif index */ #define ALL_VIFS (vifi_t)-1 #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_char vifc_flags; /* VIFF_ flags defined below */ u_char vifc_threshold; /* min ttl required to forward on vif*/ u_int vifc_rate_limit; /* max rate */ struct in_addr vifc_lcl_addr; /* local interface address */ struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */ }; #define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ #define VIFF_SRCRT 0x2 /* tunnel uses IP src routing */ #define VIFF_REGISTER 0x4 /* vif used for register en/decap */ #ifdef PIM_REG_KERNEL_ENCAP #define VIFF_REGISTER_KERNEL_ENCAP 0x8 /* vif register with kernel encap */ #endif /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC * (mfcc_tos to be added at a future point) */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfcc_rp_addr; /* The RP address for encap. */ #endif }; /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to mrouted */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; /* * Argument structure used by mrouted to get src-grp pkt counts */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* Input packet count on vif */ u_long ocount; /* Output packet count on vif */ u_long ibytes; /* Input byte count on vif */ u_long obytes; /* Output byte count on vif */ }; #ifdef KERNEL /* * Argument structure used by PIM to get the RPF neighbor and IIF info * for a given source, from the unicast routing tables. * Maybe be substituted by routing sockets for the supporting systems */ struct rpfctl { struct in_addr source; /* the source for which we want iif and rpfnbr */ struct in_addr rpfneighbor;/* next hop towards the source */ vifi_t iif;/* the incoming interface to reach the next hop */ }; /* * The kernel's virtual-interface structure. */ struct vif { u_char v_flags; /* VIFF_ flags defined above */ u_char v_threshold; /* min ttl required to forward on vif*/ u_int v_rate_limit; /* max rate */ struct tbf *v_tbf; /* token bucket structure at intf. */ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* Cached route if this is a tunnel */ #ifdef RSVP_ISI u_int v_rsvp_on; /* # RSVP listening on this vif */ struct socket *v_rsvpd; /* # RSVPD daemon */ #endif /* RSVP_ISI */ }; /* * The kernel's multicast forwarding cache entry structure * (A field for the type of service (mfc_tos) is to be added * at a future point) */ struct mfc { struct in_addr mfc_origin; /* ip origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated*/ vifi_t mfc_parent; /* incoming vif */ u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert*/ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfc_rp_addr; /* The RP address for encap. */ #endif }; #endif /* KERNEL */ /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IP packet */ struct igmpmsg { u_long unused1; u_long unused2; u_char im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 #define IGMPMSG_WRONGVIF 2 #define IGMPMSG_WHOLEPKT 3 /* used for user level encap */ u_char im_mbz; /* must be zero */ u_char im_vif; /* vif rec'd on */ u_char unused3; struct in_addr im_src, im_dst; }; #ifdef KERNEL /* * Argument structure used for pkt info. while upcall is made */ struct rtdetq { struct mbuf *m; /* A copy of the packet */ struct ifnet *ifp; /* Interface pkt came in on */ #ifdef UPCALL_TIMING struct timeval t; /* Timestamp */ #endif /* UPCALL_TIMING */ }; #define MFCTBLSIZ 256 #if (MFCTBLSIZ & (MFCTBLSIZ - 1)) == 0 /* from sys:route.h */ #define MFCHASHMOD(h) ((h) & (MFCTBLSIZ - 1)) #else #define MFCHASHMOD(h) ((h) % MFCTBLSIZ) #endif #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ /* * Token Bucket filter code */ #define MAX_BKT_SIZE 10000 /* 10K bytes size */ #define MAXQSIZE 10 /* max # of pkts in queue */ /* * queue structure at each vif */ struct pkt_queue { u_long pkt_len; /* length of packet in queue */ struct mbuf *pkt_m; /* pointer to packet mbuf */ struct ip *pkt_ip; /* pointer to ip header */ }; /* * the token bucket filter at each vif */ struct tbf { u_long last_pkt_t; /* arr. time of last pkt */ u_long n_tok; /* no of tokens in bucket */ u_long q_len; /* length of queue at this vif */ }; #endif /* KERNEL */ pimd-2.1.8/include/sunos-cc/netinet/igmp.h0000644000000000000000000000370611700261371015275 0ustar /* * Internet Group Management Protocol (IGMP) definitions. * * Written by Steve Deering, Stanford, May 1988. * * MULTICAST $Revision: 3.5 $ */ /* * IGMP packet format. */ struct igmp { u_char igmp_type; /* version & type of IGMP message */ u_char igmp_code; /* code for routing sub-msgs */ u_short igmp_cksum; /* IP-style checksum */ struct in_addr igmp_group; /* group address being reported */ }; /* (zero for queries) */ #define IGMP_MINLEN 8 /* * Message types, including version number. */ #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* Host membership query */ #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Old membership report */ #define IGMP_DVMRP 0x13 /* DVMRP routing message */ #define IGMP_PIM 0x14 /* PIM routing message */ #define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New membership report */ #define IGMP_HOST_LEAVE_MESSAGE 0x17 /* Leave-group message */ #define IGMP_MTRACE_RESP 0x1e /* traceroute resp. (to sender) */ #define IGMP_MTRACE 0x1f /* mcast traceroute messages */ #define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ /* query (in seconds) */ #define IGMP_TIMER_SCALE 10 /* denotes that the igmp->timer filed */ /* specifies time in 10th of seconds */ /* * States for the IGMPv2 state table */ #define IGMP_DELAYING_MEMBER 1 #define IGMP_IDLE_MEMBER 2 #define IGMP_LAZY_MEMBER 3 #define IGMP_SLEEPING_MEMBER 4 #define IGMP_AWAKENING_MEMBER 5 /* * We must remember whether the querier is an old or a new router. */ #define IGMP_OLD_ROUTER 0 #define IGMP_NEW_ROUTER 1 /* * Revert to new router if we haven't heard from an old router in * this amount of time. */ #define IGMP_AGE_THRESHOLD 540 pimd-2.1.8/include/sunos-gcc/0000755000000000000000000000000011700261371012663 5ustar pimd-2.1.8/include/sunos-gcc/sys/0000755000000000000000000000000011700261371013501 5ustar pimd-2.1.8/include/sunos-gcc/sys/sockio.h0000644000000000000000000001042411700261371015142 0ustar /* @(#)sockio.h 1.7 88/12/06 SMI; from UCB ioctl.h 7.1 6/4/86 */ /* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ /* * General socket ioctl definitions. */ #ifndef _sys_sockio_h #define _sys_sockio_h #include /* socket i/o controls */ #define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ #define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ #define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ #define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ #define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ #define SIOCSPGRP _IOW('s', 8, int) /* set process group */ #define SIOCGPGRP _IOR('s', 9, int) /* get process group */ #define SIOCADDRT _IOW('r', 10, struct rtentry) /* add route */ #define SIOCDELRT _IOW('r', 11, struct rtentry) /* delete route */ #define SIOCGETVIFCNT _IOWR('r', 20, struct sioc_vif_req)/* get vif pkt cnt */ #define SIOCGETSGCNT _IOWR('r', 21, struct sioc_sg_req) /* get s,g pkt cnt */ /* AH 96/9/23 added GETRPF for PIM support */ #define SIOCGETRPF _IOWR('r', 22, struct rpfctl) /* get rpf info */ #ifdef RSVP_ISI #define SIOCGETVIFINF _IOWR('r', 15, struct vif_conf) /* read m/c vifs */ #endif RSVP_ISI #define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */ #define SIOCGIFADDR _IOWR('i',13, struct ifreq) /* get ifnet address */ #define SIOCSIFDSTADDR _IOW('i', 14, struct ifreq) /* set p-p address */ #define SIOCGIFDSTADDR _IOWR('i',15, struct ifreq) /* get p-p address */ #define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */ #define SIOCGIFFLAGS _IOWR('i',17, struct ifreq) /* get ifnet flags */ #define SIOCSIFMEM _IOW('i', 18, struct ifreq) /* set interface mem */ #define SIOCGIFMEM _IOWR('i',19, struct ifreq) /* get interface mem */ #define SIOCGIFCONF _IOWR('i',20, struct ifconf) /* get ifnet list */ #define SIOCSIFMTU _IOW('i', 21, struct ifreq) /* set if_mtu */ #define SIOCGIFMTU _IOWR('i',22, struct ifreq) /* get if_mtu */ /* from 4.3BSD */ #define SIOCGIFBRDADDR _IOWR('i',23, struct ifreq) /* get broadcast addr */ #define SIOCSIFBRDADDR _IOW('i',24, struct ifreq) /* set broadcast addr */ #define SIOCGIFNETMASK _IOWR('i',25, struct ifreq) /* get net addr mask */ #define SIOCSIFNETMASK _IOW('i',26, struct ifreq) /* set net addr mask */ #define SIOCGIFMETRIC _IOWR('i',27, struct ifreq) /* get IF metric */ #define SIOCSIFMETRIC _IOW('i',28, struct ifreq) /* set IF metric */ #define SIOCSARP _IOW('i', 30, struct arpreq) /* set arp entry */ #define SIOCGARP _IOWR('i',31, struct arpreq) /* get arp entry */ #define SIOCDARP _IOW('i', 32, struct arpreq) /* delete arp entry */ #define SIOCUPPER _IOW('i', 40, struct ifreq) /* attach upper layer */ #define SIOCLOWER _IOW('i', 41, struct ifreq) /* attach lower layer */ #define SIOCSETSYNC _IOW('i', 44, struct ifreq) /* set syncmode */ #define SIOCGETSYNC _IOWR('i', 45, struct ifreq) /* get syncmode */ #define SIOCSSDSTATS _IOWR('i', 46, struct ifreq) /* sync data stats */ #define SIOCSSESTATS _IOWR('i', 47, struct ifreq) /* sync error stats */ #define SIOCSPROMISC _IOW('i', 48, int) /* request promisc mode on/off */ #define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* set m/c address */ #define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* clr m/c address */ /* FDDI controls */ #define SIOCFDRESET _IOW('i', 51, struct ifreq) /* Reset FDDI */ #define SIOCFDSLEEP _IOW('i', 52, struct ifreq) /* Sleep until next dnld req */ #define SIOCSTRTFMWAR _IOW('i', 53, struct ifreq) /* Start FW at an addr */ #define SIOCLDNSTRTFW _IOW('i', 54, struct ifreq) /* Load the shared memory */ #define SIOCGETFDSTAT _IOW('i', 55, struct ifreq) /* Get FDDI stats */ #define SIOCFDNMIINT _IOW('i', 56, struct ifreq) /* NMI to fddi */ #define SIOCFDEXUSER _IOW('i', 57, struct ifreq) /* Exec in user mode */ #define SIOCFDGNETMAP _IOW('i', 58, struct ifreq) /* Get a netmap entry */ #define SIOCFDGIOCTL _IOW('i', 59, struct ifreq) /* Generic ioctl for fddi */ /* protocol i/o controls */ #define SIOCSNIT _IOW('p', 0, struct nit_ioc) /* set nit modes */ #define SIOCGNIT _IOWR('p', 1, struct nit_ioc) /* get nit modes */ #endif /*!_sys_sockio_h*/ pimd-2.1.8/include/sunos-gcc/netinet/0000755000000000000000000000000011700261371014331 5ustar pimd-2.1.8/include/sunos-gcc/netinet/in.h0000644000000000000000000001564511700261371015123 0ustar /* @(#)in.h 1.19 90/07/27 SMI; from UCB 7.5 2/22/88 */ /* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* * Constants and structures defined by the internet system, * Per RFC 790, September 1981. */ #ifndef _netinet_in_h #define _netinet_in_h /* * Protocols */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group control protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_IPIP 4 /* IP inside IP */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_EGP 8 /* exterior gateway protocol */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_HELLO 63 /* "hello" routing protocol */ #define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */ #define IPPROTO_RSVP 46 /* resource reservation proto*/ #define IPPROTO_PIM 103 /* Protocol Independent Mcast*/ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 /* * Port/socket numbers: network standard functions */ #define IPPORT_ECHO 7 #define IPPORT_DISCARD 9 #define IPPORT_SYSTAT 11 #define IPPORT_DAYTIME 13 #define IPPORT_NETSTAT 15 #define IPPORT_FTP 21 #define IPPORT_TELNET 23 #define IPPORT_SMTP 25 #define IPPORT_TIMESERVER 37 #define IPPORT_NAMESERVER 42 #define IPPORT_WHOIS 43 #define IPPORT_MTP 57 /* * Port/socket numbers: host specific functions */ #define IPPORT_TFTP 69 #define IPPORT_RJE 77 #define IPPORT_FINGER 79 #define IPPORT_TTYLINK 87 #define IPPORT_SUPDUP 95 /* * UNIX TCP sockets */ #define IPPORT_EXECSERVER 512 #define IPPORT_LOGINSERVER 513 #define IPPORT_CMDSERVER 514 #define IPPORT_EFSSERVER 520 /* * UNIX UDP sockets */ #define IPPORT_BIFFUDP 512 #define IPPORT_WHOSERVER 513 #define IPPORT_ROUTESERVER 520 /* 520+1 also used */ /* * Ports < IPPORT_RESERVED are reserved for * privileged processes (e.g. root). * Ports > IPPORT_USERRESERVED are reserved * for servers, not necessarily privileged. */ #define IPPORT_RESERVED 1024 #define IPPORT_USERRESERVED 5000 /* * Link numbers */ #define IMPLINK_IP 155 #define IMPLINK_LOWEXPER 156 #define IMPLINK_HIGHEXPER 158 /* * Internet address * This definition contains obsolete fields for compatibility * with SunOS 3.x and 4.2bsd. The presence of subnets renders * divisions into fixed fields misleading at best. New code * should use only the s_addr field. */ struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; #define s_addr S_un.S_addr /* should be used for all code */ #define s_host S_un.S_un_b.s_b2 /* OBSOLETE: host on imp */ #define s_net S_un.S_un_b.s_b1 /* OBSOLETE: network */ #define s_imp S_un.S_un_w.s_w2 /* OBSOLETE: imp */ #define s_impno S_un.S_un_b.s_b4 /* OBSOLETE: imp # */ #define s_lh S_un.S_un_b.s_b3 /* OBSOLETE: logical host */ }; /* * Definitions of bits in internet address integers. * On subnets, the decomposition of addresses to host and net parts * is done according to subnet mask, not the masks here. */ #define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0) #define IN_CLASSA_NET 0xff000000 #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST 0x00ffffff #define IN_CLASSA_MAX 128 #define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000) #define IN_CLASSB_NET 0xffff0000 #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST 0x0000ffff #define IN_CLASSB_MAX 65536 #define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000) #define IN_CLASSC_NET 0xffffff00 #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST 0x000000ff #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) #define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ #define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ #define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ #define IN_MULTICAST(i) IN_CLASSD(i) #define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) #define INADDR_ANY (u_long)0x00000000 #define INADDR_LOOPBACK (u_long)0x7F000001 #define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */ #define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */ #define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */ #define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */ #define IN_LOOPBACKNET 127 /* official! */ /* * Define a macro to stuff the loopback address into an Internet address */ #define IN_SET_LOOPBACK_ADDR(a) {(a)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); \ (a)->sin_family = AF_INET;} /* * Socket address, internet style. */ struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; /* * Options for use with [gs]etsockopt at the IP level. */ #define IP_OPTIONS 1 /* set/get IP per-packet options */ #define IP_MULTICAST_IF 2 /* set/get IP multicast interface */ #define IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */ #define IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 5 /* add an IP group membership */ #define IP_DROP_MEMBERSHIP 6 /* drop an IP group membership */ #define IP_MULTICAST_VIF 7 /* set/get IP mcast vir. interface */ #define IP_RSVP_ON 8 /* set rsvp var. in kernel */ #define IP_RSVP_OFF 9 /* unset rsvp var in kernel */ #define IP_RSVP_VIF_ON 10 /* set rsvp per-vif socket */ #define IP_RSVP_VIF_OFF 11 /* unset rsvp per-vif socket */ #define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ #define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ #define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. */ struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ }; #if !defined(__vax__) && !defined(ntohl) && !defined(__i386__) /* * Macros for number representation conversion. */ #define ntohl(x) (x) #define ntohs(x) (x) #define htonl(x) (x) #define htons(x) (x) #endif #if !defined(ntohl) && (defined(__vax__) || defined(__i386__)) u_short ntohs(), htons(); u_long ntohl(), htonl(); #endif #ifdef KERNEL extern struct domain inetdomain; extern struct protosw inetsw[]; struct in_addr in_makeaddr(); u_long in_netof(), in_lnaof(); #endif #endif /*!_netinet_in_h*/ pimd-2.1.8/include/sunos-gcc/netinet/ip_mroute.h0000644000000000000000000002047311700261371016513 0ustar /* * Definitions for IP multicast forwarding. * * Written by David Waitzman, BBN Labs, August 1988. * Modified by Steve Deering, Stanford, February 1989. * Modified by Ajit Thyagarajan, PARC, August 1993. * Modified by Ajit Thyagarajan, PARC, August 1994. * Modified by Ahmed Helmy, USC, September 1996. * * MROUTING $Revision: 3.5 $ */ /* * Multicast Routing set/getsockopt commands. */ #define MRT_INIT 100 /* initialize forwarder */ #define MRT_DONE 101 /* shut down forwarder */ #define MRT_ADD_VIF 102 /* create virtual interface */ #define MRT_DEL_VIF 103 /* delete virtual interface */ #define MRT_ADD_MFC 104 /* insert forwarding cache entry */ #define MRT_DEL_MFC 105 /* delete forwarding cache entry */ #define MRT_VERSION 106 /* get kernel version number */ #define MRT_ASSERT 107 /* enable assert (wrong iif) processing */ #if BSD >= 199103 #define GET_TIME(t) microtime(&t) #elif defined(__sun__) #define GET_TIME(t) uniqtime(&t) #else #define GET_TIME(t) ((t) = time) #endif /* * Types and macros for handling bitmaps with one bit per virtual interface. */ #define MAXVIFS 32 typedef u_long vifbitmap_t; typedef u_short vifi_t; /* type of a vif index */ #define ALL_VIFS (vifi_t)-1 #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) #define VIFM_ISSET(n, m) ((m) & (1 << (n))) #define VIFM_CLRALL(m) ((m) = 0x00000000) #define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) #define VIFM_SAME(m1, m2) ((m1) == (m2)) /* * Argument structure for MRT_ADD_VIF. * (MRT_DEL_VIF takes a single vifi_t argument.) */ struct vifctl { vifi_t vifc_vifi; /* the index of the vif to be added */ u_char vifc_flags; /* VIFF_ flags defined below */ u_char vifc_threshold; /* min ttl required to forward on vif*/ u_int vifc_rate_limit; /* max rate */ struct in_addr vifc_lcl_addr; /* local interface address */ struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */ }; #define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ #define VIFF_SRCRT 0x2 /* tunnel uses IP src routing */ #define VIFF_REGISTER 0x4 /* vif used for register en/decap */ #ifdef PIM_REG_KERNEL_ENCAP #define VIFF_REGISTER_KERNEL_ENCAP 0x8 /* vif register with kernel encap */ #endif /* * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC * (mfcc_tos to be added at a future point) */ struct mfcctl { struct in_addr mfcc_origin; /* ip origin of mcasts */ struct in_addr mfcc_mcastgrp; /* multicast group associated*/ vifi_t mfcc_parent; /* incoming vif */ u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfcc_rp_addr; /* The RP address for encap. */ #endif }; /* * The kernel's multicast routing statistics. */ struct mrtstat { u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ u_long mrts_mfc_misses; /* # forw. cache hash table misses */ u_long mrts_upcalls; /* # calls to mrouted */ u_long mrts_no_route; /* no route for packet's origin */ u_long mrts_bad_tunnel; /* malformed tunnel options */ u_long mrts_cant_tunnel; /* no room for tunnel options */ u_long mrts_wrong_if; /* arrived on wrong interface */ u_long mrts_upq_ovflw; /* upcall Q overflow */ u_long mrts_cache_cleanups; /* # entries with no upcalls */ u_long mrts_drop_sel; /* pkts dropped selectively */ u_long mrts_q_overflow; /* pkts dropped - Q overflow */ u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ }; /* * Argument structure used by mrouted to get src-grp pkt counts */ struct sioc_sg_req { struct in_addr src; struct in_addr grp; u_long pktcnt; u_long bytecnt; u_long wrong_if; }; /* * Argument structure used by mrouted to get vif pkt counts */ struct sioc_vif_req { vifi_t vifi; /* vif number */ u_long icount; /* Input packet count on vif */ u_long ocount; /* Output packet count on vif */ u_long ibytes; /* Input byte count on vif */ u_long obytes; /* Output byte count on vif */ }; #ifdef KERNEL /* * Argument structure used by PIM to get the RPF neighbor and IIF info * for a given source, from the unicast routing tables. * Maybe be substituted by routing sockets for the supporting systems */ struct rpfctl { struct in_addr source; /* the source for which we want iif and rpfnbr */ struct in_addr rpfneighbor;/* next hop towards the source */ vifi_t iif;/* the incoming interface to reach the next hop */ }; /* * The kernel's virtual-interface structure. */ struct vif { u_char v_flags; /* VIFF_ flags defined above */ u_char v_threshold; /* min ttl required to forward on vif*/ u_int v_rate_limit; /* max rate */ struct tbf *v_tbf; /* token bucket structure at intf. */ struct in_addr v_lcl_addr; /* local interface address */ struct in_addr v_rmt_addr; /* remote address (tunnels only) */ struct ifnet *v_ifp; /* pointer to interface */ u_long v_pkt_in; /* # pkts in on interface */ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ struct route v_route; /* Cached route if this is a tunnel */ #ifdef RSVP_ISI u_int v_rsvp_on; /* # RSVP listening on this vif */ struct socket *v_rsvpd; /* # RSVPD daemon */ #endif /* RSVP_ISI */ }; /* * The kernel's multicast forwarding cache entry structure * (A field for the type of service (mfc_tos) is to be added * at a future point) */ struct mfc { struct in_addr mfc_origin; /* ip origin of mcasts */ struct in_addr mfc_mcastgrp; /* multicast group associated*/ vifi_t mfc_parent; /* incoming vif */ u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ u_long mfc_pkt_cnt; /* pkt count for src-grp */ u_long mfc_byte_cnt; /* byte count for src-grp */ u_long mfc_wrong_if; /* wrong if for src-grp */ int mfc_expire; /* time to clean entry up */ struct timeval mfc_last_assert; /* last time I sent an assert*/ #ifdef PIM_REG_KERNEL_ENCAP struct in_addr mfc_rp_addr; /* The RP address for encap. */ #endif }; #endif /* KERNEL */ /* * Struct used to communicate from kernel to multicast router * note the convenient similarity to an IP packet */ struct igmpmsg { u_long unused1; u_long unused2; u_char im_msgtype; /* what type of message */ #define IGMPMSG_NOCACHE 1 #define IGMPMSG_WRONGVIF 2 #define IGMPMSG_WHOLEPKT 3 /* used for user level encap */ u_char im_mbz; /* must be zero */ u_char im_vif; /* vif rec'd on */ u_char unused3; struct in_addr im_src, im_dst; }; #ifdef KERNEL /* * Argument structure used for pkt info. while upcall is made */ struct rtdetq { struct mbuf *m; /* A copy of the packet */ struct ifnet *ifp; /* Interface pkt came in on */ #ifdef UPCALL_TIMING struct timeval t; /* Timestamp */ #endif /* UPCALL_TIMING */ }; #define MFCTBLSIZ 256 #if (MFCTBLSIZ & (MFCTBLSIZ - 1)) == 0 /* from sys:route.h */ #define MFCHASHMOD(h) ((h) & (MFCTBLSIZ - 1)) #else #define MFCHASHMOD(h) ((h) % MFCTBLSIZ) #endif #define MAX_UPQ 4 /* max. no of pkts in upcall Q */ /* * Token Bucket filter code */ #define MAX_BKT_SIZE 10000 /* 10K bytes size */ #define MAXQSIZE 10 /* max # of pkts in queue */ /* * queue structure at each vif */ struct pkt_queue { u_long pkt_len; /* length of packet in queue */ struct mbuf *pkt_m; /* pointer to packet mbuf */ struct ip *pkt_ip; /* pointer to ip header */ }; /* * the token bucket filter at each vif */ struct tbf { u_long last_pkt_t; /* arr. time of last pkt */ u_long n_tok; /* no of tokens in bucket */ u_long q_len; /* length of queue at this vif */ }; #endif /* KERNEL */ pimd-2.1.8/include/sunos-gcc/netinet/igmp.h0000644000000000000000000000370611700261371015444 0ustar /* * Internet Group Management Protocol (IGMP) definitions. * * Written by Steve Deering, Stanford, May 1988. * * MULTICAST $Revision: 3.5 $ */ /* * IGMP packet format. */ struct igmp { u_char igmp_type; /* version & type of IGMP message */ u_char igmp_code; /* code for routing sub-msgs */ u_short igmp_cksum; /* IP-style checksum */ struct in_addr igmp_group; /* group address being reported */ }; /* (zero for queries) */ #define IGMP_MINLEN 8 /* * Message types, including version number. */ #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* Host membership query */ #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Old membership report */ #define IGMP_DVMRP 0x13 /* DVMRP routing message */ #define IGMP_PIM 0x14 /* PIM routing message */ #define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New membership report */ #define IGMP_HOST_LEAVE_MESSAGE 0x17 /* Leave-group message */ #define IGMP_MTRACE_RESP 0x1e /* traceroute resp. (to sender) */ #define IGMP_MTRACE 0x1f /* mcast traceroute messages */ #define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ /* query (in seconds) */ #define IGMP_TIMER_SCALE 10 /* denotes that the igmp->timer filed */ /* specifies time in 10th of seconds */ /* * States for the IGMPv2 state table */ #define IGMP_DELAYING_MEMBER 1 #define IGMP_IDLE_MEMBER 2 #define IGMP_LAZY_MEMBER 3 #define IGMP_SLEEPING_MEMBER 4 #define IGMP_AWAKENING_MEMBER 5 /* * We must remember whether the querier is an old or a new router. */ #define IGMP_OLD_ROUTER 0 #define IGMP_NEW_ROUTER 1 /* * Revert to new router if we haven't heard from an old router in * this amount of time. */ #define IGMP_AGE_THRESHOLD 540 pimd-2.1.8/include/README0000644000000000000000000000161211700261371011642 0ustar This directory contains missing system headers. These files should only be used as a last ditch effort on systems that miss, e.g. netinet/ip_mroute.h, netinet/in.h or similar. Some effort have been made to see to different locations across systems in the file defs.h. In most cases, the use of these files is activated by uncommenting the matching section in config.mk, or adding to the DEFS and INCLUDES. linux/ - For *really* old kernels, possibly pre-2.0. Do NOT include for any recent systems, at all! Only pim.h missing, even on 2.6.32. openbsd/ - For older releases, not needed for releases after, at least, 2003. netbsd/ - For older releases, not needed for releases after, at least, 2003. freebsd/ - For older releases, not needed for releases after, at least, 2003. freebsd2/ - For *really* old FreeBSD 2.x releases. sunos-*/ - For *really* old SunOS/OSF1 based systems. pimd-2.1.8/trace.h0000644000000000000000000001161611700261371010613 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: trace.h,v 1.7 2001/09/10 20:31:37 pavlin Exp $ */ /* * 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. * */ /* * The packet format for a traceroute request. */ struct tr_query { u_int32 tr_src; /* traceroute source */ u_int32 tr_dst; /* traceroute destination */ u_int32 tr_raddr; /* traceroute response address */ #if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) struct { u_int qid : 24; /* traceroute query id */ u_int ttl : 8; /* traceroute response ttl */ } q; #else struct { u_int ttl : 8; /* traceroute response ttl */ u_int qid : 24; /* traceroute query id */ } q; #endif /* BYTE_ORDER */ }; #define tr_rttl q.ttl #define tr_qid q.qid /* * Traceroute response format. A traceroute response has a tr_query at the * beginning, followed by one tr_resp for each hop taken. */ struct tr_resp { u_int32 tr_qarr; /* query arrival time */ u_int32 tr_inaddr; /* incoming interface address */ u_int32 tr_outaddr; /* outgoing interface address */ u_int32 tr_rmtaddr; /* parent address in source tree */ u_int32 tr_vifin; /* input packet count on interface */ u_int32 tr_vifout; /* output packet count on interface */ u_int32 tr_pktcnt; /* total incoming packets for src-grp */ u_char tr_rproto; /* routing protocol deployed on router */ u_char tr_fttl; /* ttl required to forward on outvif */ u_char tr_smask; /* subnet mask for src addr */ u_char tr_rflags; /* forwarding error codes */ }; /* defs within mtrace */ #define QUERY 1 #define RESP 2 #define QLEN sizeof(struct tr_query) #define RLEN sizeof(struct tr_resp) /* fields for tr_rflags (forwarding error codes) */ #define TR_NO_ERR 0 /* No error */ #define TR_WRONG_IF 1 /* traceroute arrived on non-oif */ #define TR_PRUNED 2 /* router has sent a prune upstream */ #define TR_OPRUNED 3 /* stop forw. after request from next hop rtr*/ #define TR_SCOPED 4 /* group adm. scoped at this hop */ #define TR_NO_RTE 5 /* no route for the source */ #define TR_NO_LHR 6 /* not the last-hop router */ #define TR_NO_FWD 7 /* not forwarding for this (S,G). Reason = ? */ #define TR_RP 8 /* I am the RP/Core */ #define TR_IIF 9 /* request arrived on the iif */ #define TR_NO_MULTI 0x0a /* multicast disabled on that interface */ #define TR_NO_SPACE 0x81 /* no space to insert responce data block */ #define TR_OLD_ROUTER 0x82 /* previous hop does not support traceroute */ #define TR_ADMIN_PROHIB 0x83 /* traceroute adm. prohibited */ /* fields for tr_smask */ #define TR_GROUP_ONLY 0x2f /* forwarding solely on group state */ #define TR_SUBNET_COUNT 0x40 /* pkt count for (S,G) is for source network */ /* fields for packets count */ #define TR_CANT_COUNT 0xffffffff /* no count can be reported */ /* fields for tr_rproto (routing protocol) */ #define PROTO_DVMRP 1 #define PROTO_MOSPF 2 #define PROTO_PIM 3 #define PROTO_CBT 4 #define PROTO_PIM_SPECIAL 5 #define PROTO_PIM_STATIC 6 #define PROTO_DVMRP_STATIC 7 #define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv) pimd-2.1.8/inet.c0000644000000000000000000001624411700261371010451 0ustar /* * The mrouted program is covered by the license in the accompanying file * named "LICENSE.mrouted". Use of the mrouted program represents acceptance of * the terms and conditions listed in that file. * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. * * * inet.c,v 3.8.4.1 1997/01/29 19:49:33 fenner Exp */ #define C(x) ((x) & 0xff) #include "defs.h" /* * Exported variables. */ char s1[MAX_INET_BUF_LEN]; /* buffers to hold the string representations */ char s2[MAX_INET_BUF_LEN]; /* of IP addresses, to be passed to inet_fmt() */ char s3[MAX_INET_BUF_LEN]; char s4[MAX_INET_BUF_LEN]; /* * Verify that a given IP address is credible as a host address. * (Without a mask, cannot detect addresses of the form {subnet,0} or * {subnet,-1}.) */ int inet_valid_host(u_int32 naddr) { u_int32 addr; addr = ntohl(naddr); return (!(IN_MULTICAST(addr) || IN_BADCLASS (addr) || (addr & 0xff000000) == 0)); } /* * Verify that a given netmask is plausible; * make sure that it is a series of 1's followed by * a series of 0's with no discontiguous 1's. */ int inet_valid_mask(mask) u_int32 mask; { if (~(((mask & -mask) - 1) | mask) != 0) { /* Mask is not contiguous */ return (FALSE); } return (TRUE); } /* * Verify that a given subnet number and mask pair are credible. * * With CIDR, almost any subnet and mask are credible. mrouted still * can't handle aggregated class A's, so we still check that, but * otherwise the only requirements are that the subnet address is * within the [ABC] range and that the host bits of the subnet * are all 0. */ int inet_valid_subnet(nsubnet, nmask) u_int32 nsubnet, nmask; { register u_int32 subnet, mask; subnet = ntohl(nsubnet); mask = ntohl(nmask); if ((subnet & mask) != subnet) return (FALSE); if (subnet == 0) return (mask == 0); if (IN_CLASSA(subnet)) { if (mask < 0xff000000 || (subnet & 0xff000000) == 0x7f000000 || (subnet & 0xff000000) == 0x00000000) return (FALSE); } else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) { /* Above Class C address space */ return (FALSE); } if (subnet & ~mask) { /* Host bits are set in the subnet */ return (FALSE); } if (!inet_valid_mask(mask)) { /* Netmask is not contiguous */ return (FALSE); } return (TRUE); } /* * Convert an IP address in u_int32 (network) format into a printable string. */ char *inet_fmt(u_int32 addr, char *s, size_t len) { u_char *a; a = (u_char *)&addr; snprintf(s, len, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); return s; } /* * Convert the printable string representation of an IP address into the * u_int32 (network) format. Return 0xffffffff on error. (To detect the * legal address with that value, you must explicitly compare the string * with "255.255.255.255".) * The return value is in network order. */ u_int32 inet_parse(s, n) char *s; int n; { u_int32 a = 0; u_int a0 = 0, a1 = 0, a2 = 0, a3 = 0; int i; char c; i = sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c); if (i < n || i > 4 || a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255) return (0xffffffff); ((u_char *)&a)[0] = a0; ((u_char *)&a)[1] = a1; ((u_char *)&a)[2] = a2; ((u_char *)&a)[3] = a3; return (a); } /* * inet_cksum extracted from: * P I N G . C * * Author - * Mike Muuss * U. S. Army Ballistic Research Laboratory * December, 1983 * Modified at Uc Berkeley * * (ping.c) Status - * Public Domain. Distribution Unlimited. * * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * */ int inet_cksum(addr, len) u_int16 *addr; u_int len; { register int nleft = (int)len; register u_int16 *w = addr; u_int16 answer = 0; register int sum = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *) (&answer) = *(u_char *)w ; sum += answer; } /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } /* * Called by following netname() to create a mask specified network address. */ void trimdomain(cp) char *cp; { static char domain[MAXHOSTNAMELEN + 1]; static int first = 1; char *s; if (first) { first = 0; if (gethostname(domain, MAXHOSTNAMELEN) == 0 && (s = strchr(domain, '.'))) (void) strlcpy(domain, s + 1, sizeof(domain)); else domain[0] = 0; } if (domain[0]) { while ((cp = strchr(cp, '.'))) { if (!strcasecmp(cp + 1, domain)) { *cp = 0; /* hit it */ break; } else { cp++; } } } } static u_long forgemask(a) u_long a; { u_long m; if (IN_CLASSA(a)) m = IN_CLASSA_NET; else if (IN_CLASSB(a)) m = IN_CLASSB_NET; else m = IN_CLASSC_NET; return (m); } static void domask(char *dst, size_t len, u_long addr, u_long mask) { int b, i; if (!mask || (forgemask(addr) == mask)) { *dst = '\0'; return; } i = 0; for (b = 0; b < 32; b++) if (mask & (1 << b)) { int bb; i = b; for (bb = b+1; bb < 32; bb++) if (!(mask & (1 << bb))) { i = -1; /* noncontig */ break; } break; } if (i == -1) snprintf(dst, len, "&0x%lx", mask); else snprintf(dst, len, "/%d", 32 - i); } /* * Return the name of the network whose address is given. * The address is assumed to be that of a net or subnet, not a host. */ char *netname(u_int32 addr, u_int32 mask) { static char line[MAXHOSTNAMELEN + 4]; u_int32 omask; u_int32 i; i = ntohl(addr); omask = mask = ntohl(mask); if ((i & 0xffffff) == 0) snprintf(line, sizeof(line), "%u", C(i >> 24)); else if ((i & 0xffff) == 0) snprintf(line, sizeof(line), "%u.%u", C(i >> 24) , C(i >> 16)); else if ((i & 0xff) == 0) snprintf(line, sizeof(line), "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); else snprintf(line, sizeof(line), "%u.%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8), C(i)); domask(line + strlen(line), sizeof(line) - strlen(line), i, omask); return line; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/RELEASE.NOTES0000644000000000000000000000150611700261371011233 0ustar $Id: RELEASE.NOTES,v 1.3 2000/03/08 09:10:52 pavlin Exp $ * Since pimd cannot reliably get preference and metric info from the kernel a configuration option is provided to specify a preference with which to advertise sources when sending PIM-Assert messages. The phyint command in pimd.conf allows you to specify a default perference for each interface. If no preference is specified, prefs will default to 101, which is high enough that default preferences advertised by either Cisco or Gated routers (both having better information on unicast routes) will will over pimd preferences. Directly connected sources will always be asserted with a preference of 0. * Because unicast routes are obtained from the kernel, only the prefered route is available. * RSRR support is currently rough and completely untested. pimd-2.1.8/pathnames.h0000644000000000000000000000427011700261371011473 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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. * */ #ifndef __PIMD_PATHNAMES_H__ #define __PIMD_PATHNAMES_H__ #include #define _PATH_PIMD_CONF "/etc/pimd.conf" #define _PATH_PIMD_RUNDIR _PATH_VARRUN "pimd" #define _PATH_PIMD_DUMP _PATH_PIMD_RUNDIR "/pimd.dump" #define _PATH_PIMD_CACHE _PATH_PIMD_RUNDIR "/pimd.cache" #endif /* __PIMD_PATHNAMES_H__ */ pimd-2.1.8/kern.c0000644000000000000000000003567511700261371010462 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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 "defs.h" #ifdef RAW_OUTPUT_IS_RAW int curttl = 0; #endif /* * XXX: in *BSD there is only MRT_ASSERT, but in Linux there are * both MRT_ASSERT and MRT_PIM */ #ifndef MRT_PIM #define MRT_PIM MRT_ASSERT #endif /* MRT_PIM */ /* * Open/init the multicast routing in the kernel and sets the * MRT_PIM (aka MRT_ASSERT) flag in the kernel. */ void k_init_pim(int socket) { int v = 1; if (setsockopt(socket, IPPROTO_IP, MRT_INIT, (char *)&v, sizeof(int)) < 0) { if (errno == EADDRINUSE) logit(LOG_ERR, 0, "Another multicast routing application is already running."); else logit(LOG_ERR, errno, "Cannot enable multicast routing in kernel"); } if (setsockopt(socket, IPPROTO_IP, MRT_PIM, (char *)&v, sizeof(int)) < 0) logit(LOG_ERR, errno, "Cannot set PIM flag in kernel"); } /* * Stops the multicast routing in the kernel and resets the * MRT_PIM (aka MRT_ASSERT) flag in the kernel. */ void k_stop_pim(int socket) { int v = 0; if (setsockopt(socket, IPPROTO_IP, MRT_PIM, (char *)&v, sizeof(int)) < 0) logit(LOG_ERR, errno, "Cannot reset PIM flag in kernel"); if (setsockopt(socket, IPPROTO_IP, MRT_DONE, (char *)NULL, 0) < 0) logit(LOG_ERR, errno, "Cannot disable multicast routing in kernel"); } /* * Set the socket sending buffer. `bufsize` is the preferred size, * `minsize` is the smallest acceptable size. */ void k_set_sndbuf(int socket, int bufsize, int minsize) { int delta = bufsize / 2; int iter = 0; /* * Set the socket buffer. If we can't set it as large as we * want, search around to try to find the highest acceptable * value. The highest acceptable value being smaller than * minsize is a fatal error. */ if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize -= delta; while (1) { iter++; if (delta > 1) delta /= 2; if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize -= delta; } else { if (delta < 1024) break; bufsize += delta; } } if (bufsize < minsize) { logit(LOG_ERR, 0, "OS-allowed send buffer size %u < app min %u", bufsize, minsize); /*NOTREACHED*/ } } IF_DEBUG(DEBUG_KERN) { logit(LOG_DEBUG, 0, "Got %d byte send buffer size in %d iterations", bufsize, iter); } } /* * Set the socket receiving buffer. `bufsize` is the preferred size, * `minsize` is the smallest acceptable size. */ void k_set_rcvbuf(int socket, int bufsize, int minsize) { int delta = bufsize / 2; int iter = 0; /* * Set the socket buffer. If we can't set it as large as we * want, search around to try to find the highest acceptable * value. The highest acceptable value being smaller than * minsize is a fatal error. */ if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize -= delta; while (1) { iter++; if (delta > 1) delta /= 2; if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize -= delta; } else { if (delta < 1024) break; bufsize += delta; } } if (bufsize < minsize) { logit(LOG_ERR, 0, "OS-allowed recv buffer size %u < app min %u", bufsize, minsize); /*NOTREACHED*/ } } IF_DEBUG(DEBUG_KERN) { logit(LOG_DEBUG, 0, "Got %d byte recv buffer size in %d iterations", bufsize, iter); } } /* * Set/reset the IP_HDRINCL option. My guess is we don't need it for raw * sockets, but having it here won't hurt. Well, unless you are running * an older version of FreeBSD (older than 2.2.2). If the multicast * raw packet is bigger than 208 bytes, then IP_HDRINCL triggers a bug * in the kernel and "panic". The kernel patch for netinet/ip_raw.c * coming with this distribution fixes it. */ void k_hdr_include(int socket, int bool) { #ifdef IP_HDRINCL if (setsockopt(socket, IPPROTO_IP, IP_HDRINCL, (char *)&bool, sizeof(bool)) < 0) logit(LOG_ERR, errno, "Failed %s IP_HDRINCL on socket %d", ENABLINGSTR(bool), socket); #endif } /* * Set the default TTL for the multicast packets outgoing from this * socket. * TODO: Does it affect the unicast packets? */ void k_set_ttl(int socket __attribute__((unused)), int t) { #ifdef RAW_OUTPUT_IS_RAW curttl = t; #else u_char ttl; ttl = t; if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0) logit(LOG_ERR, errno, "Failed setting IP_MULTICAST_TTL %u on socket %d", ttl, socket); #endif } /* * Set/reset the IP_MULTICAST_LOOP. Set/reset is specified by "flag". */ void k_set_loop(int socket, int flag) { u_char loop; loop = flag; if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0) logit(LOG_ERR, errno, "Failed %s IP_MULTICAST_LOOP on socket %d", ENABLINGSTR(flag), socket); } /* * Set the IP_MULTICAST_IF option on local interface ifa. */ void k_set_if(int socket, u_int32 ifa) { struct in_addr adr; adr.s_addr = ifa; if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) { if (errno == EADDRNOTAVAIL || errno == EINVAL) return; logit(LOG_ERR, errno, "Failed setting IP_MULTICAST_IF option on %s", inet_fmt(adr.s_addr, s1, sizeof(s1))); } } /* * Join a multicast group on virtual interface 'v'. */ void k_join(int socket, u_int32 grp, struct uvif *v) { #ifdef __linux__ struct ip_mreqn mreq; #else struct ip_mreq mreq; #endif /* __linux__ */ #ifdef __linux__ mreq.imr_ifindex = v->uv_ifindex; mreq.imr_address.s_addr = v->uv_lcl_addr; #else mreq.imr_interface.s_addr = v->uv_lcl_addr; #endif /* __linux__ */ mreq.imr_multiaddr.s_addr = grp; if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { #ifdef __linux__ logit(LOG_WARNING, errno, "Cannot join group %s on interface %s (ifindex %d)", inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2)), v->uv_ifindex); #else logit(LOG_WARNING, errno, "Cannot join group %s on interface %s", inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2))); #endif /* __linux__ */ } } /* * Leave a multicast group on virtual interface 'v'. */ void k_leave(int socket, u_int32 grp, struct uvif *v) { #ifdef __linux__ struct ip_mreqn mreq; #else struct ip_mreq mreq; #endif /* __linux__ */ #ifdef __linux__ mreq.imr_ifindex = v->uv_ifindex; mreq.imr_address.s_addr = v->uv_lcl_addr; #else mreq.imr_interface.s_addr = v->uv_lcl_addr; #endif /* __linux__ */ mreq.imr_multiaddr.s_addr = grp; if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { #ifdef __linux__ logit(LOG_WARNING, errno, "Cannot leave group %s on interface %s (ifindex %d)", inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2)), v->uv_ifindex); #else logit(LOG_WARNING, errno, "Cannot leave group %s on interface %s", inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2))); #endif /* __linux__ */ } } /* * Fill struct vifctl using corresponding fields from struct uvif. */ static void uvif_to_vifctl(struct vifctl *vc, struct uvif *v) { /* XXX: we don't support VIFF_TUNNEL; VIFF_SRCRT is obsolete */ vc->vifc_flags = 0; if (v->uv_flags & VIFF_REGISTER) vc->vifc_flags |= VIFF_REGISTER; vc->vifc_threshold = v->uv_threshold; vc->vifc_rate_limit = v->uv_rate_limit; vc->vifc_lcl_addr.s_addr = v->uv_lcl_addr; vc->vifc_rmt_addr.s_addr = v->uv_rmt_addr; } /* * Add a virtual interface in the kernel. */ void k_add_vif(int socket, vifi_t vifi, struct uvif *v) { struct vifctl vc; vc.vifc_vifi = vifi; uvif_to_vifctl(&vc, v); if (setsockopt(socket, IPPROTO_IP, MRT_ADD_VIF, (char *)&vc, sizeof(vc)) < 0) logit(LOG_ERR, errno, "Failed adding VIF %d (MRT_ADD_VIF)", vifi); } /* * Delete a virtual interface in the kernel. */ void k_del_vif(int socket, vifi_t vifi, struct uvif *v __attribute__((unused))) { /* * Unfortunately Linux MRT_DEL_VIF API differs a bit from the *BSD one. It * expects to receive a pointer to struct vifctl that corresponds to the VIF * we're going to delete. *BSD systems on the other hand exepect only the * index of that VIF. */ #ifdef __linux__ struct vifctl vc; vc.vifc_vifi = vifi; uvif_to_vifctl(&vc, v); /* 'v' is used only on Linux systems. */ if (setsockopt(socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vc, sizeof(vc)) < 0) #else /* *BSD et al. */ if (setsockopt(socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vifi, sizeof(vifi)) < 0) #endif /* !__linux__ */ { if (errno == EADDRNOTAVAIL || errno == EINVAL) return; logit(LOG_ERR, errno, "Failed removing VIF %d (MRT_DEL_VIF)", vifi); } } /* * Delete all MFC entries for particular routing entry from the kernel. */ int k_del_mfc(int socket, u_int32 source, u_int32 group) { struct mfcctl mc; mc.mfcc_origin.s_addr = source; mc.mfcc_mcastgrp.s_addr = group; if (setsockopt(socket, IPPROTO_IP, MRT_DEL_MFC, (char *)&mc, sizeof(mc)) < 0) { logit(LOG_WARNING, errno, "Failed removing MFC entry src %s, grp %s", inet_fmt(mc.mfcc_origin.s_addr, s1, sizeof(s1)), inet_fmt(mc.mfcc_mcastgrp.s_addr, s2, sizeof(s2))); return FALSE; } IF_DEBUG(DEBUG_MFC) { logit(LOG_DEBUG, 0, "Removed MFC entry src %s, grp %s", inet_fmt(mc.mfcc_origin.s_addr, s1, sizeof(s1)), inet_fmt(mc.mfcc_mcastgrp.s_addr, s2, sizeof(s2))); } return TRUE; } /* * Install/modify a MFC entry in the kernel */ int k_chg_mfc(int socket, u_int32 source, u_int32 group, vifi_t iif, vifbitmap_t oifs, u_int32 rp_addr __attribute__((unused))) { struct mfcctl mc; vifi_t vifi; struct uvif *v; mc.mfcc_origin.s_addr = source; #ifdef OLD_KERNEL mc.mfcc_originmas.s_addr = 0xffffffff; /* Got it from mrouted-3.9 */ #endif /* OLD_KERNEL */ mc.mfcc_mcastgrp.s_addr = group; mc.mfcc_parent = iif; /* * draft-ietf-pim-sm-v2-new-05.txt section 4.2 mentions iif is removed * at the packet forwarding phase */ VIFM_CLR(mc.mfcc_parent, oifs); for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { if (VIFM_ISSET(vifi, oifs)) mc.mfcc_ttls[vifi] = v->uv_threshold; else mc.mfcc_ttls[vifi] = 0; } #ifdef PIM_REG_KERNEL_ENCAP mc.mfcc_rp_addr.s_addr = rp_addr; #endif if (setsockopt(socket, IPPROTO_IP, MRT_ADD_MFC, (char *)&mc, sizeof(mc)) < 0) { logit(LOG_WARNING, errno, "Failed adding MFC entry src %s grp %s", inet_fmt(mc.mfcc_origin.s_addr, s1, sizeof(s1)), inet_fmt(mc.mfcc_mcastgrp.s_addr, s2, sizeof(s2))); return FALSE; } return TRUE; } /* * Get packet counters for particular interface * XXX: TODO: currently not used, but keep just in case we need it later. */ int k_get_vif_count(vifi_t vifi, struct vif_count *retval) { struct sioc_vif_req vreq; vreq.vifi = vifi; if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) { logit(LOG_WARNING, errno, "Failed reading kernel packet count (SIOCGETVIFCNT) on vif %d", vifi); retval->icount = retval->ocount = retval->ibytes = retval->obytes = 0xffffffff; return 1; } retval->icount = vreq.icount; retval->ocount = vreq.ocount; retval->ibytes = vreq.ibytes; retval->obytes = vreq.obytes; return 0; } /* * Gets the number of packets, bytes, and number op packets arrived * on wrong if in the kernel for particular (S,G) entry. */ int k_get_sg_cnt(int socket, u_int32 source, u_int32 group, struct sg_count *retval) { struct sioc_sg_req sgreq; sgreq.src.s_addr = source; sgreq.grp.s_addr = group; if ((ioctl(socket, SIOCGETSGCNT, (char *)&sgreq) < 0) || (sgreq.wrong_if == 0xffffffff)) { /* XXX: ipmulti-3.5 has bug in ip_mroute.c, get_sg_cnt(): * the return code is always 0, so this is why we need to check * the wrong_if value. */ logit(LOG_WARNING, errno, "Failed reading kernel count (SIOCGETSGCNT) for (S,G) on (%s, %s)", inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2))); retval->pktcnt = retval->bytecnt = retval->wrong_if = ~0; return 1; } retval->pktcnt = sgreq.pktcnt; retval->bytecnt = sgreq.bytecnt; retval->wrong_if = sgreq.wrong_if; return 0; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/README.debug0000644000000000000000000000363211700261371011310 0ustar $Id: README.debug,v 1.4 2002/11/17 20:01:31 pavlin Exp $ This file contains some hints how to debug your multicast routing. XXX: currently, it is very incomplete. If something is missing and/or is unclear, send email to the current maintainer of pimd. (see file AUTHORS for email address). 1. All systems - Make sure that the TTL of the sender is large enough to reach the receiver. E.g., if the sender and the receiver are separated by a two routers in the middle, the TTL of the data packets transmitted by the sender must be at least 3. 2. Linux 2.1 Before you start the multicast routing daemon - Check the kernel config, the following settings should be activated: * CONFIG_IP_MROUTE=y * CONFIG_IP_PIMSM_V1=y * CONFIG_IP_PIMSM_V2=y - Check the list of multicast capable interfaces: cat /proc/net/dev_mcast - Start the multicast routing daemon in debug mode (e.g., pimd -d all) 2.2 After you start the multicast routing daemon - Are the multicast vifs correctly installed in the kernel: cat /proc/net/ip_mr_vif - Is multicast forwarding enabled on those vifs: cat /proc/sys/net/ipv4/conf/eth0/mc_forwarding for each of the enabled interfaces. If it returns zero, the multicast forwarding on that interface is not working. - Is the PIM multicast routing daemon exchanging PIM_HELLO messages with its neighbors? (Look into the debug messages output; if necessary, use tcpdump as well). - Are the Bootpstrap messages received by all PIM-SM daemons? - If a Bootstrap message is received, is it accepted, or is it rejected because of a wrong iif? - After a while, does the Cand-RP set contain the set of RPs? - After the first multicast packets are received, is there CACHE_MISS signal from the kernel to the user-level daemon? - After the CACHE_MISS signal, are the MFC (Multicast Forwarding Cache) entries installed in the kernel? cat /proc/net/ip_mr_cache pimd-2.1.8/igmp_proto.c0000644000000000000000000003102711700261371011665 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: igmp_proto.c,v 1.15 2001/09/10 20:31:36 pavlin Exp $ */ /* * 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 "defs.h" typedef struct { vifi_t vifi; struct listaddr *g; int q_time; } cbk_t; /* * Forward declarations. */ static void DelVif (void *arg); static int SetTimer (vifi_t vifi, struct listaddr *g); static int DeleteTimer (int id); static void SendQuery (void *arg); static int SetQueryTimer (struct listaddr *g, vifi_t vifi, int to_expire, int q_time); /* * Send group membership queries on that interface if I am querier. */ void query_groups(struct uvif *v) { struct listaddr *g; v->uv_gq_timer = IGMP_QUERY_INTERVAL; if (v->uv_flags & VIFF_QUERIER) { send_igmp(igmp_send_buf, v->uv_lcl_addr, allhosts_group, IGMP_MEMBERSHIP_QUERY, (v->uv_flags & VIFF_IGMPV1) ? 0 : IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); } /* * Decrement the old-hosts-present timer for each * active group on that vif. */ for (g = v->uv_groups; g != NULL; g = g->al_next) { if (g->al_old > TIMER_INTERVAL) g->al_old -= TIMER_INTERVAL; else g->al_old = 0; } } /* * Process an incoming host membership query */ void accept_membership_query(u_int32 src, u_int32 dst __attribute__((unused)), u_int32 group, int tmo) { vifi_t vifi; struct uvif *v; /* Ignore my own membership query */ if (local_address(src) != NO_VIF) return; /* TODO: modify for DVMRP?? */ if ((vifi = find_vif_direct(src)) == NO_VIF) { IF_DEBUG(DEBUG_IGMP) logit(LOG_INFO, 0, "ignoring group membership query from non-adjacent host %s", inet_fmt(src, s1, sizeof(s1))); return; } v = &uvifs[vifi]; if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) || (tmo != 0 && (v->uv_flags & VIFF_IGMPV1))) { int i; /* * Exponentially back-off warning rate */ i = ++v->uv_igmpv1_warn; while (i && !(i & 1)) i >>= 1; if (i == 1) { logit(LOG_WARNING, 0, "%s %s on vif %d, %s", tmo == 0 ? "Received IGMPv1 report from" : "Received IGMPv2 report from", inet_fmt(src, s1, sizeof(s1)), vifi, tmo == 0 ? "please configure vif for IGMPv1" : "but I am configured for IGMPv1"); } } if (v->uv_querier == NULL || v->uv_querier->al_addr != src) { /* * This might be: * - A query from a new querier, with a lower source address * than the current querier (who might be me) * - A query from a new router that just started up and doesn't * know who the querier is. * - A query from the current querier */ if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr) : ntohl(v->uv_lcl_addr))) { IF_DEBUG(DEBUG_IGMP) logit(LOG_DEBUG, 0, "new querier %s (was %s) on vif %d", inet_fmt(src, s1, sizeof(s1)), v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2, sizeof(s2)) : "me", vifi); if (!v->uv_querier) { v->uv_querier = (struct listaddr *) calloc(1, sizeof(struct listaddr)); if (!v->uv_querier) { logit(LOG_ERR, 0, "Failed calloc() in accept_membership_query()\n"); return; } v->uv_querier->al_next = (struct listaddr *)NULL; v->uv_querier->al_timer = 0; v->uv_querier->al_genid = 0; /* TODO: write the protocol version */ v->uv_querier->al_pv = 0; v->uv_querier->al_mv = 0; v->uv_querier->al_old = 0; v->uv_querier->al_index = 0; v->uv_querier->al_timerid = 0; v->uv_querier->al_query = 0; v->uv_querier->al_flags = 0; v->uv_flags &= ~VIFF_QUERIER; } v->uv_querier->al_addr = src; time(&v->uv_querier->al_ctime); } } /* * Reset the timer since we've received a query. */ if (v->uv_querier && src == v->uv_querier->al_addr) v->uv_querier->al_timer = 0; /* * If this is a Group-Specific query which we did not source, * we must set our membership timer to [Last Member Query Count] * * the [Max Response Time] in the packet. */ if (!(v->uv_flags & VIFF_IGMPV1) && group != 0 && src != v->uv_lcl_addr) { struct listaddr *g; IF_DEBUG(DEBUG_IGMP) { logit(LOG_DEBUG, 0, "%s for %s from %s on vif %d, timer %d", "Group-specific membership query", inet_fmt(group, s2, sizeof(s2)), inet_fmt(src, s1, sizeof(s1)), vifi, tmo); } for (g = v->uv_groups; g != NULL; g = g->al_next) { if (group == g->al_addr && g->al_query == 0) { /* setup a timeout to remove the group membership */ if (g->al_timerid) g->al_timerid = DeleteTimer(g->al_timerid); g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT * tmo / IGMP_TIMER_SCALE; /* use al_query to record our presence in last-member state */ g->al_query = -1; g->al_timerid = SetTimer(vifi, g); IF_DEBUG(DEBUG_IGMP) { logit(LOG_DEBUG, 0, "timer for grp %s on vif %d set to %ld", inet_fmt(group, s2, sizeof(s2)), vifi, g->al_timer); } break; } } } } /* * Process an incoming group membership report. */ void accept_group_report(u_int32 src, u_int32 dst __attribute__((unused)), u_int32 group, int igmp_report_type) { vifi_t vifi; struct uvif *v; struct listaddr *g; if ((vifi = find_vif_direct_local(src)) == NO_VIF) { IF_DEBUG(DEBUG_IGMP) { logit(LOG_INFO, 0, "ignoring group membership report from non-adjacent host %s", inet_fmt(src, s1, sizeof(s1))); } return; } v = &uvifs[vifi]; /* * Look for the group in our group list; if found, reset its timer. */ for (g = v->uv_groups; g != NULL; g = g->al_next) { if (group == g->al_addr) { if (igmp_report_type == IGMP_V1_MEMBERSHIP_REPORT) g->al_old = DVMRP_OLD_AGE_THRESHOLD; g->al_reporter = src; /** delete old timers, set a timer for expiration **/ g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; if (g->al_query) g->al_query = DeleteTimer(g->al_query); if (g->al_timerid) g->al_timerid = DeleteTimer(g->al_timerid); g->al_timerid = SetTimer(vifi, g); /* TODO: might need to add a check if I am the forwarder??? */ /* if (v->uv_flags & VIFF_DR) */ add_leaf(vifi, INADDR_ANY_N, group); break; } } /* * If not found, add it to the list and update kernel cache. */ if (g == NULL) { g = (struct listaddr *)calloc(1, sizeof(struct listaddr)); if (!g) { logit(LOG_ERR, 0, "Ran out of memory"); /* fatal */ return; } g->al_addr = group; if (igmp_report_type == IGMP_V1_MEMBERSHIP_REPORT) g->al_old = DVMRP_OLD_AGE_THRESHOLD; else g->al_old = 0; /** set a timer for expiration **/ g->al_query = 0; g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL; g->al_reporter = src; g->al_timerid = SetTimer(vifi, g); g->al_next = v->uv_groups; v->uv_groups = g; time(&g->al_ctime); /* TODO: might need to add a check if I am the forwarder??? */ /* if (v->uv_flags & VIFF_DR) */ add_leaf(vifi, INADDR_ANY_N, group); } } /* TODO: send PIM prune message if the last member? */ void accept_leave_message(u_int32 src, u_int32 dst __attribute__((unused)), u_int32 group) { vifi_t vifi; struct uvif *v; struct listaddr *g; /* TODO: modify for DVMRP ??? */ if ((vifi = find_vif_direct_local(src)) == NO_VIF) { IF_DEBUG(DEBUG_IGMP) { logit(LOG_INFO, 0, "ignoring group leave report from non-adjacent host %s", inet_fmt(src, s1, sizeof(s1))); } return; } v = &uvifs[vifi]; #if 0 /* XXX: a PIM-SM last-hop router needs to know when a local member * has left. */ if (!(v->uv_flags & (VIFF_QUERIER | VIFF_DR)) || (v->uv_flags & VIFF_IGMPV1)) return; #endif /* * Look for the group in our group list in order to set up a short-timeout * query. */ for (g = v->uv_groups; g != NULL; g = g->al_next) { if (group == g->al_addr) { IF_DEBUG(DEBUG_IGMP) { logit(LOG_DEBUG, 0, "[vif.c, _accept_leave_message] %d %d \n", g->al_old, g->al_query); } /* Ignore the leave message if there are old hosts present */ if (g->al_old) return; /* still waiting for a reply to a query, ignore the leave */ if (g->al_query) return; /** delete old timer set a timer for expiration **/ if (g->al_timerid) g->al_timerid = DeleteTimer(g->al_timerid); #if IGMP_LAST_MEMBER_QUERY_COUNT != 2 /* This code needs to be updated to keep a counter of the number of queries remaining. */ #endif /** send a group specific querry **/ g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL * (IGMP_LAST_MEMBER_QUERY_COUNT + 1); if (v->uv_flags & VIFF_QUERIER) { send_igmp(igmp_send_buf, v->uv_lcl_addr, g->al_addr, IGMP_MEMBERSHIP_QUERY, IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE, g->al_addr, 0); } g->al_query = SetQueryTimer(g, vifi, IGMP_LAST_MEMBER_QUERY_INTERVAL, IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE); g->al_timerid = SetTimer(vifi, g); break; } } } /* * Time out record of a group membership on a vif */ static void DelVif(void *arg) { cbk_t *cbk = (cbk_t *)arg; vifi_t vifi = cbk->vifi; struct uvif *v = &uvifs[vifi]; struct listaddr *a, **anp, *g = cbk->g; /* * Group has expired * delete all kernel cache entries with this group */ if (g->al_query) DeleteTimer(g->al_query); delete_leaf(vifi, INADDR_ANY_N, g->al_addr); anp = &(v->uv_groups); while ((a = *anp) != NULL) { if (a == g) { *anp = a->al_next; free((char *)a); } else { anp = &a->al_next; } } free(cbk); } /* * Set a timer to delete the record of a group membership on a vif. */ static int SetTimer(vifi_t vifi, struct listaddr *g) { cbk_t *cbk; cbk = (cbk_t *) calloc(1, sizeof(cbk_t)); if (!cbk) { logit(LOG_ERR, 0, "Failed calloc() in SetTimer()\n"); return -1; } cbk->vifi = vifi; cbk->g = g; return timer_setTimer(g->al_timer, DelVif, cbk); } /* * Delete a timer that was set above. */ static int DeleteTimer(int id) { timer_clearTimer(id); return 0; } /* * Send a group-specific query. */ static void SendQuery(void *arg) { cbk_t *cbk = (cbk_t *)arg; struct uvif *v = &uvifs[cbk->vifi]; if (v->uv_flags & VIFF_QUERIER) { send_igmp(igmp_send_buf, v->uv_lcl_addr, cbk->g->al_addr, IGMP_MEMBERSHIP_QUERY, cbk->q_time, cbk->g->al_addr, 0); } cbk->g->al_query = 0; free(cbk); } /* * Set a timer to send a group-specific query. */ static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time) { cbk_t *cbk; cbk = (cbk_t *)calloc(1, sizeof(cbk_t)); if (!cbk) { logit(LOG_ERR, 0, "Failed calloc() in SetQueryTimer()\n"); return -1; } cbk->g = g; cbk->q_time = q_time; cbk->vifi = vifi; return timer_setTimer(to_expire, SendQuery, cbk); } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/.gdbinit0000644000000000000000000000005511700261371010760 0ustar set args -d pim_mrt,pim_bsr set args -d all pimd-2.1.8/strlcpy.c0000644000000000000000000000317711700261371011213 0ustar /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "defs.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } /** * Local Variables: * version-control: t * c-file-style: "bsd" * End: */ pimd-2.1.8/README.config.jp0000644000000000000000000001241511700261371012076 0ustar =============================================================== $Id: README.config.jp,v 1.3 2002/06/13 17:39:19 pavlin Exp $ ¤³¤Îʸ½ñ¤Ï pimd ¤Î README.config.jp ¤Ç¤¹. pimd ¤Ï PIM-SM ¥Ð¡¼¥¸¥ç¥ó 2 ¤Î ¥Þ¥ë¥Á¥Á¥ã¥¹¥È¥Ç¡¼¥â¥ó¤Ç¤¹. ºÇ¿·ÈÇ¤Ï http://netweb.usc.edu/pim/pimd/ ¤Ç ³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¤³¤Î¥Õ¥¡¥¤¥ë¤Ï pimd ¤ÎÀßÄê¤Ë¤Ä¤¤¤Æµ­½Ò¤·¤Æ¤¤¤Þ¤¹. ±Ñ¸ìÈÇ¤Ï README.config ¤Ë¤Ê¤ê¤Þ¤¹. XXX: ¸½¾õ¤Ç¤Ï, ¤³¤Î¥Õ¥¡¥¤¥ë¤Ï¤Þ¤ÀÉÔ´°Á´¤Ç¤¹. ¤â¤·¤Ê¤Ë¤«¤·¤éÈ´¤±¤Æ¤¤¤ë¤È¤³¤í¤ä ¤è¤¯Ê¬¤«¤é¤Ê¤¤¤È¤³¤í¤¬¤¢¤ê¤Þ¤·¤¿¤é, ºî¼Ô¤Ë¥á¡¼¥ë¤ò¤¯¤À¤µ¤¤. (¥á¡¼¥ë¥¢¥É¥ì¥¹¤Ï README ¥Õ¥¡¥¤¥ë¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤). 1. ¥Þ¥ë¥Á¥­¥ã¥¹¥È¥ë¡¼¥Æ¥£¥ó¥°¤ò¹Ô¤¦¤¿¤á¤Î GRE ¥È¥ó¥Í¥ë¤ÎÀßÄê (¾®¾¾¹°¹¬¤µ¤ó ¤Î¾ðÊó¤ò¸µ¤Ë¤·¤Æ¤¤¤Þ¤¹). Linux (Debian) ¤Î¾ì¹ç, °Ê²¼¤Î¤è¤¦¤Ë»î¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤: (½é¤á¤Æ GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹¤òÀßÄꤹ¤ë¾ì¹ç, "ip link set gre1 down" ¤È "ip tunnel del gre1" ¤Î¸å¤Ë¥¨¥é¡¼¤¬½Ð¤Þ¤¹¤¬, ̵»ë¤·¤Æ²¼¤µ¤¤). 1.1 Æó¤Ä¤Î¥Þ¥·¥ó´Ö¤Ç¤Î GRE ¥È¥ó¥Í¥ë (¥Û¥¹¥È¤Ï 11.11.11.11 ¤È 33.33.33.33) ¼ÂºÝ¤Î¥¤¥ó¥¿¥Õ¥§¡¼¥¹: [11.11.11.11] [33.33.33.33] GRE ¥È¥ó¥Í¥ë: 22.22.22.11<--------->22.22.22.33 ==== ¥Û¥¹¥È 11.11.11.11 (GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹ 22.22.22.11) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip link set gre1 down ip tunnel del gre1 ip tunnel add gre1 mode gre remote 33.33.33.33 local 11.11.11.11 ttl 127 ip addr add 22.22.22.11/24 peer 22.22.22.33/24 dev gre1 ip link set gre1 up multicast on ==== ¥Û¥¹¥È 33.33.33.33 (GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹ 22.22.22.33) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip link set gre1 down ip tunnel del gre1 ip tunnel add gre1 mode gre remote 11.11.11.11 local 33.33.33.33 ttl 127 ip addr add 22.22.22.33/24 peer 22.22.22.11/24 dev gre1 ip link set gre1 up multicast on 1.2 »°¤Ä¤Î¥Þ¥·¥ó´Ö¤Ç¤Î GRE ¥È¥ó¥Í¥ë = ½ÅÍ× =============================================================== Æó¤Ä°Ê¾å¤Î GRE ¥È¥ó¥Í¥ë¤ò¿ô¼î·Ò¤®¤Ë¤·¤è¤¦¤¹¤ë¤È, Èó¾ï¤Ë¥æ¥Ë¥­¥ã¥¹¥È ¥ë¡¼¥Æ¥£¥ó¥°¤Î¥ë¡¼¥×¤òȯÀ¸¤µ¤»¤Æ¤·¤Þ¤¤¤ä¤¹¤¯¤Ê¤ê¤Þ¤¹. ¤³¤ì¤Ï¥Þ¥ë¥Á¥­¥ã¥¹¥È ¥ë¡¼¥Æ¥£¥ó¥°¤Î¥ë¡¼¥×¤â¤Þ¤¿°ú¤­µ¯¤³¤·¤Æ¤·¤Þ¤¤¤Þ¤¹. ¥Þ¥ë¥Á¥­¥ã¥¹¥È¥ë¡¼¥Æ¥£¥ó¥°¤Î ¥ë¡¼¥×¤Ï¥Í¥Ã¥È¥ï¡¼¥¯Á´ÂΤò¥À¥¦¥ó¤µ¤»¤Æ¤·¤Þ¤¦²ÄǽÀ­¤¬¤¢¤ë¤Û¤É¤Î¾ã³²¤Ç¤¹. °Ê²¼¤ÎÀßÄê¤ò»î¤·¤Æ¤ß¤ëÁ°¤Ë, ¡Ö¼«Ê¬¤¬²¿¤ò¤·¤Æ¤¤¤ë¤Î¤«¡×¤ª¤è¤Ó¡Ö¤½¤Î·ë²Ì ²¿¤¬µ¯¤³¤ë¤Î¤«¡×¤ò¤è¤¯Íý²ò¤·¤Æ¤¯¤À¤µ¤¤. ¤³¤Îʸ½ñ¤òÆÉ¤ó¤Ç¤¤¤ë¤È¤¤¤¦¤³¤È¤Ï, ¤Þ¤À´°Á´¤Ë¤ÏÍý²ò¤µ¤ì¤Æ¤¤¤Ê¤¤¤È¤¤¤¦ ¤³¤È¤«¤â¤·¤ì¤Þ¤»¤ó. ¤â¤¦°ìÅÙ¿¶¤êÊ֤äƹͤ¨¤Æ¤ß¤Æ¤¯¤À¤µ¤¤. ====================================================================== STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!!STOP!!! IF YOU ADD MORE THAN TWO GRE TUNNELS IN A CHAIN, IT IS VERY EASY TO CREATE UNICAST ROUTING LOOPS, AND THIS MAY LEAD TO MULTICAST ROUTING LOOPS. MULTICAST ROUTING LOOP IS A DISASTER THAT MAY BRING YOUR WHOLE NETWORK DOWN. BEFORE ATTEMPTING THIS CONFIGURATION, MAKE SURE YOU UNDERSTAND VERY WELL WHAT YOU ARE DOING, AND WHAT MAY HAPPEN. IF YOU ARE READING THIS, THE CHANCES ARE THAT YOU DON'T KNOW, SO THINK AGAIN!! THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!!THINK!!! ¼ÂºÝ¤Î¥¤¥ó¥¿¥Õ¥§¡¼¥¹: [11.11.11.11] [33.33.33.33] [55.55.55.55] GRE ¥È¥ó¥Í¥ë: 22.22.22.11 <--> 22.22.22.33 44.44.44.33 <--> 44.44.44.55 ==== ¥Û¥¹¥È 33.33.33.33 (GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹ 22.22.22.33 and 44.44.44.33) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 11.11.11.11 local 33.33.33.33 ttl 127 ip addr add 22.22.22.33/24 peer 22.22.22.11/24 dev gre1 ip link set gre1 up multicast on ip tunnel add gre2 mode gre remote 55.55.55.55 local 33.33.33.33 ttl 127 ip addr add 44.44.44.33/24 peer 44.44.44.55/24 dev gre2 ip link set gre2 up multicast on ==== ¥Û¥¹¥È 55.55.55.55 (GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹ 44.44.44.55) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 33.33.33.33 local 55.55.55.55 ttl 127 ip addr add 44.44.44.55/24 peer 44.44.44.33/24 dev gre1 ip link set gre1 up multicast on route add -net 22.22.22.0 netmask 255.255.255.0 gw 44.44.44.33 gre1 ==== ¥Û¥¹¥È 11.11.11.11 (GRE ¥¤¥ó¥¿¥Õ¥§¡¼¥¹ 22.22.22.11) echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter ip tunnel add gre1 mode gre remote 33.33.33.33 local 11.11.11.11 ttl 127 ip addr add 22.22.22.11/24 peer 22.22.22.33/24 dev gre1 ip link set gre1 up multicast on route add -net 44.44.44.0 netmask 255.255.255.0 gw 22.22.22.33 gre1 2. pimd ¤ÎÀßÄê »ÈÍѲÄǽ¤Ê¤¹¤Ù¤Æ¤Î¥ª¥×¥·¥ç¥ó¤Î°ìÍ÷¤Ï pimd.conf ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤. 2.1. pimd ¤¬ Cand-RP ¤Ë¤Ê¤é¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤Ë¤Ï? "cand_rp" ¤È "group_prefix" ¤Î¹Ô¤ò¥³¥á¥ó¥È¥¢¥¦¥È¤·¤Æ¤¯¤À¤µ¤¤. 2.2. pimd ¤¬ Cand-BSR ¤Ë¤Ê¤é¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤Ë¤Ï? "cand_bootstrap_router" ¤Î¹Ô¤ò¥³¥á¥ó¥È¥¢¥¦¥È¤·¤Æ¤¯¤À¤µ¤¤. 2.3. ¼«Ê¬¤Î¥Þ¥ë¥Á¥­¥ã¥¹¥È¥ë¡¼¥¿¤ò·Ðͳ¤¹¤ë¥Þ¥ë¥Á¥­¥ã¥¹¥È¥¢¥É¥ì¥¹¤Î ¤¢¤ë¥×¥ê¥Õ¥£¥Ã¥¯¥¹¤ò¼×¤ë¤Ë¤Ï? Î㤨¤Ð, ¥×¥ê¥Õ¥£¥Ã¥¯¥¹ 238.0.0.0/8 ¤È 239.0.0.0/8 ¤ò¥¹¥³¡¼¥×¤·¤¿¤¤¤Ê¤é, pimd.conf ¤Ë°Ê²¼¤Î¹Ô¤òÄɲ䷤Ƥ¯¤À¤µ¤¤: phyint eth1 scoped 238.0.0.0 masklen 8 phyint eth1 scoped 239.0.0.0 masklen 8 2.4. ¥¹¥³¡¼¥×ÈϰϤòºîÀ®¤·¤Æ, ¼«Ê¬¤Î¥Í¥Ã¥È¥ï¡¼¥¯¶­³¦¤ò±Û¤¨¤ÆÅÁÇŤµ¤ì¤ë ¥Þ¥ë¥Á¥­¥ã¥¹¥È¥×¥ê¥Õ¥£¥Ã¥¯¥¹¤Î¥Ñ¥±¥Ã¥È¤ò»ß¤á¤ë¤Ë¤Ï? ¥¹¥³¡¼¥×¤·¤¿¤¤¸Ä¡¹¤Î¥×¥ê¥Õ¥£¥Ã¥¯¥¹¤ËÂФ¹¤ë¼«Ê¬¤Î¶­³¦¥ë¡¼¥¿¤Ë ¥¹¥³¡¼¥Ô¥ó¥°¥Õ¥£¥ë¥¿¤ò²Ã¤¨¤Æ¤¯¤À¤µ¤¤. Î㤨¤Ð: phyint eth1 scoped 239.0.0.0 masklen 8 pimd-2.1.8/TODO0000644000000000000000000001340211700261371010027 0ustar TODO List -*-org-*- THIS LIST IS FAR AWAY FROM BEING COMPLETE, so these are the few things that came up at the right moment to be written down. * Random issues: ** Run the code checker sparse harder on the code: CC=cgcc make ** Start work on ironing out a TODO list for RFC 4601 compliancy. ** Look into updates RFC 5059 and RFC 5796 ** Test again on Debian GNU/kFreeBSD. Atm it lacks netinet/pim.h, but it should be possible to run the default config on it, probing the __FreeBSD_kernel__ and doing the right thing. ** Check Kame's pim6sd old sources for relevant fixes. http://www.kame.net/dev/cvsweb2.cgi/kame/kame/kame/pim6sd/Attic/ ** Import Kame's pim6sd cfparse.[yl] config file parser reimplemented in lex & yacc, like mrouted does. ** DONE When receive PIM_REGISTER, check whether I am the chosen RP ** Install negative cache in kernel for non-frequently requested groups. ** The code should use the _PIM_VT handling of the 'struct pim' ** Check 2.10 from the spec "Unicast Routing Changes", and verify that it is properly implemented ** in pimd.conf should be mandatory, instead of relaying of its default value (16) ** Candidate RP priority configuration in pimd.conf should be per prefix, instead of a single priority for the whole RP. ** Check whether Asserts received on the iif are really evaluated by using the metrics of other asserts received on that iif, or the comparison uses the local metric and preference info (it must be the former!). ** Experimental kernel MFC (*,G) related: If the (S,G) iif or oifs are different from the (*,G) or (*,*,RP) iifs/oifs, the resp. (*,G) or (*,*,RP) will delete and disallow creating (*,G) MFC. Only after all MRT (S,G) are deleted, the corresponding (*,G) or (*,*,RP) will create (*,G) MFC. ** Experimental kernel MFC (*,G) related: Right now when the MFC (*,G) total datarate is above the SPT switch threshold, the (*,G) MFC will be deleted, and any further cache miss will result in (S,G) MFC (the problem is that we must do (S,G) monitoring for eventually high datagate sources). Only after all (S,G) MFCs expire, the daemon's MRT will stop creating (S,G) MFCs (i.e. the next cache miss will result in (*,G) kernel MFC). A better selection should be applied to sort out the higher datarate sources, and at the same time to have (*,G)MFC as well. For example, create few (S,G), and after that create the (*,G). If some of the created (S,G) MFC entries have very low datarate, delete them. ** Use NetBSD's definition for IPADDR (netinet/in.h): #ifdef _KERNEL #define __IPADDR(x) ((u_int32_t) htonl((u_int32_t)(x))) #else #define __IPADDR(x) ((u_int32_t)(x)) #endif ** The (S,G)RPbit in the DR for the sender and the (S,G)SPT in the downstream router won't timeout and will refresh each other even if the sender is not active: S--DR-----------------R1------------RP (S,G)RPbit (S,G) iif toward S ** Check whether the kernel code sends CACHE_MISS and WRONG_IIF for the LAN-scoped addresses ** If the RP for a group changes, the DR should cancel any PIM-register-stop timers (XXX: not in the spec, but should be there) ** If a new interface is configured, include it automatically ** Don't create routing entries for local link scoped groups ** Implement adm. scoped filters ** Do precise check of the timer events to speed up the propagation of the Cand-RP messages + Cand-BSR messages and the election of the BSR. ** Fix the bug for messing up the things when the receiver is on the same host as the RP for the multicast group (probably was fixed with alpha6, because I cannot reproduce it anymore) ** Do more precise error check for the received PIM messages. In most cases, the whole message must be parsed completely before starting processing it. ** Clean up the debugging messages. ** Use Patricia tree to search the routing table (There is a nice paper in Sigcomm '97 about fast routing tables implementation, so need to check it as well) ** Do switch back to the Shared Tree by timing out the SPT if the rate is too low (not in the spec, but Ahmed pointed out some complications if this happens) ** Change all countdown timers to events timeout (callout.c) (The current implementation is very unefficient if the routing table becomes very large) ** Send immediately Join/Prune, instead of relying of Join/Prune timer = 0 ** Fix the code allowing interface UP/DOWN without restarting pimd. ** Do more testings for SPT switch, Join/Prune, asserts, etc... ** Test the (*,*,RP) code (need PIM/DVMRP border router to do so) ** Test the RSRR (RSVP support) code ** Send Initial_Reply RSRR message if the interfaces detected by pimd change ** SNMP support, RFC2934 * Issues by function name: ** igmp_proto.c: - accept_group_report(): * add a leaf if DR or forwarder (currently only if DR)??? - accept_leave_message(): * send immediately PIM prune message if the last member has left ** main.c - main(): * use a combination of time and hostid to initialize the random generator. - restart(): * check the implementation ** pim_proto.c - pim_register(): * IF THE BORDER BIT IS SET, THEN FORWARD THE WHOLE PACKET FROM USER SPACE AND AT THE SAME TIME IGNORE ANY CACHE_MISS SIGNALS FROM THE KERNEL. - register_stop(): * REGISTER_STOP rate limiting ** route.c - process_cache_miss() * use negative cache. ** rp.c - add_rp_grp_entry(): * FIX THE BUG when adding an RP for different prefix requires remapping for some groups!!! (Intentionally left, waiting to come up with an idea how to implement it simple and efficient. If you configure all RPs to advertise the same prefix, the bug won't "show up") pimd-2.1.8/README0000644000000000000000000001553111700261371010224 0ustar README for pimd, the PIM-SM v2 multicast daemon =============================================== This is pimd, a lightweight, stand-alone implementation of Protocol Independent Multicast-Sparse Mode that may be freely distributed and/or deployed under the BSD license. The project implements the full PIM-SM specification according to RFC 2362 with a few noted exceptions (see the RELEASE.NOTES for details). The software should compile and run on most UNIX varieties, including FreeBSD, BSDi, NetBSD, OpenBSD, SunOS, IRIX, Solaris 2.5, Solaris 2.6, and GNU/Linux. It has, however, not been thoroughly tested on all these. If you have any questions, suggestions, bug reports, patches, or pull requests, please do NOT send them to the PIM IETF Working Group mailing list! Instead, contact the current maintainer, see the file AUTHORS, or use the github issue tracker at: http://github.com/troglobit/pimd/issues The following helpful text is a rip-off from the book Linux Routing. See http://linux-networks.net/New.Riders-Linux.Routing/tindex.htm for more. Configuring pimd ---------------- Since pimd is a single-function daemon, the configuration is really not that complex -- at least when compared to a monster tool such as gated. The configuration data is kept in the file /etc/pimd.conf. While the order of the statements does not have to strictly follow what is about to be presented, I'll walk you through the contents you might want to add to this file. The /etc/pimd.conf file begins with the following statement: default_source_preference value Routers hold elections to determine which gets to be a site's upstream router. Because pimd is such a focused tool, you generally don't want it to win over something more general. Using a value of 101 here is a minimum for making sure that gated and other routing tools are going to win the election and leave pimd to do its PIM-SM handling. The next line is: default_source_metric value This item sets the cost for sending data through this router. You want only PIM-SM data to go to this daemon; so once again, a high value is recommended to prevent accidental usage. The preferred default value is 1024. Though you can swap the first two statements around, you must have the next statement after you set default_source_metric. This item starts with: phyint interface phyint refers to physical interface. You fill in interface with a reference to the ethernet card or other network interface you're telling pimd about, either with the device's IP address or name (for example, eth0). If you just want to activate this interface with default values, you don't need to put anything else on the line. However, you do have some additional items you can add. The items are, in the order you would need to use them, as follows: * _disable_. Do not send PIM-SM traffic through this interface nor listen for PIM-SM traffic from this interface. * preference pref. This interface's value in an election. It will have the default_source_preference if not assigned. * metric cost. The cost of sending data through this interface. It will have the default_source_metric if not assigned. Add one phyint line per interface on this router. If you don't do this, pimd will simply assume that you want it to utilize all interfaces on the machine with the default values. If you set phyint for one or more interfaces but not for all, the missing ones will be assigned the defaults. After you have done this, start the next line with: cand_rp cand_rp refers to Candidate Rendezvous Point (CRP). This statement specifies which interface on this machine should be included in RP elections. Additional options to choose from are, listed in the order used, as follows: * ipadd. The default is the largest activated IP address. If you don't want to utilize that interface, add the IP address of the interface to use as the next term. * time value. The number of seconds to wait between advertising this CRP. The default value is 60 seconds. * priority num. How important this CRP is compared to others. The lower the value here, the more important the CRP. The next line begins with: cand_bootstrap_router Here you give the information for how this machine advertises itself as a Candidate BootStrap Router (CBSR). If you need to, add the ipaddr and/or priority items as defined earlier after cand_bootstrap_router. What follows is a series of statements that start with: group_prefix Each group_prefix statement outlines the set of multicast addresses that CRP, if it wins an election, will advertise to other routers. The two items you might include here are, listed in order, as follows: * groupaddr. A specific IP or network range this router will handle. Remember that a single multicast network is written as a single IP address. * masklen len. The number of IP address segments taken up by the netmask. Remember that a multicast address is a Class D and has a netmask of 255.255.255.255, which means its length is 4. Max group_prefix multicast addresses supported in pimd is 255. After this comes: switch_data_threshold rate rvalue interval ivalue This statement defines the threshold at which transmission rates trigger the changeover from the shared tree to the RP tree; starting the line with switch_register_threshold does the opposite in the same format. (See Chapter 2, "Multicast Protocols," for more details on the two PIM-SM trees.) Regardless of which of these you choose, the rvalue stands for the transmission rate in bits per second, and ivalue sets how often to sample the rate in seconds -- with a recommended minimum of five seconds. It's recommended by the pimd programmers to have ivalue the same in both statements. For example, I might end up with the following (these are real IP addresses; don't use them for actual testing purposes): default_source_preference 105 phyint 199.60.103.90 disable phyint 199.60.103.91 preference 1029 phyint 199.60.103.92 preference 1024 cand_rp 199.60.103.91 cand_bootstrap_router 199.60.103.92 group_prefix 199.60.103.0 masklen 4 switch_data_threshold rate 60000 interval 10 switch_register_threshold rate 60000 interval 10 Running pimd ------------ After you've set up the configuration file, you're ready to actually run the PIM-SM daemon, pimd. As usual, we tend to recommend that you run this by hand for testing purposes and then later add the daemon, with any startup flags it needs, to your system's startup scripts. The format for running this daemon is: pimd -c file -d level1,...,levelN Both of the flags with their values are optional: * -c file. Utilize the specified configuration file rather than the default, /etc/pimd.conf. * -d level1,...,levelN. Specifies the debug level(s) to utilize when running this daemon. Type pimd -h for a full list of these levels. pimd-2.1.8/pim_proto.c0000644000000000000000000040223711700261371011523 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: pim_proto.c,v 1.47 2003/05/28 22:57:16 pavlin Exp $ */ #include #include "defs.h" /* * Local functions definitions. */ static int parse_pim_hello (char *pim_message, size_t datalen, u_int32 src, u_int16 *holdtime); static int send_pim_register_stop (u_int32 reg_src, u_int32 reg_dst, u_int32 inner_source, u_int32 inner_grp); static build_jp_message_t *get_jp_working_buff (void); static void return_jp_working_buff (pim_nbr_entry_t *pim_nbr); static void pack_jp_message (pim_nbr_entry_t *pim_nbr); static void send_jp_message (pim_nbr_entry_t *pim_nbr); static int compare_metrics (u_int32 local_preference, u_int32 local_metric, u_int32 local_address, u_int32 remote_preference, u_int32 remote_metric, u_int32 remote_address); build_jp_message_t *build_jp_message_pool; int build_jp_message_pool_counter; /************************************************************************ * PIM_HELLO ************************************************************************/ int receive_pim_hello(u_int32 src, u_int32 dst __attribute__((unused)), char *pim_message, size_t datalen) { vifi_t vifi; struct uvif *v; pim_nbr_entry_t *nbr, *prev_nbr, *new_nbr; u_int16 holdtime = 0; int bsr_length; u_int8 *data_ptr __attribute__((unused)); srcentry_t *srcentry_ptr; mrtentry_t *mrtentry_ptr; /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; if ((vifi = find_vif_direct(src)) == NO_VIF) { /* Either a local vif or somehow received PIM_HELLO from * non-directly connected router. Ignore it. */ if (local_address(src) == NO_VIF) logit(LOG_INFO, 0, "Ignoring PIM_HELLO from non-neighbor router %s", inet_fmt(src, s1, sizeof(s1))); return FALSE; } v = &uvifs[vifi]; if (v->uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER)) return FALSE; /* Shoudn't come on this interface */ data_ptr = (u_int8 *)(pim_message + sizeof(pim_header_t)); /* Get the Holdtime (in seconds) from the message. Return if error. */ if (parse_pim_hello(pim_message, datalen, src, &holdtime) == FALSE) return FALSE; IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER) { logit(LOG_DEBUG, 0, "PIM HELLO holdtime from %s is %u", inet_fmt(src, s1, sizeof(s1)), holdtime); } for (prev_nbr = (pim_nbr_entry_t *)NULL, nbr = v->uv_pim_neighbors; nbr != (pim_nbr_entry_t *)NULL; prev_nbr = nbr, nbr = nbr->next) { /* The PIM neighbors are sorted in decreasing order of the * network addresses (note that to be able to compare them * correctly we must translate the addresses in host order. */ if (ntohl(src) < ntohl(nbr->address)) continue; if (src == nbr->address) { /* We already have an entry for this host */ if (0 == holdtime) { /* Looks like we have a nice neighbor who is going down * and wants to inform us by sending "holdtime=0". Thanks * buddy and see you again! */ logit(LOG_INFO, 0, "PIM HELLO received: neighbor %s going down", inet_fmt(src, s1, sizeof(s1))); delete_pim_nbr(nbr); return TRUE; } SET_TIMER(nbr->timer, holdtime); return TRUE; } else { /* * No entry for this neighbor. Exit the loop and create an * entry for it. */ break; } } /* * This is a new neighbor. Create a new entry for it. * It must be added right after `prev_nbr` */ new_nbr = (pim_nbr_entry_t *)calloc(1, sizeof(pim_nbr_entry_t)); if (!new_nbr) logit(LOG_ERR, 0, "Ran out of memory in receive_pim_hello()"); new_nbr->address = src; new_nbr->vifi = vifi; SET_TIMER(new_nbr->timer, holdtime); new_nbr->build_jp_message = (build_jp_message_t *)NULL; new_nbr->next = nbr; new_nbr->prev = prev_nbr; if (prev_nbr != (pim_nbr_entry_t *)NULL) prev_nbr->next = new_nbr; else v->uv_pim_neighbors = new_nbr; if (new_nbr->next != (pim_nbr_entry_t *)NULL) new_nbr->next->prev = new_nbr; v->uv_flags &= ~VIFF_NONBRS; v->uv_flags |= VIFF_PIM_NBR; /* Since a new neighbour has come up, let it know your existence */ /* XXX: TODO: not in the spec, * but probably should send the message after a short random period? */ send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME); if (v->uv_flags & VIFF_DR) { /* * If I am the current DR on that interface, so * send an RP-Set message to the new neighbor. */ if ((bsr_length = create_pim_bootstrap_message(pim_send_buf))) send_pim_unicast(pim_send_buf, v->uv_lcl_addr, src, PIM_BOOTSTRAP, bsr_length); /* The router with highest network address is the elected DR */ if (ntohl(v->uv_lcl_addr) < ntohl(src)) { /* I was the DR, but not anymore. Remove all register_vif from * oif list for all directly connected sources (for vifi). */ /* TODO: XXX: first entry is not used! */ for (srcentry_ptr = srclist->next; srcentry_ptr != (srcentry_t *)NULL; srcentry_ptr = srcentry_ptr->next) { /* If not directly connected source for vifi */ if ((srcentry_ptr->incoming != vifi) || (srcentry_ptr->upstream != (pim_nbr_entry_t *)NULL)) continue; for (mrtentry_ptr = srcentry_ptr->mrtlink; mrtentry_ptr != (mrtentry_t *)NULL; mrtentry_ptr = mrtentry_ptr->srcnext) { if (!(mrtentry_ptr->flags & MRTF_SG)) continue; /* This is not (S,G) entry */ /* Remove the register oif */ VIFM_CLR(reg_vif_num, mrtentry_ptr->joined_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } } v->uv_flags &= ~VIFF_DR; } } /* * TODO: XXX: does a new neighbor change any routing entries info? * Need to trigger joins? */ IF_DEBUG(DEBUG_PIM_HELLO) dump_vifs(stderr); /* Show we got a new neighbor */ return TRUE; } void delete_pim_nbr(pim_nbr_entry_t *nbr_delete) { srcentry_t *srcentry_ptr; srcentry_t *srcentry_ptr_next; mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_srcs; grpentry_t *grpentry_ptr; pim_nbr_entry_t *new_nbr __attribute__((unused)); cand_rp_t *cand_rp_ptr; rp_grp_entry_t *rp_grp_entry_ptr; rpentry_t *rpentry_ptr; struct uvif *v; v = &uvifs[nbr_delete->vifi]; /* Delete the entry from the pim_nbrs chain */ if (nbr_delete->prev != (pim_nbr_entry_t *)NULL) nbr_delete->prev->next = nbr_delete->next; else v->uv_pim_neighbors = nbr_delete->next; if (nbr_delete->next != (pim_nbr_entry_t *)NULL) nbr_delete->next->prev = nbr_delete->prev; return_jp_working_buff(nbr_delete); if (v->uv_pim_neighbors == (pim_nbr_entry_t *)NULL) { /* This was our last neighbor. */ v->uv_flags &= ~VIFF_PIM_NBR; v->uv_flags |= (VIFF_NONBRS | VIFF_DR); } else { if (ntohl(v->uv_lcl_addr) > ntohl(v->uv_pim_neighbors->address)) /* The first address is the new potential remote * DR address, but the local address is the winner. */ v->uv_flags |= VIFF_DR; } /* Update the source entries */ for (srcentry_ptr = srclist; srcentry_ptr != (srcentry_t *)NULL; srcentry_ptr = srcentry_ptr_next) { srcentry_ptr_next = srcentry_ptr->next; if (srcentry_ptr->upstream != nbr_delete) continue; /* Reset the next hop (PIM) router */ if (set_incoming(srcentry_ptr, PIM_IIF_SOURCE) == FALSE) { /* Coudn't reset it. Sorry, the hext hop router toward that * source is probably not a PIM router, or cannot find route * at all, hence I cannot handle this source and have to * delete it. */ delete_srcentry(srcentry_ptr); } else if (srcentry_ptr->upstream != (pim_nbr_entry_t *)NULL) { /* Ignore the local or directly connected sources */ /* Browse all MRT entries for this source and reset the * upstream router. Note that the upstream router is not always * toward the source: it could be toward the RP for example. */ new_nbr = srcentry_ptr->upstream; for (mrtentry_ptr = srcentry_ptr->mrtlink; mrtentry_ptr != (mrtentry_t *)NULL; mrtentry_ptr = mrtentry_ptr->srcnext) { if (!(mrtentry_ptr->flags & MRTF_RP)) { mrtentry_ptr->upstream = srcentry_ptr->upstream; mrtentry_ptr->metric = srcentry_ptr->metric; mrtentry_ptr->preference = srcentry_ptr->preference; change_interfaces(mrtentry_ptr, srcentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } } } } /* Update the RP entries */ for (cand_rp_ptr = cand_rp_list; cand_rp_ptr != (cand_rp_t *)NULL; cand_rp_ptr = cand_rp_ptr->next) { if (cand_rp_ptr->rpentry->upstream != nbr_delete) continue; rpentry_ptr = cand_rp_ptr->rpentry; /* Reset the RP entry iif */ /* TODO: check if error setting the iif! */ if (local_address(rpentry_ptr->address) == NO_VIF) set_incoming(rpentry_ptr, PIM_IIF_RP); else { rpentry_ptr->incoming = reg_vif_num; rpentry_ptr->upstream = (pim_nbr_entry_t *)NULL; } mrtentry_ptr = rpentry_ptr->mrtlink; if (mrtentry_ptr != (mrtentry_t *)NULL) { mrtentry_ptr->upstream = rpentry_ptr->upstream; mrtentry_ptr->metric = rpentry_ptr->metric; mrtentry_ptr->preference = rpentry_ptr->preference; change_interfaces(mrtentry_ptr, rpentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } /* Update the group entries for this RP */ for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { mrtentry_ptr = grpentry_ptr->grp_route; if (mrtentry_ptr != (mrtentry_t *)NULL) { mrtentry_ptr->upstream = rpentry_ptr->upstream; mrtentry_ptr->metric = rpentry_ptr->metric; mrtentry_ptr->preference = rpentry_ptr->preference; change_interfaces(mrtentry_ptr, rpentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } /* Update only the (S,G)RPbit entries for this group */ for (mrtentry_srcs = grpentry_ptr->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { if (mrtentry_srcs->flags & MRTF_RP) { mrtentry_ptr->upstream = rpentry_ptr->upstream; mrtentry_ptr->metric = rpentry_ptr->metric; mrtentry_ptr->preference = rpentry_ptr->preference; change_interfaces(mrtentry_srcs, rpentry_ptr->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, 0); } } } } } free((char *)nbr_delete); } /* TODO: simplify it! */ static int parse_pim_hello(char *pim_message, size_t datalen, u_int32 src, u_int16 *holdtime) { u_int8 *pim_hello_message; u_int8 *data_ptr; u_int16 option_type; u_int16 option_length; int holdtime_received_ok = FALSE; int option_total_length; pim_hello_message = (u_int8 *)(pim_message + sizeof(pim_header_t)); datalen -= sizeof(pim_header_t); for ( ; datalen >= sizeof(pim_hello_t); ) { /* Ignore any data if shorter than (pim_hello header) */ data_ptr = pim_hello_message; GET_HOSTSHORT(option_type, data_ptr); GET_HOSTSHORT(option_length, data_ptr); if (option_type == PIM_MESSAGE_HELLO_HOLDTIME) { if (PIM_MESSAGE_HELLO_HOLDTIME_LENGTH != option_length) { IF_DEBUG(DEBUG_PIM_HELLO) { logit(LOG_DEBUG, 0, "PIM HELLO Holdtime from %s: invalid OptionLength = %u", inet_fmt(src, s1, sizeof(s1)), option_length); } return FALSE; } GET_HOSTSHORT(*holdtime, data_ptr); holdtime_received_ok = TRUE; } else { /* Ignore any unknown options */ } /* Move to the next option */ /* XXX: TODO: If we are padding to the end of the 32 bit boundary, * use the first method to move to the next option, otherwise * simply (sizeof(pim_hello_t) + option_length). */ #ifdef BOUNDARY_32_BIT option_total_length = (sizeof(pim_hello_t) + (option_length & ~0x3) + ((option_length & 0x3) ? 4 : 0)); #else option_total_length = (sizeof(pim_hello_t) + option_length); #endif /* BOUNDARY_32_BIT */ datalen -= option_total_length; pim_hello_message += option_total_length; } return holdtime_received_ok; } int send_pim_hello(struct uvif *v, u_int16 holdtime) { char *buf; u_int8 *data_ptr; int datalen; buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t); data_ptr = (u_int8 *)buf; PUT_HOSTSHORT(PIM_MESSAGE_HELLO_HOLDTIME, data_ptr); PUT_HOSTSHORT(PIM_MESSAGE_HELLO_HOLDTIME_LENGTH, data_ptr); PUT_HOSTSHORT(holdtime, data_ptr); datalen = data_ptr - (u_int8 *)buf; send_pim(pim_send_buf, v->uv_lcl_addr, allpimrouters_group, PIM_HELLO, datalen); SET_TIMER(v->uv_pim_hello_timer, PIM_TIMER_HELLO_PERIOD); return TRUE; } /************************************************************************ * PIM_REGISTER ************************************************************************/ /* TODO: XXX: IF THE BORDER BIT IS SET, THEN * FORWARD THE WHOLE PACKET FROM USER SPACE * AND AT THE SAME TIME IGNORE ANY CACHE_MISS * SIGNALS FROM THE KERNEL. */ int receive_pim_register(u_int32 reg_src, u_int32 reg_dst, char *pim_message, size_t datalen) { u_int32 inner_src, inner_grp; pim_register_t *register_p; struct ip *ip; u_int32 borderBit, nullRegisterBit; mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_ptr2; vifbitmap_t oifs; /* * Message length validation. * This is suppose to be done in the kernel, but some older kernel * versions do not pefrorm the check for the NULL register messages. */ if (datalen < sizeof(pim_header_t) + sizeof(pim_register_t) + sizeof(struct ip)) { IF_DEBUG(DEBUG_PIM_REGISTER) { logit(LOG_INFO, 0, "PIM register: short packet (len = %d) from %s", datalen, inet_fmt(reg_src, s1, sizeof(s1))); } return FALSE; } /* * XXX: For PIM_REGISTER the checksum does not include * the inner IP packet. However, some older routers might * create the checksum over the whole packet. Hence, * verify the checksum over the first 8 bytes, and if fails, * then over the whole Register */ if ((inet_cksum((u_int16 *)pim_message, sizeof(pim_header_t) + sizeof(pim_register_t))) && (inet_cksum((u_int16 *)pim_message, datalen))) { IF_DEBUG(DEBUG_PIM_REGISTER) { logit(LOG_DEBUG, 0, "PIM REGISTER from DR %s: invalid PIM header checksum", inet_fmt(reg_src, s1, sizeof(s1))); } return FALSE; } register_p = (pim_register_t *)(pim_message + sizeof(pim_header_t)); borderBit = ntohl(register_p->reg_flags) & PIM_MESSAGE_REGISTER_BORDER_BIT; nullRegisterBit = ntohl(register_p->reg_flags) & PIM_MESSAGE_REGISTER_NULL_REGISTER_BIT; /* initialize the pointer to the encapsulated packet */ ip = (struct ip *)(register_p + 1); /* check the IP version (especially for the NULL register...see above) */ if (ip->ip_v != IPVERSION && (! nullRegisterBit)) { IF_DEBUG(DEBUG_PIM_REGISTER) logit(LOG_INFO, 0, "PIM register: incorrect IP version (%d) of the inner packet from %s", ip->ip_v, inet_fmt(reg_src, s1, sizeof(s1))); return FALSE; } /* We are keeping all addresses in network order, so no need for ntohl()*/ inner_src = ip->ip_src.s_addr; inner_grp = ip->ip_dst.s_addr; /* * inner_src and inner_grp must be valid IP unicast and multicast address * respectively. XXX: not in the spec. */ if ((!inet_valid_host(inner_src)) || (!IN_MULTICAST(ntohl(inner_grp)))) { if (!inet_valid_host(inner_src)) { logit(LOG_WARNING, 0, "Inner source address of register message by %s is invalid: %s", inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(inner_src, s2, sizeof(s2))); } if (!IN_MULTICAST(ntohl(inner_grp))) { logit(LOG_WARNING, 0, "Inner group address of register message by %s is invalid: %s", inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(inner_grp, s2, sizeof(s2))); } send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return FALSE; } mrtentry_ptr = find_route(inner_src, inner_grp, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); if (!mrtentry_ptr) { /* No routing entry. Send REGISTER_STOP and return. */ IF_DEBUG(DEBUG_PIM_REGISTER) { logit(LOG_DEBUG, 0, "No routing entry for source %s and/or group %s" , inet_fmt(inner_src, s1, sizeof(s1)), inet_fmt(inner_grp, s2, sizeof(s2))); } /* TODO: XXX: shoudn't be inner_src=INADDR_ANY? Not in the spec. */ send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } /* XXX: not in the spec: check if I am the RP for that group */ if ((local_address(reg_dst) == NO_VIF) || (check_mrtentry_rp(mrtentry_ptr, reg_dst) == FALSE)) { send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) found */ /* TODO: check the timer again */ SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT); /* restart timer */ if (!(mrtentry_ptr->flags & MRTF_SPT)) { /* The SPT bit is not set */ if (!nullRegisterBit) { calc_oifs(mrtentry_ptr, &oifs); if (VIFM_ISEMPTY(oifs) && (mrtentry_ptr->incoming == reg_vif_num)) { send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } /* * TODO: XXX: BUG!!! * The data will be forwarded by the kernel MFC!!! * Need to set a special flag for this routing entry so after * a cache miss occur, the multicast packet will be forwarded * from user space and won't install entry in the kernel MFC. * The problem is that the kernel MFC doesn't know the * PMBR address and simply sets the multicast forwarding * cache to accept/forward all data coming from the * register_vif. */ if (borderBit) { if (mrtentry_ptr->pmbr_addr != reg_src) { send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } } return TRUE; } /* TODO: XXX: if NULL_REGISTER and has (S,G) with SPT=0, then..?*/ return TRUE; } else { /* The SPT bit is set */ send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } } if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR)) { if (borderBit) { /* Create (S,G) state. The oifs will be the copied from the * existing (*,G) or (*,*,RP) entry. */ mrtentry_ptr2 = find_route(inner_src, inner_grp, MRTF_SG, CREATE); if (mrtentry_ptr2) { mrtentry_ptr2->pmbr_addr = reg_src; /* Clear the SPT flag */ mrtentry_ptr2->flags &= ~(MRTF_SPT | MRTF_NEW); SET_TIMER(mrtentry_ptr2->timer, PIM_DATA_TIMEOUT); /* TODO: explicitly call the Join/Prune send function? */ FIRE_TIMER(mrtentry_ptr2->jp_timer); /* Send the Join immediately */ /* TODO: explicitly call this function? send_pim_join_prune(mrtentry_ptr2->upstream->vifi, mrtentry_ptr2->upstream, PIM_JOIN_PRUNE_HOLDTIME); */ } } } if (mrtentry_ptr->flags & MRTF_WC) { /* (*,G) entry */ calc_oifs(mrtentry_ptr, &oifs); if (VIFM_ISEMPTY(oifs)) { send_pim_register_stop(reg_dst, reg_src, inner_grp, INADDR_ANY_N); return FALSE; } /* XXX: TODO: check with the spec again */ else { if (!nullRegisterBit) { /* Install cache entry in the kernel */ /* TODO: XXX: probably redundant here, because the * decapsulated mcast packet in the kernel will * result in CACHE_MISS */ u_int32 mfc_source = inner_src; #ifdef KERNEL_MFC_WC_G if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG)) mfc_source = INADDR_ANY_N; #endif /* KERNEL_MFC_WC_G */ add_kernel_cache(mrtentry_ptr, mfc_source, inner_grp, 0); k_chg_mfc(igmp_socket, mfc_source, inner_grp, mrtentry_ptr->incoming, mrtentry_ptr->oifs, mrtentry_ptr->group->rpaddr); return TRUE; } } return TRUE; } if (mrtentry_ptr->flags & MRTF_PMBR) { /* (*,*,RP) entry */ if (!nullRegisterBit) { u_int32 mfc_source = inner_src; /* XXX: have to create either (S,G) or (*,G). * The choice below is (*,G) */ mrtentry_ptr2 = find_route(INADDR_ANY_N, inner_grp, MRTF_WC, CREATE); if (!mrtentry_ptr2) return FALSE; if (mrtentry_ptr2->flags & MRTF_NEW) { /* TODO: something else? Have the feeling sth is missing */ mrtentry_ptr2->flags &= ~MRTF_NEW; /* TODO: XXX: copy the timer from the (*,*,RP) entry? */ COPY_TIMER(mrtentry_ptr->timer, mrtentry_ptr2->timer); } /* Install cache entry in the kernel */ #ifdef KERNEL_MFC_WC_G if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG)) mfc_source = INADDR_ANY_N; #endif /* KERNEL_MFC_WC_G */ add_kernel_cache(mrtentry_ptr, mfc_source, inner_grp, 0); k_chg_mfc(igmp_socket, mfc_source, inner_grp, mrtentry_ptr->incoming, mrtentry_ptr->oifs, mrtentry_ptr2->group->rpaddr); return TRUE; } } /* Shoudn't happen: invalid routing entry? */ /* XXX: TODO: shoudn't be inner_src=INADDR_ANY? Not in the spec. */ send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src); return TRUE; } int send_pim_register(char *packet) { struct ip *ip; u_int32 source, group; vifi_t vifi; rpentry_t *rpentry_ptr; mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_ptr2; u_int32 reg_src, reg_dst; int pktlen = 0; char *buf; ip = (struct ip *)packet; source = ip->ip_src.s_addr; group = ip->ip_dst.s_addr; if ((vifi = find_vif_direct_local(source)) == NO_VIF) return FALSE; if (!(uvifs[vifi].uv_flags & VIFF_DR)) return FALSE; /* I am not the DR for that subnet */ rpentry_ptr = rp_match(group); if (!rpentry_ptr) return FALSE; /* No RP for this group */ if (local_address(rpentry_ptr->address) != NO_VIF) { /* TODO: XXX: not sure it is working! */ return FALSE; /* I am the RP for this group */ } mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE); if (!mrtentry_ptr) return FALSE; /* Cannot create (S,G) state */ if (mrtentry_ptr->flags & MRTF_NEW) { /* A new entry */ mrtentry_ptr->flags &= ~MRTF_NEW; RESET_TIMER(mrtentry_ptr->rs_timer); /* Reset the Register-Suppression timer */ mrtentry_ptr2 = mrtentry_ptr->group->grp_route; if (!mrtentry_ptr2) mrtentry_ptr2 = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (mrtentry_ptr2) { FIRE_TIMER(mrtentry_ptr2->jp_timer); /* Timeout the Join/Prune timer */ /* TODO: explicitly call this function? send_pim_join_prune(mrtentry_ptr2->upstream->vifi, mrtentry_ptr2->upstream, PIM_JOIN_PRUNE_HOLDTIME); */ } } /* Restart the (S,G) Entry-timer */ SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT); IF_TIMER_NOT_SET(mrtentry_ptr->rs_timer) { /* The Register-Suppression Timer is not running. * Encapsulate the data and send to the RP. */ #ifdef PIM_OLD_KERNEL /* TODO: verify again! */ /* recompute the checksum; as checksum may fail when decapsulating * at the RP if we don't do this. */ #ifdef old_Linux ip->ip_csum = 0; #else ip->ip_sum = 0; #endif /* old_Linux */ #ifndef RAW_INPUT_IS_RAW /* TODO: htons??? */ ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); #endif /* !RAW_INPUT_IS_RAW */ #ifdef old_Linux ip->ip_csum = inet_cksum((u_int16 *)ip, ip->ip_hl << 2); #else ip->ip_sum = inet_cksum((u_int16 *)ip, ip->ip_hl << 2); #endif /* old_Linux */ #endif /* PIM_OLD_KERNEL */ buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t); memset(buf, 0, sizeof(pim_register_t)); /* No flags set */ buf += sizeof(pim_register_t); /* Copy the data packet at the back of the register packet */ /* TODO: check pktlen. ntohs? */ pktlen = ntohs(ip->ip_len); memcpy(buf, ip, pktlen); pktlen += sizeof(pim_register_t); reg_src = uvifs[vifi].uv_lcl_addr; reg_dst = mrtentry_ptr->group->rpaddr; send_pim_unicast(pim_send_buf, reg_src, reg_dst, PIM_REGISTER, pktlen); return TRUE; } return TRUE; } int send_pim_null_register(mrtentry_t *mrtentry_ptr) { struct ip *ip; pim_register_t *pim_register; int pktlen =0; vifi_t vifi; u_int32 reg_source, dest; /* No directly connected source; no local address */ if ((vifi = find_vif_direct_local(mrtentry_ptr->source->address))== NO_VIF) return FALSE; pim_register = (pim_register_t *)(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t)); memset(pim_register, 0, sizeof(pim_register_t)); pim_register->reg_flags = htonl(pim_register->reg_flags | PIM_MESSAGE_REGISTER_NULL_REGISTER_BIT); ip = (struct ip *)(pim_register + 1); /* set src/dst in dummy hdr */ ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); ip->ip_tos = 0; ip->ip_id = 0; ip->ip_off = 0; ip->ip_p = IPPROTO_UDP; /* XXX: bogus */ ip->ip_len = htons(sizeof(struct ip)); ip->ip_ttl = MINTTL; /* TODO: XXX: check whether need to setup the ttl */ ip->ip_src.s_addr = mrtentry_ptr->source->address; ip->ip_dst.s_addr = mrtentry_ptr->group->group; #ifdef old_Linux ip->ip_csum = 0; ip->ip_csum = inet_cksum((u_int16 *)ip, sizeof(struct ip)); #else ip->ip_sum = 0; ip->ip_sum = inet_cksum((u_int16 *)ip, sizeof(struct ip)); #endif /* old_Linux */ /* include the dummy ip header */ pktlen = sizeof(pim_register_t) + sizeof(struct ip); dest = mrtentry_ptr->group->rpaddr; reg_source = uvifs[vifi].uv_lcl_addr; send_pim_unicast(pim_send_buf, reg_source, dest, PIM_REGISTER, pktlen); return TRUE; } /************************************************************************ * PIM_REGISTER_STOP ************************************************************************/ int receive_pim_register_stop(u_int32 reg_src, u_int32 reg_dst, char *pim_message, size_t datalen) { pim_register_stop_t *pim_regstop_p; pim_encod_grp_addr_t encod_grp; pim_encod_uni_addr_t encod_unisrc; u_int8 *data_ptr; mrtentry_t *mrtentry_ptr; vifbitmap_t pruned_oifs; /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; pim_regstop_p = (pim_register_stop_t *)(pim_message + sizeof(pim_header_t)); data_ptr = (u_int8 *)&pim_regstop_p->encod_grp; GET_EGADDR(&encod_grp, data_ptr); GET_EUADDR(&encod_unisrc, data_ptr); IF_DEBUG(DEBUG_PIM_REGISTER) { logit(LOG_DEBUG, 0, "Received PIM_REGISTER_STOP from RP %s to %s for src = %s and group = %s", inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(reg_dst, s2, sizeof(s2)), inet_fmt(encod_unisrc.unicast_addr, s3, sizeof(s3)), inet_fmt(encod_grp.mcast_addr, s4, sizeof(s4))); } /* TODO: apply the group mask and do register_stop for all grp addresses */ /* TODO: check for SourceAddress == 0 */ mrtentry_ptr = find_route(encod_unisrc.unicast_addr, encod_grp.mcast_addr, MRTF_SG, DONT_CREATE); if (!mrtentry_ptr) return FALSE; /* XXX: not in the spec: check if the PIM_REGISTER_STOP originator is * really the RP */ if (check_mrtentry_rp(mrtentry_ptr, reg_src) == FALSE) return FALSE; /* restart the Register-Suppression timer */ SET_TIMER(mrtentry_ptr->rs_timer, (0.5 * PIM_REGISTER_SUPPRESSION_TIMEOUT) + (RANDOM() % (PIM_REGISTER_SUPPRESSION_TIMEOUT + 1))); /* Prune the register_vif from the outgoing list */ VIFM_COPY(mrtentry_ptr->pruned_oifs, pruned_oifs); VIFM_SET(reg_vif_num, pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); return TRUE; } /* TODO: optional rate limiting is not implemented yet */ /* Unicasts a REGISTER_STOP message to the DR */ static int send_pim_register_stop(u_int32 reg_src, u_int32 reg_dst, u_int32 inner_grp, u_int32 inner_src) { char *buf; u_int8 *data_ptr; buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t); data_ptr = (u_int8 *)buf; PUT_EGADDR(inner_grp, SINGLE_GRP_MSKLEN, 0, data_ptr); PUT_EUADDR(inner_src, data_ptr); send_pim_unicast(pim_send_buf, reg_src, reg_dst, PIM_REGISTER_STOP, data_ptr - (u_int8 *)buf); return TRUE; } /************************************************************************ * PIM_JOIN_PRUNE ************************************************************************/ int join_or_prune(mrtentry_t *mrtentry_ptr, pim_nbr_entry_t *upstream_router) { vifbitmap_t entry_oifs; mrtentry_t *mrtentry_grp; if (!mrtentry_ptr || !upstream_router) return PIM_ACTION_NOTHING; calc_oifs(mrtentry_ptr, &entry_oifs); if (mrtentry_ptr->flags & (MRTF_PMBR | MRTF_WC)) { /* (*,*,RP) or (*,G) entry */ /* The (*,*,RP) or (*,G) J/P messages are sent only toward the RP */ if (upstream_router != mrtentry_ptr->upstream) return PIM_ACTION_NOTHING; /* TODO: XXX: Can we have (*,*,RP) prune? */ if (VIFM_ISEMPTY(entry_oifs)) { /* NULL oifs */ if (!(uvifs[mrtentry_ptr->incoming].uv_flags & VIFF_DR)) /* I am not the DR for that subnet. */ return PIM_ACTION_PRUNE; if (VIFM_ISSET(mrtentry_ptr->incoming, mrtentry_ptr->leaves)) /* I am the DR and have local leaves */ return PIM_ACTION_JOIN; /* Probably the last local member hast timeout */ return PIM_ACTION_PRUNE; } return PIM_ACTION_JOIN; } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) entry */ /* TODO: check again */ if (mrtentry_ptr->upstream == upstream_router) { if (!(mrtentry_ptr->flags & MRTF_RP)) { /* Upstream router toward S */ if (VIFM_ISEMPTY(entry_oifs)) { if (mrtentry_ptr->group->active_rp_grp && mrtentry_ptr->group->rpaddr == my_cand_rp_address) { /* (S,G) at the RP. Don't send Join/Prune * (see the end of Section 3.3.2) */ return PIM_ACTION_NOTHING; } return PIM_ACTION_PRUNE; } else { return PIM_ACTION_JOIN; } } else { /* Upstream router toward RP */ if (VIFM_ISEMPTY(entry_oifs)) return PIM_ACTION_PRUNE; } } /* Looks like the case when the upstream router toward S is * different from the upstream router toward RP */ if (!mrtentry_ptr->group->active_rp_grp) return PIM_ACTION_NOTHING; mrtentry_grp = mrtentry_ptr->group->grp_route; if (!mrtentry_grp) { mrtentry_grp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; if (!mrtentry_grp) return PIM_ACTION_NOTHING; } if (mrtentry_grp->upstream != upstream_router) return PIM_ACTION_NOTHING; /* XXX: shoudn't happen */ if (!(mrtentry_ptr->flags & MRTF_RP) && (mrtentry_ptr->flags & MRTF_SPT)) return PIM_ACTION_PRUNE; } return PIM_ACTION_NOTHING; } /* TODO: when parsing, check if we go beyong message size */ /* TODO: too long, simplify it! */ #define PIM_JOIN_PRUNE_MINLEN (4 + PIM_ENCODE_UNI_ADDR_LEN + 4) int receive_pim_join_prune(u_int32 src, u_int32 dst __attribute__((unused)), char *pim_message, int datalen) { vifi_t vifi; struct uvif *v; pim_encod_uni_addr_t uni_target_addr; pim_encod_grp_addr_t encod_group; pim_encod_src_addr_t encod_src; u_int8 *data_ptr; u_int8 *data_ptr_start; u_int8 *data_ptr_group_end; u_int8 num_groups; u_int8 num_groups_tmp; int star_star_rp_found; u_int16 holdtime; u_int16 num_j_srcs; u_int16 num_j_srcs_tmp; u_int16 num_p_srcs; u_int32 source; u_int32 group; u_int32 s_mask; u_int32 g_mask; u_int8 s_flags; u_int8 reserved __attribute__((unused)); rpentry_t *rpentry_ptr; mrtentry_t *mrtentry_ptr; mrtentry_t *mrtentry_srcs; mrtentry_t *mrtentry_rp; grpentry_t *grpentry_ptr; u_int16 jp_value; pim_nbr_entry_t *upstream_router; int my_action; int ignore_group; rp_grp_entry_t *rp_grp_entry_ptr; u_int8 *data_ptr_group_j_start; u_int8 *data_ptr_group_p_start; if ((vifi = find_vif_direct(src)) == NO_VIF) { /* Either a local vif or somehow received PIM_JOIN_PRUNE from * non-directly connected router. Ignore it. */ if (local_address(src) == NO_VIF) { logit(LOG_INFO, 0, "Ignoring PIM_JOIN_PRUNE from non-neighbor router %s", inet_fmt(src, s1, sizeof(s1))); } return FALSE; } /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; v = &uvifs[vifi]; if (uvifs[vifi].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_NONBRS | VIFF_REGISTER)) return FALSE; /* Shoudn't come on this interface */ /* sanity check for the minimum length */ if (datalen < PIM_JOIN_PRUNE_MINLEN) { logit(LOG_NOTICE, 0, "receive_pim_join_prune: Join/Prune message size(%u) is too short from %s on %s", datalen, inet_fmt(src, s1, sizeof(s1)), v->uv_name); return FALSE; } /* * TODO: Sanity check for the message length through all the groups * (see Kame's pim6sd). */ data_ptr = (u_int8 *)(pim_message + sizeof(pim_header_t)); /* Get the target address */ GET_EUADDR(&uni_target_addr, data_ptr); GET_BYTE(reserved, data_ptr); GET_BYTE(num_groups, data_ptr); if (num_groups == 0) return FALSE; /* No indication for groups in the message */ GET_HOSTSHORT(holdtime, data_ptr); if (uni_target_addr.unicast_addr != v->uv_lcl_addr) { /* if I am not the targer of the join message */ /* Join/Prune suppression code. This either modifies the J/P timers * or triggers an overriding Join. */ /* Note that if we have (S,G) prune and (*,G) Join, we must send * them in the same message. We don't bother to modify both timers * here. The Join/Prune sending function will take care of that. */ upstream_router = find_pim_nbr(uni_target_addr.unicast_addr); if (!upstream_router) return FALSE; /* I have no such neighbor */ while (num_groups--) { GET_EGADDR(&encod_group, data_ptr); GET_HOSTSHORT(num_j_srcs, data_ptr); GET_HOSTSHORT(num_p_srcs, data_ptr); MASKLEN_TO_MASK(encod_group.masklen, g_mask); group = encod_group.mcast_addr; if (!IN_MULTICAST(ntohl(group))) { data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; /* Ignore this group and jump to the next */ } if ((ntohl(group) == CLASSD_PREFIX) && (encod_group.masklen == STAR_STAR_RP_MSKLEN)) { /* (*,*,RP) Join suppression */ while(num_j_srcs--) { GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) { /* This is the RP address. */ rpentry_ptr = rp_find(source); if (!rpentry_ptr) continue; /* Don't have such RP. Ignore */ mrtentry_rp = rpentry_ptr->mrtlink; my_action = join_or_prune(mrtentry_rp, upstream_router); if (my_action != PIM_ACTION_JOIN) continue; /* Check the holdtime */ /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_rp->jp_timer > holdtime) continue; if ((mrtentry_rp->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr))) continue; /* Set the Join/Prune suppression timer for this * routing entry by increasing the current * Join/Prune timer. */ jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_rp->jp_timer < jp_value) SET_TIMER(mrtentry_rp->jp_timer, jp_value); } } /* num_j_srcs */ while (num_p_srcs--) { /* TODO: XXX: Can we have (*,*,RP) prune message? * Not in the spec, but anyway, the code below * can handle them: either suppress * the local (*,*,RP) prunes or override the prunes by * sending (*,*,RP) and/or (*,G) and/or (S,G) Join. */ GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) { /* This is the RP address. */ rpentry_ptr = rp_find(source); if (!rpentry_ptr) continue; /* Don't have such RP. Ignore */ mrtentry_rp = rpentry_ptr->mrtlink; my_action = join_or_prune(mrtentry_rp, upstream_router); if (my_action == PIM_ACTION_PRUNE) { /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_rp->jp_timer < holdtime) || ((mrtentry_rp->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))) { /* Suppress the Prune */ jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); if (mrtentry_rp->jp_timer < jp_value) SET_TIMER(mrtentry_rp->jp_timer, jp_value); } } else if (my_action == PIM_ACTION_JOIN) { /* Override the Prune by scheduling a Join */ jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_rp->jp_timer > jp_value) SET_TIMER(mrtentry_rp->jp_timer, jp_value); } /* Check all (*,G) and (S,G) matching to this RP. * If my_action == JOIN, then send a Join and override * the (*,*,RP) Prune. */ for (grpentry_ptr = rpentry_ptr->cand_rp->rp_grp_next->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { my_action = join_or_prune(grpentry_ptr->grp_route, upstream_router); if (my_action == PIM_ACTION_JOIN) { jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (grpentry_ptr->grp_route->jp_timer > jp_value) SET_TIMER(grpentry_ptr->grp_route->jp_timer, jp_value); } for (mrtentry_srcs = grpentry_ptr->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { my_action = join_or_prune(mrtentry_srcs, upstream_router); if (my_action == PIM_ACTION_JOIN) { jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_srcs->jp_timer > jp_value) SET_TIMER(mrtentry_srcs->jp_timer, jp_value); } } /* For all (S,G) */ } /* For all (*,G) */ } } /* num_p_srcs */ continue; /* This was (*,*,RP) suppression */ } /* (*,G) or (S,G) suppression */ /* TODO: XXX: currently, accumulated groups * (i.e. group_masklen < group_address_lengt) are not * implemented. Just need to create a loop and apply the * procedure below for all groups matching the prefix. */ while (num_j_srcs--) { GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) { /* (*,G) JOIN_REQUEST (toward the RP) */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE); if (!mrtentry_ptr) continue; my_action = join_or_prune(mrtentry_ptr, upstream_router); if (my_action != PIM_ACTION_JOIN) continue; /* (*,G) Join suppresion */ if (source != mrtentry_ptr->group->active_rp_grp->rp->rpentry->address) continue; /* The RP address doesn't match. Ignore. */ /* Check the holdtime */ /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->jp_timer > holdtime) continue; if ((mrtentry_ptr->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr))) continue; jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); if (mrtentry_ptr->jp_timer < jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); continue; } /* End of (*,G) Join suppression */ /* (S,G) Join suppresion */ mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE); if (!mrtentry_ptr) continue; my_action = join_or_prune(mrtentry_ptr, upstream_router); if (my_action != PIM_ACTION_JOIN) continue; /* Check the holdtime */ /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->jp_timer > holdtime) continue; if ((mrtentry_ptr->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr))) continue; jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); if (mrtentry_ptr->jp_timer < jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); continue; } /* Prunes suppression */ while (num_p_srcs--) { GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) { /* (*,G) prune suppression */ rpentry_ptr = rp_match(group); if (!rpentry_ptr || (rpentry_ptr->address != source)) continue; /* No such RP or it is different. Ignore */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE); if (!mrtentry_ptr) continue; my_action = join_or_prune(mrtentry_ptr, upstream_router); if (my_action == PIM_ACTION_PRUNE) { /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_ptr->jp_timer < holdtime) || ((mrtentry_ptr->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))) { /* Suppress the Prune */ jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); if (mrtentry_ptr->jp_timer < jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); } } else if (my_action == PIM_ACTION_JOIN) { /* Override the Prune by scheduling a Join */ jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->jp_timer > jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); } /* Check all (S,G) entries for this group. * If my_action == JOIN, then send the Join and override * the (*,G) Prune. */ for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { my_action = join_or_prune(mrtentry_srcs, upstream_router); if (my_action == PIM_ACTION_JOIN) { jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->jp_timer > jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); } } /* For all (S,G) */ continue; /* End of (*,G) prune suppression */ } /* (S,G) prune suppression */ mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE); if (mrtentry_ptr == NULL) continue; my_action = join_or_prune(mrtentry_ptr, upstream_router); if (my_action == PIM_ACTION_PRUNE) { /* Suppress the (S,G) Prune */ /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_ptr->jp_timer < holdtime) || ((mrtentry_ptr->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))) { jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD); if (mrtentry_ptr->jp_timer < jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); } } else if (my_action == PIM_ACTION_JOIN) { /* Override the Prune by scheduling a Join */ jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->jp_timer > jp_value) SET_TIMER(mrtentry_ptr->jp_timer, jp_value); } } /* while (num_p_srcs--) */ } /* while (num_groups--) */ return TRUE; } /* End of Join/Prune suppression code */ /* I am the target of this join, so process the message */ /* The spec says that if there is (*,G) Join, it has priority over * old existing ~(S,G) prunes in the routing table. * However, if the (*,G) Join and the ~(S,G) prune are in * the same message, ~(S,G) has the priority. The spec doesn't say it, * but I think the same is true for (*,*,RP) and ~(S,G) prunes. * * The code below do: * (1) Check the whole message for (*,*,RP) Joins. * (1.1) If found, clean all pruned_oifs for all (*,G) and all (S,G) * for each RP in the list, but do not update the kernel cache. * Then go back to the beginning of the message and start * processing for each group: * (2) Check for Prunes. If no prunes, process the Joins. * (3) If there are Prunes: * (3.1) Scan the Join part for existing (*,G) Join. * (3.1.1) If there is (*,G) Join, clear join interface from * the pruned_oifs for all (S,G), but DO NOT flush the * change to the kernel (by using change_interfaces() * for example) * (3.2) After the pruned_oifs are eventually cleared in (3.1.1), * process the Prune part of the message normally * (setting the prune_oifs and flashing the changes to the (kernel). * (3.3) After the Prune part is processed, process the Join part * normally (by applying any changes to the kernel) * (4) If there were (*,*,RP) Join/Prune, process them. * * If the Join/Prune list is too long, it may result in long processing * overhead. The idea above is not to place any wrong info in the * kernel, because it may result in short-time existing traffic * forwarding on wrong interface. * Hopefully, in the future will find a better way to implement it. */ num_groups_tmp = num_groups; data_ptr_start = data_ptr; star_star_rp_found = FALSE; /* Indicating whether we have (*,*,RP) join */ while (num_groups_tmp--) { /* Search for (*,*,RP) Join */ GET_EGADDR(&encod_group, data_ptr); GET_HOSTSHORT(num_j_srcs, data_ptr); GET_HOSTSHORT(num_p_srcs, data_ptr); group = encod_group.mcast_addr; if ((ntohl(group) != CLASSD_PREFIX) || (encod_group.masklen != STAR_STAR_RP_MSKLEN)) { /* This is not (*,*,RP). Jump to the next group. */ data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; } /* (*,*,RP) found. For each RP and each (*,G) and each (S,G) clear * the pruned oif, but do not update the kernel. */ star_star_rp_found = TRUE; while (num_j_srcs--) { GET_ESADDR(&encod_src, data_ptr); rpentry_ptr = rp_find(encod_src.src_addr); if (rpentry_ptr == (rpentry_t *)NULL) continue; for (rp_grp_entry_ptr = rpentry_ptr->cand_rp->rp_grp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { if (grpentry_ptr->grp_route != (mrtentry_t *)NULL) VIFM_CLR(vifi, grpentry_ptr->grp_route->pruned_oifs); for (mrtentry_ptr = grpentry_ptr->mrtlink; mrtentry_ptr != (mrtentry_t *)NULL; mrtentry_ptr = mrtentry_ptr->grpnext) VIFM_CLR(vifi, mrtentry_ptr->pruned_oifs); } } } data_ptr += (num_p_srcs) * sizeof(pim_encod_src_addr_t); } /* * Start processing the groups. If this is (*,*,RP), skip it, but process * it at the end. */ data_ptr = data_ptr_start; num_groups_tmp = num_groups; while (num_groups_tmp--) { GET_EGADDR(&encod_group, data_ptr); GET_HOSTSHORT(num_j_srcs, data_ptr); GET_HOSTSHORT(num_p_srcs, data_ptr); group = encod_group.mcast_addr; if (!IN_MULTICAST(ntohl(group))) { data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; /* Ignore this group and jump to the next one */ } if ((ntohl(group) == CLASSD_PREFIX) && (encod_group.masklen == STAR_STAR_RP_MSKLEN)) { /* This is (*,*,RP). Jump to the next group. */ data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; } rpentry_ptr = rp_match(group); if (rpentry_ptr == (rpentry_t *)NULL) { data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; } data_ptr_group_j_start = data_ptr; data_ptr_group_p_start = data_ptr + num_j_srcs * sizeof(pim_encod_src_addr_t); data_ptr_group_end = data_ptr + (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); /* Scan the Join part for (*,G) Join and then clear the * particular interface from pruned_oifs for all (S,G). * If the RP address in the Join message is different from * the local match, ignore the whole group. */ num_j_srcs_tmp = num_j_srcs; ignore_group = FALSE; while (num_j_srcs_tmp--) { GET_ESADDR(&encod_src, data_ptr); if ((encod_src.flags & USADDR_RP_BIT) && (encod_src.flags & USADDR_WC_BIT)) { /* This is the RP address, i.e. (*,G) Join. * Check if the RP-mapping is consistent and if "yes", * then Reset the pruned_oifs for all (S,G) entries. */ if (rpentry_ptr->address != encod_src.src_addr) { ignore_group = TRUE; break; } mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE); if (mrtentry_ptr) { for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) VIFM_CLR(vifi, mrtentry_srcs->pruned_oifs); } break; } } if (ignore_group == TRUE) { data_ptr += (num_j_srcs_tmp + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; } data_ptr = data_ptr_group_p_start; /* Process the Prune part first */ while (num_p_srcs--) { GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; if (!(s_flags & (USADDR_WC_BIT | USADDR_RP_BIT))) { /* (S,G) prune sent toward S */ mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE); if (!mrtentry_ptr) continue; /* I don't have (S,G) to prune. Ignore. */ /* If the link is point-to-point, timeout the oif * immediately, otherwise decrease the timer to allow * other downstream routers to override the prune. */ /* TODO: XXX: increase the entry timer? */ if (v->uv_flags & VIFF_POINT_TO_POINT) { FIRE_TIMER(mrtentry_ptr->vif_timers[vifi]); } else { /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] > mrtentry_ptr->vif_deletion_delay[vifi]) SET_TIMER(mrtentry_ptr->vif_timers[vifi], mrtentry_ptr->vif_deletion_delay[vifi]); } IF_TIMER_NOT_SET(mrtentry_ptr->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } continue; } if ((s_flags & USADDR_RP_BIT) && (!(s_flags & USADDR_WC_BIT))) { /* ~(S,G)RPbit prune sent toward the RP */ mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE); if (mrtentry_ptr) { SET_TIMER(mrtentry_ptr->timer, holdtime); if (v->uv_flags & VIFF_POINT_TO_POINT) { FIRE_TIMER(mrtentry_ptr->vif_timers[vifi]); } else { /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] > mrtentry_ptr->vif_deletion_delay[vifi]) SET_TIMER(mrtentry_ptr->vif_timers[vifi], mrtentry_ptr->vif_deletion_delay[vifi]); } IF_TIMER_NOT_SET(mrtentry_ptr->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } continue; } /* There is no (S,G) entry. Check for (*,G) or (*,*,RP) */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr) { mrtentry_ptr = find_route(source, group, MRTF_SG | MRTF_RP, CREATE); if (!mrtentry_ptr) continue; mrtentry_ptr->flags &= ~MRTF_NEW; RESET_TIMER(mrtentry_ptr->vif_timers[vifi]); /* TODO: XXX: The spec doens't say what value to use for * the entry time. Use the J/P holdtime. */ SET_TIMER(mrtentry_ptr->timer, holdtime); /* TODO: XXX: The spec says to delete the oif. However, * its timer only should be lowered, so the prune can be * overwritten on multiaccess LAN. Spec BUG. */ VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } continue; } if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) { /* (*,G) Prune */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr) { if (mrtentry_ptr->flags & MRTF_WC) { /* TODO: XXX: Should check the whole Prune list in * advance for (*,G) prune and if the RP address * does not match the local RP-map, then ignore the * whole group, not only this particular (*,G) prune. */ if (mrtentry_ptr->group->active_rp_grp->rp->rpentry->address != source) continue; /* The RP address doesn't match. */ if (v->uv_flags & VIFF_POINT_TO_POINT) { FIRE_TIMER(mrtentry_ptr->vif_timers[vifi]); } else { /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] > mrtentry_ptr->vif_deletion_delay[vifi]) SET_TIMER(mrtentry_ptr->vif_timers[vifi], mrtentry_ptr->vif_deletion_delay[vifi]); } IF_TIMER_NOT_SET(mrtentry_ptr->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } continue; } /* No (*,G) entry, but found (*,*,RP). Create (*,G) */ if (mrtentry_ptr->source->address != source) continue; /* The RP address doesn't match. */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE); if (!mrtentry_ptr) continue; mrtentry_ptr->flags &= ~MRTF_NEW; RESET_TIMER(mrtentry_ptr->vif_timers[vifi]); /* TODO: XXX: should only lower the oif timer, so it can * be overwritten on multiaccess LAN. Spec bug. */ VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } /* (*,G) or (*,*,RP) found */ } /* (*,G) prune */ } /* while(num_p_srcs--) */ /* End of (S,G) and (*,G) Prune handling */ /* Jump back to the Join part and process it */ data_ptr = data_ptr_group_j_start; while (num_j_srcs--) { GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); if ((s_flags & USADDR_WC_BIT) && (s_flags & USADDR_RP_BIT)) { /* (*,G) Join toward RP */ /* It has been checked already that this RP address is * the same as the local RP-maping. */ mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE); if (!mrtentry_ptr) continue; VIFM_SET(vifi, mrtentry_ptr->joined_oifs); VIFM_CLR(vifi, mrtentry_ptr->pruned_oifs); VIFM_CLR(vifi, mrtentry_ptr->asserted_oifs); /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] < holdtime) { SET_TIMER(mrtentry_ptr->vif_timers[vifi], holdtime); mrtentry_ptr->vif_deletion_delay[vifi] = holdtime/3; } if (mrtentry_ptr->timer < holdtime) SET_TIMER(mrtentry_ptr->timer, holdtime); mrtentry_ptr->flags &= ~MRTF_NEW; change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); /* Need to update the (S,G) entries, because of the previous * cleaning of the pruned_oifs. The reason is that if the * oifs for (*,G) weren't changed, the (S,G) entries won't * be updated by change_interfaces() */ for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, 0); continue; } if (!(s_flags & (USADDR_WC_BIT | USADDR_RP_BIT))) { /* (S,G) Join toward S */ if (vifi == get_iif(source)) continue; /* Ignore this (S,G) Join */ mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE); if (!mrtentry_ptr) continue; VIFM_SET(vifi, mrtentry_ptr->joined_oifs); VIFM_CLR(vifi, mrtentry_ptr->pruned_oifs); VIFM_CLR(vifi, mrtentry_ptr->asserted_oifs); /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] < holdtime) { SET_TIMER(mrtentry_ptr->vif_timers[vifi], holdtime); mrtentry_ptr->vif_deletion_delay[vifi] = holdtime/3; } if (mrtentry_ptr->timer < holdtime) SET_TIMER(mrtentry_ptr->timer, holdtime); /* TODO: if this is a new entry, send immediately the * Join message toward S. The Join/Prune timer for new * entries is 0, but it does not means the message will * be sent immediately. */ mrtentry_ptr->flags &= ~MRTF_NEW; /* Note that we must create (S,G) without the RPbit set. * If we already had such entry, change_interfaces() will * reset the RPbit propertly. */ change_interfaces(mrtentry_ptr, mrtentry_ptr->source->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); continue; } } /* while(num_j_srcs--) */ data_ptr = data_ptr_group_end; } /* for all groups */ /* Now process the (*,*,RP) Join/Prune */ if (star_star_rp_found != TRUE) return TRUE; data_ptr = data_ptr_start; while (num_groups--) { /* The conservative approach is to scan again the whole message, * just in case if we have more than one (*,*,RP) requests. */ GET_EGADDR(&encod_group, data_ptr); GET_HOSTSHORT(num_j_srcs, data_ptr); GET_HOSTSHORT(num_p_srcs, data_ptr); group = encod_group.mcast_addr; if ((ntohl(group) != CLASSD_PREFIX) || (encod_group.masklen != STAR_STAR_RP_MSKLEN)) { /* This is not (*,*,RP). Jump to the next group. */ data_ptr += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t); continue; } /* (*,*,RP) found */ while (num_j_srcs--) { /* TODO: XXX: check that the iif is different from the Join oifs */ GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); mrtentry_ptr = find_route(source, INADDR_ANY_N, MRTF_PMBR, CREATE); if (mrtentry_ptr == (mrtentry_t *)NULL) continue; VIFM_SET(vifi, mrtentry_ptr->joined_oifs); VIFM_CLR(vifi, mrtentry_ptr->pruned_oifs); VIFM_CLR(vifi, mrtentry_ptr->asserted_oifs); /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] < holdtime) { SET_TIMER(mrtentry_ptr->vif_timers[vifi], holdtime); mrtentry_ptr->vif_deletion_delay[vifi] = holdtime/3; } if (mrtentry_ptr->timer < holdtime) SET_TIMER(mrtentry_ptr->timer, holdtime); mrtentry_ptr->flags &= ~MRTF_NEW; change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); /* Need to update the (S,G) and (*,G) entries, because of * the previous cleaning of the pruned_oifs. The reason is * that if the oifs for (*,*,RP) weren't changed, the * (*,G) and (S,G) entries won't be updated by change_interfaces() */ for (rp_grp_entry_ptr = mrtentry_ptr->source->cand_rp->rp_grp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { /* Update the (*,G) entry */ if (grpentry_ptr->grp_route != NULL) { change_interfaces(grpentry_ptr->grp_route, grpentry_ptr->grp_route->incoming, grpentry_ptr->grp_route->joined_oifs, grpentry_ptr->grp_route->pruned_oifs, grpentry_ptr->grp_route->leaves, grpentry_ptr->grp_route->asserted_oifs, 0); } /* Update the (S,G) entries */ for (mrtentry_srcs = grpentry_ptr->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, 0); } } continue; } while (num_p_srcs--) { /* TODO: XXX: can we have (*,*,RP) Prune? */ GET_ESADDR(&encod_src, data_ptr); source = encod_src.src_addr; if (!inet_valid_host(source)) continue; s_flags = encod_src.flags; MASKLEN_TO_MASK(encod_src.masklen, s_mask); mrtentry_ptr = find_route(source, INADDR_ANY_N, MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr == (mrtentry_t *)NULL) continue; /* If the link is point-to-point, timeout the oif * immediately, otherwise decrease the timer to allow * other downstream routers to override the prune. */ /* TODO: XXX: increase the entry timer? */ if (v->uv_flags & VIFF_POINT_TO_POINT) { FIRE_TIMER(mrtentry_ptr->vif_timers[vifi]); } else { /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->vif_timers[vifi] > mrtentry_ptr->vif_deletion_delay[vifi]) SET_TIMER(mrtentry_ptr->vif_timers[vifi], mrtentry_ptr->vif_deletion_delay[vifi]); } IF_TIMER_NOT_SET(mrtentry_ptr->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_ptr->joined_oifs); VIFM_SET(vifi, mrtentry_ptr->pruned_oifs); VIFM_SET(vifi, mrtentry_ptr->asserted_oifs); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } } } /* For all groups processing (*,*,R) */ return TRUE; } /* * TODO: NOT USED, probably buggy, but may need it in the future. */ /* * TODO: create two functions: periodic which timeout the timers * and non-periodic which only check but don't timeout the timers. */ /* * Create and send Join/Prune messages per interface. * Only the entries which have the Join/Prune timer expired are included. * In the special case when we have ~(S,G)RPbit Prune entry, we must * include any (*,G) or (*,*,RP) * Currently the whole table is scanned. In the future will have all * routing entries linked in a chain with the corresponding upstream * pim_nbr_entry. * * If pim_nbr is not NULL, then send to only this particular PIM neighbor, */ int send_periodic_pim_join_prune(vifi_t vifi, pim_nbr_entry_t *pim_nbr, u_int16 holdtime) { grpentry_t *grpentry_ptr; mrtentry_t *mrtentry_ptr; rpentry_t *rpentry_ptr; u_int32 src_addr; struct uvif *v; pim_nbr_entry_t *pim_nbr_ptr; cand_rp_t *cand_rp_ptr; /* Walk through all routing entries. The iif must match to include the * entry. Check first the (*,G) entry and then all associated (S,G). * At the end of the message will add any (*,*,RP) entries. * TODO: check other PIM-SM implementations and decide the more * appropriate place to put the (*,*,RP) entries: in the beginning of the * message or at the end. */ v = &uvifs[vifi]; /* Check the (*,G) and (S,G) entries */ for(grpentry_ptr = grplist; grpentry_ptr; grpentry_ptr = grpentry_ptr->next) { mrtentry_ptr = grpentry_ptr->grp_route; /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr && (mrtentry_ptr->incoming == vifi) && (mrtentry_ptr->jp_timer <= TIMER_INTERVAL)) { /* If join/prune to a particular neighbor only was specified */ if (pim_nbr && mrtentry_ptr->upstream != pim_nbr) continue; /* TODO: XXX: The J/P suppression timer is not in the spec! */ if (!VIFM_ISEMPTY(mrtentry_ptr->joined_oifs) || (v->uv_flags & VIFF_DR)) { add_jp_entry(mrtentry_ptr->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, grpentry_ptr->rpaddr, SINGLE_SRC_MSKLEN, 0, PIM_ACTION_JOIN); } /* TODO: XXX: TIMER implem. dependency! */ if (VIFM_ISEMPTY(mrtentry_ptr->joined_oifs) && (!(v->uv_flags & VIFF_DR)) && (mrtentry_ptr->jp_timer <= TIMER_INTERVAL)) { add_jp_entry(mrtentry_ptr->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, grpentry_ptr->rpaddr, SINGLE_SRC_MSKLEN, 0, PIM_ACTION_PRUNE); } } /* Check the (S,G) entries */ for (mrtentry_ptr = grpentry_ptr->mrtlink; mrtentry_ptr; mrtentry_ptr = mrtentry_ptr->grpnext) { /* If join/prune to a particular neighbor only was specified */ if (pim_nbr && mrtentry_ptr->upstream != pim_nbr) continue; if (mrtentry_ptr->flags & MRTF_RP) { /* RPbit set */ src_addr = mrtentry_ptr->source->address; if (VIFM_ISEMPTY(mrtentry_ptr->joined_oifs) || ((find_vif_direct_local(src_addr) != NO_VIF) && grpentry_ptr->grp_route)) /* TODO: XXX: TIMER implem. dependency! */ if ((grpentry_ptr->grp_route->incoming == vifi) && (grpentry_ptr->grp_route->jp_timer <= TIMER_INTERVAL)) /* S is directly connected. Send toward RP */ add_jp_entry(grpentry_ptr->grp_route->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, src_addr, SINGLE_SRC_MSKLEN, MRTF_RP, PIM_ACTION_PRUNE); } else { /* RPbit cleared */ if (VIFM_ISEMPTY(mrtentry_ptr->joined_oifs)) { /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_ptr->incoming == vifi) && (mrtentry_ptr->jp_timer <= TIMER_INTERVAL)) add_jp_entry(mrtentry_ptr->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, mrtentry_ptr->source->address, SINGLE_SRC_MSKLEN, 0, PIM_ACTION_PRUNE); } else { /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_ptr->incoming == vifi) && (mrtentry_ptr->jp_timer <= TIMER_INTERVAL)) add_jp_entry(mrtentry_ptr->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, mrtentry_ptr->source->address, SINGLE_SRC_MSKLEN, 0, PIM_ACTION_JOIN); } /* TODO: XXX: TIMER implem. dependency! */ if ((mrtentry_ptr->flags & MRTF_SPT) && grpentry_ptr->grp_route && (mrtentry_ptr->incoming != grpentry_ptr->grp_route->incoming) && (grpentry_ptr->grp_route->incoming == vifi) && (grpentry_ptr->grp_route->jp_timer <= TIMER_INTERVAL)) add_jp_entry(grpentry_ptr->grp_route->upstream, holdtime, grpentry_ptr->group, SINGLE_GRP_MSKLEN, mrtentry_ptr->source->address, SINGLE_SRC_MSKLEN, MRTF_RP, PIM_ACTION_PRUNE); } } } /* Check the (*,*,RP) entries */ for (cand_rp_ptr = cand_rp_list; cand_rp_ptr; cand_rp_ptr = cand_rp_ptr->next) { rpentry_ptr = cand_rp_ptr->rpentry; /* If join/prune to a particular neighbor only was specified */ if (pim_nbr && rpentry_ptr->upstream != pim_nbr) continue; /* TODO: XXX: TIMER implem. dependency! */ if (rpentry_ptr->mrtlink && (rpentry_ptr->incoming == vifi) && (rpentry_ptr->mrtlink->jp_timer <= TIMER_INTERVAL)) { add_jp_entry(rpentry_ptr->upstream, holdtime, htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, rpentry_ptr->address, SINGLE_SRC_MSKLEN, MRTF_RP | MRTF_WC, PIM_ACTION_JOIN); } } /* Send all pending Join/Prune messages */ for (pim_nbr_ptr = v->uv_pim_neighbors; pim_nbr_ptr; pim_nbr_ptr = pim_nbr->next) { /* If join/prune to a particular neighbor only was specified */ if (pim_nbr && (pim_nbr_ptr != pim_nbr)) continue; pack_and_send_jp_message(pim_nbr_ptr); } return TRUE; } int add_jp_entry(pim_nbr_entry_t *pim_nbr, u_int16 holdtime, u_int32 group, u_int8 grp_msklen, u_int32 source, u_int8 src_msklen, u_int16 addr_flags, u_int8 join_prune) { build_jp_message_t *bjpm; u_int8 *data_ptr; u_int8 flags = 0; int rp_flag; bjpm = pim_nbr->build_jp_message; if (bjpm) { if ((bjpm->jp_message_size + bjpm->join_list_size + bjpm->prune_list_size + bjpm->rp_list_join_size + bjpm->rp_list_prune_size >= MAX_JP_MESSAGE_SIZE) || (bjpm->join_list_size >= MAX_JOIN_LIST_SIZE) || (bjpm->prune_list_size >= MAX_PRUNE_LIST_SIZE) || (bjpm->rp_list_join_size >= MAX_JOIN_LIST_SIZE) || (bjpm->rp_list_prune_size >= MAX_PRUNE_LIST_SIZE)) { /* TODO: XXX: BUG: If the list is getting too large, must * be careful with the fragmentation. */ pack_and_send_jp_message(pim_nbr); bjpm = pim_nbr->build_jp_message; /* The buffer will be freed */ } } if (bjpm) { if ((bjpm->curr_group != group) || (bjpm->curr_group_msklen != grp_msklen) || (bjpm->holdtime != holdtime)) { pack_jp_message(pim_nbr); } } if (!bjpm) { bjpm = get_jp_working_buff(); if (!bjpm) { logit(LOG_ERR, 0, "Failed allocating working buffer in add_jp_entry()\n"); exit (-1); } pim_nbr->build_jp_message = bjpm; data_ptr = bjpm->jp_message; PUT_EUADDR(pim_nbr->address, data_ptr); PUT_BYTE(0, data_ptr); /* Reserved */ bjpm->num_groups_ptr = data_ptr++; /* The pointer for numgroups */ *(bjpm->num_groups_ptr) = 0; /* Zero groups */ PUT_HOSTSHORT(holdtime, data_ptr); bjpm->holdtime = holdtime; bjpm->jp_message_size = data_ptr - bjpm->jp_message; } /* TODO: move somewhere else, only when it is a new group */ bjpm->curr_group = group; bjpm->curr_group_msklen = grp_msklen; if (group == htonl(CLASSD_PREFIX) && grp_msklen == STAR_STAR_RP_MSKLEN) rp_flag = TRUE; else rp_flag = FALSE; switch (join_prune) { case PIM_ACTION_JOIN: if (rp_flag == TRUE) data_ptr = bjpm->rp_list_join + bjpm->rp_list_join_size; else data_ptr = bjpm->join_list + bjpm->join_list_size; break; case PIM_ACTION_PRUNE: if (rp_flag == TRUE) data_ptr = bjpm->rp_list_prune + bjpm->rp_list_prune_size; else data_ptr = bjpm->prune_list + bjpm->prune_list_size; break; default: return FALSE; } flags |= USADDR_S_BIT; /* Mandatory for PIMv2 */ if (addr_flags & MRTF_RP) flags |= USADDR_RP_BIT; if (addr_flags & MRTF_WC) flags |= USADDR_WC_BIT; PUT_ESADDR(source, src_msklen, flags, data_ptr); switch (join_prune) { case PIM_ACTION_JOIN: if (rp_flag == TRUE) { bjpm->rp_list_join_size = data_ptr - bjpm->rp_list_join; bjpm->rp_list_join_number++; } else { bjpm->join_list_size = data_ptr - bjpm->join_list; bjpm->join_addr_number++; } break; case PIM_ACTION_PRUNE: if (rp_flag == TRUE) { bjpm->rp_list_prune_size = data_ptr - bjpm->rp_list_prune; bjpm->rp_list_prune_number++; } else { bjpm->prune_list_size = data_ptr - bjpm->prune_list; bjpm->prune_addr_number++; } break; default: return FALSE; } return TRUE; } /* TODO: check again the size of the buffers */ static build_jp_message_t *get_jp_working_buff(void) { build_jp_message_t *bjpm_ptr; if (build_jp_message_pool_counter == 0) { bjpm_ptr = (build_jp_message_t *)calloc(1, sizeof(build_jp_message_t)); if (!bjpm_ptr) return NULL; bjpm_ptr->next = (build_jp_message_t *)NULL; bjpm_ptr->jp_message = (u_int8 *)calloc(1, MAX_JP_MESSAGE_SIZE + sizeof(pim_jp_encod_grp_t) + 2 * sizeof(pim_encod_src_addr_t)); if (!bjpm_ptr->jp_message) { free(bjpm_ptr); return NULL; } bjpm_ptr->jp_message_size = 0; bjpm_ptr->join_list_size = 0; bjpm_ptr->join_addr_number = 0; bjpm_ptr->join_list = (u_int8 *)calloc(1, MAX_JOIN_LIST_SIZE + sizeof(pim_encod_src_addr_t)); if (!bjpm_ptr->join_list) { free(bjpm_ptr->jp_message); free(bjpm_ptr); return NULL; } bjpm_ptr->prune_list_size = 0; bjpm_ptr->prune_addr_number = 0; bjpm_ptr->prune_list = (u_int8 *)calloc(1, MAX_PRUNE_LIST_SIZE + sizeof(pim_encod_src_addr_t)); if (!bjpm_ptr->prune_list) { free(bjpm_ptr->join_list); free(bjpm_ptr->jp_message); free(bjpm_ptr); return NULL; } bjpm_ptr->rp_list_join_size = 0; bjpm_ptr->rp_list_join_number = 0; bjpm_ptr->rp_list_join = (u_int8 *)calloc(1, MAX_JOIN_LIST_SIZE + sizeof(pim_encod_src_addr_t)); if (!bjpm_ptr->rp_list_join) { free(bjpm_ptr->prune_list); free(bjpm_ptr->join_list); free(bjpm_ptr->jp_message); free(bjpm_ptr); return NULL; } bjpm_ptr->rp_list_prune_size = 0; bjpm_ptr->rp_list_prune_number = 0; bjpm_ptr->rp_list_prune = (u_int8 *)calloc(1, MAX_PRUNE_LIST_SIZE + sizeof(pim_encod_src_addr_t)); if (!bjpm_ptr->rp_list_prune) { free(bjpm_ptr->rp_list_join); free(bjpm_ptr->prune_list); free(bjpm_ptr->join_list); free(bjpm_ptr->jp_message); free(bjpm_ptr); return NULL; } bjpm_ptr->curr_group = INADDR_ANY_N; bjpm_ptr->curr_group_msklen = 0; bjpm_ptr->holdtime = 0; return bjpm_ptr; } bjpm_ptr = build_jp_message_pool; build_jp_message_pool = build_jp_message_pool->next; build_jp_message_pool_counter--; bjpm_ptr->jp_message_size = 0; bjpm_ptr->join_list_size = 0; bjpm_ptr->join_addr_number = 0; bjpm_ptr->prune_list_size = 0; bjpm_ptr->prune_addr_number = 0; bjpm_ptr->curr_group = INADDR_ANY_N; bjpm_ptr->curr_group_msklen = 0; return bjpm_ptr; } static void return_jp_working_buff(pim_nbr_entry_t *pim_nbr) { build_jp_message_t *bjpm_ptr = pim_nbr->build_jp_message; if (!bjpm_ptr) return; /* Don't waste memory by keeping too many free buffers */ /* TODO: check/modify the definitions for POOL_NUMBER and size */ if (build_jp_message_pool_counter >= MAX_JP_MESSAGE_POOL_NUMBER) { free((void *)bjpm_ptr->jp_message); free((void *)bjpm_ptr->join_list); free((void *)bjpm_ptr->prune_list); free((void *)bjpm_ptr->rp_list_join); free((void *)bjpm_ptr->rp_list_prune); free((void *)bjpm_ptr); } else { bjpm_ptr->next = build_jp_message_pool; build_jp_message_pool = bjpm_ptr; build_jp_message_pool_counter++; } pim_nbr->build_jp_message = (build_jp_message_t *)NULL; } /* TODO: XXX: Currently, the (*,*,RP) stuff goes at the end of the * Join/Prune message. However, this particular implementation of PIM * processes the Join/Prune messages faster if (*,*,RP) is at the beginning. * Modify some of the functions below such that the * outgoing messages place (*,*,RP) at the beginning, not at the end. */ static void pack_jp_message(pim_nbr_entry_t *pim_nbr) { build_jp_message_t *bjpm; u_int8 *data_ptr; bjpm = pim_nbr->build_jp_message; if (!bjpm || (bjpm->curr_group == INADDR_ANY_N)) return; data_ptr = bjpm->jp_message + bjpm->jp_message_size; PUT_EGADDR(bjpm->curr_group, bjpm->curr_group_msklen, 0, data_ptr); PUT_HOSTSHORT(bjpm->join_addr_number, data_ptr); PUT_HOSTSHORT(bjpm->prune_addr_number, data_ptr); memcpy(data_ptr, bjpm->join_list, bjpm->join_list_size); data_ptr += bjpm->join_list_size; memcpy(data_ptr, bjpm->prune_list, bjpm->prune_list_size); data_ptr += bjpm->prune_list_size; bjpm->jp_message_size = (data_ptr - bjpm->jp_message); bjpm->curr_group = INADDR_ANY_N; bjpm->curr_group_msklen = 0; bjpm->join_list_size = 0; bjpm->join_addr_number = 0; bjpm->prune_list_size = 0; bjpm->prune_addr_number = 0; (*bjpm->num_groups_ptr)++; if (*bjpm->num_groups_ptr == ((u_int8)~0 - 1)) { if (bjpm->rp_list_join_number + bjpm->rp_list_prune_number) { /* Add the (*,*,RP) at the end */ data_ptr = bjpm->jp_message + bjpm->jp_message_size; PUT_EGADDR(htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, 0, data_ptr); PUT_HOSTSHORT(bjpm->rp_list_join_number, data_ptr); PUT_HOSTSHORT(bjpm->rp_list_prune_number, data_ptr); memcpy(data_ptr, bjpm->rp_list_join, bjpm->rp_list_join_size); data_ptr += bjpm->rp_list_join_size; memcpy(data_ptr, bjpm->rp_list_prune, bjpm->rp_list_prune_size); data_ptr += bjpm->rp_list_prune_size; bjpm->jp_message_size = (data_ptr - bjpm->jp_message); bjpm->rp_list_join_size = 0; bjpm->rp_list_join_number = 0; bjpm->rp_list_prune_size = 0; bjpm->rp_list_prune_number = 0; (*bjpm->num_groups_ptr)++; } send_jp_message(pim_nbr); } } void pack_and_send_jp_message(pim_nbr_entry_t *pim_nbr) { u_int8 *data_ptr; build_jp_message_t *bjpm; if (!pim_nbr || !pim_nbr->build_jp_message) return; pack_jp_message(pim_nbr); bjpm = pim_nbr->build_jp_message; if (bjpm->rp_list_join_number + bjpm->rp_list_prune_number) { /* Add the (*,*,RP) at the end */ data_ptr = bjpm->jp_message + bjpm->jp_message_size; PUT_EGADDR(htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, 0, data_ptr); PUT_HOSTSHORT(bjpm->rp_list_join_number, data_ptr); PUT_HOSTSHORT(bjpm->rp_list_prune_number, data_ptr); memcpy(data_ptr, bjpm->rp_list_join, bjpm->rp_list_join_size); data_ptr += bjpm->rp_list_join_size; memcpy(data_ptr, bjpm->rp_list_prune, bjpm->rp_list_prune_size); data_ptr += bjpm->rp_list_prune_size; bjpm->jp_message_size = (data_ptr - bjpm->jp_message); bjpm->rp_list_join_size = 0; bjpm->rp_list_join_number = 0; bjpm->rp_list_prune_size = 0; bjpm->rp_list_prune_number = 0; (*bjpm->num_groups_ptr)++; } send_jp_message(pim_nbr); } static void send_jp_message(pim_nbr_entry_t *pim_nbr) { u_int16 datalen; vifi_t vifi; datalen = pim_nbr->build_jp_message->jp_message_size; vifi = pim_nbr->vifi; memcpy(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t), pim_nbr->build_jp_message->jp_message, datalen); send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group, PIM_JOIN_PRUNE, datalen); return_jp_working_buff(pim_nbr); } /************************************************************************ * PIM_ASSERT ************************************************************************/ int receive_pim_assert(u_int32 src, u_int32 dst __attribute__((unused)), char *pim_message, int datalen) { vifi_t vifi; pim_encod_uni_addr_t eusaddr; pim_encod_grp_addr_t egaddr; u_int32 source, group; mrtentry_t *mrtentry_ptr, *mrtentry_ptr2; u_int8 *data_ptr; struct uvif *v; u_int32 assert_preference; u_int32 assert_metric; u_int32 assert_rptbit; u_int32 local_metric; u_int32 local_preference; u_int8 local_rptbit; u_int8 local_wins; pim_nbr_entry_t *original_upstream_router; vifi = find_vif_direct(src); if (vifi == NO_VIF) { /* Either a local vif or somehow received PIM_ASSERT from * non-directly connected router. Ignore it. */ if (local_address(src) == NO_VIF) logit(LOG_INFO, 0, "Ignoring PIM_ASSERT from non-neighbor router %s", inet_fmt(src, s1, sizeof(s1))); return FALSE; } /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; v = &uvifs[vifi]; if (uvifs[vifi].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_NONBRS | VIFF_REGISTER)) return FALSE; /* Shoudn't come on this interface */ data_ptr = (u_int8 *)(pim_message + sizeof(pim_header_t)); /* Get the group and source addresses */ GET_EGADDR(&egaddr, data_ptr); GET_EUADDR(&eusaddr, data_ptr); /* Get the metric related info */ GET_HOSTLONG(assert_preference, data_ptr); GET_HOSTLONG(assert_metric, data_ptr); assert_rptbit = assert_preference & PIM_ASSERT_RPT_BIT; source = eusaddr.unicast_addr; group = egaddr.mcast_addr; /* Find the longest "active" entry, i.e. the one with a kernel mirror */ if (assert_rptbit) { mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr) if (!(mrtentry_ptr->flags & MRTF_KERNEL_CACHE)) if (mrtentry_ptr->flags & MRTF_WC) { mrtentry_ptr = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; } } else { mrtentry_ptr = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); if (mrtentry_ptr) if (!(mrtentry_ptr->flags & MRTF_KERNEL_CACHE)) { if (mrtentry_ptr->flags & MRTF_SG) { mrtentry_ptr2 = mrtentry_ptr->group->grp_route; if (mrtentry_ptr2 && (mrtentry_ptr2->flags & MRTF_KERNEL_CACHE)) mrtentry_ptr = mrtentry_ptr2; else mrtentry_ptr = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; } else { if (mrtentry_ptr->flags & MRTF_WC) mrtentry_ptr = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; } } } if (!mrtentry_ptr || !(mrtentry_ptr->flags & MRTF_KERNEL_CACHE)) { /* No routing entry or not "active" entry. Ignore the assert */ return FALSE; } /* Prepare the local preference and metric */ if ((mrtentry_ptr->flags & MRTF_PMBR) || ((mrtentry_ptr->flags & MRTF_SG) && !(mrtentry_ptr->flags & MRTF_RP))) { /* Either (S,G) (toward S) or (*,*,RP). */ /* TODO: XXX: get the info from mrtentry, or source or from kernel ? */ /* local_metric = mrtentry_ptr->source->metric; local_preference = mrtentry_ptr->source->preference; */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; } else { /* Should be (*,G) or (S,G)RPbit entry. * Get what we need from the RP info. */ /* TODO: get the info from mrtentry, RP-entry or kernel? */ /* local_metric = mrtentry_ptr->group->active_rp_grp->rp->rpentry->metric; local_preference = mrtentry_ptr->group->active_rp_grp->rp->rpentry->preference; */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; } local_rptbit = (mrtentry_ptr->flags & MRTF_RP); if (local_rptbit) { /* Make the RPT bit the most significant one */ local_preference |= PIM_ASSERT_RPT_BIT; } if (VIFM_ISSET(vifi, mrtentry_ptr->oifs)) { /* The ASSERT has arrived on oif */ /* TODO: XXX: here the processing order is different from the spec. * The spec requires first eventually to create a routing entry * (see 3.5.2.1(1) and then compare the metrics. Here we compare * first the metrics with the existing longest match entry and * if we lose then create a new entry and compare again. This saves * us the unnecessary creating of a routing entry if we anyway are * going to lose: for example the local (*,*,RP) vs the remote * (*,*,RP) or (*,G) */ local_wins = compare_metrics(local_preference, local_metric, v->uv_lcl_addr, assert_preference, assert_metric, src); if (local_wins == TRUE) { /* TODO: verify the parameters */ send_pim_assert(source, group, vifi, mrtentry_ptr); return TRUE; } /* Create a "better" routing entry and try again */ if (assert_rptbit && (mrtentry_ptr->flags & MRTF_PMBR)) { /* The matching entry was (*,*,RP). Create (*,G) */ mrtentry_ptr2 = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE); } else if (!assert_rptbit && (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR))) { /* create (S,G) */ mrtentry_ptr2 = find_route(source, group, MRTF_SG, CREATE); } else { /* We have no chance to win. Give up and prune the oif */ mrtentry_ptr2 = (mrtentry_t *)NULL; } if (mrtentry_ptr2) { mrtentry_ptr2->flags &= ~MRTF_NEW; /* TODO: XXX: The spec doesn't say what entry timer value * to use when the routing entry is created because of asserts. */ SET_TIMER(mrtentry_ptr2->timer, PIM_DATA_TIMEOUT); if (mrtentry_ptr2->flags & MRTF_RP) { /* Either (*,G) or (S,G)RPbit entry. * Get what we need from the RP info. */ /* TODO: where to get the metric+preference from? */ /* local_metric = mrtentry_ptr->group->active_rp_grp->rp->rpentry->metric; local_preference = mrtentry_ptr->group->active_rp_grp->rp->rpentry->preference; */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; local_preference |= PIM_ASSERT_RPT_BIT; } else { /* (S,G) toward the source */ /* TODO: where to get the metric from ? */ /* local_metric = mrtentry_ptr->source->metric; local_preference = mrtentry_ptr->source->preference; */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; } local_wins = compare_metrics(local_preference, local_metric, v->uv_lcl_addr, assert_preference, assert_metric, src); if (local_wins == TRUE) { /* TODO: verify the parameters */ send_pim_assert(source, group, vifi, mrtentry_ptr); return TRUE; } /* We lost, but have created the entry which has to be pruned */ mrtentry_ptr = mrtentry_ptr2; } /* Have to remove that outgoing vifi from mrtentry_ptr */ VIFM_SET(vifi, mrtentry_ptr->asserted_oifs); /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_ptr->timer < PIM_ASSERT_TIMEOUT) SET_TIMER(mrtentry_ptr->timer, PIM_ASSERT_TIMEOUT); /* TODO: XXX: check that the timer of all affected routing entries * has been restarted. */ change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); return FALSE; /* Doesn't matter the return value */ } /* End of assert received on oif */ if (mrtentry_ptr->incoming == vifi) { /* Assert received on iif */ if (assert_rptbit) { if (!(mrtentry_ptr->flags & MRTF_RP)) return TRUE; /* The locally used upstream router will * win the assert, so don't change it. */ } /* TODO: where to get the local metric and preference from? * system call or mrtentry is fine? */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; if (mrtentry_ptr->flags & MRTF_RP) local_preference |= PIM_ASSERT_RPT_BIT; local_wins = compare_metrics(local_preference, local_metric, mrtentry_ptr->upstream->address, assert_preference, assert_metric, src); if (local_wins == TRUE) return TRUE; /* return whatever */ /* The upstream must be changed to the winner */ mrtentry_ptr->preference = assert_preference; mrtentry_ptr->metric = assert_metric; mrtentry_ptr->upstream = find_pim_nbr(src); /* Check if the upstream router is different from the original one */ if (mrtentry_ptr->flags & MRTF_PMBR) original_upstream_router = mrtentry_ptr->source->upstream; else if (mrtentry_ptr->flags & MRTF_RP) original_upstream_router = mrtentry_ptr->group->active_rp_grp->rp->rpentry->upstream; else original_upstream_router = mrtentry_ptr->source->upstream; if (mrtentry_ptr->upstream != original_upstream_router) { mrtentry_ptr->flags |= MRTF_ASSERTED; SET_TIMER(mrtentry_ptr->assert_timer, PIM_ASSERT_TIMEOUT); } else { mrtentry_ptr->flags &= ~MRTF_ASSERTED; } } return TRUE; } int send_pim_assert(u_int32 source, u_int32 group, vifi_t vifi, mrtentry_t *mrtentry_ptr) { u_int8 *data_ptr; u_int8 *data_start_ptr; u_int32 local_preference; u_int32 local_metric; srcentry_t *srcentry_ptr __attribute__((unused)); /* Don't send assert if the outgoing interface a tunnel or register vif */ /* TODO: XXX: in the code above asserts are accepted over VIFF_TUNNEL. * Check if anything can go wrong if asserts are accepted and/or * sent over VIFF_TUNNEL. */ if (uvifs[vifi].uv_flags & (VIFF_REGISTER | VIFF_TUNNEL)) return FALSE; data_ptr = (u_int8 *)(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t)); data_start_ptr = data_ptr; PUT_EGADDR(group, SINGLE_GRP_MSKLEN, 0, data_ptr); PUT_EUADDR(source, data_ptr); /* TODO: XXX: where to get the metric from: srcentry_ptr or mrtentry_ptr * or from the kernel? */ if (mrtentry_ptr->flags & MRTF_PMBR) { /* (*,*,RP) */ srcentry_ptr = mrtentry_ptr->source; /* TODO: set_incoming(srcentry_ptr, PIM_IIF_RP); */ } else if (mrtentry_ptr->flags & MRTF_RP) { /* (*,G) or (S,G)RPbit (iif toward RP) */ srcentry_ptr = mrtentry_ptr->group->active_rp_grp->rp->rpentry; /* TODO: set_incoming(srcentry_ptr, PIM_IIF_RP); */ } else { /* (S,G) toward S */ srcentry_ptr = mrtentry_ptr->source; /* TODO: set_incoming(srcentry_ptr, PIM_IIF_SOURCE); */ } /* TODO: check again! local_metric = srcentry_ptr->metric; local_preference = srcentry_ptr->preference; */ local_metric = mrtentry_ptr->metric; local_preference = mrtentry_ptr->preference; if (mrtentry_ptr->flags & MRTF_RP) local_preference |= PIM_ASSERT_RPT_BIT; PUT_HOSTLONG(local_preference, data_ptr); PUT_HOSTLONG(local_metric, data_ptr); send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group, PIM_ASSERT, data_ptr - data_start_ptr); return TRUE; } /* Return TRUE if the local win, otherwise FALSE */ static int compare_metrics(u_int32 local_preference, u_int32 local_metric, u_int32 local_address, u_int32 remote_preference, u_int32 remote_metric, u_int32 remote_address) { /* Now lets see who has a smaller gun (aka "asserts war") */ /* FYI, the smaller gun...err metric wins, but if the same * caliber, then the bigger network address wins. The order of * threatment is: preference, metric, address. */ /* The RPT bits are already included as the most significant bits * of the preferences. */ if (remote_preference > local_preference) return TRUE; if (remote_preference < local_preference) return FALSE; if (remote_metric > local_metric) return TRUE; if (remote_metric < local_metric) return FALSE; if (ntohl(local_address) > ntohl(remote_address)) return TRUE; return FALSE; } /************************************************************************ * PIM_BOOTSTRAP ************************************************************************/ #define PIM_BOOTSTRAP_MINLEN (PIM_MINLEN + PIM_ENCODE_UNI_ADDR_LEN) int receive_pim_bootstrap(u_int32 src, u_int32 dst, char *pim_message, int datalen) { u_int8 *data_ptr; u_int8 *max_data_ptr; u_int16 new_bsr_fragment_tag; u_int8 new_bsr_hash_masklen; u_int8 new_bsr_priority; pim_encod_uni_addr_t new_bsr_uni_addr; u_int32 new_bsr_address; struct rpfctl rpfc; pim_nbr_entry_t *n, *rpf_neighbor __attribute__((unused)); u_int32 neighbor_addr; vifi_t vifi, incoming = NO_VIF; int min_datalen; pim_encod_grp_addr_t curr_group_addr; pim_encod_uni_addr_t curr_rp_addr; u_int8 curr_rp_count; u_int8 curr_frag_rp_count; u_int16 reserved_short __attribute__((unused)); u_int16 curr_rp_holdtime; u_int8 curr_rp_priority; u_int8 reserved_byte __attribute__((unused)); u_int32 curr_group_mask; u_int32 prefix_h; grp_mask_t *grp_mask_ptr; grp_mask_t *grp_mask_next; rp_grp_entry_t *grp_rp_entry_ptr; rp_grp_entry_t *grp_rp_entry_next; /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; if (find_vif_direct(src) == NO_VIF) { /* Either a local vif or somehow received PIM_BOOTSTRAP from * non-directly connected router. Ignore it. */ if (local_address(src) == NO_VIF) logit(LOG_INFO, 0, "Ignoring PIM_BOOTSTRAP from non-neighbor router %s", inet_fmt(src, s1, sizeof(s1))); return FALSE; } /* sanity check for the minimum length */ if (datalen < PIM_BOOTSTRAP_MINLEN) { logit(LOG_NOTICE, 0, "receive_pim_bootstrap: Bootstrap message size(%u) is too short from %s", datalen, inet_fmt(src, s1, sizeof(s1))); return FALSE; } data_ptr = (u_int8 *)(pim_message + sizeof(pim_header_t)); /* Parse the PIM_BOOTSTRAP message */ GET_HOSTSHORT(new_bsr_fragment_tag, data_ptr); GET_BYTE(new_bsr_hash_masklen, data_ptr); GET_BYTE(new_bsr_priority, data_ptr); GET_EUADDR(&new_bsr_uni_addr, data_ptr); new_bsr_address = new_bsr_uni_addr.unicast_addr; if (local_address(new_bsr_address) != NO_VIF) return FALSE; /* The new BSR is one of my local addresses */ /* * Compare the current BSR priority with the priority of the BSR * included in the message. */ /* TODO: if I am just starting and will become the BSR, * I should accept the message coming from the current BSR and get the * current Cand-RP-Set. */ if ((curr_bsr_priority > new_bsr_priority) || ((curr_bsr_priority == new_bsr_priority) && (ntohl(curr_bsr_address) > ntohl(new_bsr_address)))) { /* The message's BSR is less preferred than the current BSR */ return FALSE; /* Ignore the received BSR message */ } /* Check the iif, if this was PIM-ROUTERS multicast */ if (dst == allpimrouters_group) { k_req_incoming(new_bsr_address, &rpfc); if (rpfc.iif == NO_VIF || rpfc.rpfneighbor.s_addr == INADDR_ANY_N) { /* coudn't find a route to the BSR */ return FALSE; } neighbor_addr = rpfc.rpfneighbor.s_addr; incoming = rpfc.iif; if (uvifs[incoming].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) return FALSE; /* Shoudn't arrive on that interface */ /* Find the upstream router */ for (n = uvifs[incoming].uv_pim_neighbors; n != NULL; n = n->next) { if (ntohl(neighbor_addr) < ntohl(n->address)) continue; if (neighbor_addr == n->address) { rpf_neighbor = n; break; } return FALSE; /* No neighbor toward BSR found */ } if (!n || n->address != src) return FALSE; /* Sender of this message is not the RPF neighbor */ } else { if (local_address(dst) == NO_VIF) { /* TODO: XXX: this situation should be handled earlier: * The destination is neither ALL_PIM_ROUTERS neither me */ return FALSE; } /* Probably unicasted from the current DR */ if (cand_rp_list != (cand_rp_t *)NULL) { /* Hmmm, I do have a Cand-RP-list, but some neighbor has a * different opinion and is unicasting it to me. Ignore this guy. */ return FALSE; } for (vifi = 0; vifi < numvifs; vifi++) { if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) continue; if (uvifs[vifi].uv_lcl_addr == dst) { incoming = vifi; break; } } if (incoming == NO_VIF) { /* Cannot find the receiving iif toward that DR */ IF_DEBUG(DEBUG_RPF | DEBUG_PIM_BOOTSTRAP) logit(LOG_DEBUG, 0, "Unicast boostrap message from %s to ignored: cannot find iif", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return FALSE; } /* TODO: check the sender is directly connected and I am really the DR */ } if (cand_rp_flag == TRUE) { /* If change in the BSR address, schedule immediate Cand-RP-Adv */ /* TODO: use some random delay? */ if (new_bsr_address != curr_bsr_address) { SET_TIMER(pim_cand_rp_adv_timer, 0); } } /* Forward the BSR Message first and then update the RP-set list */ /* TODO: if the message was unicasted to me, resend? */ for (vifi = 0; vifi < numvifs; vifi++) { if (vifi == incoming) continue; if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_NONBRS)) continue; memcpy(pim_send_buf + sizeof(struct ip), pim_message, datalen); send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group, PIM_BOOTSTRAP, datalen - sizeof(pim_header_t)); } max_data_ptr = (u_int8 *)pim_message + datalen; /* TODO: XXX: this 22 is HARDCODING!!! Do a bunch of definitions * and make it stylish! */ min_datalen = 22; if (new_bsr_fragment_tag != curr_bsr_fragment_tag || new_bsr_address != curr_bsr_address) { /* Throw away the old segment */ delete_rp_list(&segmented_cand_rp_list, &segmented_grp_mask_list); } curr_bsr_address = new_bsr_address; curr_bsr_priority = new_bsr_priority; curr_bsr_fragment_tag = new_bsr_fragment_tag; MASKLEN_TO_MASK(new_bsr_hash_masklen, curr_bsr_hash_mask); SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT); while (data_ptr + min_datalen <= max_data_ptr) { GET_EGADDR(&curr_group_addr, data_ptr); GET_BYTE(curr_rp_count, data_ptr); GET_BYTE(curr_frag_rp_count, data_ptr); GET_HOSTSHORT(reserved_short, data_ptr); MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask); if (curr_rp_count == 0) { delete_grp_mask(&cand_rp_list, &grp_mask_list, curr_group_addr.mcast_addr, curr_group_mask); continue; } if (curr_rp_count == curr_frag_rp_count) { /* Add all RPs */ while(curr_frag_rp_count--) { GET_EUADDR(&curr_rp_addr, data_ptr); GET_HOSTSHORT(curr_rp_holdtime, data_ptr); GET_BYTE(curr_rp_priority, data_ptr); GET_BYTE(reserved_byte, data_ptr); MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, curr_rp_addr.unicast_addr, curr_rp_priority, curr_rp_holdtime, curr_group_addr.mcast_addr, curr_group_mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); } continue; } /* * This is a partial list of the RPs for this group prefix. * Save until all segments arrive. */ prefix_h = ntohl(curr_group_addr.mcast_addr & curr_group_mask); for (grp_mask_ptr = segmented_grp_mask_list; grp_mask_ptr != (grp_mask_t *)NULL; grp_mask_ptr = grp_mask_ptr->next) { if (ntohl(grp_mask_ptr->group_addr & grp_mask_ptr->group_mask) > prefix_h) continue; else break; } if ((grp_mask_ptr != (grp_mask_t *)NULL) && (grp_mask_ptr->group_addr == curr_group_addr.mcast_addr) && (grp_mask_ptr->group_mask == curr_group_mask) && (grp_mask_ptr->group_rp_number + curr_frag_rp_count == curr_rp_count)) { /* All missing PRs have arrived. Add all RP entries */ while(curr_frag_rp_count--) { GET_EUADDR(&curr_rp_addr, data_ptr); GET_HOSTSHORT(curr_rp_holdtime, data_ptr); GET_BYTE(curr_rp_priority, data_ptr); GET_BYTE(reserved_byte, data_ptr); MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, curr_rp_addr.unicast_addr, curr_rp_priority, curr_rp_holdtime, curr_group_addr.mcast_addr, curr_group_mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); } /* Add the rest from the previously saved segments */ for(grp_rp_entry_ptr = grp_mask_ptr->grp_rp_next; grp_rp_entry_ptr != (rp_grp_entry_t *)NULL; grp_rp_entry_ptr = grp_rp_entry_ptr->grp_rp_next) { add_rp_grp_entry(&cand_rp_list, &grp_mask_list, grp_rp_entry_ptr->rp->rpentry->address, grp_rp_entry_ptr->priority, grp_rp_entry_ptr->holdtime, curr_group_addr.mcast_addr, curr_group_mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); } delete_grp_mask(&segmented_cand_rp_list, &segmented_grp_mask_list, curr_group_addr.mcast_addr, curr_group_mask); } else { /*Add the partially received RP-list to the group of pending RPs*/ while(curr_frag_rp_count--) { GET_EUADDR(&curr_rp_addr, data_ptr); GET_HOSTSHORT(curr_rp_holdtime, data_ptr); GET_BYTE(curr_rp_priority, data_ptr); GET_BYTE(reserved_byte, data_ptr); MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask); add_rp_grp_entry(&segmented_cand_rp_list, &segmented_grp_mask_list, curr_rp_addr.unicast_addr, curr_rp_priority, curr_rp_holdtime, curr_group_addr.mcast_addr, curr_group_mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); } } } /* Garbage collection. Check all group prefixes and if the * fragment_tag for a group_prefix is the same as curr_bsr_fragment_tag, * then remove all RPs for this group_prefix which have different * fragment tag. */ for (grp_mask_ptr = grp_mask_list; grp_mask_ptr != (grp_mask_t *)NULL; grp_mask_ptr = grp_mask_next) { grp_mask_next = grp_mask_ptr->next; if (grp_mask_ptr->fragment_tag == curr_bsr_fragment_tag) { for (grp_rp_entry_ptr = grp_mask_ptr->grp_rp_next; grp_rp_entry_ptr != (rp_grp_entry_t *)NULL; grp_rp_entry_ptr = grp_rp_entry_next) { grp_rp_entry_next = grp_rp_entry_ptr->grp_rp_next; if (grp_rp_entry_ptr->fragment_tag != curr_bsr_fragment_tag) delete_rp_grp_entry(&cand_rp_list, &grp_mask_list, grp_rp_entry_ptr); } } } /* Cleanup also the list used by incompleted segments */ for (grp_mask_ptr = segmented_grp_mask_list; grp_mask_ptr != (grp_mask_t *)NULL; grp_mask_ptr = grp_mask_next) { grp_mask_next = grp_mask_ptr->next; if (grp_mask_ptr->fragment_tag == curr_bsr_fragment_tag) { for (grp_rp_entry_ptr = grp_mask_ptr->grp_rp_next; grp_rp_entry_ptr != (rp_grp_entry_t *)NULL; grp_rp_entry_ptr = grp_rp_entry_next) { grp_rp_entry_next = grp_rp_entry_ptr->grp_rp_next; if (grp_rp_entry_ptr->fragment_tag != curr_bsr_fragment_tag) delete_rp_grp_entry(&segmented_cand_rp_list, &segmented_grp_mask_list, grp_rp_entry_ptr); } } } return TRUE; } void send_pim_bootstrap(void) { int datalen; vifi_t vifi; if ((datalen = create_pim_bootstrap_message(pim_send_buf))) { for (vifi = 0; vifi < numvifs; vifi++) { if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) continue; send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group, PIM_BOOTSTRAP, datalen); } } } /************************************************************************ * PIM_CAND_RP_ADV ************************************************************************/ /* * If I am the Bootstrap router, process the advertisement, otherwise * ignore it. */ #define PIM_CAND_RP_ADV_MINLEN (PIM_MINLEN + PIM_ENCODE_UNI_ADDR_LEN) int receive_pim_cand_rp_adv(u_int32 src, u_int32 dst __attribute__((unused)), char *pim_message, int datalen) { u_int8 prefix_cnt; u_int8 priority; u_int16 holdtime; pim_encod_uni_addr_t cand_rp_addr; pim_encod_grp_addr_t encod_grp_addr; u_int8 *data_ptr; u_int32 grp_mask; /* Checksum */ if (inet_cksum((u_int16 *)pim_message, datalen)) return FALSE; /* if I am not the bootstrap RP, then do not accept the message */ if (cand_bsr_flag == FALSE || curr_bsr_address != my_bsr_address) return FALSE; /* sanity check for the minimum length */ if (datalen < PIM_CAND_RP_ADV_MINLEN) { logit(LOG_NOTICE, 0, "receive_pim_cand_rp_adv: cand_RP message size(%u) is too short from %s", datalen, inet_fmt(src, s1, sizeof(s1))); return FALSE; } data_ptr = (u_int8 *)(pim_message + sizeof(pim_header_t)); /* Parse the CAND_RP_ADV message */ /* TODO: XXX: check datalen whether it is at least the minimum */ GET_BYTE(prefix_cnt, data_ptr); GET_BYTE(priority, data_ptr); GET_HOSTSHORT(holdtime, data_ptr); GET_EUADDR(&cand_rp_addr, data_ptr); if (prefix_cnt == 0) { /* The default 224.0.0.0 and masklen of 4 */ MASKLEN_TO_MASK(ALL_MCAST_GROUPS_LENGTH, grp_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, cand_rp_addr.unicast_addr, priority, holdtime, htonl(ALL_MCAST_GROUPS_ADDR), grp_mask, my_bsr_hash_mask, curr_bsr_fragment_tag); return TRUE; } while (prefix_cnt--) { GET_EGADDR(&encod_grp_addr, data_ptr); MASKLEN_TO_MASK(encod_grp_addr.masklen, grp_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, cand_rp_addr.unicast_addr, priority, holdtime, encod_grp_addr.mcast_addr, grp_mask, my_bsr_hash_mask, curr_bsr_fragment_tag); /* TODO: Check for datalen */ } return TRUE; } int send_pim_cand_rp_adv(void) { u_int8 prefix_cnt; u_int32 grp_mask; pim_encod_grp_addr_t encod_grp_addr; u_int8 *data_ptr; if (!inet_valid_host(curr_bsr_address)) return FALSE; /* No BSR yet */ if (curr_bsr_address == my_bsr_address) { /* I am the BSR and have to include my own group_prefix stuff */ prefix_cnt = *cand_rp_adv_message.prefix_cnt_ptr; if (prefix_cnt == 0) { /* The default 224.0.0.0 and masklen of 4 */ MASKLEN_TO_MASK(ALL_MCAST_GROUPS_LENGTH, grp_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, my_cand_rp_address, my_cand_rp_priority, my_cand_rp_holdtime, htonl(ALL_MCAST_GROUPS_ADDR), my_bsr_hash_mask, grp_mask, curr_bsr_fragment_tag); return TRUE; } /* TODO: hardcoding!! */ data_ptr = cand_rp_adv_message.buffer + (4 + 6); while (prefix_cnt--) { GET_EGADDR(&encod_grp_addr, data_ptr); MASKLEN_TO_MASK(encod_grp_addr.masklen, grp_mask); add_rp_grp_entry(&cand_rp_list, &grp_mask_list, my_cand_rp_address, my_cand_rp_priority, my_cand_rp_holdtime, encod_grp_addr.mcast_addr, grp_mask, my_bsr_hash_mask, curr_bsr_fragment_tag); /* TODO: Check for datalen */ } return TRUE; } data_ptr = (u_int8 *)(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t)); memcpy(data_ptr, cand_rp_adv_message.buffer, cand_rp_adv_message.message_size); send_pim_unicast(pim_send_buf, my_cand_rp_address, curr_bsr_address, PIM_CAND_RP_ADV, cand_rp_adv_message.message_size); return TRUE; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/vif.c0000644000000000000000000004666311700261371010306 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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 "defs.h" /* * Exported variables. */ struct uvif uvifs[MAXVIFS]; /* array of all virtual interfaces */ vifi_t numvifs; /* Number of vifs in use */ int vifs_down; /* 1=>some interfaces are down */ int phys_vif; /* An enabled vif */ vifi_t reg_vif_num; /* really virtual interface for registers */ int udp_socket; /* Since the honkin' kernel doesn't support * ioctls on raw IP sockets, we need a UDP * socket as well as our IGMP (raw) socket. */ int total_interfaces; /* Number of all interfaces: including the * non-configured, but excluding the * loopback interface and the non-multicast * capable interfaces. */ static void start_vif (vifi_t vifi); static void stop_vif (vifi_t vifi); static void start_all_vifs (void); static int init_reg_vif (void); static int update_reg_vif (vifi_t register_vifi); void init_vifs(void) { vifi_t vifi; struct uvif *v; int enabled_vifs; numvifs = 0; reg_vif_num = NO_VIF; vifs_down = FALSE; /* Configure the vifs based on the interface configuration of the the kernel and * the contents of the configuration file. (Open a UDP socket for ioctl use in * the config procedures if the kernel can't handle IOCTL's on the IGMP socket.) */ #ifdef IOCTL_OK_ON_RAW_SOCKET udp_socket = igmp_socket; #else if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) logit(LOG_ERR, errno, "UDP socket"); #endif /* Clean up all vifs */ for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) { zero_vif(v, FALSE); } logit(LOG_INFO, 0, "Getting vifs from kernel"); config_vifs_from_kernel(); if (disable_all_by_default) { logit(LOG_INFO, 0, "Disabling all vifs from kernel"); for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) v->uv_flags |= VIFF_DISABLED; } logit(LOG_INFO, 0, "Getting vifs from %s", configfilename); config_vifs_from_file(); /* * Quit if there are fewer than two enabled vifs. */ enabled_vifs = 0; phys_vif = -1; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* Initialize the outgoing timeout for each vif. Currently use a fixed time * 'PIM_JOIN_PRUNE_HOLDTIME'. Later, may add a configurable array to feed * these parameters, or compute them as function of the i/f bandwidth and the * overall connectivity...etc. */ SET_TIMER(v->uv_jp_timer, PIM_JOIN_PRUNE_HOLDTIME); if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL)) continue; if (phys_vif == -1) phys_vif = vifi; enabled_vifs++; } if (enabled_vifs < 1) /* XXX: TODO: */ logit(LOG_ERR, 0, "Cannot forward: %s", enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif"); k_init_pim(igmp_socket); /* Call to kernel to initialize structures */ /* Add a dummy virtual interface to support Registers in the kernel. * In order for this to work, the kernel has to have been modified * with the PIM patches to ip_mroute.{c,h} and ip.c */ init_reg_vif(); start_all_vifs(); } /* * Initialize the passed vif with all appropriate default values. * "t" is true if a tunnel or register_vif, or false if a phyint. */ void zero_vif(struct uvif *v, int t) { v->uv_flags = 0; v->uv_metric = DEFAULT_METRIC; v->uv_admetric = 0; v->uv_threshold = DEFAULT_THRESHOLD; v->uv_rate_limit = t ? DEFAULT_REG_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT; v->uv_lcl_addr = INADDR_ANY_N; v->uv_rmt_addr = INADDR_ANY_N; v->uv_dst_addr = t ? INADDR_ANY_N : allpimrouters_group; v->uv_subnet = INADDR_ANY_N; v->uv_subnetmask = INADDR_ANY_N; v->uv_subnetbcast = INADDR_ANY_N; strlcpy(v->uv_name, "", IFNAMSIZ); v->uv_groups = (struct listaddr *)NULL; v->uv_dvmrp_neighbors = (struct listaddr *)NULL; NBRM_CLRALL(v->uv_nbrmap); v->uv_querier = (struct listaddr *)NULL; v->uv_igmpv1_warn = 0; v->uv_prune_lifetime = 0; v->uv_acl = (struct vif_acl *)NULL; RESET_TIMER(v->uv_leaf_timer); v->uv_addrs = (struct phaddr *)NULL; v->uv_filter = (struct vif_filter *)NULL; RESET_TIMER(v->uv_pim_hello_timer); RESET_TIMER(v->uv_gq_timer); RESET_TIMER(v->uv_jp_timer); v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL; v->uv_local_pref = default_source_preference; v->uv_local_metric = default_source_metric; #ifdef __linux__ v->uv_ifindex = -1; #endif /* __linux__ */ } /* * Add a (the) register vif to the vif table. */ static int init_reg_vif(void) { struct uvif *v; vifi_t i; v = &uvifs[numvifs]; v->uv_flags = 0; if ((numvifs + 1) == MAXVIFS) { /* Exit the program! The PIM router must have a Register vif */ logit(LOG_ERR, 0, "Cannot install the Register vif: too many interfaces"); return FALSE; } /* * So far in PIM we need only one register vif and we save its number in * the global reg_vif_num. */ reg_vif_num = numvifs; /* set the REGISTER flag */ v->uv_flags = VIFF_REGISTER; #ifdef PIM_EXPERIMENTAL v->uv_flags |= VIFF_REGISTER_KERNEL_ENCAP; #endif strlcpy(v->uv_name, "register_vif0", sizeof(v->uv_name)); /* Use the address of the first available physical interface to * create the register vif. */ for (i = 0; i < numvifs; i++) { if (uvifs[i].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER | VIFF_TUNNEL)) continue; break; } if (i >= numvifs) { logit(LOG_ERR, 0, "No physical interface enabled"); return -1; } v->uv_lcl_addr = uvifs[i].uv_lcl_addr; v->uv_threshold = MINTTL; numvifs++; total_interfaces++; return 0; } static void start_all_vifs(void) { vifi_t vifi; struct uvif *v; u_int action; /* Start first the NON-REGISTER vifs */ for (action = 0; ; action = VIFF_REGISTER) { for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* If starting non-registers but the vif is a register or if starting * registers, but the interface is not a register, then just continue. */ if ((v->uv_flags & VIFF_REGISTER) ^ action) continue; /* Start vif if not DISABLED or DOWN */ if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) { if (v->uv_flags & VIFF_DISABLED) logit(LOG_INFO, 0, "Interface %s is DISABLED; vif #%u out of service", v->uv_name, vifi); else logit(LOG_INFO, 0, "Interface %s is DOWN; vif #%u out of service", v->uv_name, vifi); } else { start_vif(vifi); } } if (action == VIFF_REGISTER) break; /* We are done */ } } /* * stop all vifs */ void stop_all_vifs(void) { vifi_t vifi; struct uvif *v; for (vifi = 0; vifi < numvifs; vifi++) { v = &uvifs[vifi]; if (!(v->uv_flags & VIFF_DOWN)) stop_vif(vifi); } } /* * Initialize the vif and add to the kernel. The vif can be either * physical, register or tunnel (tunnels will be used in the future * when this code becomes PIM multicast boarder router. */ static void start_vif(vifi_t vifi) { struct uvif *v; v = &uvifs[vifi]; /* Initialy no router on any vif */ if (v->uv_flags & VIFF_REGISTER) v->uv_flags = v->uv_flags & ~VIFF_DOWN; else { v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN; SET_TIMER(v->uv_pim_hello_timer, 1 + RANDOM() % PIM_TIMER_HELLO_PERIOD); SET_TIMER(v->uv_jp_timer, 1 + RANDOM() % PIM_JOIN_PRUNE_PERIOD); /* TODO: CHECK THE TIMERS!!!!! Set or reset? */ RESET_TIMER(v->uv_gq_timer); v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL; } /* Tell kernel to add, i.e. start this vif */ k_add_vif(igmp_socket, vifi, &uvifs[vifi]); logit(LOG_INFO, 0, "Interface %s comes up; vif #%u now in service", v->uv_name, vifi); if (!(v->uv_flags & VIFF_REGISTER)) { /* * Join the PIM multicast group on the interface. */ k_join(igmp_socket, allpimrouters_group, v); /* * Join the ALL-ROUTERS multicast group on the interface. * This allows mtrace requests to loop back if they are run * on the multicast router. */ k_join(igmp_socket, allrouters_group, v); /* * Until neighbors are discovered, assume responsibility for sending * periodic group membership queries to the subnet. Send the first * query. */ v->uv_flags |= VIFF_QUERIER; query_groups(v); /* * Send a probe via the new vif to look for neighbors. */ send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME); } #ifdef __linux__ else { struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); /* strlcpy(ifr.ifr_name,v->uv_name, IFNAMSIZ); */ strlcpy(ifr.ifr_name, "pimreg", IFNAMSIZ); if (ioctl(udp_socket, SIOGIFINDEX, (char *) &ifr) < 0) { logit(LOG_ERR, errno, "ioctl SIOGIFINDEX for %s", ifr.ifr_name); /* Not reached */ return; } v->uv_ifindex = ifr.ifr_ifindex; } #endif /* __linux__ */ } /* * Stop a vif (either physical interface, tunnel or * register.) If we are running only PIM we don't have tunnels. */ static void stop_vif(vifi_t vifi) { struct uvif *v; struct listaddr *a; pim_nbr_entry_t *n, *next; struct vif_acl *acl; /* * TODO: make sure that the kernel viftable is * consistent with the daemon table */ v = &uvifs[vifi]; if (!(v->uv_flags & VIFF_REGISTER)) { k_leave(igmp_socket, allpimrouters_group, v); k_leave(igmp_socket, allrouters_group, v); /* * Discard all group addresses. (No need to tell kernel; * the k_del_vif() call will clean up kernel state.) */ while (v->uv_groups != NULL) { a = v->uv_groups; v->uv_groups = a->al_next; free((char *)a); } } /* * TODO: inform (eventually) the neighbors I am going down by sending * PIM_HELLO with holdtime=0 so someone else should become a DR. */ /* TODO: dummy! Implement it!! Any problems if don't use it? */ delete_vif_from_mrt(vifi); /* Delete the interface from the kernel's vif structure. */ k_del_vif(igmp_socket, vifi, v); v->uv_flags = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS) | VIFF_DOWN; if (!(v->uv_flags & VIFF_REGISTER)) { RESET_TIMER(v->uv_pim_hello_timer); RESET_TIMER(v->uv_jp_timer); RESET_TIMER(v->uv_gq_timer); for (n = v->uv_pim_neighbors; n != NULL; n = next) { next = n->next; /* Free the space for each neighbour */ free((char *)n); } v->uv_pim_neighbors = NULL; } /* TODO: currently not used */ /* The Access Control List (list with the scoped addresses) */ while (v->uv_acl != NULL) { acl = v->uv_acl; v->uv_acl = acl->acl_next; free((char *)acl); } vifs_down = TRUE; logit(LOG_INFO, 0, "Interface %s goes down; vif #%u out of service", v->uv_name, vifi); } /* * Update the register vif in the multicast routing daemon and the * kernel because the interface used initially to get its local address * is DOWN. register_vifi is the index to the Register vif which needs * to be updated. As a result the Register vif has a new uv_lcl_addr and * is UP (virtually :)) */ static int update_reg_vif(vifi_t register_vifi) { struct uvif *v; vifi_t vifi; /* Find the first useable vif with solid physical background */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL)) continue; /* Found. Stop the bogus Register vif first */ stop_vif(register_vifi); uvifs[register_vifi].uv_lcl_addr = uvifs[vifi].uv_lcl_addr; start_vif(register_vifi); IF_DEBUG(DEBUG_PIM_REGISTER | DEBUG_IF) { logit(LOG_NOTICE, 0, "Interface %s has come up; vif #%u now in service", uvifs[register_vifi].uv_name, register_vifi); } return 0; } vifs_down = TRUE; logit(LOG_WARNING, 0, "Cannot start Register vif: %s", uvifs[vifi].uv_name); return -1; } /* * See if any interfaces have changed from up state to down, or vice versa, * including any non-multicast-capable interfaces that are in use as local * tunnel end-points. Ignore interfaces that have been administratively * disabled. */ void check_vif_state(void) { vifi_t vifi; struct uvif *v; struct ifreq ifr; static int checking_vifs = 0; /* * XXX: TODO: True only for DVMRP?? Check. * If we get an error while checking, (e.g. two interfaces go down * at once, and we decide to send a prune out one of the failed ones) * then don't go into an infinite loop! */ if (checking_vifs) return; vifs_down = FALSE; checking_vifs = 1; /* TODO: Check all potential interfaces!!! */ /* Check the physical and tunnels only */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_flags & (VIFF_DISABLED | VIFF_REGISTER)) continue; /* get the interface flags */ strlcpy(ifr.ifr_name, v->uv_name, sizeof(ifr.ifr_name)); if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) { if (errno == ENODEV) { logit(LOG_NOTICE, 0, "Interface %s has gone; vif #%u taken out of service", v->uv_name, vifi); stop_vif(vifi); vifs_down = TRUE; continue; } logit(LOG_ERR, errno, "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); } if (v->uv_flags & VIFF_DOWN) { if (ifr.ifr_flags & IFF_UP) start_vif(vifi); else vifs_down = TRUE; } else { if (!(ifr.ifr_flags & IFF_UP)) { logit(LOG_NOTICE, 0, "Interface %s has gone down; vif #%u taken out of service", v->uv_name, vifi); stop_vif(vifi); vifs_down = TRUE; } } } /* Check the register(s) vif(s) */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { vifi_t vifi2; struct uvif *v2; int found; if (!(v->uv_flags & VIFF_REGISTER)) continue; found = 0; /* Find a physical vif with the same IP address as the * Register vif. */ for (vifi2 = 0, v2 = uvifs; vifi2 < numvifs; ++vifi2, ++v2) { if (v2->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL)) continue; if (v->uv_lcl_addr != v2->uv_lcl_addr) continue; found = 1; break; } /* The physical interface with the IP address as the Register * vif is probably DOWN. Get a replacement. */ if (!found) update_reg_vif(vifi); } checking_vifs = 0; } /* * If the source is directly connected to us, find the vif number for * the corresponding physical interface (Register and tunnels excluded). * Local addresses are excluded. * Return the vif number or NO_VIF if not found. */ vifi_t find_vif_direct(u_int32 src) { vifi_t vifi; struct uvif *v; struct phaddr *p; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL)) continue; if (src == v->uv_lcl_addr) return NO_VIF; /* src is one of our IP addresses */ if ((src & v->uv_subnetmask) == v->uv_subnet && ((v->uv_subnetmask == 0xffffffff) || (src != v->uv_subnetbcast))) return vifi; /* Check the extra subnets for this vif */ /* TODO: don't think currently pimd can handle extra subnets */ for (p = v->uv_addrs; p; p = p->pa_next) { if ((src & p->pa_subnetmask) == p->pa_subnet && ((p->pa_subnetmask == 0xffffffff) || (src != p->pa_subnetbcast))) return vifi; } /* POINTOPOINT but not VIFF_TUNNEL interface (e.g., GRE) */ if ((v->uv_flags & VIFF_POINT_TO_POINT) && (src == v->uv_rmt_addr)) return vifi; } return NO_VIF; } /* * Checks if src is local address. If "yes" return the vif index, * otherwise return value is NO_VIF. */ vifi_t local_address(u_int32 src) { vifi_t vifi; struct uvif *v; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* TODO: XXX: what about VIFF_TUNNEL? */ if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) continue; if (src != v->uv_lcl_addr) continue; else return vifi; } /* Returning NO_VIF means not a local address */ return NO_VIF; } /* * If the source is directly connected, or is local address, * find the vif number for the corresponding physical interface * (Register and tunnels excluded). * Return the vif number or NO_VIF if not found. */ vifi_t find_vif_direct_local(u_int32 src) { vifi_t vifi; struct uvif *v; struct phaddr *p; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* TODO: XXX: what about VIFF_TUNNEL? */ if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_TUNNEL)) continue; if (src == v->uv_lcl_addr) return vifi; /* src is one of our IP addresses */ if (((src & v->uv_subnetmask) == v->uv_subnet) && ((v->uv_subnetmask == 0xffffffff) || (src != v->uv_subnetbcast))) return vifi; /* Check the extra subnets for this vif */ /* TODO: don't think currently pimd can handle extra subnets */ for (p = v->uv_addrs; p; p = p->pa_next) { if (((src & p->pa_subnetmask) == p->pa_subnet) && ((p->pa_subnetmask == 0xffffffff) || (src != p->pa_subnetbcast))) return vifi; } /* POINTOPOINT but not VIFF_TUNNEL interface (e.g., GRE) */ if ((v->uv_flags & VIFF_POINT_TO_POINT) && (src == v->uv_rmt_addr)) return vifi; } return NO_VIF; } /* * Returns the highest address of local vif that is UP and ENABLED. * The VIFF_REGISTER interface(s) is/are excluded. */ u_int32 max_local_address(void) { vifi_t vifi; struct uvif *v; u_int32 max_address = 0; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { /* Count vif if not DISABLED or DOWN */ /* TODO: XXX: What about VIFF_TUNNEL? */ if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) continue; if (ntohl(v->uv_lcl_addr) > ntohl(max_address)) max_address = v->uv_lcl_addr; } return max_address; } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/rsrr.h0000644000000000000000000001560111700261371010503 0ustar /* * Copyright (c) 1993, 1998-2001. * The University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define RSRR_SERV_PATH "/tmp/.rsrr_svr" /* Note this needs to be 14 chars for 4.3 BSD compatibility */ #define RSRR_CLI_PATH "/tmp/.rsrr_cli" #define RSRR_MAX_LEN 2048 #define RSRR_HEADER_LEN (sizeof(struct rsrr_header)) #define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq)) #define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr)) #define RSRR_VIF_LEN (sizeof(struct rsrr_vif)) /* Current maximum number of vifs. */ #define RSRR_MAX_VIFS 32 /* Maximum acceptable version */ #define RSRR_MAX_VERSION 1 /* RSRR message types */ #define RSRR_ALL_TYPES 0 #define RSRR_INITIAL_QUERY 1 #define RSRR_INITIAL_REPLY 2 #define RSRR_ROUTE_QUERY 3 #define RSRR_ROUTE_REPLY 4 /* Each definition represents the position of the bit from right to left. */ /* All not defined bits are zeroes */ /* RSRR Initial Reply (Vif) Status bits * * 0 = disabled bit, set if the vif is administratively disabled. */ #define RSRR_DISABLED_BIT 0 /* RSRR Route Query/Reply flag bits * * 0 = Route Change Notification bit, set if the reservation protocol * wishes to receive notification of a route change for the * source-destination pair listed in the query. Notification is in the * form of an unsolicitied Route Reply. * 1 = Error bit, set if routing doesn't have a routing entry for * the source-destination pair. * (TODO: XXX: currently not used by rsvpd?) * (2,3) = Shared tree (Reply only) * = 01 if the listed sender is using a shared tree, but some other * senders for the same destination use sender (source-specific) * trees. * = 10 if all senders for the destination use shared tree. * = 00 otherwise */ #define RSRR_NOTIFICATION_BIT 0 #define RSRR_ERROR_BIT 1 #define RSRR_THIS_SENDER_SHARED_TREE 2 #define RSRR_ALL_SENDERS_SHARED_TREE 3 #define RSRR_SET_ALL_SENDERS_SHARED_TREE(X) \ BIT_SET((X), RSRR_ALL_SENDERS_SHARED_TREE); \ BIT_CLR((X), RSRR_THIS_SENDER_SHARED_TREE); #define RSRR_THIS_SENDER_SHARED_TREE_SOME_OTHER_NOT(X) \ BIT_SET((X), RSRR_THIS_SENDER_SHARED_TREE); \ BIT_CLR((X), RSRR_ALL_SENDERS_SHARED_TREE) /* Definition of an RSRR message header. * An Initial Query uses only the header, and an Initial Reply uses * the header and a list of vifs. */ struct rsrr_header { u_int8 version; /* RSRR Version, currently 1 */ u_int8 type; /* type of message, as defined above*/ u_int8 flags; /* flags; defined by type */ u_int8 num; /* number; defined by type */ }; /* Definition of a vif as seen by the reservation protocol. * * Routing gives the reservation protocol a list of vifs in the * Initial Reply. * * We explicitly list the ID because we can't assume that all routing * protocols will use the same numbering scheme. * * The status is a bitmask of status flags, as defined above. It is the * responsibility of the reservation protocol to perform any status checks * if it uses the MULTICAST_VIF socket option. * * The threshold indicates the ttl an outgoing packet needs in order to * be forwarded. The reservation protocol must perform this check itself if * it uses the MULTICAST_VIF socket option. * * The local address is the address of the physical interface over which * packets are sent. */ struct rsrr_vif { u_int8 id; /* vif id */ u_int8 threshold; /* vif threshold ttl */ u_int16 status; /* vif status bitmask */ u_int32 local_addr; /* vif local address */ }; /* Definition of an RSRR Route Query. * * The query asks routing for the forwarding entry for a particular * source and destination. The query ID uniquely identifies the query * for the reservation protocol. Thus, the combination of the client's * address and the query ID forms a unique identifier for routing. * Flags are defined above. */ struct rsrr_rq { u_int32 dest_addr; /* destination */ u_int32 source_addr; /* source */ u_int32 query_id; /* query ID */ }; /* Definition of an RSRR Route Reply. * * Routing uses the reply to give the reservation protocol the * forwarding entry for a source-destination pair. Routing copies the * query ID from the query and fills in the incoming vif and a bitmask * of the outgoing vifs. * Flags are defined above. */ /* TODO: XXX: in_vif is 16 bits here, but in rsrr_vif it is 8 bits. * Bug in the spec? */ struct rsrr_rr { u_int32 dest_addr; /* destination */ u_int32 source_addr; /* source */ u_int32 query_id; /* query ID */ u_int16 in_vif; /* incoming vif */ u_int16 reserved; /* reserved */ u_int32 out_vif_bm; /* outgoing vif bitmask */ }; /* TODO: XXX: THIS IS NOT IN THE SPEC! (OBSOLETE?) */ #ifdef NOT_IN_THE_SPEC /* Definition of an RSRR Service Query/Reply. * * The query asks routing to perform a service for a particular * source/destination combination. The query also lists the vif * that the service applies to. */ struct rsrr_sqr { u_int32 dest_addr; /* destination */ u_int32 source_addr; /* source */ u_int32 query_id; /* query ID */ u_int16 vif; /* vif */ u_int16 reserved; /* reserved */ }; #endif /* NOT_IN_THE_SPEC */ pimd-2.1.8/timer.c0000644000000000000000000010406311700261371010627 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: timer.c,v 1.31 2001/09/10 20:31:37 pavlin Exp $ */ #include "defs.h" /* * Global variables */ /* * XXX: The RATE is in bits/s. To include the header overhead, * the approximation is 1 byte/s = 10 bits/s * `whatever_bytes` is the maximum number of bytes within the test interval. */ u_int32 pim_reg_rate_bytes = (PIM_DEFAULT_REG_RATE * PIM_DEFAULT_REG_RATE_INTERVAL) / 10; u_int32 pim_reg_rate_check_interval = PIM_DEFAULT_REG_RATE_INTERVAL; u_int32 pim_data_rate_bytes = (PIM_DEFAULT_DATA_RATE * PIM_DEFAULT_DATA_RATE_INTERVAL) / 10; u_int32 pim_data_rate_check_interval = PIM_DEFAULT_DATA_RATE_INTERVAL; /* * Local functions definitions. */ /* * Local variables */ u_int16 unicast_routing_timer; /* Used to check periodically for any * change in the unicast routing. */ u_int16 unicast_routing_check_interval; u_int8 ucast_flag; /* Used to indicate there was a timeout */ u_int16 pim_data_rate_timer; /* Used to check periodically the datarate * of the active sources and eventually * switch to the shortest path * (if forwarder) */ u_int8 pim_data_rate_flag; /* Used to indicate there was a timeout */ u_int16 pim_reg_rate_timer; /* The same as above, but used by the RP * to switch to the shortest path * and avoid the PIM registers. */ u_int8 pim_reg_rate_flag; u_int8 rate_flag; /* * TODO: XXX: the timers below are not used. Instead, the data rate timer * is used. */ u_int16 kernel_cache_timer; /* Used to timeout the kernel cache * entries for idle sources */ u_int16 kernel_cache_check_interval; /* to request and compare any route changes */ srcentry_t srcentry_save; rpentry_t rpentry_save; /* * Init some timers */ void init_timers() { unicast_routing_check_interval = UCAST_ROUTING_CHECK_INTERVAL; SET_TIMER(unicast_routing_timer, unicast_routing_check_interval); /* The routing_check and the rate_check timers are interleaved to * reduce the amount of work that has to be done at once. */ /* XXX: for simplicity, both the intervals are the same */ if (pim_data_rate_check_interval < pim_reg_rate_check_interval) pim_reg_rate_check_interval = pim_data_rate_check_interval; SET_TIMER(pim_data_rate_timer, 3*pim_data_rate_check_interval/2); SET_TIMER(pim_reg_rate_timer, 3*pim_reg_rate_check_interval/2); /* Initialize the srcentry and rpentry used to save the old routes * during unicast routing change discovery process. */ srcentry_save.prev = (srcentry_t *)NULL; srcentry_save.next = (srcentry_t *)NULL; srcentry_save.address = INADDR_ANY_N; srcentry_save.mrtlink = (mrtentry_t *)NULL; srcentry_save.incoming = NO_VIF; srcentry_save.upstream = (pim_nbr_entry_t *)NULL; srcentry_save.metric = ~0; srcentry_save.preference = ~0; RESET_TIMER(srcentry_save.timer); srcentry_save.cand_rp = (cand_rp_t *)NULL; rpentry_save.prev = (rpentry_t *)NULL; rpentry_save.next = (rpentry_t *)NULL; rpentry_save.address = INADDR_ANY_N; rpentry_save.mrtlink = (mrtentry_t *)NULL; rpentry_save.incoming = NO_VIF; rpentry_save.upstream = (pim_nbr_entry_t *)NULL; rpentry_save.metric = ~0; rpentry_save.preference = ~0; RESET_TIMER(rpentry_save.timer); rpentry_save.cand_rp = (cand_rp_t *)NULL; } /* * On every timer interrupt, advance (i.e. decrease) the timer for each * neighbor and group entry for each vif. */ void age_vifs() { vifi_t vifi; register struct uvif *v; register pim_nbr_entry_t *next_nbr, *curr_nbr; /* XXX: TODO: currently, sending to qe* interface which is DOWN * doesn't return error (ENETDOWN) on my Solaris machine, * so have to check periodically the * interfaces status. If this is fixed, just remove the defs around * the "if (vifs_down)" line. */ #if (!((defined SunOS) && (SunOS >= 50))) if (vifs_down) #endif /* Solaris */ check_vif_state(); /* Age many things */ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER)) continue; /* Timeout neighbors */ for (curr_nbr = v->uv_pim_neighbors; curr_nbr != NULL; curr_nbr = next_nbr) { next_nbr = curr_nbr->next; /* * Never timeout neighbors with holdtime = 0xffff. * This may be used with ISDN lines to avoid keeping the * link up with periodic Hello messages. */ /* TODO: XXX: TIMER implem. dependency! */ if (PIM_MESSAGE_HELLO_HOLDTIME_FOREVER == curr_nbr->timer) continue; IF_NOT_TIMEOUT(curr_nbr->timer) continue; delete_pim_nbr(curr_nbr); } /* PIM_HELLO periodic */ IF_TIMEOUT(v->uv_pim_hello_timer) send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME); #ifdef TOBE_DELETED /* PIM_JOIN_PRUNE periodic */ /* TODO: XXX: TIMER implem. dependency! */ if (v->uv_jp_timer <= TIMER_INTERVAL) /* TODO: need to scan the whole routing table, * because different entries have different Join/Prune timer. * Probably don't need the Join/Prune timer per vif. */ send_pim_join_prune(vifi, (pim_nbr_entry_t *)NULL, PIM_JOIN_PRUNE_HOLDTIME); else /* TODO: XXX: TIMER implem. dependency! */ v->uv_jp_timer -= TIMER_INTERVAL; #endif /* TOBE_DELETED */ /* IGMP query periodic */ IF_TIMEOUT(v->uv_gq_timer) query_groups(v); } IF_DEBUG(DEBUG_IF) dump_vifs(stderr); } /* * Scan the whole routing table and timeout a bunch of timers: * - oifs timers * - Join/Prune timer * - routing entry * - Assert timer * - Register-Suppression timer * * - If the global timer for checking the unicast routing has expired, perform * also iif/upstream router change verification * - If the global timer for checking the data rate has expired, check the * number of bytes forwarded after the lastest timeout. If bigger than * a given threshold, then switch to the shortest path. * If `number_of_bytes == 0`, then delete the kernel cache entry. * * Only the entries which have the Join/Prune timer expired are sent. * In the special case when we have ~(S,G)RPbit Prune entry, we must * include any (*,G) or (*,*,RP) XXX: ???? what and why? * * Below is a table which summarizes the segmantic rules. * * On the left side is "if A must be included in the J/P message". * On the top is "shall/must include B?" * "Y" means "MUST include" * "SY" means "SHOULD include" * "N" means "NO NEED to include" * (G is a group that matches to RP) * * -----------||-----------||----------- * || (*,*,RP) || (*,G) || (S,G) || * ||-----------||-----------||-----------|| * || J | P || J | P || J | P || * ==================================================|| * J || n/a | n/a || N | Y || N | Y || * (*,*,RP) -----------------------------------------|| * P || n/a | n/a || SY | N || SY | N || * ==================================================|| * J || N | N || n/a | n/a || N | Y || * (*,G) -----------------------------------------|| * P || N | N || n/a | n/a || SY | N || * ==================================================|| * J || N | N || N | N || n/a | n/a || * (S,G) -----------------------------------------|| * P || N | N || N | N || n/a | n/a || * ================================================== * */ void age_routes() { cand_rp_t *cand_rp_ptr; grpentry_t *grpentry_ptr; grpentry_t *grpentry_ptr_next; mrtentry_t *mrtentry_grp; mrtentry_t *mrtentry_rp; mrtentry_t *mrtentry_wide; mrtentry_t *mrtentry_srcs; mrtentry_t *mrtentry_srcs_next; struct uvif *v; vifi_t vifi; pim_nbr_entry_t *pim_nbr_ptr; int change_flag; int rp_action, grp_action, src_action = PIM_ACTION_NOTHING, src_action_rp = PIM_ACTION_NOTHING; int dont_calc_action; int did_switch_flag; rp_grp_entry_t *rp_grp_entry_ptr; kernel_cache_t *kernel_cache_ptr; kernel_cache_t *kernel_cache_next; u_long curr_bytecnt; rpentry_t *rpentry_ptr; int update_rp_iif; int update_src_iif; vifbitmap_t new_pruned_oifs; /* * Timing out of the global `unicast_routing_timer` * and `data_rate_timer` */ IF_TIMEOUT(unicast_routing_timer) { ucast_flag = TRUE; SET_TIMER(unicast_routing_timer, unicast_routing_check_interval); } ELSE { ucast_flag = FALSE; } IF_TIMEOUT(pim_data_rate_timer) { pim_data_rate_flag = TRUE; SET_TIMER(pim_data_rate_timer, pim_data_rate_check_interval); } ELSE { pim_data_rate_flag = FALSE; } IF_TIMEOUT(pim_reg_rate_timer) { pim_reg_rate_flag = TRUE; SET_TIMER(pim_reg_rate_timer, pim_reg_rate_check_interval); } ELSE { pim_reg_rate_flag = FALSE; } rate_flag = pim_data_rate_flag | pim_reg_rate_flag; /* Scan the (*,*,RP) entries */ for (cand_rp_ptr = cand_rp_list; cand_rp_ptr != (cand_rp_t *)NULL; cand_rp_ptr = cand_rp_ptr->next) { rpentry_ptr = cand_rp_ptr->rpentry; /* Need to save only `incoming` and `upstream` to discover * unicast route changes. `metric` and `preference` are not * interesting for us. */ rpentry_save.incoming = rpentry_ptr->incoming; rpentry_save.upstream = rpentry_ptr->upstream; update_rp_iif = FALSE; if ((ucast_flag == TRUE) && (rpentry_ptr->address != my_cand_rp_address)) { /* I am not the RP. If I was the RP, then the iif is * register_vif and no need to reset it. */ if (set_incoming(rpentry_ptr, PIM_IIF_RP) != TRUE) { /* TODO: XXX: no route to that RP. Panic? There is a high * probability the network is partitioning so immediately * remapping to other RP is not a good idea. Better wait * the Bootstrap mechanism to take care of it and provide * me with correct Cand-RP-Set. */ ; } else { if ((rpentry_save.upstream != rpentry_ptr->upstream) || (rpentry_save.incoming != rpentry_ptr->incoming)) { /* Routing change has occur. Update all (*,G) * and (S,G)RPbit iifs mapping to that RP */ update_rp_iif = TRUE; } } } rp_action = PIM_ACTION_NOTHING; mrtentry_rp = cand_rp_ptr->rpentry->mrtlink; if (mrtentry_rp != (mrtentry_t *)NULL) { /* outgoing interfaces timers */ change_flag = FALSE; for (vifi = 0; vifi < numvifs; vifi++) { if (VIFM_ISSET(vifi, mrtentry_rp->joined_oifs)) { IF_TIMEOUT(mrtentry_rp->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_rp->joined_oifs); change_flag = TRUE; } } } if ((change_flag == TRUE) || (update_rp_iif == TRUE)) { change_interfaces(mrtentry_rp, rpentry_ptr->incoming, mrtentry_rp->joined_oifs, mrtentry_rp->pruned_oifs, mrtentry_rp->leaves, mrtentry_rp->asserted_oifs, 0); mrtentry_rp->upstream = rpentry_ptr->upstream; } if (rate_flag == TRUE) { /* Check the activity for this entry */ /* XXX: the spec says to start monitoring first the * total traffic for all senders for particular (*,*,RP) * or (*,G) and if the total traffic exceeds some * predefined threshold, then start monitoring the data * traffic for each particular sender for this group: * (*,G) or (*,*,RP). However, because the kernel * cache/traffic info is of the form (S,G), it is easier * if we are simply collecting (S,G) traffic all the time. * * For (*,*,RP) if the number of bytes received between * the last check and now exceeds some precalculated * value (based on interchecking period and datarate * threshold AND if there are directly connected * members (i.e. we are their last hop(e) router), then * create (S,G) and start initiating (S,G) Join toward * the source. The same applies for (*,G). * The spec does not say that if the datarate goes * below a given threshold, then will switch back to the * shared tree, hence after a switch to the source-specific * tree occurs, a source with low datarate, but * periodically sending will keep the (S,G) states. * * If a source with kernel cache entry has been idle * after the last time a check of the datarate for the * whole routing table, then delete its kernel cache * entry. */ for (kernel_cache_ptr = mrtentry_rp->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_next) { kernel_cache_next = kernel_cache_ptr->next; curr_bytecnt = kernel_cache_ptr->sg_count.bytecnt; if (k_get_sg_cnt(udp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, &kernel_cache_ptr->sg_count) || (curr_bytecnt == kernel_cache_ptr->sg_count.bytecnt)) { /* Either for some reason there is no such * routing entry or that particular (s,g) was * idle. Delete the routing entry from the kernel. */ delete_single_kernel_cache(mrtentry_rp, kernel_cache_ptr); continue; } /* Check if the datarate was high enough to switch * to source specific tree. */ /* Forwarder initiated switch */ did_switch_flag = FALSE; if (curr_bytecnt + pim_data_rate_bytes < kernel_cache_ptr->sg_count.bytecnt) { if (VIFM_LASTHOP_ROUTER(mrtentry_rp->leaves, mrtentry_rp->oifs)) { #ifdef KERNEL_MFC_WC_G if (kernel_cache_ptr->source == INADDR_ANY_N) { delete_single_kernel_cache(mrtentry_rp, kernel_cache_ptr); mrtentry_rp->flags |= MRTF_MFC_CLONE_SG; continue; } #endif /* KERNEL_MFC_WC_G */ switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); did_switch_flag = TRUE; } } /* RP initiated switch */ if ((did_switch_flag == FALSE) && (curr_bytecnt + pim_reg_rate_bytes < kernel_cache_ptr->sg_count.bytecnt)) { if (mrtentry_rp->incoming == reg_vif_num) { #ifdef KERNEL_MFC_WC_G if (kernel_cache_ptr->source == INADDR_ANY_N) { delete_single_kernel_cache(mrtentry_rp, kernel_cache_ptr); mrtentry_rp->flags |= MRTF_MFC_CLONE_SG; continue; } #endif /* KERNEL_MFC_WC_G */ switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); } } } } /* Join/Prune timer */ IF_TIMEOUT(mrtentry_rp->jp_timer) { rp_action = join_or_prune(mrtentry_rp, mrtentry_rp->upstream); if (rp_action != PIM_ACTION_NOTHING) add_jp_entry(mrtentry_rp->upstream, PIM_JOIN_PRUNE_HOLDTIME, htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, mrtentry_rp->source->address, SINGLE_SRC_MSKLEN, MRTF_RP | MRTF_WC, rp_action); SET_TIMER(mrtentry_rp->jp_timer, PIM_JOIN_PRUNE_PERIOD); } /* Assert timer */ if (mrtentry_rp->flags & MRTF_ASSERTED) { IF_TIMEOUT(mrtentry_rp->assert_timer) { /* TODO: XXX: reset the upstream router now */ mrtentry_rp->flags &= ~MRTF_ASSERTED; } } /* Register-Suppression timer */ /* TODO: to reduce the kernel calls, if the timer is running, * install a negative cache entry in the kernel? */ /* TODO: can we have Register-Suppression timer for (*,*,RP)? * Currently no... */ IF_TIMEOUT(mrtentry_rp->rs_timer) {} /* routing entry */ if ((TIMEOUT(mrtentry_rp->timer)) && (VIFM_ISEMPTY(mrtentry_rp->leaves))) { delete_mrtentry(mrtentry_rp); } } /* mrtentry_rp != NULL */ /* Just in case if that (*,*,RP) was deleted */ mrtentry_rp = cand_rp_ptr->rpentry->mrtlink; /* Check the (*,G) and (S,G) entries */ for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr_next) { grpentry_ptr_next = grpentry_ptr->rpnext; mrtentry_grp = grpentry_ptr->grp_route; mrtentry_srcs = grpentry_ptr->mrtlink; grp_action = PIM_ACTION_NOTHING; if (mrtentry_grp != (mrtentry_t *)NULL) { /* The (*,G) entry */ /* outgoing interfaces timers */ change_flag = FALSE; for (vifi = 0; vifi < numvifs; vifi++) { if (VIFM_ISSET(vifi, mrtentry_grp->joined_oifs)) IF_TIMEOUT(mrtentry_grp->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_grp->joined_oifs); change_flag = TRUE; } } if ((change_flag == TRUE) || (update_rp_iif == TRUE)) { change_interfaces(mrtentry_grp, rpentry_ptr->incoming, mrtentry_grp->joined_oifs, mrtentry_grp->pruned_oifs, mrtentry_grp->leaves, mrtentry_grp->asserted_oifs, 0); mrtentry_grp->upstream = rpentry_ptr->upstream; } /* Check the sources activity */ if (rate_flag == TRUE) { for (kernel_cache_ptr = mrtentry_grp->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_next) { kernel_cache_next = kernel_cache_ptr->next; curr_bytecnt = kernel_cache_ptr->sg_count.bytecnt; if (k_get_sg_cnt(udp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, &kernel_cache_ptr->sg_count) || (curr_bytecnt == kernel_cache_ptr->sg_count.bytecnt)) { /* Either for whatever reason there is * no such routing entry or that * particular (s,g) was idle. * Delete the routing entry from * the kernel. */ delete_single_kernel_cache(mrtentry_grp, kernel_cache_ptr); continue; } /* Check if the datarate was high enough to * switch to source specific tree. */ /* Forwarder initiated switch */ did_switch_flag = FALSE; if (curr_bytecnt + pim_data_rate_bytes < kernel_cache_ptr->sg_count.bytecnt) { if (VIFM_LASTHOP_ROUTER(mrtentry_grp->leaves, mrtentry_grp->oifs)) { #ifdef KERNEL_MFC_WC_G if (kernel_cache_ptr->source == INADDR_ANY_N) { delete_single_kernel_cache(mrtentry_grp, kernel_cache_ptr); mrtentry_grp->flags |= MRTF_MFC_CLONE_SG; continue; } #endif /* KERNEL_MFC_WC_G */ switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); did_switch_flag = TRUE; } } /* RP initiated switch */ if ((did_switch_flag == FALSE) && (curr_bytecnt + pim_reg_rate_bytes < kernel_cache_ptr->sg_count.bytecnt)){ if (mrtentry_grp->incoming == reg_vif_num) { #ifdef KERNEL_MFC_WC_G if (kernel_cache_ptr->source == INADDR_ANY_N) { delete_single_kernel_cache(mrtentry_grp, kernel_cache_ptr); mrtentry_grp->flags |= MRTF_MFC_CLONE_SG; continue; } #endif /* KERNEL_MFC_WC_G */ switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); } } } } dont_calc_action = FALSE; if (rp_action != PIM_ACTION_NOTHING) { grp_action = join_or_prune(mrtentry_grp, mrtentry_grp->upstream); dont_calc_action = TRUE; if (((rp_action == PIM_ACTION_JOIN) && (grp_action == PIM_ACTION_PRUNE)) || ((rp_action == PIM_ACTION_PRUNE) && (grp_action == PIM_ACTION_JOIN))) FIRE_TIMER(mrtentry_grp->jp_timer); } /* Join/Prune timer */ IF_TIMEOUT(mrtentry_grp->jp_timer) { if (dont_calc_action != TRUE) grp_action = join_or_prune(mrtentry_grp, mrtentry_grp->upstream); if (grp_action != PIM_ACTION_NOTHING) add_jp_entry(mrtentry_grp->upstream, PIM_JOIN_PRUNE_HOLDTIME, mrtentry_grp->group->group, SINGLE_GRP_MSKLEN, cand_rp_ptr->rpentry->address, SINGLE_SRC_MSKLEN, MRTF_RP | MRTF_WC, grp_action); SET_TIMER(mrtentry_grp->jp_timer, PIM_JOIN_PRUNE_PERIOD); } /* Assert timer */ if (mrtentry_grp->flags & MRTF_ASSERTED) { IF_TIMEOUT(mrtentry_grp->assert_timer) { /* TODO: XXX: reset the upstream router now */ mrtentry_grp->flags &= ~MRTF_ASSERTED; } } /* Register-Suppression timer */ /* TODO: to reduce the kernel calls, if the timer * is running, install a negative cache entry in * the kernel? */ /* TODO: currently cannot have Register-Suppression * timer for (*,G) entry, but keep this around. */ IF_TIMEOUT(mrtentry_grp->rs_timer) {} /* routing entry */ if ((TIMEOUT(mrtentry_grp->timer)) && (VIFM_ISEMPTY(mrtentry_grp->leaves))) { delete_mrtentry(mrtentry_grp); } } /* if (mrtentry_grp != NULL) */ /* For all (S,G) for this group */ /* XXX: mrtentry_srcs was set before */ for ( ; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs_next) { /* routing entry */ mrtentry_srcs_next = mrtentry_srcs->grpnext; /* outgoing interfaces timers */ change_flag = FALSE; for (vifi = 0; vifi < numvifs; vifi++) { if (VIFM_ISSET(vifi, mrtentry_srcs->joined_oifs)) { /* TODO: checking for reg_num_vif is slow! */ if (vifi != reg_vif_num) { IF_TIMEOUT(mrtentry_srcs->vif_timers[vifi]) { VIFM_CLR(vifi, mrtentry_srcs->joined_oifs); change_flag = TRUE; } } } } update_src_iif = FALSE; if (ucast_flag == TRUE) { if (!(mrtentry_srcs->flags & MRTF_RP)) { /* iif toward the source */ srcentry_save.incoming = mrtentry_srcs->source->incoming; srcentry_save.upstream = mrtentry_srcs->source->upstream; if (set_incoming(mrtentry_srcs->source, PIM_IIF_SOURCE) != TRUE) { /* * XXX: not in the spec! * Cannot find route toward that source. * This is bad. Delete the entry. */ delete_mrtentry(mrtentry_srcs); continue; } else { /* iif info found */ if ((srcentry_save.incoming != mrtentry_srcs->incoming) || (srcentry_save.upstream != mrtentry_srcs->upstream)) { /* Route change has occur */ update_src_iif = TRUE; mrtentry_srcs->incoming = mrtentry_srcs->source->incoming; mrtentry_srcs->upstream = mrtentry_srcs->source->upstream; } } } else { /* (S,G)RPBit with iif toward RP */ if ((rpentry_save.upstream != mrtentry_srcs->upstream) || (rpentry_save.incoming != mrtentry_srcs->incoming)) { update_src_iif = TRUE; /* XXX: a hack */ /* XXX: setup the iif now! */ mrtentry_srcs->incoming = rpentry_ptr->incoming; mrtentry_srcs->upstream = rpentry_ptr->upstream; } } } if ((change_flag == TRUE) || (update_src_iif == TRUE)) /* Flush the changes */ change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, 0); if (rate_flag == TRUE) { for (kernel_cache_ptr = mrtentry_srcs->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_next) { kernel_cache_next = kernel_cache_ptr->next; curr_bytecnt = kernel_cache_ptr->sg_count.bytecnt; if (k_get_sg_cnt(udp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, &kernel_cache_ptr->sg_count) || (curr_bytecnt == kernel_cache_ptr->sg_count.bytecnt)) { /* Either for some reason there is no such * routing entry or that particular (s,g) was * idle. Delete the routing entry from the * kernel. */ delete_single_kernel_cache(mrtentry_srcs, kernel_cache_ptr); continue; } /* Check if the datarate was high enough to * switch to source specific tree. Need to check * only when we have (S,G)RPbit in the forwarder * or the RP itself. */ #if 0 /* XXX: A bug report I've received report * says that we don't need this. I think * it is correct, but want this around * for a while to make sure something * doesn't go wrong. */ if (!(mrtentry_srcs->flags & MRTF_RP)) continue; #endif /* 0 */ /* Forwarder initiated switch */ did_switch_flag = FALSE; if (curr_bytecnt + pim_data_rate_bytes < kernel_cache_ptr->sg_count.bytecnt) { if (!(mrtentry_srcs->flags & MRTF_RP)) { SET_TIMER(mrtentry_srcs->timer, PIM_DATA_TIMEOUT); continue; } if (VIFM_LASTHOP_ROUTER(mrtentry_srcs->leaves, mrtentry_srcs->oifs)) { switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); did_switch_flag = TRUE; } } /* RP initiated switch */ if ((did_switch_flag == FALSE) && (curr_bytecnt + pim_reg_rate_bytes < kernel_cache_ptr->sg_count.bytecnt)) { if (!(mrtentry_srcs->flags & MRTF_RP)) { SET_TIMER(mrtentry_srcs->timer, PIM_DATA_TIMEOUT); continue; } if (mrtentry_srcs->incoming == reg_vif_num) switch_shortest_path(kernel_cache_ptr->source, kernel_cache_ptr->group); } /* XXX: currentry the spec doesn't say to switch * back to the shared tree if low datarate, * but if needed to implement, the check must be * done here. Don't forget to check whether I am * a forwarder for that source. */ } } mrtentry_wide = mrtentry_srcs->group->grp_route; if (mrtentry_wide == (mrtentry_t *)NULL) mrtentry_wide = mrtentry_rp; dont_calc_action = FALSE; if ((rp_action != PIM_ACTION_NOTHING) || (grp_action != PIM_ACTION_NOTHING)) { src_action_rp = join_or_prune(mrtentry_srcs, rpentry_ptr->upstream); src_action = src_action_rp; dont_calc_action = TRUE; if (src_action_rp == PIM_ACTION_JOIN) { if ((grp_action == PIM_ACTION_PRUNE) || (rp_action == PIM_ACTION_PRUNE)) FIRE_TIMER(mrtentry_srcs->jp_timer); } else if (src_action_rp == PIM_ACTION_PRUNE) { if ((grp_action == PIM_ACTION_JOIN) || (rp_action == PIM_ACTION_JOIN)) FIRE_TIMER(mrtentry_srcs->jp_timer); } } /* Join/Prune timer */ IF_TIMEOUT(mrtentry_srcs->jp_timer) { if ((dont_calc_action != TRUE) || (rpentry_ptr->upstream != mrtentry_srcs->upstream)) src_action = join_or_prune(mrtentry_srcs, mrtentry_srcs->upstream); if (src_action != PIM_ACTION_NOTHING) add_jp_entry(mrtentry_srcs->upstream, PIM_JOIN_PRUNE_HOLDTIME, mrtentry_srcs->group->group, SINGLE_GRP_MSKLEN, mrtentry_srcs->source->address, SINGLE_SRC_MSKLEN, mrtentry_srcs->flags & MRTF_RP, src_action); if (mrtentry_wide != (mrtentry_t *)NULL) { /* Have both (S,G) and (*,G) (or (*,*,RP)). * Check if need to send (S,G) PRUNE toward RP */ if (mrtentry_srcs->upstream != mrtentry_wide->upstream) { if (dont_calc_action != TRUE) src_action_rp = join_or_prune(mrtentry_srcs, mrtentry_wide->upstream); /* XXX: TODO: do error check if * src_action == PIM_ACTION_JOIN, which should * be an error. */ if (src_action_rp == PIM_ACTION_PRUNE) { add_jp_entry(mrtentry_wide->upstream, PIM_JOIN_PRUNE_HOLDTIME, mrtentry_srcs->group->group, SINGLE_GRP_MSKLEN, mrtentry_srcs->source->address, SINGLE_SRC_MSKLEN, MRTF_RP, src_action_rp); } } } SET_TIMER(mrtentry_srcs->jp_timer, PIM_JOIN_PRUNE_PERIOD); } /* Assert timer */ if (mrtentry_srcs->flags & MRTF_ASSERTED) { IF_TIMEOUT(mrtentry_srcs->assert_timer) { /* TODO: XXX: reset the upstream router now */ mrtentry_srcs->flags &= ~MRTF_ASSERTED; } } /* Register-Suppression timer */ /* TODO: to reduce the kernel calls, if the timer * is running, install a negative cache entry in * the kernel? */ IF_TIMER_SET(mrtentry_srcs->rs_timer) { IF_TIMEOUT(mrtentry_srcs->rs_timer) { /* Start encapsulating the packets */ VIFM_COPY(mrtentry_srcs->pruned_oifs, new_pruned_oifs); VIFM_CLR(reg_vif_num, new_pruned_oifs); change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, new_pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, 0); } ELSE { /* The register suppression timer is running. Check * whether it is time to send PIM_NULL_REGISTER. */ /* TODO: XXX: TIMER implem. dependency! */ if (mrtentry_srcs->rs_timer <= PIM_REGISTER_PROBE_TIME) { /* Time to send a PIM_NULL_REGISTER */ /* XXX: a (bad) hack! This will be sending * periodically NULL_REGISTERS between * PIM_REGISTER_PROBE_TIME and 0. Well, * because PROBE_TIME is 5 secs, it will * happen only once, so it helps to avoid * adding a flag to the routing entry whether * a NULL_REGISTER was sent. */ send_pim_null_register(mrtentry_srcs); } } } /* routing entry */ if (TIMEOUT(mrtentry_srcs->timer)) { if (VIFM_ISEMPTY(mrtentry_srcs->leaves)) { delete_mrtentry(mrtentry_srcs); continue; } /* XXX: if DR, Register suppressed, * and leaf oif inherited from (*,G), the * directly connected source is not active anymore, * this (S,G) entry won't timeout. Check if the leaf * oifs are inherited from (*,G); if true. delete the * (S,G) entry. */ if (mrtentry_srcs->group->grp_route != (mrtentry_t *)NULL) { if (!((mrtentry_srcs->group->grp_route->leaves & mrtentry_srcs->leaves) ^ mrtentry_srcs->leaves)) { delete_mrtentry(mrtentry_srcs); continue; } } } } /* End of (S,G) loop */ } /* End of (*,G) loop */ } } /* For all cand RPs */ /* TODO: check again! */ for (vifi = 0, v = &uvifs[0]; vifi < numvifs; vifi++, v++) { /* Send all pending Join/Prune messages */ for (pim_nbr_ptr = v->uv_pim_neighbors; pim_nbr_ptr != (pim_nbr_entry_t *)NULL; pim_nbr_ptr = pim_nbr_ptr->next) { pack_and_send_jp_message(pim_nbr_ptr); } } IF_DEBUG(DEBUG_PIM_MRT) dump_pim_mrt(stderr); return; } /* * TODO: timeout the RP-group mapping entries during the scan of the * whole routing table? */ void age_misc() { rp_grp_entry_t *rp_grp_entry_ptr; rp_grp_entry_t *rp_grp_entry_next; grp_mask_t *grp_mask_ptr; grp_mask_t *grp_mask_next; /* Timeout the Cand-RP-set entries */ for (grp_mask_ptr = grp_mask_list; grp_mask_ptr != (grp_mask_t *)NULL; grp_mask_ptr = grp_mask_next) { /* If we timeout an entry, the grp_mask_ptr entry might be * removed. */ grp_mask_next = grp_mask_ptr->next; for (rp_grp_entry_ptr = grp_mask_ptr->grp_rp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_next) { rp_grp_entry_next = rp_grp_entry_ptr->grp_rp_next; if (rp_grp_entry_ptr->holdtime < 60000) { IF_TIMEOUT(rp_grp_entry_ptr->holdtime) delete_rp_grp_entry(&cand_rp_list, &grp_mask_list, rp_grp_entry_ptr); } } } /* Cand-RP-Adv timer */ if (cand_rp_flag == TRUE) { IF_TIMEOUT(pim_cand_rp_adv_timer) { send_pim_cand_rp_adv(); SET_TIMER(pim_cand_rp_adv_timer, my_cand_rp_adv_period); } } /* bootstrap-timer */ IF_TIMEOUT(pim_bootstrap_timer) { if (cand_bsr_flag == FALSE) { /* * If I am not Cand-BSR, start accepting Bootstrap messages * from anyone. * XXX: Even if the BSR has timeout, the existing * Cand-RP-Set is kept. */ curr_bsr_fragment_tag = 0; curr_bsr_priority = 0; /* Lowest priority */ curr_bsr_address = INADDR_ANY_N; /* Lowest priority */ MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, curr_bsr_hash_mask); SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT); } else { /* I am Cand-BSR, so set the current BSR to me */ if (curr_bsr_address == my_bsr_address) { SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_PERIOD); send_pim_bootstrap(); } else { /* Short delay before becoming the BSR and start * sending of the Cand-RP set * (to reduce the transient control overhead). */ SET_TIMER(pim_bootstrap_timer, bootstrap_initial_delay()); curr_bsr_fragment_tag = RANDOM(); curr_bsr_priority = my_bsr_priority; curr_bsr_address = my_bsr_address; curr_bsr_hash_mask = my_bsr_hash_mask; } } } IF_DEBUG(DEBUG_PIM_BOOTSTRAP | DEBUG_PIM_CAND_RP) dump_rp_set(stderr); /* TODO: XXX: anything else to timeout */ } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/pidfile.c0000644000000000000000000000562111700261371011123 0ustar /* $OpenBSD: pidfile.c,v 1.8 2008/06/26 05:42:05 ray Exp $ */ /* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include static char *pidfile_path; static pid_t pidfile_pid; static void pidfile_cleanup(void); extern char *__progname; int pidfile(const char *basename) { int save_errno, result; pid_t pid; FILE *f; if (basename == NULL) basename = __progname; if (pidfile_path != NULL) { free(pidfile_path); pidfile_path = NULL; } /* _PATH_VARRUN includes trailing / */ result = asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename); if (result == -1 || pidfile_path == NULL) return (-1); if ((f = fopen(pidfile_path, "w")) == NULL) { save_errno = errno; free(pidfile_path); pidfile_path = NULL; errno = save_errno; return (-1); } pid = getpid(); if (fprintf(f, "%ld\n", (long)pid) <= 0 || fclose(f) != 0) { save_errno = errno; (void) unlink(pidfile_path); free(pidfile_path); pidfile_path = NULL; errno = save_errno; return (-1); } pidfile_pid = pid; if (atexit(pidfile_cleanup) < 0) { save_errno = errno; (void) unlink(pidfile_path); free(pidfile_path); pidfile_path = NULL; pidfile_pid = 0; errno = save_errno; return (-1); } return (0); } static void pidfile_cleanup(void) { if (pidfile_path != NULL && pidfile_pid == getpid()) (void) unlink(pidfile_path); } pimd-2.1.8/defs.h0000644000000000000000000005677411700261371010454 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * 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. * */ #ifndef __PIMD_DEFS_H__ #define __PIMD_DEFS_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #if ((defined(SYSV)) || (defined(__bsdi__)) || ((defined SunOS) && (SunOS < 50))) #include #endif /* SYSV || bsdi || SunOS 4.x */ #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #endif /* __FreeBSD__ */ #if defined(__bsdi__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define rtentry kernel_rtentry #include #undef rtentry #endif /* bsdi or __FreeBSD_version >= 220000 */ #ifdef __linux__ #define _LINUX_IN_H /* For Linux <= 2.6.25 */ #include #include #else #include #endif /* __linux__ */ #if defined(HAVE_STRLCPY) #include #endif #if defined(HAVE_STRTONUM) #include #endif #if defined(HAVE_PIDFILE) #if defined(OpenBSD) || defined(NetBSD) #include #else #include #endif #endif #include #ifdef RSRR #include #endif /* RSRR */ typedef u_int u_int32; typedef u_short u_int16; typedef u_char u_int8; #ifndef BYTE_ORDER #if (BSD >= 199103) #include #else #ifdef __linux__ #include #else #define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ #define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ #define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ #if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ defined(__ia64) || \ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ defined(__alpha__) || defined(__alpha) #define BYTE_ORDER LITTLE_ENDIAN #endif #if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ defined(apollo) || defined(__convex__) || defined(_CRAY) || \ defined(__hppa) || defined(__hp9000) || \ defined(__hp9000s300) || defined(__hp9000s700) || \ defined(BIT_ZERO_ON_LEFT) || defined(m68k) #define BYTE_ORDER BIG_ENDIAN #endif #endif /* linux */ #endif /* BSD */ #endif /* BYTE_ORDER */ typedef void (*cfunc_t) (void *); typedef void (*ihfunc_t) (int, fd_set *); #include "dvmrp.h" /* Added for further compatibility and convenience */ #include "pimd.h" #include "mrt.h" #include "igmpv2.h" #include "vif.h" #include "debug.h" #include "pathnames.h" #ifdef RSRR #include "rsrr.h" #include "rsrr_var.h" #endif /* RSRR */ /* * Miscellaneous constants and macros */ /* #if (!(defined(__bsdi__)) && !(defined(KERNEL))) */ #ifndef KERNEL #define max(a, b) ((a) < (b) ? (b) : (a)) #define min(a, b) ((a) > (b) ? (b) : (a)) #endif #define ENABLINGSTR(bool) (bool) ? "enabling" : "disabling" /* * Various definitions to make it working for different platforms */ /* The old style sockaddr definition doesn't have sa_len */ #if defined(_AIX) || (defined(BSD) && (BSD >= 199006)) /* sa_len was added with 4.3-Reno */ #define HAVE_SA_LEN #endif /* Versions of Solaris older than 2.6 don't have routing sockets. */ /* XXX TODO: check FreeBSD version and add all other platforms */ #if defined(__linux__) || (defined(SunOS) && SunOS >=56) || defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (IRIX) || defined (__bsdi__) || defined(NetBSD) || defined(OpenBSD) #define HAVE_ROUTING_SOCKETS 1 #endif #define TRUE 1 #define FALSE 0 #ifndef MAX #define MAX(a,b) (((a) >= (b))? (a) : (b)) #define MIN(a,b) (((a) <= (b))? (a) : (b)) #endif /* MAX & MIN */ #define CREATE TRUE #define DONT_CREATE FALSE #define MFC_MOVE_FORCE 0x1 #define MFC_UPDATE_FORCE 0x2 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) #define ARRAY_LEN(a) (sizeof((a)) / sizeof((a)[0])) #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ #define MINTTL 1 /* min TTL in the packets send locally */ #define MAX_IP_PACKET_LEN 576 #define MIN_IP_HEADER_LEN 20 #define MAX_IP_HEADER_LEN 60 /* * The IGMPv2 defines INADDR_ALLRTRS_GROUP, but earlier * ones don't, so we define it conditionally here. */ #ifndef INADDR_ALLRTRS_GROUP /* address for multicast mtrace msg */ #define INADDR_ALLRTRS_GROUP (u_int32)0xe0000002 /* 224.0.0.2 */ #endif #ifndef INADDR_MAX_LOCAL_GROUP #define INADDR_MAX_LOCAL_GROUP (u_int32)0xe00000ff /* 224.0.0.255 */ #endif #define INADDR_ANY_N (u_int32)0x00000000 /* INADDR_ANY in * network order */ #define CLASSD_PREFIX (u_int32)0xe0000000 /* 224.0.0.0 */ #define STAR_STAR_RP_MSKLEN 4 /* Masklen for * 224.0.0.0 : * to encode (*,*,RP) */ #define ALL_MCAST_GROUPS_ADDR (u_int32)0xe0000000 /* 224.0.0.0 */ #define ALL_MCAST_GROUPS_LENGTH 4 /* Used by DVMRP */ #define DEFAULT_METRIC 1 /* default subnet/tunnel metric */ #define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */ /* Used if no relaible unicast routing information available */ #define UCAST_DEFAULT_SOURCE_METRIC 1024 #define UCAST_DEFAULT_SOURCE_PREFERENCE 1024 #define TIMER_INTERVAL 5 /* 5 sec virtual timer granularity */ /* * TODO: recalculate the messages sizes, probably with regard to the MTU * TODO: cleanup */ #define MAX_JP_MESSAGE_SIZE 8192 #define MAX_JP_MESSAGE_POOL_NUMBER 8 #define MAX_JOIN_LIST_SIZE 1500 #define MAX_PRUNE_LIST_SIZE 1500 #ifdef RSRR #define BIT_ZERO(X) ((X) = 0) #define BIT_SET(X,n) ((X) |= 1 << (n)) #define BIT_CLR(X,n) ((X) &= ~(1 << (n))) #define BIT_TST(X,n) ((X) & 1 << (n)) #endif /* RSRR */ #ifdef SYSV #define setlinebuf(s) setvbuf((s), (NULL), (_IOLBF), 0) #define RANDOM() lrand48() #else #define RANDOM() random() #endif /* SYSV */ /* * External declarations for global variables and functions. */ #define SEND_BUF_SIZE (128*1024) /* Maximum buff size to * send a packet */ #define RECV_BUF_SIZE (128*1024) /* Maximum buff size to * receive a packet */ #define SO_SEND_BUF_SIZE_MAX (256*1024) #define SO_SEND_BUF_SIZE_MIN (48*1024) #define SO_RECV_BUF_SIZE_MAX (256*1024) #define SO_RECV_BUF_SIZE_MIN (48*1024) /* TODO: describe the variables and clean up */ extern char *igmp_recv_buf; extern char *igmp_send_buf; extern char *pim_recv_buf; extern char *pim_send_buf; extern int igmp_socket; extern int pim_socket; extern u_int32 allhosts_group; extern u_int32 allrouters_group; extern u_int32 allpimrouters_group; extern build_jp_message_t *build_jp_message_pool; extern int build_jp_message_pool_counter; extern u_long virtual_time; extern char *configfilename; extern int haveterminal; extern char *__progname; extern struct cand_rp_adv_message_ { u_int8 *buffer; u_int8 *insert_data_ptr; u_int8 *prefix_cnt_ptr; u_int16 message_size; } cand_rp_adv_message; extern int disable_all_by_default; /* * Used to contol the switching to the shortest path: * `reg_rate` used by the RP * `data_rate` used by the last hop router */ extern u_int32 pim_reg_rate_bytes; extern u_int32 pim_reg_rate_check_interval; extern u_int32 pim_data_rate_bytes; extern u_int32 pim_data_rate_check_interval; extern cand_rp_t *cand_rp_list; extern grp_mask_t *grp_mask_list; extern cand_rp_t *segmented_cand_rp_list; extern grp_mask_t *segmented_grp_mask_list; extern u_int16 curr_bsr_fragment_tag; extern u_int8 curr_bsr_priority; extern u_int32 curr_bsr_address; extern u_int32 curr_bsr_hash_mask; extern u_int8 cand_bsr_flag; /* candidate BSR flag */ extern u_int8 my_bsr_priority; extern u_int32 my_bsr_address; extern u_int32 my_bsr_hash_mask; extern u_int8 cand_rp_flag; /* Candidate RP flag */ extern u_int32 my_cand_rp_address; extern u_int8 my_cand_rp_priority; extern u_int16 my_cand_rp_holdtime; extern u_int16 my_cand_rp_adv_period; /* The locally configured * Cand-RP adv. period. */ extern u_int16 pim_bootstrap_timer; extern u_int32 rp_my_ipv4_hashmask; extern u_int16 pim_cand_rp_adv_timer; extern u_int32 default_source_metric; extern u_int32 default_source_preference; extern srcentry_t *srclist; extern grpentry_t *grplist; extern rpentry_t *rplist; extern struct uvif uvifs[MAXVIFS]; extern vifi_t numvifs; extern int total_interfaces; extern vifi_t reg_vif_num; extern int phys_vif; extern int udp_socket; extern int vifs_down; #define MAX_INET_BUF_LEN 19 extern char s1[MAX_INET_BUF_LEN]; extern char s2[MAX_INET_BUF_LEN]; extern char s3[MAX_INET_BUF_LEN]; extern char s4[MAX_INET_BUF_LEN]; #if !((defined(BSD) && (BSD >= 199103)) || (defined(__linux__))) extern int errno; #endif #ifndef IGMP_MEMBERSHIP_QUERY #define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY #if !(defined(NetBSD) || defined(OpenBSD) || defined(__FreeBSD__)) #define IGMP_V1_MEMBERSHIP_REPORT IGMP_HOST_MEMBERSHIP_REPORT #define IGMP_V2_MEMBERSHIP_REPORT IGMP_HOST_NEW_MEMBERSHIP_REPORT #else #define IGMP_V1_MEMBERSHIP_REPORT IGMP_v1_HOST_MEMBERSHIP_REPORT #define IGMP_V2_MEMBERSHIP_REPORT IGMP_v2_HOST_MEMBERSHIP_REPORT #endif #define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE #endif #if defined(NetBSD) || defined(OpenBSD) || defined(__FreeBSD__) #define IGMP_MTRACE_RESP IGMP_MTRACE_REPLY #define IGMP_MTRACE IGMP_MTRACE_QUERY #endif /* For timeout. The timers count down */ #define SET_TIMER(timer, value) (timer) = (value) #define RESET_TIMER(timer) (timer) = 0 #define COPY_TIMER(timer_1, timer_2) (timer_2) = (timer_1) #define IF_TIMER_SET(timer) if ((timer) > 0) #define IF_TIMER_NOT_SET(timer) if ((timer) <= 0) #define FIRE_TIMER(timer) (timer) = 0 #define IF_TIMEOUT(timer) \ if (!((timer) -= (MIN(timer, TIMER_INTERVAL)))) #define IF_NOT_TIMEOUT(timer) \ if ((timer) -= (MIN(timer, TIMER_INTERVAL))) #define TIMEOUT(timer) \ (!((timer) -= (MIN(timer, TIMER_INTERVAL)))) #define NOT_TIMEOUT(timer) \ ((timer) -= (MIN(timer, TIMER_INTERVAL))) #if 0 #define IF_TIMEOUT(value) \ if (!(((value) >= TIMER_INTERVAL) && ((value) -= TIMER_INTERVAL))) #define IF_NOT_TIMEOUT(value) \ if (((value) >= TIMER_INTERVAL) && ((value) -= TIMER_INTERVAL)) #define TIMEOUT(value) \ (!(((value) >= TIMER_INTERVAL) && ((value) -= TIMER_INTERVAL))) #define NOT_TIMEOUT(value) \ (((value) >= TIMER_INTERVAL) && ((value) -= TIMER_INTERVAL)) #endif /* 0 */ #define ELSE else /* To make emacs cc-mode happy */ #define MASK_TO_VAL(x, i) { \ u_int32 _x = ntohl(x); \ (i) = 1; \ while ((_x) <<= 1) \ (i)++; \ }; #define VAL_TO_MASK(x, i) { \ x = htonl(~((1 << (32 - (i))) - 1)); \ }; /* * External function definitions */ /* callout.c */ extern void callout_init (void); extern void free_all_callouts (void); extern void age_callout_queue (int); extern int timer_nextTimer (void); extern int timer_setTimer (int, cfunc_t, void *); extern void timer_clearTimer (int); extern int timer_leftTimer (int); /* config.c */ extern void config_vifs_from_kernel (void); extern void config_vifs_from_file (void); /* debug.c */ extern char *packet_kind (u_int proto, u_int type, u_int code); extern int debug_kind (u_int proto, u_int type, u_int code); extern void logit (int, int, const char *, ...); extern int log_level (u_int proto, u_int type, u_int code); extern void dump (int i); extern void fdump (int i); extern void cdump (int i); extern void dump_vifs (FILE *fp); extern void dump_pim_mrt (FILE *fp); extern int dump_rp_set (FILE *fp); /* dvmrp_proto.c */ extern void dvmrp_accept_probe (u_int32 src, u_int32 dst, u_char *p, int datalen, u_int32 level); extern void dvmrp_accept_report (u_int32 src, u_int32 dst, u_char *p, int datalen, u_int32 level); extern void dvmrp_accept_info_request (u_int32 src, u_int32 dst, u_char *p, int datalen); extern void dvmrp_accept_info_reply (u_int32 src, u_int32 dst, u_char *p, int datalen); extern void dvmrp_accept_neighbors (u_int32 src, u_int32 dst, u_char *p, int datalen, u_int32 level); extern void dvmrp_accept_neighbors2 (u_int32 src, u_int32 dst, u_char *p, int datalen, u_int32 level); extern void dvmrp_accept_prune (u_int32 src, u_int32 dst, u_char *p, int datalen); extern void dvmrp_accept_graft (u_int32 src, u_int32 dst, u_char *p, int datalen); extern void dvmrp_accept_g_ack (u_int32 src, u_int32 dst, u_char *p, int datalen); /* igmp.c */ extern void init_igmp (void); extern void send_igmp (char *buf, u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen); /* igmp_proto.c */ extern void query_groups (struct uvif *v); extern void accept_membership_query (u_int32 src, u_int32 dst, u_int32 group, int tmo); extern void accept_group_report (u_int32 src, u_int32 dst, u_int32 group, int r_type); extern void accept_leave_message (u_int32 src, u_int32 dst, u_int32 group); /* inet.c */ extern int inet_cksum (u_int16 *addr, u_int len); extern int inet_valid_host (u_int32 naddr); extern int inet_valid_mask (u_int32 mask); extern int inet_valid_subnet (u_int32 nsubnet, u_int32 nmask); extern char *inet_fmt (u_int32 addr, char *s, size_t len); extern char *netname (u_int32 addr, u_int32 mask); extern u_int32 inet_parse (char *s, int n); /* kern.c */ extern void k_set_sndbuf (int socket, int bufsize, int minsize); extern void k_set_rcvbuf (int socket, int bufsize, int minsize); extern void k_hdr_include (int socket, int bool); extern void k_set_ttl (int socket, int t); extern void k_set_loop (int socket, int l); extern void k_set_if (int socket, u_int32 ifa); extern void k_join (int socket, u_int32 grp, struct uvif *v); extern void k_leave (int socket, u_int32 grp, struct uvif *v); extern void k_init_pim (int socket); extern void k_stop_pim (int socket); extern int k_del_mfc (int socket, u_int32 source, u_int32 group); extern int k_chg_mfc (int socket, u_int32 source, u_int32 group, vifi_t iif, vifbitmap_t oifs, u_int32 rp_addr); extern void k_add_vif (int socket, vifi_t vifi, struct uvif *v); extern void k_del_vif (int socket, vifi_t vifi, struct uvif *v); extern int k_get_vif_count (vifi_t vifi, struct vif_count *retval); extern int k_get_sg_cnt (int socket, u_int32 source, u_int32 group, struct sg_count *retval); /* main.c */ extern int register_input_handler (int fd, ihfunc_t func); /* mrt.c */ extern void init_pim_mrt (void); extern mrtentry_t *find_route (u_int32 source, u_int32 group, u_int16 flags, char create); extern grpentry_t *find_group (u_int32 group); extern srcentry_t *find_source (u_int32 source); extern void delete_mrtentry (mrtentry_t *mrtentry_ptr); extern void delete_srcentry (srcentry_t *srcentry_ptr); extern void delete_grpentry (grpentry_t *grpentry_ptr); extern void delete_mrtentry_all_kernel_cache (mrtentry_t *mrtentry_ptr); extern void delete_single_kernel_cache (mrtentry_t *mrtentry_ptr, kernel_cache_t *kernel_cache_ptr); extern void delete_single_kernel_cache_addr (mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group); extern void add_kernel_cache (mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group, u_int16 flags); /* pim.c */ extern void init_pim (void); extern void send_pim (char *buf, u_int32 src, u_int32 dst, int type, int datalen); extern void send_pim_unicast (char *buf, u_int32 src, u_int32 dst, int type, int datalen); /* pim_proto.c */ extern int receive_pim_hello (u_int32 src, u_int32 dst, char *pim_message, size_t datalen); extern int send_pim_hello (struct uvif *v, u_int16 holdtime); extern void delete_pim_nbr (pim_nbr_entry_t *nbr_delete); extern int receive_pim_register (u_int32 src, u_int32 dst, char *pim_message, size_t datalen); extern int send_pim_null_register (mrtentry_t *r); extern int receive_pim_register_stop (u_int32 src, u_int32 dst, char *pim_message, size_t datalen); extern int send_pim_register (char *pkt); extern int receive_pim_join_prune (u_int32 src, u_int32 dst, char *pim_message, int datalen); extern int join_or_prune (mrtentry_t *mrtentry_ptr, pim_nbr_entry_t *upstream_router); extern int receive_pim_assert (u_int32 src, u_int32 dst, char *pim_message, int datalen); extern int send_pim_assert (u_int32 source, u_int32 group, vifi_t vifi, mrtentry_t *mrtentry_ptr); extern int send_periodic_pim_join_prune (vifi_t vifi, pim_nbr_entry_t *pim_nbr, u_int16 holdtime); extern int add_jp_entry (pim_nbr_entry_t *pim_nbr, u_int16 holdtime, u_int32 group, u_int8 grp_msklen, u_int32 source, u_int8 src_msklen, u_int16 addr_flags, u_int8 join_prune); extern void pack_and_send_jp_message (pim_nbr_entry_t *pim_nbr); extern int receive_pim_cand_rp_adv (u_int32 src, u_int32 dst, char *pim_message, int datalen); extern int receive_pim_bootstrap (u_int32 src, u_int32 dst, char *pim_message, int datalen); extern int send_pim_cand_rp_adv (void); extern void send_pim_bootstrap (void); /* route.c */ extern int set_incoming (srcentry_t *srcentry_ptr, int srctype); extern vifi_t get_iif (u_int32 source); extern pim_nbr_entry_t *find_pim_nbr (u_int32 source); extern int add_sg_oif (mrtentry_t *mrtentry_ptr, vifi_t vifi, u_int16 holdtime, int update_holdtime); extern void add_leaf (vifi_t vifi, u_int32 source, u_int32 group); extern void delete_leaf (vifi_t vifi, u_int32 source, u_int32 group); extern int change_interfaces (mrtentry_t *mrtentry_ptr, vifi_t new_iif, vifbitmap_t new_joined_oifs_, vifbitmap_t new_pruned_oifs, vifbitmap_t new_leaves_, vifbitmap_t new_asserted_oifs, u_int16 flags); extern void calc_oifs (mrtentry_t *mrtentry_ptr, vifbitmap_t *oifs_ptr); extern void process_kernel_call (void); extern int delete_vif_from_mrt (vifi_t vifi); extern mrtentry_t *switch_shortest_path (u_int32 source, u_int32 group); /* routesock.c */ extern int k_req_incoming (u_int32 source, struct rpfctl *rpfp); #ifdef HAVE_ROUTING_SOCKETS extern int init_routesock (void); extern int routing_socket; #endif /* HAVE_ROUTING_SOCKETS */ /* rp.c */ extern void init_rp_and_bsr (void); extern u_int16 bootstrap_initial_delay (void); extern rp_grp_entry_t *add_rp_grp_entry (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 rp_addr, u_int8 rp_priority, u_int16 rp_holdtime, u_int32 group_addr, u_int32 group_mask, u_int32 bsr_hash_mask, u_int16 fragment_tag); extern void delete_rp_grp_entry (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, rp_grp_entry_t *rp_grp_entry_delete); extern void delete_grp_mask (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 group_addr, u_int32 group_mask); extern void delete_rp (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list, u_int32 rp_addr); extern void delete_rp_list (cand_rp_t **used_cand_rp_list, grp_mask_t **used_grp_mask_list); extern rpentry_t *rp_match (u_int32 group); extern rp_grp_entry_t *rp_grp_match (u_int32 group); extern rpentry_t *rp_find (u_int32 rp_address); extern int remap_grpentry (grpentry_t *grpentry_ptr); extern int create_pim_bootstrap_message (char *send_buff); extern int check_mrtentry_rp (mrtentry_t *mrtentry_ptr, u_int32 rp_addr); #ifdef RSRR #ifdef PIM #define gtable mrtentry #endif /* PIM */ #define RSRR_NOTIFICATION_OK TRUE #define RSRR_NOTIFICATION_FALSE FALSE /* rsrr.c */ extern void rsrr_init (void); extern void rsrr_clean (void); extern void rsrr_cache_send (struct gtable *, int); extern void rsrr_cache_clean (struct gtable *); extern void rsrr_cache_bring_up (struct gtable *); #endif /* RSRR */ /* timer.c */ extern void init_timers (void); extern void age_vifs (void); extern void age_routes (void); extern void age_misc (void); extern int unicast_routing_changes (srcentry_t *src_ent); extern int clean_srclist (void); /* trace.c */ /* u_int is promoted u_char */ extern void accept_mtrace (u_int32 src, u_int32 dst, u_int32 group, char *data, u_int no, int datalen); extern void accept_neighbor_request (u_int32 src, u_int32 dst); extern void accept_neighbor_request2 (u_int32 src, u_int32 dst); /* vif.c */ extern void init_vifs (void); extern void zero_vif (struct uvif *, int); extern void stop_all_vifs (void); extern void check_vif_state (void); extern vifi_t local_address (u_int32 src); extern vifi_t find_vif_direct (u_int32 src); extern vifi_t find_vif_direct_local (u_int32 src); extern u_int32 max_local_address (void); struct rp_hold { struct rp_hold *next; u_int32 address; u_int32 group; u_int32 mask; u_int8 priority; }; #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_PIDFILE int pidfile(const char *basename); #endif #endif /* __PIMD_DEFS_H__ */ /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/igmp.c0000644000000000000000000002642611700261371010451 0ustar /* * Copyright (c) 1998-2001 * University of Southern California/Information Sciences Institute. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: igmp.c,v 1.18 2002/09/26 00:59:29 pavlin Exp $ */ /* * 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 "defs.h" /* * Exported variables. */ char *igmp_recv_buf; /* input packet buffer */ char *igmp_send_buf; /* output packet buffer */ int igmp_socket; /* socket for all network I/O */ u_int32 allhosts_group; /* allhosts addr in net order */ u_int32 allrouters_group; /* All-Routers addr in net order */ #ifdef RAW_OUTPUT_IS_RAW extern int curttl; #endif /* RAW_OUTPUT_IS_RAW */ /* * Local functions definitions. */ static void igmp_read (int i, fd_set *rfd); static void accept_igmp (ssize_t recvlen); /* * Open and initialize the igmp socket, and fill in the non-changing * IP header fields in the output packet buffer. */ void init_igmp(void) { struct ip *ip; igmp_recv_buf = calloc(1, RECV_BUF_SIZE); igmp_send_buf = calloc(1, SEND_BUF_SIZE); if (!igmp_recv_buf || !igmp_send_buf) logit(LOG_ERR, 0, "Ran out of memory in init_igmp()"); if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) logit(LOG_ERR, errno, "Failed creating IGMP socket in init_igmp()"); k_hdr_include(igmp_socket, TRUE); /* include IP header when sending */ k_set_sndbuf(igmp_socket, SO_SEND_BUF_SIZE_MAX, SO_SEND_BUF_SIZE_MIN); /* lots of output buffering */ k_set_rcvbuf(igmp_socket, SO_RECV_BUF_SIZE_MAX, SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */ k_set_ttl(igmp_socket, MINTTL); /* restrict multicasts to one hop */ k_set_loop(igmp_socket, FALSE); /* disable multicast loopback */ ip = (struct ip *)igmp_send_buf; memset(ip, 0, sizeof(*ip)); ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); ip->ip_tos = 0xc0; /* Internet Control */ ip->ip_id = 0; /* let kernel fill in */ ip->ip_off = 0; ip->ip_ttl = MAXTTL; /* applies to unicasts only */ ip->ip_p = IPPROTO_IGMP; #ifdef old_Linux ip->ip_csum = 0; /* let kernel fill in */ #else ip->ip_sum = 0; /* let kernel fill in */ #endif /* old_Linux */ /* Everywhere in the daemon we use network-byte-order */ allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); allrouters_group = htonl(INADDR_ALLRTRS_GROUP); if (register_input_handler(igmp_socket, igmp_read) < 0) logit(LOG_ERR, 0, "Failed registering igmp_read() as an input handler in init_igmp()"); } /* Read an IGMP message */ static void igmp_read(int i __attribute__((unused)), fd_set *rfd __attribute__((unused))) { ssize_t len; socklen_t dummy = 0; while ((len = recvfrom(igmp_socket, igmp_recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_ERR, errno, "Failed recvfrom() in igmp_read()"); return; } accept_igmp(len); } /* * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ static void accept_igmp(ssize_t recvlen) { register u_int32 src, dst, group; struct ip *ip; struct igmp *igmp; int ipdatalen, iphdrlen, igmpdatalen; if (recvlen < (ssize_t)sizeof(struct ip)) { logit(LOG_WARNING, 0, "Received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)igmp_recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; /* packets sent up from kernel to daemon have ip->ip_p = 0 */ if (ip->ip_p == 0) { #if 0 /* XXX */ if (src == 0 || dst == 0) logit(LOG_WARNING, 0, "Kernel request not accurate, src %s dst %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); else #endif process_kernel_call(); return; } iphdrlen = ip->ip_hl << 2; #ifdef RAW_INPUT_IS_RAW ipdatalen = ntohs(ip->ip_len) - iphdrlen; #else ipdatalen = ip->ip_len; #endif if (iphdrlen + ipdatalen != recvlen) { logit(LOG_WARNING, 0, "Received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inet_fmt(src, s1, sizeof(s1)), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(igmp_recv_buf + iphdrlen); group = igmp->igmp_group.s_addr; igmpdatalen = ipdatalen - IGMP_MINLEN; if (igmpdatalen < 0) { logit(LOG_WARNING, 0, "Received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inet_fmt(src, s1, sizeof(s1))); return; } /* TODO: too noisy. Remove it? */ #if 0 IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_IGMP, igmp->igmp_type, igmp->igmp_code)) logit(LOG_DEBUG, 0, "RECV %s from %-15s to %s", packet_kind(IPPROTO_IGMP, igmp->igmp_type, igmp->igmp_code), inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); #endif /* 0 */ switch (igmp->igmp_type) { case IGMP_MEMBERSHIP_QUERY: accept_membership_query(src, dst, group, igmp->igmp_code); return; case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: accept_group_report(src, dst, group, igmp->igmp_type); return; case IGMP_V2_LEAVE_GROUP: accept_leave_message(src, dst, group); return; case IGMP_DVMRP: /* XXX: TODO: most of the stuff below is not implemented. We are still * only PIM router. */ group = ntohl(group); switch (igmp->igmp_code) { case DVMRP_PROBE: dvmrp_accept_probe(src, dst, (u_char *)(igmp+1), igmpdatalen, group); return; case DVMRP_REPORT: dvmrp_accept_report(src, dst, (u_char *)(igmp+1), igmpdatalen, group); return; case DVMRP_ASK_NEIGHBORS: accept_neighbor_request(src, dst); return; case DVMRP_ASK_NEIGHBORS2: accept_neighbor_request2(src, dst); return; case DVMRP_NEIGHBORS: dvmrp_accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen, group); return; case DVMRP_NEIGHBORS2: dvmrp_accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen, group); return; case DVMRP_PRUNE: dvmrp_accept_prune(src, dst, (u_char *)(igmp+1), igmpdatalen); return; case DVMRP_GRAFT: dvmrp_accept_graft(src, dst, (u_char *)(igmp+1), igmpdatalen); return; case DVMRP_GRAFT_ACK: dvmrp_accept_g_ack(src, dst, (u_char *)(igmp+1), igmpdatalen); return; case DVMRP_INFO_REQUEST: dvmrp_accept_info_request(src, dst, (u_char *)(igmp+1), igmpdatalen); return; case DVMRP_INFO_REPLY: dvmrp_accept_info_reply(src, dst, (u_char *)(igmp+1), igmpdatalen); return; default: logit(LOG_INFO, 0, "Ignoring unknown DVMRP message code %u from %s to %s", igmp->igmp_code, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return; } case IGMP_PIM: return; /* TODO: this is PIM v1 message. Handle it?. */ case IGMP_MTRACE_RESP: return; /* TODO: implement it */ case IGMP_MTRACE: accept_mtrace(src, dst, group, (char *)(igmp+1), igmp->igmp_code, igmpdatalen); return; default: logit(LOG_INFO, 0, "Ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return; } } void send_igmp(char *buf, u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen) { struct sockaddr_in sdst; struct ip *ip; struct igmp *igmp; int sendlen; int setloop = 0; /* Prepare the IP header */ ip = (struct ip *)buf; ip->ip_len = sizeof(struct ip) + IGMP_MINLEN + datalen; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; sendlen = ip->ip_len; #if defined(RAW_OUTPUT_IS_RAW) || defined(OpenBSD) ip->ip_len = htons(ip->ip_len); #endif /* RAW_OUTPUT_IS_RAW || OpenBSD */ igmp = (struct igmp *)(buf + sizeof(struct ip)); igmp->igmp_type = type; igmp->igmp_code = code; igmp->igmp_group.s_addr = group; igmp->igmp_cksum = 0; igmp->igmp_cksum = inet_cksum((u_int16 *)igmp, IGMP_MINLEN + datalen); if (IN_MULTICAST(ntohl(dst))) { k_set_if(igmp_socket, src); if (type != IGMP_DVMRP || dst == allhosts_group) { setloop = 1; k_set_loop(igmp_socket, TRUE); } #ifdef RAW_OUTPUT_IS_RAW ip->ip_ttl = curttl; } else { ip->ip_ttl = MAXTTL; #endif /* RAW_OUTPUT_IS_RAW */ } memset(&sdst, 0, sizeof(sdst)); sdst.sin_family = AF_INET; #ifdef HAVE_SA_LEN sdst.sin_len = sizeof(sdst); #endif sdst.sin_addr.s_addr = dst; while (sendto(igmp_socket, igmp_send_buf, sendlen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ else if (errno == ENETDOWN || errno == ENODEV) check_vif_state(); else logit(log_level(IPPROTO_IGMP, type, code), errno, "Sendto to %s on %s", inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2))); if (setloop) k_set_loop(igmp_socket, FALSE); return; } if (setloop) k_set_loop(igmp_socket, FALSE); IF_DEBUG(DEBUG_PKT|debug_kind(IPPROTO_IGMP, type, code)) { logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s", packet_kind(IPPROTO_IGMP, type, code), src == INADDR_ANY_N ? "INADDR_ANY" : inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } } /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */ pimd-2.1.8/igmpv2.h0000644000000000000000000000211211700261371010710 0ustar /* * The mrouted program is covered by the license in the accompanying file * named "LICENSE". Use of the mrouted program represents acceptance of * the terms and conditions listed in that file. * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. * * * igmpv2.h,v 3.8 1997/05/01 23:10:31 fenner Exp */ /* * Constants for IGMP Version 2. Several of these, especially the * robustness variable, should be variables and not constants. */ #define IGMP_ROBUSTNESS_VARIABLE 2 #define IGMP_QUERY_INTERVAL 125 #define IGMP_QUERY_RESPONSE_INTERVAL 10 #define IGMP_GROUP_MEMBERSHIP_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ IGMP_QUERY_INTERVAL + \ IGMP_QUERY_RESPONSE_INTERVAL) #define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (IGMP_ROBUSTNESS_VARIABLE * \ IGMP_QUERY_INTERVAL + \ IGMP_QUERY_RESPONSE_INTERVAL / 2) #define IGMP_STARTUP_QUERY_INTERVAL 30 #define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE #define IGMP_LAST_MEMBER_QUERY_INTERVAL 1 #define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS_VARIABLE pimd-2.1.8/netlink.c0000644000000000000000000001431111700261371011147 0ustar /* * Fred Griffoul sent me this file to use * it when compiling pimd under Linux. * There was no copyright message or author name, so I assume he was the * author, and deserves the copyright/credit for it: * * COPYRIGHT/AUTHORSHIP by Fred Griffoul * (until proven otherwise). */ #ifdef __linux__ #include #include #include #include #include #include #include #include "defs.h" #include int routing_socket = -1; static __u32 pid; /* pid_t, but /usr/include/linux/netlink.h says __u32 ... */ static __u32 seq; static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf); static int addattr32(struct nlmsghdr *n, size_t maxlen, int type, __u32 data) { int len = RTA_LENGTH(4); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta, len); } if (len) logit(LOG_WARNING, 0, "NETLINK: Deficit in rtattr %d\n", len); return 0; } /* open and initialize the routing socket */ int init_routesock(void) { socklen_t addr_len; struct sockaddr_nl local; routing_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (routing_socket < 0) { logit(LOG_ERR, errno, "netlink socket"); return -1; } memset(&local, 0, sizeof(local)); local.nl_family = AF_NETLINK; local.nl_groups = 0; if (bind(routing_socket, (struct sockaddr *) &local, sizeof(local)) < 0) { logit(LOG_ERR, errno, "netlink bind"); return -1; } addr_len = sizeof(local); if (getsockname(routing_socket, (struct sockaddr *) &local, &addr_len) < 0) { logit(LOG_ERR, errno, "netlink getsockname"); return -1; } if (addr_len != sizeof(local)) { logit(LOG_ERR, 0, "netlink wrong addr len"); return -1; } if (local.nl_family != AF_NETLINK) { logit(LOG_ERR, 0, "netlink wrong addr family"); return -1; } pid = local.nl_pid; seq = time(NULL); return 0; } /* get the rpf neighbor info */ int k_req_incoming(u_int32 source, struct rpfctl *rpf) { int rlen; register int l; char buf[512]; struct nlmsghdr *n = (struct nlmsghdr *) buf; struct rtmsg *r = NLMSG_DATA(n); struct sockaddr_nl addr; rpf->source.s_addr = source; rpf->iif = ALL_VIFS; rpf->rpfneighbor.s_addr = 0; n->nlmsg_type = RTM_GETROUTE; n->nlmsg_flags = NLM_F_REQUEST; n->nlmsg_len = NLMSG_LENGTH(sizeof(*r)); n->nlmsg_pid = pid; n->nlmsg_seq = ++seq; memset(r, 0, sizeof(*r)); r->rtm_family = AF_INET; r->rtm_dst_len = 32; addattr32(n, sizeof(buf), RTA_DST, rpf->source.s_addr); #ifdef CONFIG_RTNL_OLD_IFINFO r->rtm_optlen = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); #endif addr.nl_family = AF_NETLINK; addr.nl_groups = 0; addr.nl_pid = 0; /* tracef(TRF_NETLINK, "NETLINK: ask path to %s", inet_fmt(rpf->source.s_addr, s1, sizeof(s1))); */ logit(LOG_DEBUG, 0, "NETLINK: ask path to %s", inet_fmt(rpf->source.s_addr, s1, sizeof(s1))); while ((rlen = sendto(routing_socket, buf, n->nlmsg_len, 0, (struct sockaddr *) &addr, sizeof(addr))) < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_WARNING, errno, "Error writing to routing socket"); return FALSE; } do { socklen_t alen = sizeof(addr); l = recvfrom(routing_socket, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &alen); if (l < 0) { if (errno == EINTR) continue; /* Received signal, retry syscall. */ logit(LOG_WARNING, errno, "Error writing to routing socket"); return FALSE; } } while (n->nlmsg_seq != seq || n->nlmsg_pid != pid); if (n->nlmsg_type != RTM_NEWROUTE) { if (n->nlmsg_type != NLMSG_ERROR) { logit(LOG_WARNING, 0, "netlink: wrong answer type %d", n->nlmsg_type); } else { logit(LOG_WARNING, -(*(int*)NLMSG_DATA(n)), "netlink get_route"); } return FALSE; } return getmsg(NLMSG_DATA(n), l - sizeof(*n), rpf); } static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf) { vifi_t vifi; struct uvif *v; struct rtattr *rta[RTA_MAX + 1]; if (rtm->rtm_type == RTN_LOCAL) { /* tracef(TRF_NETLINK, "NETLINK: local address"); */ logit(LOG_DEBUG, 0, "NETLINK: local address"); if ((rpf->iif = local_address(rpf->source.s_addr)) != MAXVIFS) { rpf->rpfneighbor.s_addr = rpf->source.s_addr; return TRUE; } return FALSE; } rpf->rpfneighbor.s_addr = 0; if (rtm->rtm_type != RTN_UNICAST) { /* tracef(TRF_NETLINK, "NETLINK: route type is %d", rtm->rtm_type); */ logit(LOG_DEBUG, 0, "NETLINK: route type is %d", rtm->rtm_type); return FALSE; } memset(rta, 0, sizeof(rta)); parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), msglen - sizeof(*rtm)); if (rta[RTA_OIF]) { int ifindex = *(int *) RTA_DATA(rta[RTA_OIF]); for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_ifindex == ifindex) break; } if (vifi >= numvifs) { logit(LOG_WARNING, 0, "NETLINK: ifindex=%d, but no vif", ifindex); return FALSE; } /* tracef(TRF_NETLINK, "NETLINK: vif %d, ifindex=%d", vifi, ifindex);*/ logit(LOG_DEBUG, 0, "NETLINK: vif %d, ifindex=%d", vifi, ifindex); } else { logit(LOG_WARNING, 0, "NETLINK: no interface"); return FALSE; } if (rta[RTA_GATEWAY]) { __u32 gw = *(__u32 *) RTA_DATA(rta[RTA_GATEWAY]); /* tracef(TRF_NETLINK, "NETLINK: gateway is %s", inet_fmt(gw, s1, sizeof(s1))); */ logit(LOG_DEBUG, 0, "NETLINK: gateway is %s", inet_fmt(gw, s1, sizeof(s1))); rpf->rpfneighbor.s_addr = gw; } else rpf->rpfneighbor.s_addr = rpf->source.s_addr; rpf->iif = vifi; return TRUE; } #endif /* __linux__ */ /** * Local Variables: * version-control: t * indent-tabs-mode: t * c-file-style: "ellemtel" * c-basic-offset: 4 * End: */