IPv6 multicast routing.

kernel IPv6 multicast routing support.
  pim6 dense mode daemon
  pim6 sparse mode daemon
  netstat support of IPv6 multicast routing statistics

  Merging to the current and testing with other existing multicast routers
  is done by Tatsuya Jinmei <jinmei@kame.net>, who writes and maintainances
  the base code in KAME distribution.

  Make world check and kernel build check was also successful.
This commit is contained in:
Yoshinobu Inoue 2000-01-28 05:10:56 +00:00
parent de6d75328e
commit 0fea3d5165
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=56722
100 changed files with 35703 additions and 10 deletions

View File

@ -723,6 +723,7 @@ netinet6/in6_gif.c optional gif inet6
netinet6/ip6_forward.c optional inet6
netinet6/in6_ifattach.c optional inet6
netinet6/ip6_input.c optional inet6
netinet6/ip6_mroute.c optional inet6
netinet6/ip6_output.c optional inet6
netinet6/in6_pcb.c optional inet6
netinet6/in6_prefix.c optional inet6

View File

@ -215,6 +215,12 @@ struct ip6protosw inet6sw[] = {
&nousrreqs
},
#endif /* GIF */
{ SOCK_RAW, &inet6domain, IPPROTO_PIM, PR_ATOMIC|PR_ADDR,
pim6_input, rip6_output, 0, rip6_ctloutput,
0,
0, 0, 0, 0,
&rip6_usrreqs
},
/* raw wildcard */
{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR,
rip6_input, rip6_output, 0, rip6_ctloutput,

View File

@ -3,7 +3,7 @@
PROG= netstat
SRCS= if.c inet.c inet6.c main.c mbuf.c mroute.c ipx.c route.c \
unix.c atalk.c netgraph.c # iso.c ns.c tp_astring.c
unix.c atalk.c netgraph.c mroute6.c # iso.c ns.c tp_astring.c
CFLAGS+=-Wall
#CFLAGS+=-g

View File

@ -133,7 +133,6 @@ static struct nlist nl[] = {
{ "_ipsecstat" },
#define N_IPSEC6STAT 31
{ "_ipsec6stat" },
#ifdef notyet
#define N_PIM6STAT 32
{ "_pim6stat" },
#define N_MRT6PROTO 33
@ -144,7 +143,6 @@ static struct nlist nl[] = {
{ "_mf6ctable" },
#define N_MIF6TABLE 36
{ "_mif6table" },
#endif
{ "" },
};
@ -481,21 +479,17 @@ main(argc, argv)
if (af == AF_INET || af == AF_UNSPEC)
mrt_stats(nl[N_MRTSTAT].n_value);
#ifdef INET6
#ifdef notyet
if (af == AF_INET6 || af == AF_UNSPEC)
mrt6_stats(nl[N_MRT6STAT].n_value);
#endif
#endif
} else {
if (af == AF_INET || af == AF_UNSPEC)
mroutepr(nl[N_MFCTABLE].n_value,
nl[N_VIFTABLE].n_value);
#ifdef INET6
#ifdef notyet
if (af == AF_INET6 || af == AF_UNSPEC)
mroute6pr(nl[N_MF6CTABLE].n_value,
nl[N_MIF6TABLE].n_value);
#endif
#endif
}
exit(0);

View File

@ -82,7 +82,7 @@ mroutepr(mfcaddr, vifaddr)
vifi_t maxvif = 0;
if (mfcaddr == 0 || vifaddr == 0) {
printf("No multicast routing compiled into this system.\n");
printf("No IPv4 multicast routing compiled into this system.\n");
return;
}

235
usr.bin/netstat/mroute6.c Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* 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.
*
* @(#)mroute.c 8.2 (Berkeley) 4/28/95
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <stdio.h>
#define KERNEL 1
#include <netinet6/ip6_mroute.h>
#undef KERNEL
#include "netstat.h"
#define WID_ORG (lflag ? 39 : (nflag ? 29 : 18)) /* width of origin column */
#define WID_GRP (lflag ? 18 : (nflag ? 16 : 18)) /* width of group column */
extern char *routename6 __P((struct sockaddr_in6 *));
void
mroute6pr(mfcaddr, mifaddr)
u_long mfcaddr, mifaddr;
{
struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
struct mif6 mif6table[MAXMIFS];
struct mf6c mfc;
struct rtdetq rte, *rtep;
register struct mif6 *mifp;
register mifi_t mifi;
register int i;
register int banner_printed;
register int saved_nflag;
mifi_t maxmif = 0;
long int waitings;
if (mfcaddr == 0 || mifaddr == 0) {
printf("No IPv6 multicast routing compiled into this"
"system.\n");
return;
}
saved_nflag = nflag;
nflag = 1;
kread(mifaddr, (char *)&mif6table, sizeof(mif6table));
banner_printed = 0;
for (mifi = 0, mifp = mif6table; mifi < MAXMIFS; ++mifi, ++mifp) {
struct ifnet ifnet;
char ifname[IFNAMSIZ];
if (mifp->m6_ifp == NULL)
continue;
kread((u_long)mifp->m6_ifp, (char *)&ifnet, sizeof(ifnet));
maxmif = mifi;
if (!banner_printed) {
printf("\nIPv6 Multicast Interface Table\n"
" Mif Rate PhyIF "
"Pkts-In Pkts-Out\n");
banner_printed = 1;
}
printf(" %2u %4d",
mifi, mifp->m6_rate_limit);
printf(" %5s", (mifp->m6_flags & MIFF_REGISTER) ?
"reg0" : if_indextoname(ifnet.if_index, ifname));
printf(" %9qu %9qu\n", mifp->m6_pkt_in, mifp->m6_pkt_out);
}
if (!banner_printed)
printf("\nIPv6 Multicast Interface Table is empty\n");
kread(mfcaddr, (char *)&mf6ctable, sizeof(mf6ctable));
banner_printed = 0;
for (i = 0; i < MF6CTBLSIZ; ++i) {
mfcp = mf6ctable[i];
while(mfcp) {
kread((u_long)mfcp, (char *)&mfc, sizeof(mfc));
if (!banner_printed) {
printf ("\nIPv6 Multicast Forwarding Cache\n");
printf(" %-*.*s %-*.*s %s",
WID_ORG, WID_ORG, "Origin",
WID_GRP, WID_GRP, "Group",
" Packets Waits In-Mif Out-Mifs\n");
banner_printed = 1;
}
printf(" %-*.*s", WID_ORG, WID_ORG,
routename6(&mfc.mf6c_origin));
printf(" %-*.*s", WID_GRP, WID_GRP,
routename6(&mfc.mf6c_mcastgrp));
printf(" %9qu", mfc.mf6c_pkt_cnt);
for (waitings = 0, rtep = mfc.mf6c_stall; rtep; ) {
waitings++;
kread((u_long)rtep, (char *)&rte, sizeof(rte));
rtep = rte.next;
}
printf(" %3ld", waitings);
if (mfc.mf6c_parent == MF6C_INCOMPLETE_PARENT)
printf(" --- ");
else
printf(" %3d ", mfc.mf6c_parent);
for (mifi = 0; mifi <= maxmif; mifi++) {
if (IF_ISSET(mifi, &mfc.mf6c_ifset))
printf(" %u", mifi);
}
printf("\n");
mfcp = mfc.mf6c_next;
}
}
if (!banner_printed)
printf("\nIPv6 Multicast Routing Table is empty\n");
printf("\n");
nflag = saved_nflag;
}
void
mrt6_stats(mstaddr)
u_long mstaddr;
{
struct mrt6stat mrtstat;
if (mstaddr == 0) {
printf("No IPv6 multicast routing compiled into this"
"system.\n");
return;
}
kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
printf("IPv6 multicast forwarding:\n");
printf(" %10qu multicast forwarding cache lookup%s\n",
mrtstat.mrt6s_mfc_lookups, plural(mrtstat.mrt6s_mfc_lookups));
printf(" %10qu multicast forwarding cache miss%s\n",
mrtstat.mrt6s_mfc_misses, plurales(mrtstat.mrt6s_mfc_misses));
printf(" %10qu upcall%s to mrouted\n",
mrtstat.mrt6s_upcalls, plural(mrtstat.mrt6s_upcalls));
printf(" %10qu upcall queue overflow%s\n",
mrtstat.mrt6s_upq_ovflw, plural(mrtstat.mrt6s_upq_ovflw));
printf(" %10qu upcall%s dropped due to full socket buffer\n",
mrtstat.mrt6s_upq_sockfull, plural(mrtstat.mrt6s_upq_sockfull));
printf(" %10qu cache cleanup%s\n",
mrtstat.mrt6s_cache_cleanups, plural(mrtstat.mrt6s_cache_cleanups));
printf(" %10qu datagram%s with no route for origin\n",
mrtstat.mrt6s_no_route, plural(mrtstat.mrt6s_no_route));
printf(" %10qu datagram%s arrived with bad tunneling\n",
mrtstat.mrt6s_bad_tunnel, plural(mrtstat.mrt6s_bad_tunnel));
printf(" %10qu datagram%s could not be tunneled\n",
mrtstat.mrt6s_cant_tunnel, plural(mrtstat.mrt6s_cant_tunnel));
printf(" %10qu datagram%s arrived on wrong interface\n",
mrtstat.mrt6s_wrong_if, plural(mrtstat.mrt6s_wrong_if));
printf(" %10qu datagram%s selectively dropped\n",
mrtstat.mrt6s_drop_sel, plural(mrtstat.mrt6s_drop_sel));
printf(" %10qu datagram%s dropped due to queue overflow\n",
mrtstat.mrt6s_q_overflow, plural(mrtstat.mrt6s_q_overflow));
printf(" %10qu datagram%s dropped for being too large\n",
mrtstat.mrt6s_pkt2large, plural(mrtstat.mrt6s_pkt2large));
}

View File

@ -78,11 +78,9 @@ void ip6_stats __P((u_long, char *));
void ip6_ifstats __P((char *));
void icmp6_stats __P((u_long, char *));
void icmp6_ifstats __P((char *));
#ifdef notyet
void pim6_stats __P((u_long, char *));
void mroute6pr __P((u_long, u_long));
void mrt6_stats __P((u_long));
#endif
#endif /*INET6*/
void bdg_stats __P((u_long, char *));

View File

@ -59,6 +59,8 @@ SUBDIR= IPXrouted \
pccard \
pciconf \
periodic \
pim6dd \
pim6sd \
pkg_install \
pnpinfo \
portmap \

View File

@ -0,0 +1,49 @@
$FreeBSD$
The mrouted program is covered by the following license. Use of the
mrouted program represents acceptance of these terms and conditions.
1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
to use, copy and modify the computer software ``mrouted'' (hereinafter
called the ``Program''), upon the terms and conditions hereinafter set
out and until Licensee discontinues use of the Licensed Program.
2. LICENSEE acknowledges that the Program is a research tool still in
the development state, that it is being supplied ``as is,'' without any
accompanying services from STANFORD, and that this license is entered
into in order to encourage scientific collaboration aimed at further
development and application of the Program.
3. LICENSEE may copy the Program and may sublicense others to use object
code copies of the Program or any derivative version of the Program.
All copies must contain all copyright and other proprietary notices found
in the Program as provided by STANFORD. Title to copyright to the
Program remains with STANFORD.
4. LICENSEE may create derivative versions of the Program. LICENSEE
hereby grants STANFORD a royalty-free license to use, copy, modify,
distribute and sublicense any such derivative works. At the time
LICENSEE provides a copy of a derivative version of the Program to a
third party, LICENSEE shall provide STANFORD with one copy of the source
code of the derivative version at no charge to STANFORD.
5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
for any liability nor for any direct, indirect or consequential damages
with respect to any claim by LICENSEE or any third party on account of or
arising from this Agreement or use of the Program.
6. This agreement shall be construed, interpreted and applied in
accordance with the State of California and any legal action arising
out of this Agreement or use of the Program shall be filed in a court
in the State of California.
7. Nothing in this Agreement shall be construed as conferring rights to
use in advertising, publicity or otherwise any trademark or the name
of ``Stanford''.
The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: LICENSE.pimd,v 1.1.1.1 1999/08/08 23:30:50 itojun 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.
*
* $FreeBSD$
*/

14
usr.sbin/pim6dd/Makefile Normal file
View File

@ -0,0 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
# $FreeBSD$
PROG= pim6dd
MAN5= pim6dd.conf.5
MAN8= pim6dd.8
SRCS= mld6.c mld6_proto.c\
inet6.c kern.c main.c config.c debug.c routesock.c vers.c callout.c\
route.c vif.c timer.c mrt.c pim6.c pim6_proto.c trace.c
CFLAGS+= -DINET6 -DPIM -DIOCTL_OK_ON_RAW_SOCKET
.include <bsd.prog.mk>

2
usr.sbin/pim6dd/VERSION Normal file
View File

@ -0,0 +1,2 @@
# $FreeBSD$
0.2.1.0-alpha15

256
usr.sbin/pim6dd/callout.c Normal file
View File

@ -0,0 +1,256 @@
/*
* 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
*
* $FreeBSD$
*/
#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*/
};
#ifdef CALLOUT_DEBUG
static void print_Q __P((void));
#else
#define print_Q()
#endif
void
callout_init()
{
if (Q) {
log(LOG_ERR, 0, "timer used before callout_init()");
exit(1);
}
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)
log(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) {
log(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)
log(LOG_DEBUG, 0, "setting timer:");
print_Q();
#endif
/* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed 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;
return node->id;
} else {
/* keep moving */
delay -= ptr->time; node->time = delay;
prev = ptr;
ptr = ptr->next;
}
}
prev->next = node;
}
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
*/
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);
return;
}
prev = ptr;
ptr = ptr->next;
}
}
#ifdef CALLOUT_DEBUG
/*
* debugging utility
*/
static void
print_Q()
{
struct timeout_q *ptr;
IF_DEBUG(DEBUG_TIMEOUT)
for (ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
}
#endif /* CALLOUT_DEBUG */

681
usr.sbin/pim6dd/config.c Normal file
View File

@ -0,0 +1,681 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: config.c,v 1.3 1999/12/30 09:23:08 itojun 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.
*
* $FreeBSD$
*/
#include "defs.h"
/*
* Forward declarations.
*/
static char *next_word __P((char **));
static int parse_phyint __P((char *s));
static void add_phaddr __P((struct uvif *v, struct sockaddr_in6 *addr,
struct in6_addr *mask));
static mifi_t ifname2mifi __P((char *ifname));
static int wordToOption __P((char *));
static int parse_filter __P((char *s));
#if 0 /* not used */
static int parse_default_source_metric __P((char *));
static int parse_default_source_preference __P((char *));
#endif
/*
* Query the kernel to find network interfaces that are multicast-capable
* and install them in the uvifs array.
*/
void
config_vifs_from_kernel()
{
struct ifreq *ifrp, *ifend;
register struct uvif *v;
register vifi_t vifi;
int n;
struct sockaddr_in6 addr;
struct in6_addr mask, prefix;
short flags;
int num_ifreq = 64;
struct ifconf ifc;
total_interfaces = 0; /* The total number of physical interfaces */
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
ifc.ifc_buf = calloc(ifc.ifc_len, sizeof(char));
while (ifc.ifc_buf) {
caddr_t newbuf;
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
/*
* If the buffer was large enough to hold all the addresses
* then break out, otherwise increase the buffer size and
* try again.
*
* The only way to know that we definitely had enough space
* is to know that there was enough space for at least one
* more struct ifreq. ???
*/
if ((num_ifreq * sizeof(struct ifreq)) >=
ifc.ifc_len + sizeof(struct ifreq))
break;
num_ifreq *= 2;
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
newbuf = realloc(ifc.ifc_buf, ifc.ifc_len);
if (newbuf == NULL)
free(ifc.ifc_buf);
ifc.ifc_buf = newbuf;
}
if (ifc.ifc_buf == NULL)
log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
ifrp = (struct ifreq *)ifc.ifc_buf;
ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
/*
* Loop through all of the interfaces.
*/
for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
struct ifreq ifr;
struct in6_ifreq ifr6;
#ifdef HAVE_SA_LEN
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
n = sizeof(*ifrp);
#else
n = sizeof(*ifrp);
#endif /* HAVE_SA_LEN */
/*
* Ignore any interface for an address family other than IPv6.
*/
if (ifrp->ifr_addr.sa_family != AF_INET6) {
total_interfaces++; /* Eventually may have IPv6 address later */
continue;
}
memcpy(&addr, &ifrp->ifr_addr, sizeof(struct sockaddr_in6));
/*
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
* SIOCGIFFLAGS stomps over it because the requests
* are returned in a union.)
*/
memcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
memcpy(ifr6.ifr_name, ifrp->ifr_name, sizeof(ifr6.ifr_name));
/*
* Ignore loopback interfaces and interfaces that do not
* support multicast.
*/
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
flags = ifr.ifr_flags;
if ((flags & (IFF_LOOPBACK | IFF_MULTICAST)) != IFF_MULTICAST)
continue;
/*
* Get netmask of the address.
*/
ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr;
if (ioctl(udp_socket, SIOCGIFNETMASK_IN6, (char *)&ifr6) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK_IN6 for %s",
ifr6.ifr_name);
memcpy(&mask, &ifr6.ifr_addr.sin6_addr, sizeof(mask));
if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) {
addr.sin6_scope_id = if_nametoindex(ifrp->ifr_name);
#ifdef __KAME__
/*
* Hack for KAME kernel. Set sin6_scope_id field of a
* link local address and clear the index embedded in
* the address.
*/
/* clear interface index */
addr.sin6_addr.s6_addr[2] = 0;
addr.sin6_addr.s6_addr[3] = 0;
#endif
}
/*
* If the address is connected to the same subnet as one already
* installed in the uvifs array, just add the address to the list
* of addresses of the uvif.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
add_phaddr(v, &addr, &mask);
break;
}
}
if (vifi != numvifs)
continue;
/*
* If there is room in the uvifs array, install this interface.
*/
if (numvifs == MAXMIFS) {
log(LOG_WARNING, 0, "too many ifs, ignoring %s", ifr.ifr_name);
continue;
}
/*
* Everyone below is a potential vif interface.
* We don't care if it has wrong configuration or not configured
* at all.
*/
total_interfaces++;
v = &uvifs[numvifs];
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
v->uv_admetric = 0;
#if 0
v->uv_threshold = DEFAULT_THRESHOLD;
#endif
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
#if 0
v->uv_rmt_addr = INADDR_ANY_N;
#endif
v->uv_dst_addr = allpim6routers_group;
v->uv_prefix.sin6_addr = prefix;
v->uv_subnetmask = mask;
strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
v->uv_ifindex = if_nametoindex(v->uv_name);
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_prune_lifetime = 0;
v->uv_acl = (struct vif_acl *)NULL;
v->uv_leaf_timer = 0;
v->uv_addrs = (struct phaddr *)NULL;
v->uv_filter = (struct vif_filter *)NULL;
v->uv_pim_hello_timer = 0;
v->uv_gq_timer = 0;
v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL;
v->uv_local_pref = default_source_preference;
v->uv_local_metric = default_source_metric;
add_phaddr(v, &addr, &mask);
if (flags & IFF_POINTOPOINT)
v->uv_flags |= (VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
log(LOG_INFO, 0,
"installing %s as if #%u - rate=%d",
v->uv_name, numvifs, v->uv_rate_limit);
++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;
}
}
}
static void
add_phaddr(v, addr, mask)
struct uvif *v;
struct sockaddr_in6 *addr;
struct in6_addr *mask;
{
struct phaddr *pa;
int i;
if ((pa = malloc(sizeof(*pa))) == NULL)
log(LOG_ERR, 0, "add_phaddr: memory exhausted");
memset(pa, 0, sizeof(*pa));
pa->pa_addr = *addr;
pa->pa_subnetmask = *mask;
/*
* install the prefix of the address derived from the address
* and the mask.
*/
for (i = 0; i < sizeof(struct in6_addr); i++)
pa->pa_prefix.sin6_addr.s6_addr[i] =
addr->sin6_addr.s6_addr[i] & mask->s6_addr[i];
pa->pa_prefix.sin6_scope_id = addr->sin6_scope_id;
if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
if (v->uv_linklocal) {
log(LOG_WARNING, 0,
"add_phaddr: found more than one link-local "
"address on %s",
v->uv_name);
}
v->uv_linklocal = pa; /* relace anyway */
}
/* link into chain */
pa->pa_next = v->uv_addrs;
v->uv_addrs = pa;
}
static mifi_t
ifname2mifi(ifname)
char *ifname;
{
mifi_t mifi;
struct uvif *v;
for (mifi = 0, v = uvifs; mifi < numvifs; ++mifi, ++v) {
if (strcmp(v->uv_name, ifname) == 0)
break;
}
return(mifi);
}
#define UNKNOWN -1
#define EMPTY 1
#define PHYINT 2
#define DEFAULT_SOURCE_METRIC 3
#define DEFAULT_SOURCE_PREFERENCE 4
#define FILTER 5
/*
* 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(word)
char *word;
{
if (EQUAL(word, ""))
return EMPTY;
if (EQUAL(word, "phyint"))
return PHYINT;
if (EQUAL(word, "default_source_metric"))
return DEFAULT_SOURCE_METRIC;
if (EQUAL(word, "default_source_preference"))
return DEFAULT_SOURCE_PREFERENCE;
if (EQUAL(word, "filter"))
return FILTER;
return UNKNOWN;
}
/*
* function name: parse_phyint
* input: char *s, pointing to the parsing point of the file
* output: int (TRUE if the parsing was successful, o.w. FALSE)
* operation: parses the physical interface file configurations, if any.
* The general form is:
* phyint <ifname> [disable]
*/
static int
parse_phyint(s)
char *s;
{
char *w, c, *ifname;
vifi_t vifi;
struct uvif *v;
u_int n;
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_WARNING, 0, "Missing phyint in %s", configfilename);
return(FALSE);
} /* if empty */
ifname = w;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (vifi == numvifs) {
log(LOG_WARNING, 0,
"phyint %s in %s is not a configured interface",
ifname, configfilename);
return(FALSE);
} /* if vifi == numvifs */
if (strcmp(v->uv_name, ifname))
continue;
while (!EQUAL((w = next_word(&s)), "")) {
if (EQUAL(w, "disable"))
v->uv_flags |= VIFF_DISABLED;
else if (EQUAL(w, "nolistener"))
v->uv_flags |= VIFF_NOLISTENER;
else if(EQUAL(w, "preference")) {
if(EQUAL((w = next_word(&s)), ""))
log(LOG_WARNING, 0,
"Missing preference for phyint %s in %s",
ifname, configfilename);
else if (sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n > 255 )
log(LOG_WARNING, 0,
"Invalid preference '%s' for phyint %s in %s",
w, ifname,
configfilename);
else {
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG, 0,
"Config setting default local preference on %s to %d.",
ifname, n);
v->uv_local_pref = n;
}
} else if(EQUAL(w, "metric")) {
if(EQUAL((w = next_word(&s)), ""))
log(LOG_WARNING, 0,
"Missing metric for phyint %s in %s",
ifname, configfilename);
else if (sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n > 1024 )
log(LOG_WARNING, 0,
"Invalid metric '%s' for phyint %s in %s",
w, ifname,
configfilename);
else {
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG, 0,
"Config setting default local metric on %s to %d.",
ifname, n);
v->uv_local_metric = n;
}
}
} /* if not empty */
break;
}
return(TRUE);
}
static int
parse_filter(s)
char *s;
{
char *w, *groups, *p;
mifi_t mifi;
struct in6_addr grp1, grp2;
if_set filterset;
struct mrtfilter *filter;
int plen = 0, filtertype;
if (EQUAL((groups = next_word(&s)), "")) {
log(LOG_WARNING, 0, "Missing multicast group in %s",
configfilename);
return(FALSE);
}
/*
* Group address specification. Valid format are the followings.
* - Group1-Group2: specifies a numerical range of a scope.
* - GroupPrefix/Prefixlen: specifies a prefix of a scope. If the
* Prefixlen is omitted, it means the exact match.
*/
if ((p = strchr(groups, '-')) != NULL) { /* Group1-Group2 */
char *maddr1, *maddr2;
maddr1 = groups;
maddr2 = p + 1;
*p = '\0';
if (inet_pton(AF_INET6, maddr1, (void *)&grp1) != 1 ||
!IN6_IS_ADDR_MULTICAST(&grp1)) {
log(LOG_WARNING, 0, "invalid group address %s", maddr1);
return(FALSE);
}
if (inet_pton(AF_INET6, maddr2, (void *)&grp2) != 1 ||
!IN6_IS_ADDR_MULTICAST(&grp2)) {
log(LOG_WARNING, 0, "invalid group address %s", maddr2);
return(FALSE);
}
filtertype = FILTER_RANGE;
}
else if ((p = strchr(groups, '/')) != NULL) { /* GroupPrefix/Plen */
char *mprefix = groups;
int plen = atoi(p + 1);
*p = '\0';
if (inet_pton(AF_INET6, mprefix, (void *)&grp1) != 1 ||
!IN6_IS_ADDR_MULTICAST(&grp1)) {
log(LOG_WARNING, 0, "invalid group prefix %s", mprefix);
return(FALSE);
}
if (plen < 0 || plen > 128) {
log(LOG_WARNING, 0, "invalid prefix length %s", p + 1);
return(FALSE);
}
filtertype = FILTER_PREFIX;
}
else {
if (inet_pton(AF_INET6, groups, (void *)&grp1) != 1) {
log(LOG_WARNING, 0, "invalid group address %s", groups);
return(FALSE);
}
plen = 128; /* exact match */
filtertype = FILTER_PREFIX;
}
IF_ZERO(&filterset);
while (!EQUAL((w = next_word(&s)), "")) {
if ((mifi = ifname2mifi(w)) == MAXMIFS) {
/* XXX: scope consideration?? */
log(LOG_WARNING, 0,
"phyint %s in %s is not a configured interface",
w, configfilename);
return(FALSE);
}
IF_SET(mifi, &filterset);
}
if (IF_ISEMPTY(&filterset)) {
log(LOG_WARNING, 0,
"filter set is empty. ignore it.");
return(FALSE);
}
filter = add_filter(filtertype, &grp1, &grp2, plen);
IF_COPY(&filterset, &filter->ifset);
return(TRUE);
}
#if 0 /* not used */
/*
* function name: parse_default_source_metric
* input: char *s
* output: int
* operation: reads and assigns the default source metric, if no reliable
* unicast routing information available.
* General form:
* 'default_source_metric <number>'.
* default pref and metric statements should precede all phyint
* statements in the config file.
*/
static int
parse_default_source_metric(s)
char *s;
{
char *w;
u_int value;
vifi_t vifi;
struct uvif *v;
value = DEFAULT_LOCAL_METRIC;
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_WARNING, 0,
"Missing default source metric; set to default %u",
DEFAULT_LOCAL_METRIC);
} else if (sscanf(w, "%u", &value) != 1) {
log(LOG_WARNING, 0,
"Invalid default source metric; set to default %u",
DEFAULT_LOCAL_METRIC);
value = DEFAULT_LOCAL_METRIC;
}
default_source_metric = value;
log(LOG_INFO, 0, "default_source_metric is %u", value);
for (vifi = 0, v = uvifs; vifi < MAXMIFS; ++vifi, ++v) {
v->uv_local_metric = default_source_metric;
}
return(TRUE);
}
/*
* function name: parse_default_source_preference
* input: char *s
* output: int
* operation: reads and assigns the default source preference, if no reliable
* unicast routing information available.
* General form:
* 'default_source_preference <number>'.
* default pref and metric statements should precede all phyint
* statements in the config file.
*/
static int
parse_default_source_preference(s)
char *s;
{
char *w;
u_int value;
vifi_t vifi;
struct uvif *v;
value = DEFAULT_LOCAL_PREF;
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_WARNING, 0,
"Missing default source preference; set to default %u",
DEFAULT_LOCAL_PREF);
} else if (sscanf(w, "%u", &value) != 1) {
log(LOG_WARNING, 0,
"Invalid default source preference; set to default %u",
DEFAULT_LOCAL_PREF);
value = DEFAULT_LOCAL_PREF;
}
default_source_preference = value;
log(LOG_INFO, 0, "default_source_preference is %u", value);
for (vifi = 0, v = uvifs; vifi < MAXMIFS; ++vifi, ++v) {
v->uv_local_pref = default_source_preference;
}
return(TRUE);
}
#endif
void
config_vifs_from_file()
{
FILE *f;
char linebuf[100];
char *w, *s;
struct ifconf ifc;
int option;
char ifbuf[BUFSIZ];
if ((f = fopen(configfilename, "r")) == NULL) {
if (errno != ENOENT) log(LOG_WARNING, errno, "can't open %s",
configfilename);
return;
}
ifc.ifc_buf = ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
s = linebuf;
w = next_word(&s);
option = wordToOption(w);
switch(option) {
case EMPTY:
continue;
break;
case PHYINT:
parse_phyint(s);
break;
case FILTER:
parse_filter(s);
break;
default:
log(LOG_WARNING, 0, "unknown command '%s' in %s",
w, configfilename);
}
}
fclose(f);
}
static char *
next_word(s)
char **s;
{
char *w;
w = *s;
while (*w == ' ' || *w == '\t')
w++;
*s = w;
for(;;) {
switch (**s) {
case ' ' :
case '\t' :
**s = '\0';
(*s)++;
return(w);
case '\n' :
case '#' :
**s = '\0';
return(w);
case '\0' :
return(w);
default :
if (isascii(**s) && isupper(**s))
**s = tolower(**s);
(*s)++;
}
}
}

500
usr.sbin/pim6dd/debug.c Normal file
View File

@ -0,0 +1,500 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: debug.c,v 1.4 1999/09/20 14:28:08 jinmei 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.
*
* $FreeBSD$
*/
#include "defs.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
extern int haveterminal;
extern char *progname;
int log_nmsgs = 0;
unsigned long debug = 0x00000000; /* If (long) is smaller than
* 4 bytes, then we are in
* trouble.
*/
static char dumpfilename[] = _PATH_PIM6D_DUMP;
static char cachefilename[] = _PATH_PIM6D_CACHE; /* TODO: notused */
char *
packet_kind(proto, type, code)
u_int proto, type, code;
{
static char unknown[60];
switch (proto) {
case IPPROTO_ICMPV6:
switch (type) {
case MLD6_LISTENER_QUERY: return "Multicast Listener Query ";
case MLD6_LISTENER_REPORT: return "Multicast Listener Report ";
case MLD6_LISTENER_DONE: return "Multicast Listener Done ";
default:
sprintf(unknown,
"UNKNOWN ICMPv6 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:
sprintf(unknown, "UNKNOWN PIM v2 message type =%3d ", type);
return unknown;
}
default:
sprintf(unknown, "UNKNOWN proto =%3d ", proto);
return unknown;
}
}
/*
* Used for debugging particular type of messages.
*/
int
debug_kind(proto, type, code)
u_int proto, type, code;
{
switch (proto) {
case IPPROTO_ICMPV6:
switch (type) {
case MLD6_LISTENER_QUERY: return DEBUG_MLD;
case MLD6_LISTENER_REPORT: return DEBUG_MLD;
case MLD6_LISTENER_DONE: return DEBUG_MLD;
default: return DEBUG_MLD;
}
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_ICMPV6:
switch (type) {
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(i)
int i;
{
FILE *fp;
fp = fopen(dumpfilename, "w");
if (fp != NULL) {
dump_vifs(fp);
dump_pim_mrt(fp);
dump_lcl_grp(fp);
(void) fclose(fp);
}
}
/* TODO: dummy, to be used in the future. */
/*
* Dump local cache contents to a file.
*/
void
cdump(i)
int i;
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL) {
/* TODO: implement it:
dump_cache(fp);
*/
(void) fclose(fp);
}
}
void
dump_vifs(fp)
FILE *fp;
{
vifi_t vifi;
register struct uvif *v;
pim_nbr_entry_t *n;
struct phaddr *pa;
int width;
int i;
fprintf(fp, "\nMulticast Interface Table\n %-4s %-6s %-50s %-14s %s",
"Mif", " PhyIF", "Local-Address/Prefixlen", "Flags",
"Neighbors\n");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
int firstaddr = 1;
for (pa = v->uv_addrs; pa; pa = pa->pa_next) {
if (!firstaddr) {
fprintf(fp, " %3s %6s %-50s\n", "", "",
net6name(&pa->pa_addr.sin6_addr,
&pa->pa_subnetmask));
continue;
}
firstaddr = 0;
fprintf(fp, " %-3u %6s %-50s", vifi, v->uv_name,
net6name(&pa->pa_addr.sin6_addr,
&pa->pa_subnetmask));
firstaddr = 0;
#if 0
if (v->uv_flags & MIFF_REGISTER)
fprintf(fp, "%-16s ", v->uv_name);
else
fprintf(fp,"%-16.16s ",
net6name(&v->uv_prefix.sin6_addr,
&v->uv_subnetmask));
#endif
width = 0;
if (v->uv_flags & VIFF_DISABLED)
fprintf(fp, " DISABLED");
if (v->uv_flags & VIFF_NOLISTENER)
fprintf(fp, " NOLISTENER");
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 0 /* impossible */
if (v->uv_flags & VIFF_DVMRP_NBR) {
fprintf(fp, " DVMRP");
width += 6;
}
#endif
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, "%-12s\n",
inet6_fmt(&n->address.sin6_addr));
for (n = n->next; n != NULL; n = n->next)
fprintf(fp, "%64s %-15s\n", "",
inet6_fmt(&n->address.sin6_addr));
}
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.
*/
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
struct timeval now;
struct tm *thyme;
va_start(ap, format);
#else
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
va_dcl
{
va_list ap;
static char fmt[311] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap);
#endif
vsprintf(&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)) {
time_t sectime;
gettimeofday(&now,NULL);
sectime = (time_t) now.tv_sec;
thyme = localtime(&sectime);
if (!debug)
fprintf(stderr, "%s: ", progname);
fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", 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: %m", msg);
} else
syslog(severity, "%s", msg);
}
if (severity <= LOG_ERR) exit(-1);
}
/* TODO: format the output for better readability */
void
dump_pim_mrt(fp)
FILE *fp;
{
grpentry_t *g;
register mrtentry_t *r;
register vifi_t vifi;
u_int number_of_groups = 0;
char oifs[(sizeof(if_set)<<3)+1];
char pruned_oifs[(sizeof(if_set)<<3)+1];
char asserted_oifs[(sizeof(if_set)<<3)+1];
char leaves_oifs[(sizeof(if_set)<<3)+1];
char filter_oifs[(sizeof(if_set)<<3)+1];
char incoming_iif[(sizeof(if_set)<<3)+1];
fprintf(fp, "Multicast Routing Table\n%s",
" Source Group Flags\n");
/* TODO: remove the dummy 0:: group (first in the chain) */
for (g = grplist->next; g != (grpentry_t *)NULL; g = g->next) {
number_of_groups++;
/* Print all (S,G) routing info */
for (r = g->mrtlink; r != (mrtentry_t *)NULL; r = r->grpnext) {
fprintf(fp, "---------------------------(S,G)----------------------------\n");
/* Print the routing info */
fprintf(fp, " %-15s", inet6_fmt(&r->source->address.sin6_addr));
fprintf(fp, " %-15s", inet6_fmt(&g->group.sin6_addr));
for (vifi = 0; vifi < numvifs; vifi++) {
oifs[vifi] =
IF_ISSET(vifi, &r->oifs) ? 'o' : '.';
pruned_oifs[vifi] =
IF_ISSET(vifi, &r->pruned_oifs) ? 'p' : '.';
asserted_oifs[vifi] =
IF_ISSET(vifi, &r->pruned_oifs) ? 'a' : '.';
filter_oifs[vifi] =
IF_ISSET(vifi, &r->filter_oifs) ? 'f' : '.';
leaves_oifs[vifi] =
IF_ISSET(vifi, &r->leaves) ? 'l' : '.';
incoming_iif[vifi] = '.';
}
oifs[vifi] = 0x0; /* End of string */
pruned_oifs[vifi] = 0x0;
leaves_oifs[vifi] = 0x0;
filter_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, "Pruned oifs: %-20s\n", pruned_oifs);
fprintf(fp, "Asserted oifs: %-20s\n", pruned_oifs);
fprintf(fp, "Filtered oifs: %-20s\n", filter_oifs);
fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs);
fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
fprintf(fp, "Incoming : %-20s\n", incoming_iif);
fprintf(fp, "Upstream nbr: %s\n",
r->upstream ? inet6_fmt(&r->upstream->address.sin6_addr) : "NONE");
fprintf(fp, "\nTIMERS: Entry Prune VIFS:");
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %2d", vifi);
fprintf(fp, "\n %3d ",
r->timer);
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %3d", r->prune_timers[vifi]);
fprintf(fp, "\n");
}
}/* for all groups */
fprintf(fp, "Number of Groups: %u\n", number_of_groups);
}
void
dump_lcl_grp(fp)
FILE *fp;
{
vifi_t vifi;
struct uvif *v;
struct listaddr *g;
fprintf(fp, "\nList of local listener information per interface\n");
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
int first = 1;
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (first) {
fprintf(fp, " Mif %d(%s)\n", vifi, v->uv_name);
first = 0;
}
fprintf(fp, " %s", inet6_fmt(&g->al_addr.sin6_addr));
if (g->al_timerid)
fprintf(fp, " timeout: %d",
timer_leftTimer(g->al_timerid));
if (g->al_query)
fprintf(fp, " querytimer: %d",
timer_leftTimer(g->al_timerid));
fputc('\n', fp);
}
}
}

121
usr.sbin/pim6dd/debug.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: debug.h,v 1.1.1.1 1999/08/08 23:30:52 itojun 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.
*
* $FreeBSD$
*/
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 )
/* MLD related */
#define DEBUG_MLD_PROTO 0x00000010
#define DEBUG_MLD_TIMER 0x00000020
#define DEBUG_MLD_MEMBER 0x00000040
#define DEBUG_MEMBER DEBUG_MLD_MEMBER
#define DEBUG_MLD ( DEBUG_MLD_PROTO | DEBUG_MLD_TIMER | \
DEBUG_MLD_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_GRAFT 0x02000000
#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 | DEBUG_PIM_GRAFT )
#define DEBUG_MRT ( DEBUG_DVMRP_ROUTE | DEBUG_PIM_MRT )
#define DEBUG_NEIGHBORS ( DEBUG_DVMRP_PEER | DEBUG_PIM_HELLO )
#define DEBUG_TIMER ( DEBUG_MLD_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 */

597
usr.sbin/pim6dd/defs.h Normal file
View File

@ -0,0 +1,597 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: defs.h,v 1.6 1999/12/10 06:09:13 itojun Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#if ((defined(SYSV)) || (defined(__bsdi__)) || ((defined SunOS) && (SunOS < 50)))
#include <sys/sockio.h>
#endif /* SYSV || __bsdi__ || SunOS 4.x */
#include <sys/time.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/icmp6.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <osreldate.h>
#define rtentry kernel_rtentry
#include <net/route.h>
#undef rtentry
#include <netinet/ip_mroute.h>
#include <netinet6/ip6_mroute.h>
#include <strings.h>
#ifdef RSRR
#include <sys/un.h>
#endif /* RSRR */
typedef u_int u_int32;
typedef u_short u_int16;
typedef u_char u_int8;
#ifndef __P
#ifdef __STDC__
#define __P(x) x
#else
#define __P(x) ()
#endif
#endif
typedef void (*cfunc_t) __P((void *));
typedef void (*ihfunc_t) __P((int, fd_set *));
#include "pimdd.h"
#include "mrt.h"
#include "mld6.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
/*
* Various definitions to make it working for different platforms
*/
/* The old style sockaddr definition doesn't have sa_len */
#if (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(SunOS) && SunOS >=56) || (defined __FreeBSD__) || (defined IRIX) || (defined __bsdi__) || defined(__NetBSD__))
#define HAVE_ROUTING_SOCKETS
#endif
#define TRUE 1
#define FALSE 0
#define CREATE TRUE
#define DONT_CREATE FALSE
#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
/* obnoxious gcc gives an extraneous warning about this constant... */
#if defined(__STDC__) || defined(__GNUC__)
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
#else
#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
#define const /**/
#endif
#define MINHLIM 1 /* min hoplim 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 <netinet/in.h> 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 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 */
#define TIMER_INTERVAL 5 /* 5 sec virtual timer granularity */
#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 bcopy(a, b, c) memcpy((b), (a), (c))
#define bzero(s, n) memset((s), 0, (n))
#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 RECV_BUF_SIZE 64*1024 /* Maximum buff size to send
* or receive packet */
#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 *mld6_recv_buf;
extern char *mld6_send_buf;
extern char *pim6_recv_buf;
extern char *pim6_send_buf;
extern int mld6_socket;
extern int pim6_socket;
extern struct sockaddr_in6 allnodes_group;
extern struct sockaddr_in6 allrouters_group;
extern struct sockaddr_in6 allpim6routers_group;
extern if_set nbr_mifs;
#ifdef RSRR
extern int rsrr_socket;
#endif /* RSRR */
extern u_long virtual_time;
extern char configfilename[];
extern u_int32 default_source_metric;
extern u_int32 default_source_preference;
extern srcentry_t *srclist;
extern grpentry_t *grplist;
extern struct uvif uvifs[];
extern vifi_t numvifs;
extern int total_interfaces;
extern int phys_vif;
extern int udp_socket;
extern int vifs_down;
extern char s1[];
extern char s2[];
extern char s3[];
extern char s4[];
#if !(defined(BSD) && (BSD >= 199103))
extern int errno;
extern int sys_nerr;
extern char * sys_errlist[];
#endif
#ifndef IGMP_MEMBERSHIP_QUERY
#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY
#if !(defined(__NetBSD__))
#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__)
#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 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(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))
#define ELSE else /* To make emacs cc-mode happy */
/*
* External function definitions
*/
/* callout.c */
extern void callout_init __P((void));
extern void free_all_callouts __P((void));
extern void age_callout_queue __P((int));
extern int timer_nextTimer __P((void));
extern int timer_setTimer __P((int, cfunc_t, void *));
extern void timer_clearTimer __P((int));
extern int timer_leftTimer __P((int));
/* config.c */
extern void config_vifs_from_kernel __P((void));
extern void config_vifs_from_file __P((void));
/* debug.c */
extern char *packet_kind __P((u_int proto, u_int type, u_int code));
extern int debug_kind __P((u_int proto, u_int type, u_int code));
extern void log __P((int, int, char *, ...));
extern int log_level __P((u_int proto, u_int type, u_int code));
extern void dump __P((int i));
extern void fdump __P((int i));
extern void cdump __P((int i));
extern void dump_vifs __P((FILE *fp));
extern void dump_pim_mrt __P((FILE *fp));
extern void dump_lcl_grp __P((FILE *fp));
/* dvmrp_proto.c */
extern void dvmrp_accept_probe __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern void dvmrp_accept_report __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern void dvmrp_accept_info_request __P((u_int32 src, u_int32 dst,
u_char *p, int datalen));
extern void dvmrp_accept_info_reply __P((u_int32 src, u_int32 dst,
u_char *p, int datalen));
extern void dvmrp_accept_neighbors __P((u_int32 src, u_int32 dst,
u_char *p, int datalen,
u_int32 level));
extern void dvmrp_accept_neighbors2 __P((u_int32 src, u_int32 dst,
u_char *p, int datalen,
u_int32 level));
extern void dvmrp_accept_prune __P((u_int32 src, u_int32 dst,
char *p, int datalen));
extern void dvmrp_accept_graft __P((u_int32 src, u_int32 dst,
char *p, int datalen));
extern void dvmrp_accept_g_ack __P((u_int32 src, u_int32 dst,
char *p, int datalen));
/* mld6.c */
void init_mld6 __P((void));
void send_mld6 __P((int type, int code, struct sockaddr_in6 *src,
struct sockaddr_in6 *dst, struct in6_addr *group,
int index, int delay, int datalen, int alert));
/* mld6_proto.c */
extern void query_groups __P((struct uvif *v));
extern int check_grp_membership __P((struct uvif *v,
struct sockaddr_in6 *group));
extern void accept_listener_query __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group,
int tmo));
extern void accept_listener_report __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group));
extern void accept_listener_done __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group));
extern int check_multicast_listener __P((struct uvif *v,
struct sockaddr_in6 *group));
/* igmp.c */
#if 0
extern void init_igmp __P((void));
extern void send_igmp __P((char *buf, u_int32 src, u_int32 dst,
int type, int code, u_int32 group,
int datalen));
/* igmp_proto.c */
extern void query_groups __P((struct uvif *v));
extern void accept_membership_query __P((u_int32 src, u_int32 dst,
u_int32 group, int tmo));
extern void accept_group_report __P((u_int32 src, u_int32 dst,
u_int32 group, int r_type));
extern void accept_leave_message __P((u_int32 src, u_int32 dst,
u_int32 group));
#endif
#if 0
/* inet.c */
extern int inet_cksum __P((u_int16 *addr, u_int len));
extern int inet_valid_host __P((u_int32 naddr));
extern int inet_valid_mask __P((u_int32 mask));
extern int inet_valid_subnet __P((u_int32 nsubnet, u_int32 nmask));
extern char *inet_fmt __P((u_int32, char *s));
#ifdef NOSUCHDEF
extern char *inet_fmts __P((u_int32 addr, u_int32 mask, char *s));
#endif /* NOSUCHDEF */
extern char *netname __P((u_int32 addr, u_int32 mask));
extern u_int32 inet_parse __P((char *s, int n));
#endif
/* inet6.c */
extern int inet6_equal __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_lessoreq __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_lessthan __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_localif_address __P((struct sockaddr_in6 *sa,
struct uvif *v));
extern int inet6_greaterthan __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_greateroreq __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_match_prefix __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2,
struct in6_addr *mask));
extern int inet6_mask2plen __P((struct in6_addr *mask));
extern int inet6_uvif2scopeid __P((struct sockaddr_in6 *sa, struct uvif *v));
extern int inet6_valid_host __P((struct sockaddr_in6 *addr));
extern char *inet6_fmt __P((struct in6_addr *addr));
extern char *ifindex2str __P((int ifindex));
extern char *net6name __P((struct in6_addr *prefix,
struct in6_addr *mask));
/* kern.c */
extern void k_set_rcvbuf __P((int socket, int bufsize, int minsize));
extern void k_hdr_include __P((int socket, int bool));
extern void k_set_hlim __P((int socket, int t));
extern void k_set_loop __P((int socket, int l));
extern void k_set_if __P((int socket, u_int ifindex));
extern void k_join __P((int socket, struct in6_addr *grp,
u_int ifindex));
extern void k_leave __P((int socket, struct in6_addr *grp,
u_int ifindex));
extern void k_init_pim __P((int));
extern void k_stop_pim __P((int));
extern int k_del_mfc __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern int k_chg_mfc __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group, vifi_t iif,
if_set *oifs));
extern void k_add_vif __P((int socket, vifi_t vifi, struct uvif *v));
extern void k_del_vif __P((int socket, vifi_t vifi));
extern int k_get_vif_count __P((vifi_t vifi, struct vif_count *retval));
extern int k_get_sg_cnt __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group,
struct sg_count *retval));
/* main.c */
extern int register_input_handler __P((int fd, ihfunc_t func));
/* mrt.c */
extern void init_pim6_mrt __P((void));
extern mrtentry_t *find_route __P((struct sockaddr_in6 *source,
struct sockaddr_in6 *group,
u_int16 flags, char create));
extern grpentry_t *find_group __P((struct sockaddr_in6 *group));
extern srcentry_t *find_source __P((struct sockaddr_in6 *source));
extern void delete_mrtentry __P((mrtentry_t *mrtentry_ptr));
extern void delete_srcentry __P((srcentry_t *srcentry_ptr));
extern void delete_grpentry __P((grpentry_t *grpentry_ptr));
extern struct mrtfilter *search_filter __P((struct in6_addr *));
extern struct mrtfilter *add_filter __P((int, struct in6_addr *,
struct in6_addr *, int));
/* pim6.c */
extern void init_pim6 __P((void));
extern void send_pim6 __P((char *buf, struct sockaddr_in6 *src,
struct sockaddr_in6 *dst,
int type, int datalen));
/* pim6_poto.c */
extern int receive_pim6_hello __P((struct sockaddr_in6 *src,
char *pim_message, int datalen));
extern int send_pim6_hello __P((struct uvif *v, u_int16 holdtime));
extern void delete_pim6_nbr __P((pim_nbr_entry_t *nbr_delete));
extern int receive_pim6_join_prune __P((struct sockaddr_in6 *src,
char *pim_message, int datalen));
extern int send_pim6_jp __P((mrtentry_t *mrtentry_ptr, int action,
mifi_t mifi,
struct sockaddr_in6 *target_addr,
u_int16 holdtime, int echo));
extern int receive_pim6_assert __P((struct sockaddr_in6 *src,
char *pim_message, int datalen));
extern int send_pim6_assert __P((struct sockaddr_in6 *source,
struct sockaddr_in6 *group,
mifi_t mifi,
mrtentry_t *mrtentry_ptr));
extern void delete_pim6_graft_entry __P((mrtentry_t *mrtentry_ptr));
extern int receive_pim6_graft __P((struct sockaddr_in6 *src,
char *pim_message, int datalen,
int pimtype));
extern int send_pim6_graft __P((mrtentry_t *mrtentry_ptr));
#if 0
/* pim.c */
extern void init_pim __P((void));
extern void send_pim __P((char *buf, u_int32 src, u_int32 dst,
int type, int datalen));
extern void send_pim_unicast __P((char *buf, u_int32 src, u_int32 dst,
int type, int datalen));
/* pim_proto.c */
extern int receive_pim_hello __P((u_int32 src, u_int32 dst,
char *pim_message, int datalen));
extern int send_pim_hello __P((struct uvif *v, u_int16 holdtime));
extern void delete_pim_nbr __P((pim_nbr_entry_t *nbr_delete));
extern int receive_pim_join_prune __P((u_int32 src, u_int32 dst,
char *pim_message, int datalen));
extern int send_pim_jp __P((mrtentry_t *mrtentry_ptr, int action,
vifi_t vifi, u_int32 target_addr,
u_int16 holdtime));
extern int receive_pim_assert __P((u_int32 src, u_int32 dst,
char *pim_message, int datalen));
extern int send_pim_assert __P((u_int32 source, u_int32 group,
vifi_t vifi,
mrtentry_t *mrtentry_ptr));
extern void delete_pim_graft_entry __P((mrtentry_t *mrtentry_ptr));
extern int receive_pim_graft __P((u_int32 src, u_int32 dst,
char *pim_message, int datalen,
int pimtype));
#endif
/* route.c */
extern int set_incoming __P((srcentry_t *srcentry_ptr,
int srctype));
extern vifi_t get_iif __P((struct sockaddr_in6 *source));
extern pim_nbr_entry_t *find_pim6_nbr __P((struct sockaddr_in6 *source));
extern int add_sg_oif __P((mrtentry_t *mrtentry_ptr,
vifi_t vifi,
u_int16 holdtime,
int update_holdtime));
extern void add_leaf __P((vifi_t vifi,
struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern void delete_leaf __P((vifi_t vifi,
struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern void set_leaves __P((mrtentry_t *mrtentry_ptr));
extern int change_interfaces __P((mrtentry_t *mrtentry_ptr,
vifi_t new_iif,
if_set *new_pruned_oifs,
if_set *new_leaves_,
if_set *new_asserted_oifs));
extern void calc_oifs __P((mrtentry_t *mrtentry_ptr,
if_set *oifs_ptr));
extern void process_kernel_call __P((void));
extern int delete_vif_from_mrt __P((vifi_t vifi));
extern void trigger_join_alert __P((mrtentry_t *mrtentry_ptr));
extern void trigger_prune_alert __P((mrtentry_t *mrtentry_ptr));
/* routesock.c */
extern int k_req_incoming __P((struct sockaddr_in6 *source,
struct rpfctl *rpfp));
#ifdef HAVE_ROUTING_SOCKETS
extern int init_routesock __P((void));
#endif /* HAVE_ROUTING_SOCKETS */
#ifdef RSRR
#define gtable mrtentry
#define RSRR_NOTIFICATION_OK TRUE
#define RSRR_NOTIFICATION_FALSE FALSE
/* rsrr.c */
extern void rsrr_init __P((void));
extern void rsrr_clean __P((void));
extern void rsrr_cache_send __P((struct gtable *, int));
extern void rsrr_cache_clean __P((struct gtable *));
extern void rsrr_cache_bring_up __P((struct gtable *));
#endif /* RSRR */
/* timer.c */
extern void init_timers __P((void));
extern void age_vifs __P((void));
extern void age_routes __P((void));
extern int clean_srclist __P((void));
/* trace.c */
/* u_int is promoted u_char */
extern void accept_mtrace __P((struct sockaddr_in6 *src,
struct in6_addr *dst, struct in6_addr *group,
int ifindex, char *data, u_int no, int datalen));
/* vif.c */
extern void init_vifs __P((void));
extern void stop_all_vifs __P((void));
extern void check_vif_state __P((void));
extern vifi_t local_address __P((struct sockaddr_in6 *src));
extern vifi_t find_vif_direct __P((struct sockaddr_in6 *src));
extern vifi_t find_vif_direct_local __P((struct sockaddr_in6 *src));
extern struct sockaddr_in6 *max_global_address __P((void));
extern struct sockaddr_in6 *uv_global __P((vifi_t vifi));

288
usr.sbin/pim6dd/inet6.c Normal file
View File

@ -0,0 +1,288 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
int
inet6_uvif2scopeid(struct sockaddr_in6 *sa, struct uvif *v)
{
if (IN6_IS_ADDR_MULTICAST(&sa->sin6_addr)) {
if (IN6_IS_ADDR_MC_LINKLOCAL(&sa->sin6_addr))
return(v->uv_ifindex);
if (IN6_IS_ADDR_MC_SITELOCAL(&sa->sin6_addr))
return(v->uv_siteid);
}
else {
if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
return(v->uv_ifindex);
if (IN6_IS_ADDR_SITELOCAL(&sa->sin6_addr))
return(v->uv_siteid);
}
return(0);
}
int
inet6_localif_address(struct sockaddr_in6 *sa, struct uvif *v)
{
struct phaddr *pa;
for (pa = v->uv_addrs; pa; pa = pa->pa_next)
if (inet6_equal(sa, &pa->pa_addr))
return(TRUE);
return(FALSE);
}
int
inet6_valid_host(struct sockaddr_in6 *addr)
{
if (IN6_IS_ADDR_MULTICAST(&addr->sin6_addr))
return(FALSE);
return(TRUE);
}
int
inet6_equal(struct sockaddr_in6 *sa1, struct sockaddr_in6 *sa2)
{
if (sa1->sin6_scope_id == sa2->sin6_scope_id &&
IN6_ARE_ADDR_EQUAL(&sa1->sin6_addr, &sa2->sin6_addr))
return(1);
return(0);
}
int
inet6_lessthan(struct sockaddr_in6 *sa1, struct sockaddr_in6 *sa2)
{
u_int32_t s32_1, s32_2;
int i;
if (sa1->sin6_scope_id < sa2->sin6_scope_id)
return(1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id) {
for (i = 0; i < 4; i++) {
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 > s32_2)
return(0);
if (s32_1 < s32_2)
return(1);
/* otherwide, continue to compare */
}
}
return(0);
}
int
inet6_lessoreq(struct sockaddr_in6 *sa1, struct sockaddr_in6 *sa2)
{
u_int32_t s32_1, s32_2;
int i;
if (sa1->sin6_scope_id < sa2->sin6_scope_id)
return(1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id) {
for (i = 0; i < 4; i++) {
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 > s32_2)
return(0);
if (s32_1 < s32_2)
return(1);
/* otherwide, continue to compare */
}
/* sa1 == sa2 */
return(1);
}
return(0);
}
int
inet6_greaterthan(struct sockaddr_in6 *sa1, struct sockaddr_in6 *sa2)
{
u_int32_t s32_1, s32_2;
int i;
if (sa1->sin6_scope_id > sa2->sin6_scope_id)
return(1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id) {
for (i = 0; i < 4; i++) {
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 < s32_2)
return(0);
if (s32_1 > s32_2)
return(1);
/* otherwide, continue to compare */
}
}
return(0);
}
int
inet6_greateroreq(struct sockaddr_in6 *sa1, struct sockaddr_in6 *sa2)
{
u_int32_t s32_1, s32_2;
int i;
if (sa1->sin6_scope_id > sa2->sin6_scope_id)
return(1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id) {
for (i = 0; i < 4; i++) {
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 < s32_2)
return(0);
if (s32_1 > s32_2)
return(1);
/* otherwide, continue to compare */
}
/* sa1 == sa2 */
return(1);
}
return(0);
}
int
inet6_match_prefix(sa1, sa2, mask)
struct sockaddr_in6 *sa1, *sa2;
struct in6_addr *mask;
{
int i;
if (sa1->sin6_scope_id != sa2->sin6_scope_id)
return(0);
for (i = 0; i < 16; i++) {
if ((sa1->sin6_addr.s6_addr[i] ^ sa2->sin6_addr.s6_addr[i]) &
mask->s6_addr[i])
return(0);
}
return(1);
}
char *
inet6_fmt(struct in6_addr *addr)
{
static char ip6buf[8][INET6_ADDRSTRLEN];
static int ip6round = 0;
char *cp;
ip6round = (ip6round + 1) & 7;
cp = ip6buf[ip6round];
inet_ntop(AF_INET6, addr, cp, INET6_ADDRSTRLEN);
return(cp);
}
char *
ifindex2str(int ifindex)
{
static char ifname[IFNAMSIZ];
return(if_indextoname(ifindex, ifname));
}
int
inet6_mask2plen(struct in6_addr *mask)
{
int masklen;
u_char *p = (u_char *)mask;
u_char *lim = p + 16;
for (masklen = 0; p < lim; p++) {
switch (*p) {
case 0xff:
masklen += 8;
break;
case 0xfe:
masklen += 7;
break;
case 0xfc:
masklen += 6;
break;
case 0xf8:
masklen += 5;
break;
case 0xf0:
masklen += 4;
break;
case 0xe0:
masklen += 3;
break;
case 0xc0:
masklen += 2;
break;
case 0x80:
masklen += 1;
break;
case 0x00:
break;
}
}
return(masklen);
}
char *
net6name(struct in6_addr *prefix, struct in6_addr *mask)
{
static char ip6buf[8][INET6_ADDRSTRLEN + 4]; /* length of addr/plen */
static int ip6round = 0;
char *cp;
ip6round = (ip6round + 1) & 7;
cp = ip6buf[ip6round];
inet_ntop(AF_INET6, prefix, cp, INET6_ADDRSTRLEN);
cp += strlen(cp);
*cp = '/';
cp++;
sprintf(cp, "%d", inet6_mask2plen(mask));
return(ip6buf[ip6round]);
}

415
usr.sbin/pim6dd/kern.c Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: kern.c,v 1.1.1.1 1999/08/08 23:30:52 itojun 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.
*
* $FreeBSD$
*/
#include "defs.h"
#ifdef RAW_OUTPUT_IS_RAW
int curttl = 0;
#endif
/*
* Open/init the multicast routing in the kernel and sets the MRT_ASSERT
* flag in the kernel.
*
*/
void
k_init_pim(socket)
int socket;
{
int v = 1;
if (setsockopt(socket, IPPROTO_IPV6,
MRT6_INIT, (char *)&v, sizeof(int)) < 0)
log(LOG_ERR, errno, "cannot enable multicast routing in kernel");
if(setsockopt(socket, IPPROTO_IPV6,
MRT6_PIM, (char *)&v, sizeof(int)) < 0)
log(LOG_ERR, errno, "cannot set ASSERT flag in kernel");
}
/*
* Stops the multicast routing in the kernel and resets the MRT_ASSERT
* flag in the kernel.
*/
void
k_stop_pim(socket)
int socket;
{
int v = 0;
if(setsockopt(socket, IPPROTO_IPV6, MRT6_PIM,
(char *)&v, sizeof(int)) < 0)
log(LOG_ERR, errno, "cannot reset ASSERT flag in kernel");
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DONE, (char *)NULL, 0) < 0)
log(LOG_ERR, errno, "cannot disable multicast routing in kernel");
}
/*
* Set the socket receiving buffer. `bufsize` is the preferred size,
* `minsize` is the smallest acceptable size.
*/
void k_set_rcvbuf(socket, bufsize, minsize)
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) {
log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
bufsize, minsize);
/*NOTREACHED*/
}
}
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
bufsize, iter);
}
#if 0 /* there is no HDRINCL option in IPv6 */
/*
* 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(socket, bool)
int socket;
int bool;
{
#ifdef IP_HDRINCL
if (setsockopt(socket, IPPROTO_IP, IP_HDRINCL,
(char *)&bool, sizeof(bool)) < 0)
log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
#endif
}
#endif /* 0 */
/*
* Set the default Hop Limit for the multicast packets outgoing from this
* socket.
*/
void k_set_hlim(socket, h)
int socket;
int h;
{
#ifdef RAW_OUTPUT_IS_RAW
curttl = h;
#else
int hlim = h;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
(char *)&hlim, sizeof(hlim)) < 0)
log(LOG_ERR, errno, "setsockopt IPV6_MULTICAST_HOPS %u", hlim);
#endif
}
/*
* Set/reset the IPV6_MULTICAST_LOOP. Set/reset is specified by "flag".
*/
void k_set_loop(socket, flag)
int socket;
int flag;
{
u_int loop;
loop = flag;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
(char *)&loop, sizeof(loop)) < 0)
log(LOG_ERR, errno, "setsockopt IPV6_MULTICAST_LOOP %u", loop);
}
/*
* Set the IPV6_MULTICAST_IF option on local interface which has the
* specified index.
*/
void k_set_if(socket, ifindex)
int socket;
u_int ifindex;
{
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(char *)&ifindex, sizeof(ifindex)) < 0)
log(LOG_ERR, errno, "setsockopt IPV6_MULTICAST_IF for %s",
ifindex2str(ifindex));
}
/*
* Join a multicast grp group on local interface ifa.
*/
void k_join(socket, grp, ifindex)
int socket;
struct in6_addr *grp;
u_int ifindex;
{
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = *grp;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
(char *)&mreq, sizeof(mreq)) < 0)
log(LOG_WARNING, errno, "cannot join group %s on interface %s",
inet6_fmt(grp), ifindex2str(ifindex));
}
/*
* Leave a multicats grp group on local interface ifa.
*/
void k_leave(socket, grp, ifindex)
int socket;
struct in6_addr *grp;
u_int ifindex;
{
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = *grp;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
(char *)&mreq, sizeof(mreq)) < 0)
log(LOG_WARNING, errno, "cannot leave group %s on interface %s",
inet6_fmt(grp), ifindex2str(ifindex));
}
/*
* Add a virtual interface in the kernel.
*/
void k_add_vif(socket, vifi, v)
int socket;
vifi_t vifi;
struct uvif *v;
{
struct mif6ctl mc;
mc.mif6c_mifi = vifi;
/* TODO: only for DVMRP tunnels?
mc.mif6c_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
*/
mc.mif6c_flags = v->uv_flags;
#ifdef notyet
mc.mif6c_rate_limit = v->uv_rate_limit;
#endif
mc.mif6c_pifi = v->uv_ifindex;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MIF,
(char *)&mc, sizeof(mc)) < 0)
log(LOG_ERR, errno, "setsockopt MRT6_ADD_MIF on mif %d", vifi);
}
/*
* Delete a virtual interface in the kernel.
*/
void k_del_vif(socket, vifi)
int socket;
vifi_t vifi;
{
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MIF,
(char *)&vifi, sizeof(vifi)) < 0)
log(LOG_ERR, errno, "setsockopt MRT6_DEL_MIF on mif %d", vifi);
}
/*
* Delete all MFC entries for particular routing entry from the kernel.
*/
int
k_del_mfc(socket, source, group)
int socket;
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
{
struct mf6cctl mc;
mc.mf6cc_origin = *source;
mc.mf6cc_mcastgrp = *group;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MFC, (char *)&mc,
sizeof(mc)) < 0) {
log(LOG_WARNING, errno, "setsockopt MRT6_DEL_MFC");
return FALSE;
}
IF_DEBUG(DEBUG_MFC)
log(LOG_DEBUG, 0, "Deleted MFC entry: src %s, grp %s",
inet6_fmt(&source->sin6_addr),
inet6_fmt(&group->sin6_addr));
return(TRUE);
}
/*
* Install/modify a MFC entry in the kernel
*/
int
k_chg_mfc(socket, source, group, iif, oifs)
int socket;
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
vifi_t iif;
if_set *oifs;
{
struct mf6cctl mc;
vifi_t vifi;
mc.mf6cc_origin = *source;
mc.mf6cc_mcastgrp = *group;
mc.mf6cc_parent = iif;
IF_ZERO(&mc.mf6cc_ifset);
for (vifi = 0; vifi < numvifs; vifi++) {
if (IF_ISSET(vifi, oifs))
IF_SET(vifi, &mc.mf6cc_ifset);
else
IF_CLR(vifi, &mc.mf6cc_ifset);
}
if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MFC, (char *)&mc,
sizeof(mc)) < 0) {
log(LOG_WARNING, errno,
"setsockopt MRT6_ADD_MFC for source %s and group %s",
inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
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, retval)
vifi_t vifi;
struct vif_count *retval;
{
struct sioc_mif_req6 mreq;
mreq.mifi = vifi;
if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *)&mreq) < 0) {
log(LOG_WARNING, errno, "SIOCGETMIFCNT_IN6 on vif %d", vifi);
retval->icount = retval->ocount = retval->ibytes =
retval->obytes = 0xffffffff;
return (1);
}
retval->icount = mreq.icount;
retval->ocount = mreq.ocount;
retval->ibytes = mreq.ibytes;
retval->obytes = mreq.obytes;
return (0);
}
/*
* Gets the number of packets, bytes, and number of packets arrived
* on wrong if in the kernel for particular (S,G) entry.
*/
int
k_get_sg_cnt(socket, source, group, retval)
int socket; /* udp_socket */
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
struct sg_count *retval;
{
struct sioc_sg_req6 sgreq;
sgreq.src = *source;
sgreq.grp = *group;
if (ioctl(socket, SIOCGETSGCNT_IN6, (char *)&sgreq) < 0) {
log(LOG_WARNING, errno, "SIOCGETSGCNT_IN6 on (%s %s)",
inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
retval->pktcnt = retval->bytecnt = retval->wrong_if = ~0; /* XXX */
return(1);
}
retval->pktcnt = sgreq.pktcnt;
retval->bytecnt = sgreq.bytecnt;
retval->wrong_if = sgreq.wrong_if;
return(0);
}

719
usr.sbin/pim6dd/main.c Normal file
View File

@ -0,0 +1,719 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: main.c,v 1.2 1999/08/13 09:20:13 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
#ifdef SNMP
#include "snmp.h"
#endif
char configfilename[256] = _PATH_PIM6D_CONF;
char versionstring[100];
static char pidfilename[] = _PATH_PIM6D_PID;
/* TODO: not used
static char genidfilename[] = _PATH_PIM6D_GENID;
*/
int haveterminal = 1;
char *progname;
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;
int level;
int nchars;
} debugnames[] = {
#if 0
{ "dvmrp_detail", DEBUG_DVMRP_DETAIL, 5 },
{ "dvmrp_prunes", DEBUG_DVMRP_PRUNE, 8 },
{ "dvmrp_pruning", DEBUG_DVMRP_PRUNE, 8 },
{ "dvmrp_mrt", DEBUG_DVMRP_ROUTE, 7 },
{ "dvmrp_routes", DEBUG_DVMRP_ROUTE, 7 },
{ "dvmrp_routing", 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 },
#endif
{ "trace", DEBUG_TRACE, 2 },
{ "mtrace", DEBUG_TRACE, 2 },
{ "traceroute", DEBUG_TRACE, 2 },
{ "timeout", DEBUG_TIMEOUT, 2 },
{ "callout", DEBUG_TIMEOUT, 3 },
{ "pkt", DEBUG_PKT, 2 },
{ "packets", 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_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_graft", DEBUG_PIM_GRAFT, 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 },
{ "routers", DEBUG_NEIGHBORS, 6 },
{ "mrouters", DEBUG_NEIGHBORS, 7 },
{ "neighbors", DEBUG_NEIGHBORS, 1 },
{ "timers", DEBUG_TIMER, 1 },
{ "asserts", DEBUG_ASSERT, 1 },
{ "all", DEBUG_ALL, 2 },
{ "3", 0xffffffff, 1 } /* compat. */
};
/*
* Forward declarations.
*/
static void handler __P((int));
static void timer __P((void *));
static void cleanup __P((void));
static void restart __P((int));
static void cleanup __P((void));
static void resetlogging __P((void *));
/* To shut up gcc -Wstrict-prototypes */
int main __P((int argc, char **argv));
int
register_input_handler(fd, func)
int fd;
ihfunc_t func;
{
if (nhandlers >= NHANDLERS)
return -1;
ihandlers[nhandlers].fd = fd;
ihandlers[nhandlers++].func = func;
return 0;
}
int
main(argc, argv)
int argc;
char *argv[];
{
int dummy, dummysigalrm;
FILE *fp;
struct timeval tv, difftime, curtime, lasttime, *timeout;
fd_set rfds, readers;
int nfds, n, i, secs;
extern char todaysversion[];
struct sigaction sa;
struct debugname *d;
char c;
int tmpd;
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "pim6dd: must be root\n");
exit(1);
}
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
argv++;
argc--;
while (argc > 0 && *argv[0] == '-') {
if (strcmp(*argv, "-d") == 0) {
if (argc > 1 && *(argv + 1)[0] != '-') {
char *p,*q;
int i, len;
struct debugname *d;
argv++;
argc--;
debug = 0;
p = *argv; q = NULL;
while (p) {
q = strchr(p, ',');
if (q)
*q++ = '\0';
len = strlen(p);
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++)
if (len >= d->nchars && strncmp(d->name, p, len) == 0)
break;
if (i == sizeof(debugnames) / sizeof(debugnames[0])) {
int j = 0xffffffff;
int k = 0;
fprintf(stderr, "Valid debug levels: ");
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++) {
if ((j & d->level) == d->level) {
if (k++)
putc(',', stderr);
fputs(d->name, stderr);
j &= ~d->level;
}
}
putc('\n', stderr);
goto usage;
}
debug |= d->level;
p = q;
}
}
else
debug = DEBUG_DEFAULT;
}
else if (strcmp(*argv, "-c") == 0) {
if (argc > 1) {
argv++; argc--;
strcpy(configfilename, *argv);
}
else
goto usage;
/* TODO: not implemented */
#ifdef SNMP
}
else if (strcmp(*argv, "-P") == 0) {
if (argc > 1 && isdigit(*(argv + 1)[0])) {
argv++, argc--;
dest_port = atoi(*argv);
}
else
dest_port = DEFAULT_PORT;
#endif
}
else
goto usage;
argv++; argc--;
}
if (argc > 0) {
usage:
tmpd = 0xffffffff;
fprintf(stderr, "usage: pim6dd [-c configfile] [-d [debug_level][,debug_level]]\n");
fprintf(stderr, "debug levels: ");
c = '(';
for (d = debugnames; d < debugnames +
sizeof(debugnames) / sizeof(debugnames[0]); d++) {
if ((tmpd & d->level) == d->level) {
tmpd &= ~d->level;
fprintf(stderr, "%c%s", c, d->name);
c = ',';
}
}
fprintf(stderr, ")\n");
exit(1);
}
if (debug != 0) {
tmpd = debug;
fprintf(stderr, "debug level 0x%lx ", debug);
c = '(';
for (d = debugnames; d < debugnames +
sizeof(debugnames) / sizeof(debugnames[0]); d++) {
if ((tmpd & d->level) == d->level) {
tmpd &= ~d->level;
fprintf(stderr, "%c%s", c, d->name);
c = ',';
}
}
fprintf(stderr, ")\n");
}
#ifdef LOG_DAEMON
(void)openlog("pim6dd", LOG_PID, LOG_DAEMON);
(void)setlogmask(LOG_UPTO(LOG_NOTICE));
#else
(void)openlog("pim6dd", LOG_PID);
#endif /* LOG_DAEMON */
sprintf(versionstring, "pim6dd version %s", todaysversion);
log(LOG_DEBUG, 0, "%s starting", versionstring);
/* TODO: XXX: use a combination of time and hostid to initialize the random
* generator.
*/
#ifdef SYSV
srand48(time(NULL));
#else
{
struct timeval tm;
gettimeofday(&tm, NULL);
srandom(tm.tv_usec + gethostid());
}
#endif
callout_init();
/* Start up the log rate-limiter */
resetlogging(NULL);
init_mld6();
#if 0
k_stop_pim(mld6_socket);
exit(0); /* XXX */
#endif
init_pim6();
init_pim6_mrt();
init_timers();
/* TODO: check the kernel DVMRP/MROUTED/PIM support version */
#ifdef SNMP
if (i = snmp_init())
return i;
#endif /* SNMP */
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(mld6_socket, &readers);
nfds = mld6_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 == 0) {
/* Detach from the terminal */
#ifdef TIOCNOTTY
int t;
#endif /* TIOCNOTTY */
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);
#if defined(SYSV) || defined(linux)
(void)setpgrp();
#else
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
(void)ioctl(t, TIOCNOTTY, (char *)0);
(void)close(t);
}
#else
if (setsid() < 0)
perror("setsid");
#endif /* TIOCNOTTY */
#endif /* SYSV */
} /* End of child process code */
#ifdef HAVE_ROUTING_SOCKETS
init_routesock();
#endif /* HAVE_ROUTING_SOCKETS */
fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", (int)getpid());
(void) fclose(fp);
}
/*
* Main receive loop.
*/
dummy = 0;
dummysigalrm = SIGALRM;
difftime.tv_usec = 0;
gettimeofday(&curtime, NULL);
lasttime = curtime;
for(;;) {
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
secs = timer_nextTimer();
if (secs == -1)
timeout = NULL;
else {
timeout = &tv;
timeout->tv_sec = secs;
timeout->tv_usec = 0;
}
if (sighandled) {
if (sighandled & GOT_SIGINT) {
sighandled &= ~GOT_SIGINT;
break;
}
if (sighandled & GOT_SIGHUP) {
sighandled &= ~GOT_SIGHUP;
restart(SIGHUP);
}
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 */
log(LOG_WARNING, errno, "select failed");
continue;
}
/*
* 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;
#ifdef TIMERDEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "TIMEOUT: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec );
#endif
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) {
#ifdef TIMERDEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "\taging callouts: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec );
#endif
age_callout_queue(difftime.tv_sec);
}
secs = -1;
} while (difftime.tv_sec > 0);
/* Handle sockets */
if (n > 0) {
/* TODO: shall check first mld6_socket for better performance? */
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
}
}
}
} /* Main loop */
log(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(i)
void *i;
{
age_vifs(); /* Timeout neighbors and groups */
age_routes(); /* Timeout routing entries */
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()
{
#ifdef RSRR
rsrr_clean();
#endif /* RSRR */
k_stop_pim(mld6_socket);
/* TODO: XXX (not in the spec)
*/
}
/*
* Signal handler. Take note of the fact that the signal arrived
* so that the main loop can take care of it.
*/
static void
handler(sig)
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 */
/* PIMDM TODO */
/*
* Restart the daemon
*/
static void
restart(i)
int i;
{
#ifdef SNMP
int s;
#endif /* SNMP */
log(LOG_NOTICE, 0, "% restart", versionstring);
/*
* reset all the entries
*/
/*
* TODO: delete?
* free_all_routes();
*/
free_all_callouts();
stop_all_vifs();
nhandlers=0;
k_stop_pim(mld6_socket);
close(mld6_socket);
close(pim6_socket);
close(udp_socket);
/*
* start processing again
*/
init_mld6();
init_pim6();
#ifdef HAVE_ROUTING_SOCKETS
init_routesock();
#endif /* HAVE_ROUTING_SOCKETS */
init_pim6_mrt();
#ifdef SNMP
if ( s = snmp_init())
exit(s);
#endif /* SNMP */
init_vifs();
#ifdef RSRR
rsrr_init();
#endif /* RSRR */
/* schedule timer interrupts */
timer_setTimer(TIMER_INTERVAL, timer, NULL);
}
static void
resetlogging(arg)
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);
}

537
usr.sbin/pim6dd/mld6.c Normal file
View File

@ -0,0 +1,537 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: mld6.c,v 1.7 2000/01/04 17:17:21 jinmei 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.
*
* $FreeBSD$
*/
#include "defs.h"
#include <sys/uio.h>
/*
* Exported variables.
*/
char *mld6_recv_buf; /* input packet buffer */
char *mld6_send_buf; /* output packet buffer */
int mld6_socket; /* socket for all network I/O */
struct sockaddr_in6 allrouters_group = {sizeof(struct sockaddr_in6), AF_INET6};
struct sockaddr_in6 allnodes_group = {sizeof(struct sockaddr_in6), AF_INET6};
/* Extenals */
extern struct in6_addr in6addr_linklocal_allnodes;
/* local variables. */
static struct sockaddr_in6 dst = {sizeof(dst), AF_INET6};
static struct msghdr sndmh,
rcvmh;
static struct iovec sndiov[2];
static struct iovec rcviov[2];
static struct sockaddr_in6 from;
static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int))];
#ifndef USE_RFC2292BIS
u_int8_t raopt[IP6OPT_RTALERT_LEN];
#endif
static char *sndcmsgbuf;
static int ctlbuflen = 0;
static u_short rtalert_code;
/* local functions */
static void mld6_read __P((int i, fd_set * fds));
static void accept_mld6 __P((int len));
static void make_mld6_msg __P((int, int, struct sockaddr_in6 *,
struct sockaddr_in6 *, struct in6_addr *, int, int, int, int));
#ifndef IP6OPT_ROUTER_ALERT
#define IP6OPT_ROUTER_ALERT IP6OPT_RTALERT
#endif
/*
* Open and initialize the MLD socket.
*/
void
init_mld6()
{
struct icmp6_filter filt;
int on;
rtalert_code = htons(IP6OPT_RTALERT_MLD);
if (!mld6_recv_buf && (mld6_recv_buf = malloc(RECV_BUF_SIZE)) == NULL)
log(LOG_ERR, 0, "malloca failed");
if (!mld6_send_buf && (mld6_send_buf = malloc(RECV_BUF_SIZE)) == NULL)
log(LOG_ERR, 0, "malloca failed");
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG,0,"%d octets allocated for the emit/recept buffer mld6",RECV_BUF_SIZE);
if ((mld6_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
log(LOG_ERR, errno, "MLD6 socket");
k_set_rcvbuf(mld6_socket, SO_RECV_BUF_SIZE_MAX,
SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
k_set_hlim(mld6_socket, MINHLIM); /* restrict multicasts to one hop */
k_set_loop(mld6_socket, FALSE); /* disable multicast loopback */
/* address initialization */
allnodes_group.sin6_addr = in6addr_linklocal_allnodes;
if (inet_pton(AF_INET6, "ff02::2",
(void *) &allrouters_group.sin6_addr) != 1)
log(LOG_ERR, 0, "inet_pton failed for ff02::2");
/* filter all non-MLD ICMP messages */
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_QUERY, &filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REPORT, &filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REDUCTION, &filt);
ICMP6_FILTER_SETPASS(MLD6_MTRACE_RESP, &filt);
ICMP6_FILTER_SETPASS(MLD6_MTRACE, &filt);
if (setsockopt(mld6_socket, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
sizeof(filt)) < 0)
log(LOG_ERR, errno, "setsockopt(ICMP6_FILTER)");
/* specify to tell receiving interface */
on = 1;
#ifdef IPV6_RECVPKTINFO
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_RECVPKTINFO)");
#else /* old adv. API */
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_PKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_PKTINFO)");
#endif
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
#ifdef IPV6_RECVHOPLIMIT
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_RECVHOPLIMIT)");
#else /* old adv. API */
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_HOPLIMIT)");
#endif
/* initialize msghdr for receiving packets */
rcviov[0].iov_base = (caddr_t) mld6_recv_buf;
rcviov[0].iov_len = RECV_BUF_SIZE;
rcvmh.msg_name = (caddr_t) & from;
rcvmh.msg_namelen = sizeof(from);
rcvmh.msg_iov = rcviov;
rcvmh.msg_iovlen = 1;
rcvmh.msg_control = (caddr_t) rcvcmsgbuf;
rcvmh.msg_controllen = sizeof(rcvcmsgbuf);
/* initialize msghdr for sending packets */
sndiov[0].iov_base = (caddr_t)mld6_send_buf;
sndmh.msg_namelen = sizeof(struct sockaddr_in6);
sndmh.msg_iov = sndiov;
sndmh.msg_iovlen = 1;
/* specifiy to insert router alert option in a hop-by-hop opt hdr. */
#ifndef USE_RFC2292BIS
raopt[0] = IP6OPT_ROUTER_ALERT;
raopt[1] = IP6OPT_RTALERT_LEN - 2;
memcpy(&raopt[2], (caddr_t) & rtalert_code, sizeof(u_short));
#endif
/* register MLD message handler */
if (register_input_handler(mld6_socket, mld6_read) < 0)
log(LOG_ERR, 0,
"Couldn't register mld6_read as an input handler");
}
/* Read an MLD message */
static void
mld6_read(i, rfd)
int i;
fd_set *rfd;
{
register int mld6_recvlen;
mld6_recvlen = recvmsg(mld6_socket, &rcvmh, 0);
if (mld6_recvlen < 0)
{
if (errno != EINTR)
log(LOG_ERR, errno, "MLD6 recvmsg");
return;
}
/* TODO: make it as a thread in the future releases */
accept_mld6(mld6_recvlen);
}
/*
* Process a newly received MLD6 packet that is sitting in the input packet
* buffer.
*/
static void
accept_mld6(recvlen)
int recvlen;
{
struct in6_addr *group, *dst = NULL;
struct mld6_hdr *mldh;
struct cmsghdr *cm;
struct in6_pktinfo *pi = NULL;
int *hlimp = NULL;
int ifindex = 0;
struct sockaddr_in6 *src = (struct sockaddr_in6 *) rcvmh.msg_name;
/*
* If control length is zero, it must be an upcall from the kernel
* multicast forwarding engine.
* XXX: can we trust it?
*/
if (rcvmh.msg_controllen == 0) {
/* XXX: msg_controllen must be reset in this case. */
rcvmh.msg_controllen = sizeof(rcvcmsgbuf);
process_kernel_call();
return;
}
if (recvlen < sizeof(struct mld6_hdr))
{
log(LOG_WARNING, 0,
"received packet too short (%u bytes) for MLD header",
recvlen);
return;
}
mldh = (struct mld6_hdr *) rcvmh.msg_iov[0].iov_base;
group = &mldh->mld6_addr;
/* extract optional information via Advanced API */
for (cm = (struct cmsghdr *) CMSG_FIRSTHDR(&rcvmh);
cm;
cm = (struct cmsghdr *) CMSG_NXTHDR(&rcvmh, cm))
{
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_PKTINFO &&
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
{
pi = (struct in6_pktinfo *) (CMSG_DATA(cm));
ifindex = pi->ipi6_ifindex;
dst = &pi->ipi6_addr;
}
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_HOPLIMIT &&
cm->cmsg_len == CMSG_LEN(sizeof(int)))
hlimp = (int *) CMSG_DATA(cm);
}
if (hlimp == NULL)
{
log(LOG_WARNING, 0,
"failed to get receiving hop limit");
return;
}
/* TODO: too noisy. Remove it? */
//#define NOSUCHDEF
#ifdef NOSUCHDEF
IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_ICMPV6, mldh->mld6_type,
mldh->mld6_code))
log(LOG_DEBUG, 0, "RECV %s from %s to %s",
packet_kind(IPPROTO_ICMPV6,
mldh->mld6_type, mldh->mld6_code),
inet6_fmt(&src->sin6_addr), inet6_fmt(dst));
#endif /* NOSUCHDEF */
/* for an mtrace message, we don't need strict checks */
if (mldh->mld6_type == MLD6_MTRACE) {
accept_mtrace(src, dst, group, ifindex, (char *)(mldh + 1),
mldh->mld6_code, recvlen - sizeof(struct mld6_hdr));
return;
}
/* hop limit check */
if (*hlimp != 1)
{
log(LOG_WARNING, 0,
"received an MLD6 message with illegal hop limit(%d) from %s",
*hlimp, inet6_fmt(&src->sin6_addr));
/* but accept the packet */
}
if (ifindex == 0)
{
log(LOG_WARNING, 0, "failed to get receiving interface");
return;
}
/* scope check */
if (IN6_IS_ADDR_MC_NODELOCAL(&mldh->mld6_addr))
{
log(LOG_INFO, 0,
"RECV %s with an invalid scope: %s from %s",
inet6_fmt(&mldh->mld6_addr),
inet6_fmt(&src->sin6_addr));
return; /* discard */
}
/* source address check */
if (!IN6_IS_ADDR_LINKLOCAL(&src->sin6_addr))
{
log(LOG_INFO, 0,
"RECV %s from a non link local address: %s",
packet_kind(IPPROTO_ICMPV6, mldh->mld6_type,
mldh->mld6_code),
inet6_fmt(&src->sin6_addr));
return;
}
switch (mldh->mld6_type)
{
case MLD6_LISTENER_QUERY:
accept_listener_query(src, dst, group,
ntohs(mldh->mld6_maxdelay));
return;
case MLD6_LISTENER_REPORT:
accept_listener_report(src, dst, group);
return;
case MLD6_LISTENER_DONE:
accept_listener_done(src, dst, group);
return;
default:
/* This must be impossible since we set a type filter */
log(LOG_INFO, 0,
"ignoring unknown ICMPV6 message type %x from %s to %s",
mldh->mld6_type, inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
return;
}
}
static void
make_mld6_msg(type, code, src, dst, group, ifindex, delay, datalen, alert)
int type, code, ifindex, delay, datalen, alert;
struct sockaddr_in6 *src, *dst;
struct in6_addr *group;
{
static struct sockaddr_in6 dst_sa = {sizeof(dst_sa), AF_INET6};
struct mld6_hdr *mhp = (struct mld6_hdr *)mld6_send_buf;
int ctllen, hbhlen = 0;
switch(type) {
case MLD6_MTRACE:
case MLD6_MTRACE_RESP:
sndmh.msg_name = (caddr_t)dst;
break;
default:
if (IN6_IS_ADDR_UNSPECIFIED(group))
dst_sa.sin6_addr = allnodes_group.sin6_addr;
else
dst_sa.sin6_addr = *group;
sndmh.msg_name = (caddr_t)&dst_sa;
datalen = sizeof(struct mld6_hdr);
break;
}
bzero(mhp, sizeof(*mhp));
mhp->mld6_type = type;
mhp->mld6_code = code;
mhp->mld6_maxdelay = htons(delay);
mhp->mld6_addr = *group;
sndiov[0].iov_len = datalen;
/* estimate total ancillary data length */
ctllen = 0;
if (ifindex != -1 || src)
ctllen += CMSG_SPACE(sizeof(struct in6_pktinfo));
if (alert) {
#ifdef USE_RFC2292BIS
if ((hbhlen = inet6_opt_init(NULL, 0)) == -1)
log(LOG_ERR, 0, "inet6_opt_init(0) failed");
if ((hbhlen = inet6_opt_append(NULL, 0, hbhlen, IP6OPT_ROUTER_ALERT, 2,
2, NULL)) == -1)
log(LOG_ERR, 0, "inet6_opt_append(0) failed");
if ((hbhlen = inet6_opt_finish(NULL, 0, hbhlen)) == -1)
log(LOG_ERR, 0, "inet6_opt_finish(0) failed");
#else /* old advanced API */
hbhlen = inet6_option_space(sizeof(raopt));
#endif
ctllen += CMSG_SPACE(hbhlen);
}
/* extend ancillary data space (if necessary) */
if (ctlbuflen < ctllen) {
if (sndcmsgbuf)
free(sndcmsgbuf);
if ((sndcmsgbuf = malloc(ctllen)) == NULL)
log(LOG_ERR, 0, "make_mld6_msg: malloc failed"); /* assert */
ctlbuflen = ctllen;
}
/* store ancillary data */
if ((sndmh.msg_controllen = ctllen) > 0) {
struct cmsghdr *cmsgp;
sndmh.msg_control = sndcmsgbuf;
cmsgp = CMSG_FIRSTHDR(&sndmh);
if (ifindex != -1 || src) {
struct in6_pktinfo *pktinfo;
cmsgp->cmsg_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_PKTINFO;
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
memset((caddr_t)pktinfo, 0, sizeof(*pktinfo));
if (ifindex != -1)
pktinfo->ipi6_ifindex = ifindex;
if (src)
pktinfo->ipi6_addr = src->sin6_addr;
cmsgp = CMSG_NXTHDR(&sndmh, cmsgp);
}
if (alert) {
#ifdef USE_RFC2292BIS
int currentlen;
void *hbhbuf, *optp = NULL;
cmsgp->cmsg_len = CMSG_SPACE(hbhlen);
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_HOPOPTS;
hbhbuf = CMSG_DATA(cmsgp);
if ((currentlen = inet6_opt_init(hbhbuf, hbhlen)) == -1)
log(LOG_ERR, 0, "inet6_opt_init(len = %d) failed",
hbhlen);
if ((currentlen = inet6_opt_append(hbhbuf, hbhlen,
currentlen,
IP6OPT_ROUTER_ALERT, 2,
2, &optp)) == -1)
log(LOG_ERR, 0,
"inet6_opt_append(len = %d) failed",
currentlen, hbhlen);
(void)inet6_opt_set_val(optp, 0, &rtalert_code,
sizeof(rtalert_code));
if (inet6_opt_finish(hbhbuf, hbhlen, currentlen) == -1)
log(LOG_ERR, 0, "inet6_opt_finish(buf) failed");
#else /* old advanced API */
if (inet6_option_init((void *)cmsgp, &cmsgp, IPV6_HOPOPTS))
log(LOG_ERR, 0, /* assert */
"make_mld6_msg: inet6_option_init failed");
if (inet6_option_append(cmsgp, raopt, 4, 0))
log(LOG_ERR, 0, /* assert */
"make_mld6_msg: inet6_option_append failed");
#endif
cmsgp = CMSG_NXTHDR(&sndmh, cmsgp);
}
}
else
sndmh.msg_control = NULL; /* clear for safety */
}
void
send_mld6(type, code, src, dst, group, index, delay, datalen, alert)
int type;
int code; /* for trace packets only */
struct sockaddr_in6 *src;
struct sockaddr_in6 *dst; /* may be NULL */
struct in6_addr *group;
int index, delay, alert;
int datalen; /* for trace packets only */
{
int setloop = 0;
struct sockaddr_in6 *dstp;
make_mld6_msg(type, code, src, dst, group, index, delay, datalen, alert);
dstp = (struct sockaddr_in6 *)sndmh.msg_name;
if (IN6_ARE_ADDR_EQUAL(&dstp->sin6_addr, &allnodes_group.sin6_addr)) {
setloop = 1;
k_set_loop(mld6_socket, TRUE);
}
if (sendmsg(mld6_socket, &sndmh, 0) < 0) {
if (errno == ENETDOWN)
check_vif_state();
else
log(log_level(IPPROTO_ICMPV6, type, 0), errno,
"sendmsg to %s with src %s on %s",
inet6_fmt(&dstp->sin6_addr),
src ? inet6_fmt(&src->sin6_addr) : "(unspec)",
ifindex2str(index));
if (setloop)
k_set_loop(mld6_socket, FALSE);
return;
}
IF_DEBUG(DEBUG_PKT|debug_kind(IPPROTO_IGMP, type, 0))
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
packet_kind(IPPROTO_ICMPV6, type, 0),
src ? inet6_fmt(&src->sin6_addr) : "unspec",
inet6_fmt(&dstp->sin6_addr));
}

45
usr.sbin/pim6dd/mld6.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/*
* Constans for Multicast Listener Discovery protocol for IPv6.
*/
#define MLD6_ROBUSTNESS_VARIABLE 2
#define MLD6_QUERY_INTERVAL 125 /* in seconds */
#define MLD6_QUERY_RESPONSE_INTERVAL 10000 /* in milliseconds */
#ifndef MLD6_TIMER_SCALE
#define MLD6_TIMER_SCALE 1000
#endif
#define MLD6_LISTENER_INTERVAL (MLD6_ROBUSTNESS_VARIABLE * \
MLD6_QUERY_INTERVAL + \
MLD6_QUERY_RESPONSE_INTERVAL / MLD6_TIMER_SCALE)
#define MLD6_LAST_LISTENER_QUERY_INTERVAL 1000 /* in milliseconds */
#define MLD6_LAST_LISTENER_QUERY_COUNT MLD6_ROBUSTNESS_VARIABLE

View File

@ -0,0 +1,532 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: mld6_proto.c,v 1.2 1999/09/12 17:00:09 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
extern struct in6_addr in6addr_any;
typedef struct {
mifi_t mifi;
struct listaddr *g;
int q_time;
} cbk_t;
/*
* Forward declarations.
*/
static void DelVif __P((void *arg));
static int SetTimer __P((int mifi, struct listaddr *g));
static int DeleteTimer __P((int id));
static void SendQuery __P((void *arg));
static int SetQueryTimer __P((struct listaddr *g, int mifi, int to_expire,
int q_time));
/*
* Send group membership queries on that interface if I am querier.
*/
void
query_groups(v)
register struct uvif *v;
{
register struct listaddr *g;
v->uv_gq_timer = MLD6_QUERY_INTERVAL;
if (v->uv_flags & VIFF_QUERIER && (v->uv_flags & VIFF_NOLISTENER) == 0)
send_mld6(MLD6_LISTENER_QUERY, 0, &v->uv_linklocal->pa_addr,
NULL, (struct in6_addr *)&in6addr_any,
v->uv_ifindex, MLD6_QUERY_RESPONSE_INTERVAL, 0, 1);
/*
* 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_listener_query(src, dst, group, tmo)
struct sockaddr_in6 *src;
struct in6_addr *dst, *group;
int tmo;
{
register int mifi;
register struct uvif *v;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
/* Ignore my own membership query */
if (local_address(src) != NO_VIF)
return;
if ((mifi = find_vif_direct(src)) == NO_VIF) {
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_query: can't find a mif");
return;
}
v = &uvifs[mifi];
if (v->uv_querier == NULL || inet6_equal(&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 (inet6_lessthan(src, (v->uv_querier ? &v->uv_querier->al_addr
: &v->uv_linklocal->pa_addr))) {
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0, "new querier %s (was %s) "
"on mif %d",
inet6_fmt(&src->sin6_addr),
v->uv_querier ?
inet6_fmt(&v->uv_querier->al_addr.sin6_addr) :
"me", mifi);
if (!v->uv_querier) {
v->uv_querier = (struct listaddr *)
malloc(sizeof(struct listaddr));
v->uv_querier->al_next = (struct listaddr *)NULL;
v->uv_querier->al_timer = 0;
v->uv_querier->al_genid = 0;
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 && inet6_equal(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 (!IN6_IS_ADDR_UNSPECIFIED(group) &&
inet6_equal(src, &v->uv_linklocal->pa_addr)) {
register struct listaddr *g;
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"%s for %s from %s on mif %d, timer %d",
"Group-specific membership query",
inet6_fmt(group),
inet6_fmt(&src->sin6_addr), mifi, tmo);
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (inet6_equal(&group_sa, &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 = MLD6_LAST_LISTENER_QUERY_COUNT *
tmo / MLD6_TIMER_SCALE;
/*
* use al_query to record our presence
* in last-member state
*/
g->al_query = -1;
g->al_timerid = SetTimer(mifi, g);
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"timer for grp %s on mif %d "
"set to %d",
inet6_fmt(group),
mifi, g->al_timer);
break;
}
}
}
}
/*
* Process an incoming group membership report.
*/
void
accept_listener_report(src, dst, group)
struct sockaddr_in6 *src;
struct in6_addr *dst, *group;
{
register mifi_t mifi;
register struct uvif *v;
register struct listaddr *g;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
if (IN6_IS_ADDR_MC_LINKLOCAL(group)) {
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accept_listener_report: group(%s) has the "
"link-local scope. discard", inet6_fmt(group));
return;
}
if ((mifi = find_vif_direct_local(src)) == NO_VIF) {
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_report: can't find a mif");
return;
}
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accepting multicast listener report: "
"src %s, dst% s, grp %s",
inet6_fmt(&src->sin6_addr), inet6_fmt(dst),
inet6_fmt(group));
v = &uvifs[mifi];
/*
* Look for the group in our group list; if found, reset its timer.
*/
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (inet6_equal(&group_sa, &g->al_addr)) {
g->al_reporter = *src;
/* delete old timers, set a timer for expiration */
g->al_timer = MLD6_LISTENER_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(mifi, g);
add_leaf(mifi, NULL, &group_sa);
break;
}
}
/*
* If not found, add it to the list and update kernel cache.
*/
if (g == NULL) {
g = (struct listaddr *)malloc(sizeof(struct listaddr));
if (g == NULL)
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
g->al_addr = group_sa;
g->al_old = 0;
/** set a timer for expiration **/
g->al_query = 0;
g->al_timer = MLD6_LISTENER_INTERVAL;
g->al_reporter = *src;
g->al_timerid = SetTimer(mifi, g);
g->al_next = v->uv_groups;
v->uv_groups = g;
time(&g->al_ctime);
add_leaf(mifi, NULL, &group_sa);
}
}
/* TODO: send PIM prune message if the last member? */
void
accept_listener_done(src, dst, group)
struct sockaddr_in6 *src;
struct in6_addr *dst, *group;
{
register mifi_t mifi;
register struct uvif *v;
register struct listaddr *g;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
if ((mifi = find_vif_direct_local(src)) == NO_VIF) {
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_done: can't find a mif");
return;
}
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accepting listener done message: src %s, dst% s, grp %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst), inet6_fmt(group));
v = &uvifs[mifi];
if (!(v->uv_flags & (VIFF_QUERIER | VIFF_DR)))
return;
/*
* Look for the group in our group list in order to set up a
* short-timeout query.
*/
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (inet6_equal(&group_sa, &g->al_addr)) {
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"[accept_done_message] %d %d \n",
g->al_old, g->al_query);
/*
* Ignore the done message if there are old
* hosts present
*/
if (g->al_old)
return;
/*
* still waiting for a reply to a query,
* ignore the done
*/
if (g->al_query)
return;
/** delete old timer set a timer for expiration **/
if (g->al_timerid)
g->al_timerid = DeleteTimer(g->al_timerid);
/** send a group specific querry **/
g->al_timer = (MLD6_LAST_LISTENER_QUERY_INTERVAL/MLD6_TIMER_SCALE) *
(MLD6_LAST_LISTENER_QUERY_COUNT + 1);
if (v->uv_flags & VIFF_QUERIER &&
(v->uv_flags & VIFF_NOLISTENER) == 0)
send_mld6(MLD6_LISTENER_QUERY, 0,
&v->uv_linklocal->pa_addr, NULL,
&g->al_addr.sin6_addr,
v->uv_ifindex,
MLD6_LAST_LISTENER_QUERY_INTERVAL, 0, 1);
g->al_query = SetQueryTimer(g, mifi,
MLD6_LAST_LISTENER_QUERY_INTERVAL/MLD6_TIMER_SCALE,
MLD6_LAST_LISTENER_QUERY_INTERVAL);
g->al_timerid = SetTimer(mifi, g);
break;
}
}
}
/*
* Time out record of a group membership on a vif
*/
static void
DelVif(arg)
void *arg;
{
cbk_t *cbk = (cbk_t *)arg;
mifi_t mifi = cbk->mifi;
struct uvif *v = &uvifs[mifi];
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(mifi, NULL, &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(mifi, g)
mifi_t mifi;
struct listaddr *g;
{
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->mifi = mifi;
cbk->g = g;
return timer_setTimer(g->al_timer, DelVif, cbk);
}
/*
* Delete a timer that was set above.
*/
static int
DeleteTimer(id)
int id;
{
timer_clearTimer(id);
return 0;
}
/*
* Send a group-specific query.
*/
static void
SendQuery(arg)
void *arg;
{
cbk_t *cbk = (cbk_t *)arg;
register struct uvif *v = &uvifs[cbk->mifi];
if (v->uv_flags & VIFF_QUERIER && (v->uv_flags & VIFF_NOLISTENER) == 0)
send_mld6(MLD6_LISTENER_QUERY, 0, &v->uv_linklocal->pa_addr,
NULL, &cbk->g->al_addr.sin6_addr,
v->uv_ifindex, cbk->q_time, 0, 1);
cbk->g->al_query = 0;
free(cbk);
}
/*
* Set a timer to send a group-specific query.
*/
static int
SetQueryTimer(g, mifi, to_expire, q_time)
struct listaddr *g;
mifi_t mifi;
int to_expire;
int q_time;
{
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->q_time = q_time;
cbk->mifi = mifi;
return timer_setTimer(to_expire, SendQuery, cbk);
}
/* Checks for MLD listener: returns TRUE if there is a receiver for the
* group on the given uvif, or returns FALSE otherwise.
*/
int
check_multicast_listener(v, group)
struct uvif *v;
struct sockaddr_in6 *group;
{
register struct listaddr *g;
/*
* Look for the group in our listener list;
*/
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (inet6_equal(group, &g->al_addr))
return TRUE;
}
return FALSE;
}

803
usr.sbin/pim6dd/mrt.c Normal file
View File

@ -0,0 +1,803 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: mrt.c,v 1.2 1999/08/24 10:04:56 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
srcentry_t *srclist;
grpentry_t *grplist;
/*
* Local functions definition
*/
static srcentry_t *create_srcentry __P((struct sockaddr_in6 *source));
static int search_srclist __P((struct sockaddr_in6 *source,
srcentry_t **sourceEntry));
static int search_srcmrtlink __P((srcentry_t *srcentry_ptr,
struct sockaddr_in6 *group,
mrtentry_t **mrtPtr));
static void insert_srcmrtlink __P((mrtentry_t *elementPtr,
mrtentry_t *insertPtr,
srcentry_t *srcListPtr));
static grpentry_t *create_grpentry __P((struct sockaddr_in6 *group));
static int search_grplist __P((struct sockaddr_in6 *group,
grpentry_t **groupEntry));
static int search_grpmrtlink __P((grpentry_t *grpentry_ptr,
struct sockaddr_in6 *source,
mrtentry_t **mrtPtr));
static void insert_grpmrtlink __P((mrtentry_t *elementPtr,
mrtentry_t *insertPtr,
grpentry_t *grpListPtr));
static mrtentry_t *alloc_mrtentry __P((srcentry_t *srcentry_ptr,
grpentry_t *grpentry_ptr));
static mrtentry_t *create_mrtentry __P((srcentry_t *srcentry_ptr,
grpentry_t *grpentry_ptr,
u_int16 flags));
void
init_pim6_mrt()
{
/* TODO: delete any existing routing table */
/* Initialize the source list */
/* The first entry has the unspecified address and is not used */
/* The order is the smallest address first. */
srclist = (srcentry_t *)malloc(sizeof(srcentry_t));
srclist->next = (srcentry_t *)NULL;
srclist->prev = (srcentry_t *)NULL;
memset(&srclist->address, 0, sizeof(struct sockaddr_in6));
srclist->address.sin6_len = sizeof(struct sockaddr_in6);
srclist->address.sin6_family = AF_INET6;
srclist->mrtlink = (mrtentry_t *)NULL;
srclist->incoming = NO_VIF;
srclist->upstream = (pim_nbr_entry_t *)NULL;
srclist->metric = 0;
srclist->preference = 0;
srclist->timer = 0;
/* Initialize the group list */
/* The first entry has the unspecified address and is not used */
/* The order is the smallest address first. */
grplist = (grpentry_t *)malloc(sizeof(grpentry_t));
grplist->next = (grpentry_t *)NULL;
grplist->prev = (grpentry_t *)NULL;
memset(&grplist->group, 0, sizeof(struct sockaddr_in6));
grplist->group.sin6_len = sizeof(struct sockaddr_in6);
grplist->group.sin6_family = AF_INET6;
grplist->mrtlink = (mrtentry_t *)NULL;
}
grpentry_t*
find_group(group)
struct sockaddr_in6 *group;
{
grpentry_t *grpentry_ptr;
if (!IN6_IS_ADDR_MULTICAST(&group->sin6_addr))
return (grpentry_t *)NULL;
if (search_grplist(group, &grpentry_ptr) == TRUE) {
/* Group found! */
return (grpentry_ptr);
}
return (grpentry_t *)NULL;
}
srcentry_t *
find_source(source)
struct sockaddr_in6 *source;
{
srcentry_t *srcentry_ptr;
if (!inet6_valid_host(source))
return (srcentry_t *)NULL;
if (search_srclist(source, &srcentry_ptr) == TRUE) {
/* Source found! */
return (srcentry_ptr);
}
return (srcentry_t *)NULL;
}
mrtentry_t *
find_route(source, group, flags, create)
struct sockaddr_in6 *source, *group;
u_int16 flags;
char create;
{
srcentry_t *srcentry_ptr;
grpentry_t *grpentry_ptr;
mrtentry_t *mrtentry_ptr;
if (!IN6_IS_ADDR_MULTICAST(&group->sin6_addr))
return (mrtentry_t *)NULL;
if (!inet6_valid_host(source))
return (mrtentry_t *)NULL;
if (create == DONT_CREATE) {
if (search_grplist(group, &grpentry_ptr) == FALSE)
return (mrtentry_t *)NULL;
/* Search for the source */
if (search_grpmrtlink(grpentry_ptr, source,
&mrtentry_ptr) == TRUE) {
/* Exact (S,G) entry found */
return (mrtentry_ptr);
}
return (mrtentry_t *)NULL;
}
/* Creation allowed */
grpentry_ptr = create_grpentry(group);
if (grpentry_ptr == (grpentry_t *)NULL) {
return (mrtentry_t *)NULL;
}
/* Setup the (S,G) routing entry */
srcentry_ptr = create_srcentry(source);
if (srcentry_ptr == (srcentry_t *)NULL) {
if (grpentry_ptr->mrtlink == (mrtentry_t *)NULL) {
/* New created grpentry. Delete it. */
delete_grpentry(grpentry_ptr);
}
return (mrtentry_t *)NULL;
}
mrtentry_ptr = create_mrtentry(srcentry_ptr, grpentry_ptr, MRTF_SG);
if (mrtentry_ptr == (mrtentry_t *)NULL) {
if (grpentry_ptr->mrtlink == (mrtentry_t *)NULL) {
/* New created grpentry. Delete it. */
delete_grpentry(grpentry_ptr);
}
if (srcentry_ptr->mrtlink == (mrtentry_t *)NULL) {
/* New created srcentry. Delete it. */
delete_srcentry(srcentry_ptr);
}
return (mrtentry_t *)NULL;
}
if (mrtentry_ptr->flags & MRTF_NEW) {
struct mrtfilter *f;
/* The mrtentry pref/metric should be the pref/metric of the
* _upstream_ assert winner. Since this isn't known now,
* set it to the config'ed default
*/
mrtentry_ptr->incoming = srcentry_ptr->incoming;
mrtentry_ptr->upstream = srcentry_ptr->upstream;
mrtentry_ptr->metric = srcentry_ptr->metric;
mrtentry_ptr->preference = srcentry_ptr->preference;
if ((f = search_filter(&group->sin6_addr)))
IF_COPY(&f->ifset, &mrtentry_ptr->filter_oifs);
}
return (mrtentry_ptr);
}
void
delete_srcentry(srcentry_ptr)
srcentry_t *srcentry_ptr;
{
mrtentry_t *mrtentry_ptr;
mrtentry_t *mrtentry_next;
if (srcentry_ptr == (srcentry_t *)NULL)
return;
/* TODO: XXX: the first entry is unused and always there */
srcentry_ptr->prev->next = srcentry_ptr->next;
if (srcentry_ptr->next != (srcentry_t *)NULL)
srcentry_ptr->next->prev = srcentry_ptr->prev;
for (mrtentry_ptr = srcentry_ptr->mrtlink;
mrtentry_ptr != (mrtentry_t *)NULL;
mrtentry_ptr = mrtentry_next) {
mrtentry_next = mrtentry_ptr->srcnext;
if (mrtentry_ptr->grpprev != (mrtentry_t *)NULL)
mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext;
else {
mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext;
if (mrtentry_ptr->grpnext == (mrtentry_t *)NULL) {
/* Delete the group entry */
delete_grpentry(mrtentry_ptr->group);
}
}
if (mrtentry_ptr->grpnext != (mrtentry_t *)NULL)
mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev;
FREE_MRTENTRY(mrtentry_ptr);
}
free((char *)srcentry_ptr);
}
void
delete_grpentry(grpentry_ptr)
grpentry_t *grpentry_ptr;
{
mrtentry_t *mrtentry_ptr;
mrtentry_t *mrtentry_next;
if (grpentry_ptr == (grpentry_t *)NULL)
return;
/* TODO: XXX: the first entry is unused and always there */
grpentry_ptr->prev->next = grpentry_ptr->next;
if (grpentry_ptr->next != (grpentry_t *)NULL)
grpentry_ptr->next->prev = grpentry_ptr->prev;
for (mrtentry_ptr = grpentry_ptr->mrtlink;
mrtentry_ptr != (mrtentry_t *)NULL;
mrtentry_ptr = mrtentry_next) {
mrtentry_next = mrtentry_ptr->grpnext;
if (mrtentry_ptr->srcprev != (mrtentry_t *)NULL)
mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext;
else {
mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext;
if (mrtentry_ptr->srcnext == (mrtentry_t *)NULL) {
/* Delete the srcentry if this was the last routing entry */
delete_srcentry(mrtentry_ptr->source);
}
}
if (mrtentry_ptr->srcnext != (mrtentry_t *)NULL)
mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev;
FREE_MRTENTRY(mrtentry_ptr);
}
free((char *)grpentry_ptr);
}
void
delete_mrtentry(mrtentry_ptr)
mrtentry_t *mrtentry_ptr;
{
if (mrtentry_ptr == (mrtentry_t *)NULL)
return;
/* Delete the kernel cache first */
k_del_mfc(mld6_socket, &mrtentry_ptr->source->address,
&mrtentry_ptr->group->group);
#ifdef RSRR
/* Tell the reservation daemon */
rsrr_cache_clean(mrtentry_ptr);
#endif /* RSRR */
/* (S,G) mrtentry */
/* Delete from the grpentry MRT chain */
if (mrtentry_ptr->grpprev != (mrtentry_t *)NULL)
mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext;
else {
mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext;
if (mrtentry_ptr->grpnext == (mrtentry_t *)NULL) {
/* Delete the group entry */
delete_grpentry(mrtentry_ptr->group);
}
}
if (mrtentry_ptr->grpnext != (mrtentry_t *)NULL)
mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev;
/* Delete from the srcentry MRT chain */
if (mrtentry_ptr->srcprev != (mrtentry_t *)NULL)
mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext;
else {
mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext;
if (mrtentry_ptr->srcnext == (mrtentry_t *)NULL) {
/* Delete the srcentry if this was the last routing entry */
delete_srcentry(mrtentry_ptr->source);
}
}
if (mrtentry_ptr->srcnext != (mrtentry_t *)NULL)
mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev;
FREE_MRTENTRY(mrtentry_ptr);
}
static int
search_srclist(source, sourceEntry)
struct sockaddr_in6 *source;
register srcentry_t **sourceEntry;
{
register srcentry_t *s_prev,*s;
for (s_prev = srclist, s = s_prev->next; s != (srcentry_t *)NULL;
s_prev = s, s = s->next) {
/* The srclist is ordered with the smallest addresses first.
* The first entry is not used.
*/
if (inet6_lessthan(&s->address, source))
continue;
if (inet6_equal(&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(group, groupEntry)
struct sockaddr_in6 *group;
register grpentry_t **groupEntry;
{
register grpentry_t *g_prev, *g;
for (g_prev = grplist, g = g_prev->next; g != (grpentry_t *)NULL;
g_prev = g, g = g->next) {
/* The grplist is ordered with the smallest address first.
* The first entry is not used.
*/
if (inet6_lessthan(&g->group, group))
continue;
if (inet6_equal(&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(source)
struct sockaddr_in6 *source;
{
register srcentry_t *srcentry_ptr;
srcentry_t *srcentry_prev;
if (search_srclist(source, &srcentry_prev) == TRUE)
return (srcentry_prev);
srcentry_ptr = (srcentry_t *)malloc(sizeof(srcentry_t));
if (srcentry_ptr == (srcentry_t *)NULL) {
log(LOG_WARNING, 0, "Memory allocation error for srcentry %s",
inet6_fmt(&source->sin6_addr));
return (srcentry_t *)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 (srcentry_t *)NULL;
}
srcentry_ptr->mrtlink = (mrtentry_t *)NULL;
srcentry_ptr->timer = 0;
srcentry_ptr->next = srcentry_prev->next;
srcentry_prev->next = srcentry_ptr;
srcentry_ptr->prev = srcentry_prev;
if (srcentry_ptr->next != (srcentry_t *)NULL)
srcentry_ptr->next->prev = srcentry_ptr;
IF_DEBUG(DEBUG_MFC)
log(LOG_DEBUG, 0, "create source entry, source %s",
inet6_fmt(&source->sin6_addr));
return (srcentry_ptr);
}
static grpentry_t *
create_grpentry(group)
struct sockaddr_in6 *group;
{
register grpentry_t *grpentry_ptr;
grpentry_t *grpentry_prev;
if (search_grplist(group, &grpentry_prev) == TRUE)
return (grpentry_prev);
grpentry_ptr = (grpentry_t *)malloc(sizeof(grpentry_t));
if (grpentry_ptr == (grpentry_t *)NULL) {
log(LOG_WARNING, 0, "Memory allocation error for grpentry %s",
inet6_fmt(&group->sin6_addr));
return (grpentry_t *)NULL;
}
grpentry_ptr->group = *group;
grpentry_ptr->mrtlink = (mrtentry_t *)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_t *)NULL)
grpentry_ptr->next->prev = grpentry_ptr;
IF_DEBUG(DEBUG_MFC)
log(LOG_DEBUG, 0, "create group entry, group %s",
inet6_fmt(&group->sin6_addr));
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 the previous entry
* (or NULL if first in the chain.
*/
static int
search_srcmrtlink(srcentry_ptr, group, mrtPtr)
srcentry_t *srcentry_ptr;
struct sockaddr_in6 *group;
mrtentry_t **mrtPtr;
{
register mrtentry_t *mrtentry_ptr;
register mrtentry_t *m_prev = (mrtentry_t *)NULL;
for(mrtentry_ptr = srcentry_ptr->mrtlink;
mrtentry_ptr != (mrtentry_t *)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 (inet6_lessthan(&mrtentry_ptr->group->group, group))
continue;
if (inet6_equal(&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 the previous entry
* (or NULL if first in the chain.
*/
static int
search_grpmrtlink(grpentry_ptr, source, mrtPtr)
grpentry_t *grpentry_ptr;
struct sockaddr_in6 *source;
mrtentry_t **mrtPtr;
{
register mrtentry_t *mrtentry_ptr;
register mrtentry_t *m_prev = (mrtentry_t *)NULL;
for (mrtentry_ptr = grpentry_ptr->mrtlink;
mrtentry_ptr != (mrtentry_t *)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 (inet6_lessthan(&mrtentry_ptr->source->address, source))
continue;
if (inet6_equal(source, &mrtentry_ptr->source->address)) {
*mrtPtr = mrtentry_ptr;
return(TRUE);
}
break;
}
*mrtPtr = m_prev;
return(FALSE);
}
static void
insert_srcmrtlink(mrtentry_new, mrtentry_prev, srcentry_ptr)
mrtentry_t *mrtentry_new;
mrtentry_t *mrtentry_prev;
srcentry_t *srcentry_ptr;
{
if (mrtentry_prev == (mrtentry_t *)NULL) {
/* Has to be insert as the head entry for this source */
mrtentry_new->srcnext = srcentry_ptr->mrtlink;
mrtentry_new->srcprev = (mrtentry_t *)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 != (mrtentry_t *)NULL)
mrtentry_new->srcnext->srcprev = mrtentry_new;
}
static void
insert_grpmrtlink(mrtentry_new, mrtentry_prev, grpentry_ptr)
mrtentry_t *mrtentry_new;
mrtentry_t *mrtentry_prev;
grpentry_t *grpentry_ptr;
{
if (mrtentry_prev == (mrtentry_t *)NULL) {
/* Has to be insert as the head entry for this group */
mrtentry_new->grpnext = grpentry_ptr->mrtlink;
mrtentry_new->grpprev = (mrtentry_t *)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 != (mrtentry_t *)NULL)
mrtentry_new->grpnext->grpprev = mrtentry_new;
}
static mrtentry_t *
alloc_mrtentry(srcentry_ptr, grpentry_ptr)
srcentry_t *srcentry_ptr;
grpentry_t *grpentry_ptr;
{
register mrtentry_t *mrtentry_ptr;
u_int16 i, *i_ptr;
u_long *il_ptr;
u_int8 vif_numbers;
mrtentry_ptr = (mrtentry_t *)malloc(sizeof(mrtentry_t));
if (mrtentry_ptr == (mrtentry_t *)NULL) {
log(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
return (mrtentry_t *)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;
IF_ZERO(&mrtentry_ptr->leaves);
IF_ZERO(&mrtentry_ptr->pruned_oifs);
IF_ZERO(&mrtentry_ptr->oifs);
IF_ZERO(&mrtentry_ptr->filter_oifs);
IF_ZERO(&mrtentry_ptr->asserted_oifs);
mrtentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
mrtentry_ptr->metric = 0;
mrtentry_ptr->preference = 0;
#ifdef RSRR
mrtentry_ptr->rsrr_cache = (struct 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->prune_timers = (u_int16 *)malloc(sizeof(u_int16) * numvifs);
mrtentry_ptr->prune_delay_timerids =
(u_long *)malloc(sizeof(u_long) * numvifs);
mrtentry_ptr->last_assert = (u_long *)malloc(sizeof(u_long) * numvifs);
mrtentry_ptr->last_prune = (u_long *)malloc(sizeof(u_long) * numvifs);
vif_numbers = numvifs;
#else
mrtentry_ptr->prune_timers =
(u_int16 *)malloc(sizeof(u_int16) * total_interfaces);
mrtentry_ptr->prune_delay_timerids =
(u_long *)malloc(sizeof(u_long) * total_interfaces);
mrtentry_ptr->last_assert =
(u_long *)malloc(sizeof(u_long) * total_interfaces);
mrtentry_ptr->last_prune =
(u_long *)malloc(sizeof(u_long) * total_interfaces);
vif_numbers = total_interfaces;
#endif /* SAVE_MEMORY */
if ((mrtentry_ptr->prune_timers == (u_int16 *)NULL) ||
(mrtentry_ptr->prune_delay_timerids == (u_long *)NULL) ||
(mrtentry_ptr->last_assert == (u_long *)NULL) ||
(mrtentry_ptr->last_prune == (u_long *)NULL)) {
log(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
FREE_MRTENTRY(mrtentry_ptr);
return (mrtentry_t *)NULL;
}
/* Reset the timers */
for (i = 0, i_ptr = mrtentry_ptr->prune_timers; i < vif_numbers;
i++, i_ptr++)
*i_ptr = 0;
for (i = 0, il_ptr = mrtentry_ptr->prune_delay_timerids; i < vif_numbers;
i++, il_ptr++)
*il_ptr = 0;
for (i = 0, il_ptr = mrtentry_ptr->last_assert; i < vif_numbers;
i++, il_ptr++)
*il_ptr = 0;
for (i = 0, il_ptr = mrtentry_ptr->last_prune; i < vif_numbers;
i++, il_ptr++)
*il_ptr = 0;
mrtentry_ptr->flags = MRTF_NEW;
mrtentry_ptr->timer = 0;
mrtentry_ptr->join_delay_timerid = 0;
mrtentry_ptr->assert_timer = 0;
mrtentry_ptr->graft = (pim_graft_entry_t *)NULL;
return(mrtentry_ptr);
}
static mrtentry_t *
create_mrtentry(srcentry_ptr, grpentry_ptr, flags)
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 */
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
/* (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!
*/
log(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n",
inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
/* not reached but to make lint happy */
return (mrtentry_t *)NULL;
}
/*
* Create and insert in group mrtlink and source mrtlink chains.
*/
r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr);
if (r_new == (mrtentry_t *)NULL)
return (mrtentry_t *)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);
}
/* ======================== */
/* filter related functions */
struct mrtfilter *filterlist;
/*
* Search for a filter entry in the filter list.
*/
struct mrtfilter *
search_filter(maddr)
struct in6_addr *maddr;
{
struct mrtfilter *f;
struct sockaddr_in6 msa6;
for (f = filterlist; f; f = f->next) {
switch(f->type) {
case FILTER_RANGE:
msa6.sin6_scope_id = 0; /* XXX: scope consideration */
msa6.sin6_addr = *maddr;
if (inet6_greateroreq(&msa6, &f->mrtf_from) &&
inet6_lessoreq(&msa6, &f->mrtf_to))
return(f);
break;
case FILTER_PREFIX:
msa6.sin6_scope_id = 0; /* XXX: scope consideration */
if (inet6_match_prefix(&msa6, &f->mrtf_prefix,
&f->mrtf_mask))
return(f);
break;
}
}
return(NULL);
}
/*
* Make a new filter entry.
* This function assumes
*/
struct mrtfilter *
add_filter(type, maddr1, maddr2, plen)
struct in6_addr *maddr1, *maddr2;
int type, plen;
{
struct mrtfilter *f;
struct sockaddr_in6 from, to;
if ((f = malloc(sizeof(*f))) == NULL)
log(LOG_ERR, 0, "add_filter: malloc failed"); /* assert */
memset((void *)f, 0, sizeof(*f));
f->type = type;
switch(type) {
case FILTER_RANGE:
memset((void *)&from, 0, sizeof(from));
memset((void *)&to, 0, sizeof(to));
from.sin6_addr = *maddr1;
to.sin6_addr = *maddr2;
if (inet6_lessthan(&from, &to)) {
f->mrtf_from = from;
f->mrtf_to = to;
}
else {
f->mrtf_from = to;
f->mrtf_to = from;
}
break;
case FILTER_PREFIX:
f->mrtf_prefix.sin6_addr = *maddr1;
MASKLEN_TO_MASK6(plen, f->mrtf_mask);
break;
}
f->next = filterlist;
filterlist = f;
return(f);
}

228
usr.sbin/pim6dd/mrt.h Normal file
View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: mrt.h,v 1.2 1999/08/24 10:04:56 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#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) */
/* Macro to duplicate oif info (oif bits, timers): XXX: unused */
#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); \
bcopy((from)->prune_timers, (to)->prune_timers, \
numvifs*sizeof((from)->prune_timers[0])); \
bcopy((from)->prune_delay_timerids, \
(to)->prune_delay_timerids, \
numvifs*sizeof((from)->prune_delay_timerids[0])); \
(to)->join_delay_timerid = (from)->join_delay_timerid; \
} while (0)
#ifdef SAVE_MEMORY
#define FREE_MRTENTRY(mrtentry_ptr) \
do { \
u_int16 i; \
u_long *il_ptr; \
free((char *)((mrtentry_ptr)->prune_timers)); \
for(i=0, il_ptr=(mrtentry_ptr)->prune_delay_timerids; \
i<numvifs; i++, il_ptr++) \
timer_clearTimer(*il_ptr); \
free((char *)((mrtentry_ptr)->prune_delay_timerids)); \
timer_clearTimer((mrtentry_ptr)->join_delay_timerid); \
delete_pim6_graft_entry((mrtentry_ptr)); \
free((char *)(mrtentry_ptr)); \
} while (0)
#else
#define FREE_MRTENTRY(mrtentry_ptr) \
do { \
u_int16 i; \
u_long *il_ptr; \
free((char *)((mrtentry_ptr)->prune_timers)); \
for(i=0, il_ptr=(mrtentry_ptr)->prune_delay_timerids; \
i<total_interfaces; i++, il_ptr++) \
timer_clearTimer(*il_ptr); \
free((char *)((mrtentry_ptr)->prune_delay_timerids)); \
free((char *)((mrtentry_ptr)->last_assert)); \
free((char *)((mrtentry_ptr)->last_prune)); \
timer_clearTimer((mrtentry_ptr)->join_delay_timerid); \
delete_pim6_graft_entry((mrtentry_ptr)); \
free((char *)(mrtentry_ptr)); \
} while (0)
#endif /* SAVE_MEMORY */
typedef struct pim_nbr_entry {
struct pim_nbr_entry *next; /* link to next neighbor */
struct pim_nbr_entry *prev; /* link to prev neighbor */
struct sockaddr_in6 address; /* neighbor address */
vifi_t vifi; /* which interface */
u_int16 timer; /* for timing out neighbor */
} pim_nbr_entry_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) */
};
typedef struct mrtentry mrtentry_t;
typedef struct pim_graft_entry {
struct pim_graft_entry *next;
struct pim_graft_entry *prev;
mrtentry_t *mrtlink;
} pim_graft_entry_t;
typedef struct srcentry {
struct srcentry *next; /* link to next entry */
struct srcentry *prev; /* link to prev entry */
struct sockaddr_in6 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? */
} srcentry_t;
typedef struct grpentry {
struct grpentry *next; /* link to next entry */
struct grpentry *prev; /* link to prev entry */
struct sockaddr_in6 group; /* subnet group of multicasts */
struct mrtentry *mrtlink; /* link to (S,G) routing entries */
} grpentry_t;
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) */
if_set oifs; /* The current result oifs */
if_set pruned_oifs; /* The pruned oifs (Prune received) */
if_set asserted_oifs; /* The asserted oifs (Lost Assert) */
if_set filter_oifs; /* The filtered oifs */
if_set 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; /* Metric for the upstream */
u_int32 preference; /* preference for the upstream */
u_int16 *prune_timers; /* prune timer list */
u_long *prune_delay_timerids; /* timers for LAN prunes */
u_long join_delay_timerid; /* timer for delay joins */
u_int16 flags; /* The MRTF_* flags */
u_int16 timer; /* entry timer */
u_int assert_timer;
struct sg_count sg_count;
u_long *last_assert; /* time for last data-driven assert */
u_long *last_prune; /* time for last data-driven prune */
pim_graft_entry_t *graft; /* Pointer into graft entry list */
#ifdef RSRR
struct rsrr_cache *rsrr_cache; /* Used to save RSRR requests for
* routes change notification.
*/
#endif /* RSRR */
};
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 */
};
#define FILTER_RANGE 0
#define FILTER_PREFIX 1
struct mrtfilter {
struct mrtfilter *next; /* link to the next entry */
int type; /* filter type: RANGE or PREFIX */
union { /* type specific data structure */
struct {
struct sockaddr_in6 from;
struct sockaddr_in6 to;
} mrtfu_range;
struct {
struct sockaddr_in6 prefix;
struct in6_addr mask;
} mrtfu_prefix;
} mrtu;
if_set ifset; /* interface list */
};
#define mrtf_from mrtu.mrtfu_range.from
#define mrtf_to mrtu.mrtfu_range.to
#define mrtf_prefix mrtu.mrtfu_prefix.prefix
#define mrtf_mask mrtu.mrtfu_prefix.mask

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: pathnames.h,v 1.2 1999/12/16 05:36:37 jinmei 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.
*
* $FreeBSD$
*/
#define _PATH_PIM6D_CONF "/usr/local/v6/etc/pim6dd.conf"
#if (defined(BSD) && (BSD >= 199103))
#define _PATH_PIM6D_PID "/var/run/pim6dd.pid"
#define _PATH_PIM6D_GENID "/var/run/pim6dd.genid"
#define _PATH_PIM6D_DUMP "/var/run/pim6dd.dump"
#define _PATH_PIM6D_CACHE "/var/run/pim6dd.cache"
#else
#define _PATH_PIM6D_PID "/etc/pim6dd.pid"
#define _PATH_PIM6D_GENID "/etc/pim6dd.genid"
#define _PATH_PIM6D_DUMP "/etc/pim6dd.dump"
#define _PATH_PIM6D_CACHE "/etc/pim6dd.cache"
#endif

436
usr.sbin/pim6dd/pim6.c Normal file
View File

@ -0,0 +1,436 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: pim6.c,v 1.3 1999/10/26 08:39:19 itojun Exp $
* $FreeBSD$
*/
#include "defs.h"
#include <sys/uio.h>
/*
* Exported variables.
*/
char *pim6_recv_buf; /* input packet buffer */
char *pim6_send_buf; /* output packet buffer */
struct sockaddr_in6 allpim6routers_group; /* ALL_PIM_ROUTERS group */
int pim6_socket; /* socket for PIM control msgs */
/*
* Local variables.
*/
static struct sockaddr_in6 from;
static struct msghdr sndmh;
static struct iovec sndiov[2];
static struct in6_pktinfo *sndpktinfo;
/*
* Local function definitions.
*/
static void pim6_read __P((int f, fd_set *rfd));
static void accept_pim6 __P((int recvlen));
static int pim6_cksum __P((u_short *, struct in6_addr *,
struct in6_addr *, int));
void
init_pim6()
{
static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
struct cmsghdr *cmsgp = (struct cmsghdr *)sndcmsgbuf;
if ((pim6_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_PIM)) < 0)
log(LOG_ERR, errno, "PIM6 socket");
k_set_rcvbuf(pim6_socket, SO_RECV_BUF_SIZE_MAX,
SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
k_set_hlim(pim6_socket, MINHLIM); /* restrict multicasts to one hop */
k_set_loop(pim6_socket, FALSE); /* disable multicast loopback */
allpim6routers_group.sin6_len = sizeof(allpim6routers_group);
allpim6routers_group.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, "ff02::d",
(void *)&allpim6routers_group.sin6_addr) != 1)
log(LOG_ERR, 0, "inet_pton failed for ff02::d");
if ((pim6_recv_buf = malloc(RECV_BUF_SIZE)) == NULL ||
(pim6_send_buf = malloc(RECV_BUF_SIZE)) == NULL) {
log(LOG_ERR, 0, "init_pim6: malloc failed\n");
}
/* initialize msghdr for sending packets */
sndmh.msg_namelen = sizeof(struct sockaddr_in6);
sndmh.msg_iov = sndiov;
sndmh.msg_iovlen = 1;
sndmh.msg_control = (caddr_t)sndcmsgbuf;
sndmh.msg_controllen = sizeof(sndcmsgbuf);
/* initilization cmsg for specifing outgoing interfaces and source */
sndpktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
cmsgp->cmsg_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_PKTINFO;
if (register_input_handler(pim6_socket, pim6_read) < 0)
log(LOG_ERR, 0,
"cannot register pim6_read() as an input handler");
IF_ZERO(&nbr_mifs);
}
/* Read a PIM message */
static void
pim6_read(f, rfd)
int f;
fd_set *rfd;
{
register int pim6_recvlen;
int fromlen = sizeof(from);
#ifdef SYSV
sigset_t block, oblock;
#else
register int omask;
#endif
pim6_recvlen = recvfrom(pim6_socket, pim6_recv_buf, RECV_BUF_SIZE,
0, (struct sockaddr *)&from, &fromlen);
if (pim6_recvlen < 0) {
if (errno != EINTR)
log(LOG_ERR, errno, "PIM6 recvmsg");
return;
}
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
/* Use of omask taken from main() */
omask = sigblock(sigmask(SIGALRM));
#endif /* SYSV */
accept_pim6(pim6_recvlen);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif /* SYSV */
}
static void
accept_pim6(pimlen)
int pimlen;
{
register struct pim *pim;
struct sockaddr_in6 *src = &from;
/* sanity check */
if (pimlen < sizeof(pim)) {
log(LOG_WARNING, 0,
"data field too short (%u bytes) for PIM header, from %s",
pimlen, inet6_fmt(&src->sin6_addr));
return;
}
pim = (struct pim *)pim6_recv_buf;
#ifdef NOSUCHDEF /* TODO: delete. Too noisy */
IF_DEBUG(DEBUG_PIM_DETAIL) {
IF_DEBUG(DEBUG_PIM) {
log(LOG_DEBUG, 0, "Receiving %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
log(LOG_DEBUG, 0, "PIM type is %u", pim->pim_type);
}
}
#endif /* NOSUCHDEF */
/* Check of PIM version is already done in the kernel */
/*
* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address)
* is it necessary?
*/
/* Checksum verification is done in the kernel. */
switch (pim->pim_type) {
case PIM_HELLO:
receive_pim6_hello(src, (char *)(pim), pimlen);
break;
case PIM_REGISTER:
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
case PIM_REGISTER_STOP:
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
case PIM_JOIN_PRUNE:
receive_pim6_join_prune(src, (char *)(pim), pimlen);
break;
case PIM_BOOTSTRAP:
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
case PIM_ASSERT:
receive_pim6_assert(src, (char *)(pim), pimlen);
break;
case PIM_GRAFT:
case PIM_GRAFT_ACK:
receive_pim6_graft(src, (char *)(pim), pimlen, pim->pim_type);
break;
case PIM_CAND_RP_ADV:
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
default:
log(LOG_INFO, 0,
"ignore unknown PIM message code %u from %s",
pim->pim_type,
inet6_fmt(&src->sin6_addr));
break;
}
}
/*
* Send a multicast PIM packet from src to dst, PIM message type = "type"
* and data length (after the PIM header) = "datalen"
*/
void
send_pim6(buf, src, dst, type, datalen)
char *buf;
struct sockaddr_in6 *src, *dst;
int type, datalen;
{
struct pim *pim;
int setloop = 0;
int ifindex = 0, sendlen = sizeof(struct pim) + datalen;
/* Prepare the PIM packet */
pim = (struct pim *)buf;
pim->pim_type = type;
pim->pim_ver = PIM_PROTOCOL_VERSION;
pim->pim_rsv = 0;
pim->pim_cksum = 0;
/*
* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the
* encapsulated packet from the checksum.
*/
pim->pim_cksum = pim6_cksum((u_int16 *)pim,
&src->sin6_addr, &dst->sin6_addr,
sendlen);
/*
* Specify the source address of the packet. Also, specify the
* outgoing interface and the source address if possible.
*/
memcpy(&sndpktinfo->ipi6_addr, &src->sin6_addr,
sizeof(src->sin6_addr));
if ((ifindex = src->sin6_scope_id) != 0) {
sndpktinfo->ipi6_ifindex = ifindex;
}
else {
sndpktinfo->ipi6_ifindex = 0; /* make sure to be cleared */
log(LOG_WARNING, 0,
"send_pim6: could not determine the outgoint IF; send anyway");
}
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) {
k_set_if(pim6_socket, ifindex);
if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allnodes_group.sin6_addr) ||
IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allrouters_group.sin6_addr) ||
IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allpim6routers_group.sin6_addr)) {
setloop = 1;
k_set_loop(pim6_socket, TRUE);
}
}
sndmh.msg_name = (caddr_t)dst;
sndiov[0].iov_base = (caddr_t)buf;
sndiov[0].iov_len = sendlen;
if (sendmsg(pim6_socket, &sndmh, 0) < 0) {
if (errno == ENETDOWN)
check_vif_state();
else
log(LOG_WARNING, errno, "sendto from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(&dst->sin6_addr));
if (setloop)
k_set_loop(pim6_socket, FALSE);
return;
}
if (setloop)
k_set_loop(pim6_socket, FALSE);
IF_DEBUG(DEBUG_PIM_DETAIL) {
IF_DEBUG(DEBUG_PIM) {
char ifname[IFNAMSIZ];
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s on %s",
packet_kind(IPPROTO_PIM, type, 0),
inet6_fmt(&src->sin6_addr),
inet6_fmt(&dst->sin6_addr),
ifindex ? if_indextoname(ifindex, ifname) : "?");
}
}
}
u_int pim_send_cnt = 0;
#define SEND_DEBUG_NUMBER 50
/* ============================== */
/*
* Checksum routine for Internet Protocol family headers (Portable Version).
*
* This routine is very heavily used in the network
* code and should be modified for each CPU to be as fast as possible.
*/
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
static union {
u_short phs[4];
struct {
u_long ph_len;
u_char ph_zero[3];
u_char ph_nxt;
} ph;
} uph;
/*
* 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.
*/
static int
pim6_cksum(addr, src, dst, len)
u_short *addr;
struct in6_addr *src, *dst;
int len;
{
register int nleft = len;
register u_short *w;
register int sum = 0;
u_short answer = 0;
/*
* First create IP6 pseudo header and calculate a summary.
*/
w = (u_short *)src;
uph.ph.ph_len = htonl(len);
uph.ph.ph_nxt = IPPROTO_PIM;
/* IPv6 source address */
sum += w[0];
/* XXX: necessary? */
if (!(IN6_IS_ADDR_LINKLOCAL(src) || IN6_IS_ADDR_MC_LINKLOCAL(src)))
sum += w[1];
sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
sum += w[6]; sum += w[7];
/* IPv6 destination address */
w = (u_short *)dst;
sum += w[0];
/* XXX: necessary? */
if (!(IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst)))
sum += w[1];
sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
sum += w[6]; sum += w[7];
/* Payload length and upper layer identifier */
sum += uph.phs[0]; sum += uph.phs[1];
sum += uph.phs[2]; sum += uph.phs[3];
/*
* Secondly calculate a summary of the first mbuf excluding offset.
*/
w = addr;
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);
}

1598
usr.sbin/pim6dd/pim6_proto.c Normal file

File diff suppressed because it is too large Load Diff

112
usr.sbin/pim6dd/pim6dd.8 Normal file
View File

@ -0,0 +1,112 @@
.\" Copyright (C) 1998 WIDE Project.
.\" 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: pim6dd.8,v 1.3 1999/08/13 09:20:43 jinmei Exp $
.\" $FreeBSD$
.\"
.Dd Nov 17, 1998
.Dt PIM6DD 8
.Os KAME
.Sh NAME
.Nm pim6dd
.Nd PIM for IPv6 dense mode daemon
.Sh SYNOPSIS
.Nm
.Op Fl c Ar configfile
.Op Fl d Op debug_level Op ,debug_level
.Sh DESCRIPTION
.Nm Pim6dd
is an IPv6 multicast routing daemon, which supports
PIMv2(Protocol Independent Multicast Version 2) dense mode
for IPv6.
.Pp
Options supported by
.Nm pim6dd :
.Bl -tag -width Ds
.It Fl c Ar configfile
Specify alternate location,
.Ar configfile ,
for configuration file.
By default,
.Pa /usr/local/v6/etc/pim6dd.conf
is used.
.It Fl d
Specify debug levels. If this option is specified without any arguments,
all debug messages will be printed out.
A subset of the messages to be printed out can be specified
as arguments of the option.
Valid debug levels are
.Ic timeout, packets, interfaces, kernel, mfc, pim_detail, pim_hello,
.Ic kernel, mfc, pim_detail, pim_hello, pim_jp, pim_graft, pim_asserts,
.Ic pim_routes, pim_timers, rpf, pim, routes, routers, timers,
and
.Ic asserts.
.El
.Pp
.Nm Pim6dd
automatically configures itself to forward on all multicast-capable
interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
the "loopback interface").
To override the default configuration,
configuration commands may be placed in
.Pa /usr/local/v6/etc/pim6dd.conf
(or an alternative file, specified by the "\-c" option).
.\"
.Sh FILES
.Bl -tag -width /usr/local/v6/etc/pim6dd.conf -compact
.It Pa /usr/local/v6/etc/pim6dd.conf
The default configuration file.
.El
.Sh SEE ALSO
.Xr daemon 3 ,
.Xr pim6dd.conf 5
.Sh HISTORY
The
.Nm
command is based on
.Nm pimdd,
which is an IPv4 multicast routing daemon
developed at the University of Oregon.
.Nm Pimdd
has been derived from PIM sparse-mode
.Nm pimd
developed at University of Southern California.
Part of these two programs above has also been derived from
.Nm mrouted.
.Nm Mrouted
is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.
.\"
.Sh BUGS
.Nm Pim6dd
does not contain any unicast routing engine, so a unicast routing
daemon needs to run on the system.
.Pp
The kernel unicast routing table is periodically polled by
.Nm
in order to follow changes of existing unicast routes.
.\"

View File

@ -0,0 +1,157 @@
.\" Copyright (C) 1998 WIDE Project.
.\" 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: pim6dd.conf.5,v 1.2 1999/12/10 06:08:49 itojun Exp $
.\" $FreeBSD$
.\"
.Dd Nov 17, 1998
.Dt PIM6DD.CONF 5
.Os KAME
.Sh NAME
.Nm pim6dd.conf
.Nd "config file for pim6dd, PIM for IPv6 dense mode daemon"
.\"
.Sh DESCRIPTION
The file describes how the
.Nm pim6dd
daemon treats each interface on the system.
By default(including the case where there is no configuration file),
PIM will be activated on all interfaces, which can be overridden
by the file.
Lines beginning with
.Ql #
are comments.
.Pp
There are four types of configuration commands:
.Bl -tag -width Ds -compact
.It Xo
.Ic default_source_preference Ar preference
.Xc
Specifies a default preference value when sending a PIM assert message.
Preferences are used by assert elections to determine upstream routers.
Currently
.Nm
cannot reliably obtain preferences and metrics from the
unicast routing protocols, so a default value may be configured.
.\"
.It Ic default_source_metric Ar metric
Specifies a default metric value when sending a PIM assert message.
It is recommended that preferences be set such that metrics are never
consulted. However, default metrics may also be set and will default to
1024.
.\"
.It Xo
.Ic phyint Ar interface
.Op disable
.Xc
Specifies
.Nm
to ignore the interface even if the interface is multicast-capable.
Interfaces are specified in the form of "name unit", such as
.Ar gif0
and
.Ar ep1.
.\"
.It Xo
.Ic phyint Ar interface
.Op preference Ar preference
.Op metric Ar metric
.Xc
Specifies the preference and/or metric values when sending a PIM
assert message on the interface.
.\"
.It Xo
.Ic filter Ar groupaddrs Ar interfaces...
.Xc
Specifies an output filter. If an incoming multicast packet's destination
matches the specified
.Ar groupaddrs,
the packet is not sent on the
.Ar interfaces.
Moreover, if there is no other interface than the specified
interfaces,
.Nm pim6dd
sends a prune message to the upstream neighbor.
Valid formats of
.Ar groupaddrs
are as follows.
.Bl -tag -width Ds -compact
.It Ar multicastaddr1-multicastaddr2
specifies a numerical range of a scope.
Multicast addresses
from
.Ar multicastaddr1
to
.Ar multicastaddr2
will be filtered out.
Note that neither a white space nor a tab character must not be
inserted before nor after
.Ql - .
.It Ar multicastaddr/prefixlen
specifies a group prefix of a scope.
Multicast addresses which match the specified prefix will be filtered
out.
If
.Ar prefixlen
is omitted, it means the exact match for
.Ar multicastaddr.
.El
.Ar interfaces
are specified as a blank separated list of interfaces. Each interface is
specified in the form of "name unit".
.El
.\"
.Sh EXAMPLE
.Bd -literal -offset
#phyint gif0 disable
#phyint ep0 preference 101
phyint de0 disable
filter ff15::4000/120 gif1 gif2
filter ff18::1000-ff18::1050 gif3
.Ed
.Sh SEE ALSO
.Xr pim6dd 8
.Sh HISTORY
The
.Nm pim6dd
command and the configuration file
.Nm
are based on
.Nm pimdd,
which is an IPv4 multicast routing daemon
developed at the University of Oregon.
.Nm Pimdd
has been derived from PIM sparse-mode
.Nm pimd
developed at University of Southern California.
Part of these two programs above has also been derived from
.Nm mrouted.
.Nm Mrouted
is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.
.\" .Sh BUGS
.\" (to be written)

553
usr.sbin/pim6dd/pimdd.h Normal file
View File

@ -0,0 +1,553 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: pimdd.h,v 1.1.1.1 1999/08/08 23:30:53 itojun Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include <netinet6/pim6.h>
#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 */
/* PIM protocol timers (in seconds) */
#ifndef TIMER_INTERVAL
#define TIMER_INTERVAL 5 /* virtual timer granularity */
#endif /* TIMER_INTERVAL */
#define PIM_DATA_TIMEOUT 210
#define PIM_TIMER_HELLO_PERIOD 30
#define PIM_JOIN_PRUNE_HOLDTIME 210
#define PIM_RANDOM_DELAY_JOIN_TIMEOUT 3
#define PIM_GRAFT_RETRANS_PERIOD 3
#define PIM_TIMER_HELLO_HOLDTIME (3.5 * PIM_TIMER_HELLO_PERIOD)
#define PIM_ASSERT_TIMEOUT 210
/* Misc definitions */
#define SINGLE_SRC_MSKLEN 32 /* the single source mask length */
#define SINGLE_GRP_MSKLEN 32 /* the single group mask length */
#define SINGLE_SRC_MSK6LEN 128 /* the single source mask length for IPv6*/
#define SINGLE_GRP_MSK6LEN 128 /* the single group mask length for IPv6*/
/* TODO: change? */
#define PIM_GROUP_PREFIX_DEFAULT_MASKLEN 16 /* The default group masklen if
* omitted in the config file.
*/
#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_LOCAL_PREF 101 /* Default assert preference */
#define DEFAULT_LOCAL_METRIC 1024 /* Default assert metric */
/**************************************************************************
* 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
#define ADDRT_IPv6 0
#if 0 /* XXX: the definition is for IPv4 only */
/* 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;
#endif
/* Encoded-Unicast: 18 bytes long */
typedef struct pim6_encod_uni_addr_ {
u_int8 addr_family;
u_int8 encod_type;
struct in6_addr unicast_addr; /* XXX: Note the 32-bit boundary
* misalignment for the unicast
* address when placed in the
* memory. Must read it byte-by-byte!
*/
} pim6_encod_uni_addr_t;
#if 0 /* XXX: the definition is for IPv4 only */
/* 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;
#endif
/* Encoded-Group */
typedef struct pim6_encod_grp_addr_ {
u_int8 addr_family;
u_int8 encod_type;
u_int8 reserved;
u_int8 masklen;
struct in6_addr mcast_addr;
} pim6_encod_grp_addr_t;
#if 0 /* XXX: the definition is for IPv4 only */
/* 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;
#endif
/* Encoded-Source */
typedef struct pim6_encod_src_addr_ {
u_int8 addr_family;
u_int8 encod_type;
u_int8 flags;
u_int8 masklen;
struct in6_addr src_addr;
} pim6_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;
#if 0
/* 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;
#endif
#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 */
#define PIM_HELLO 0
#ifndef PIM_REGISTER
#define PIM_REGISTER 1
#endif
#define PIM_REGISTER_STOP 2
#define PIM_JOIN_PRUNE 3
#define PIM_BOOTSTRAP 4
#define PIM_ASSERT 5
#define PIM_GRAFT 6
#define PIM_GRAFT_ACK 7
#define PIM_CAND_RP_ADV 8
#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
#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)
#define MASKLEN_TO_MASK6(masklen, mask6) \
do {\
u_char maskarray[8] = \
{0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; \
int bytelen, bitlen, i; \
memset(&(mask6), 0, sizeof(mask6));\
bytelen = (masklen) / 8;\
bitlen = (masklen) % 8;\
for (i = 0; i < bytelen; i++) \
(mask6).s6_addr[i] = 0xff;\
if (bitlen) \
(mask6).s6_addr[bytelen] = maskarray[bitlen - 1]; \
}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.
*/
/* 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 GET_ESADDR6(esa, cp) /* XXX: hard coding */ \
do { \
(esa)->addr_family = *(cp)++; \
(esa)->encod_type = *(cp)++; \
(esa)->flags = *(cp)++; \
(esa)->masklen = *(cp)++; \
memcpy(&(esa)->src_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} 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 PUT_ESADDR6(addr, masklen, flags, cp) \
do { \
int i; \
struct in6_addr maskaddr; \
MASKLEN_TO_MASK6(masklen, maskaddr); \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
*(cp)++ = (flags); /* flags */ \
*(cp)++ = (masklen); \
for (i = 0; i < sizeof(struct in6_addr); i++, (cp)++) \
*(cp) = maskaddr.s6_addr[i] & (addr).s6_addr[i]; \
} 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 GET_EGADDR6(ega, cp) /* XXX: hard coding */ \
do { \
(ega)->addr_family = *(cp)++; \
(ega)->encod_type = *(cp)++; \
(ega)->reserved = *(cp)++; \
(ega)->masklen = *(cp)++; \
memcpy(&(ega)->mcast_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} 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 PUT_EGADDR6(addr, masklen, reserved, cp) \
do { \
int i; \
struct in6_addr maskaddr; \
MASKLEN_TO_MASK6(masklen, maskaddr); \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
*(cp)++ = (reserved); /* reserved; should be 0 */ \
*(cp)++ = (masklen); \
for (i = 0; i < sizeof(struct in6_addr); i++, (cp)++) \
*(cp) = maskaddr.s6_addr[i] & (addr).s6_addr[i]; \
} 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 GET_EUADDR6(eua, cp) /* XXX hard conding */ \
do { \
(eua)->addr_family = *(cp)++; \
(eua)->encod_type = *(cp)++; \
memcpy(&(eua)->unicast_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
#define PUT_EUADDR(addr, cp) \
do { \
*(cp)++ = ADDRF_IPv4; /* family */ \
*(cp)++ = ADDRT_IPv4; /* type */ \
PUT_NETLONG((addr), (cp)); \
} while(0)
#define PUT_EUADDR6(addr, cp) \
do { \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
memcpy((cp), &(addr), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
/* TODO: Currently not used. Probably not need at all. Delete! */
#ifdef NOSUCHDEF
/* This is completely IGMP related stuff? */
#define PIM_LEAF_TIMEOUT (3.5 * IGMP_QUERY_INTERVAL)
#endif /* NOSUCHDEF */
#if defined(__bsdi__) || defined(__NetBSD__)
/*
* 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

659
usr.sbin/pim6dd/route.c Normal file
View File

@ -0,0 +1,659 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: route.c,v 1.3 1999/10/27 11:40:30 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
static u_int16 max_prune_timeout __P((mrtentry_t *));
static void process_cache_miss __P((struct mrt6msg *im));
static void process_wrong_iif __P((struct mrt6msg *im));
u_int32 default_source_preference = DEFAULT_LOCAL_PREF;
u_int32 default_source_metric = DEFAULT_LOCAL_METRIC;
/* Return the iif for given address */
vifi_t
get_iif(address)
struct sockaddr_in6 *address;
{
struct rpfctl rpfc;
k_req_incoming(address, &rpfc);
if (IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
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_pim6_nbr(source)
struct sockaddr_in6 *source;
{
struct rpfctl rpfc;
pim_nbr_entry_t *pim_nbr;
struct sockaddr_in6 *next_hop_router_addr;
if (local_address(source) != NO_VIF)
return (pim_nbr_entry_t *)NULL;
k_req_incoming(source, &rpfc);
if ((IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
|| (rpfc.iif == NO_VIF))
return (pim_nbr_entry_t *)NULL;
next_hop_router_addr = &rpfc.rpfneighbor;
for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors;
pim_nbr != (pim_nbr_entry_t *)NULL;
pim_nbr = pim_nbr->next)
if (inet6_equal(&pim_nbr->address, next_hop_router_addr))
return(pim_nbr);
return (pim_nbr_entry_t *)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?
*/
/* PIMDM 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.
* Note that srctype is a hold-over from the PIM-SM daemon and is unused.
*/
int
set_incoming(srcentry_ptr, srctype)
srcentry_t *srcentry_ptr;
int srctype;
{
struct rpfctl rpfc;
struct sockaddr_in6 *source = &srcentry_ptr->address;
struct sockaddr_in6 *neighbor_addr;
register struct uvif *v;
register pim_nbr_entry_t *n;
/* Preference will be 0 if directly connected */
srcentry_ptr->preference = 0;
srcentry_ptr->metric = 0;
if ((srcentry_ptr->incoming = local_address(source)) != NO_VIF) {
/* The source is a local address */
/* TODO: set the upstream to myself? */
srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
return (TRUE);
}
if ((srcentry_ptr->incoming = find_vif_direct(source)) == NO_VIF) {
/* 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) ||
IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr)) {
/* couldn't find a route */
IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
log(LOG_DEBUG, 0, "NO ROUTE found for %s",
inet6_fmt(&source->sin6_addr));
return(FALSE);
}
srcentry_ptr->incoming = rpfc.iif;
neighbor_addr = &rpfc.rpfneighbor;
}
else {
/* The source is directly connected.
*/
srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
return (TRUE);
}
/* 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 ;-)
*/
for (n = v->uv_pim_neighbors; n != NULL; n = n->next) {
if (inet6_lessthan(neighbor_addr, &n->address))
continue;
if (inet6_equal(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)
log(LOG_DEBUG, 0,
"For src %s, iif is %d, next hop router is %s",
inet6_fmt(&source->sin6_addr), srcentry_ptr->incoming,
inet6_fmt(&neighbor_addr->sin6_addr));
return(TRUE);
}
else break;
}
/* TODO: control the number of messages! */
log(LOG_INFO, 0,
"For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
inet6_fmt(&source->sin6_addr), srcentry_ptr->incoming,
inet6_fmt(&neighbor_addr->sin6_addr));
srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
return(FALSE);
}
/* Set the leaves in a new mrtentry */
void set_leaves(mrtentry_ptr)
mrtentry_t *mrtentry_ptr;
{
vifi_t vifi;
struct uvif *v;
/* Check for a group report on each vif */
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
if(check_multicast_listener(v, &mrtentry_ptr->group->group))
IF_SET(vifi, &mrtentry_ptr->leaves);
}
/* Handle new receiver
*
* TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
* we have source-specific Join/Prune.
*/
void
add_leaf(vifi, source, group)
vifi_t vifi;
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
{
grpentry_t *grpentry_ptr;
mrtentry_t *mrtentry_srcs;
if_set new_leaves;
int state_change;
grpentry_ptr = find_group(group);
if (grpentry_ptr == (grpentry_t *)NULL)
return;
/* walk the source list for the group and add vif to oiflist */
for (mrtentry_srcs = grpentry_ptr->mrtlink;
mrtentry_srcs != (mrtentry_t *)NULL;
mrtentry_srcs = mrtentry_srcs->grpnext) {
/* if applicable, add the vif to the leaves */
if (mrtentry_srcs->incoming == vifi)
continue;
if(!(IF_ISSET(vifi, &mrtentry_srcs->leaves))) {
IF_DEBUG(DEBUG_MRT)
log(LOG_DEBUG, 0, "Adding leaf vif %d for src %s group %s",
vifi,
inet6_fmt(&mrtentry_srcs->source->address.sin6_addr),
inet6_fmt(&group->sin6_addr));
IF_COPY(&mrtentry_srcs->leaves, &new_leaves);
IF_SET(vifi, &new_leaves); /* Add the leaf */
state_change =
change_interfaces(mrtentry_srcs,
mrtentry_srcs->incoming,
&mrtentry_srcs->pruned_oifs,
&new_leaves,
&mrtentry_srcs->asserted_oifs);
/* Handle transition from negative cache */
if(state_change == 1)
trigger_join_alert(mrtentry_srcs);
}
}
}
/*
* TODO: XXX: currently `source` is not used. To be used with IGMPv3 where
* we have source-specific joins/prunes.
*/
void
delete_leaf(vifi, source, group)
vifi_t vifi;
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
{
grpentry_t *grpentry_ptr;
mrtentry_t *mrtentry_srcs;
if_set new_leaves;
int state_change;
/* mrtentry_t *mrtentry_ptr;
* mrtentry_t *mrtentry_srcs;
* vifbitmap_t new_oifs;
* vifbitmap_t old_oifs;
* vifbitmap_t new_leaves;
*/
grpentry_ptr = find_group(group);
if (grpentry_ptr == (grpentry_t *)NULL)
return;
/* walk the source list for the group and delete vif to leaves */
for (mrtentry_srcs = grpentry_ptr->mrtlink;
mrtentry_srcs != (mrtentry_t *)NULL;
mrtentry_srcs = mrtentry_srcs->grpnext) {
/* if applicable, delete the vif from the leaves */
if (mrtentry_srcs->incoming == vifi)
continue;
if(IF_ISSET(vifi, &mrtentry_srcs->leaves)) {
IF_DEBUG(DEBUG_MRT)
log(LOG_DEBUG, 0, "Deleting leaf vif %d for src %s, group %s",
vifi,
inet6_fmt(&mrtentry_srcs->source->address.sin6_addr),
inet6_fmt(&group->sin6_addr));
IF_COPY(&mrtentry_srcs->leaves, &new_leaves);
IF_CLR(vifi, &new_leaves); /* Remove the leaf */
state_change =
change_interfaces(mrtentry_srcs,
mrtentry_srcs->incoming,
&mrtentry_srcs->pruned_oifs,
&new_leaves,
&mrtentry_srcs->asserted_oifs);
/* Handle transition to negative cache */
if(state_change == -1)
trigger_prune_alert(mrtentry_srcs);
}
}
}
void
calc_oifs(mrtentry_ptr, oifs_ptr)
mrtentry_t *mrtentry_ptr;
if_set *oifs_ptr;
{
if_set oifs;
/*
* oifs =
* ((nbr_ifs - my_prune) + my_leaves) - my_filters - incoming_interface,
* i.e.`leaves` have higher priority than `prunes`, but lower than `filters'.
* Asserted oifs (those that lost assert) are handled as pruned oifs.
* The incoming interface is always deleted from the oifs
*/
if (mrtentry_ptr == (mrtentry_t *)NULL) {
IF_ZERO(oifs_ptr);
return;
}
IF_COPY(&nbr_mifs, &oifs);
IF_CLR_MASK(&oifs, &mrtentry_ptr->pruned_oifs);
IF_MERGE(&oifs, &mrtentry_ptr->leaves, &oifs);
IF_CLR_MASK(&oifs, &mrtentry_ptr->asserted_oifs);
IF_CLR_MASK(&oifs, &mrtentry_ptr->filter_oifs);
IF_CLR(mrtentry_ptr->incoming, &oifs);
IF_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_ptr, new_iif, new_pruned_oifs,
new_leaves_, new_asserted_oifs)
mrtentry_t *mrtentry_ptr;
vifi_t new_iif;
if_set *new_pruned_oifs;
if_set *new_leaves_;
if_set *new_asserted_oifs;
{
if_set old_pruned_oifs; /* unnecessary? */
if_set old_leaves; /* unnecessary? */
if_set new_leaves;
if_set new_real_oifs; /* The result oifs */
if_set old_real_oifs;
if_set old_asserted_oifs; /* unnecessary? */
vifi_t old_iif;
int return_value;
if (mrtentry_ptr == (mrtentry_t *)NULL)
return (0);
IF_COPY(new_leaves_, &new_leaves);
old_iif = mrtentry_ptr->incoming;
IF_COPY(&mrtentry_ptr->leaves, &old_leaves);
IF_COPY(&mrtentry_ptr->pruned_oifs, &old_pruned_oifs);
IF_COPY(&mrtentry_ptr->asserted_oifs, &old_asserted_oifs);
IF_COPY(&mrtentry_ptr->oifs, &old_real_oifs);
mrtentry_ptr->incoming = new_iif;
IF_COPY(new_pruned_oifs, &mrtentry_ptr->pruned_oifs);
IF_COPY(&new_leaves, &mrtentry_ptr->leaves);
IF_COPY(new_asserted_oifs, &mrtentry_ptr->asserted_oifs);
calc_oifs(mrtentry_ptr, &new_real_oifs);
if (IF_ISEMPTY(&old_real_oifs)) {
if (IF_ISEMPTY(&new_real_oifs))
return_value = 0;
else
return_value = 1;
} else {
if (IF_ISEMPTY(&new_real_oifs))
return_value = -1;
else
return_value = 0;
}
if ((IF_SAME(&new_real_oifs, &old_real_oifs))
&& (new_iif == old_iif))
return 0; /* Nothing to change */
IF_COPY(&new_real_oifs, &mrtentry_ptr->oifs);
k_chg_mfc(mld6_socket, &mrtentry_ptr->source->address,
&mrtentry_ptr->group->group, new_iif, &new_real_oifs);
#ifdef RSRR
rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
#endif /* RSRR */
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)
vifi_t vifi;
{
return TRUE;
}
static u_int16
max_prune_timeout(mrtentry_ptr)
mrtentry_t *mrtentry_ptr;
{
vifi_t vifi;
#if 0
/* XXX: I don't understand how the variable works...(jinmei@kame.net) */
u_int16 time_left = 0;
#endif
u_int16 max_holdtime = 0;
for(vifi=0; vifi < numvifs; ++vifi)
if(IF_ISSET(vifi, &mrtentry_ptr->pruned_oifs) &&
mrtentry_ptr->prune_timers[vifi])
/* XXX - too expensive ? */
if(mrtentry_ptr->prune_timers[vifi] > max_holdtime)
max_holdtime = mrtentry_ptr->prune_timers[vifi];
#if 0
/* XXX: This is original. But does it have any meaning? */
max_holdtime = time_left;
#endif
if(max_holdtime == 0)
max_holdtime = (u_int16)PIM_JOIN_PRUNE_HOLDTIME;
return(max_holdtime);
}
void
process_kernel_call()
{
register struct mrt6msg *im; /* igmpmsg control struct */
im = (struct mrt6msg *) mld6_recv_buf;
switch (im->im6_msgtype) {
case MRT6MSG_NOCACHE:
process_cache_miss(im);
break;
case MRT6MSG_WRONGMIF:
process_wrong_iif(im);
break;
default:
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG, 0, "Unknown kernel_call code, %d", im->im6_msgtype);
break;
}
}
/*
* Protocol actions:
* 1. Create (S,G) entry (find_route(CREATE))
* a. set iif and oifs
*/
static void
process_cache_miss(im)
struct mrt6msg *im;
{
static struct sockaddr_in6 source = {sizeof(source), AF_INET6};
static struct sockaddr_in6 group = {sizeof(group), AF_INET6};
mrtentry_t *mrtentry_ptr;
/*
* 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.sin6_addr = im->im6_dst;
source.sin6_addr = im->im6_src;
group.sin6_scope_id = inet6_uvif2scopeid(&group, &uvifs[im->im6_mif]);
source.sin6_scope_id = inet6_uvif2scopeid(&source, &uvifs[im->im6_mif]);
IF_DEBUG(DEBUG_MFC)
log(LOG_DEBUG, 0, "Cache miss, src %s, dst %s",
inet6_fmt(&source.sin6_addr), inet6_fmt(&group.sin6_addr));
/* Don't create routing entries for the LAN scoped addresses */
if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
return;
/* Create the (S,G) entry */
mrtentry_ptr = find_route(&source, &group, MRTF_SG, CREATE);
if (mrtentry_ptr == (mrtentry_t *)NULL)
return;
mrtentry_ptr->flags &= ~MRTF_NEW;
/* Set oifs */
set_leaves(mrtentry_ptr);
calc_oifs(mrtentry_ptr, &(mrtentry_ptr->oifs));
/* Add it to the kernel */
k_chg_mfc(mld6_socket, &source, &group, mrtentry_ptr->incoming,
&mrtentry_ptr->oifs);
#ifdef RSRR
rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
#endif /* RSRR */
/* No need to call change_interfaces, but check for NULL oiflist */
if(IF_ISEMPTY(&mrtentry_ptr->oifs))
trigger_prune_alert(mrtentry_ptr);
}
/*
* A multicast packet has been received on wrong iif by the kernel.
* If the packet was received on a point-to-point interface, rate-limit
* prunes. if the packet was received on a LAN interface, rate-limit
* asserts.
*/
static void
process_wrong_iif(im)
struct mrt6msg *im;
{
static struct sockaddr_in6 source = {sizeof(source), AF_INET6};
static struct sockaddr_in6 group = {sizeof(group), AF_INET6};
mifi_t mifi;
mrtentry_t *mrtentry_ptr;
group.sin6_addr = im->im6_dst;
source.sin6_addr = im->im6_src;
mifi = (mifi_t)im->im6_mif;
group.sin6_scope_id = inet6_uvif2scopeid(&group, &uvifs[mifi]);
source.sin6_scope_id = inet6_uvif2scopeid(&source, &uvifs[mifi]);
/* PIMDM TODO Don't create routing entries for the LAN scoped addresses */
if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
return;
mrtentry_ptr = find_route(&source, &group, MRTF_SG, DONT_CREATE);
if(mrtentry_ptr == (mrtentry_t *)NULL)
return;
/* Ratelimit prunes or asserts */
#ifdef notyet
if(uvifs[mifi].uv_flags & VIFF_POINT_TO_POINT) {
/* Wrong vif on P2P interface - rate-limit prunes */
if(mrtentry_ptr->last_prune[mifi] == virtual_time)
/* Skip due to rate-limiting */
return;
mrtentry_ptr->last_prune[mifi] = virtual_time;
if(uvifs[mifi].uv_rmt_addr)
send_pim6_jp(mrtentry_ptr, PIM_ACTION_PRUNE, mifi,
uvifs[mifi].uv_rmt_addr,
max_prune_timeout(mrtentry_ptr), 0);
else
log(LOG_WARNING, 0,
"Can't send wrongvif prune on p2p %s: no remote address",
uvifs[mifi].uv_lcl_addr);
} else
#endif
{
/* Wrong vif on LAN interface - rate-limit asserts */
if(mrtentry_ptr->last_assert[mifi] == virtual_time)
/* Skip due to rate-limiting */
return;
mrtentry_ptr->last_assert[mifi] = virtual_time;
/* Send the assert */
send_pim6_assert(&source, &group, mifi, mrtentry_ptr);
}
}
void
trigger_prune_alert(mrtentry_ptr)
mrtentry_t *mrtentry_ptr;
{
IF_DEBUG(DEBUG_MRT)
log(LOG_DEBUG, 0, "Now negative cache for src %s, grp %s - pruning",
inet6_fmt(&mrtentry_ptr->source->address.sin6_addr),
inet6_fmt(&mrtentry_ptr->group->group.sin6_addr));
/* Set the entry timer to the max of the prune timers */
SET_TIMER(mrtentry_ptr->timer, max_prune_timeout(mrtentry_ptr));
/* Send a prune */
if(mrtentry_ptr->upstream)
send_pim6_jp(mrtentry_ptr, PIM_ACTION_PRUNE, mrtentry_ptr->incoming,
&mrtentry_ptr->upstream->address,
max_prune_timeout(mrtentry_ptr), 0);
}
void
trigger_join_alert(mrtentry_ptr)
mrtentry_t *mrtentry_ptr;
{
IF_DEBUG(DEBUG_MRT)
log(LOG_DEBUG, 0, "Now forwarding state for src %s, grp %s - grafting",
inet6_fmt(&mrtentry_ptr->source->address.sin6_addr),
inet6_fmt(&mrtentry_ptr->group->group.sin6_addr));
/* Refresh the entry timer */
SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
/* Send graft */
send_pim6_graft(mrtentry_ptr);
}

373
usr.sbin/pim6dd/routesock.c Normal file
View File

@ -0,0 +1,373 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: routesock.c,v 1.4 1999/11/19 04:05:48 sumikawa 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.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/file.h>
#include "defs.h"
#include <sys/socket.h>
#include <net/route.h>
#ifdef HAVE_ROUTING_SOCKETS
#include <net/if_dl.h>
#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#ifdef HAVE_ROUTING_SOCKETS
union sockunion {
struct sockaddr sa;
struct sockaddr_in6 sin6;
struct sockaddr_dl sdl;
} so_dst, so_ifp;
typedef union sockunion *sup;
int routing_socket;
int rtm_addrs, pid;
struct rt_metrics rt_metrics;
u_long rtm_inits;
/*
* Local functions definitions.
*/
static int getmsg __P((register 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(4)) /* TODO: a hack!! */
#endif
/* Open and initialize the routing socket */
int
init_routesock()
{
pid = getpid();
routing_socket = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
if (routing_socket < 0) {
log(LOG_ERR, 0, "\nRouting socket error");
return -1;
}
if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1){
log(LOG_ERR, 0, "\n Routing socket error");
return -1;
}
#if 0
{
int off;
off = 0;
if (setsockopt(routing_socket, SOL_SOCKET,
SO_USELOOPBACK, (char *)&off,
sizeof(off)) < 0){
log(LOG_ERR, 0 , "\n setsockopt(SO_USELOOPBACK,0)");
return -1;
}
}
#endif
return 0;
}
struct {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
/* get the rpf neighbor info */
int
k_req_incoming(source, rpfp)
struct sockaddr_in6 *source;
struct rpfctl *rpfp;
{
int flags = RTF_STATIC;
register sup su;
static int seq;
int rlen;
register char *cp = m_rtmsg.m_space;
register int l;
struct rpfctl rpfinfo;
/* TODO: a hack!!!! */
#ifdef HAVE_SA_LEN
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) { \
l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
}
#else
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) { \
l = ROUNDUP(4); bcopy((char *)&(u), cp, l); cp += l;\
}
#endif /* HAVE_SA_LEN */
/* initialize */
memset(&rpfp->rpfneighbor, 0, sizeof(rpfp->rpfneighbor));
rpfp->source = *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 = *source;
return(TRUE);
}
/* prepare the routing socket params */
rtm_addrs |= RTA_DST;
rtm_addrs |= RTA_IFP;
su = &so_dst;
su->sin6.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
su->sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
su->sin6.sin6_addr = source->sin6_addr;
su->sin6.sin6_scope_id = source->sin6_scope_id;
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;
bzero((char *)&m_rtmsg, 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)
log(LOG_DEBUG, 0,
"Writing to routing socket: no such route\n");
else
log(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)
log(LOG_DEBUG, 0, "Read from routing socket failed: %s", strerror(errno));
return(FALSE);
}
if (getmsg(&rtm, l, &rpfinfo)){
rpfp->rpfneighbor = rpfinfo.rpfneighbor;
rpfp->iif = rpfinfo.iif;
}
#undef rtm
return (TRUE);
}
/*
* Returns TRUE on success, FALSE otherwise. rpfinfo contains the result.
*/
int
getmsg(rtm, msglen, rpfinfop)
register struct rt_msghdr *rtm;
int msglen;
struct rpfctl *rpfinfop;
{
struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
struct sockaddr_dl *ifp = NULL;
register struct sockaddr *sa;
register char *cp;
register int i;
struct sockaddr_in6 *sin6;
vifi_t vifi;
struct uvif *v;
char in6txt[INET6_ADDRSTRLEN];
if (rpfinfop == (struct rpfctl *)NULL)
return(FALSE);
sin6 = (struct sockaddr_in6 *)&so_dst;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, "route to: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
cp = ((char *)(rtm + 1));
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);
}
if (!ifp){ /* No incoming interface */
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0,
"No incoming interface for destination %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
return(FALSE);
}
if (dst && mask)
mask->sa_family = dst->sa_family;
if (dst) {
sin6 = (struct sockaddr_in6 *)dst;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, " destination is: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
}
if (gate && rtm->rtm_flags & RTF_GATEWAY) {
sin6 = (struct sockaddr_in6 *)gate;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, " gateway is: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
rpfinfop->rpfneighbor = *sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
#if 0
rpfinfop->rpfneighbor.sin6_scope_id =
ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
#endif
rpfinfop->rpfneighbor.sin6_scope_id = ifp->sdl_index;
/*
* XXX: KAME kernel embeds the interface index to the address.
* Clear the index for safety.
*/
rpfinfop->rpfneighbor.sin6_addr.s6_addr[2] = 0;
rpfinfop->rpfneighbor.sin6_addr.s6_addr[3] = 0;
}
}
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)
log(LOG_DEBUG, 0, " iif is %d", vifi);
rpfinfop->iif = vifi;
if (vifi >= numvifs){
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0,
"Invalid incoming interface for destination %s, because of invalid virtual interface",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
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(source, rpfcinfo)
struct sockaddr_in6 *source;
struct rpfctl *rpfcinfo;
{
rpfcinfo->source = *source;
rpfcinfo->iif = NO_VIF; /* just initialized, will be */
/* changed in kernel */
memset(&rpfcinfo->rpfneighbor, 0, sizeof(rpfcinfo->rpfneighbor)); /* initialized */
if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0){
log(LOG_ERR, errno, "ioctl SIOCGETRPF k_req_incoming");
return(FALSE);
}
return (TRUE);
}
#endif /* HAVE_ROUTING_SOCKETS */

322
usr.sbin/pim6dd/timer.c Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 1998 by the University of Oregon.
* 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 Oregon.
* The name of the University of Oregon may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Kurt Windisch (kurtw@antc.uoregon.edu)
*
* $Id: timer.c,v 1.3 1999/09/15 07:45:12 jinmei Exp $
*/
/*
* Part of this program has been derived from PIM sparse-mode pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* The pimd program is COPYRIGHT 1998 by University of Southern California.
*
* 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.
*
* $FreeBSD$
*/
#include "defs.h"
/*
* Global variables
*/
/*
* 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 */
/* to request and compare any route changes */
srcentry_t srcentry_save;
/*
* Init some timers
*/
void
init_timers()
{
unicast_routing_check_interval = UCAST_ROUTING_CHECK_INTERVAL;
unicast_routing_timer = unicast_routing_check_interval;
/* Initialize the srcentry used to save the old routes
* during unicast routing change discovery process.
*/
srcentry_save.prev = (srcentry_t *)NULL;
srcentry_save.next = (srcentry_t *)NULL;
memset(&srcentry_save.address, 0, sizeof(struct sockaddr_in6));
srcentry_save.address.sin6_len = sizeof(struct sockaddr_in6);
srcentry_save.address.sin6_family= AF_INET6;
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;
srcentry_save.timer = 0;
}
/*
* 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))
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.
*/
if (PIM_MESSAGE_HELLO_HOLDTIME_FOREVER == curr_nbr->timer)
continue;
IF_NOT_TIMEOUT(curr_nbr->timer)
continue;
delete_pim6_nbr(curr_nbr);
}
/* PIM_HELLO periodic */
IF_TIMEOUT(v->uv_pim_hello_timer)
send_pim6_hello(v, PIM_TIMER_HELLO_HOLDTIME);
/* MLD query periodic */
IF_TIMEOUT(v->uv_gq_timer)
query_groups(v);
}
IF_DEBUG(DEBUG_IF) {
dump_vifs(stderr);
dump_lcl_grp(stderr);
}
}
/*
* Scan the whole routing table and timeout a bunch of timers:
* - prune timers
* - Join/Prune delay timer
* - routing entry
* - Assert timer
*/
void
age_routes()
{
mrtentry_t *mrtentry_ptr, *mrtentry_next;
grpentry_t *grpentry_ptr, *grpentry_next;
vifi_t vifi;
int change_flag, state_change;
int update_src_iif;
u_long curr_bytecnt;
/*
* Timing out of the global `unicast_routing_timer` and data rate timer
*/
IF_TIMEOUT(unicast_routing_timer) {
ucast_flag = TRUE;
unicast_routing_timer = unicast_routing_check_interval;
}
ELSE {
ucast_flag = FALSE;
}
/* Walk the the (S,G) entries */
if(grplist == (grpentry_t *)NULL)
return;
for(grpentry_ptr = grplist;
grpentry_ptr != (grpentry_t *)NULL;
grpentry_ptr = grpentry_next) {
grpentry_next = grpentry_ptr->next;
for(mrtentry_ptr = grpentry_ptr->mrtlink;
mrtentry_ptr != (mrtentry_t *)NULL;
mrtentry_ptr = mrtentry_next) {
mrtentry_next = mrtentry_ptr->grpnext;
/* Refresh entry timer if data forwarded */
curr_bytecnt = mrtentry_ptr->sg_count.bytecnt;
if (k_get_sg_cnt(udp_socket,
&mrtentry_ptr->source->address,
&mrtentry_ptr->group->group,
&mrtentry_ptr->sg_count)) {
/* No such routing entry in kernel */
delete_mrtentry(mrtentry_ptr);
continue;
}
if(!(IF_ISEMPTY(&mrtentry_ptr->oifs)) &&
curr_bytecnt != mrtentry_ptr->sg_count.bytecnt) {
/* Packets have been forwarded - refresh timer
* Note that these counters count packets received,
* not packets forwarded. So only refresh if packets
* received and non-null oiflist.
*/
IF_DEBUG(DEBUG_MFC)
log(LOG_DEBUG, 0,
"Refreshing src %s, dst %s after %d bytes forwarded",
inet6_fmt(&mrtentry_ptr->source->address.sin6_addr),
inet6_fmt(&mrtentry_ptr->group->group.sin6_addr),
mrtentry_ptr->sg_count.bytecnt);
SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
}
/* Time out the entry */
IF_TIMEOUT(mrtentry_ptr->timer) {
delete_mrtentry(mrtentry_ptr);
continue;
}
/* Time out asserts */
if(mrtentry_ptr->flags & MRTF_ASSERTED)
IF_TIMEOUT(mrtentry_ptr->assert_timer) {
mrtentry_ptr->flags &= ~MRTF_ASSERTED;
mrtentry_ptr->upstream = mrtentry_ptr->source->upstream;
mrtentry_ptr->metric = mrtentry_ptr->source->metric;
mrtentry_ptr->preference = mrtentry_ptr->source->preference;
}
/* Time out Pruned interfaces */
change_flag = FALSE;
for (vifi = 0; vifi < numvifs; vifi++) {
if (IF_ISSET(vifi, &mrtentry_ptr->pruned_oifs))
IF_TIMEOUT(mrtentry_ptr->prune_timers[vifi]) {
IF_CLR(vifi, &mrtentry_ptr->pruned_oifs);
SET_TIMER(mrtentry_ptr->prune_timers[vifi], 0);
change_flag = TRUE;
}
}
/* Unicast Route changes */
update_src_iif = FALSE;
if (ucast_flag == TRUE) {
/* iif toward the source */
srcentry_save.incoming = mrtentry_ptr->source->incoming;
srcentry_save.upstream = mrtentry_ptr->source->upstream;
srcentry_save.preference = mrtentry_ptr->source->preference;
srcentry_save.metric = mrtentry_ptr->source->metric;
if (set_incoming(mrtentry_ptr->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_ptr);
continue;
}
else {
/* iif info found */
if (!(mrtentry_ptr->flags & MRTF_ASSERTED) &&
((srcentry_save.incoming !=
mrtentry_ptr->incoming)
|| (srcentry_save.upstream !=
mrtentry_ptr->upstream))) {
/* Route change has occur */
update_src_iif = TRUE;
mrtentry_ptr->incoming =
mrtentry_ptr->source->incoming;
mrtentry_ptr->upstream =
mrtentry_ptr->source->upstream;
/* mrtentry should have pref/metric of upstream
* assert winner, but we dont have that info,
* so use the source pref/metric, which will be
* larger and thus the correct assert winner
* from upstream will be chosen.
*/
mrtentry_ptr->preference =
mrtentry_ptr->source->preference;
mrtentry_ptr->metric =
mrtentry_ptr->source->metric;
}
}
}
if ((change_flag == TRUE) || (update_src_iif == TRUE)) {
/* Flush the changes */
state_change =
change_interfaces(mrtentry_ptr,
mrtentry_ptr->incoming,
&mrtentry_ptr->pruned_oifs,
&mrtentry_ptr->leaves,
&mrtentry_ptr->asserted_oifs);
if(state_change == -1)
trigger_prune_alert(mrtentry_ptr);
}
}
}
IF_DEBUG(DEBUG_PIM_MRT)
dump_pim_mrt(stderr);
return;
}

540
usr.sbin/pim6dd/trace.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* non-commercial purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: trace.c,v 1.5 1999/09/16 08:46:00 jinmei 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.
*
* $FreeBSD$
*/
#include "defs.h"
#include "trace.h"
/* TODO */
/*
* Traceroute function which returns traceroute replies to the requesting
* router. Also forwards the request to downstream routers.
*/
void
accept_mtrace(src, dst, group, ifindex, data, no, datalen)
struct sockaddr_in6 *src;
struct in6_addr *dst;
struct in6_addr *group;
int ifindex;
char *data;
u_int no; /* promoted u_char */
int datalen;
{
u_char type;
mrtentry_t *mrt;
struct tr6_query *qry;
struct tr6_resp *resp;
int vifi, ovifi;
char *p;
int rcount;
int errcode = TR_NO_ERR;
int resptype;
struct timeval tp;
struct sioc_mif_req6 mreq;
struct in6_addr parent_address;
struct sockaddr_in6 src_sa6 = {sizeof(src_sa6), AF_INET6};
struct sockaddr_in6 dst_sa6 = {sizeof(dst_sa6), AF_INET6};
struct sockaddr_in6 resp_sa6 = {sizeof(resp_sa6), AF_INET6};
struct sockaddr_in6 grp_sa6 = {sizeof(grp_sa6), AF_INET6};
struct sockaddr_in6 *sa_global;
#ifdef SM_ONLY
rpentry_t *rpentry_ptr;
#endif
/* 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)
log(LOG_DEBUG, 0, "Initial traceroute query rcvd "
"from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
}
else if ((datalen - QLEN) % RLEN == 0) {
type = RESP;
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "In-transit traceroute query rcvd "
"from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
if (IN6_IS_ADDR_MULTICAST(dst)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Dropping multicast response");
return;
}
}
else {
log(LOG_WARNING, 0, "%s from %s to %s",
"Non decipherable traceroute request recieved",
inet6_fmt(&src->sin6_addr), inet6_fmt(dst));
return;
}
qry = (struct tr6_query *)data;
src_sa6.sin6_addr = qry->tr_src;
src_sa6.sin6_scope_id =
(IN6_IS_ADDR_LINKLOCAL(&qry->tr_src)
|| IN6_IS_ADDR_MC_LINKLOCAL(&qry->tr_src)) ? ifindex : 0;
dst_sa6.sin6_addr = qry->tr_dst;
dst_sa6.sin6_scope_id =
(IN6_IS_ADDR_LINKLOCAL(&qry->tr_dst)
|| IN6_IS_ADDR_MC_LINKLOCAL(&qry->tr_dst)) ? ifindex : 0;
grp_sa6.sin6_addr = *group;
grp_sa6.sin6_scope_id = 0;
/*
* if it is a packet with all reports filled, drop it
*/
if ((rcount = (datalen - QLEN)/RLEN) == no) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "packet with all reports filled in");
return;
}
IF_DEBUG(DEBUG_TRACE) {
log(LOG_DEBUG, 0, "s: %s g: %s d: %s ",
inet6_fmt(&qry->tr_src),
inet6_fmt(group), inet6_fmt(&qry->tr_dst));
log(LOG_DEBUG, 0, "rhlim: %d rd: %s", qry->tr_rhlim,
inet6_fmt(&qry->tr_raddr));
log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
}
/* determine the routing table entry for this traceroute */
mrt = find_route(&src_sa6, &grp_sa6, 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.sin6_addr;
else
parent_address = in6addr_any;
log(LOG_DEBUG, 0,
"mrt parent mif: %d rtr: %s metric: %d",
mrt->incoming,
inet6_fmt(&parent_address), mrt->metric);
/* TODO
log(LOG_DEBUG, 0, "mrt origin %s",
RT_FMT(rt, s1));
*/
} else
log(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)
log(LOG_DEBUG, 0,
"ignoring duplicate traceroute packet");
return;
}
if (mrt == (mrtentry_t *)NULL) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Mcast traceroute: no route entry %s",
inet6_fmt(&qry->tr_src));
#if 0
if (IN6_IS_ADDR_MULTICAST(dst))
return;
#endif
}
vifi = find_vif_direct(&dst_sa6);
if (vifi == NO_VIF) {
/*
* The traceroute destination is not on one of
* my subnet vifs.
*/
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not an interface",
inet6_fmt(&qry->tr_dst));
if (IN6_IS_ADDR_MULTICAST(dst))
return;
errcode = TR_WRONG_IF;
} else if (mrt != (mrtentry_t *)NULL &&
!IF_ISSET(vifi, &mrt->oifs)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not on forwarding tree "
"for src %s",
inet6_fmt(&qry->tr_dst),
inet6_fmt(&qry->tr_src));
if (IN6_IS_ADDR_MULTICAST(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)
log(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)
log(LOG_DEBUG, 0, "Sending traceroute response");
/* copy the packet to the sending buffer */
p = mld6_send_buf + sizeof(struct mld6_hdr);
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 tr6_resp) > mld6_send_buf + RECV_BUF_SIZE) {
resp = (struct tr6_resp *)p - 1;
resp->tr_rflags = TR_NO_SPACE;
mrt = NULL;
goto sendit;
}
/*
* fill in initial response fields
*/
resp = (struct tr6_resp *)p;
bzero(resp, sizeof(struct tr6_resp));
datalen += (RLEN + sizeof(struct mld6_hdr));
resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec << 10) / 15625));
resp->tr_rproto = PROTO_PIM;
resp->tr_outifid = (vifi == NO_VIF) ? TR_NO_VIF : htonl(vifi);
resp->tr_rflags = errcode;
if ((sa_global = max_global_address()) == NULL) /* impossible */
log(LOG_ERR, 0, "acept_mtrace: max_global_address returns NULL");
resp->tr_lcladdr = sa_global->sin6_addr;
/*
* obtain # of packets out on interface
*/
mreq.mifi = vifi;
if (vifi != NO_VIF &&
ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *)&mreq) >= 0)
resp->tr_vifout = htonl(mreq.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->sin6_addr = *dst; /* the dst address of resp. pkt */
resp->tr_inifid = TR_NO_VIF;
resp->tr_rflags = TR_NO_RTE;
memset(&resp->tr_rmtaddr, 0, sizeof(struct in6_addr));
} else {
/* get # of packets in on interface */
mreq.mifi = mrt->incoming;
if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *)&mreq) >= 0)
resp->tr_vifin = htonl(mreq.icount);
else
resp->tr_vifin = 0xffffffff;
/*
* TODO
* MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
*/
resp->tr_inifid = htonl(mrt->incoming);
if (mrt->upstream != (pim_nbr_entry_t *)NULL)
parent_address = mrt->upstream->address.sin6_addr;
else
parent_address = in6addr_any;
resp->tr_rmtaddr = parent_address;
if (!IF_ISSET(vifi, &mrt->oifs)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not on forwarding tree "
"for src %s",
inet6_fmt(&qry->tr_dst),
inet6_fmt(&qry->tr_src));
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 */
}
#ifdef SM_ONLY
/*
* If we're the RP for the trace group, note it.
*/
rpentry_ptr = rp_match(&grp_sa6);
if (rpentry_ptr && local_address(&rpentry_ptr->address) != NO_VIF)
resp->tr_rflags = TR_RP;
#endif /* SM_ONLY */
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)
log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
ovifi = NO_VIF; /* unspecified */
if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) {
resptype = MLD6_MTRACE_RESP;
resp_sa6.sin6_addr = qry->tr_raddr;
if (IN6_IS_ADDR_LINKLOCAL(&resp_sa6.sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&resp_sa6.sin6_addr)) {
if ((ovifi = find_vif_direct(&dst_sa6)) == NO_VIF) {
log(LOG_INFO, 0,
"can't determine outgoing i/f for mtrace "
"response.");
return;
}
}
} else
/* TODO */
{
#if 0
if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
resp_sa6.sin6_addr = qry->tr_raddr;
resp->tr_rflags = TR_OLD_ROUTER;
resptype = MLD6_MTRACE_RESP;
} else
#endif /* 0 */
#ifdef SM_ONLY
if (mrt->incoming &&
(uvifs[mrt->incoming].uv_flags & MIFF_REGISTER)) {
log(LOG_DEBUG, 0,
"incoming i/f is for register. "
"Can't be forwarded anymore.");
resp_sa6.sin6_addr = qry->tr_raddr;
resptype = MLD6_MTRACE_RESP;
} else
#endif /* SM_ONLY */
{
if (mrt->upstream != (pim_nbr_entry_t *)NULL)
parent_address =
mrt->upstream->address.sin6_addr;
else
parent_address = allrouters_group.sin6_addr;
resp_sa6.sin6_addr = parent_address;
ovifi = mrt->incoming;
resptype = MLD6_MTRACE;
}
}
if (IN6_IS_ADDR_MULTICAST(&resp_sa6.sin6_addr)) {
struct sockaddr_in6 *sa6;
/*
* Send the reply on a known multicast capable vif.
* If we don't have one, we can't source any
* multicasts anyway.
*/
if (IN6_IS_ADDR_MC_LINKLOCAL(&resp_sa6.sin6_addr)) {
sa6 = &uvifs[ovifi].uv_linklocal->pa_addr;
ifindex = uvifs[ovifi].uv_ifindex;
}
else {
if (phys_vif != -1 &&
(sa6 = uv_global(phys_vif)) != NULL) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Sending reply to %s from %s",
inet6_fmt(dst),
inet6_fmt(&sa6->sin6_addr));
ifindex = uvifs[phys_vif].uv_ifindex;
}
else {
log(LOG_INFO, 0, "No enabled phyints -- %s",
"dropping traceroute reply");
return;
}
}
k_set_hlim(mld6_socket, qry->tr_rhlim);
send_mld6(resptype, no, sa6, &resp_sa6, group,
ifindex, 0, datalen, 0);
k_set_hlim(mld6_socket, 1);
} else {
struct sockaddr_in6 *sa6 = NULL;
ifindex = -1; /* unspecified by default */
if (IN6_IS_ADDR_LINKLOCAL(&resp_sa6.sin6_addr)) {
/* ovifi must be valid in this case */
ifindex = uvifs[ovifi].uv_ifindex;
sa6 = &uvifs[ovifi].uv_linklocal->pa_addr;
}
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Sending %s to %s from %s",
resptype == MLD6_MTRACE_RESP ?
"reply" : "request on",
inet6_fmt(dst),
sa6 ? inet6_fmt(&sa6->sin6_addr) : "unspecified");
send_mld6(resptype, no, sa6, &resp_sa6, group, ifindex,
0, datalen, 0);
}
return;
}

204
usr.sbin/pim6dd/trace.h Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: trace.h,v 1.2 1999/09/12 17:00:10 jinmei 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.
*
* $FreeBSD$
*/
/*
* The packet format for a traceroute request.
*/
struct tr6_query {
struct in6_addr tr_src; /* traceroute source */
struct in6_addr tr_dst; /* traceroute destination */
struct in6_addr tr_raddr; /* traceroute response address */
#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
struct {
u_int32_t qid : 24; /* traceroute query id */
u_int32_t rhlim : 8; /* traceroute response ttl */
} q;
#else
struct {
u_int32_t rhlim : 8; /* traceroute response ttl */
u_int32_t qid : 24; /* traceroute query id */
} q;
#endif /* BYTE_ORDER */
};
#define tr_rhlim q.rhlim
#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 tr6_resp {
u_int32_t tr_qarr; /* query arrival time */
#if 0
struct in6_addr tr_inaddr; /* incoming interface address */
struct in6_addr tr_outaddr; /* outgoing interface address */
#endif
u_int32_t tr_inifid; /* incoming interface identifier */
u_int32_t tr_outifid; /* outgoing interface identifier */
struct in6_addr tr_lcladdr; /* router's address(must have largest scope) */
struct in6_addr tr_rmtaddr; /* parent address in source tree */
u_int32_t tr_vifin; /* input packet count on interface */
u_int32_t tr_vifout; /* output packet count on interface */
u_int32_t tr_pktcnt; /* total incoming packets for src-grp */
u_char tr_rproto; /* routing protocol deployed on router */
#if 0
u_char tr_fhlim; /* hop limit required to forward on outvif */
#endif
u_char tr_flags; /* flags */
u_char tr_plen; /* prefix length for src addr */
u_char tr_rflags; /* forwarding error codes */
};
/* defs within mtrace */
#define QUERY 1
#define RESP 2
#define QLEN sizeof(struct tr6_query)
#define RLEN sizeof(struct tr6_resp)
/* fields for tr_inifid and tr_outifid */
#define TR_NO_VIF 0xffffffff/* interface can't be determined */
/* 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_flags */
#define TR_SUBNET_COUNT 0x80 /* pkt count for (S,G) is for source network */
/* fields for r_plen */
#define TR_GROUP_ONLY 0xff /* forwarding solely on group state */
/* 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 MASK_TO_VAL(x, i) { \
u_int32_t _x = ntohl(x); \
(i) = 1; \
while ((_x) <<= 1) \
(i)++; \
};
#define VAL_TO_MASK(x, i) { \
x = htonl(~((1 << (32 - (i))) - 1)); \
};
#define MASKLEN_TO_MASK6(masklen, mask6) \
do {\
u_char maskarray[8] = \
{0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; \
int bytelen, bitlen, i; \
memset(&(mask6), 0, sizeof(mask6));\
bytelen = (masklen) / 8;\
bitlen = (masklen) % 8;\
for (i = 0; i < bytelen; i++) \
(mask6).s6_addr[i] = 0xff;\
if (bitlen) \
(mask6).s6_addr[bytelen] = maskarray[bitlen - 1]; \
}while(0);
/* obnoxious gcc gives an extraneous warning about this constant... */
#if defined(__STDC__) || defined(__GNUC__)
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
#else
#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
#define const /**/
#endif
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)

2
usr.sbin/pim6dd/vers.c Normal file
View File

@ -0,0 +1,2 @@
/* $FreeBSD$ */
char todaysversion[]="0.2.1.0-alpha15";

528
usr.sbin/pim6dd/vif.c Normal file
View File

@ -0,0 +1,528 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: vif.c,v 1.3 1999/09/12 17:00:11 jinmei 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.
*
* $FreeBSD$
*/
#include "defs.h"
/*
* Exported variables.
*/
struct uvif uvifs[MAXMIFS]; /* 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 */
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. */
/* How dumb. */
int total_interfaces; /* Number of all interfaces: including the
* non-configured, but excluding the
* loopback interface and the non-multicast
* capable interfaces.
*/
if_set if_nullset; /* an interface face that has all-0 bit
* (for comparison)
*/
/*
* Forward declarations.
*/
static void start_vif __P((vifi_t vifi));
static void stop_vif __P((vifi_t vifi));
static void start_all_vifs __P((void));
void
init_vifs()
{
vifi_t vifi;
struct uvif *v;
int enabled_vifs;
numvifs = 0;
vifs_down = FALSE;
/*
* Configure the vifs based on the interface configuration of
* 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 MLD socket.)
*/
#ifdef IOCTL_OK_ON_RAW_SOCKET
udp_socket = mld6_socket;
#else
if ((udp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
log(LOG_ERR, errno, "UDP6 socket");
#endif
/*
* Clean up all vifs
*/
for (vifi = 0, v = uvifs; vifi < MAXMIFS; ++vifi, ++v) {
memset(v, 0, sizeof(*v));
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
v->uv_admetric = 0;
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
strncpy(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_prune_lifetime = 0;
v->uv_acl = (struct vif_acl *)NULL;
v->uv_leaf_timer = 0;
v->uv_addrs = (struct phaddr *)NULL;
v->uv_filter = (struct vif_filter *)NULL;
v->uv_pim_hello_timer = 0;
v->uv_gq_timer = 0;
v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL;
v->uv_local_pref = default_source_preference;
v->uv_local_metric = default_source_metric;
}
log(LOG_INFO, 0, "Getting ifs from kernel");
config_vifs_from_kernel();
log(LOG_INFO, 0, "Getting ifs from %s", configfilename);
config_vifs_from_file();
/*
* Quit if there are fewer than two enabled vifs or there is a vif
* which has no link local address.
*/
enabled_vifs = 0;
phys_vif = -1;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
continue;
if (v->uv_linklocal == NULL)
log(LOG_ERR, 0,
"there is no link-local address on vif#%d", vifi);
if (phys_vif == -1) {
struct phaddr *p;
/*
* If this vif has a global address, set its id
* to phys_vif.
*/
for(p = v->uv_addrs; p; p = p->pa_next) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
phys_vif = vifi;
break;
}
}
}
enabled_vifs++;
}
if (enabled_vifs < 2)
log(LOG_ERR, 0, "can't forward: %s",
enabled_vifs == 0 ? "no enabled ifs" : "only one enabled if");
memset(&if_nullset, 0, sizeof(if_nullset));
k_init_pim(mld6_socket); /* Call to kernel to initiliaze structures */
start_all_vifs();
}
static void
start_all_vifs()
{
vifi_t vifi;
struct uvif *v;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
/* Start vif if not DISABLED or DOWN */
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) {
if (v->uv_flags & VIFF_DISABLED)
log(LOG_INFO, 0,
"%s is DISABLED; if #%u out of service",
v->uv_name, vifi);
else
log(LOG_INFO, 0,
"%s is DOWN; if #%u out of service",
v->uv_name, vifi);
}
else
start_vif(vifi);
}
}
/*
* stop all vifs
*/
void
stop_all_vifs()
{
vifi_t vifi;
struct uvif *v;
for (vifi = 0, v=uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DOWN)) {
stop_vif(vifi);
}
}
}
/*
* Initialize the vif and add to the kernel. The vif can be either
* physical, tunnel (tunnels will be used in the future
* when this code becomes PIM multicast boarder router.)
*/
static void
start_vif(vifi)
vifi_t vifi;
{
struct uvif *v;
u_long random_delay;
v = &uvifs[vifi];
/* Initialy no router on any vif */
v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN;
v->uv_pim_hello_timer = 1 + RANDOM() % PIM_TIMER_HELLO_PERIOD;
/* TODO: CHECK THE TIMERS!!!!! Set or reset? */
v->uv_gq_timer = 0;
v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL;
/* Tell kernel to add, i.e. start this vif */
k_add_vif(mld6_socket, vifi, &uvifs[vifi]);
log(LOG_INFO, 0, "%s comes up; if #%u now in service", v->uv_name, vifi);
/*
* Join the PIM multicast group on the interface.
*/
k_join(mld6_socket, &allpim6routers_group.sin6_addr, v->uv_ifindex);
/*
* 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(mld6_socket, &allrouters_group.sin6_addr, v->uv_ifindex);
/*
* 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);
/*
* To avoid synchronization among routers booting simultaneously, set
* the hello timer to a random value between 1 to PIM_TIMER_HELLO_PERIOD.
*/
random_delay = 1 + (random() % (long)(PIM_TIMER_HELLO_PERIOD - 1));
v->uv_pim_hello_timer = random_delay;
}
/*
* Stop a vif (either physical interface or tunnel).
* If we are running only PIM we don't have tunnels.
*/
static void
stop_vif(vifi)
vifi_t vifi;
{
struct uvif *v;
struct listaddr *a;
register 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];
k_leave(mld6_socket, &allpim6routers_group.sin6_addr, v->uv_ifindex);
k_leave(mld6_socket, &allrouters_group.sin6_addr, v->uv_ifindex);
/*
* 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(mld6_socket, vifi);
v->uv_flags = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS )
| VIFF_DOWN;
v->uv_pim_hello_timer = 0;
v->uv_gq_timer = 0;
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;
log(LOG_INFO, 0,
"%s goes down; if #%u out of service", v->uv_name, vifi);
}
/*
* return the max global Ipv6 address of an UP and ENABLED interface
* other than the MIFF_REGISTER interface.
*/
struct sockaddr_in6 *
max_global_address()
{
vifi_t vifi;
struct uvif *v;
struct phaddr *p;
struct phaddr *pmax = NULL;
for(vifi=0,v=uvifs;vifi< numvifs;++vifi,++v)
{
if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
continue;
/*
* take first the max global address of the interface
* (without link local) => aliasing
*/
for(p=v->uv_addrs;p!=NULL;p=p->pa_next)
{
/*
* If this is the first global address, take it anyway.
*/
if (pmax == NULL) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
pmax = p;
}
else {
if (inet6_lessthan(&pmax->pa_addr,
&p->pa_addr) &&
!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
pmax=p;
}
}
}
return(pmax ? &pmax->pa_addr : NULL);
}
struct sockaddr_in6 *
uv_global(vifi)
vifi_t vifi;
{
struct uvif *v = &uvifs[vifi];
struct phaddr *p;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
return(&p->pa_addr);
}
return(NULL);
}
/*
* 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()
{
register vifi_t vifi;
register 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 interfaces only */
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & VIFF_DISABLED)
continue;
strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
/* get the interface flags */
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
log(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)) {
log(LOG_NOTICE, 0,
"%s has gone down; if #%u taken out of service",
v->uv_name, vifi);
stop_vif(vifi);
vifs_down = TRUE;
}
}
}
checking_vifs = 0;
}
/*
* If the source is directly connected to us, find the vif number for
* the corresponding physical interface (tunnels excluded).
* Local addresses are excluded.
* Return the vif number or NO_VIF if not found.
*/
vifi_t
find_vif_direct(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
continue;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (inet6_equal(src, &p->pa_addr))
return(NO_VIF);
if (inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
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(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
continue;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (inet6_equal(src, &p->pa_addr))
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
* (tunnels excluded).
* Return the vif number or NO_VIF if not found.
*/
vifi_t
find_vif_direct_local(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
continue;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (inet6_equal(src, &p->pa_addr) ||
inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
return(vifi);
}
}
return (NO_VIF);
}

292
usr.sbin/pim6dd/vif.h Normal file
View File

@ -0,0 +1,292 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: vif.h,v 1.2 1999/08/24 16:45:23 jinmei 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.
*
* $FreeBSD$
*/
/*
* 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 <netinet/ip_mroute.h>, 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 <netinet/ip_mroute.h> was missing some required functions anyway
*/
#if !defined(__NetBSD__)
#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))
/*
* And <netinet6/ip6_mroute.h> was missing some required functions anyway
*/
extern if_set if_nullset;
#define IF_ISEMPTY(p) (memcmp((p), &if_nullset, sizeof(if_nullset)) == 0)
#define IF_CLR_MASK(p, mask) \
{\
int idx;\
for (idx = 0; idx < sizeof(*(p))/sizeof(fd_mask); idx++) {\
(p)->ifs_bits[idx] &= ~((mask)->ifs_bits[idx]);\
}\
}
#define IF_MERGE(p1, p2, result) \
{\
int idx;\
for (idx = 0; idx < sizeof(*(p1))/sizeof(fd_mask); idx++) {\
(result)->ifs_bits[idx] = (p1)->ifs_bits[idx]|(p2)->ifs_bits[idx]; \
}\
}
#define IF_SAME(p1, p2) (memcmp((p1),(p2),sizeof(*(p1))) == 0)
/* Check whether I am the forwarder on some LAN */
#define VIFM_FORWARDER(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 */
#if 0 /* unused for IPv6? */
u_char uv_threshold; /* min ttl required to forward on vif */
#endif
u_int uv_rate_limit; /* rate limit on this vif */
struct sockaddr_in6 uv_lcl_addr;/* local address of this vif */
struct phaddr *uv_linklocal;/* link-local address of this vif */
#if 0
u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */
#endif
struct sockaddr_in6 uv_dst_addr; /* destination for PIM messages */
struct sockaddr_in6 uv_prefix; /* prefix (phyints only) */
struct in6_addr uv_subnetmask; /* subnet mask (phyints only) */
char uv_name[IFNAMSIZ]; /* interface name */
u_int uv_ifindex; /* index of the interface */
u_int uv_siteid; /* index of the site on the interface */
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; /* MLD querier on vif */
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 addresses 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 */
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 */
};
/* 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 */
#define VIFF_NOLISTENER 0x800000 /* no listener on the link */
struct phaddr {
struct phaddr *pa_next;
struct sockaddr_in6 pa_addr; /* extra address */
struct sockaddr_in6 pa_prefix; /* prefix of the extra address */
struct in6_addr pa_subnetmask; /* netmask */
};
/* 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;
struct sockaddr_in6 *vfe_addr;
struct in6_addr vfe_mask;
int vfe_flags;
#define VFEF_EXACT 0x0001
};
struct listaddr {
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
struct sockaddr_in6 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 */
struct sockaddr_in6 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: unnecessary for mld */
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)MAXMIFS) /* 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 sockaddr_in6 source; /* the source for which we want iif and rpfnbr */
struct sockaddr_in6 rpfneighbor;/* next hop towards the source */
vifi_t iif; /* the incoming interface to reach the next hop */
};

126
usr.sbin/pim6sd/BUGS.TODO Normal file
View File

@ -0,0 +1,126 @@
$Id: BUGS.TODO,v 1.1.1.1 1999/08/08 23:30:57 itojun Exp $
$FreeBSD$
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.
* 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
===TODO 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")
================DONE=====================
* When receive PIM_REGISTER, check whether I am the chosen RP

10
usr.sbin/pim6sd/BUGS.V6 Normal file
View File

@ -0,0 +1,10 @@
$FreeBSD$
Write your bugs reports here
BSR and Cand_rp discovery (base mecanism ): fixed
Encap/decap and unicast register send : fixed.
Join/Prune messages: They are sent but the RP don't create the (*,G) entry: fixed.
Check with the sockaddr6_any and sockaddr_d (not sure it works because of the scope..)
Pb with filling the upstream neighbor:fixed
to query groups at boot time not efficient because there is no RP

View File

@ -0,0 +1,49 @@
$FreeBSD$
The mrouted program is covered by the following license. Use of the
mrouted program represents acceptance of these terms and conditions.
1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
to use, copy and modify the computer software ``mrouted'' (hereinafter
called the ``Program''), upon the terms and conditions hereinafter set
out and until Licensee discontinues use of the Licensed Program.
2. LICENSEE acknowledges that the Program is a research tool still in
the development state, that it is being supplied ``as is,'' without any
accompanying services from STANFORD, and that this license is entered
into in order to encourage scientific collaboration aimed at further
development and application of the Program.
3. LICENSEE may copy the Program and may sublicense others to use object
code copies of the Program or any derivative version of the Program.
All copies must contain all copyright and other proprietary notices found
in the Program as provided by STANFORD. Title to copyright to the
Program remains with STANFORD.
4. LICENSEE may create derivative versions of the Program. LICENSEE
hereby grants STANFORD a royalty-free license to use, copy, modify,
distribute and sublicense any such derivative works. At the time
LICENSEE provides a copy of a derivative version of the Program to a
third party, LICENSEE shall provide STANFORD with one copy of the source
code of the derivative version at no charge to STANFORD.
5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
for any liability nor for any direct, indirect or consequential damages
with respect to any claim by LICENSEE or any third party on account of or
arising from this Agreement or use of the Program.
6. This agreement shall be construed, interpreted and applied in
accordance with the State of California and any legal action arising
out of this Agreement or use of the Program shall be filed in a court
in the State of California.
7. Nothing in this Agreement shall be construed as conferring rights to
use in advertising, publicity or otherwise any trademark or the name
of ``Stanford''.
The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
* $FreeBSD$
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: LICENSE.pimd,v 1.1.1.1 1999/08/08 23:30:57 itojun 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.
*
* $FreeBSD$
*/

49
usr.sbin/pim6sd/Makefile Normal file
View File

@ -0,0 +1,49 @@
# Copyright (c) 1999 WIDE Project. 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.
# $FreeBSD$
PROG= pim6sd
SRCS= mld6.c mld6_proto.c\
inet6.c kern.c main.c config.c debug.c routesock.c vers.c callout.c\
route.c vif.c timer.c mrt.c pim6.c pim6_proto.c rp.c crc.c trace.c\
cfparse.y cftoken.l
SRCS+= y.tab.h
y.tab.h: cfparse.y
CLEANFILES+= lex.yy.c y.tab.h y.tab.c
CFLAGS+= -g
CFLAGS+=-DINET6 -DPIM -DIOCTL_OK_ON_RAW_SOCKET -I${.OBJDIR}
CFLAGS+=-DHAVE_STDARG_H
LDADD+= -ly -ll
MAN1= pim6stat.1
MAN5= pim6sd.conf.5
MAN8= pim6sd.8
afterinstall:
install ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${INSTALLFLAGS} ${SRCDIR}/pim6stat ${DESTDIR}${BINDIR}
.include <bsd.prog.mk>

85
usr.sbin/pim6sd/README Normal file
View File

@ -0,0 +1,85 @@
$Id: README,v 1.1.1.1 1999/08/08 23:30:57 itojun Exp $
$FreeBSD$
WARNING! WARNING! WARNING!
THIS RELEASE IS VERY ALPHA, SO PLEASE DO NOT REDISTRIBUTE AND
DO NOT TRY IT OUTSIDE OF YOUR TESTBED.
This is README for pimd, the PIM multicast daemon.
PIM-SM version: 2
Check ftp://catarina.usc.edu/pub/pim/pimd/ for lastest version.
SUPPORTED PLATFORMS: FreeBSD-2.2.*, SunOS-4.1.3, Solaris-2.5.1 and 2.6,
SGI, BSDI 3.0/3.1, NetBSD-1.3
AVAILABLE PIM kernel patches: FreeBSD-2.2.1, FreeBSD-2.2.2, FreeBSD-2.2,5,
SunOS-4.1.3, SGI, BSDI-3.0, BSDI-3.1, NetBSD-1.3
Linux: pimd compiles under Linux, and linux-2.1.103 seems to have PIM-SMv2
kernel support, but I haven't tested whether the kernel patches really work.
FAST START (read "fast explanation" :))
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" 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.
Pavlin Ivanov Radoslavov
pavlin@catarina.usc.edu
ACKNOWLEDGEMENTS:
* The PIM kernel modifications and pimd itself were originally
written by Ahmed Helmy (ahelmy@catarina.usc.edu) as a summer intern in SGI.
* The "up to the March '97 I-D spec" + RSVP support pimd version was done
during my 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 <hwr@pilhuhn.de>
* 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" <jd9812@my-dejanews.com> and
Fred Griffoul <griffoul@ccrle.nec.de>
* 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.

View File

@ -0,0 +1,15 @@
$FreeBSD$
WARNING WARNING WARNING:
This is Pim Sparse Mode for IPv6. BUT IT HAS STILL SOME PROBLEMS !
So , before trying to run it , take a look to the code.
THIS VERSION NEEDS :
lots of debugging work...
AND : more debugging work :)
Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.

316
usr.sbin/pim6sd/callout.c Normal file
View File

@ -0,0 +1,316 @@
/*
* 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
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* $FreeBSD$
*/
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include "debug.h"
#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 __P((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)
log(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)
{
log(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)
log(LOG_DEBUG, 0, "setting timer:");
print_Q();
#endif
/* create a node */
node = (struct timeout_q *) malloc(sizeof(struct timeout_q));
if (node == 0)
{
log(LOG_WARNING, 0, "Malloc Failed 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)
log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
}
#endif /* CALLOUT_DEBUG2 */

62
usr.sbin/pim6sd/callout.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* $FreeBSD$
*/
#ifndef CALLOUT_H
#define CALLOUT_H
#include "defs.h"
extern void callout_init __P((void));
extern void free_all_callouts __P((void));
extern void age_callout_queue __P((int));
extern int timer_nextTimer __P((void));
extern int timer_setTimer __P((int, cfunc_t, void *));
extern void timer_clearTimer __P((int));
extern int timer_leftTimer __P((int));
#endif

55
usr.sbin/pim6sd/cfparse.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*
* $FreeBSD$
*/
#if defined(YIPS_DEBUG)
# define DP(str) YIPSDEBUG(DEBUG_CONF, cfdebug_print(str, yytext, yyleng))
# define YYD_ECHO \
{ YIPSDEBUG(DEBUG_CONF, printf("<%d>", yy_start); ECHO ; printf("\n");); }
# define YIPSDP(cmd) YIPSDEBUG(DEBUG_CONF, cmd)
# define PLOG printf
#else
# define DP(str)
# define YYD_ECHO
# define YIPSDP(cmd)
# define PLOG(cmd)
#endif /* defined(YIPS_DEBUG) */
/* cfparse.y */
extern void cf_init __P((int, int));
#ifdef notyet
extern int re_cfparse __P((void));
#endif
extern int cf_post_config __P((void));
extern int yyparse __P((void));
/* cftoken.l */
extern void yyerror __P((char *, ...));
extern void yywarn __P((char *, ...));
extern int cfparse __P((int, int));

960
usr.sbin/pim6sd/cfparse.y Normal file
View File

@ -0,0 +1,960 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*
* $FreeBSD$
*/
%{
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <syslog.h>
#include "defs.h"
#include "rp.h"
#include "vif.h"
#include "var.h"
#include "vmbuf.h"
#include "cfparse.h"
#include "debug.h"
#include "pimd.h"
#include "timer.h"
#include "inet6.h"
#define set_param(var,val,p) \
do {\
if ((var) != -1) {\
yywarn("%s doubly defined(ignore %d)", (p), (val));\
}\
else {\
(var) = val;\
}\
} while(0)
struct in6_prefix {
struct in6_addr paddr;
int plen;
};
struct attr_list {
struct attr_list *next;
int type;
union {
unsigned int flags;
double number;
struct in6_prefix prefix;
}attru;
};
enum {IFA_FLAG, IFA_PREFERENCE, IFA_METRIC, RPA_PRIORITY, RPA_TIME,
BSRA_PRIORITY, BSRA_TIME, IN6_PREFIX, THRESA_RATE, THRESA_INTERVAL};
static int strict; /* flag if the grammer check is strict */
static struct attr_list *rp_attr, *bsr_attr, *grp_prefix, *regthres_attr,
*datathres_attr;
static char *cand_rp_ifname, *cand_bsr_ifname;
static int srcmetric, srcpref, helloperiod, jpperiod, granularity,
datatimo, regsuptimo, probetime, asserttimo;
static double helloperiod_coef, jpperiod_coef;
static int debugonly;
%}
%union {
unsigned long num;
double fl;
vchar_t val;
struct attr_list *attr;
}
%token EOS
%token LOGGING LOGLEV NOLOGLEV
%token YES NO
%token REVERSELOOKUP
%token PHYINT IFNAME DISABLE PREFERENCE METRIC NOLISTENER
%token GRPPFX
%token CANDRP CANDBSR TIME PRIORITY
%token NUMBER STRING SLASH
%token REGTHRES DATATHRES RATE INTERVAL
%token SRCMETRIC SRCPREF HELLOPERIOD GRANULARITY JPPERIOD
%token DATATIME REGSUPTIME PROBETIME ASSERTTIME
%type <num> LOGLEV NOLOGLEV
%type <fl> NUMBER
%type <val> STRING IFNAME
%type <attr> if_attributes rp_substatement rp_attributes
%type <attr> bsr_substatement bsr_attributes thres_attributes
%%
statements:
/* empty */
| statements statement
;
statement:
logging_statement
| reverselookup_statement
| phyint_statement
| candrp_statement
| candbsr_statement
| grppfx_statement
| regthres_statement
| datathres_statement
| param_statement
;
/* logging */
logging_statement:
LOGGING log_specs EOS
;
log_specs:
/* empty */
| log_specs LOGLEV {debug |= $2;}
| log_specs NOLOGLEV {debug &= ~($2);}
;
/* reverselookup */
reverselookup_statement:
REVERSELOOKUP YES EOS { numerichost = FALSE; }
| REVERSELOOKUP NO EOS { numerichost = TRUE; }
;
/* phyint */
phyint_statement:
PHYINT IFNAME if_attributes EOS {
struct uvif *v;
v = find_vif($2.v);
free($2.v); /* XXX */
if (v == NULL) {
yywarn("unknown interface: %s", $2.v);
free_attr_list($3);
if (strict)
return(-1);
}
else {
struct attr_list *p;
for (p = (struct attr_list *)v->config_attr;
p && p->next; p = p->next)
;
if (p)
p->next = (void *)$3;
else
v->config_attr = (void *)$3;
}
}
;
if_attributes:
{ $$ = NULL; }
| if_attributes DISABLE
{
if (($$ = add_attribute_flag($1, IFA_FLAG,
VIFF_DISABLED)) == NULL)
return(-1);
}
| if_attributes NOLISTENER
{
if (($$ = add_attribute_flag($1, IFA_FLAG,
VIFF_NOLISTENER)) == NULL)
return(-1);
}
| if_attributes PREFERENCE NUMBER
{
if (($$ = add_attribute_num($1, IFA_PREFERENCE, $3))
== NULL)
return(-1);
}
| if_attributes METRIC NUMBER
{
if (($$ = add_attribute_num($1, IFA_METRIC, $3))
== NULL)
return(-1);
}
;
/* cand_rp */
candrp_statement:
CANDRP rp_substatement EOS {
if (cand_rp_flag == TRUE) {
yywarn("cand_rp doubly defined");
free_attr_list($2);
if (strict)
return(-1);
}
else {
cand_rp_flag = TRUE;
rp_attr = $2;
}
}
;
/* XXX: intermediate rule to avoid shift-reduce conflict */
rp_substatement:
IFNAME rp_attributes
{
if (cand_rp_ifname) {
yywarn("ifname for cand_rp doubly defined");
if (strict)
return(-1);
}
else
cand_rp_ifname = $1.v;
$$ = $2;
}
| rp_attributes
;
rp_attributes:
{ $$ = NULL; }
| rp_attributes PRIORITY NUMBER
{
if (($$ = add_attribute_num($1, RPA_PRIORITY, $3))
== NULL)
return(-1);
}
| rp_attributes TIME NUMBER
{
if (($$ = add_attribute_num($1, RPA_TIME, $3))
== NULL)
return(-1);
}
;
/* cand_bootstrap_router */
candbsr_statement:
CANDBSR bsr_substatement EOS {
if (cand_bsr_flag == TRUE) {
yywarn("cand_bsr doubly defined");
free_attr_list($2);
if (strict)
return(-1);
}
else {
cand_bsr_flag = TRUE;
bsr_attr = $2;
}
}
;
/* XXX: intermediate rule to avoid shift-reduce conflict */
bsr_substatement:
IFNAME bsr_attributes
{
if (cand_bsr_ifname) {
yywarn("ifname for cand_bsr doubly defined");
if (strict)
return(-1);
}
else
cand_bsr_ifname = $1.v;
$$ = $2;
}
| bsr_attributes
;
bsr_attributes:
{ $$ = NULL; }
| bsr_attributes PRIORITY NUMBER
{
if (($$ = add_attribute_num($1, BSRA_PRIORITY, $3))
== NULL)
return(-1);
}
| bsr_attributes TIME NUMBER
{
if (($$ = add_attribute_num($1, BSRA_TIME, $3))
== NULL)
return(-1);
}
;
/* group_prefix <group-addr>/<prefix_len> */
grppfx_statement:
GRPPFX STRING SLASH NUMBER EOS {
struct in6_prefix prefix;
int prefixok = 1;
if (inet_pton(AF_INET6, $2.v, &prefix.paddr) != 1) {
yywarn("invalid IPv6 address: %s (ignored)", $2);
prefixok = 0;
}
free($2.v); /* XXX: which was allocated dynamically */
prefix.plen = $4;
if (prefix.plen < 0 || prefix.plen > 128) {
yywarn("invalid prefix length: %d (ignored)",
prefix.plen);
prefixok = 0;
}
if (prefixok) {
struct attr_list *new;
if ((new = malloc(sizeof(*new))) == NULL) {
yyerror("malloc failed");
return(NULL);
}
memset(new, 0, sizeof(*new));
new->type = IN6_PREFIX;
new->attru.prefix = prefix;
new->next = grp_prefix;
grp_prefix = new;
}
}
;
/*
* switch_register_threshold [rate <number> interval <number>]
* 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).
*/
regthres_statement:
REGTHRES thres_attributes EOS {
if (regthres_attr) {
yywarn("switch_register_threshold doubly defined");
free_attr_list($2);
if (strict)
return(-1);
}
else
regthres_attr = $2;
}
;
thres_attributes:
{ $$ = NULL; }
| thres_attributes RATE NUMBER
{
if (($$ = add_attribute_num($1, THRESA_RATE, $3))
== NULL)
return(-1);
}
| thres_attributes INTERVAL NUMBER
{
if (($$ = add_attribute_num($1, THRESA_INTERVAL, $3))
== NULL)
return(-1);
}
/*
* switch_data_threshold [rate <number> interval <number>]
* Operation: reads and assigns the switch to the spt threshold due to
* data packets, if used as DR.
*/
datathres_statement:
DATATHRES thres_attributes EOS {
if (datathres_attr) {
yywarn("switch_data_threshold doubly defined");
free_attr_list($2);
if (strict)
return(-1);
}
else
datathres_attr = $2;
}
;
param_statement:
SRCMETRIC NUMBER EOS
{
set_param(srcmetric, $2, "default_source_metric");
}
| SRCPREF NUMBER EOS
{
set_param(srcpref, $2, "default_source_preference");
}
| HELLOPERIOD NUMBER EOS
{
set_param(helloperiod, $2, "hello_period");
}
| HELLOPERIOD NUMBER NUMBER EOS
{
set_param(helloperiod, $2, "hello_period");
set_param(helloperiod_coef, $3, "hello_period(coef)");
}
| JPPERIOD NUMBER EOS
{
set_param(jpperiod, $2, "join_prune_period");
}
| JPPERIOD NUMBER NUMBER EOS
{
set_param(jpperiod, $2, "join_prune_period");
set_param(jpperiod_coef, $3, "join_prune_period(coef)");
}
| GRANULARITY NUMBER EOS
{
set_param(granularity, $2, "granularity");
}
| REGSUPTIME NUMBER EOS
{
set_param(regsuptimo, $2, "register_suppression_timeout");
}
| PROBETIME NUMBER EOS
{
set_param(probetime, $2, "probe_time");
}
| ASSERTTIME NUMBER EOS
{
set_param(asserttimo, $2, "assert_timeout");
}
;
%%
static struct attr_list *
add_attribute_flag(list, type, flag)
struct attr_list *list;
int type;
unsigned int flag;
{
struct attr_list *p;
if ((p = malloc(sizeof(*p))) == NULL) {
yyerror("malloc failed");
return(NULL);
}
memset((void *)p, 0, sizeof(*p));
p->type = type;
p->attru.flags = flag;
p->next = list;
return(p);
}
/* XXX: too many dup code... */
static struct attr_list *
add_attribute_num(list, type, num)
struct attr_list *list;
int type;
double num;
{
struct attr_list *p;
if ((p = malloc(sizeof(*p))) == NULL) {
yyerror("malloc failed");
return(NULL);
}
memset((void *)p, 0, sizeof(*p));
p->type = type;
p->attru.number = num;
p->next = list;
return(p);
}
static void
free_attr_list(list)
struct attr_list *list;
{
struct attr_list *p, *next;
for(p = list; p; p = next) {
next = p->next;
free(p);
}
}
int
param_config()
{
struct uvif *v;
vifi_t vifi;
/* at first, set the default values to all the undefined variables */
if (srcmetric == -1) srcmetric = DEFAULT_LOCAL_METRIC;
if (srcpref == -1) srcpref = DEFAULT_LOCAL_PREF;
if (helloperiod == -1) helloperiod = PIM_TIMER_HELLO_PERIOD;
if (helloperiod_coef == -1) helloperiod_coef = 3.5;
if (jpperiod == -1) jpperiod = PIM_JOIN_PRUNE_PERIOD;
if (jpperiod_coef == -1) jpperiod_coef = 3.5;
if (granularity == -1) granularity = DEFAULT_TIMER_INTERVAL;
if (datatimo == -1) datatimo = PIM_DATA_TIMEOUT;
if (regsuptimo == -1) regsuptimo = PIM_REGISTER_SUPPRESSION_TIMEOUT;
if (probetime == -1) probetime = PIM_REGISTER_PROBE_TIME;
if (asserttimo == -1) asserttimo = PIM_ASSERT_TIMEOUT;
/* set protocol parameters using the configuration variables */
for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
v->uv_local_metric = srcmetric;
v->uv_local_pref = srcpref;
}
pim_hello_period = helloperiod;
pim_hello_holdtime = helloperiod * helloperiod_coef;
pim_join_prune_period = jpperiod;
pim_join_prune_holdtime = jpperiod * jpperiod_coef;
timer_interval = granularity;
pim_data_timeout = datatimo;
pim_register_suppression_timeout = regsuptimo;
pim_register_probe_time = probetime;
pim_assert_timeout = asserttimo;
IF_DEBUG(DEBUG_PIM_HELLO) {
log(LOG_DEBUG, 0, "pim_hello_period set to: %u",
pim_hello_period);
log(LOG_DEBUG, 0, "pim_hello_holdtime set to: %u",
pim_hello_holdtime);
}
IF_DEBUG(DEBUG_PIM_JOIN_PRUNE) {
log(LOG_DEBUG,0 , "pim_join_prune_period set to: %u",
pim_join_prune_period);
log(LOG_DEBUG, 0, "pim_join_prune_holdtime set to: %u",
pim_join_prune_holdtime);
}
return(0);
}
int
phyint_config()
{
struct uvif *v;
vifi_t vifi;
struct attr_list *al;
for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v) {
for (al = (struct attr_list *)v->config_attr; al; al = al->next) {
switch(al->type) {
case IFA_FLAG:
v->uv_flags |= al->attru.flags;
break;
case IFA_PREFERENCE:
if (al->attru.number < 1 ||
al->attru.number > 255)
yywarn("invalid phyint preference(%d)",
(int)al->attru.number);
else {
v->uv_local_pref = al->attru.number;
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG, 0,
"default localpref for %s "
"is %d",
v->uv_name,
v->uv_local_pref);
}
break;
case IFA_METRIC:
if (al->attru.number < 1 ||
al->attru.number > 1024)
yywarn("invalid metric(%d)",
al->attru.number);
else {
v->uv_metric = al->attru.number;
IF_DEBUG(DEBUG_ASSERT)
log(LOG_DEBUG, 0,
"default local metric for %s "
"is %d",
v->uv_name,
v->uv_metric);
}
break;
}
}
}
return(0);
}
int
rp_config()
{
struct sockaddr_in6 *sa6_rp = NULL;
struct attr_list *al;
u_int8 *data_ptr;
/* initialization by default values */
my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
my_cand_rp_priority = PIM_DEFAULT_CAND_RP_PRIORITY;
if (cand_rp_ifname) {
sa6_rp = local_iface(cand_rp_ifname);
if (!sa6_rp)
log(LOG_WARNING, 0,
"cand_rp '%s' is not configured. "
"take the max local address the router..",
cand_rp_ifname);
}
for (al = rp_attr; al; al = al->next) {
switch(al->type) {
case RPA_PRIORITY:
if (al->attru.number < 0)
my_cand_rp_priority =
PIM_DEFAULT_CAND_RP_PRIORITY;
else
my_cand_rp_priority = al->attru.number;
break;
case RPA_TIME:
if (al->attru.number < 10)
my_cand_rp_adv_period = 10;
else if (al->attru.number > PIM_DEFAULT_CAND_RP_ADV_PERIOD)
my_cand_rp_adv_period =
PIM_DEFAULT_CAND_RP_ADV_PERIOD;
else
my_cand_rp_adv_period = al->attru.number;
break;
default:
yywarn("unknown attribute(%d) for RP", al->type);
break;
}
}
if (!sa6_rp)
sa6_rp = max_global_address(); /* this MUST suceed */
my_cand_rp_address = *sa6_rp;
/*
* initialize related parameters
*/
/*
* Note that sizeof(pim6_enocd_uni_addr_t) might be larger than
* the length of the Encoded-Unicast-address field(18 byte) due to
* some padding put in the compiler. However, it doesn't matter
* since we use the space just as a buffer(i.e not as the message).
*/
cand_rp_adv_message.buffer = (u_int8 *)malloc(4 +
sizeof(pim6_encod_uni_addr_t) +
255*sizeof(pim6_encod_grp_addr_t));
if(cand_rp_adv_message.buffer == NULL)
log(LOG_ERR, 0, "Candrpadv Buffer allocation");
cand_rp_adv_message.prefix_cnt_ptr = cand_rp_adv_message.buffer;
/*
* By default, if no group_prefix configured, then prefix_cnt == 0
* implies group_prefix = ff00::/8 and masklen = 8.
*/
*cand_rp_adv_message.prefix_cnt_ptr = 0;
cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
/* TODO: XXX: HARDCODING!!! */
cand_rp_adv_message.insert_data_ptr += (4 + 18);
cand_rp_adv_message.message_size =
cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
/* TODO: HARDCODING! */
data_ptr = cand_rp_adv_message.buffer + 1; /* WARNING */
PUT_BYTE(my_cand_rp_priority,data_ptr);
PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
PUT_EUADDR6(my_cand_rp_address.sin6_addr,data_ptr);
IF_DEBUG(DEBUG_PIM_CAND_RP) {
log(LOG_DEBUG, 0,
"Local Cand-RP address is : %s",
inet6_fmt(&my_cand_rp_address.sin6_addr));
log(LOG_DEBUG, 0,
"Local Cand-RP priority is : %u",my_cand_rp_priority);
log(LOG_DEBUG, 0,
"Local Cand-RP advertisement period is : %u sec.",
my_cand_rp_adv_period);
}
return(0);
}
int
bsr_config()
{
struct sockaddr_in6 *sa6_bsr = NULL;
struct attr_list *al;
/* initialization by default values */
my_bsr_period = PIM_DEFAULT_BOOTSTRAP_PERIOD;
my_bsr_priority = PIM_DEFAULT_BSR_PRIORITY;
if (cand_bsr_ifname) {
sa6_bsr = local_iface(cand_bsr_ifname);
if (!sa6_bsr)
log(LOG_WARNING, 0,
"bsr '%s' is not configured. "
"take the max local address the router..",
cand_bsr_ifname);
}
for (al = bsr_attr; al; al = al->next) {
switch(al->type) {
case BSRA_PRIORITY:
if (al->attru.number >= 0)
my_bsr_priority = al->attru.number;
break;
case BSRA_TIME:
if (al->attru.number < 10)
my_bsr_period = 10;
else if (al->attru.number > PIM_DEFAULT_BOOTSTRAP_PERIOD)
my_bsr_period =
PIM_DEFAULT_BOOTSTRAP_PERIOD;
else
my_bsr_period = al->attru.number;
break;
default:
yywarn("unknown attribute(%d) for BSR", al->type);
break;
}
}
if (!sa6_bsr)
sa6_bsr = max_global_address(); /* this MUST suceed */
my_bsr_address = *sa6_bsr;
IF_DEBUG(DEBUG_PIM_BOOTSTRAP) {
log(LOG_DEBUG, 0,
"Local BSR address: %s",
inet6_fmt(&my_bsr_address.sin6_addr));
log(LOG_DEBUG, 0,
"Local BSR priority : %u",my_bsr_priority);
log(LOG_DEBUG,0,
"Local BSR period is : %u sec.",
my_bsr_period);
}
return(0);
}
int
grp_prefix_config()
{
struct attr_list *pl;
if (cand_rp_flag != TRUE) {
log(LOG_WARNING, 0,
"group_prefix was specified without cand_rp(ignored)");
return(0);
}
for (pl = grp_prefix; pl; pl = pl->next) {
if (!IN6_IS_ADDR_MULTICAST(&pl->attru.prefix.paddr)) {
log(LOG_WARNING, 0,
"Config error: %s is not a mulicast address(ignored)",
inet6_fmt(&pl->attru.prefix.paddr));
continue;
}
if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) {
log(LOG_WARNING, 0,
"Too many group_prefix configured. Truncating...");
break;
}
/* validation for plen has almost done */
if (pl->attru.prefix.plen < PIM_GROUP_PREFIX_DEFAULT_MASKLEN)
pl->attru.prefix.plen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
PUT_EGADDR6(pl->attru.prefix.paddr,
(u_int8)pl->attru.prefix.plen, 0,
cand_rp_adv_message.insert_data_ptr);
(*cand_rp_adv_message.prefix_cnt_ptr)++;
}
/* finally, adjust the data size */
cand_rp_adv_message.message_size =
cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
return(0);
}
int
regthres_config()
{
struct attr_list *al;
int rate = -1;
int interval = -1;
if (cand_rp_flag != TRUE) {
log(LOG_WARNING, 0,
"register_threshold was specified without cand_rp");
}
for (al = regthres_attr; al; al = al->next) {
switch(al->type) {
case THRESA_RATE:
if (al->attru.number < 0)
yywarn("invalid regthres rate: %d(ignored)",
al->attru.number);
else if (rate != -1)
yywarn("regthres rate is doubly defined(ignored)");
else
rate = al->attru.number;
break;
case THRESA_INTERVAL:
if (al->attru.number < 0)
yywarn("invalid regthres interval: %d(ignored)",
al->attru.number);
else if (interval != -1)
yywarn("regthres interval is doubly defined(ignored)");
else
interval = al->attru.number;
break;
default:
yywarn("unknown attribute(%d) for regthres", al->type);
break;
}
}
/* set default values if not specified */
if (rate == -1)
rate = PIM_DEFAULT_REG_RATE;
if (interval == -1)
interval = PIM_DEFAULT_REG_RATE_INTERVAL;
pim_reg_rate_bytes = (rate * interval ) /10;
pim_reg_rate_check_interval = interval;
return(0);
}
int
datathres_config()
{
struct attr_list *al;
int rate = -1;
int interval = -1;
for (al = datathres_attr; al; al = al->next) {
switch(al->type) {
case THRESA_RATE:
if (al->attru.number < 0)
yywarn("invalid datathres rate: %d(ignored)",
al->attru.number);
else if (rate != -1)
yywarn("datathres rate is doubly defined(ignored)");
else
rate = al->attru.number;
break;
case THRESA_INTERVAL:
if (al->attru.number < 0)
yywarn("invalid datathres interval: %d(ignored)",
al->attru.number);
else if (interval != -1)
yywarn("datathres interval is doubly defined(ignored)");
else
interval = al->attru.number;
break;
default:
yywarn("unknown attribute(%d) for datathres", al->type);
break;
}
}
/* set default values if not specified */
if (rate == -1)
rate = PIM_DEFAULT_DATA_RATE;
if (interval == -1)
interval = PIM_DEFAULT_DATA_RATE_INTERVAL;
pim_data_rate_bytes = (rate * interval ) /10;
pim_data_rate_check_interval = interval;
return(0);
}
int
cf_post_config()
{
struct uvif *v;
vifi_t vifi;
if (debugonly)
goto cleanup;
param_config(); /* must be called before phyint_conifg() */
phyint_config();
if (cand_bsr_flag == TRUE)
bsr_config();
if (cand_rp_flag == TRUE)
rp_config();
if (grp_prefix) /* this must be called after rp_config() */
grp_prefix_config();
if (cand_rp_flag == TRUE)
regthres_config();
datathres_config();
IF_DEBUG(DEBUG_SWITCH) {
log(LOG_DEBUG, 0, "reg_rate_limit set to %u (bits/s)",
pim_reg_rate_bytes);
log(LOG_DEBUG, 0, "reg_rate_interval set to %u s.",
pim_reg_rate_check_interval);
log(LOG_DEBUG, 0, "data_rate_limit set to %u (bits/s)",
pim_data_rate_bytes);
log(LOG_DEBUG, 0, "data_rate_interval set to %u s.",
pim_data_rate_check_interval);
}
cleanup:
/* cleanup temporary variables */
if (cand_rp_ifname) free(cand_rp_ifname);
if (cand_bsr_ifname) free(cand_bsr_ifname);
if (rp_attr) free_attr_list(rp_attr);
if (bsr_attr) free_attr_list(bsr_attr);
if (grp_prefix) free_attr_list(grp_prefix);
if (regthres_attr) free_attr_list(regthres_attr);
if (datathres_attr) free_attr_list(datathres_attr);
for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v)
free_attr_list((struct attr_list *)v->config_attr);
return(0);
}
/* initialize all the temporary variables */
void
cf_init(s, d)
{
struct uvif *v;
vifi_t vifi;
strict = s;
debugonly = d;
debug = 0;
rp_attr = bsr_attr = grp_prefix = regthres_attr = datathres_attr = NULL;
cand_rp_ifname = cand_bsr_ifname = NULL;
srcmetric = srcpref = helloperiod = jpperiod = jpperiod_coef
= granularity = datatimo = regsuptimo = probetime
= asserttimo = -1;
helloperiod_coef = jpperiod_coef = -1;
for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v)
v->config_attr = NULL;
}

657
usr.sbin/pim6sd/cftoken.l Normal file
View File

@ -0,0 +1,657 @@
%{
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "var.h"
#include "vmbuf.h"
#include "debug.h"
#include "cfparse.h"
#include "y.tab.h"
static int yyerrorcount = 0;
int lineno = 1;
int yy_first_time = 1;
extern char configfilename[];
static void cfdebug_print __P((char *, char *, int));
%}
/* common seciton */
nl \n
ws [ \t]+
comment \#.*
semi \;
string [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*
digit [0-9]
integer {digit}+
number {integer}|({digit}*\.{integer})
hexdigit [0-9A-Fa-f]
hexpair {hexdigit}{hexdigit}
hexstring 0[xX]{hexpair}+
ifname [a-zA-Z]+[0-9]+
slash \/
%s S_CNF
%s S_LOG
%s S_PHYINT S_IFCONF S_CANDRP S_CANDBSR S_PREFIX
%s S_THRES
%%
%{
if (yy_first_time) {
BEGIN S_CNF;
yy_first_time = 0;
}
%}
/* logging */
<S_CNF>log { DP("begin logging"); BEGIN S_LOG; return(LOGGING); }
<S_LOG>(no)?mld_proto {
YYD_ECHO;
yylval.num = DEBUG_MLD_PROTO;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mld_timer {
YYD_ECHO;
yylval.num = DEBUG_MLD_TIMER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mld_member {
YYD_ECHO;
yylval.num = DEBUG_MLD_MEMBER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mld {
YYD_ECHO;
yylval.num = DEBUG_MLD;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?switch {
YYD_ECHO;
yylval.num = DEBUG_SWITCH;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?m?trace {
YYD_ECHO;
yylval.num = DEBUG_TRACE;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?traceroute {
YYD_ECHO;
yylval.num = DEBUG_TRACE;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?timeout {
YYD_ECHO;
yylval.num = DEBUG_TIMEOUT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?callout {
YYD_ECHO;
yylval.num = DEBUG_TIMEOUT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pkt {
YYD_ECHO;
yylval.num = DEBUG_PKT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?packets {
YYD_ECHO;
yylval.num = DEBUG_PKT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?interfaces {
YYD_ECHO;
yylval.num = DEBUG_IF;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?vif {
YYD_ECHO;
yylval.num = DEBUG_IF;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?kernel {
YYD_ECHO;
yylval.num = DEBUG_KERN;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?cache {
YYD_ECHO;
yylval.num = DEBUG_MFC;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mfc {
YYD_ECHO;
yylval.num = DEBUG_MFC;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?k_cache {
YYD_ECHO;
yylval.num = DEBUG_MFC;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?k_mfc {
YYD_ECHO;
yylval.num = DEBUG_MFC;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?rsrr {
YYD_ECHO;
yylval.num = DEBUG_RSRR;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_detail {
YYD_ECHO;
yylval.num = DEBUG_PIM_DETAIL;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_hello {
YYD_ECHO;
yylval.num = DEBUG_PIM_HELLO;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_neighbors {
YYD_ECHO;
yylval.num = DEBUG_PIM_HELLO;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_register {
YYD_ECHO;
yylval.num = DEBUG_PIM_REGISTER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?registers {
YYD_ECHO;
yylval.num = DEBUG_PIM_REGISTER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_join_prune {
YYD_ECHO;
yylval.num = DEBUG_PIM_JOIN_PRUNE;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_j_p {
YYD_ECHO;
yylval.num = DEBUG_PIM_JOIN_PRUNE;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_jp {
YYD_ECHO;
yylval.num = DEBUG_PIM_JOIN_PRUNE;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_bootstrap {
YYD_ECHO;
yylval.num = DEBUG_PIM_BOOTSTRAP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_bsr {
YYD_ECHO;
yylval.num = DEBUG_PIM_BOOTSTRAP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?bsr {
YYD_ECHO;
yylval.num = DEBUG_PIM_BOOTSTRAP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?bootstrap {
YYD_ECHO;
yylval.num = DEBUG_PIM_BOOTSTRAP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_asserts {
YYD_ECHO;
yylval.num = DEBUG_PIM_ASSERT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_cand_rp {
YYD_ECHO;
yylval.num = DEBUG_PIM_CAND_RP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_c_rp {
YYD_ECHO;
yylval.num = DEBUG_PIM_CAND_RP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_rp {
YYD_ECHO;
yylval.num = DEBUG_PIM_CAND_RP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?rp {
YYD_ECHO;
yylval.num = DEBUG_PIM_CAND_RP;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_routes {
YYD_ECHO;
yylval.num = DEBUG_PIM_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_routing {
YYD_ECHO;
yylval.num = DEBUG_PIM_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_mrt {
YYD_ECHO;
yylval.num = DEBUG_PIM_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_timers {
YYD_ECHO;
yylval.num = DEBUG_PIM_TIMER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim_rpf {
YYD_ECHO;
yylval.num = DEBUG_PIM_RPF;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?rpf {
YYD_ECHO;
yylval.num = DEBUG_RPF;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?pim {
YYD_ECHO;
yylval.num = DEBUG_PIM;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?routes {
YYD_ECHO;
yylval.num = DEBUG_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?routing {
YYD_ECHO;
yylval.num = DEBUG_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mrt {
YYD_ECHO;
yylval.num = DEBUG_MRT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?routers {
YYD_ECHO;
yylval.num = DEBUG_NEIGHBORS;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?mrouters {
YYD_ECHO;
yylval.num = DEBUG_NEIGHBORS;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?neighbors {
YYD_ECHO;
yylval.num = DEBUG_NEIGHBORS;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?timers {
YYD_ECHO;
yylval.num = DEBUG_TIMER;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>(no)?asserts {
YYD_ECHO;
yylval.num = DEBUG_ASSERT;
if (strncmp("no", yytext, 2))
return(LOGLEV);
else
return(NOLOGLEV);
}
<S_LOG>all { YYD_ECHO; yylval.num = DEBUG_ALL; return(LOGLEV); }
<S_LOG>3 { YYD_ECHO; yylval.num = DEBUG_ALL; return(LOGLEV); }
<S_LOG>{semi} { DP("end logging"); BEGIN S_CNF; return(EOS); }
<S_LOG>{string} { yywarn("unknown log type: %s (ignored)", yytext); }
/* yes-or-no */
[yY][eE][sS] { YYD_ECHO; return(YES); }
[nN][oO] { YYD_ECHO; return(NO); }
/* reverselookup */
<S_CNF>reverselookup { YYD_ECHO; return(REVERSELOOKUP); }
/* phyint */
<S_CNF>phyint { DP("begin phyint"); BEGIN S_PHYINT; return(PHYINT); }
<S_PHYINT>{string} {
YYD_ECHO;
BEGIN S_IFCONF;
yylval.val.l = strlen(yytext);
yylval.val.v = strdup(yytext);
return(IFNAME);
}
<S_PHYINT>{semi} { yyerror("phyint was specified without interface."); return(EOS); }
<S_IFCONF>disable { YYD_ECHO; return(DISABLE); }
<S_IFCONF>preference { YYD_ECHO; return(PREFERENCE); }
<S_IFCONF>metric { YYD_ECHO; return(METRIC); }
<S_IFCONF>nolistener { YYD_ECHO; return(NOLISTENER); }
<S_IFCONF>{semi} { DP("end phyint"); BEGIN S_CNF; return(EOS); }
/* cand_rp */
<S_CNF>cand_rp { DP("begin cand_rp"); BEGIN S_CANDRP; return(CANDRP); }
<S_CANDRP>priority { YYD_ECHO; return(PRIORITY); }
<S_CANDRP>time { YYD_ECHO; return(TIME); }
<S_CANDRP>{ifname} {
YYD_ECHO;
yylval.val.l = strlen(yytext);
yylval.val.v = strdup(yytext);
return(IFNAME);
}
<S_CANDRP>{semi} { DP("end cand_rp"); BEGIN S_CNF; return(EOS); }
/* cand_bootstrap_router */
<S_CNF>cand_bootstrap_router { DP("begin cand_bsr"); BEGIN S_CANDBSR; return(CANDBSR); }
<S_CANDBSR>priority { YYD_ECHO; return(PRIORITY); }
<S_CANDBSR>time { YYD_ECHO; return(TIME); }
<S_CANDBSR>{ifname} {
YYD_ECHO;
yylval.val.l = strlen(yytext);
yylval.val.v = strdup(yytext);
return(IFNAME);
}
<S_CANDBSR>{semi} { DP("end cand_bsr"); BEGIN S_CNF; return(EOS); }
/* group_prefix */
<S_CNF>group_prefix { YYD_ECHO; return(GRPPFX); }
/* switch_register_threshold */
<S_CNF>switch_register_threshold {
YYD_ECHO; BEGIN S_THRES; return(REGTHRES);
}
/* switch_data_threshold */
<S_CNF>switch_data_threshold {
YYD_ECHO; BEGIN S_THRES; return(DATATHRES);
}
<S_THRES>rate { YYD_ECHO; return(RATE); }
<S_THRES>interval { YYD_ECHO; return(INTERVAL); }
<S_THRES>{semi} { DP("end thres"); BEGIN S_CNF; return(EOS); }
/* various parameters */
<S_CNF>default_source_metric { YYD_ECHO; return(SRCMETRIC); }
<S_CNF>default_source_preference { YYD_ECHO; return(SRCPREF); }
<S_CNF>hello_period { YYD_ECHO; return(HELLOPERIOD); }
<S_CNF>granularity { YYD_ECHO; return(GRANULARITY); }
<S_CNF>join_prune_period { YYD_ECHO; return(JPPERIOD); }
<S_CNF>data_timeout { YYD_ECHO; return(DATATIME); }
<S_CNF>register_suppression_timeout { YYD_ECHO; return(REGSUPTIME); }
<S_CNF>probe_time { YYD_ECHO; return(PROBETIME); }
<S_CNF>assert_timeout { YYD_ECHO; return(ASSERTTIME); }
/* misc */
{ws} { ; }
{nl} { lineno++; }
{comment} { DP("comment"); }
{number} { YYD_ECHO; yylval.fl = atof(yytext); return(NUMBER); }
{slash} { YYD_ECHO; return(SLASH); }
{semi} { DP("end cnf"); return(EOS); }
/* last resort */
{string} {
YYD_ECHO;
yylval.val.l = strlen(yytext);
yylval.val.v = strdup(yytext);
return(STRING);
}
%%
static void
cfdebug_print(w, t, l)
char *w, *t;
int l;
{
printf("<%d>%s [%s] (%d)\n", yy_start, w, t, l);
}
static void
yyerror0(char *s, va_list ap)
{
fprintf(stderr, "%s %d: ", configfilename, lineno);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
}
void
yyerror(char *s, ...)
{
va_list ap;
#ifdef HAVE_STDARG_H
va_start(ap, s);
#else
va_start(ap);
#endif
yyerror0(s, ap);
va_end(ap);
yyerrorcount++;
}
void
yywarn(char *s, ...)
{
va_list ap;
#ifdef HAVE_STDARG_H
va_start(ap, s);
#else
va_start(ap);
#endif
yyerror0(s, ap);
va_end(ap);
}
int
cfparse(strict, debugonly)
int strict, debugonly;
{
if ((yyin = fopen(configfilename, "r")) == NULL) {
fprintf(stderr, "cfparse: fopen(%s)", configfilename);
return(-1);
}
cf_init(strict, debugonly);
if ((yyparse() || yyerrorcount) && strict) {
if (yyerrorcount) {
yyerror("fatal parse failure: exiting (%d errors)",
yyerrorcount);
} else
yyerror("fatal parse failure: exiting");
return(-1);
}
YIPSDP(PLOG("parse successed.\n"));
return cf_post_config();
}

1609
usr.sbin/pim6sd/config.c Normal file

File diff suppressed because it is too large Load Diff

73
usr.sbin/pim6sd/config.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* $FreeBSD$
*/
#ifndef CONFIG_H
#define CONFIG_H
#define UNKNOWN -1
#define EMPTY 1
#define PHYINT 2
#define CANDIDATE_RP 3
#define GROUP_PREFIX 4
#define BOOTSTRAP_RP 5
#define REG_THRESHOLD 6
#define DATA_THRESHOLD 7
#define DEFAULT_SOURCE_METRIC 8
#define DEFAULT_SOURCE_PREFERENCE 9
#define HELLO_PERIOD 10
#define GRANULARITY 11
#define JOIN_PRUNE_PERIOD 12
#define DATA_TIMEOUT 13
#define REGISTER_SUPPRESSION_TIMEOUT 14
#define PROBE_TIME 15
#define ASSERT_TIMEOUT 16
#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
void config_vifs_from_kernel();
void config_vifs_from_file();
#endif

97
usr.sbin/pim6sd/crc.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* $FreeBSD$
*/
/* CRC implantation : stolen from RFC 2083 section 15.*/
/* Table of CRCs of all 8-bit messages. */
unsigned long crc_table[256];
/* Flag: has the table been computed? Initially false. */
int crc_table_computed = 0;
/* Make the table for a fast CRC. */
void make_crc_table(void)
{
unsigned long c;
int n, k;
for (n = 0; n < 256; n++)
{
c = (unsigned long) n;
for (k = 0; k < 8; k++)
{
if (c & 1)
c = 0xedb88320L ^ (c >> 1);
else
c = c >> 1;
}
crc_table[n] = c;
}
crc_table_computed = 1;
}
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
should be initialized to all 1's, and the transmitted value
is the 1's complement of the final running CRC (see the
crc() routine below)). */
unsigned long update_crc(unsigned long crc, unsigned char *buf,
int len)
{
unsigned long c = crc;
int n;
if (!crc_table_computed)
make_crc_table();
for (n = 0; n < len; n++)
{
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
}
return c;
}
/* Return the CRC of the bytes buf[0..len-1]. */
unsigned long crc(unsigned char *buf, int len)
{
return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
}

48
usr.sbin/pim6sd/crc.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef CRC_H
#define CRC_H
extern long crc __P((unsigned char *buf, int len));
#endif

910
usr.sbin/pim6sd/debug.c Normal file
View File

@ -0,0 +1,910 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <stdio.h>
#include <syslog.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip_mroute.h>
#include <netinet/icmp6.h>
#include <netinet6/pim6.h>
#include "pathnames.h"
#include "defs.h"
#include "pimd.h"
#include "debug.h"
#include "mrt.h"
#include "vif.h"
#include "rp.h"
#include "inet6.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
extern char *progname;
int log_nmsgs = 0;
unsigned long debug = 0x00000000; /* If (long) is smaller than 4 bytes,
* then we are in trouble. */
static char dumpfilename[] = _PATH_PIM6D_DUMP;
static char cachefilename[] = _PATH_PIM6D_CACHE; /* TODO: notused */
static char statfilename[] = _PATH_PIM6D_STAT;
char *
packet_kind(proto, type, code)
u_int proto,
type,
code;
{
static char unknown[60];
switch (proto)
{
case IPPROTO_ICMPV6:
switch (type)
{
case MLD6_LISTENER_QUERY:
return "Multicast Listener Query ";
case MLD6_LISTENER_REPORT:
return "Multicast Listener Report ";
case MLD6_LISTENER_DONE:
return "Multicast Listener Done ";
default:
sprintf(unknown,
"UNKNOWN ICMPv6 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:
sprintf(unknown, "UNKNOWN PIM v2 message type =%3d ", type);
return unknown;
}
default:
sprintf(unknown, "UNKNOWN proto =%3d ", proto);
return unknown;
}
}
/*
* Used for debugging particular type of messages.
*/
int
debug_kind(proto, type, code)
u_int proto,
type,
code;
{
switch (proto)
{
case IPPROTO_ICMPV6:
switch (type)
{
case MLD6_LISTENER_QUERY:
return DEBUG_MLD;
case MLD6_LISTENER_REPORT:
return DEBUG_MLD;
case MLD6_LISTENER_DONE:
return DEBUG_MLD;
default:
return DEBUG_MLD;
}
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_ICMPV6:
switch (type)
{
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(i)
int i;
{
FILE *fp;
fp = fopen(dumpfilename, "w");
if (fp != NULL)
{
dump_vifs(fp);
dump_nbrs(fp);
dump_pim_mrt(fp);
dump_rp_set(fp);
(void) fclose(fp);
}
}
/* TODO: dummy, to be used in the future. */
/*
* Dump local cache contents to a file.
*/
void
cdump(i)
int i;
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL)
{
/*
* TODO: implement it: dump_cache(fp);
*/
(void) fclose(fp);
}
}
void
dump_stat()
{
FILE *fp;
vifi_t vifi;
register struct uvif *v;
fp = fopen(statfilename, "w");
if (fp == NULL) {
log(LOG_WARNING, errno, "dump_stat: can't open file(%s)",
statfilename);
return;
}
fprintf(fp, "pim6sd per-interface statistics\n");
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
#if 0 /* is it better to skip them? */
if ((v->uv_flags & (VIFF_DISABLED|VIFF_DOWN)) != 0)
continue;
#endif
fprintf(fp, " Mif=%d, PhyIF=%s\n", vifi, v->uv_name);
fprintf(fp, "\t%qu pim6 hello received\n", v->uv_in_pim6_hello);
fprintf(fp, "\t%qu pim6 join-prune received\n",
v->uv_in_pim6_join_prune);
fprintf(fp, "\t%qu pim6 bootstrap received\n",
v->uv_in_pim6_bootsrap);
fprintf(fp, "\t%qu pim6 assert received\n", v->uv_in_pim6_assert);
fprintf(fp, "\t%qu pim6 hello sent\n", v->uv_out_pim6_hello);
fprintf(fp, "\t%qu pim6 join-prune sent\n",
v->uv_out_pim6_join_prune);
fprintf(fp, "\t%qu pim6 bootstrap sent\n",
v->uv_out_pim6_bootsrap);
fprintf(fp, "\t%qu pim6 assert sent\n", v->uv_out_pim6_assert);
fprintf(fp, "\t%qu MLD query received\n", v->uv_in_mld_query);
fprintf(fp, "\t%qu MLD report received\n", v->uv_in_mld_report);
fprintf(fp, "\t%qu MLD done received\n", v->uv_in_mld_done);
fprintf(fp, "\t%qu MLD query sent\n", v->uv_out_mld_query);
fprintf(fp, "\t%qu MLD report sent\n", v->uv_out_mld_report);
fprintf(fp, "\t%qu MLD done sent\n", v->uv_out_mld_done);
fprintf(fp, "\t%qu forwarding cache miss\n", v->uv_cache_miss);
fprintf(fp, "\t%qu forwarding cache miss and not created\n",
v->uv_cache_notcreated);
fprintf(fp, "\t%qu PIM neighbor timeouts\n", v->uv_pim6_nbr_timo);
fprintf(fp, "\t%qu MLD listener timeouts\n", v->uv_listener_timo);
fprintf(fp, "\t%qu out-I/F timeouts\n", v->uv_outif_timo);
}
fprintf(fp, "\npim6sd interface independent statistics\n");
fprintf(fp, "\t%qu pim6 register received\n", pim6dstat.in_pim6_register);
fprintf(fp, "\t%qu pim6 register-stop received\n",
pim6dstat.in_pim6_register_stop);
fprintf(fp, "\t%qu pim6 cand-RP received\n", pim6dstat.in_pim6_cand_rp);
fprintf(fp, "\t%qu pim6 graft received\n", pim6dstat.in_pim6_graft);
fprintf(fp, "\t%qu pim6 graft ack received\n",
pim6dstat.in_pim6_graft_ack);
fprintf(fp, "\t%qu pim6 register sent\n", pim6dstat.out_pim6_register);
fprintf(fp, "\t%qu pim6 register-stop sent\n",
pim6dstat.out_pim6_register_stop);
fprintf(fp, "\t%qu pim6 cand-RP sent\n", pim6dstat.out_pim6_cand_rp);
fprintf(fp, "\t%qu transitions of forwarder initiated SPT\n",
pim6dstat.pim6_trans_spt_forward);
fprintf(fp, "\t%qu transitions of RP initiated SPT\n",
pim6dstat.pim6_trans_spt_rp);
fprintf(fp, "\t%qu pim6 bootstrap timeouts\n",
pim6dstat.pim6_bootstrap_timo);
fprintf(fp, "\t%qu pim6 RP group entry timeouts\n",
pim6dstat.pim6_rpgrp_timo);
fprintf(fp, "\t%qu pim6 routing entry timeouts\n",
pim6dstat.pim6_rtentry_timo);
fprintf(fp, "\t%qu kernel cache additions\n", pim6dstat.kern_add_cache);
fprintf(fp, "\t%qu kernel cache addition failures\n",
pim6dstat.kern_add_cache_fail);
fprintf(fp, "\t%qu kernel cache deletions\n", pim6dstat.kern_del_cache);
fprintf(fp, "\t%qu kernel cache deletion failures\n",
pim6dstat.kern_del_cache_fail);
fprintf(fp, "\t%qu failures of getting kernel cache\n",
pim6dstat.kern_sgcnt_fail);
fclose(fp);
}
void
dump_vifs(fp)
FILE *fp;
{
vifi_t vifi;
register struct uvif *v;
struct phaddr *pa;
fprintf(fp, "\nMulticast Interface Table\n %-4s %-6s %-43s %5s %-14s\n",
"Mif", " PhyIF", "Local-Address/Prefixlen","Scope", "Flags");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
{
int firstaddr = 1;
for (pa = v->uv_addrs; pa; pa = pa->pa_next)
{
if (!firstaddr)
{
fprintf(fp, " %3s %6s %-43s", "", "",
net6name(&pa->pa_addr.sin6_addr,
&pa->pa_subnetmask));
fprintf(fp," %-5d\n", pa->pa_addr.sin6_scope_id);
continue;
}
firstaddr = 0;
fprintf(fp, " %-3u %6s %-43s", vifi,
(v->uv_flags & MIFF_REGISTER)?"regist":v->uv_name,
net6name(&pa->pa_addr.sin6_addr,
&pa->pa_subnetmask));
fprintf(fp," %-5d", pa->pa_addr.sin6_scope_id);
if (v->uv_flags & MIFF_REGISTER)
fprintf(fp, " REGISTER");
if (v->uv_flags & VIFF_DISABLED)
fprintf(fp, " DISABLED");
if (v->uv_flags & VIFF_NOLISTENER)
fprintf(fp, " NOLISTENER");
if (v->uv_flags & VIFF_DOWN)
fprintf(fp, " DOWN");
if (v->uv_flags & VIFF_DR)
fprintf(fp, " DR");
if (v->uv_flags & VIFF_PIM_NBR)
fprintf(fp, " PIM");
#if 0 /* impossible */
if (v->uv_flags & VIFF_DVMRP_NBR)
{
fprintf(fp, " DVMRP");
}
#endif
if (v->uv_flags & VIFF_NONBRS)
fprintf(fp, " %-12s", "NO-NBR");
fprintf(fp, "\n");
}
fprintf(fp, " %3s %6s ", "", "");
fprintf(fp, "Timers: PIM hello = %d:%02d, MLD query = %d:%02d\n",
v->uv_pim_hello_timer / 60, v->uv_pim_hello_timer % 60,
v->uv_gq_timer / 60, v->uv_gq_timer % 60);
}
fprintf(fp, "\n");
}
void
dump_nbrs(fp)
FILE *fp;
{
struct uvif *v;
vifi_t vifi;
pim_nbr_entry_t *n;
fprintf(fp, "PIM Neighbor List\n");
fprintf(fp, " %-3s %6s %-40s %-5s\n",
"Mif", "PhyIF", "Address", "Timer");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if ((n = v->uv_pim_neighbors) != NULL) {
int first = 1;
fprintf(fp, " %-3u %6s", vifi,
(v->uv_flags & MIFF_REGISTER)?"regist":
v->uv_name);
for (; n != NULL; n = n->next) {
if (first)
first = 0;
else
fprintf(fp, " %3s %6s", "", "");
fprintf(fp, " %-40s %-5u\n",
inet6_fmt(&n->address.sin6_addr),
n->timer);
}
}
}
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.
*/
#ifdef __STDC__
void
log(int severity, int syserr, char *format,...)
{
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
struct timeval now;
struct tm *thyme;
va_start(ap, format);
#else
/* VARARGS3 */
void
log(severity, syserr, format, va_alist)
int severity,
syserr;
char *format;
va_dcl
{
va_list ap;
static char fmt[311] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap);
#endif
vsprintf(&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 (debug || severity <= LOG_WARNING)
{
time_t t;
FILE *fp = log_fp ? log_fp : stderr;
gettimeofday(&now, NULL);
t = (time_t)now.tv_sec;
thyme = localtime(&t);
if (!debug)
fprintf(fp, "%s: ", progname);
fprintf(fp, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
if (syserr == 0)
fprintf(fp, "\n");
else
if (syserr < sys_nerr)
fprintf(fp, ": %s\n", sys_errlist[syserr]);
else
fprintf(fp, ": errno %d\n", 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: %m", msg);
}
else
syslog(severity, "%s", msg);
}
if (severity <= LOG_ERR)
exit(-1);
}
/* TODO: format the output for better readability */
void
dump_pim_mrt(fp)
FILE *fp;
{
grpentry_t *g;
register mrtentry_t *r;
register vifi_t vifi;
int i;
u_int number_of_cache_mirrors = 0;
u_int number_of_groups = 0;
char joined_oifs[(sizeof(if_set) << 3) + 1];
char asserted_oifs[(sizeof(if_set) << 3) + 1];
cand_rp_t *rp;
kernel_cache_t *kernel_cache;
char oifs[(sizeof(if_set) << 3) + 1];
char pruned_oifs[(sizeof(if_set) << 3) + 1];
char leaves_oifs[(sizeof(if_set) << 3) + 1];
char incoming_iif[(sizeof(if_set) << 3) + 1];
fprintf(fp, "Multicast Routing Table\n%s",
" Source Group RP-addr Flags\n");
/* TODO: remove the dummy 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", "IN6ADDR_ANY");
fprintf(fp, " %-15s", inet6_fmt(&g->group.sin6_addr));
fprintf(fp, " %-15s",
g->active_rp_grp ? inet6_fmt(&g->rpaddr.sin6_addr) : "NULL");
for (vifi = 0; vifi < numvifs; vifi++)
{
oifs[vifi] =
IF_ISSET(vifi, &r->oifs) ? 'o' : '.';
joined_oifs[vifi] =
IF_ISSET(vifi, &r->joined_oifs) ? 'j' : '.';
pruned_oifs[vifi] =
IF_ISSET(vifi, &r->pruned_oifs) ? 'p' : '.';
leaves_oifs[vifi] =
IF_ISSET(vifi, &r->leaves) ? 'l' : '.';
asserted_oifs[vifi] =
IF_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, "Upstream nbr: %s\n",
r->upstream ? inet6_fmt(&r->upstream->address.sin6_addr) : "NONE");
fprintf(fp, "\nTIMERS: Entry=%d JP=%d RS=%d Assert=%d\n",
r->timer, r->jp_timer, r->rs_timer, r->assert_timer);
fprintf(fp, " MIF 0 1 2 3 4 5 6 7 8 9\n");
for (vifi = 0, i = 0; vifi < numvifs && i <= numvifs / 10; i++) {
int j;
fprintf(fp, " %4d", i);
for (j = 0; j < 10 && vifi < numvifs; j++, vifi++)
fprintf(fp, " %3d", 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", inet6_fmt(&r->source->address.sin6_addr));
fprintf(fp, " %-15s", inet6_fmt(&g->group.sin6_addr));
fprintf(fp, " %-15s",
g->active_rp_grp ? inet6_fmt(&g->rpaddr.sin6_addr) : "NULL");
for (vifi = 0; vifi < numvifs; vifi++)
{
oifs[vifi] =
IF_ISSET(vifi, &r->oifs) ? 'o' : '.';
joined_oifs[vifi] =
IF_ISSET(vifi, &r->joined_oifs) ? 'j' : '.';
pruned_oifs[vifi] =
IF_ISSET(vifi, &r->pruned_oifs) ? 'p' : '.';
leaves_oifs[vifi] =
IF_ISSET(vifi, &r->leaves) ? 'l' : '.';
asserted_oifs[vifi] =
IF_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, "Upstream nbr: %s\n",
r->upstream ? inet6_fmt(&r->upstream->address.sin6_addr) : "NONE");
fprintf(fp, "\nTIMERS: Entry=%d JP=%d RS=%d Assert=%d\n",
r->timer, r->jp_timer, r->rs_timer, r->assert_timer);
fprintf(fp, " MIF 0 1 2 3 4 5 6 7 8 9\n");
for (vifi = 0, i = 0; vifi < numvifs && i <= numvifs / 10; i++) {
int j;
fprintf(fp, " %4d", i);
for (j = 0; j < 10 && vifi < numvifs; j++, vifi++)
fprintf(fp, " %3d", 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", inet6_fmt(&r->source->address.sin6_addr));
fprintf(fp, " %-15s", "IN6ADDR_ANY");
for (vifi = 0; vifi < numvifs; vifi++)
{
oifs[vifi] =
IF_ISSET(vifi, &r->oifs) ? 'o' : '.';
joined_oifs[vifi] =
IF_ISSET(vifi, &r->joined_oifs) ? 'j' : '.';
pruned_oifs[vifi] =
IF_ISSET(vifi, &r->pruned_oifs) ? 'p' : '.';
leaves_oifs[vifi] =
IF_ISSET(vifi, &r->leaves) ? 'l' : '.';
asserted_oifs[vifi] =
IF_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=%d JP=%d RS=%d Assert=%d\n",
r->timer, r->jp_timer, r->rs_timer, r->assert_timer);
fprintf(fp, " MIF 0 1 2 3 4 5 6 7 8 9\n");
for (vifi = 0, i = 0; vifi < numvifs && i <= numvifs / 10; i++) {
int j;
fprintf(fp, " %4d", i);
for (j = 0; j < 10 && vifi < numvifs; j++, vifi++)
fprintf(fp, " %3d", 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(fp)
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 Prio: %d Timeout: %d\n",
inet6_fmt(&curr_bsr_address.sin6_addr), curr_bsr_priority,
pim_bootstrap_timer);
fprintf(fp, "%-40s %-3s Group prefix Prio Hold Age\n",
"RP-address", "IN");
for (rp = cand_rp_list; rp != (cand_rp_t *) NULL; rp = rp->next)
{
fprintf(fp, "%-40s %-3d ",
inet6_fmt(&rp->rpentry->address.sin6_addr),
rp->rpentry->incoming);
if ((rp_grp_entry = rp->rp_grp_next) != (rp_grp_entry_t *) NULL)
{
grp_mask = rp_grp_entry->group;
fprintf(fp, "%-16.16s %-4u %-4u %-3u\n",
net6name(&grp_mask->group_addr.sin6_addr,
&grp_mask->group_mask),
rp_grp_entry->priority, rp_grp_entry->advholdtime,
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, "%59.16s %-4u %-4u %-3u\n", /* XXX: hardcoding */
net6name(&grp_mask->group_addr.sin6_addr,
&grp_mask->group_mask),
rp_grp_entry->priority,
rp_grp_entry->advholdtime, rp_grp_entry->holdtime);
}
}
}
return (TRUE);
}

153
usr.sbin/pim6sd/debug.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef DEBUG_H
#define DEBUG_H
#include <sys/types.h>
#include <stdio.h>
extern unsigned long debug;
extern int log_nmsgs;
extern FILE *log_fp;
#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 )
/* MLD related */
#define DEBUG_MLD_PROTO 0x00000010
#define DEBUG_MLD_TIMER 0x00000020
#define DEBUG_MLD_MEMBER 0x00000040
#define DEBUG_MEMBER DEBUG_MLD_MEMBER
#define DEBUG_MLD ( DEBUG_MLD_PROTO | DEBUG_MLD_TIMER | \
DEBUG_MLD_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_MLD_TIMER | DEBUG_DVMRP_TIMER | \
DEBUG_PIM_TIMER )
#define DEBUG_ASSERT ( DEBUG_PIM_ASSERT )
/* CONFIG related */
#define DEBUG_CONF 0x01000000
#define DEBUG_ALL 0xffffffff
#define DEBUG_SWITCH 0x80000000
#define DEBUG_DEFAULT 0xffffffff/* default if "-d" given without value */
#if defined(YIPS_DEBUG)
#define YIPSDEBUG(lev,arg) if ((debug & (lev)) == (lev)) { arg; }
#else
#define YIPSDEBUG(lev,arg)
#endif /* defined(YIPS_DEBUG) */
extern char *packet_kind __P((u_int proto, u_int type,
u_int code));
extern int debug_kind __P((u_int proto, u_int type,
u_int code));
extern void log __P((int, int, char *, ...));
extern int log_level __P((u_int proto, u_int type,
u_int code));
extern void dump __P((int i));
extern void fdump __P((int i));
extern void cdump __P((int i));
extern void dump_vifs __P((FILE *fp));
extern void dump_nbrs __P((FILE *fp));
extern void dump_pim_mrt __P((FILE *fp));
extern int dump_rp_set __P((FILE *fp));
extern void dump_stat __P(());
#endif

82
usr.sbin/pim6sd/defs.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef DEFS_H
#define DEFS_H
#include <sys/types.h>
#define TRUE 1
#define FALSE 0
#define ELSE else /* To make emacs cc-mode happy */
#define max( a , b ) ( ( a )<( b )?( b ):( a ) )
typedef void ( *ihfunc_t ) __P( ( int , fd_set * ) );
typedef void ( *cfunc_t ) __P( ( void * ) );
int register_input_handler __P((int fd,ihfunc_t func));
/* CONFIGCONFIGCONFIGCONFIG */
#define HAVE_ROUTING_SOCKETS
#define HAVE_SA_LEN
#define RANDOM() random()
#define PRINTF printf
#define ALL_MCAST_GROUPS_LENGTH 8
typedef u_int u_int32;
typedef u_short u_int16;
typedef u_char u_int8;
extern char configfilename[];
#endif

283
usr.sbin/pim6sd/inet6.c Normal file
View File

@ -0,0 +1,283 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include "defs.h"
#include "vif.h"
#include "inet6.h"
#include <arpa/inet.h>
/* flag if address to hostname resolution should be perfomed */
int numerichost = TRUE;
int
inet6_uvif2scopeid(struct sockaddr_in6 * sa, struct uvif * v)
{
if (IN6_IS_ADDR_MULTICAST(&sa->sin6_addr))
{
if (IN6_IS_ADDR_MC_LINKLOCAL(&sa->sin6_addr))
return (v->uv_ifindex);
if (IN6_IS_ADDR_MC_SITELOCAL(&sa->sin6_addr))
return (v->uv_siteid);
}
else
{
if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
return (v->uv_ifindex);
if (IN6_IS_ADDR_SITELOCAL(&sa->sin6_addr))
return (v->uv_siteid);
}
return (0);
}
int
inet6_localif_address(struct sockaddr_in6 * sa, struct uvif * v)
{
struct phaddr *pa;
for (pa = v->uv_addrs; pa; pa = pa->pa_next)
if (inet6_equal(sa, &pa->pa_addr))
return (TRUE);
return (FALSE);
}
int
inet6_valid_host(struct sockaddr_in6 * addr)
{
if (IN6_IS_ADDR_MULTICAST(&addr->sin6_addr))
return (FALSE);
return (TRUE);
}
int
inet6_equal(struct sockaddr_in6 * sa1, struct sockaddr_in6 * sa2)
{
if (sa1->sin6_scope_id == sa2->sin6_scope_id &&
IN6_ARE_ADDR_EQUAL(&sa1->sin6_addr, &sa2->sin6_addr))
return (1);
return (0);
}
int
inet6_lessthan(struct sockaddr_in6 * sa1, struct sockaddr_in6 * sa2)
{
u_int32_t s32_1,
s32_2;
int i;
if (sa1->sin6_scope_id < sa2->sin6_scope_id)
return (1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id)
{
for (i = 0; i < 4; i++)
{
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 > s32_2)
return (0);
if (s32_1 < s32_2)
return (1);
/* otherwide, continue to compare */
}
}
return (0);
}
int
inet6_greaterthan(struct sockaddr_in6 * sa1, struct sockaddr_in6 * sa2)
{
u_int32_t s32_1,
s32_2;
int i;
if (sa1->sin6_scope_id > sa2->sin6_scope_id)
return (1);
if (sa1->sin6_scope_id == sa2->sin6_scope_id)
{
for (i = 0; i < 4; i++)
{
s32_1 = ntohl(*(u_int32_t *)&sa1->sin6_addr.s6_addr[i * 4]);
s32_2 = ntohl(*(u_int32_t *)&sa2->sin6_addr.s6_addr[i * 4]);
if (s32_1 < s32_2)
return (0);
if (s32_1 > s32_2)
return (1);
/* otherwide, continue to compare */
}
}
return (0);
}
int
inet6_match_prefix(sa1, sa2, mask)
struct sockaddr_in6 *sa1,
*sa2;
struct in6_addr *mask;
{
int i;
if (sa1->sin6_scope_id != sa2->sin6_scope_id)
return (0);
for (i = 0; i < 16; i++)
{
if ((sa1->sin6_addr.s6_addr[i] ^ sa2->sin6_addr.s6_addr[i]) &
mask->s6_addr[i])
return (0);
}
return (1);
}
char *
inet6_fmt(struct in6_addr * addr)
{
static char ip6buf[8][MAXHOSTNAMELEN];
static int ip6round = 0;
char *cp;
struct sockaddr_in6 sa6;
int flags = NI_WITHSCOPEID;
ip6round = (ip6round + 1) & 7;
cp = ip6buf[ip6round];
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_len = sizeof(sa6);
sa6.sin6_family = AF_INET6;
sa6.sin6_addr = *addr;
sa6.sin6_scope_id = 0; /* XXX */
if (numerichost)
flags |= NI_NUMERICHOST;
getnameinfo((struct sockaddr *)&sa6, sa6.sin6_len, cp, MAXHOSTNAMELEN,
NULL, 0, flags);
return(cp);
}
char *
ifindex2str(int ifindex)
{
static char ifname[IFNAMSIZ];
return (if_indextoname(ifindex, ifname));
}
int
inet6_mask2plen(struct in6_addr * mask)
{
int masklen;
u_char *p = (u_char *) mask;
u_char *lim = p + 16;
for (masklen = 0; p < lim; p++)
{
switch (*p)
{
case 0xff:
masklen += 8;
break;
case 0xfe:
masklen += 7;
break;
case 0xfc:
masklen += 6;
break;
case 0xf8:
masklen += 5;
break;
case 0xf0:
masklen += 4;
break;
case 0xe0:
masklen += 3;
break;
case 0xc0:
masklen += 2;
break;
case 0x80:
masklen += 1;
break;
case 0x00:
break;
}
}
return (masklen);
}
char *
net6name(struct in6_addr * prefix, struct in6_addr * mask)
{
static char ip6buf[8][INET6_ADDRSTRLEN + 4]; /* length of addr/plen */
static int ip6round = 0;
char *cp;
ip6round = (ip6round + 1) & 7;
cp = ip6buf[ip6round];
inet_ntop(AF_INET6, prefix, cp, INET6_ADDRSTRLEN);
cp += strlen(cp);
*cp = '/';
cp++;
sprintf(cp, "%d", inet6_mask2plen(mask));
return (ip6buf[ip6round]);
}

76
usr.sbin/pim6sd/inet6.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef INET6_H
#define INET6_H
#include "vif.h"
extern int numerichost;
extern int inet6_equal __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_lessthan __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_localif_address __P((struct sockaddr_in6 *sa,
struct uvif *v));
extern int inet6_greaterthan __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2));
extern int inet6_match_prefix __P((struct sockaddr_in6 *sa1,
struct sockaddr_in6 *sa2,
struct in6_addr *mask));
extern int inet6_mask2plen __P((struct in6_addr *mask));
extern int inet6_uvif2scopeid __P((struct sockaddr_in6 *sa, struct uvif *v));
extern int inet6_valid_host __P((struct sockaddr_in6 *addr));
extern char *inet6_fmt __P((struct in6_addr *addr));
extern char *ifindex2str __P((int ifindex));
extern char *net6name __P((struct in6_addr *prefix,
struct in6_addr *mask));
#endif

413
usr.sbin/pim6sd/kern.c Normal file
View File

@ -0,0 +1,413 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#include <sys/time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet6/ip6_mroute.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <net/if_var.h>
#endif
#include <netinet6/in6_var.h>
#include <syslog.h>
#include "pimd.h"
#include "inet6.h"
#include "vif.h"
#include "mrt.h"
#include "debug.h"
/*
* Open/init the multicast routing in the kernel and sets the MRT_ASSERT
* flag in the kernel.
*
*/
void
k_init_pim(int socket)
{
int v = 1;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_INIT, (char *) &v, sizeof(int)) < 0)
log(LOG_ERR, errno, "cannot enable multicast routing in kernel");
if (setsockopt(socket, IPPROTO_IPV6, MRT6_PIM, (char *) &v, sizeof(int)) < 0)
log(LOG_ERR, errno, "Pim kernel initialization");
}
/*
* Stops the multicast routing in the kernel and resets the MRT_ASSERT flag
* in the kernel.
*/
void
k_stop_pim(socket)
int socket;
{
int v = 0;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_PIM,
(char *) &v, sizeof(int)) < 0)
log(LOG_ERR, errno, "Cannot reset PIM flag in kernel");
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DONE, (char *) NULL, 0) < 0)
log(LOG_ERR, errno, "cannot disable multicast routing in kernel");
}
/*
* 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)
log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
bufsize, minsize);
/*NOTREACHED*/
}
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG,0,"Buffer reception size for socket %d : %d in %d iterations",socket, bufsize, iter);
}
/*
* Set the default Hop Limit for the multicast packets outgoing from this
* socket.
*/
void
k_set_hlim(int socket, int h)
{
int hlim = h;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &hlim, sizeof(hlim)) < 0)
log(LOG_ERR,errno,"k_set_hlim");
}
/*
* Set/reset the IPV6_MULTICAST_LOOP. Set/reset is specified by "flag".
*/
void
k_set_loop(int socket, int flag)
{
u_int loop;
loop = flag;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) < 0)
log(LOG_ERR,errno,"k_set_loop");
}
/*
* Set the IPV6_MULTICAST_IF option on local interface which has the
* specified index.
*/
void
k_set_if(int socket, u_int ifindex)
{
if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(char *) &ifindex, sizeof(ifindex)) < 0)
log(LOG_ERR, errno, "setsockopt IPV6_MULTICAST_IF for %s",
ifindex2str(ifindex));
}
/*
* Join a multicast grp group on local interface ifa.
*/
void
k_join(int socket, struct in6_addr * grp, u_int ifindex)
{
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = *grp;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
(char *) &mreq, sizeof(mreq)) < 0)
syslog(LOG_WARNING, "Cannot join group %s on interface %s",
inet6_fmt(grp), ifindex2str(ifindex));
}
/*
* Leave a multicats grp group on local interface ifa.
*/
void
k_leave(int socket, struct in6_addr * grp, u_int ifindex)
{
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = *grp;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
(char *) &mreq, sizeof(mreq)) < 0)
syslog(LOG_WARNING, "Cannot leave group %s on interface %s",
inet6_fmt(grp), ifindex2str(ifindex));
}
/*
* Add a virtual interface in the kernel.
*/
void
k_add_vif(int socket, vifi_t vifi, struct uvif * v)
{
struct mif6ctl mc;
mc.mif6c_mifi = vifi;
mc.mif6c_flags = v->uv_flags;
mc.mif6c_pifi = v->uv_ifindex;
if ((v->uv_flags & MIFF_REGISTER))
IF_DEBUG(DEBUG_PIM_REGISTER)
log(LOG_DEBUG,0,"register vifi : %d , register pifi : %d ", vifi, v->uv_ifindex);
if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MIF,
(char *) &mc, sizeof(mc)) < 0)
log(LOG_ERR, errno, "setsockopt MRT6_ADD_MIF on mif %d", vifi);
}
/*
* Delete a virtual interface in the kernel.
*/
void
k_del_vif(int socket, vifi_t vifi)
{
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MIF,
(char *) &vifi, sizeof(vifi)) < 0)
log(LOG_ERR, errno, "setsockopt MRT6_DEL_MIF on mif %d", vifi);
}
/*
* Delete all MFC entries for particular routing entry from the kernel.
*/
int
k_del_mfc(int socket, struct sockaddr_in6 * source, struct sockaddr_in6 * group)
{
struct mf6cctl mc;
mc.mf6cc_origin = *source;
mc.mf6cc_mcastgrp = *group;
pim6dstat.kern_del_cache++;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MFC, (char *) &mc, sizeof(mc)) < 0)
{
pim6dstat.kern_del_cache_fail++;
log(LOG_WARNING, errno, "setsockopt MRT6_DEL_MFC");
return FALSE;
}
syslog(LOG_DEBUG, "Deleted MFC entry : src %s ,grp %s", inet6_fmt(&source->sin6_addr),
inet6_fmt(&group->sin6_addr));
return TRUE;
}
/*
* Install/modify a MFC entry in the kernel
*/
int
k_chg_mfc(socket, source, group, iif, oifs, rp_addr)
int socket;
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
vifi_t iif;
if_set *oifs;
struct sockaddr_in6 *rp_addr;
{
struct mf6cctl mc;
vifi_t vifi;
struct uvif *v;
mc.mf6cc_origin = *source;
mc.mf6cc_mcastgrp = *group;
mc.mf6cc_parent = iif;
IF_ZERO(&mc.mf6cc_ifset);
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
{
if (IF_ISSET(vifi, oifs))
IF_SET(vifi, &mc.mf6cc_ifset);
else
IF_CLR(vifi, &mc.mf6cc_ifset);
}
#ifdef PIM_REG_KERNEL_ENCAP
mc.mf6cc_rp_addr.s_addr = rp_addr;
#endif
pim6dstat.kern_add_cache++;
if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MFC, (char *) &mc,
sizeof(mc)) < 0)
{
pim6dstat.kern_add_cache_fail++;
log(LOG_WARNING, errno,
"setsockopt MRT_ADD_MFC for source %s and group %s",
inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
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, retval)
vifi_t vifi;
struct vif_count *retval;
{
struct sioc_mif_req6 mreq;
mreq.mifi = vifi;
if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *) &mreq) < 0)
{
log(LOG_WARNING, errno, "SIOCGETMIFCNT_IN6 on vif %d", vifi);
retval->icount = retval->ocount = retval->ibytes =
retval->obytes = 0xffffffff;
return (1);
}
retval->icount = mreq.icount;
retval->ocount = mreq.ocount;
retval->ibytes = mreq.ibytes;
retval->obytes = mreq.obytes;
return (0);
}
/*
* Gets the number of packets, bytes, and number of packets arrived on wrong
* if in the kernel for particular (S,G) entry.
*/
int
k_get_sg_cnt(socket, source, group, retval)
int socket; /* udp_socket */
struct sockaddr_in6 *source;
struct sockaddr_in6 *group;
struct sg_count *retval;
{
struct sioc_sg_req6 sgreq;
sgreq.src = *source;
sgreq.grp = *group;
if (ioctl(socket, SIOCGETSGCNT_IN6, (char *) &sgreq) < 0)
{
pim6dstat.kern_sgcnt_fail++;
log(LOG_WARNING, errno, "SIOCGETSGCNT_IN6 on (%s %s)",
inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
retval->pktcnt = retval->bytecnt = retval->wrong_if = ~0; /* XXX */
return (1);
}
retval->pktcnt = sgreq.pktcnt;
retval->bytecnt = sgreq.bytecnt;
retval->wrong_if = sgreq.wrong_if;
return (0);
}

78
usr.sbin/pim6sd/kern.h Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef KERN_H
#define KERN_H
#include "vif.h"
#include "mrt.h"
extern void k_set_rcvbuf __P((int socket, int bufsize, int minsize));
extern void k_set_hlim __P((int socket, int t));
extern void k_set_loop __P((int socket, int l));
extern void k_set_if __P((int socket, u_int ifindex));
extern void k_join __P((int socket, struct in6_addr *grp,
u_int ifindex));
extern void k_leave __P((int socket, struct in6_addr *grp,
u_int ifindex));
extern void k_init_pim __P(());
extern void k_stop_pim __P(());
extern int k_del_mfc __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern int k_chg_mfc __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group, vifi_t iif,
if_set *oifs, struct sockaddr_in6 *rp_addr));
extern void k_add_vif __P((int socket, vifi_t vifi, struct uvif *v));
extern void k_del_vif __P((int socket, vifi_t vifi));
extern int k_get_vif_count __P((vifi_t vifi, struct vif_count *retval));
extern int k_get_sg_cnt __P((int socket, struct sockaddr_in6 *source,
struct sockaddr_in6 *group,
struct sg_count *retval));
#endif

767
usr.sbin/pim6sd/main.c Normal file
View File

@ -0,0 +1,767 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <sys/param.h>
#include <sys/time.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <fcntl.h>
#include "pathnames.h"
#include "defs.h"
#include "debug.h"
#include "mld6.h"
#include "pim6.h"
#include "vif.h"
#include "routesock.h"
#include "callout.h"
#include "mrt.h"
#include "timer.h"
#include "rp.h"
#include "kern.h"
#include "cfparse.h"
char configfilename[256] = _PATH_PIM6D_CONF;
char versionstring[100];
char logfilename[256] = _PATH_PIM6D_LOGFILE;
/* TODO: not used
static char genidfilename[] = _PATH_PIM6D_GENID;
*/
static char pidfilename[] = _PATH_PIM6D_PID;
FILE *log_fp = stderr;
char *progname;
static int foreground = 0;
static int sighandled = 0;
#define GOT_SIGINT 0x01
#define GOT_SIGHUP 0x02
#define GOT_SIGUSR1 0x04
#define GOT_SIGUSR2 0x08
#define GOT_SIGALRM 0x10
#define GOT_SIGINFO 0x20
#define NHANDLERS 3
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;
int level;
int nchars;
} debugnames[] = {
{ "mld_proto", DEBUG_MLD_PROTO, 5 },
{ "mld_timer", DEBUG_MLD_TIMER, 5 },
{ "mld_member", DEBUG_MLD_MEMBER, 5 },
{ "mld", DEBUG_MLD, 3 },
{ "switch", DEBUG_SWITCH, 2 },
{ "trace", DEBUG_TRACE, 2 },
{ "mtrace", DEBUG_TRACE, 2 },
{ "traceroute", DEBUG_TRACE, 2 },
{ "timeout", DEBUG_TIMEOUT, 2 },
{ "callout", DEBUG_TIMEOUT, 3 },
{ "pkt", DEBUG_PKT, 2 },
{ "packets", 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_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 },
{ "routers", DEBUG_NEIGHBORS, 6 },
{ "mrouters", DEBUG_NEIGHBORS, 7 },
{ "neighbors", DEBUG_NEIGHBORS, 1 },
{ "timers", DEBUG_TIMER, 1 },
{ "asserts", DEBUG_ASSERT, 1 },
{ "all", DEBUG_ALL, 2 },
{ "3", 0xffffffff, 1 } /* compat. */
};
/*
* Forward declarations.
*/
static void handler __P((int));
static void timer __P((void *));
static void cleanup __P((void));
static void restart __P((int));
static void cleanup __P((void));
/* To shut up gcc -Wstrict-prototypes */
int main __P((int argc, char **argv));
int
register_input_handler(fd, func)
int fd;
ihfunc_t func;
{
if (nhandlers >= NHANDLERS)
return -1;
ihandlers[nhandlers].fd = fd;
ihandlers[nhandlers++].func = func;
return 0;
}
int
main(argc, argv)
int argc;
char *argv[];
{
int dummy,
dummysigalrm;
FILE *fp;
struct timeval tv,
difftime,
curtime,
lasttime,
*timeout;
fd_set rfds,
readers;
int nfds=0,
n,
i,
secs;
extern char todaysversion[];
struct sigaction sa;
struct debugname *d;
char c;
int tmpd;
setlinebuf(stderr);
if (geteuid() != 0)
{
fprintf(stderr, "pim6sd: must be root\n");
exit(1);
}
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
argv++;
argc--;
while (argc > 0 && *argv[0] == '-')
{
if (strcmp(*argv, "-d") == 0)
{
if (argc > 1 && *(argv + 1)[0] != '-')
{
char *p,
*q;
int i,
len;
struct debugname *d;
int no=0;
argv++;
argc--;
debug = 0;
p = *argv;
q = NULL;
while (p)
{
q = strchr(p, ',');
if (q)
*q++ = '\0';
if(p[0]=='-')
{
no=1;
p++;
}
len = strlen(p);
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++)
if (len >= d->nchars && strncmp(d->name, p, len) == 0)
break;
if (i == sizeof(debugnames) / sizeof(debugnames[0]))
{
int j = 0xffffffff;
int k = 0;
fprintf(stderr, "Valid debug levels: ");
for (i = 0, d = debugnames;
i < sizeof(debugnames) / sizeof(debugnames[0]);
i++, d++)
{
if ((j & d->level) == d->level)
{
if (k++)
putc(',', stderr);
fputs(d->name, stderr);
j &= ~d->level;
}
}
putc('\n', stderr);
goto usage;
}
if(no)
{
debug &=~d->level;
no=0;
}
else
debug |= d->level;
p = q;
}
}
else
debug = DEBUG_DEFAULT;
}
else if (strcmp(*argv, "-c") == 0) {
if (argc > 1)
{
argv++;
argc--;
strcpy(configfilename, *argv);
}
else
goto usage;
}
else if (strcmp(*argv, "-f") == 0)
foreground = 1;
else
goto usage;
argv++;
argc--;
}
if (argc > 0)
{
usage:
tmpd = 0xffffffff;
fprintf(stderr, "usage: pim6sd [-c configfile] [-d [debug_level][,debug_level]]\n");
fprintf(stderr, "debug levels: ");
c = '(';
for (d = debugnames; d < debugnames +
sizeof(debugnames) / sizeof(debugnames[0]); d++)
{
if ((tmpd & d->level) == d->level)
{
tmpd &= ~d->level;
fprintf(stderr, "%c%s", c, d->name);
c = ',';
}
}
fprintf(stderr, ")\n");
exit(1);
}
if (debug != 0)
{
tmpd = debug;
fprintf(stderr, "debug level 0x%lx ", debug);
c = '(';
for (d = debugnames; d < debugnames +
sizeof(debugnames) / sizeof(debugnames[0]); d++)
{
if ((tmpd & d->level) == d->level)
{
tmpd &= ~d->level;
fprintf(stderr, "%c%s", c, d->name);
c = ',';
}
}
fprintf(stderr, ")\n");
}
#ifdef LOG_DAEMON
(void) openlog("pim6sd", LOG_PID, LOG_DAEMON);
// (void) setlogmask(LOG_UPTO(LOG_NOTICE));
#else
(void) openlog("pim6sd", LOG_PID);
#endif /* LOG_DAEMON */
/* open a log file */
if ((log_fp = fopen(logfilename, "w")) == NULL)
log(LOG_ERR, errno, "fopen(%s)", logfilename);
setlinebuf(log_fp);
sprintf(versionstring, "pim6sd version %s", todaysversion);
log(LOG_INFO, 0, "%s starting", versionstring);
/*
* TODO: XXX: use a combination of time and hostid to initialize the
* random generator.
*/
#ifdef SYSV
srand48(time(NULL));
#else
srandom(time(NULL));
#endif
callout_init();
init_mld6();
init_pim6();
#ifdef HAVE_ROUTING_SOCKETS
init_routesock();
#endif /* HAVE_ROUTING_SOCKETS */
init_pim6_mrt();
init_timers();
/* TODO: check the kernel DVMRP/MROUTED/PIM support version */
init_vifs();
init_rp6_and_bsr6(); /* Must be after init_vifs() */
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);
sigaction(SIGINFO, &sa, NULL);
FD_ZERO(&readers);
FD_SET(mld6_socket, &readers);
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(log_fp);
IF_DEBUG(DEBUG_PIM_MRT)
dump_pim_mrt(log_fp);
/* schedule first timer interrupt */
timer_setTimer(timer_interval, timer, NULL);
if (foreground == 0)
{
/* Detach from the terminal */
#ifdef TIOCNOTTY
int t;
#endif /* TIOCNOTTY */
if (fork())
exit(0);
#ifdef HAVE_ROUTING_SOCKETS
pid = getpid();
#endif
(void) close(0);
(void) close(1);
(void) close(2);
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
#if defined(SYSV) || defined(linux)
(void) setpgrp();
#else
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0)
{
(void) ioctl(t, TIOCNOTTY, (char *) 0);
(void) close(t);
}
#else
if (setsid() < 0)
perror("setsid");
#endif /* TIOCNOTTY */
#endif /* SYSV */
} /* End of child process code */
fp = fopen(pidfilename, "w");
if (fp != NULL)
{
fprintf(fp, "%d\n", (int) getpid());
(void) fclose(fp);
}
/*
* Main receive loop.
*/
dummy = 0;
dummysigalrm = SIGALRM;
difftime.tv_usec = 0;
gettimeofday(&curtime, NULL);
lasttime = curtime;
for (;;)
{
bcopy((char *) &readers, (char *) &rfds, sizeof(rfds));
secs = timer_nextTimer();
if (secs == -1)
timeout = NULL;
else
{
timeout = &tv;
timeout->tv_sec = secs;
timeout->tv_usec = 0;
}
if (sighandled)
{
if (sighandled & GOT_SIGINT)
{
sighandled &= ~GOT_SIGINT;
break;
}
if (sighandled & GOT_SIGHUP)
{
sighandled &= ~GOT_SIGHUP;
restart(SIGHUP);
}
if (sighandled & GOT_SIGINFO)
{
sighandled &= ~GOT_SIGINFO;
dump_stat();
}
if (sighandled & GOT_SIGUSR1)
{
sighandled &= ~GOT_SIGUSR1;
fdump(SIGUSR1);
}
if (sighandled & GOT_SIGUSR2)
{
sighandled &= ~GOT_SIGUSR2;
#ifdef notyet
cdump(SIGUSR2);
#else
cfparse(0, 1); /* reset debug level */
#endif
}
if (sighandled & GOT_SIGALRM)
{
sighandled &= ~GOT_SIGALRM;
timer(&dummysigalrm);
}
}
if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0)
{
if (errno != EINTR)
log(LOG_WARNING, errno, "select failed");
continue;
}
/*
* 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;
#ifdef TIMERDEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "TIMEOUT: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec);
#endif
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)
if (secs == 0 || difftime.tv_sec > 0)
{
#ifdef TIMERDEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "\taging callouts: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec);
#endif
age_callout_queue(difftime.tv_sec);
}
secs = -1;
} while (difftime.tv_sec > 0);
/* Handle sockets */
if (n > 0)
{
for (i = 0; i < nhandlers; i++)
{
if (FD_ISSET(ihandlers[i].fd, &rfds))
{
(*ihandlers[i].func) (ihandlers[i].fd, &rfds);
}
}
}
} /* Main loop */
log(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.
* this granularity is configurable ( see file pim6sd.conf.sample)
*/
static void
timer(i)
void *i;
{
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()
{
/*
* 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(mld6_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(sig)
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;
case SIGINFO:
sighandled |= GOT_SIGINFO;
break;
}
}
/* TODO: not verified */
/*
* Restart the daemon
*/
static void
restart(i)
int i;
{
log(LOG_NOTICE, 0, "% restart", versionstring);
/*
* reset all the entries
*/
/*
* TODO: delete?
free_all_routes();
*/
free_all_callouts();
stop_all_vifs();
nhandlers=0;
k_stop_pim(mld6_socket);
close(mld6_socket);
close(pim6_socket);
close(udp_socket);
/*
* start processing again
*/
init_mld6();
init_pim6();
#ifdef HAVE_ROUTING_SOCKETS
init_routesock();
#endif /* HAVE_ROUTING_SOCKETS */
init_pim6_mrt();
init_vifs();
/* schedule timer interrupts */
timer_setTimer(timer_interval, timer, NULL);
}

555
usr.sbin/pim6sd/mld6.c Normal file
View File

@ -0,0 +1,555 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include "mld6.h"
#include "kern.h"
#include "defs.h"
#include "inet6.h"
#include "debug.h"
#include "mld6_proto.h"
#include "route.h"
#include "trace.h"
/*
* Exported variables.
*/
char *mld6_recv_buf; /* input packet buffer */
char *mld6_send_buf; /* output packet buffer */
int mld6_socket; /* socket for all network I/O */
struct sockaddr_in6 allrouters_group = {sizeof(struct sockaddr_in6), AF_INET6};
struct sockaddr_in6 allnodes_group = {sizeof(struct sockaddr_in6), AF_INET6};
/* Extenals */
extern struct in6_addr in6addr_linklocal_allnodes;
/* local variables. */
static struct sockaddr_in6 dst = {sizeof(dst), AF_INET6};
static struct msghdr sndmh,
rcvmh;
static struct iovec sndiov[2];
static struct iovec rcviov[2];
static struct sockaddr_in6 from;
static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int))];
#ifndef USE_RFC2292BIS
u_int8_t raopt[IP6OPT_RTALERT_LEN];
#endif
static char *sndcmsgbuf;
static int ctlbuflen = 0;
static u_short rtalert_code;
/* local functions */
static void mld6_read __P((int i, fd_set * fds));
static void accept_mld6 __P((int len));
#ifndef IP6OPT_ROUTER_ALERT /* XXX to be compatible older systems */
#define IP6OPT_ROUTER_ALERT IP6OPT_RTALERT
#endif
/*
* Open and initialize the MLD socket.
*/
void
init_mld6()
{
struct icmp6_filter filt;
int on;
rtalert_code = htons(IP6OPT_RTALERT_MLD);
if (!mld6_recv_buf && (mld6_recv_buf = malloc(RECV_BUF_SIZE)) == NULL)
log(LOG_ERR, 0, "malloca failed");
if (!mld6_send_buf && (mld6_send_buf = malloc(RECV_BUF_SIZE)) == NULL)
log(LOG_ERR, 0, "malloca failed");
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG,0,"%d octets allocated for the emit/recept buffer mld6",RECV_BUF_SIZE);
if ((mld6_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
log(LOG_ERR, errno, "MLD6 socket");
k_set_rcvbuf(mld6_socket, SO_RECV_BUF_SIZE_MAX,
SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
k_set_hlim(mld6_socket, MINHLIM); /* restrict multicasts to one hop */
k_set_loop(mld6_socket, FALSE); /* disable multicast loopback */
/* address initialization */
allnodes_group.sin6_addr = in6addr_linklocal_allnodes;
if (inet_pton(AF_INET6, "ff02::2",
(void *) &allrouters_group.sin6_addr) != 1)
log(LOG_ERR, 0, "inet_pton failed for ff02::2");
/* filter all non-MLD ICMP messages */
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_QUERY, &filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REPORT, &filt);
ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REDUCTION, &filt);
ICMP6_FILTER_SETPASS(MLD6_MTRACE_RESP, &filt);
ICMP6_FILTER_SETPASS(MLD6_MTRACE, &filt);
if (setsockopt(mld6_socket, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
sizeof(filt)) < 0)
log(LOG_ERR, errno, "setsockopt(ICMP6_FILTER)");
/* specify to tell receiving interface */
on = 1;
#ifdef IPV6_RECVPKTINFO
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_RECVPKTINFO)");
#else /* old adv. API */
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_PKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_PKTINFO)");
#endif
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
#ifdef IPV6_RECVHOPLIMIT
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_RECVHOPLIMIT)");
#else /* old adv. API */
if (setsockopt(mld6_socket, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_HOPLIMIT)");
#endif
/* initialize msghdr for receiving packets */
rcviov[0].iov_base = (caddr_t) mld6_recv_buf;
rcviov[0].iov_len = RECV_BUF_SIZE;
rcvmh.msg_name = (caddr_t) & from;
rcvmh.msg_namelen = sizeof(from);
rcvmh.msg_iov = rcviov;
rcvmh.msg_iovlen = 1;
rcvmh.msg_control = (caddr_t) rcvcmsgbuf;
rcvmh.msg_controllen = sizeof(rcvcmsgbuf);
/* initialize msghdr for sending packets */
sndiov[0].iov_base = (caddr_t)mld6_send_buf;
sndmh.msg_namelen = sizeof(struct sockaddr_in6);
sndmh.msg_iov = sndiov;
sndmh.msg_iovlen = 1;
/* specifiy to insert router alert option in a hop-by-hop opt hdr. */
#ifndef USE_RFC2292BIS
raopt[0] = IP6OPT_ROUTER_ALERT;
raopt[1] = IP6OPT_RTALERT_LEN - 2;
memcpy(&raopt[2], (caddr_t) & rtalert_code, sizeof(u_short));
#endif
/* register MLD message handler */
if (register_input_handler(mld6_socket, mld6_read) < 0)
log(LOG_ERR, 0,
"Couldn't register mld6_read as an input handler");
}
/* Read an MLD message */
static void
mld6_read(i, rfd)
int i;
fd_set *rfd;
{
register int mld6_recvlen;
mld6_recvlen = recvmsg(mld6_socket, &rcvmh, 0);
if (mld6_recvlen < 0)
{
if (errno != EINTR)
log(LOG_ERR, errno, "MLD6 recvmsg");
return;
}
/* TODO: make it as a thread in the future releases */
accept_mld6(mld6_recvlen);
}
/*
* Process a newly received MLD6 packet that is sitting in the input packet
* buffer.
*/
static void
accept_mld6(recvlen)
int recvlen;
{
struct in6_addr *group, *dst = NULL;
struct mld6_hdr *mldh;
struct cmsghdr *cm;
struct in6_pktinfo *pi = NULL;
int *hlimp = NULL;
int ifindex = 0;
struct sockaddr_in6 *src = (struct sockaddr_in6 *) rcvmh.msg_name;
/*
* If control length is zero, it must be an upcall from the kernel
* multicast forwarding engine.
* XXX: can we trust it?
*/
if (rcvmh.msg_controllen == 0) {
/* XXX: msg_controllen must be reset in this case. */
rcvmh.msg_controllen = sizeof(rcvcmsgbuf);
process_kernel_call();
return;
}
if (recvlen < sizeof(struct mld6_hdr))
{
log(LOG_WARNING, 0,
"received packet too short (%u bytes) for MLD header",
recvlen);
return;
}
mldh = (struct mld6_hdr *) rcvmh.msg_iov[0].iov_base;
group = &mldh->mld6_addr;
/* extract optional information via Advanced API */
for (cm = (struct cmsghdr *) CMSG_FIRSTHDR(&rcvmh);
cm;
cm = (struct cmsghdr *) CMSG_NXTHDR(&rcvmh, cm))
{
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_PKTINFO &&
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
{
pi = (struct in6_pktinfo *) (CMSG_DATA(cm));
ifindex = pi->ipi6_ifindex;
dst = &pi->ipi6_addr;
}
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_HOPLIMIT &&
cm->cmsg_len == CMSG_LEN(sizeof(int)))
hlimp = (int *) CMSG_DATA(cm);
}
if (hlimp == NULL)
{
log(LOG_WARNING, 0,
"failed to get receiving hop limit");
return;
}
/* TODO: too noisy. Remove it? */
//#define NOSUCHDEF
#ifdef NOSUCHDEF
IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_ICMPV6, mldh->mld6_type,
mldh->mld6_code))
log(LOG_DEBUG, 0, "RECV %s from %s to %s",
packet_kind(IPPROTO_ICMPV6,
mldh->mld6_type, mldh->mld6_code),
inet6_fmt(&src->sin6_addr), inet6_fmt(dst));
#endif /* NOSUCHDEF */
/* for an mtrace message, we don't need strict checks */
if (mldh->mld6_type == MLD6_MTRACE) {
accept_mtrace(src, dst, group, ifindex, (char *)(mldh + 1),
mldh->mld6_code, recvlen - sizeof(struct mld6_hdr));
return;
}
/* hop limit check */
if (*hlimp != 1)
{
log(LOG_WARNING, 0,
"received an MLD6 message with illegal hop limit(%d) from %s",
*hlimp, inet6_fmt(&src->sin6_addr));
/* but accept the packet */
}
if (ifindex == 0)
{
log(LOG_WARNING, 0, "failed to get receiving interface");
return;
}
/* scope check */
if (IN6_IS_ADDR_MC_NODELOCAL(&mldh->mld6_addr))
{
log(LOG_INFO, 0,
"RECV %s with an invalid scope: %s from %s",
inet6_fmt(&mldh->mld6_addr),
inet6_fmt(&src->sin6_addr));
return; /* discard */
}
/* source address check */
if (!IN6_IS_ADDR_LINKLOCAL(&src->sin6_addr))
{
log(LOG_INFO, 0,
"RECV %s from a non link local address: %s",
packet_kind(IPPROTO_ICMPV6, mldh->mld6_type,
mldh->mld6_code),
inet6_fmt(&src->sin6_addr));
return;
}
switch (mldh->mld6_type)
{
case MLD6_LISTENER_QUERY:
accept_listener_query(src, dst, group,
ntohs(mldh->mld6_maxdelay));
return;
case MLD6_LISTENER_REPORT:
accept_listener_report(src, dst, group);
return;
case MLD6_LISTENER_DONE:
accept_listener_done(src, dst, group);
return;
default:
/* This must be impossible since we set a type filter */
log(LOG_INFO, 0,
"ignoring unknown ICMPV6 message type %x from %s to %s",
mldh->mld6_type, inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
return;
}
}
static void
make_mld6_msg(type, code, src, dst, group, ifindex, delay, datalen, alert)
int type, code, ifindex, delay, datalen, alert;
struct sockaddr_in6 *src, *dst;
struct in6_addr *group;
{
static struct sockaddr_in6 dst_sa = {sizeof(dst_sa), AF_INET6};
struct mld6_hdr *mhp = (struct mld6_hdr *)mld6_send_buf;
int ctllen, hbhlen = 0;
switch(type) {
case MLD6_MTRACE:
case MLD6_MTRACE_RESP:
sndmh.msg_name = (caddr_t)dst;
break;
default:
if (IN6_IS_ADDR_UNSPECIFIED(group))
dst_sa.sin6_addr = allnodes_group.sin6_addr;
else
dst_sa.sin6_addr = *group;
sndmh.msg_name = (caddr_t)&dst_sa;
datalen = sizeof(struct mld6_hdr);
break;
}
bzero(mhp, sizeof(*mhp));
mhp->mld6_type = type;
mhp->mld6_code = code;
mhp->mld6_maxdelay = htons(delay);
mhp->mld6_addr = *group;
sndiov[0].iov_len = datalen;
/* estimate total ancillary data length */
ctllen = 0;
if (ifindex != -1 || src)
ctllen += CMSG_SPACE(sizeof(struct in6_pktinfo));
if (alert) {
#ifdef USE_RFC2292BIS
if ((hbhlen = inet6_opt_init(NULL, 0)) == -1)
log(LOG_ERR, 0, "inet6_opt_init(0) failed");
if ((hbhlen = inet6_opt_append(NULL, 0, hbhlen, IP6OPT_ROUTER_ALERT, 2,
2, NULL)) == -1)
log(LOG_ERR, 0, "inet6_opt_append(0) failed");
if ((hbhlen = inet6_opt_finish(NULL, 0, hbhlen)) == -1)
log(LOG_ERR, 0, "inet6_opt_finish(0) failed");
#else /* old advanced API */
hbhlen = inet6_option_space(sizeof(raopt));
#endif
ctllen += CMSG_SPACE(hbhlen);
}
/* extend ancillary data space (if necessary) */
if (ctlbuflen < ctllen) {
if (sndcmsgbuf)
free(sndcmsgbuf);
if ((sndcmsgbuf = malloc(ctllen)) == NULL)
log(LOG_ERR, 0, "make_mld6_msg: malloc failed"); /* assert */
ctlbuflen = ctllen;
}
/* store ancillary data */
if ((sndmh.msg_controllen = ctllen) > 0) {
struct cmsghdr *cmsgp;
sndmh.msg_control = sndcmsgbuf;
cmsgp = CMSG_FIRSTHDR(&sndmh);
if (ifindex != -1 || src) {
struct in6_pktinfo *pktinfo;
cmsgp->cmsg_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_PKTINFO;
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
memset((caddr_t)pktinfo, 0, sizeof(*pktinfo));
if (ifindex != -1)
pktinfo->ipi6_ifindex = ifindex;
if (src)
pktinfo->ipi6_addr = src->sin6_addr;
cmsgp = CMSG_NXTHDR(&sndmh, cmsgp);
}
if (alert) {
#ifdef USE_RFC2292BIS
int currentlen;
void *hbhbuf, *optp = NULL;
cmsgp->cmsg_len = CMSG_SPACE(hbhlen);
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_HOPOPTS;
hbhbuf = CMSG_DATA(cmsgp);
if ((currentlen = inet6_opt_init(hbhbuf, hbhlen)) == -1)
log(LOG_ERR, 0, "inet6_opt_init(len = %d) failed",
hbhlen);
if ((currentlen = inet6_opt_append(hbhbuf, hbhlen,
currentlen,
IP6OPT_ROUTER_ALERT, 2,
2, &optp)) == -1)
log(LOG_ERR, 0,
"inet6_opt_append(len = %d) failed",
currentlen, hbhlen);
(void)inet6_opt_set_val(optp, 0, &rtalert_code,
sizeof(rtalert_code));
if (inet6_opt_finish(hbhbuf, hbhlen, currentlen) == -1)
log(LOG_ERR, 0, "inet6_opt_finish(buf) failed");
#else /* old advanced API */
if (inet6_option_init((void *)cmsgp, &cmsgp, IPV6_HOPOPTS))
log(LOG_ERR, 0, /* assert */
"make_mld6_msg: inet6_option_init failed");
if (inet6_option_append(cmsgp, raopt, 4, 0))
log(LOG_ERR, 0, /* assert */
"make_mld6_msg: inet6_option_append failed");
#endif
cmsgp = CMSG_NXTHDR(&sndmh, cmsgp);
}
}
else
sndmh.msg_control = NULL; /* clear for safety */
}
void
send_mld6(type, code, src, dst, group, index, delay, datalen, alert)
int type;
int code; /* for trace packets only */
struct sockaddr_in6 *src;
struct sockaddr_in6 *dst; /* may be NULL */
struct in6_addr *group;
int index, delay, alert;
int datalen; /* for trace packets only */
{
int setloop = 0;
struct sockaddr_in6 *dstp;
make_mld6_msg(type, code, src, dst, group, index, delay, datalen, alert);
dstp = (struct sockaddr_in6 *)sndmh.msg_name;
if (IN6_ARE_ADDR_EQUAL(&dstp->sin6_addr, &allnodes_group.sin6_addr)) {
setloop = 1;
k_set_loop(mld6_socket, TRUE);
}
if (sendmsg(mld6_socket, &sndmh, 0) < 0) {
if (errno == ENETDOWN)
check_vif_state();
else
log(log_level(IPPROTO_ICMPV6, type, 0), errno,
"sendmsg to %s with src %s on %s",
inet6_fmt(&dstp->sin6_addr),
src ? inet6_fmt(&src->sin6_addr) : "(unspec)",
ifindex2str(index));
if (setloop)
k_set_loop(mld6_socket, FALSE);
return;
}
IF_DEBUG(DEBUG_PKT|debug_kind(IPPROTO_IGMP, type, 0))
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
packet_kind(IPPROTO_ICMPV6, type, 0),
src ? inet6_fmt(&src->sin6_addr) : "unspec",
inet6_fmt(&dstp->sin6_addr));
}

90
usr.sbin/pim6sd/mld6.h Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef MLD6_H
#define MLD6_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define RECV_BUF_SIZE 64*1024
#define SO_RECV_BUF_SIZE_MAX 256*1024
#define SO_RECV_BUF_SIZE_MIN 48*1024
#define MINHLIM 1
/*
* Constans for Multicast Listener Discovery protocol for IPv6.
*/
#define MLD6_ROBUSTNESS_VARIABLE 2
#define MLD6_QUERY_INTERVAL 125 /* in seconds */
#define MLD6_QUERY_RESPONSE_INTERVAL 10000 /* in milliseconds */
#ifndef MLD6_TIMER_SCALE
#define MLD6_TIMER_SCALE 1000
#endif
#define MLD6_LISTENER_INTERVAL (MLD6_ROBUSTNESS_VARIABLE * \
MLD6_QUERY_INTERVAL + \
MLD6_QUERY_RESPONSE_INTERVAL / MLD6_TIMER_SCALE)
#define MLD6_LAST_LISTENER_QUERY_INTERVAL 1000 /* in milliseconds */
#define MLD6_LAST_LISTENER_QUERY_COUNT MLD6_ROBUSTNESS_VARIABLE
extern int mld6_socket;
extern char *mld6_recv_buf;
extern struct sockaddr_in6 allrouters_group;
extern struct sockaddr_in6 allnodes_group;
extern char *mld6_send_buf;
void init_mld6 __P(());
void send_mld6 __P((int type, int code, struct sockaddr_in6 *src,
struct sockaddr_in6 *dst, struct in6_addr *group,
int index, int delay, int datalen, int alert));
#endif

View File

@ -0,0 +1,632 @@
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet6/ip6_mroute.h>
#include <netinet/icmp6.h>
#include <syslog.h>
#include <stdlib.h>
#include "mld6.h"
#include "vif.h"
#include "debug.h"
#include "inet6.h"
#include "route.h"
#include "callout.h"
#include "timer.h"
extern struct in6_addr in6addr_any;
typedef struct
{
mifi_t mifi;
struct listaddr *g;
int q_time;
} cbk_t;
/*
* Forward declarations.
*/
static void DelVif __P((void *arg));
static int SetTimer __P((int mifi, struct listaddr * g));
static int DeleteTimer __P((int id));
static void SendQuery __P((void *arg));
static int SetQueryTimer
__P((struct listaddr * g, int mifi, int to_expire,
int q_time));
/*
* Send group membership queries on that interface if I am querier.
*/
void
query_groups(v)
register struct uvif *v;
{
register struct listaddr *g;
v->uv_gq_timer = MLD6_QUERY_INTERVAL;
if (v->uv_flags & VIFF_QUERIER && (v->uv_flags & VIFF_NOLISTENER) == 0) {
send_mld6(MLD6_LISTENER_QUERY, 0, &v->uv_linklocal->pa_addr,
NULL, (struct in6_addr *)&in6addr_any, v->uv_ifindex,
MLD6_QUERY_RESPONSE_INTERVAL, 0, 1);
v->uv_out_mld_query++;
}
/*
* 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_listener_query(src, dst, group, tmo)
struct sockaddr_in6 *src;
struct in6_addr *dst,
*group;
int tmo;
{
register int mifi;
register struct uvif *v;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
/* Ignore my own membership query */
if (local_address(src) != NO_VIF)
return;
if ((mifi = find_vif_direct(src)) == NO_VIF)
{
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_query: can't find a mif");
return;
}
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accepting multicast listener query: "
"src %s, dst %s, grp %s",
inet6_fmt(&src->sin6_addr), inet6_fmt(dst),
inet6_fmt(group));
v = &uvifs[mifi];
v->uv_in_mld_query++;
if (v->uv_querier == NULL || inet6_equal(&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 (inet6_lessthan(src, (v->uv_querier ? &v->uv_querier->al_addr
: &v->uv_linklocal->pa_addr)))
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0, "new querier %s (was %s) "
"on mif %d",
inet6_fmt(&src->sin6_addr),
v->uv_querier ?
inet6_fmt(&v->uv_querier->al_addr.sin6_addr) :
"me", mifi);
if (!v->uv_querier)
{
v->uv_querier = (struct listaddr *)malloc(sizeof(struct listaddr));
v->uv_querier->al_next = (struct listaddr *) NULL;
v->uv_querier->al_timer = 0;
v->uv_querier->al_genid = 0;
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 && inet6_equal(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 (!IN6_IS_ADDR_UNSPECIFIED(group) &&
inet6_equal(src, &v->uv_linklocal->pa_addr))
{
register struct listaddr *g;
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"%s for %s from %s on mif %d, timer %d",
"Group-specific membership query",
inet6_fmt(group),
inet6_fmt(&src->sin6_addr), mifi, tmo);
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next)
{
if (inet6_equal(&group_sa, &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 = MLD6_LAST_LISTENER_QUERY_COUNT *
tmo / MLD6_TIMER_SCALE;
/*
* use al_query to record our presence in last-member state
*/
g->al_query = -1;
g->al_timerid = SetTimer(mifi, g);
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"timer for grp %s on mif %d "
"set to %d",
inet6_fmt(group),
mifi, g->al_timer);
break;
}
}
}
}
/*
* Process an incoming group membership report.
*/
void
accept_listener_report(src, dst, group)
struct sockaddr_in6 *src;
struct in6_addr *dst,
*group;
{
register mifi_t mifi;
register struct uvif *v;
register struct listaddr *g;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
if (IN6_IS_ADDR_MC_LINKLOCAL(group)) {
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accept_listener_report: group(%s) has the "
"link-local scope. discard", inet6_fmt(group));
return;
}
if ((mifi = find_vif_direct_local(src)) == NO_VIF)
{
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_report: can't find a mif");
return;
}
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accepting multicast listener report: "
"src %s,dst %s, grp %s",
inet6_fmt(&src->sin6_addr),inet6_fmt(dst),
inet6_fmt(group));
v = &uvifs[mifi];
v->uv_in_mld_report++;
/*
* Look for the group in our group list; if found, reset its timer.
*/
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next)
{
if (inet6_equal(&group_sa, &g->al_addr))
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG,0,
"The group already exist");
g->al_reporter = *src;
/* delete old timers, set a timer for expiration */
g->al_timer = MLD6_LISTENER_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(mifi, g);
add_leaf(mifi, NULL, &group_sa);
break;
}
}
/*
* If not found, add it to the list and update kernel cache.
*/
if (g == NULL)
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG,0,
"The group don't exist , trying to add it");
g = (struct listaddr *) malloc(sizeof(struct listaddr));
if (g == NULL)
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
g->al_addr = group_sa;
g->al_old = 0;
/** set a timer for expiration **/
g->al_query = 0;
g->al_timer = MLD6_LISTENER_INTERVAL;
g->al_reporter = *src;
g->al_timerid = SetTimer(mifi, g);
g->al_next = v->uv_groups;
v->uv_groups = g;
time(&g->al_ctime);
add_leaf(mifi, NULL, &group_sa);
}
}
/* TODO: send PIM prune message if the last member? */
void
accept_listener_done(src, dst, group)
struct sockaddr_in6 *src;
struct in6_addr *dst,
*group;
{
register mifi_t mifi;
register struct uvif *v;
register struct listaddr *g;
struct sockaddr_in6 group_sa = {sizeof(group_sa), AF_INET6};
/* Don't create routing entries for the LAN scoped addresses */
if (IN6_IS_ADDR_MC_NODELOCAL(group)) /* sanity? */
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accept_listener_done: address multicast node local(%s),"
" ignore it...", inet6_fmt(group));
return;
}
if (IN6_IS_ADDR_MC_LINKLOCAL(group))
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"accept_listener_done: address multicast link local(%s), "
"ignore it ...", inet6_fmt(group));
return;
}
if ((mifi = find_vif_direct_local(src)) == NO_VIF)
{
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accept_listener_done: can't find a mif");
return;
}
IF_DEBUG(DEBUG_MLD)
log(LOG_INFO, 0,
"accepting listener done message: src %s, dst% s, grp %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst), inet6_fmt(group));
v = &uvifs[mifi];
v->uv_in_mld_done++;
if (!(v->uv_flags & (VIFF_QUERIER | VIFF_DR)))
return;
/*
* Look for the group in our group list in order to set up a
* short-timeout query.
*/
group_sa.sin6_addr = *group;
group_sa.sin6_scope_id = inet6_uvif2scopeid(&group_sa, v);
for (g = v->uv_groups; g != NULL; g = g->al_next)
{
if (inet6_equal(&group_sa, &g->al_addr))
{
IF_DEBUG(DEBUG_MLD)
log(LOG_DEBUG, 0,
"[accept_done_message] %d %d \n",
g->al_old, g->al_query);
/*
* Ignore the done message if there are old hosts present
*/
if (g->al_old)
return;
/*
* still waiting for a reply to a query, ignore the done
*/
if (g->al_query)
return;
/** delete old timer set a timer for expiration **/
if (g->al_timerid)
g->al_timerid = DeleteTimer(g->al_timerid);
/** send a group specific querry **/
g->al_timer = (MLD6_LAST_LISTENER_QUERY_INTERVAL / MLD6_TIMER_SCALE) *
(MLD6_LAST_LISTENER_QUERY_COUNT + 1);
if (v->uv_flags & VIFF_QUERIER &&
(v->uv_flags & VIFF_NOLISTENER) == 0) {
send_mld6(MLD6_LISTENER_QUERY, 0,
&v->uv_linklocal->pa_addr, NULL,
&g->al_addr.sin6_addr,
v->uv_ifindex,
MLD6_LAST_LISTENER_QUERY_INTERVAL, 0, 1);
v->uv_out_mld_query++;
}
g->al_query = SetQueryTimer(g, mifi,
MLD6_LAST_LISTENER_QUERY_INTERVAL / MLD6_TIMER_SCALE,
MLD6_LAST_LISTENER_QUERY_INTERVAL);
g->al_timerid = SetTimer(mifi, g);
break;
}
}
}
/*
* Time out record of a group membership on a vif
*/
static void
DelVif(arg)
void *arg;
{
cbk_t *cbk = (cbk_t *) arg;
mifi_t mifi = cbk->mifi;
struct uvif *v = &uvifs[mifi];
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(mifi, NULL, &g->al_addr);
/* increment statistics */
v->uv_listener_timo++;
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(mifi, g)
mifi_t mifi;
struct listaddr *g;
{
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->mifi = mifi;
cbk->g = g;
return timer_setTimer(g->al_timer, DelVif, cbk);
}
/*
* Delete a timer that was set above.
*/
static int
DeleteTimer(id)
int id;
{
timer_clearTimer(id);
return 0;
}
/*
* Send a group-specific query.
*/
static void
SendQuery(arg)
void *arg;
{
cbk_t *cbk = (cbk_t *) arg;
register struct uvif *v = &uvifs[cbk->mifi];
if (v->uv_flags & VIFF_QUERIER && (v->uv_flags & VIFF_NOLISTENER) == 0) {
send_mld6(MLD6_LISTENER_QUERY, 0, &v->uv_linklocal->pa_addr,
NULL, &cbk->g->al_addr.sin6_addr, v->uv_ifindex,
cbk->q_time, 0, 1);
v->uv_out_mld_query++;
}
cbk->g->al_query = 0;
free(cbk);
}
/*
* Set a timer to send a group-specific query.
*/
static int
SetQueryTimer(g, mifi, to_expire, q_time)
struct listaddr *g;
mifi_t mifi;
int to_expire;
int q_time;
{
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->q_time = q_time;
cbk->mifi = mifi;
return timer_setTimer(to_expire, SendQuery, cbk);
}
/*
* Checks for MLD listener: returns TRUE if there is a receiver for the group
* on the given uvif, or returns FALSE otherwise.
*/
int
check_multicast_listener(v, group)
struct uvif *v;
struct sockaddr_in6 *group;
{
register struct listaddr *g;
/*
* Look for the group in our listener list;
*/
for (g = v->uv_groups; g != NULL; g = g->al_next)
{
if (inet6_equal(group, &g->al_addr))
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef MLD6_PROTO_H
#define MLD6_PROTO_H
#include "vif.h"
extern void query_groups __P((struct uvif *v));
extern int check_grp_membership __P((struct uvif *v,
struct sockaddr_in6 *group));
extern void accept_listener_query __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group,
int tmo));
extern void accept_listener_report __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group));
extern void accept_listener_done __P((struct sockaddr_in6 *src,
struct in6_addr *dst,
struct in6_addr *group));
extern int check_multicast_listener __P((struct uvif *v,
struct sockaddr_in6 *group));
#endif

1495
usr.sbin/pim6sd/mrt.c Normal file

File diff suppressed because it is too large Load Diff

341
usr.sbin/pim6sd/mrt.h Normal file
View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef MRT_H
#define MRT_H
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip_mroute.h>
#include <netinet6/ip6_mroute.h>
#include <string.h>
#include "defs.h"
/* flags for the mrt entries */
#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) */
#define CREATE TRUE
#define DONT_CREATE FALSE
#define MFC_MOVE_FORCE 0x1
#define MFC_UPDATE_FORCE 0x2
/* Macro to duplicate oif info (oif bits, timers) */
#define VOIF_COPY(from , to ) \
do { \
IF_COPY(&from->joined_oifs , &to->joined_oifs); \
IF_COPY(&from->oifs ,&to->oifs ); \
IF_COPY(&from->leaves , &to->leaves); \
IF_COPY(&from->pruned_oifs , &to->leaves ); \
IF_COPY(&from->asserted_oifs ,&to->asserted_oifs); \
bcopy(from->vif_timers , to->vif_timers , \
numvifs*sizeof(from->vif_timers[0])); \
bcopy(from->vif_deletion_delay , to->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 */
struct sockaddr_in6 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 */
struct sockaddr_in6 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 */
struct sockaddr_in6 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;
struct sockaddr_in6 group_addr;
struct in6_addr group_mask;
struct in6_addr 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 advholdtime; /* The advertised holdtime */
u_int16 holdtime; /* The RP holdtime (will be aged) */
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 */
struct sockaddr_in6 group; /* subnet group of multicasts */
struct sockaddr_in6 rpaddr; /* The IPv6 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) */
if_set oifs; /* The current result oifs */
if_set joined_oifs; /* The joined oifs (Join received) */
if_set pruned_oifs; /* The pruned oifs (Prune received) */
if_set asserted_oifs; /* The asserted oifs (lost Assert) */
if_set 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 */
struct sockaddr_in6 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_quad_t pktcnt; /* Number of packets for (s,g) */
u_quad_t bytecnt; /* Number of bytes for (s,g) */
u_quad_t wrong_if; /* Number of packets received on wrong iif for (s,g) */
};
/*
* 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;
struct sockaddr_in6 source;
struct sockaddr_in6 group;
struct sg_count sg_count; /* The (s,g) data retated counters (see above) */
} kernel_cache_t;
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 */
};
/* globals and functions exportations */
extern srcentry_t *srclist;
extern grpentry_t *grplist;
extern void init_pim6_mrt __P(());
extern mrtentry_t *find_route __P((struct sockaddr_in6 *source,
struct sockaddr_in6 *group,
u_int16 flags, char create));
extern grpentry_t *find_group __P((struct sockaddr_in6 *group));
extern srcentry_t *find_source __P((struct sockaddr_in6 *source));
extern void delete_mrtentry __P((mrtentry_t *mrtentry_ptr));
extern void delete_srcentry __P((srcentry_t *srcentry_ptr));
extern void delete_grpentry __P((grpentry_t *grpentry_ptr));
extern void delete_mrtentry_all_kernel_cache __P((mrtentry_t *mrtentry_ptr));
extern void delete_single_kernel_cache __P((mrtentry_t *mrtentry_ptr,
kernel_cache_t *kernel_cache_ptr));
extern void delete_single_kernel_cache_addr __P((mrtentry_t *mrtentry_ptr,
struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern void add_kernel_cache __P((mrtentry_t *mrtentry_ptr,
struct sockaddr_in6 *source, struct sockaddr_in6 *group,
u_int16 flags));
#endif

View File

@ -0,0 +1,86 @@
# Copyright (c) 1999 WIDE Project. 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.
# Copyright (c) 1998 by the University of Oregon.
# 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 Oregon.
# The name of the University of Oregon may not be used to endorse or
# promote products derived from this software without specific prior
# written permission.
#
# THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
# ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
# PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
# NON-INFRINGEMENT.
#
# IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
# TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
# THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Other copyrights might apply to parts of this software and are so
# noted when applicable.
#
#
# Questions concerning this software should be directed to
# Kurt Windisch (kurtw@antc.uoregon.edu)
#
# $Id: Makefile,v 1.2 1999/09/13 01:23:22 jinmei Exp $
# $FreeBSD$
#
#
#Part of this program has been derived from PIM sparse-mode pimd.
#The pimd program is covered by the license in the accompanying file
#named "LICENSE.pimd".
#
#The pimd program is COPYRIGHT 1998 by University of Southern California.
#
#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.
PROG= mtrace6
CFLAGS+=-Wall
CFLAGS+= -I$(.CURDIR)/..
MAN8= mtrace6.8
.include <bsd.prog.mk>

View File

@ -0,0 +1,115 @@
.\" Copyright (C) 1999 WIDE Project.
.\" 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: mtrace6.8,v 1.3 1999/09/12 17:03:18 jinmei Exp $
.\" $FreeBSD$
.\"
.Dd Sep 12, 1999
.Dt MTRACE6 8
.Os KAME
.Sh NAME
.Nm mtrace6
.Nd print IPv6 multicast path from a source to
a receiver
.Sh SYNOPSIS
.Nm
.Op Fl d Ar destination
.Op Fl g Ar gateway
.Op Fl h Ar hops
.Op Fl i Ar interface
.Op Fl m Ar maxhops
.Op Fl n
.Op Fl r Ar response_addr
.Op Fl w Ar waittime
.Ar source
.Ar group
.Sh DESCRIPTION
.Nm
utilizes a tracing feature implemented in multicast routers that is
accessed via an extension to the MLD protocol. A trace query is
passed hop-by-hop along the reverse path from the
.Ar destination
to the
.Ar source ,
collecting hop addresses, packet counts, and routing error conditions
along the path, and then the response is returned to the requestor.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl d Ar destination
Specifies the multicast receiver that the query wants to trace.
It is the host running
.Nm mtrace6
by default.
.It Fl g Ar gateway
Send the trace query via unicast directly to the multicast router
.Ar gateway .
The unicast router must be the last-hop router on the path from the
intended source to the receiver.
.Ar gateway
can also be a multicast address that the last hop router joins.
.It Fl h Ar hops
Set
.Ar hops
to the IPv6 hop limit field of query packets. The default is 64.
.It Fl i Ar interface
Specifies the local interface (on a multi-homed host) for sending
the trace query and as the default for the receiver and the response
destination.
.It Fl m Ar maxhops
Set to
.Ar maxhops
to the maximum number of hops that will be traced from the receiver
back toward the source. The default is 127 hops.
.It Fl n
Print hop addresses numerically rather than symbolically and numerically
(saves a nameserver address-to-name lookup for each router found on
the path).
.It Fl r Ar response_addr
Specify the host that the trace response sends to.
By default, the response will send to the host running
.Nm mtrace6 .
.It Fl w Ar waittime
Set the time to wait for a trace response to
.Ar waittime
seconds. The default is 3 seconds.
.El
.Sh SEE ALSO
.Xr pim6dd 8 ,
.Xr pim6sd 8 ,
.Xr mtrace 8
.Sh BUGS
Multicast trace for IPv6 is experimental. MLD types for query and
response, and packet format are not officially defined.
.Pp
.Ar waittime
specified by the
.Fl w
option is currently meaningless.
.Sh HISTORY
The
.Nm mtrace6
command first appeared in WIDE/KAME IPv6 protocol stack kit.

View File

@ -0,0 +1,661 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <net/if.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <net/if_var.h>
#endif
#include <netinet/in.h>
#include <netinet6/in6.h>
#include <netinet6/in6_var.h>
#include <netinet6/icmp6.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <err.h>
#include "trace.h"
static void usage(), open_socket(), make_packet(), mtrace_loop(), show_result();
static char *gateway, *intface, *source, *group, *receiver, *destination;
static int mldsoc, hops = 64, maxhops = 127, waittime = 3, querylen, opt_n;
static struct sockaddr *gw_sock, *src_sock, *grp_sock, *dst_sock, *rcv_sock;
static char *querypacket;
static char frombuf[1024]; /* XXX: enough size? */
int
main(argc, argv)
int argc;
char *argv[];
{
int op;
/* get parameters */
while((op = getopt(argc, argv, "d:g:h:i:m:nr:w:")) != -1) {
switch(op) {
case 'd':
destination = optarg;
break;
case 'g':
gateway = optarg;
break;
case 'h':
hops = atoi(optarg);
if (hops < 0 || hops > 255) {
warnx("query/response hops must be between 0 and 255");
usage();
}
break;
case 'i':
intface = optarg;
break;
case 'm':
maxhops = atoi(optarg);
if (maxhops < 0 || maxhops > 255) {
warnx("maxhops must be between 0 and 255");
usage();
}
break;
case 'n':
opt_n = 1;
break;
case 'r':
receiver = optarg;
break;
case 'w':
waittime = atoi(optarg);
break;
case '?':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (argc < 2)
usage();
source = argv[0];
group = argv[1];
/* examine addresses and open a socket */
open_socket();
/* construct a query packet according to the specified parameters */
make_packet();
mtrace_loop();
}
static char *
proto_type(type)
u_int type;
{
static char buf[80];
switch (type) {
case PROTO_DVMRP:
return ("DVMRP");
case PROTO_MOSPF:
return ("MOSPF");
case PROTO_PIM:
return ("PIM");
case PROTO_CBT:
return ("CBT");
case PROTO_PIM_SPECIAL:
return ("PIM/Special");
case PROTO_PIM_STATIC:
return ("PIM/Static");
case PROTO_DVMRP_STATIC:
return ("DVMRP/Static");
case 0:
return ("None");
default:
(void) sprintf(buf, "Unknown protocol code %d", type);
return (buf);
}
}
static char *
pr_addr(addr, numeric)
struct sockaddr_in6 *addr;
int numeric;
{
static char buf[MAXHOSTNAMELEN];
int flag = 0;
if (numeric)
flag |= NI_NUMERICHOST;
flag |= NI_WITHSCOPEID;
getnameinfo((struct sockaddr *)addr, addr->sin6_len, buf, sizeof(buf),
NULL, 0, flag);
return (buf);
}
static void
setqid(family, query)
int family;
char *query;
{
struct tr6_query *q6;
switch(family) {
case AF_INET6:
q6 = (struct tr6_query *)((struct mld6_hdr *)query + 1);
q6->tr_qid = (u_int32_t)random();
}
}
static void
mtrace_loop()
{
int nsoc, fromlen, rcvcc;
struct timeval tv, tv_wait;
struct fd_set fds;
struct sockaddr_storage from_ss;
struct sockaddr *from_sock = (struct sockaddr *)&from_ss;
/* initializa random number of query ID */
gettimeofday(&tv, 0);
srandom(tv.tv_usec);
while(1) { /* XXX */
setqid(gw_sock->sa_family, querypacket);
if (sendto(mldsoc, (void *)querypacket, querylen, 0, gw_sock,
gw_sock->sa_len) < 0)
err(1, "sendto");
tv_wait.tv_sec = waittime;
tv_wait.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(mldsoc, &fds);
if ((nsoc = select(mldsoc + 1, &fds, NULL, NULL, &tv_wait)) < 0)
err(1, "select");
if (nsoc == 0) {
printf("Timeout\n");
exit(0); /* XXX try again? */
}
fromlen = sizeof(from_ss);
if ((rcvcc = recvfrom(mldsoc, frombuf, sizeof(frombuf), 0,
from_sock, &fromlen))
< 0)
err(1, "recvfrom");
show_result(from_sock, rcvcc);
exit(0); /* XXX */
}
}
char *fwd_code[] = {"NOERR", "WRONGIF", "SPRUNE", "RPRUNE", "SCOPED", "NORT",
"WRONGLH", "NOFWD", "RP", "RPFIF", "NOMC", "HIDDEN"};
char *fwd_errcode[] = {"", "NOSPC", "OLD", "ADMIN"};
static char *
str_rflags(flag)
int flag;
{
if (0x80 & flag) { /* fatal error */
flag &= ~0x80;
if (flag >= sizeof(fwd_errcode) / sizeof(char *) ||
flag == 0) {
warnx("unknown error code(%d)", flag);
return("UNKNOWN");
}
return(fwd_errcode[flag]);
}
/* normal code */
if (flag >= sizeof(fwd_code) / sizeof(char *)) {
warnx("unknown forward code(%d)", flag);
return("UNKNOWN");
}
return(fwd_code[flag]);
}
static void
show_ip6_result(from6, datalen)
struct sockaddr_in6 *from6;
int datalen;
{
struct mld6_hdr *mld6_tr_resp = (struct mld6_hdr *)frombuf;
struct mld6_hdr *mld6_tr_query = (struct mld6_hdr *)querypacket;
struct tr6_query *tr6_rquery = (struct tr6_query *)(mld6_tr_resp + 1);
struct tr6_query *tr6_query = (struct tr6_query *)(mld6_tr_query + 1);
struct tr6_resp *tr6_resp = (struct tr6_resp *)(tr6_rquery + 1),
*rp, *rp_end;
int i;
if (datalen < sizeof(*mld6_tr_resp) + sizeof(*tr6_rquery) +
sizeof(*tr6_resp)) {
warnx("show_ip6_result: receive data length(%d) is short",
datalen);
return;
}
switch(mld6_tr_resp->mld6_type) {
case MLD6_MTRACE_RESP:
if ((datalen - sizeof(*mld6_tr_resp) - sizeof(*tr6_rquery)) %
sizeof(*tr6_resp)) {
warnx("show_ip6_result: incomplete response (%d bytes)",
datalen);
return;
}
rp_end = (struct tr6_resp *)((char *)mld6_tr_resp + datalen);
/* sanity check for the response */
if (tr6_query->tr_qid != tr6_rquery->tr_qid ||
!IN6_ARE_ADDR_EQUAL(&tr6_query->tr_src, &tr6_rquery->tr_src) ||
!IN6_ARE_ADDR_EQUAL(&tr6_query->tr_dst, &tr6_rquery->tr_dst))
return; /* XXX: bark here? */
for (i = 0, rp = tr6_resp; rp < rp_end; i++, rp++) {
struct sockaddr_in6 sa_resp, sa_upstream;
/* reinitialize the sockaddr. paranoid? */
memset((void *)&sa_resp, 0, sizeof(sa_resp));
sa_resp.sin6_family = AF_INET6;
sa_resp.sin6_len = sizeof(sa_resp);
memset((void *)&sa_upstream, 0, sizeof(sa_upstream));
sa_upstream.sin6_family = AF_INET6;
sa_upstream.sin6_len = sizeof(sa_upstream);
sa_resp.sin6_addr = rp->tr_lcladdr;
sa_upstream.sin6_addr = rp->tr_rmtaddr;
/* print information for the router */
printf("%3d ", -i);/* index */
/* router address and incoming/outgoing interface */
printf("%s", pr_addr((struct sockaddr *)&sa_resp, opt_n));
printf("(%s/%ld->%ld) ",
pr_addr((struct sckaddr *)&sa_upstream),
ntohl(rp->tr_inifid), ntohl(rp->tr_outifid));
/* multicast routing protocol type */
printf("%s ", proto_type(rp->tr_rproto));
/* forwarding error code */
printf("%s", str_rflags(rp->tr_rflags & 0xff));
putchar('\n');
}
break;
default: /* impossible... */
warnx("show_ip6_result: invalid ICMPv6 type(%d)",
mld6_tr_resp->mld6_type); /* assert? */
break;
}
}
static void
show_result(from, datalen)
struct sockaddr *from;
int datalen;
{
switch(from->sa_family) {
case AF_INET6:
show_ip6_result((struct sockaddr_in6 *)from, datalen);
break;
default:
errx(1, "show_result: illegal AF(%d) on recv", from->sa_family);
}
}
static void
set_sockaddr(addrname, hints, sap)
char *addrname;
struct addrinfo *hints;
struct sockaddr *sap;
{
struct addrinfo *res;
int ret_ga;
ret_ga = getaddrinfo(addrname, NULL, hints, &res);
if (ret_ga)
errx(1, "getaddrinfo faild: %s", gai_strerror(ret_ga));
if (!res->ai_addr)
errx(1, "getaddrinfo failed");
memcpy((void *)sap, (void *)res->ai_addr, res->ai_addr->sa_len);
freeaddrinfo(res);
}
static int
is_multicast(sa)
struct sockaddr *sa;
{
switch(sa->sa_family) {
case AF_INET6:
if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr))
return 1;
else
return 0;
break;
default:
return 0; /* XXX: support IPv4? */
}
}
static char *
all_routers_str(family)
int family;
{
switch(family) {
case AF_INET6:
return("ff02::1");
default:
errx(1, "all_routers_str: unknown AF(%d)", family);
}
}
int
ip6_validaddr(ifname, addr)
char *ifname;
struct sockaddr_in6 *addr;
{
int s;
struct in6_ifreq ifr6;
u_int32_t flags6;
/* we need a global address only...XXX: should be flexible? */
if (IN6_IS_ADDR_LOOPBACK(&addr->sin6_addr) ||
IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) ||
IN6_IS_ADDR_SITELOCAL(&addr->sin6_addr))
return(0);
/* get IPv6 dependent flags and examine them */
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "ip6_validaddr: socket");
strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *addr;
if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0)
err(1, "ioctl(SIOCGIFAFLAG_IN6)");
close(s);
flags6 = ifr6.ifr_ifru.ifru_flags6;
if (flags6 & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE |
IN6_IFF_DUPLICATED | IN6_IFF_DETACHED))
return(0);
return(1);
}
int
get_my_sockaddr(family, addrp)
int family;
struct sockaddr *addrp;
{
#define IF_BUFSIZE 8192 /* XXX: adhoc...should be customizable? */
int i, s;
struct ifconf ifconf;
struct ifreq *ifrp;
static char ifbuf[IF_BUFSIZE];
if ((s = socket(family, SOCK_DGRAM, 0)) < 0)
err(1, "socket");
ifconf.ifc_buf = ifbuf;
ifconf.ifc_len = sizeof(ifbuf);
if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
err(1, "ioctl(SIOCGIFCONF)");
close(s);
for (i = 0; i < ifconf.ifc_len; ) {
ifrp = (struct ifreq *)(ifbuf + i);
if (ifrp->ifr_addr.sa_family == family) {
switch(family) {
case AF_INET6:
if (ip6_validaddr(ifrp->ifr_name,
(struct sockaddr_in6 *)&ifrp->ifr_addr))
goto found;
}
}
i += IFNAMSIZ;
/* i += max(sizeof(sockaddr), ifr_addr.sa_len) */
if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
i += ifrp->ifr_addr.sa_len;
else
i += sizeof(struct sockaddr);
}
return(-1); /* not found */
found:
memcpy((void *)addrp, (void *)&ifrp->ifr_addr, ifrp->ifr_addr.sa_len);
return(0);
#undef IF_BUFSIZE
}
static void
set_hlim(s, addr, hops)
int s, hops;
struct sockaddr *addr;
{
struct sockaddr_in6 *sin6;
int opt;
switch(addr->sa_family) {
case AF_INET6:
sin6 = (struct sockaddr_in6 *)addr;
opt = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) ?
IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
if (setsockopt(s, IPPROTO_IPV6, opt, (char *)&hops,
sizeof(hops)) == -1)
err(1, "setsockopt(%s)",
(opt == IPV6_MULTICAST_HOPS) ?
"IPV6_MULTICAST_HOPS" : "IPV6_UNICAST_HOPS");
break;
}
}
static void
set_join(s, ifname, group)
int s;
char *ifname;
struct sockaddr *group;
{
struct ipv6_mreq mreq6;
u_int ifindex;
switch(group->sa_family) {
case AF_INET6:
if ((ifindex = if_nametoindex(ifname)) == 0)
err(1, "set_join: if_nametoindex failed for %s", ifname);
mreq6.ipv6mr_multiaddr =
((struct sockaddr_in6 *)group)->sin6_addr;
mreq6.ipv6mr_interface = ifindex;
if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
sizeof(mreq6)) < 0)
err(1, "setsockopt(IPV6_JOIN_GROUP)");
break;
}
}
static void
set_filter(s, family)
{
struct icmp6_filter filter6;
switch(family) {
case AF_INET6:
ICMP6_FILTER_SETBLOCKALL(&filter6);
ICMP6_FILTER_SETPASS(MLD6_MTRACE_RESP, &filter6);
if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter6,
sizeof(filter6)) < 0)
err(1, "setsockopt(ICMP6_FILTER)");
break;
}
}
static void
open_socket()
{
struct addrinfo hints;
static struct sockaddr_storage gw_ss, src_ss, grp_ss, dst_ss, rcv_ss;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6; /* to be independent of AF? */
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
/* multicast group(must be specified) */
grp_sock = (struct sockaddr *)&grp_ss;
set_sockaddr(group, &hints, grp_sock);
if (!is_multicast(grp_sock))
errx(1, "group(%s) is not a multicast address", group);
/* multicast source(must be specified) */
src_sock = (struct sockaddr *)&src_ss;
set_sockaddr(source, &hints, src_sock);
if (is_multicast(src_sock))
errx(1, "source(%s) is not a unicast address", source);
/* last hop gateway for the destination(if specified) */
gw_sock = (struct sockaddr *)&gw_ss;
if (gateway) /* can be either multicast or unicast */
set_sockaddr(gateway, &hints, gw_sock);
else {
char *r = all_routers_str(grp_sock->sa_family);
set_sockaddr(r, &hints, gw_sock);
}
/* destination address for the trace */
dst_sock = (struct sockaddr *)&dst_ss;
if (destination) {
set_sockaddr(destination, &hints, dst_sock);
if (is_multicast(dst_sock))
errx(1, "destination(%s) is not a unicast address",
destination);
}
else {
/* XXX: consider interface? */
get_my_sockaddr(grp_sock->sa_family, dst_sock);
}
/* response receiver(if specified) */
rcv_sock = (struct sockaddr *)&rcv_ss;
if (receiver) { /* can be either multicast or unicast */
set_sockaddr(receiver, &hints, rcv_sock);
if (is_multicast(rcv_sock) &&
intface == NULL) {
#ifdef notyet
warnx("receive I/F is not specified for multicast"
"response(%s)", receiver);
intface = default_intface;
#else
errx(1, "receive I/F is not specified for multicast"
"response(%s)", receiver);
#endif
}
}
else {
/* XXX: consider interface? */
get_my_sockaddr(grp_sock->sa_family, rcv_sock);
}
if ((mldsoc = socket(hints.ai_family, hints.ai_socktype,
hints.ai_protocol)) < 0)
err(1, "socket");
/* set necessary socket options */
if (hops)
set_hlim(mldsoc, gw_sock, hops);
if (receiver && is_multicast(rcv_sock))
set_join(mldsoc, intface, rcv_sock);
set_filter(mldsoc, grp_sock->sa_family);
}
static void
make_ip6_packet()
{
struct mld6_hdr *mld6_tr_query;
struct tr6_query *tr6_query;
querylen = sizeof(*mld6_tr_query) + sizeof(*tr6_query);
if ((querypacket = malloc(querylen)) == NULL)
errx(1, "make_ip6_packet: malloc failed");
memset(querypacket, 0, querylen);
/* fill in MLD header */
mld6_tr_query = (struct mld6_hdr *)querypacket;
mld6_tr_query->mld6_type = MLD6_MTRACE;
mld6_tr_query->mld6_code = maxhops & 0xff;
mld6_tr_query->mld6_addr = ((struct sockaddr_in6 *)grp_sock)->sin6_addr;
/* fill in mtrace query fields */
tr6_query = (struct tr6_query *)(mld6_tr_query + 1);
tr6_query->tr_src = ((struct sockaddr_in6 *)src_sock)->sin6_addr;
tr6_query->tr_dst = ((struct sockaddr_in6 *)dst_sock)->sin6_addr;
tr6_query->tr_raddr = ((struct sockaddr_in6 *)rcv_sock)->sin6_addr;
tr6_query->tr_rhlim = 0xff & hops;
}
static void
make_packet()
{
switch(grp_sock->sa_family) {
case AF_INET6:
make_ip6_packet();
break;
default:
errx(1, "make_packet: unsupported AF(%d)", grp_sock->sa_family);
}
}
static void
usage()
{
errx(1,
"[-d destination] [-g gateway] [-h hops] [-i interface] "
"[-m maxhops] [-n] [-r response_addr] [-w waittime] source group");
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#ifndef PATHNAMES_H
#define PATHNAMES_H
#define _PATH_PIM6D_CONF "/usr/local/v6/etc/pim6sd.conf"
#define _PATH_PIM6D_LOGFILE "/var/log/pim6sd.log"
#if (defined(BSD) && (BSD >= 199103))
#define _PATH_PIM6D_PID "/var/run/pim6sd.pid"
#define _PATH_PIM6D_GENID "/var/run/pim6sd.genid"
#define _PATH_PIM6D_DUMP "/var/run/pim6sd.dump"
#define _PATH_PIM6D_CACHE "/var/run/pim6sd.cache"
#define _PATH_PIM6D_STAT "/var/run/pim6sd.stat"
#else
#define _PATH_PIM6D_PID "/etc/pim6sd.pid"
#define _PATH_PIM6D_GENID "/etc/pim6sd.genid"
#define _PATH_PIM6D_DUMP "/etc/pim6sd.dump"
#define _PATH_PIM6D_CACHE "/etc/pim6sd.cache"
#define _PATH_PIM6D_STAT "/etc/pim6sd.stat"
#endif
#endif

507
usr.sbin/pim6sd/pim6.c Normal file
View File

@ -0,0 +1,507 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*/
/*
* Copyright (C) 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <netinet6/ip6_mroute.h>
#include <netinet6/pim6.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <syslog.h>
#include <signal.h>
#include "mld6.h"
#include "defs.h"
#include "kern.h"
#include "pim6.h"
#include "pimd.h"
#include "pim6_proto.h"
#include "inet6.h"
#include "debug.h"
struct sockaddr_in6 allpim6routers_group;
int pim6_socket;
char *pim6_recv_buf;
char *pim6_send_buf;
static struct sockaddr_in6 from;
static struct iovec sndiovpim[2];
static struct iovec rcviovpim[2];
static struct msghdr sndmhpim,
rcvmhpim;
static u_char sndcmsgbufpim[CMSG_SPACE(sizeof(struct in6_pktinfo))];
static u_char rcvcmsgbufpim[CMSG_SPACE(sizeof(struct in6_pktinfo))];
/*
* Local function definitions.
*/
static void pim6_read __P((int f, fd_set *rfd));
static void accept_pim6 __P((int recvlen));
static int pim6_cksum __P((u_short *, struct in6_addr *,
struct in6_addr *, int));
void init_pim6()
{
struct cmsghdr *cmsgp;
int on;
if ( (pim6_recv_buf = malloc( RECV_BUF_SIZE)) == NULL ||
(pim6_send_buf = malloc (RECV_BUF_SIZE)) == NULL)
log(LOG_ERR,errno,"pim6 buffer allocation");
IF_DEBUG(DEBUG_KERN)
log(LOG_DEBUG,0,"%d octets allocated for the emit/recept buffer pim6",RECV_BUF_SIZE);
if( (pim6_socket = socket(AF_INET6,SOCK_RAW,IPPROTO_PIM)) < 0 )
log(LOG_ERR,errno,"pim6_socket");
k_set_rcvbuf(pim6_socket,SO_RECV_BUF_SIZE_MAX,SO_RECV_BUF_SIZE_MIN);
k_set_hlim(pim6_socket,MINHLIM);
k_set_loop(pim6_socket,FALSE);
memset(&allpim6routers_group, 0, sizeof(allpim6routers_group));
allpim6routers_group.sin6_len = sizeof(allpim6routers_group);
allpim6routers_group.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, "ff02::d",
(void *)&allpim6routers_group.sin6_addr) != 1 )
log(LOG_ERR, 0, "inet_pton failed for ff02::d");
memset(&sockaddr6_d, 0, sizeof(sockaddr6_d));
sockaddr6_d.sin6_len = sizeof(sockaddr6_d);
sockaddr6_d.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, "ff00::",
(void *)&sockaddr6_d.sin6_addr) != 1)
log(LOG_ERR, 0, "inet_pton failed for ff00::");
/* specify to tell receiving interface */
on = 1;
#ifdef IPV6_RECVPKTINFO
if (setsockopt(pim6_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_RECVPKTINFO)");
#else
if (setsockopt(pim6_socket, IPPROTO_IPV6, IPV6_PKTINFO, &on,
sizeof(on)) < 0)
log(LOG_ERR, errno, "setsockopt(IPV6_PKTINFO)");
#endif
/* initialize msghdr for receiving packets */
rcviovpim[0].iov_base = (caddr_t) pim6_recv_buf;
rcviovpim[0].iov_len = RECV_BUF_SIZE;
rcvmhpim.msg_name = (caddr_t ) &from;
rcvmhpim.msg_namelen = sizeof (from);
rcvmhpim.msg_iov = rcviovpim;
rcvmhpim.msg_iovlen = 1;
rcvmhpim.msg_control = (caddr_t ) rcvcmsgbufpim;
rcvmhpim.msg_controllen = sizeof (rcvcmsgbufpim);
sndmhpim.msg_namelen=sizeof(struct sockaddr_in6);
sndmhpim.msg_iov=sndiovpim;
sndmhpim.msg_iovlen=1;
sndmhpim.msg_control=(caddr_t)sndcmsgbufpim;
sndmhpim.msg_controllen=sizeof(sndcmsgbufpim);
cmsgp=(struct cmsghdr *)sndcmsgbufpim;
cmsgp->cmsg_len=CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsgp->cmsg_level=IPPROTO_IPV6;
cmsgp->cmsg_type=IPV6_PKTINFO;
if ( register_input_handler(pim6_socket, pim6_read) <0)
log(LOG_ERR,0,"Registering pim6 socket");
/* 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
pim6_read(f, rfd)
int f;
fd_set *rfd;
{
register int pim6_recvlen;
#ifdef SYSV
sigset_t block, oblock;
#else
register int omask;
#endif
pim6_recvlen = recvmsg(pim6_socket,&rcvmhpim,0);
if (pim6_recvlen < 0) {
if (errno != EINTR)
log(LOG_ERR, errno, "PIM6 recvmsg");
return;
}
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
/* Use of omask taken from main() */
omask = sigblock(sigmask(SIGALRM));
#endif /* SYSV */
accept_pim6(pim6_recvlen);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif /* SYSV */
}
static void
accept_pim6(pimlen)
int pimlen;
{
register struct pim *pim;
struct sockaddr_in6 dst;
struct in6_pktinfo *pi=NULL;
struct sockaddr_in6 *src = (struct sockaddr_in6 *)rcvmhpim.msg_name;
struct cmsghdr *cm;
int ifindex=0;
/* sanity check */
if (pimlen < sizeof(pim)) {
log(LOG_WARNING, 0,
"data field too short (%u bytes) for PIM header, from %s",
pimlen, inet6_fmt(&src->sin6_addr));
return;
}
pim = (struct pim *)rcvmhpim.msg_iov[0].iov_base;
/* extract vital information via Advanced API */
for(cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhpim);
cm;
cm =(struct cmsghdr *)CMSG_NXTHDR(&rcvmhpim , cm ))
{
if( cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_PKTINFO &&
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
{
pi=(struct in6_pktinfo *)(CMSG_DATA(cm));
dst.sin6_addr=pi->ipi6_addr;
ifindex = pi->ipi6_ifindex;
if (IN6_IS_ADDR_LINKLOCAL(&dst.sin6_addr))
dst.sin6_scope_id = ifindex;
else
dst.sin6_scope_id = 0;
}
}
if(pi==NULL)
log(LOG_ERR,0,"pim6_socket : unable to get destination packet");
if(ifindex==0)
log(LOG_ERR,0,"pim6_socket : unable to get ifindex");
#define NOSUCHDEF
#ifdef NOSUCHDEF /* TODO: delete. Too noisy */
IF_DEBUG(DEBUG_PIM_DETAIL) {
IF_DEBUG(DEBUG_PIM) {
log(LOG_DEBUG, 0, "Receiving %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
}
}
#endif /* NOSUCHDEF */
/* Check of PIM version is already done in the kernel */
/*
* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address)
* is it necessary?
*/
/* Checksum verification is done in the kernel. */
switch (pim->pim_type) {
case PIM_HELLO:
receive_pim6_hello(src, (char *)(pim), pimlen);
break;
case PIM_REGISTER:
receive_pim6_register(src, &dst, (char *)(pim), pimlen);
break;
case PIM_REGISTER_STOP:
receive_pim6_register_stop(src, &dst, (char *)(pim), pimlen);
break;
case PIM_JOIN_PRUNE:
receive_pim6_join_prune(src, &dst, (char *)(pim), pimlen);
break;
case PIM_BOOTSTRAP:
receive_pim6_bootstrap(src, &dst, (char *)(pim), pimlen);
break;
case PIM_ASSERT:
receive_pim6_assert(src, &dst, (char *)(pim), pimlen);
break;
case PIM_GRAFT:
pim6dstat.in_pim6_graft++;
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
case PIM_GRAFT_ACK:
pim6dstat.in_pim6_graft_ack++;
log(LOG_INFO, 0, "ignore %s from %s",
packet_kind(IPPROTO_PIM, pim->pim_type, 0),
inet6_fmt(&src->sin6_addr));
break;
case PIM_CAND_RP_ADV:
receive_pim6_cand_rp_adv(src, &dst, (char *)(pim), pimlen);
break;
default:
log(LOG_INFO, 0,
"ignore unknown PIM message code %u from %s",
pim->pim_type,
inet6_fmt(&src->sin6_addr));
break;
}
}
void
send_pim6(char *buf, struct sockaddr_in6 *src,
struct sockaddr_in6 *dst, int type, int datalen)
{
struct pim *pim;
int setloop=0;
int ifindex=0;
int sendlen=sizeof(struct pim)+datalen;
struct cmsghdr *cmsgp;
struct in6_pktinfo *sndpktinfo;
sndiovpim[0].iov_base=(caddr_t)buf;
sndiovpim[0].iov_len=datalen+sizeof(struct pim);
cmsgp=(struct cmsghdr *)sndcmsgbufpim;
sndpktinfo=(struct in6_pktinfo *)CMSG_DATA(cmsgp);
sndmhpim.msg_name=(caddr_t)dst;
pim = (struct pim *)buf;
pim->pim_type = type;
pim->pim_ver = PIM_PROTOCOL_VERSION;
pim->pim_rsv = 0;
pim->pim_cksum = 0;
if(pim->pim_type == PIM_REGISTER)
{
sendlen = sizeof(struct pim)+sizeof(pim_register_t);
}
pim->pim_cksum = pim6_cksum((u_int16 *)pim,
&src->sin6_addr, &dst->sin6_addr,
sendlen);
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
{
if (!IN6_IS_ADDR_LINKLOCAL(&src->sin6_addr))
{
log(LOG_WARNING, 0,
"trying to send pim multicast packet "
"with non linklocal src(%s), ignoring",
inet6_fmt(&src->sin6_addr));
return;
}
sndmhpim.msg_control=NULL;
sndmhpim.msg_controllen=0;
ifindex=src->sin6_scope_id;
k_set_if(pim6_socket , ifindex);
if( IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allnodes_group.sin6_addr) ||
IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allrouters_group.sin6_addr) ||
IN6_ARE_ADDR_EQUAL(&dst->sin6_addr,
&allpim6routers_group.sin6_addr))
{
setloop=1;
k_set_loop(pim6_socket, TRUE);
}
}
else
{
sndmhpim.msg_control=(caddr_t)sndcmsgbufpim;
sndmhpim.msg_controllen=sizeof(sndcmsgbufpim);
sndpktinfo->ipi6_ifindex=src->sin6_scope_id;
memcpy(&sndpktinfo->ipi6_addr, &src->sin6_addr,
sizeof(sndpktinfo->ipi6_addr));
}
if( sendmsg(pim6_socket, &sndmhpim, 0) <0 )
if (errno == ENETDOWN)
check_vif_state();
else
log(LOG_WARNING, errno, "sendmsg from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(&dst->sin6_addr));
if(setloop)
k_set_loop(pim6_socket, FALSE);
return;
}
/* ============================== */
/*
* Checksum routine for Internet Protocol family headers (Portable Version).
*
* This routine is very heavily used in the network
* code and should be modified for each CPU to be as fast as possible.
*/
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
static union {
u_short phs[4];
struct {
u_long ph_len;
u_char ph_zero[3];
u_char ph_nxt;
} ph;
} uph;
/*
* 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.
*/
int pim6_cksum(u_short *addr, struct in6_addr *src ,struct in6_addr *dst , int len )
{
register int nleft = len;
register u_short *w;
register int sum = 0;
u_short answer = 0;
/*
* First create IP6 pseudo header and calculate a summary.
*/
w = (u_short *)src;
uph.ph.ph_len = htonl(len);
uph.ph.ph_nxt = IPPROTO_PIM;
/* IPv6 source address */
sum += w[0];
/* XXX: necessary? */
if (!(IN6_IS_ADDR_LINKLOCAL(src) || IN6_IS_ADDR_MC_LINKLOCAL(src)))
sum += w[1];
sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
sum += w[6]; sum += w[7];
/* IPv6 destination address */
w = (u_short *)dst;
sum += w[0];
/* XXX: necessary? */
if (!(IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst)))
sum += w[1];
sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
sum += w[6]; sum += w[7];
/* Payload length and upper layer identifier */
sum += uph.phs[0]; sum += uph.phs[1];
sum += uph.phs[2]; sum += uph.phs[3];
/*
* Secondly calculate a summary of the first mbuf excluding offset.
*/
w = addr;
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);
}

70
usr.sbin/pim6sd/pim6.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef PIM6_H
#define PIM6_H
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netinet6/ip6_mroute.h>
extern struct sockaddr_in6 allpim6routers_group;
extern char *pim6_send_buf;
extern int pim6_socket;
void init_pim6();
extern void send_pim6 __P((char *buf, struct sockaddr_in6 *src,
struct sockaddr_in6 *dst, int type,
int datalen));
#endif

4126
usr.sbin/pim6sd/pim6_proto.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef PIM6_PROTO_H
#define PIM6_PROTO_H
#include "defs.h"
#include "vif.h"
#include "mrt.h"
extern build_jp_message_t *build_jp_message_pool;
extern int build_jp_message_pool_counter;
extern struct sockaddr_in6 sockaddr6_any;
extern struct sockaddr_in6 sockaddr6_d;
extern int receive_pim6_hello __P((struct sockaddr_in6 *src,
char *pim_message, int datalen));
extern int send_pim6_hello __P((struct uvif *v, u_int16 holdtime));
extern void delete_pim6_nbr __P((pim_nbr_entry_t *nbr_delete));
extern int receive_pim6_register __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message, int datalen));
extern int send_pim6_null_register __P((mrtentry_t *r));
extern int receive_pim6_register_stop __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message,
int datalen));
extern int send_pim6_register __P((char *pkt));
extern int receive_pim6_join_prune __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message, int datalen));
extern int join_or_prune __P((mrtentry_t *mrtentry_ptr,
pim_nbr_entry_t *upstream_router));
extern int receive_pim6_assert __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message, int datalen));
extern int send_pim6_assert __P((struct sockaddr_in6 *source, struct sockaddr_in6 *group,
vifi_t vifi,
mrtentry_t *mrtentry_ptr));
extern int send_periodic_pim6_join_prune __P((vifi_t vifi,
pim_nbr_entry_t *pim_nbr,
u_int16 holdtime));
extern int add_jp_entry __P((pim_nbr_entry_t *pim_nbr,
u_int16 holdtime, struct sockaddr_in6 *group,
u_int8 grp_msklen, struct sockaddr_in6 *source,
u_int8 src_msklen,
u_int16 addr_flags,
u_int8 join_prune));
extern void pack_and_send_jp6_message __P((pim_nbr_entry_t *pim_nbr));
extern int receive_pim6_cand_rp_adv __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message, int datalen));
extern int receive_pim6_bootstrap __P((struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
char *pim_message, int datalen));
extern int send_pim6_cand_rp_adv __P(());
extern void send_pim6_bootstrap __P(());
#endif

149
usr.sbin/pim6sd/pim6sd.8 Normal file
View File

@ -0,0 +1,149 @@
.\" Copyright (C) 1999 WIDE Project.
.\" 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: pim6sd.8,v 1.4 1999/12/16 05:38:06 jinmei Exp $
.\" $FreeBSD$
.\"
.Dd June 10, 1999
.Dt PIM6SD 8
.Os KAME
.Sh NAME
.Nm pim6sd
.Nd PIM for IPv6 sparse mode daemon
.Sh SYNOPSIS
.Nm
.Op Fl c Ar configfile
.Op Fl d Op debug_level Op ,debug_level
.Op Fl f
.Sh DESCRIPTION
.Nm Pim6sd
is an IPv6 multicast routing daemon, which supports
PIMv2(Protocol Independent Multicast Version 2) sparse mode
for IPv6.
.Pp
Options supported by
.Nm pim6sd :
.Bl -tag -width Ds
.It Fl c Ar configfile
Specify alternate location,
.Ar configfile ,
for configuration file.
By default,
.Pa /usr/local/v6/etc/pim6sd.conf
is used.
.It Fl d
Specify debug levels. If this option is specified without any arguments,
all debug messages will be printed out.
A subset of the messages to be printed out can be specified
as arguments of the option.
Valid debug levels are
.Ic mld_proto, mld_timer, mld_member, mld, switch, trace, mtrace, traceroute,
.Ic timeout, callout, pkt, packets, interfaces, vif, kernel, cache, mfc,
.Ic k_cache, k_mfc, rsrr, pim_detail, pim_hello, pim_neighbors, pim_register,
.Ic registers, pim_join_prune, pim_j_p, pim_jp, pim_bootstrap, pim_bsr, bsr,
.Ic bootstrap, pim_asserts, pim_cand_rp, pim_c_rp, pim_rp, rp, pim_routes,
.Ic pim_routing, pim_mrt, pim_timers, pim_rpf, rpf, pim, routes, routing,
.Ic mrt, routers, mrouters, neighbors, timers,
and
.Ic asserts.
.It Fl f
Do not become daemon, run in foreground. This option is for debugging
use.
.El
.Pp
.Nm Pim6sd
automatically configures itself to forward on all multicast-capable
interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
the "loopback interface").
To override the default configuration,
configuration commands may be placed in
.Pa /usr/local/v6/etc/pim6sd.conf
(or an alternative file, specified by the "\-c" option).
.Pp
The
.Nm
program dumps its current routing information to a dump file when
it receives a SIGUSR1 signal.
The information includes a list of PIM neighbors,
.Nm
internal multicast routing table, and
BSR and RP related information. Also, the program dumps its internal
statistics to a file when it receives a SIGINFO signal.
.Pp
When
.Nm
receives a SIGUSR2 signal, it rereads the configuration file and
reset its debug level.
.Pp
The
.Nm
program puts its logs to a separate file
.Pa (/var/log/pim6sd.log).
The log level can be configured by the
.Fl d
command line option or the configuration file.
.\"
.Sh FILES
.Bl -tag -width /usr/local/v6/etc/pim6sd.conf -compact
.It Pa /usr/local/v6/etc/pim6sd.conf
The default configuration file.
.It Pa /var/run/pim6sd.dump
The file to which
.Nm
dumps its internal status.
.It Pa /var/run/pim6sd.stat
The file to which
.Nm
dumps its internal statistics.
.It Pa /var/log/pim6sd.log
The pim6sd specific log file.
.El
.Sh SEE ALSO
.Xr daemon 3 ,
.Xr pim6sd.conf 5
.Sh HISTORY
The
.Nm
command is developed by Mickael Hoerdt at LSIIT Laboratory.
It is based on IPv4 PIM sparse-mode
.Nm pimd
developed at University of Southern California,
which has also been derived from
.Nm mrouted.
.Nm Mrouted
is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.
.\"
.Sh BUGS
.Nm Pim6sd
does not contain any unicast routing engine, so a unicast routing
daemon needs to run on the system.
.Pp
The kernel unicast routing table is periodically polled by
.Nm
in order to follow changes of existing unicast routes.
.\"

View File

@ -0,0 +1,330 @@
.\" Copyright (C) 1999 WIDE Project.
.\" 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: pim6sd.conf.5,v 1.7 1999/12/03 07:31:45 jinmei Exp $
.\" $FreeBSD$
.\"
.Dd Oct 6, 1999
.Dt PIM6SD.CONF 5
.Os KAME
.Sh NAME
.Nm pim6sd.conf
.Nd config file for pim6sd, PIM-SM daemon for IPv6
.\"
.Sh DESCRIPTION
The
.Nm pim6sd
configuration file consists of a sequence of statements terminated
by a semi-colon (`;'), each of which specifies how the daemon treats
each interface on the system, specifies some parameters of the PIM
protocol, and requires some special behavior defined by the protocol.
.Pp
Each statement can be constructed by multiple lines.
.Pp
Lines beginning with
.Ql #
are comments.
.\".Pp
.\"Note that
.\".Nm pim6sd
.\"works even without the configuration file, although the daemon
.\"will warn that there is no configuration file.
.\"In such a case, the daemon will automatically set the default value
.\"to each configurable parameter.
.\"
.Pp
The following statements can be specified in the configuration file.
.Pp
.Bl -tag -width Ds -compact
.It Xo
.Ic log
.Ar option...
.Ic ;
.Xc
Specify debug messages to be printed out. Each
.Ar option
usually specifies a subset of the messages to be printed.
If an
.Ar option
begins with
.Ic no ,
it means that the set of the messages that are specified by the option
will not be printed. For example,
.Ic `all nomld'
means that all the messages except MLD related ones will be printed.
Valid options are
.Ic mld_proto, mld_timer, mld_member, mld, switch, trace, mtrace, traceroute,
.Ic timeout, callout, pkt, packets, interfaces, vif, kernel, cache, mfc,
.Ic k_cache, k_mfc, rsrr, pim_detail, pim_hello, pim_neighbors, pim_register,
.Ic registers, pim_join_prune, pim_j_p, pim_jp, pim_bootstrap, pim_bsr, bsr,
.Ic bootstrap, pim_asserts, pim_cand_rp, pim_c_rp, pim_rp, rp, pim_routes,
.Ic pim_routing, pim_mrt, pim_timers, pim_rpf, rpf, pim, routes, routing,
.Ic mrt, routers, mrouters, neighbors, timers, asserts,
and
.Ic all .
.\"
.It Xo
.Ic reverselookup (yes \(ba no);
.Xc
Specifies if a hostname for an IPv6 address should be resolved
on logging.
.Ic yes
means a hostname should be resolved, and
.Ic no
means should not.
By default, a hostname is not resolved.
.\"
.It Xo
.Ic phyint Ar interface
.Op disable
.Ic ;
.Xc
Specifies
.Nm
to ignore the interface even if the interface is multicast-capable.
Note that PIM will be activated on all interfaces by default(including
the case where there is no configuration file).
Interfaces are specified in the form of "name unit", such as
.Ar gif0
and
.Ar ep1.
.\"
.It Xo
.Ic phyint Ar interface
.Op preference Ar preference
.Op metric Ar metric
.Op nolistener
.Ic ;
.Xc
Specifies the preference and/or metric values when sending a PIM
assert message on the interface.
If another optional parameter
.Ic nolistener
is specified,
.Nm pim6sd
will not send any MLD packets on the interface.
This option is usually meaningless but will be useful when
MLD messages are noisy (e.g. when debugging) and there is surely no
listner on the interface.
.\"
.It Xo
.Ic default_source_preference Ar preference;
.Xc
Specifies a default preference value when sending a PIM assert message.
Preferences are used by assert elections to determine upstream routers.
Currently
.Nm pim6sd
cannot reliably obtain preferences and metrics from the
unicast routing protocols, so a default value may be configured.
The default preference is 1024.
.\"
.It Ic default_source_metric Ar metric;
Specifies a default metric value when sending a PIM assert message.
It is recommended that preferences be set such that metrics are never
consulted. However, default metrics may also be set and will default to
1024.
.\"
.It Xo
.Ic granularity Ar second;
.Xc
Specifies timer granularity in seconds.
The default value is 5.
.\"
.It Xo
.Ic hello_period Ar period Ar coef;
.Xc
.Ar Period
specifies the period in second between 2 hello messages.
.Ar Coef
is the coefficient to determine the hello holdtime;
the holdtime will be
.Ar period
*
.Ar coef .
The default values of the period and the coefficient are 30 and 3.5,
respectively. The default holdtime is 105 seconds as a result.
.\"
.It Xo
.Ic join_prune_period Ar period Ar coef;
.Xc
.Ar Period
specifies the period in second between 2 join/prune messages.
.Ar Coef
is the coefficient to determine the join/prune holdtime;
the holdtime will be
.Ar period
*
.Ar coef .
The default values of the period and the coefficient are 60 and 3.5,
respectively. Consequently, the default holdtime is 210 seconds.
.\"
.It Xo
.Ic data_timeout Ar timer;
.Xc
Specifies the time after which (S,G) state for a silent source will be
deleted.
The default value is 210.
.\"
.It Xo
.Ic register_suppression_timeout Ar interval;
.Xc
.Ar Interval
specifies the interval between receiving a Register-Stop and allowing
PIM Register to be send again.
The default value is 60.
.\"
.It Xo
.Ic probe_time Ar timer;
.Xc
.Ar Timer
specifies the time between sending a null Register and the
Register-Suppression-Timer expiring unless it is restarted by
receiving a Register-Stop.
The default value is 5.
.\"
.It Xo
.Ic assert_timeout Ar interval;
.Xc
.Ar Interval
specifies the interval between the last time an Assert is received and
the time at which the assert is timeout.
The default value is 180.
.\"
.It Xo
.Ic cand_rp
.Op Ar interface
.Op Ic time Ar time
.Op Ic priority Ar priority
.Ic ;
.Xc
Specifies to act as a candidate Rendezvous Point(RP).
It is recommended to specify
.Ic cand_rp
only in typical usage.
All other parameters are optional and will be set automatically.
If an
.Ar interface
is specified,
.Nm pim6sd
will search for a global address on the specified interface
and set the address in Candidate RP Advertisements.
An optional parameter
.Ic time
specifies the interval of two succeeding advertisements in seconds.
Its default value is 60.
2.5 *
.Ar time
will be set to Candidate-RP-Advertisement messages.
Another optional parameter
.Ic priority
specifies the priority of the RP.
The default value is 0, which means the highest priority.
.\"
.It Xo
.Ic group_prefix Ar prefix;
.Xc
When acting as a Rendezvous Point(RP),
.Ar prefix
specifies a group prefix that the RP will handle.
.\"
.It Xo
.Ic cand_bootstrap_router
.Op Ar interface
.Op Ic time Ar time
.Op Ic priority Ar priority
.Ic ;
.Xc
Specifies to act as a candidate bootstrap router(BSR).
It is recommended to specify
.Ic cand_bootstrap_router
only in typical usage.
All other parameters are optional and will be set automatically.
If an
.Ar interface
is specified,
.Nm pim6sd
will search for a global address on the specified interface
and set the address in Bootstrap messages.
An optional parameter
.Ic time
specifies the interval of two succeeding bootstraps in seconds.
Its default value is 60.
Another optional parameter
.Ic priority
specifies the priority of the RP.
The default value is 0, which means the lowest priority.
.\"
.It Xo
.Ic switch_register_threshold Ic rate Ar rate Ic interval Ar interval;
.Xc
Specifies the threshold that a Rendezvous Point(RP) switches to a shortest
path tree, which is valid only when acting as an RP.
.Ic rate
specifies the threshold in bits per second, and
.Ic interval
specifies the interval of checking the rate in seconds.
The default values are 50000 and 20, respectively.
\"
.It Xo
.Ic switch_data_threshold Ic rate Ar rate Ic interval Ar interval;
.Xc
Specifies the threshold that a last hop router switches to a shortest
path tree.
.Ic rate
specifies the threshold in bits per second, and
.Ic interval
specifies the interval of checking the rate in seconds.
The default values are 50000 and 20, respectively.
.El
.\"
.Sh EXAMPLE
.Bd -literal -offset
#phyint gif0 disable;
#phyint ep0 preference 101;
phyint de0 disable;
#
#followings are for a candidate Rendezvous Point, which should usually
#be disabled.
cand_bootstrap_router;
cand_rp;
.Ed
.Sh SEE ALSO
.Xr pim6sd 8
.Sh HISTORY
The
.Nm pim6sd
command is developed by Mickael Hoerdt at LSIIT Laboratory.
It is based on IPv4 PIM sparse-mode
.Nm pimd
developed at University of Southern California,
which has also been derived from
.Nm mrouted.
.Nm Mrouted
is COPYRIGHT 1989 by The Board of Trustees of
Leland Stanford Junior University.
.\" .Sh BUGS
.\" (to be written)

View File

@ -0,0 +1,107 @@
# $FreeBSD$
#
#The timer granularity.
#More this value is small,more pim6sd will be accurate
#default if not specified : 5
#BE SURE to have to same granularity on ALL routers,
#otherwise....
#granularity 5;
#syntax : phyint <interface> <disable> <metric> [metric] <preference> [preference]
#metric and pref are for the asserts messages
#samples :
#phyint ed1 disable;
#phyint de0 disable;
#phyint ed0 disable;
#phyint gif0 disable;
#---------------Protocol timer specifications---------------------------#
#Notes : theses value are the default spec value!
#do not touch it if you don't know what you do!!
#you MUST change theses values according to the granularity value!
#syntax : 'hello_period <number> <coef>'.
# number is the period in second between 2 hello messages
# and coef is the coef to deterimine the hello holdtime=hello_period*coef
# default if not specified: 30 3.5
#hello_period 30 3.5;
#syntax : 'join_prune_period <number> <coef>'.
# number is the period in second between 2 join/prune messages
# and coef is the coef to deterimine the join/prune holdtime=join_prune_period*coef
# default if not specified : 60 3.5
#join_prune_period 60 3.5;
#syntax : 'data_timeout <number>'.
# number is the time after which (S,G) state for a silent source will be deleted
# default if not specified : 210
#data_timeout 210;
#syntax : 'register_suppression_timeout <number>'.
# This is the mean interval between receiving a Register-Stop and allowing
#Register to be send again.
# default if not specified : 60
#register_suppression_timeout 60;
#syntax : 'probe_time <number>'.
#This is the time between sending a null Register and the Register-Suppression-Timer
#expiring unless it is restarted by receiving a Register-Stop.
#default if not specified : 5
#probe_time 5;
#syntax : 'assert_timeout <number>'.
#this is the interval between the last time an Assert is received and the time at wich the
#assert is timeout
#default if not specified : 180
#assert_timeout 180;
#syntax : <cand_rp> <interface> <time> [time] <priority> [priority]
#and time can't be < 10
#you can just type cand_rp,
#samples :
#cand_rp;
#cand_rp de0;
#cand_rp ed0 priority 0 time 6;
#syntax : <group_prefix> <multicast address>/<prefix length>
#group_prefix ff06::15
#default if not specified : ff00::/8
#samples:
#group_prefix ff1e::15/128;
#group_prefix ff2e::/16;
#syntax : <cand_bootstrap_router> <interface> <priority> [priority] <time> [time]
#Typically, you can simply set cand_bootstrap_router for a candidate bootstrap
#router. All other parameters are optional.
#the bootstrap period is configurable, BUT the holdtime of a bootstrap
#router is not in the fields of a bootstrap message : it is hardcoded
#in the pim6sd include file!
#So be sure to have a time < PIM_BOOSTRAP_TIMEOUT (file pimd.h )
#cand_bootstrap_router de0 priority 15 time 5;
#syntax : <switch_register_threshold> <rate> [number] <interval> [number]
#default rate = 50000 interval = 20s
#samples :
#TODO : not tested
#switch_register_threshold rate 54389 interval 45;
#switch_register_threshold;
#syntax : <switch_data_threshold> <rate> [number] <interval> [number]
#default rate = 50000 interval = 20s
#TODO : not tested
#samples:
#switch_data_threshold interval 100 rate 1000;
#syntax : <default_source_metric> [number]
#default_source_metric 1243;
#syntax : <default_source_preference> [number]
#default_source_preference 123 ;

89
usr.sbin/pim6sd/pim6stat Executable file
View File

@ -0,0 +1,89 @@
#!/bin/sh
# Copyright (c) 1999 WIDE Project. 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.
#
# $FreeBSD$
# get options
while getopts "df:p:sw:" option
do
case $option in
d)
densemode="YES";;
f)
dumpfile="${OPTARG}";;
p)
pidfile="${OPTARG}";;
s)
statmode="YES";;
w)
waittime="${OPTARG}";;
*) # (error msg printed by getopts)
echo usage: pim6stat [-d][-f dumpfile][-p pidfile][-w waitsec]
exit 2;;
esac
done
# set parameters
if [ X"${pidfile}" = X ]; then
if [ X"${densemode}" = X"YES" ]; then
pidfile=/var/run/pim6dd.pid
else
pidfile=/var/run/pim6sd.pid
fi
fi
if [ X"${waittime}" = X ]; then
waittime=1
fi
if [ X"${statmode}" = X"YES" ]; then
signame=-INFO
else
signame=-USR1
fi
if [ X"${dumpfile}" = X ]; then
if [ X"${statmode}" = X"YES" ]; then
if [ X"${densemode}" = X"YES" ]; then
dumpfile=/var/run/pim6dd.stat
else
dumpfile=/var/run/pim6sd.stat
fi
else
if [ X"${densemode}" = X"YES" ]; then
dumpfile=/var/run/pim6dd.dump
else
dumpfile=/var/run/pim6sd.dump
fi
fi
fi
# execution
kill ${signame} `cat ${pidfile}`
sleep ${waittime}
cat ${dumpfile}

View File

@ -0,0 +1,92 @@
.\" Copyright (C) 1999 WIDE Project.
.\" 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: pim6stat.1,v 1.3 1999/12/16 05:38:06 jinmei Exp $
.\" $FreeBSD$
.\"
.Dd July 28, 1999
.Dt PIM6STAT 1
.Os KAME
.Sh NAME
.Nm pim6stat
.Nd show PIM for IPv6 status
.Sh SYNOPSIS
.Nm
.Op Fl d
.Op Fl f dumpfile
.Op Fl p pidfile
.Op Fl s
.Op Fl w waitsec
.Sh DESCRIPTION
.Nm Pim6stat
shows status or statistics of the PIM for IPv6 daemon currently running.
When invoked, it sends a signal to let the daemon dump its internal
status to a file, waits for dumping, and outputs the content of the file
to standard output.
.Pp
Options supported by
.Nm pim6stat :
.Bl -tag -width Ds
.It Fl d
specifies to show the status of a dense mode daemon (if running).
By default,
.Nm
assumes sparse mode.
.It Fl f
specifies the dumpfile to which the PIM daemon dumps its status.
.It Fl p
specifies the PID file of the currently running daemon.
.It Fl s
specifies to dump statistics instead of status (for sparse mode only).
.It Fl w
specifies the wait period in seconds between sending a signal to the
daemon and outputs the dumpfile.
.El
.Sh FILES
.Bl -tag -width /var/run/pim6sd.pid -compact
.It Pa /var/run/pim6sd.pid
The default PID file for a sparse mode daemon.
.It Pa /var/run/pim6dd.pid
The default PID file for a dense mode daemon.
.It Pa /var/run/pim6sd.dump
The default dump file for a sparse mode daemon.
.It Pa /var/run/pim6dd.dump
The default dump file for a dense mode daemon.
.It Pa /var/run/pim6sd.stat
The default statistics dump file for a sparse mode daemon.
.El
.Sh SEE ALSO
.Xr pim6sd 8 ,
.Xr pim6dd 8
.Sh HISTORY
The
.Nm
command first appeared in KAME IPv6 protocol stack kit.
.Sh BUGS
.Nm Pim6stat
needs superuser privilege.
.\"

527
usr.sbin/pim6sd/pimd.h Normal file
View File

@ -0,0 +1,527 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef PIMD_H
#define PIMD_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "defs.h"
#define PIM_PROTOCOL_VERSION 2
/* PIM protocol timers (in seconds) */
#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
#define PIM_DEFAULT_BOOTSTRAP_PERIOD 60
#define PIM_BOOTSTRAP_TIMEOUT (2.5 * PIM_DEFAULT_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_DEFAULT_BSR_PRIORITY 0 /* 0 is the lowest */
#define RP_DEFAULT_IPV6_HASHMASKLEN 126 /* the default group msklen used
* by the hash function to
* calculate the group-to-RP
* mapping
*/
#define SINGLE_SRC_MSK6LEN 128 /* the single source mask length */
#define SINGLE_GRP_MSK6LEN 128 /* the single group mask length */
/* TODO: change? */
#define PIM_GROUP_PREFIX_DEFAULT_MASKLEN 8 /* The default group masklen if
* omitted in the config file.
*/
/* 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_IPv6 0
/* Encoded-Unicast: 18 bytes long */
typedef struct pim6_encod_uni_addr_ {
u_int8 addr_family;
u_int8 encod_type;
struct in6_addr unicast_addr; /* XXX: Note the 32-bit boundary
* misalignment for the unicast
* address when placed in the
* memory. Must read it byte-by-byte!
*/
} pim6_encod_uni_addr_t;
/* XXX: sizeof(pim6_encod_uni_addr_t) does not work due to misalignment */
#define PIM6_ENCODE_UNI_ADDR_LEN 18
/* Encoded-Group */
typedef struct pim6_encod_grp_addr_ {
u_int8 addr_family;
u_int8 encod_type;
u_int8 reserved;
u_int8 masklen;
struct in6_addr mcast_addr;
} pim6_encod_grp_addr_t;
/* XXX: sizeof(pim6_encod_grp_addr_t) MAY NOT work due to an alignment problem */
#define PIM6_ENCODE_GRP_ADDR_LEN 20
/* Encoded-Source */
typedef struct pim6_encod_src_addr_ {
u_int8 addr_family;
u_int8 encod_type;
u_int8 flags;
u_int8 masklen;
struct in6_addr src_addr;
} pim6_encod_src_addr_t;
/* XXX: sizeof(pim6_encod_src_addr_t) MAY NOT work due to an alignment problem */
#define PIM6_ENCODE_SRC_ADDR_LEN 20
#define USADDR_RP_BIT 0x1
#define USADDR_WC_BIT 0x2
#define USADDR_S_BIT 0x4
/**************************************************************************
* PIM Messages formats *
*************************************************************************/
/* 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_ {
pim6_encod_grp_addr_t encod_grp;
pim6_encod_uni_addr_t encod_src; /* XXX: 18 bytes long, misaligned */
} pim_register_stop_t;
/* PIM Join/Prune: XXX: all 128-bit addresses misaligned! */
typedef struct pim_jp_header_ {
pim6_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_ {
pim6_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 */
#define PIM_HELLO 0
#define PIM_REGISTER_STOP 2
#define PIM_JOIN_PRUNE 3
#define PIM_BOOTSTRAP 4
#define PIM_ASSERT 5
#define PIM_GRAFT 6
#define PIM_GRAFT_ACK 7
#define PIM_CAND_RP_ADV 8
#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
/* 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_MASKLEN6(mask , masklen) \
do { \
register u_int32 tmp_mask; \
register u_int8 tmp_masklen = sizeof((mask)) <<3; \
int i; \
int kl; \
for(i=0;i<4;i++) \
{ \
tmp_mask=ntohl(*(u_int32_t *)&mask.s6_addr[i * 4]); \
for(kl=32; tmp_masklen >0 && kl>0 ; tmp_masklen--, kl-- , tmp_mask >>=1) \
if( tmp_mask & 0x1) \
break; \
} \
(masklen) =tmp_masklen; \
} while (0)
#define MASKLEN_TO_MASK6(masklen, mask6) \
do {\
u_char maskarray[8] = \
{0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; \
int bytelen, bitlen, i; \
memset(&(mask6), 0, sizeof(mask6));\
bytelen = (masklen) / 8;\
bitlen = (masklen) % 8;\
for (i = 0; i < bytelen; i++) \
(mask6).s6_addr[i] = 0xff;\
if (bitlen) \
(mask6).s6_addr[bytelen] = maskarray[bitlen - 1]; \
}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.
*/
/* 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_ESADDR6(esa, cp) /* XXX: hard coding */ \
do { \
(esa)->addr_family = *(cp)++; \
(esa)->encod_type = *(cp)++; \
(esa)->flags = *(cp)++; \
(esa)->masklen = *(cp)++; \
memcpy(&(esa)->src_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
#define PUT_ESADDR6(addr, masklen, flags, cp) \
do { \
int i; \
struct in6_addr maskaddr; \
MASKLEN_TO_MASK6(masklen, maskaddr); \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
*(cp)++ = (flags); /* flags */ \
*(cp)++ = (masklen); \
for (i = 0; i < sizeof(struct in6_addr); i++, (cp)++) \
*(cp) = maskaddr.s6_addr[i] & (addr).s6_addr[i]; \
} while(0)
#define GET_EGADDR6(ega, cp) /* XXX: hard coding */ \
do { \
(ega)->addr_family = *(cp)++; \
(ega)->encod_type = *(cp)++; \
(ega)->reserved = *(cp)++; \
(ega)->masklen = *(cp)++; \
memcpy(&(ega)->mcast_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
#define PUT_EGADDR6(addr, masklen, reserved, cp) \
do { \
int i; \
struct in6_addr maskaddr; \
MASKLEN_TO_MASK6(masklen, maskaddr); \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
*(cp)++ = (reserved); /* reserved; should be 0 */ \
*(cp)++ = (masklen); \
for (i = 0; i < sizeof(struct in6_addr); i++, (cp)++) \
*(cp) = maskaddr.s6_addr[i] & (addr).s6_addr[i]; \
} while(0)
#define GET_EUADDR6(eua, cp) /* XXX hard conding */ \
do { \
(eua)->addr_family = *(cp)++; \
(eua)->encod_type = *(cp)++; \
memcpy(&(eua)->unicast_addr, (cp), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
#define PUT_EUADDR6(addr, cp) \
do { \
*(cp)++ = ADDRF_IPv6; /* family */ \
*(cp)++ = ADDRT_IPv6; /* type */ \
memcpy((cp), &(addr), sizeof(struct in6_addr)); \
(cp) += sizeof(struct in6_addr); \
} while(0)
/* Used if no relaible unicast routing information available */
#define UCAST_DEFAULT_SOURCE_METRIC 1024
#define UCAST_DEFAULT_SOURCE_PREFERENCE 1024
#define DEFAULT_LOCAL_PREF 101 /* assert pref par defaut */
#define DEFAULT_LOCAL_METRIC 1024 /* assert metrique par default */
/*
* 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
#define STAR_STAR_RP_MSK6LEN 8 /* Masklen for
* ff00 ::
* to encode (*,*,RP)
*/
/* interface independent statistics */
struct pim6dstat {
/* incoming PIM6 packets on this interface */
u_quad_t in_pim6_register;
u_quad_t in_pim6_register_stop;
u_quad_t in_pim6_cand_rp;
u_quad_t in_pim6_graft; /* for dense mode only */
u_quad_t in_pim6_graft_ack; /* for dense mode only */
/* outgoing PIM6 packets on this interface */
u_quad_t out_pim6_register;
u_quad_t out_pim6_register_stop;
u_quad_t out_pim6_cand_rp;
/* SPT transition */
u_quad_t pim6_trans_spt_forward;
u_quad_t pim6_trans_spt_rp;
/* occurrences of timeouts */
u_quad_t pim6_bootstrap_timo;/* pim_bootstrap_timer */
u_quad_t pim6_rpgrp_timo; /* rp_grp_entry_ptr->holdtime */
u_quad_t pim6_rtentry_timo; /* routing entry */
/* kernel internals */
u_quad_t kern_add_cache;
u_quad_t kern_add_cache_fail;
u_quad_t kern_del_cache;
u_quad_t kern_del_cache_fail;
u_quad_t kern_sgcnt_fail;
};
extern struct pim6dstat pim6dstat;
#endif

1180
usr.sbin/pim6sd/route.c Normal file

File diff suppressed because it is too large Load Diff

85
usr.sbin/pim6sd/route.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef ROUTE_H
#define ROUTE_H
#include "mrt.h"
extern u_int32 default_source_preference;
extern u_int32 default_source_metric;
int change_interfaces( mrtentry_t *mrtentry_ptr,vifi_t new_iif,
if_set *new_joined_oifs,if_set *new_pruned_oifs,if_set *new_leaves_ , if_set *asserted ,
u_int16 flags);
extern void process_kernel_call __P(());
extern int set_incoming __P((srcentry_t *srcentry_ptr,
int srctype));
extern vifi_t get_iif __P((struct sockaddr_in6 *source));
extern int add_sg_oif __P((mrtentry_t *mrtentry_ptr,
vifi_t vifi,
u_int16 holdtime,
int update_holdtime));
extern void add_leaf __P((vifi_t vifi, struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern void delete_leaf __P((vifi_t vifi, struct sockaddr_in6 *source,
struct sockaddr_in6 *group));
extern pim_nbr_entry_t *find_pim6_nbr __P((struct sockaddr_in6 *source));
extern void calc_oifs __P((mrtentry_t *mrtentry_ptr,
if_set *oifs_ptr));
extern void process_kernel_call __P(());
extern int delete_vif_from_mrt __P((vifi_t vifi));
extern mrtentry_t *switch_shortest_path __P((struct sockaddr_in6 *source, struct sockaddr_in6 *group));
#endif

428
usr.sbin/pim6sd/routesock.c Normal file
View File

@ -0,0 +1,428 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <sys/param.h>
#include <sys/file.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "defs.h"
#include <sys/socket.h>
#include <net/route.h>
#ifdef HAVE_ROUTING_SOCKETS
#include <net/if_dl.h>
#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "vif.h"
#include "debug.h"
#ifdef HAVE_ROUTING_SOCKETS
union sockunion
{
struct sockaddr sa;
struct sockaddr_in6 sin6;
struct sockaddr_dl sdl;
} so_dst, so_ifp;
typedef union sockunion *sup;
int routing_socket;
int rtm_addrs,
pid;
struct rt_metrics rt_metrics;
u_long rtm_inits;
/*
* Local functions definitions.
*/
static int getmsg
__P((register 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(4)) /* TODO: a hack!! */
#endif
/* Open and initialize the routing socket */
int
init_routesock()
{
pid = getpid();
routing_socket = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
if (routing_socket < 0)
{
log(LOG_ERR, 0, "\nRouting socket error");
return -1;
}
if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1)
{
log(LOG_ERR, 0, "\n Routing socket error");
return -1;
}
// TODO : UTILITY ?
#if 0
{
int off;
off = 0;
if (setsockopt(routing_socket, SOL_SOCKET,
SO_USELOOPBACK, (char *) &off,
sizeof(off)) < 0)
{
log(LOG_ERR, 0, "\n setsockopt(SO_USELOOPBACK,0)");
return -1;
}
}
#endif
return 0;
}
struct
{
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
/* get the rpf neighbor info */
int
k_req_incoming(source, rpfp)
struct sockaddr_in6 *source;
struct rpfctl *rpfp;
{
int flags = RTF_STATIC;
register sup su;
static int seq;
int rlen;
register char *cp = m_rtmsg.m_space;
register int l;
struct rpfctl rpfinfo;
/* TODO: a hack!!!! */
#ifdef HAVE_SA_LEN
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) { \
l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
}
#else
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) { \
l = ROUNDUP(4); bcopy((char *)&(u), cp, l); cp += l;\
}
#endif /* HAVE_SA_LEN */
/* initialize */
memset(&rpfp->rpfneighbor, 0, sizeof(rpfp->rpfneighbor));
rpfp->source = *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 = *source;
return (TRUE);
}
/* prepare the routing socket params */
rtm_addrs |= RTA_DST;
rtm_addrs |= RTA_IFP;
su = &so_dst;
su->sin6.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
su->sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
su->sin6.sin6_addr = source->sin6_addr;
su->sin6.sin6_scope_id = source->sin6_scope_id;
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;
bzero((char *) &m_rtmsg, 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)
log(LOG_DEBUG, 0,
"Writing to routing socket: no such route\n");
else
log(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)
log(LOG_DEBUG, 0, "Read from routing socket failed: %s", strerror(errno));
return (FALSE);
}
if (getmsg(&rtm, l, &rpfinfo))
{
rpfp->rpfneighbor = rpfinfo.rpfneighbor;
rpfp->iif = rpfinfo.iif;
}
#undef rtm
return (TRUE);
}
/*
* Returns TRUE on success, FALSE otherwise. rpfinfo contains the result.
*/
int
getmsg(rtm, msglen, rpfinfop)
register struct rt_msghdr *rtm;
int msglen;
struct rpfctl *rpfinfop;
{
struct sockaddr *dst = NULL,
*gate = NULL,
*mask = NULL;
struct sockaddr_dl *ifp = NULL;
register struct sockaddr *sa;
register char *cp;
register int i;
struct sockaddr_in6 *sin6;
vifi_t vifi;
struct uvif *v;
char in6txt[INET6_ADDRSTRLEN];
if (rpfinfop == (struct rpfctl *) NULL)
return (FALSE);
sin6 = (struct sockaddr_in6 *) & so_dst;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, "route to: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
cp = ((char *) (rtm + 1));
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;
#if 0
default:
/*
* There are some defined flags other than above 4,
* but we are not interested in them.
*/
log(LOG_WARNING, 0,
"Routesock.c (getmsg) unknown flag : %d",i);
#endif
}
ADVANCE(cp, sa);
}
if (!ifp)
{ /* No incoming interface */
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0,
"No incoming interface for destination %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
return (FALSE);
}
if (dst && mask)
mask->sa_family = dst->sa_family;
if (dst)
{
sin6 = (struct sockaddr_in6 *) dst;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, " destination is: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
}
if (gate && rtm->rtm_flags & RTF_GATEWAY)
{
sin6 = (struct sockaddr_in6 *) gate;
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0, " gateway is: %s",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
rpfinfop->rpfneighbor = *sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
{
#if 0
rpfinfop->rpfneighbor.sin6_scope_id =
ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
#endif
rpfinfop->rpfneighbor.sin6_scope_id = ifp->sdl_index;
/*
* XXX: KAME kernel embeds the interface index to the address.
* Clear the index for safety.
*/
rpfinfop->rpfneighbor.sin6_addr.s6_addr[2] = 0;
rpfinfop->rpfneighbor.sin6_addr.s6_addr[3] = 0;
}
}
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)
log(LOG_DEBUG, 0, " iif is %d", vifi);
rpfinfop->iif = vifi;
if (vifi >= numvifs)
{
IF_DEBUG(DEBUG_RPF)
log(LOG_DEBUG, 0,
"Invalid incoming interface for destination %s, because of invalid virtual interface",
inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
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(source, rpfcinfo)
struct sockaddr_in6 *source;
struct rpfctl *rpfcinfo;
{
rpfcinfo->source = *source;
rpfcinfo->iif = NO_VIF; /* just initialized, will be */
/* changed in kernel */
memset(&rpfcinfo->rpfneighbor, 0, sizeof(rpfcinfo->rpfneighbor)); /* initialized */
if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0)
{
log(LOG_ERR, errno, "ioctl SIOCGETRPF k_req_incoming");
return (FALSE);
}
return (TRUE);
}
#endif /* HAVE_ROUTING_SOCKETS */

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef ROUTESOCK_H
#define ROUTESOCK_H
void init_routesock();
extern int pid;
extern int k_req_incoming __P((struct sockaddr_in6 *source,
struct rpfctl *rpfp));
#endif

1210
usr.sbin/pim6sd/rp.c Normal file

File diff suppressed because it is too large Load Diff

123
usr.sbin/pim6sd/rp.h Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef RP_H
#define RP_H
#include "defs.h"
#include "mrt.h"
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_int8 cand_rp_flag;
extern u_int8 cand_bsr_flag;
extern u_int8 my_cand_rp_priority;
extern u_int8 my_bsr_priority;
extern u_int16 my_cand_rp_adv_period;
extern u_int16 my_bsr_period;
extern u_int16 my_cand_rp_holdtime;
extern struct sockaddr_in6 my_cand_rp_address;
extern struct sockaddr_in6 my_bsr_address;
extern struct in6_addr my_bsr_hash_mask;
extern struct in6_addr curr_bsr_hash_mask;
extern struct sockaddr_in6 curr_bsr_address;
extern u_int16 curr_bsr_fragment_tag;
extern u_int8 curr_bsr_priority;
extern u_int16 pim_bootstrap_timer;
extern u_int16 pim_cand_rp_adv_timer;
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 void init_rp6_and_bsr6 __P(());
void delete_rp_list( cand_rp_t **used_cand_rp_list , grp_mask_t **used_grp_mask_list );
u_int16 bootstrap_initial_delay();
extern rpentry_t *rp_match __P((struct sockaddr_in6 *group));
extern rp_grp_entry_t *rp_grp_match __P((struct sockaddr_in6 *group));
extern int create_pim6_bootstrap_message __P((char *send_buff));
extern rp_grp_entry_t *add_rp_grp_entry __P((cand_rp_t **used_cand_rp_list,
grp_mask_t **used_grp_mask_list,
struct sockaddr_in6 *rp_addr,
u_int8 rp_priority,
u_int16 rp_holdtime,
struct sockaddr_in6 *group_addr,
struct in6_addr group_mask,
struct in6_addr bsr_hash_mask,
u_int16 fragment_tag));
extern void delete_rp_grp_entry __P((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 __P((cand_rp_t **used_cand_rp_list,
grp_mask_t **used_grp_mask_list,
struct sockaddr_in6 *group_addr,
struct in6_addr group_mask));
extern void delete_rp __P((cand_rp_t **used_cand_rp_list,
grp_mask_t **used_grp_mask_list,
struct sockaddr_in6 *rp_addr));
extern void delete_rp_list __P((cand_rp_t **used_cand_rp_list,
grp_mask_t **used_grp_mask_list));
extern rpentry_t *rp_match __P((struct sockaddr_in6 *group));
extern rp_grp_entry_t *rp_grp_match __P((struct sockaddr_in6 *group));
extern rpentry_t *rp_find __P((struct sockaddr_in6 *rp_address));
extern int remap_grpentry __P((grpentry_t *grpentry_ptr));
extern int check_mrtentry_rp __P((mrtentry_t *mrtentry_ptr,
struct sockaddr_in6 *rp_addr));
#endif

1286
usr.sbin/pim6sd/timer.c Normal file

File diff suppressed because it is too large Load Diff

102
usr.sbin/pim6sd/timer.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 1999 LSIIT Laboratory.
* 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.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
#ifndef TIMER_H
#define TIMER_H
/* the default granularity if not specified in the config file */
#define DEFAULT_TIMER_INTERVAL 5
/* 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_TIMER_NOT_SET(timer) if ((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)))
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 u_int32 pim_hello_period;
extern u_int32 pim_hello_holdtime;
extern u_int32 timer_interval;
extern u_int32 pim_join_prune_period;
extern u_int32 pim_join_prune_holdtime;
extern u_int32 pim_data_timeout;
extern u_int32 pim_register_suppression_timeout;
extern u_int32 pim_register_probe_time;
extern u_int32 pim_assert_timeout;
extern void init_timers __P(());
extern void init_timers __P(());
extern void age_vifs __P(());
extern void age_routes __P(());
extern void age_misc __P(());
#endif

559
usr.sbin/pim6sd/trace.c Normal file
View File

@ -0,0 +1,559 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* non-commercial purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: trace.c,v 1.7 1999/09/16 08:45:45 jinmei 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 <sys/types.h>
#include <sys/socket.h>
#include "vif.h"
#include "inet6.h"
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <errno.h>
#include <net/if.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <net/if_var.h>
#endif
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_mroute.h>
#include <netinet6/in6_var.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include "defs.h"
#include "mld6.h"
#include "kern.h"
#include "debug.h"
#include "mld6_proto.h"
#include "route.h"
#include "rp.h"
#include "trace.h"
/* TODO */
/*
* Traceroute function which returns traceroute replies to the requesting
* router. Also forwards the request to downstream routers.
*/
void
accept_mtrace(src, dst, group, ifindex, data, no, datalen)
struct sockaddr_in6 *src;
struct in6_addr *dst;
struct in6_addr *group;
int ifindex;
char *data;
u_int no; /* promoted u_char */
int datalen;
{
u_char type;
mrtentry_t *mrt;
struct tr6_query *qry;
struct tr6_resp *resp;
int vifi, ovifi;
char *p;
int rcount;
int errcode = TR_NO_ERR;
int resptype;
struct timeval tp;
struct sioc_mif_req6 mreq;
struct in6_addr parent_address;
struct sockaddr_in6 src_sa6 = {sizeof(src_sa6), AF_INET6};
struct sockaddr_in6 dst_sa6 = {sizeof(dst_sa6), AF_INET6};
struct sockaddr_in6 resp_sa6 = {sizeof(resp_sa6), AF_INET6};
struct sockaddr_in6 grp_sa6 = {sizeof(grp_sa6), AF_INET6};
struct sockaddr_in6 *sa_global;
rpentry_t *rpentry_ptr;
/* 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)
log(LOG_DEBUG, 0, "Initial traceroute query rcvd "
"from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
}
else if ((datalen - QLEN) % RLEN == 0) {
type = RESP;
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "In-transit traceroute query rcvd "
"from %s to %s",
inet6_fmt(&src->sin6_addr),
inet6_fmt(dst));
if (IN6_IS_ADDR_MULTICAST(dst)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Dropping multicast response");
return;
}
}
else {
log(LOG_WARNING, 0, "%s from %s to %s",
"Non decipherable traceroute request recieved",
inet6_fmt(&src->sin6_addr), inet6_fmt(dst));
return;
}
qry = (struct tr6_query *)data;
src_sa6.sin6_addr = qry->tr_src;
src_sa6.sin6_scope_id =
(IN6_IS_ADDR_LINKLOCAL(&qry->tr_src)
|| IN6_IS_ADDR_MC_LINKLOCAL(&qry->tr_src)) ? ifindex : 0;
dst_sa6.sin6_addr = qry->tr_dst;
dst_sa6.sin6_scope_id =
(IN6_IS_ADDR_LINKLOCAL(&qry->tr_dst)
|| IN6_IS_ADDR_MC_LINKLOCAL(&qry->tr_dst)) ? ifindex : 0;
grp_sa6.sin6_addr = *group;
grp_sa6.sin6_scope_id = 0;
/*
* if it is a packet with all reports filled, drop it
*/
if ((rcount = (datalen - QLEN)/RLEN) == no) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "packet with all reports filled in");
return;
}
IF_DEBUG(DEBUG_TRACE) {
log(LOG_DEBUG, 0, "s: %s g: %s d: %s ",
inet6_fmt(&qry->tr_src),
inet6_fmt(group), inet6_fmt(&qry->tr_dst));
log(LOG_DEBUG, 0, "rhlim: %d rd: %s", qry->tr_rhlim,
inet6_fmt(&qry->tr_raddr));
log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
}
/* determine the routing table entry for this traceroute */
mrt = find_route(&src_sa6, &grp_sa6, 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.sin6_addr;
else
parent_address = in6addr_any;
log(LOG_DEBUG, 0,
"mrt parent mif: %d rtr: %s metric: %d",
mrt->incoming,
inet6_fmt(&parent_address), mrt->metric);
/* TODO
log(LOG_DEBUG, 0, "mrt origin %s",
RT_FMT(rt, s1));
*/
} else
log(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)
log(LOG_DEBUG, 0,
"ignoring duplicate traceroute packet");
return;
}
if (mrt == (mrtentry_t *)NULL) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Mcast traceroute: no route entry %s",
inet6_fmt(&qry->tr_src));
#if 0
if (IN6_IS_ADDR_MULTICAST(dst))
return;
#endif
}
vifi = find_vif_direct(&dst_sa6);
if (vifi == NO_VIF) {
/*
* The traceroute destination is not on one of
* my subnet vifs.
*/
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not an interface",
inet6_fmt(&qry->tr_dst));
if (IN6_IS_ADDR_MULTICAST(dst))
return;
errcode = TR_WRONG_IF;
} else if (mrt != (mrtentry_t *)NULL &&
!IF_ISSET(vifi, &mrt->oifs)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not on forwarding tree "
"for src %s",
inet6_fmt(&qry->tr_dst),
inet6_fmt(&qry->tr_src));
if (IN6_IS_ADDR_MULTICAST(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)
log(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)
log(LOG_DEBUG, 0, "Sending traceroute response");
/* copy the packet to the sending buffer */
p = mld6_send_buf + sizeof(struct mld6_hdr);
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 tr6_resp) > mld6_send_buf + RECV_BUF_SIZE) {
resp = (struct tr6_resp *)p - 1;
resp->tr_rflags = TR_NO_SPACE;
mrt = NULL;
goto sendit;
}
/*
* fill in initial response fields
*/
resp = (struct tr6_resp *)p;
bzero(resp, sizeof(struct tr6_resp));
datalen += (RLEN + sizeof(struct mld6_hdr));
resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec << 10) / 15625));
resp->tr_rproto = PROTO_PIM;
resp->tr_outifid = (vifi == NO_VIF) ? TR_NO_VIF : htonl(vifi);
resp->tr_rflags = errcode;
if ((sa_global = max_global_address()) == NULL) /* impossible */
log(LOG_ERR, 0, "acept_mtrace: max_global_address returns NULL");
resp->tr_lcladdr = sa_global->sin6_addr;
/*
* obtain # of packets out on interface
*/
mreq.mifi = vifi;
if (vifi != NO_VIF &&
ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *)&mreq) >= 0)
resp->tr_vifout = htonl(mreq.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->sin6_addr = *dst; /* the dst address of resp. pkt */
resp->tr_inifid = TR_NO_VIF;
resp->tr_rflags = TR_NO_RTE;
memset(&resp->tr_rmtaddr, 0, sizeof(struct in6_addr));
} else {
/* get # of packets in on interface */
mreq.mifi = mrt->incoming;
if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *)&mreq) >= 0)
resp->tr_vifin = htonl(mreq.icount);
else
resp->tr_vifin = 0xffffffff;
/*
* TODO
* MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
*/
resp->tr_inifid = htonl(mrt->incoming);
if (mrt->upstream != (pim_nbr_entry_t *)NULL)
parent_address = mrt->upstream->address.sin6_addr;
else
parent_address = in6addr_any;
resp->tr_rmtaddr = parent_address;
if (!IF_ISSET(vifi, &mrt->oifs)) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Destination %s not on forwarding tree "
"for src %s",
inet6_fmt(&qry->tr_dst),
inet6_fmt(&qry->tr_src));
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 */
}
/*
* If we're the RP for the trace group, note it.
*/
rpentry_ptr = rp_match(&grp_sa6);
if (rpentry_ptr && local_address(&rpentry_ptr->address) != NO_VIF)
resp->tr_rflags = TR_RP;
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)
log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
ovifi = NO_VIF; /* unspecified */
if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) {
resptype = MLD6_MTRACE_RESP;
resp_sa6.sin6_addr = qry->tr_raddr;
if (IN6_IS_ADDR_LINKLOCAL(&resp_sa6.sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&resp_sa6.sin6_addr)) {
if ((ovifi = find_vif_direct(&dst_sa6)) == NO_VIF) {
log(LOG_INFO, 0,
"can't determine outgoing i/f for mtrace "
"response.");
return;
}
}
} else
/* TODO */
{
#if 0
if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
resp_sa6.sin6_addr = qry->tr_raddr;
resp->tr_rflags = TR_OLD_ROUTER;
resptype = MLD6_MTRACE_RESP;
} else
#endif /* 0 */
if (mrt->incoming &&
(uvifs[mrt->incoming].uv_flags & MIFF_REGISTER)) {
log(LOG_DEBUG, 0,
"incoming i/f is for register. "
"Can't be forwarded anymore.");
resp_sa6.sin6_addr = qry->tr_raddr;
resptype = MLD6_MTRACE_RESP;
} else {
if (mrt->upstream != (pim_nbr_entry_t *)NULL)
parent_address =
mrt->upstream->address.sin6_addr;
else
parent_address = allrouters_group.sin6_addr;
resp_sa6.sin6_addr = parent_address;
ovifi = mrt->incoming;
resptype = MLD6_MTRACE;
}
}
if (IN6_IS_ADDR_MULTICAST(&resp_sa6.sin6_addr)) {
struct sockaddr_in6 *sa6;
/*
* Send the reply on a known multicast capable vif.
* If we don't have one, we can't source any
* multicasts anyway.
*/
if (IN6_IS_ADDR_MC_LINKLOCAL(&resp_sa6.sin6_addr)) {
sa6 = &uvifs[ovifi].uv_linklocal->pa_addr;
ifindex = uvifs[ovifi].uv_ifindex;
}
else {
if (phys_vif != -1 &&
(sa6 = uv_global(phys_vif)) != NULL) {
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0,
"Sending reply to %s from %s",
inet6_fmt(dst),
inet6_fmt(&sa6->sin6_addr));
ifindex = uvifs[phys_vif].uv_ifindex;
}
else {
log(LOG_INFO, 0, "No enabled phyints -- %s",
"dropping traceroute reply");
return;
}
}
k_set_hlim(mld6_socket, qry->tr_rhlim);
send_mld6(resptype, no, sa6, &resp_sa6, group,
ifindex, 0, datalen, 0);
k_set_hlim(mld6_socket, 1);
} else {
struct sockaddr_in6 *sa6 = NULL;
ifindex = -1; /* unspecified by default */
if (IN6_IS_ADDR_LINKLOCAL(&resp_sa6.sin6_addr)) {
/* ovifi must be valid in this case */
ifindex = uvifs[ovifi].uv_ifindex;
sa6 = &uvifs[ovifi].uv_linklocal->pa_addr;
}
IF_DEBUG(DEBUG_TRACE)
log(LOG_DEBUG, 0, "Sending %s to %s from %s",
resptype == MLD6_MTRACE_RESP ?
"reply" : "request on",
inet6_fmt(dst),
sa6 ? inet6_fmt(&sa6->sin6_addr) : "unspecified");
send_mld6(resptype, no, sa6, &resp_sa6, group, ifindex,
0, datalen, 0);
}
return;
}

211
usr.sbin/pim6sd/trace.h Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (C) 1999 WIDE Project.
* 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.
*/
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
*
* $Id: trace.h,v 1.2 1999/09/09 15:47:11 jinmei 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.
*
*/
#ifndef TRACE_H
#define TRACE_H
/*
* The packet format for a traceroute request.
*/
struct tr6_query {
struct in6_addr tr_src; /* traceroute source */
struct in6_addr tr_dst; /* traceroute destination */
struct in6_addr tr_raddr; /* traceroute response address */
#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
struct {
u_int32_t qid : 24; /* traceroute query id */
u_int32_t rhlim : 8; /* traceroute response ttl */
} q;
#else
struct {
u_int32_t rhlim : 8; /* traceroute response ttl */
u_int32_t qid : 24; /* traceroute query id */
} q;
#endif /* BYTE_ORDER */
};
#define tr_rhlim q.rhlim
#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 tr6_resp {
u_int32_t tr_qarr; /* query arrival time */
#if 0
struct in6_addr tr_inaddr; /* incoming interface address */
struct in6_addr tr_outaddr; /* outgoing interface address */
#endif
u_int32_t tr_inifid; /* incoming interface identifier */
u_int32_t tr_outifid; /* outgoing interface identifier */
struct in6_addr tr_lcladdr; /* router's address(must have largest scope) */
struct in6_addr tr_rmtaddr; /* parent address in source tree */
u_int32_t tr_vifin; /* input packet count on interface */
u_int32_t tr_vifout; /* output packet count on interface */
u_int32_t tr_pktcnt; /* total incoming packets for src-grp */
u_char tr_rproto; /* routing protocol deployed on router */
#if 0
u_char tr_fhlim; /* hop limit required to forward on outvif */
#endif
u_char tr_flags; /* flags */
u_char tr_plen; /* prefix length for src addr */
u_char tr_rflags; /* forwarding error codes */
};
/* defs within mtrace */
#define QUERY 1
#define RESP 2
#define QLEN sizeof(struct tr6_query)
#define RLEN sizeof(struct tr6_resp)
/* fields for tr_inifid and tr_outifid */
#define TR_NO_VIF 0xffffffff/* interface can't be determined */
/* 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_flags */
#define TR_SUBNET_COUNT 0x80 /* pkt count for (S,G) is for source network */
/* fields for r_plen */
#define TR_GROUP_ONLY 0xff /* forwarding solely on group state */
/* 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 MASK_TO_VAL(x, i) { \
u_int32_t _x = ntohl(x); \
(i) = 1; \
while ((_x) <<= 1) \
(i)++; \
};
#define VAL_TO_MASK(x, i) { \
x = htonl(~((1 << (32 - (i))) - 1)); \
};
#define MASKLEN_TO_MASK6(masklen, mask6) \
do {\
u_char maskarray[8] = \
{0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; \
int bytelen, bitlen, i; \
memset(&(mask6), 0, sizeof(mask6));\
bytelen = (masklen) / 8;\
bitlen = (masklen) % 8;\
for (i = 0; i < bytelen; i++) \
(mask6).s6_addr[i] = 0xff;\
if (bitlen) \
(mask6).s6_addr[bytelen] = maskarray[bitlen - 1]; \
}while(0);
/* obnoxious gcc gives an extraneous warning about this constant... */
#if defined(__STDC__) || defined(__GNUC__)
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
#else
#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
#define const /**/
#endif
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)
void accept_mtrace __P((struct sockaddr_in6 *, struct in6_addr *,
struct in6_addr *, int, char *, u_int, int));
#endif /* TRACE_H */

62
usr.sbin/pim6sd/var.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/* YIPS @(#)$Id: var.h,v 1.1 1999/10/29 09:04:54 jinmei Exp $ */
#if !defined(_VAR_H_)
#define _VAR_H_
#include <sys/socket.h>
#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
#define CALLOC(size, cast) (cast)calloc(1, (size))
#define ISSET(exp, bit) (((exp) & (bit)) == (bit))
#define ATOX(c) \
(isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
#define LALIGN(a) \
((a) > 0 ? ((a) &~ (sizeof(long) - 1)) : sizeof(long))
#define RNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define BUFADDRSIZE 128
#define INET_NTOP(addr, buf) \
inet_ntop(((struct sockaddr *)(addr))->sa_family, _INADDRBYSA(addr), buf, sizeof(buf))
#define GETNAMEINFO(x, y, z) \
getnameinfo((x), (x)->sa_len, (y), sizeof(y), (z), sizeof(z), \
NI_NUMERICHOST | NI_NUMERICSERV)
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#endif /*!defined(_VAR_H_)*/

2
usr.sbin/pim6sd/vers.c Normal file
View File

@ -0,0 +1,2 @@
/* $FreeBSD$ */
char todaysversion[]="2.1.0-alpha23";

824
usr.sbin/pim6sd/vif.c Normal file
View File

@ -0,0 +1,824 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#include <sys/ioctl.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include "vif.h"
#include "mld6.h"
#include "pim6.h"
#include "pimd.h"
#include "route.h"
#include "config.h"
#include "inet6.h"
#include "kern.h"
#include "mld6_proto.h"
#include "pim6_proto.h"
#include "mrt.h"
#include "debug.h"
#include "timer.h"
struct uvif uvifs[MAXMIFS]; /*the list of virtualsinterfaces */
vifi_t numvifs; /*total number of interface */
int vifs_down;
vifi_t reg_vif_num; /*register interface*/
int phys_vif; /* An enabled vif that has a global address */
int udp_socket;
int total_interfaces;
if_set if_nullset;
if_set if_result;
int init_reg_vif();
void start_all_vifs();
void start_vif( vifi_t vifi );
void stop_vif( vifi_t vivi );
int update_reg_vif( vifi_t register_vifi);
extern int cfparse(int, int);
void init_vifs()
{
vifi_t vifi;
struct uvif *v;
int enabled_vifs;
numvifs = 0;
reg_vif_num = NO_VIF;
/*
* Configure the vifs based on the interface configuration of
* 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 MLD socket.)
*/
#ifdef IOCTL_OK_ON_RAW_SOCKET
udp_socket = mld6_socket;
#else
if ((udp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
log(LOG_ERR, errno, "UDP6 socket");
#endif
/* clean all the interfaces ... */
for(vifi = 0,v=uvifs; vifi < MAXVIFS; ++ vifi, ++v)
{
memset(v,0,sizeof(*v)); /* everything is zeroed => NULL , pointer NULL , addrANY ...) */
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
strncpy(v->uv_name,"",IFNAMSIZ);
v->uv_local_pref = default_source_preference;
v->uv_local_metric = default_source_metric;
}
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,"Interfaces world initialized...");
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,"Getting vifs from kernel");
config_vifs_from_kernel();
if (max_global_address() == NULL)
log(LOG_ERR, 0, "There's no global address");
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,"Getting vifs from %s",configfilename);
/* read config from file */
if (cfparse(1, 0) != 0)
log(LOG_ERR, 0, "fatal error in parsing the config file");
enabled_vifs = 0;
phys_vif = -1;
for( vifi = 0, v = uvifs ; vifi < numvifs ; ++ vifi,++v)
{
if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
continue;
if(v->uv_linklocal == NULL)
log(LOG_ERR,0,"there is no link-local address on vif %s",v->uv_name);
if (phys_vif == -1) {
struct phaddr *p;
/*
* If this vif has a global address, set its id
* to phys_vif.
*/
for(p = v->uv_addrs; p; p = p->pa_next) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
phys_vif = vifi;
break;
}
}
}
enabled_vifs++;
}
if (enabled_vifs < 2)
log(LOG_ERR,0,"can't forward: %s",
enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif" );
memset(&if_nullset,0,sizeof(if_nullset));
k_init_pim(mld6_socket);
IF_DEBUG(DEBUG_PIM_DETAIL)
log(LOG_DEBUG,0,"Pim kernel initialization done");
/* Add a dummy virtual interface to support Registers in the kernel. */
init_reg_vif();
start_all_vifs();
}
int init_reg_vif()
{
struct uvif *v;
vifi_t i;
v = &uvifs[numvifs];
if (( numvifs+1 ) == MAXVIFS )
{
/* Exit the program! The PIM router must have a Register vif */
log(LOG_ERR, 0,
"cannot install the Register vif: too many interfaces");
/* To make lint happy */
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;
/* 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 | MIFF_REGISTER))
continue;
else
break;
}
if( i >= numvifs)
{
log(LOG_ERR, 0, "No physical interface enabled");
return -1;
}
memcpy(v,&uvifs[i],sizeof(*v));
strncpy(v->uv_name,"register_mif0",IFNAMSIZ);
v->uv_flags = MIFF_REGISTER;
#ifdef PIM_EXPERIMENTAL
v->uv_flags |= MIFF_REGISTER_KERNEL_ENCAP;
#endif
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,"Interface %s (subnet %s) ,installed on vif #%u - rate = %d",
v->uv_name,net6name(&v->uv_prefix.sin6_addr,&v->uv_subnetmask),
reg_vif_num,v->uv_rate_limit);
numvifs++;
total_interfaces++;
return 0;
}
void start_all_vifs()
{
vifi_t vifi;
struct uvif *v;
u_int action;
/* Start first the NON-REGISTER vifs */
for(action=0; ;action = MIFF_REGISTER )
{
for(vifi= 0,v = uvifs;vifi < numvifs ; ++vifi, ++v)
{
if (( v->uv_flags & MIFF_REGISTER ) ^ action )
/* If starting non-registers but the vif is a register
* or if starting registers, but the interface is not
* a register, then just continue.
*/
continue;
if ( v->uv_flags & (VIFF_DISABLED | VIFF_DOWN ))
{
IF_DEBUG(DEBUG_IF)
{
if ( v-> uv_flags & VIFF_DISABLED)
log(LOG_DEBUG,0,"%s is DISABLED ; vif #%u out of service",v->uv_name,vifi);
else
log(LOG_DEBUG,0,"%s is DOWN ; vif #%u out of service",v->uv_name,vifi);
}
}
else
start_vif(vifi);
}
if ( action == MIFF_REGISTER)
break;
}
}
/*
* 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.
*/
void start_vif (vifi_t vifi)
{
struct uvif *v;
v = &uvifs[vifi];
/* Initialy no router on any vif */
if( v-> uv_flags & MIFF_REGISTER)
v->uv_flags = v->uv_flags & ~VIFF_DOWN;
else
{
v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~ VIFF_DOWN;
v->uv_pim_hello_timer = 1 + RANDOM() % pim_hello_period;
v->uv_jp_timer = 1 + RANDOM() % pim_join_prune_period;
}
/* Tell kernel to add, i.e. start this vif */
k_add_vif(mld6_socket,vifi,&uvifs[vifi]);
IF_DEBUG(DEBUG_IF)
log(LOG_DEBUG,0,"%s comes up ,vif #%u now in service",v->uv_name,vifi);
if(!(v->uv_flags & MIFF_REGISTER))
{
/*
* Join the PIM multicast group on the interface.
*/
k_join(mld6_socket,&allpim6routers_group.sin6_addr,v->uv_ifindex);
/*
* Join the ALL-ROUTERS multicast group on the interface.
* This allows mtrace requests to loop back if they are run
* on the multicast router.this allow receiving mld6 messages too.
*/
k_join(mld6_socket,&allrouters_group.sin6_addr,v->uv_ifindex);
/*
* 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_pim6_hello( v , pim_hello_holdtime );
}
}
/*
* Stop a vif (either physical interface, tunnel or
* register.) If we are running only PIM we don't have tunnels.
*/
void stop_vif( vifi_t vifi )
{
struct uvif *v;
struct listaddr *a;
register pim_nbr_entry_t *n;
register pim_nbr_entry_t *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&MIFF_REGISTER ) )
{
k_leave( mld6_socket , &allpim6routers_group.sin6_addr , v->uv_ifindex );
k_leave( mld6_socket , &allrouters_group.sin6_addr , v->uv_ifindex );
/*
* 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( mld6_socket , vifi );
v->uv_flags=(v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS) | VIFF_DOWN;
if( !(v->uv_flags & MIFF_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;
IF_DEBUG(DEBUG_IF)
log( LOG_DEBUG ,0,"%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 :))
*/
int
update_reg_vif( vifi_t register_vifi )
{
register struct uvif *v;
register 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_TUNNEL
| MIFF_REGISTER))
continue;
/* Found. Stop the bogus Register vif first */
stop_vif(register_vifi);
uvifs[register_vifi].uv_linklocal->pa_addr =
uvifs[vifi].uv_linklocal->pa_addr;
start_vif(register_vifi);
IF_DEBUG(DEBUG_PIM_REGISTER | DEBUG_IF)
log(LOG_NOTICE, 0, "%s has come up; vif #%u now in service",
uvifs[register_vifi].uv_name, register_vifi);
return 0;
}
vifs_down = TRUE;
log(LOG_WARNING, 0, "Cannot start Register vif: %s",
uvifs[vifi].uv_name);
return(-1);
}
/*
* return the max global Ipv6 address of an UP and ENABLED interface
* other than the MIFF_REGISTER interface.
*/
struct sockaddr_in6 *
max_global_address()
{
vifi_t vifi;
struct uvif *v;
struct phaddr *p;
struct phaddr *pmax = NULL;
for(vifi=0,v=uvifs;vifi< numvifs;++vifi,++v)
{
if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
continue;
/*
* take first the max global address of the interface
* (without link local) => aliasing
*/
for(p=v->uv_addrs;p!=NULL;p=p->pa_next)
{
/*
* If this is the first global address, take it anyway.
*/
if (pmax == NULL) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
pmax = p;
}
else {
if (inet6_lessthan(&pmax->pa_addr,
&p->pa_addr) &&
!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
pmax=p;
}
}
}
return(pmax ? &pmax->pa_addr : NULL);
}
struct sockaddr_in6 *
uv_global(vifi)
vifi_t vifi;
{
struct uvif *v = &uvifs[vifi];
struct phaddr *p;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
return(&p->pa_addr);
}
return(NULL);
}
/*
* Check if the interface exists in the mif table. If true
* return the highest address of the interface else return NULL.
*/
struct sockaddr_in6 *
local_iface(char *ifname)
{
register struct uvif *v;
vifi_t vifi;
struct phaddr *p;
struct phaddr *pmax = NULL;
for(vifi=0,v=uvifs;vifi<numvifs;++vifi,++v)
{
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
continue;
if(EQUAL(v->uv_name, ifname))
{
for(p=v->uv_addrs; p!=NULL; p=p->pa_next)
{
if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr)&&
!IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
/*
* If this is the first global address
* or larger than the current MAX global
* address, remember it.
*/
if (pmax == NULL ||
inet6_lessthan(&pmax->pa_addr,
&p->pa_addr))
pmax = p;
}
}
if (pmax)
return(&pmax->pa_addr);
}
}
return NULL;
}
/*
* 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()
{
register vifi_t vifi;
register 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=TRUE;
/* 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|MIFF_REGISTER ) )
continue;
strncpy( ifr.ifr_name , v->uv_name , IFNAMSIZ );
/* get the interface flags */
if( ioctl( udp_socket , SIOCGIFFLAGS , (char *)&ifr )<0 )
log(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 ))
{
log( LOG_NOTICE ,0,
"%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 )
{
register vifi_t vifi2;
register struct uvif *v2;
int found;
if( !(v->uv_flags & MIFF_REGISTER ) )
continue;
else
{
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_TUNNEL|MIFF_REGISTER ))
continue;
if( IN6_ARE_ADDR_EQUAL( &v->uv_linklocal->pa_addr.sin6_addr,
&v2->uv_linklocal->pa_addr.sin6_addr ))
{
found=1;
break;
}
}
if(!found)
/* The physical interface with the IP address as the Register
* vif is probably DOWN. Get a replacement.
*/
update_reg_vif( vifi );
}
}
checking_vifs=0;
}
/*
* If the source is directly connected to us, find the vif number for
* the corresponding physical interface (tunnels excluded).
* Local addresses are excluded.
* Return the vif number or NO_VIF if not found.
*/
vifi_t
find_vif_direct(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
{
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL|MIFF_REGISTER))
continue;
for (p = v->uv_addrs; p; p = p->pa_next)
{
if (inet6_equal(src, &p->pa_addr))
return(NO_VIF);
if (inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
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(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
continue;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (inet6_equal(src, &p->pa_addr))
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
* (tunnels excluded).
* Return the vif number or NO_VIF if not found.
*/
vifi_t
find_vif_direct_local(src)
struct sockaddr_in6 *src;
{
vifi_t vifi;
register struct uvif *v;
register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL |MIFF_REGISTER))
continue;
for (p = v->uv_addrs; p; p = p->pa_next) {
if (inet6_equal(src, &p->pa_addr) ||
inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
return(vifi);
}
}
return (NO_VIF);
}
int
vif_forwarder(if_set *p1 , if_set *p2)
{
int idx;
for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
{
if (p1->ifs_bits[idx] & p2->ifs_bits[idx])
return(TRUE);
}
/* (p1 & p2) is empty. We're not the forwarder */
return(FALSE);
}
if_set *
vif_and(if_set *p1 , if_set *p2, if_set *result)
{
int idx;
IF_ZERO(result);
for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
{
result->ifs_bits[idx] = p1->ifs_bits[idx] & p2->ifs_bits[idx];
}
return(result);
}
if_set *
vif_xor(if_set *p1 , if_set *p2, if_set *result)
{
int idx;
IF_ZERO(result);
for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
{
result->ifs_bits[idx] =
p1->ifs_bits[idx] ^ p2->ifs_bits[idx];
}
return(result);
}
/*
* stop all vifs
*/
void
stop_all_vifs()
{
vifi_t vifi;
struct uvif *v;
for (vifi = 0, v=uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DOWN)) {
stop_vif(vifi);
}
}
}
struct uvif *
find_vif(ifname)
char *ifname;
{
struct uvif *v;
vifi_t vifi;
for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v) {
if (strcasecmp(v->uv_name, ifname) == 0)
return(v);
}
return(NULL);
}

277
usr.sbin/pim6sd/vif.h Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright (c) 1998 by the University of Southern California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation in source and binary forms for lawful
* purposes and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both
* the copyright notice and this permission notice appear in supporting
* documentation, and that any documentation, advertising materials,
* and other materials related to such distribution and use acknowledge
* that the software was developed by the University of Southern
* California and/or Information Sciences Institute.
* The name of the University of Southern California may not
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
* NON-INFRINGEMENT.
*
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $FreeBSD$
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
*/
/*
* Part of this program has been derived from mrouted.
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted".
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*/
#ifndef VIF_H
#define VIF_H
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/route.h>
#include <net/if.h>
#include <netinet6/ip6_mroute.h>
#include <netinet/ip_mroute.h>
#include "defs.h"
extern int total_interfaces;
extern int udp_socket;
extern struct uvif uvifs[];
extern vifi_t numvifs;
extern int vifs_down;
extern int phys_vif;
extern vifi_t reg_vif_num;
#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
#define DEFAULT_METRIC 1
#define VIFF_DOWN 0x000100
#define VIFF_DISABLED 0x000200
#define VIFF_QUERIER 0x000400
#define VIFF_REXMIT_PRUNES 0x004000
#define VIFF_DR 0x040000
#define VIFF_NONBRS 0x080000
#define VIFF_PIM_NBR 0x200000
#define VIFF_POINT_TO_POINT 0x400000
#define NBRTYPE u_long
#define NBRBITS sizeof(NBRTYPE) *8
extern if_set if_nullset;
#define IF_ISEMPTY(p) (memcmp((p), &if_nullset, sizeof(if_nullset)) == 0)
#define IF_SAME(p1, p2) (memcmp((p1),(p2),sizeof(*(p1))) == 0)
#define IF_CLR_MASK(p, mask) \
{\
int idx;\
for (idx = 0; idx < sizeof(*(p))/sizeof(fd_mask); idx++) {\
(p)->ifs_bits[idx] &= ~((mask)->ifs_bits[idx]);\
}\
}
#define IF_MERGE(p1, p2, result) \
{\
int idx;\
for (idx = 0; idx < sizeof(*(p1))/sizeof(fd_mask); idx++) {\
(result)->ifs_bits[idx] = (p1)->ifs_bits[idx]|(p2)->ifs_bits[idx]; \
}\
}
typedef struct {
NBRTYPE hi;
NBRTYPE lo;
} nbrbitmap_t;
struct vf_element {
struct vf_element *vfe_next;
struct sockaddr_in6 *vfe_addr;
struct in6_addr vfe_mask;
int vfe_flags;
#define VFRF_EXACT 0x0001
};
#define VFT_ACCEPT 1
#define VFT_DENY 2
#define VFF_BIDIR 1
struct vif_filter {
int vf_type;
int vf_flags;
struct vf_element *vf_filter;
};
struct listaddr {
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
struct sockaddr_in6 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 */
struct sockaddr_in6 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
/*
* 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;
u_char uv_metric; /* VIFF_ flags defined below */
u_char uv_admetric; /* advertised cost of this vif */
u_int uv_rate_limit; /* rate limit on this vif */
struct phaddr *uv_linklocal; /* link-local address of this vif */
struct sockaddr_in6 uv_rmt_addr;/* remote end-point addr (tunnels only) */
struct sockaddr_in6 uv_dst_addr;/* destination for PIM messages */
struct sockaddr_in6 uv_prefix; /* prefix (phyints only) */
struct in6_addr uv_subnetmask; /* subnet mask (phyints only) */
char uv_name[IFNAMSIZ]; /* interface name */
u_int uv_ifindex; /* index of the interface */
u_int uv_siteid; /* index of the site on the interface */
struct listaddr *uv_groups; /* list of local groups (phyints only) */
struct lisaddr *uv_dvmrp_neighbors;
nbrbitmap_t uv_nbrmap; /* bitmap of active neighboring routers */
struct listaddr *uv_querier; /* MLD querier on vif */
int uv_prune_lifetime; /* Prune lifetime or 0 for default */
struct vif_acl *uv_acl; /* access control list of groups */
int uv_leaftimer; /* time until this vif is considrd leaf */
struct phaddr *uv_addrs; /* Additional addresses on this vif */
struct vif_filter *uvfilter; /* 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; /* 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 nbr routers */
void *config_attr; /* temporary buffer while parsing config */
/* the followings are to collect statistics */
/* incoming PIM6 packets on this interface */
u_quad_t uv_in_pim6_hello;
u_quad_t uv_in_pim6_join_prune;
u_quad_t uv_in_pim6_bootsrap;
u_quad_t uv_in_pim6_assert;
/* outgoing PIM6 packets on this interface */
u_quad_t uv_out_pim6_hello;
u_quad_t uv_out_pim6_join_prune;
u_quad_t uv_out_pim6_bootsrap;
u_quad_t uv_out_pim6_assert;
/* incoming MLD packets on this interface */
u_quad_t uv_in_mld_query;
u_quad_t uv_in_mld_report;
u_quad_t uv_in_mld_done;
/* outgoing MLD packets on this interface */
u_quad_t uv_out_mld_query;
u_quad_t uv_out_mld_report;
u_quad_t uv_out_mld_done;
/* statistics about the forwarding cache in kernel */
u_quad_t uv_cache_miss;
u_quad_t uv_cache_notcreated;
/* occurrences of timeouts */
u_quad_t uv_pim6_nbr_timo;
u_quad_t uv_listener_timo;
u_quad_t uv_outif_timo; /* outgoing interfaces timers */
};
struct phaddr {
struct phaddr *pa_next;
struct sockaddr_in6 pa_addr;
struct sockaddr_in6 pa_prefix;
struct in6_addr pa_subnetmask;
};
/* The Access Control List (list with scoped addresses) member */
#define VIFF_NOLISTENER 0x800000 /* no listener on the link */
struct vif_acl {
struct vif_acl *acl_next;
struct sockaddr_in6 acl_addr;
struct in6_addr acl_mask;
};
/*
* Used to get the RPF neighbor and IIF info
* for a given source from the unicast routing table.
*/
struct rpfctl {
struct sockaddr_in6 source; /* the source for which we want iif and rpfnbr */
struct sockaddr_in6 rpfneighbor;/* next hop towards the source */
vifi_t iif; /* the incoming interface to reach the next hop */
};
extern void init_vifs __P(());
extern void stop_all_vifs __P(());
extern void check_vif_state __P(());
struct sockaddr_in6 * max_global_address();
struct sockaddr_in6 * uv_global __P(());
extern vifi_t local_address __P((struct sockaddr_in6 *src));
struct sockaddr_in6 * local_iface( char *ifname );
extern vifi_t find_vif_direct __P((struct sockaddr_in6 *src));
extern vifi_t find_vif_direct_local __P((struct sockaddr_in6 *src));
extern int vif_forwarder __P((if_set *p1 ,if_set *p2));
extern if_set *vif_and __P((if_set *p1, if_set *p2, if_set *result));
extern if_set *vif_xor __P((if_set *p1, if_set *p2, if_set *result));
extern struct uvif *find_vif __P((char *ifname));
#endif

49
usr.sbin/pim6sd/vmbuf.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* 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.
*
* $FreeBSD$
*/
/* YIPS @(#)$Id: vmbuf.h,v 1.1 1999/10/29 09:04:55 jinmei Exp $ */
typedef struct _vchar_ {
u_int32_t t; /* type of the value */
size_t l; /* length of the value */
caddr_t v; /* place holder to the value in buffer */
#if 0
caddr_t v0; /* pointer to the buffer - not used any more */
#endif
} vchar_t;
extern vchar_t *vmalloc(size_t);
extern vchar_t *vrealloc(vchar_t *, size_t);
extern void vfree(vchar_t *);
extern vchar_t *vdup(vchar_t *);
extern int pvdump(vchar_t *);
#define VREALLOC(ptr, size) ((ptr) = vrealloc((ptr), (size)))