mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2025-01-01 00:18:15 +01:00
This is a 'for reference' import of mrouted release 3.8.
I'm using these to try to resync our tree with the vendor branch..
This commit is contained in:
parent
29a6d69cc3
commit
73950bd7a6
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: callout.c,v 3.6 1995/06/25 18:47:29 fenner Exp $
|
||||
* $Id: callout.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
@ -16,7 +16,7 @@
|
||||
static int id = 0;
|
||||
static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
|
||||
|
||||
static int in_callout= 0;
|
||||
static int in_callout = 0;
|
||||
|
||||
struct timeout_q {
|
||||
struct timeout_q *next; /* next event */
|
||||
@ -53,12 +53,15 @@ age_callout_queue()
|
||||
in_callout = 1;
|
||||
ptr = Q;
|
||||
|
||||
while (ptr){
|
||||
if (!ptr->time ) {
|
||||
while (ptr) {
|
||||
if (!ptr->time) {
|
||||
/* timeout has happened */
|
||||
Q = Q->next;
|
||||
|
||||
in_callout = 0;
|
||||
if (ptr->func)
|
||||
ptr->func(ptr->data);
|
||||
Q = Q->next;
|
||||
in_callout = 1;
|
||||
|
||||
free(ptr);
|
||||
ptr = Q;
|
||||
@ -206,3 +209,18 @@ print_Q()
|
||||
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
|
||||
}
|
||||
#endif /* IGMP_DEBUG */
|
||||
int
|
||||
secs_remaining( timer_id)
|
||||
int timer_id;
|
||||
{
|
||||
struct timeout_q *ptr;
|
||||
int left=0;
|
||||
|
||||
for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
|
||||
left += ptr->time;
|
||||
|
||||
if (!ptr) /* not found */
|
||||
return 0;
|
||||
|
||||
return left + ptr->time;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Written by Bill Fenner, NRL, 1994
|
||||
*
|
||||
* $Id: cfparse.y,v 3.6 1995/06/25 18:49:46 fenner Exp $
|
||||
* $Id: cfparse.y,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
@ -13,6 +13,7 @@
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include "defs.h"
|
||||
#include <netdb.h>
|
||||
|
||||
/*
|
||||
* Local function declarations
|
||||
@ -69,14 +70,16 @@ int numbounds = 0; /* Number of named boundaries */
|
||||
|
||||
%token CACHE_LIFETIME PRUNING
|
||||
%token PHYINT TUNNEL NAME
|
||||
%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
|
||||
%token DISABLE IGMPV1 SRCRT
|
||||
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
|
||||
%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
|
||||
%token <num> BOOLEAN
|
||||
%token <num> NUMBER
|
||||
%token <ptr> STRING
|
||||
%token <addrmask> ADDRMASK
|
||||
%token <addr> ADDR
|
||||
|
||||
%type <addr> interface
|
||||
%type <addr> interface addrname
|
||||
%type <addrmask> bound boundary addrmask
|
||||
|
||||
%start conf
|
||||
@ -109,10 +112,9 @@ stmt : error
|
||||
fatal("%s is not a configured interface",
|
||||
inet_fmt($2,s1));
|
||||
|
||||
/*log(LOG_INFO, 0, "phyint: %x\n", v);*/
|
||||
}
|
||||
ifmods
|
||||
| TUNNEL interface ADDR {
|
||||
| TUNNEL interface addrname {
|
||||
|
||||
struct ifreq *ifr;
|
||||
struct ifreq ffr;
|
||||
@ -172,7 +174,6 @@ stmt : error
|
||||
v->uv_flags |= VIFF_DOWN;
|
||||
vifs_down = TRUE;
|
||||
}
|
||||
/*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
|
||||
}
|
||||
tunnelmods
|
||||
{
|
||||
@ -195,10 +196,30 @@ stmt : error
|
||||
strcpy(boundlist[numbounds].name, $2);
|
||||
boundlist[numbounds++].bound = $3;
|
||||
}
|
||||
| SYSNAM STRING {
|
||||
#ifdef SNMP
|
||||
set_sysName($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSCONTACT STRING {
|
||||
#ifdef SNMP
|
||||
set_sysContact($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSVERSION STRING {
|
||||
#ifdef SNMP
|
||||
set_sysVersion($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
| SYSLOCATION STRING {
|
||||
#ifdef SNMP
|
||||
set_sysLocation($2);
|
||||
#endif /* SNMP */
|
||||
}
|
||||
;
|
||||
|
||||
tunnelmods : /* empty */
|
||||
| tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
|
||||
| tunnelmods tunnelmod
|
||||
;
|
||||
|
||||
tunnelmod : mod
|
||||
@ -206,12 +227,13 @@ tunnelmod : mod
|
||||
;
|
||||
|
||||
ifmods : /* empty */
|
||||
| ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
|
||||
| ifmods ifmod
|
||||
;
|
||||
|
||||
ifmod : mod
|
||||
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
|
||||
| NETMASK ADDR {
|
||||
| IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
|
||||
| NETMASK addrname {
|
||||
u_int32 subnet, mask;
|
||||
|
||||
mask = $2;
|
||||
@ -222,6 +244,11 @@ ifmod : mod
|
||||
v->uv_subnetmask = mask;
|
||||
v->uv_subnetbcast = subnet | ~mask;
|
||||
}
|
||||
| NETMASK {
|
||||
|
||||
warn("Expected address after netmask keyword, ignored");
|
||||
|
||||
}
|
||||
| ALTNET addrmask {
|
||||
|
||||
struct phaddr *ph;
|
||||
@ -241,6 +268,11 @@ ifmod : mod
|
||||
ph->pa_next = v->uv_addrs;
|
||||
v->uv_addrs = ph;
|
||||
|
||||
}
|
||||
| ALTNET {
|
||||
|
||||
warn("Expected address after altnet keyword, ignored");
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
@ -250,7 +282,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
|
||||
}
|
||||
| THRESHOLD {
|
||||
|
||||
warn("Expected number after threshold keyword");
|
||||
warn("Expected number after threshold keyword, ignored");
|
||||
|
||||
}
|
||||
| METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
|
||||
@ -259,7 +291,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
|
||||
}
|
||||
| METRIC {
|
||||
|
||||
warn("Expected number after metric keyword");
|
||||
warn("Expected number after metric keyword, ignored");
|
||||
|
||||
}
|
||||
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
|
||||
@ -268,7 +300,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
|
||||
}
|
||||
| RATE_LIMIT {
|
||||
|
||||
warn("Expected number after rate_limit keyword");
|
||||
warn("Expected number after rate_limit keyword, ignored");
|
||||
|
||||
}
|
||||
| BOUNDARY bound {
|
||||
@ -289,7 +321,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
|
||||
}
|
||||
| BOUNDARY {
|
||||
|
||||
warn("Expected boundary spec after boundary keyword");
|
||||
warn("Expected boundary spec after boundary keyword, ignored");
|
||||
|
||||
}
|
||||
;
|
||||
@ -302,6 +334,20 @@ interface : ADDR { $$ = $1; }
|
||||
}
|
||||
;
|
||||
|
||||
addrname : ADDR { $$ = $1; }
|
||||
| STRING { struct hostent *hp;
|
||||
|
||||
if ((hp = gethostbyname($1)) == NULL)
|
||||
fatal("No such host %s", $1);
|
||||
|
||||
if (hp->h_addr_list[1])
|
||||
fatal("Hostname %s does not %s",
|
||||
$1, "map to a unique address");
|
||||
|
||||
bcopy(hp->h_addr_list[0], &$$,
|
||||
hp->h_length);
|
||||
}
|
||||
|
||||
bound : boundary { $$ = $1; }
|
||||
| STRING { int i;
|
||||
|
||||
@ -413,6 +459,15 @@ next_word()
|
||||
continue;
|
||||
}
|
||||
q = p;
|
||||
#ifdef SNMP
|
||||
if (*p == '"') {
|
||||
p++;
|
||||
while (*p && *p != '"' && *p != '\n')
|
||||
p++; /* find next whitespace */
|
||||
if (*p == '"')
|
||||
p++;
|
||||
} else
|
||||
#endif
|
||||
while (*p && *p != ' ' && *p != '\t' && *p != '\n')
|
||||
p++; /* find next whitespace */
|
||||
*p++ = '\0'; /* null-terminate string */
|
||||
@ -459,10 +514,12 @@ yylex()
|
||||
return BOUNDARY;
|
||||
if (!strcmp(q,"netmask"))
|
||||
return NETMASK;
|
||||
if (!strcmp(q,"name"))
|
||||
return NAME;
|
||||
if (!strcmp(q,"igmpv1"))
|
||||
return IGMPV1;
|
||||
if (!strcmp(q,"altnet"))
|
||||
return ALTNET;
|
||||
if (!strcmp(q,"name"))
|
||||
return NAME;
|
||||
if (!strcmp(q,"on") || !strcmp(q,"yes")) {
|
||||
yylval.num = 1;
|
||||
return BOOLEAN;
|
||||
@ -494,6 +551,22 @@ yylex()
|
||||
yylval.num = n;
|
||||
return NUMBER;
|
||||
}
|
||||
#ifdef SNMP
|
||||
if (!strcmp(q,"sysName"))
|
||||
return SYSNAM;
|
||||
if (!strcmp(q,"sysContact"))
|
||||
return SYSCONTACT;
|
||||
if (!strcmp(q,"sysVersion"))
|
||||
return SYSVERSION;
|
||||
if (!strcmp(q,"sysLocation"))
|
||||
return SYSLOCATION;
|
||||
if (*q=='"') {
|
||||
if (q[ strlen(q)-1 ]=='"')
|
||||
q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
|
||||
yylval.ptr = q+1;
|
||||
return STRING;
|
||||
}
|
||||
#endif
|
||||
yylval.ptr = q;
|
||||
return STRING;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: config.c,v 3.6 1995/06/25 18:50:37 fenner Exp $
|
||||
* $Id: config.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: defs.h,v 3.6.1.1 1995/06/26 00:18:18 fenner Exp $
|
||||
* $Id: defs.h,v 3.8 1995/11/29 22:36:34 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -23,6 +23,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef SYSV
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
@ -46,7 +49,7 @@ typedef u_int u_int32;
|
||||
#endif
|
||||
|
||||
typedef void (*cfunc_t) __P((void *));
|
||||
typedef void (*ihfunc_t) __P((fd_set *));
|
||||
typedef void (*ihfunc_t) __P((int, fd_set *));
|
||||
|
||||
#include "dvmrp.h"
|
||||
#include "vif.h"
|
||||
@ -68,13 +71,17 @@ typedef void (*ihfunc_t) __P((fd_set *));
|
||||
|
||||
#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
|
||||
|
||||
#define VENDOR_CODE 1 /* Get a new vendor code if you make significant
|
||||
* changes to mrouted. */
|
||||
|
||||
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
|
||||
|
||||
#define MROUTED_VERSION 6 /* increment on local changes or bug fixes, */
|
||||
#define MROUTED_VERSION 8 /* increment on local changes or bug fixes, */
|
||||
/* reset to 0 whever PROTOCOL_VERSION increments */
|
||||
|
||||
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
|
||||
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
|
||||
#define MROUTED_LEVEL ((MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
|
||||
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16) | \
|
||||
(VENDOR_CODE << 24))
|
||||
/* for IGMP 'group' field of DVMRP messages */
|
||||
|
||||
#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
|
||||
@ -98,10 +105,17 @@ typedef void (*ihfunc_t) __P((fd_set *));
|
||||
#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 signal(s,f) sigset(s,f)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* External declarations for global variables and functions.
|
||||
*/
|
||||
#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
|
||||
#define RECV_BUF_SIZE 8192
|
||||
extern char *recv_buf;
|
||||
extern char *send_buf;
|
||||
extern int igmp_socket;
|
||||
@ -139,6 +153,17 @@ extern int sys_nerr;
|
||||
extern char * sys_errlist[];
|
||||
#endif
|
||||
|
||||
#ifdef OLD_KERNEL
|
||||
#define MRT_INIT DVMRP_INIT
|
||||
#define MRT_DONE DVMRP_DONE
|
||||
#define MRT_ADD_VIF DVMRP_ADD_VIF
|
||||
#define MRT_DEL_VIF DVMRP_DEL_VIF
|
||||
#define MRT_ADD_MFC DVMRP_ADD_MFC
|
||||
#define MRT_DEL_MFC DVMRP_DEL_MFC
|
||||
|
||||
#define IGMP_PIM 0x14
|
||||
#endif
|
||||
|
||||
/* main.c */
|
||||
extern void log __P((int, int, char *, ...));
|
||||
extern int register_input_handler __P((int fd, ihfunc_t func));
|
||||
@ -161,7 +186,7 @@ extern void timer_clearTimer __P((int timer_id));
|
||||
extern void init_routes __P((void));
|
||||
extern void start_route_updates __P((void));
|
||||
extern void update_route __P((u_int32 origin, u_int32 mask,
|
||||
int metric, u_int32 src,
|
||||
u_int metric, u_int32 src,
|
||||
vifi_t vifi));
|
||||
extern void age_routes __P((void));
|
||||
extern void expire_all_routes __P((void));
|
||||
@ -285,7 +310,7 @@ extern int find_src_grp __P((u_int32 src, u_int32 mask,
|
||||
|
||||
/* rsrr.c */
|
||||
extern void rsrr_init __P((void));
|
||||
extern void rsrr_read __P((fd_set *rfd));
|
||||
extern void rsrr_read __P((int f, fd_set *rfd));
|
||||
extern void rsrr_clean __P((void));
|
||||
extern void rsrr_cache_send __P((struct gtable *gt, int notify));
|
||||
extern void rsrr_cache_clean __P((struct gtable *gt));
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: dvmrp.h,v 3.6 1995/06/25 18:52:10 fenner Exp $
|
||||
* $Id: dvmrp.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -96,6 +96,8 @@
|
||||
#define DVMRP_PRUNE 7 /* prune message */
|
||||
#define DVMRP_GRAFT 8 /* graft message */
|
||||
#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */
|
||||
#define DVMRP_INFO_REQUEST 10 /* information request */
|
||||
#define DVMRP_INFO_REPLY 11 /* information reply */
|
||||
|
||||
/*
|
||||
* 'flags' byte values in DVMRP_NEIGHBORS2 reply.
|
||||
@ -108,6 +110,12 @@
|
||||
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
|
||||
#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
|
||||
|
||||
/*
|
||||
* Request/reply types for info queries/replies
|
||||
*/
|
||||
#define DVMRP_INFO_VERSION 1 /* version string */
|
||||
#define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */
|
||||
|
||||
/*
|
||||
* Limit on length of route data
|
||||
*/
|
||||
@ -122,8 +130,14 @@
|
||||
*/
|
||||
/* address for multicast DVMRP msgs */
|
||||
#define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
|
||||
/* (This is the timer interrupt */
|
||||
@ -144,8 +158,7 @@
|
||||
#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
|
||||
#define LEAVE_EXPIRE_TIME 3 /* " " after receiving a leave */
|
||||
/* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
|
||||
* the timer in mrouted doesn't allow us to follow the spec and make it any
|
||||
* shorter. */
|
||||
* the timer in mrouted doesn't allow us to make it any shorter. */
|
||||
|
||||
#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
|
||||
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: igmp.c,v 3.6 1995/06/25 18:52:55 fenner Exp $
|
||||
* $Id: igmp.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -94,6 +94,8 @@ packet_kind(type, code)
|
||||
case DVMRP_PRUNE: return "prune message ";
|
||||
case DVMRP_GRAFT: return "graft message ";
|
||||
case DVMRP_GRAFT_ACK: return "graft message ack ";
|
||||
case DVMRP_INFO_REQUEST: return "info request ";
|
||||
case DVMRP_INFO_REPLY: return "info reply ";
|
||||
default: return "unknown DVMRP msg ";
|
||||
}
|
||||
case IGMP_PIM:
|
||||
@ -154,8 +156,8 @@ accept_igmp(recvlen)
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
log(LOG_WARNING, 0,
|
||||
"received packet shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
"received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -232,6 +234,15 @@ accept_igmp(recvlen)
|
||||
accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_INFO_REQUEST:
|
||||
accept_info_request(src, dst, (char *)(igmp+1),
|
||||
igmpdatalen);
|
||||
return;
|
||||
|
||||
case DVMRP_INFO_REPLY:
|
||||
accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen);
|
||||
return;
|
||||
|
||||
default:
|
||||
log(LOG_INFO, 0,
|
||||
"ignoring unknown DVMRP message code %u from %s to %s",
|
||||
@ -296,9 +307,10 @@ send_igmp(src, dst, type, code, group, datalen)
|
||||
u_int32 group;
|
||||
int datalen;
|
||||
{
|
||||
static struct sockaddr_in sdst;
|
||||
struct sockaddr_in sdst;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
int setloop;
|
||||
|
||||
ip = (struct ip *)send_buf;
|
||||
ip->ip_src.s_addr = src;
|
||||
@ -313,8 +325,13 @@ send_igmp(src, dst, type, code, group, datalen)
|
||||
igmp->igmp_cksum = inet_cksum((u_short *)igmp,
|
||||
IGMP_MINLEN + datalen);
|
||||
|
||||
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
|
||||
if (dst == allhosts_group) k_set_loop(TRUE);
|
||||
if (IN_MULTICAST(ntohl(dst))) {
|
||||
k_set_if(src);
|
||||
if (type != IGMP_DVMRP) {
|
||||
setloop = 1;
|
||||
k_set_loop(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
bzero(&sdst, sizeof(sdst));
|
||||
sdst.sin_family = AF_INET;
|
||||
@ -332,7 +349,8 @@ send_igmp(src, dst, type, code, group, datalen)
|
||||
inet_fmt(dst, s1), inet_fmt(src, s2));
|
||||
}
|
||||
|
||||
if (dst == allhosts_group) k_set_loop(FALSE);
|
||||
if (setloop)
|
||||
k_set_loop(FALSE);
|
||||
|
||||
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
|
||||
packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: inet.c,v 3.6 1995/06/25 18:54:45 fenner Exp $
|
||||
* $Id: inet.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -41,6 +41,22 @@ inet_valid_host(naddr)
|
||||
(addr & 0xff000000) == 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a given netmask is plausible;
|
||||
* make sure that it is a series of 1's followed by
|
||||
* a series of 0's with no discontiguous 1's.
|
||||
*/
|
||||
int
|
||||
inet_valid_mask(mask)
|
||||
u_int32 mask;
|
||||
{
|
||||
if (~(((mask & -mask) - 1) | mask) != 0) {
|
||||
/* Mask is not contiguous */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a given subnet number and mask pair are credible.
|
||||
@ -62,21 +78,26 @@ inet_valid_subnet(nsubnet, nmask)
|
||||
|
||||
if ((subnet & mask) != subnet) return (FALSE);
|
||||
|
||||
if (subnet == 0 && mask == 0)
|
||||
return (TRUE);
|
||||
if (subnet == 0)
|
||||
return (mask == 0);
|
||||
|
||||
if (IN_CLASSA(subnet)) {
|
||||
if (mask < 0xff000000 ||
|
||||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
|
||||
(subnet & 0xff000000) == 0x7f000000 ||
|
||||
(subnet & 0xff000000) == 0x00000000) return (FALSE);
|
||||
}
|
||||
else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
|
||||
/* Above Class C address space */
|
||||
return (FALSE);
|
||||
}
|
||||
else if (subnet & ~mask) {
|
||||
if (subnet & ~mask) {
|
||||
/* Host bits are set in the subnet */
|
||||
return (FALSE);
|
||||
}
|
||||
if (!inet_valid_mask(mask)) {
|
||||
/* Netmask is not contiguous */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: kern.c,v 3.6 1995/06/25 18:57:38 fenner Exp $
|
||||
* $Id: kern.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -162,8 +162,11 @@ void k_add_rg(origin, g)
|
||||
struct gtable *g;
|
||||
{
|
||||
struct mfcctl mc;
|
||||
int i;
|
||||
vifi_t i;
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_ADD, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
/* copy table values so that setsockopt can process it */
|
||||
mc.mfcc_origin.s_addr = origin;
|
||||
#ifdef OLD_KERNEL
|
||||
@ -176,8 +179,12 @@ void k_add_rg(origin, g)
|
||||
|
||||
/* write to kernel space */
|
||||
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
|
||||
(char *)&mc, sizeof(mc)) < 0)
|
||||
(char *)&mc, sizeof(mc)) < 0) {
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -191,6 +198,9 @@ int k_del_rg(origin, g)
|
||||
struct mfcctl mc;
|
||||
int retval;
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_DEL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
/* copy table values so that setsockopt can process it */
|
||||
mc.mfcc_origin.s_addr = origin;
|
||||
#ifdef OLD_KERNEL
|
||||
@ -200,8 +210,12 @@ int k_del_rg(origin, g)
|
||||
|
||||
/* write to kernel space */
|
||||
if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
|
||||
(char *)&mc, sizeof(mc))) < 0)
|
||||
(char *)&mc, sizeof(mc))) < 0) {
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
|
||||
#endif
|
||||
log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -211,6 +225,9 @@ int k_del_rg(origin, g)
|
||||
*/
|
||||
int k_get_version()
|
||||
{
|
||||
#ifdef OLD_KERNEL
|
||||
return -1;
|
||||
#else
|
||||
int vers;
|
||||
int len = sizeof(vers);
|
||||
|
||||
@ -220,4 +237,5 @@ int k_get_version()
|
||||
"getsockopt MRT_VERSION: perhaps your kernel is too old");
|
||||
|
||||
return vers;
|
||||
#endif
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: main.c,v 3.6 1995/06/25 18:58:06 fenner Exp $
|
||||
* $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -32,7 +32,13 @@
|
||||
#include "snmp.h"
|
||||
#endif
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] =
|
||||
"@(#) $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
|
||||
#endif
|
||||
|
||||
extern char *configfilename;
|
||||
char versionstring[100];
|
||||
|
||||
static char pidfilename[] = _PATH_MROUTED_PID;
|
||||
static char dumpfilename[] = _PATH_MROUTED_DUMP;
|
||||
@ -45,7 +51,11 @@ int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
|
||||
int debug = 0;
|
||||
u_char pruning = 1; /* Enable pruning by default */
|
||||
|
||||
#ifdef SNMP
|
||||
#define NHANDLERS 34
|
||||
#else
|
||||
#define NHANDLERS 2
|
||||
#endif
|
||||
|
||||
static struct ihandler {
|
||||
int fd; /* File descriptor */
|
||||
@ -64,6 +74,7 @@ static void cdump __P((int));
|
||||
static void restart __P((int));
|
||||
static void timer __P((void));
|
||||
static void cleanup __P((void));
|
||||
static void resetlogging __P((void *));
|
||||
|
||||
/* To shut up gcc -Wstrict-prototypes */
|
||||
int main __P((int argc, char **argv));
|
||||
@ -97,22 +108,12 @@ main(argc, argv)
|
||||
fd_set rfds, readers;
|
||||
int nfds, n, i;
|
||||
#ifdef SNMP
|
||||
char *myname;
|
||||
fd_set wfds;
|
||||
|
||||
|
||||
if (myname = strrchr(argv[0], '/'))
|
||||
myname++;
|
||||
if (myname == NULL || *myname == 0)
|
||||
myname = argv[0];
|
||||
isodetailor (myname, 0);
|
||||
struct timeval timeout, *tvp = &timeout;
|
||||
struct timeval sched, *svp = &sched, now, *nvp = &now;
|
||||
int index, block;
|
||||
#endif
|
||||
|
||||
#ifdef SYSV
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
#else
|
||||
setlinebuf(stderr);
|
||||
#endif
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "must be root\n");
|
||||
@ -135,6 +136,14 @@ main(argc, argv)
|
||||
goto usage;
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
pruning = 0;
|
||||
#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--;
|
||||
@ -159,6 +168,9 @@ usage: fprintf(stderr,
|
||||
(void)open("/", 0);
|
||||
(void)dup2(0, 1);
|
||||
(void)dup2(0, 2);
|
||||
#ifdef SYSV
|
||||
(void)setpgrp();
|
||||
#else
|
||||
#ifdef TIOCNOTTY
|
||||
t = open("/dev/tty", 2);
|
||||
if (t >= 0) {
|
||||
@ -168,6 +180,7 @@ usage: fprintf(stderr,
|
||||
#else
|
||||
if (setsid() < 0)
|
||||
perror("setsid");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -179,9 +192,11 @@ usage: fprintf(stderr,
|
||||
#else
|
||||
(void)openlog("mrouted", LOG_PID);
|
||||
#endif
|
||||
log(LOG_NOTICE, 0, "mrouted version %d.%d",
|
||||
sprintf(versionstring, "mrouted version %d.%d",
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
|
||||
log(LOG_NOTICE, 0, "%s", versionstring);
|
||||
|
||||
#ifdef SYSV
|
||||
srand48(time(NULL));
|
||||
#else
|
||||
@ -209,12 +224,9 @@ usage: fprintf(stderr,
|
||||
}
|
||||
|
||||
callout_init();
|
||||
|
||||
#ifdef SNMP
|
||||
snmp_init();
|
||||
#endif
|
||||
|
||||
init_igmp();
|
||||
init_routes();
|
||||
init_ktable();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
|
||||
#ifndef OLD_KERNEL
|
||||
@ -229,15 +241,29 @@ usage: fprintf(stderr,
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
#endif
|
||||
|
||||
init_routes();
|
||||
init_ktable();
|
||||
#ifdef SNMP
|
||||
if (i = snmp_init())
|
||||
return i;
|
||||
|
||||
gettimeofday(nvp, 0);
|
||||
if (nvp->tv_usec < 500000L){
|
||||
svp->tv_usec = nvp->tv_usec + 500000L;
|
||||
svp->tv_sec = nvp->tv_sec;
|
||||
} else {
|
||||
svp->tv_usec = nvp->tv_usec - 500000L;
|
||||
svp->tv_sec = nvp->tv_sec + 1;
|
||||
}
|
||||
#endif /* SNMP */
|
||||
|
||||
init_vifs();
|
||||
|
||||
#ifdef RSRR
|
||||
rsrr_init();
|
||||
#endif /* RSRR */
|
||||
|
||||
#if defined(__STDC__) || defined(__GNUC__)
|
||||
/* Allow cleanup if unexpected exit. Apparently some architectures
|
||||
/*
|
||||
* Allow cleanup if unexpected exit. Apparently some architectures
|
||||
* have a kernel bug where closing the socket doesn't do an
|
||||
* ip_mrouter_done(), so we attempt to do it on exit.
|
||||
*/
|
||||
@ -253,8 +279,6 @@ usage: fprintf(stderr,
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
if (debug >= 2) dump(0);
|
||||
|
||||
(void)signal(SIGALRM, fasttimer);
|
||||
|
||||
(void)signal(SIGHUP, restart);
|
||||
@ -274,6 +298,17 @@ usage: fprintf(stderr,
|
||||
nfds = ihandlers[i].fd + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the vifs in the kernel as late as possible in the
|
||||
* initialization sequence.
|
||||
*/
|
||||
init_installvifs();
|
||||
|
||||
if (debug >= 2) dump(0);
|
||||
|
||||
/* Start up the log rate-limiter */
|
||||
resetlogging(NULL);
|
||||
|
||||
(void)alarm(1); /* schedule first timer interrupt */
|
||||
|
||||
/*
|
||||
@ -281,23 +316,38 @@ usage: fprintf(stderr,
|
||||
*/
|
||||
dummy = 0;
|
||||
for(;;) {
|
||||
#ifdef SYSV
|
||||
sigset_t block, oblock;
|
||||
#endif
|
||||
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
|
||||
#ifdef SNMP
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
if (smux_fd != NOTOK) {
|
||||
if (rock_and_roll)
|
||||
FD_SET(smux_fd, &rfds);
|
||||
else
|
||||
FD_SET(smux_fd, &wfds);
|
||||
if (smux_fd >= nfds)
|
||||
nfds = smux_fd + 1;
|
||||
}
|
||||
|
||||
if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
|
||||
gettimeofday(nvp, 0);
|
||||
if (nvp->tv_sec > svp->tv_sec
|
||||
|| (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
|
||||
alarmTimer(nvp);
|
||||
eventTimer(nvp);
|
||||
if (nvp->tv_usec < 500000L){
|
||||
svp->tv_usec = nvp->tv_usec + 500000L;
|
||||
svp->tv_sec = nvp->tv_sec;
|
||||
} else {
|
||||
svp->tv_usec = nvp->tv_usec - 500000L;
|
||||
svp->tv_sec = nvp->tv_sec + 1;
|
||||
}
|
||||
}
|
||||
|
||||
tvp = &timeout;
|
||||
tvp->tv_sec = 0;
|
||||
tvp->tv_usec = 500000L;
|
||||
|
||||
block = 0;
|
||||
snmp_select_info(&nfds, &rfds, tvp, &block);
|
||||
if (block == 1)
|
||||
tvp = NULL; /* block without timeout */
|
||||
if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0)
|
||||
#else
|
||||
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
|
||||
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0)
|
||||
#endif
|
||||
{
|
||||
if (errno != EINTR) /* SIGALRM is expected */
|
||||
log(LOG_WARNING, errno, "select failed");
|
||||
continue;
|
||||
@ -310,25 +360,31 @@ usage: fprintf(stderr,
|
||||
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
|
||||
continue;
|
||||
}
|
||||
#ifdef SYSV
|
||||
(void)sigemptyset(&block);
|
||||
(void)sigaddset(&block, SIGALRM);
|
||||
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
|
||||
log(LOG_ERR, errno, "sigprocmask");
|
||||
#else
|
||||
omask = sigblock(sigmask(SIGALRM));
|
||||
#endif
|
||||
accept_igmp(recvlen);
|
||||
#ifdef SYSV
|
||||
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
|
||||
#else
|
||||
(void)sigsetmask(omask);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < nhandlers; i++) {
|
||||
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
|
||||
(*ihandlers[i].func)(&rfds);
|
||||
(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SNMP
|
||||
if (smux_fd != NOTOK) {
|
||||
if (rock_and_roll) {
|
||||
if (FD_ISSET(smux_fd, &rfds))
|
||||
doit_smux();
|
||||
} else if (FD_ISSET(smux_fd, &wfds))
|
||||
start_smux();
|
||||
}
|
||||
snmp_read(&rfds);
|
||||
snmp_timeout(); /* poll */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -444,13 +500,7 @@ timer()
|
||||
}
|
||||
|
||||
#ifdef SNMP
|
||||
if (smux_fd == NOTOK && !dont_bother_anymore
|
||||
&& virtual_time % SNMPD_RETRY_INTERVAL == 0) {
|
||||
/*
|
||||
* Time to check for snmpd running.
|
||||
*/
|
||||
try_smux_init();
|
||||
}
|
||||
sync_timer();
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -467,8 +517,7 @@ static void
|
||||
done(i)
|
||||
int i;
|
||||
{
|
||||
log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
log(LOG_NOTICE, 0, "%s exiting", versionstring);
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
@ -545,14 +594,23 @@ restart(i)
|
||||
int i;
|
||||
{
|
||||
register int omask;
|
||||
#ifdef SYSV
|
||||
sigset_t block, oblock;
|
||||
#endif
|
||||
|
||||
log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
|
||||
PROTOCOL_VERSION, MROUTED_VERSION);
|
||||
log(LOG_NOTICE, 0, "%s restart", versionstring);
|
||||
|
||||
/*
|
||||
* reset all the entries
|
||||
*/
|
||||
#ifdef SYSV
|
||||
(void)sigemptyset(&block);
|
||||
(void)sigaddset(&block, SIGALRM);
|
||||
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
|
||||
log(LOG_ERR, errno, "sigprocmask");
|
||||
#else
|
||||
omask = sigblock(sigmask(SIGALRM));
|
||||
#endif
|
||||
free_all_prunes();
|
||||
free_all_routes();
|
||||
stop_all_vifs();
|
||||
@ -567,14 +625,41 @@ restart(i)
|
||||
pruning = 1;
|
||||
|
||||
init_igmp();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
init_routes();
|
||||
init_ktable();
|
||||
init_vifs();
|
||||
k_init_dvmrp(); /* enable DVMRP routing in kernel */
|
||||
init_installvifs();
|
||||
|
||||
#ifdef SYSV
|
||||
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
|
||||
#else
|
||||
(void)sigsetmask(omask);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */
|
||||
#define LOG_SHUT_UP 600 /* shut up for 10 minutes */
|
||||
static int log_nmsgs = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log errors and other messages to the system log daemon and to stderr,
|
||||
@ -633,12 +718,40 @@ log(severity, syserr, format, va_alist)
|
||||
}
|
||||
|
||||
if (severity <= LOG_NOTICE) {
|
||||
if (syserr != 0) {
|
||||
errno = syserr;
|
||||
syslog(severity, "%s: %m", msg);
|
||||
} else
|
||||
syslog(severity, "%s", msg);
|
||||
if (log_nmsgs++ < LOG_MAX_MSGS) {
|
||||
if (syserr != 0) {
|
||||
errno = syserr;
|
||||
syslog(severity, "%s: %m", msg);
|
||||
} else
|
||||
syslog(severity, "%s", msg);
|
||||
}
|
||||
|
||||
if (severity <= LOG_ERR) exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
void
|
||||
md_log(what, origin, mcastgrp)
|
||||
int what;
|
||||
u_int32 origin, mcastgrp;
|
||||
{
|
||||
static FILE *f = NULL;
|
||||
struct timeval tv;
|
||||
u_int32 buf[4];
|
||||
|
||||
if (!f) {
|
||||
if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
|
||||
log(LOG_ERR, errno, "open /tmp/mrouted.clog");
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
buf[0] = tv.tv_sec;
|
||||
buf[1] = what;
|
||||
buf[2] = origin;
|
||||
buf[3] = mcastgrp;
|
||||
|
||||
fwrite(buf, sizeof(u_int32), 4, f);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Mapper for connections between MRouteD multicast routers.
|
||||
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
|
||||
*
|
||||
* $Id: mapper.c,v 3.6 1995/06/25 18:59:02 fenner Exp $
|
||||
* $Id: mapper.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -302,7 +302,7 @@ void accept_neighbors(src, dst, p, datalen, level)
|
||||
/* if node is running a recent mrouted, ask for additional info */
|
||||
if (level != 0) {
|
||||
node->version = level;
|
||||
node->tries = 0;
|
||||
node->tries = 1;
|
||||
ask2(src);
|
||||
return;
|
||||
}
|
||||
@ -374,7 +374,7 @@ void accept_neighbors(src, dst, p, datalen, level)
|
||||
for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
|
||||
if (nb_i->addr == nb_n->addr) {
|
||||
if (nb_i->metric != nb_n->metric
|
||||
|| nb_i->threshold != nb_i->threshold)
|
||||
|| nb_i->threshold != nb_n->threshold)
|
||||
log(LOG_WARNING, 0,
|
||||
"inconsistent %s for neighbor %s of %s",
|
||||
"metric/threshold",
|
||||
@ -451,6 +451,8 @@ void accept_neighbors2(src, dst, p, datalen, level)
|
||||
int datalen;
|
||||
{
|
||||
Node *node = find_node(src, &routers);
|
||||
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
|
||||
/* well, only possibly_broken_cisco, but that's too long to type. */
|
||||
|
||||
if (node->tries == 0) /* Never heard of 'em; must have hit them at */
|
||||
node->tries = 1; /* least once, though...*/
|
||||
@ -478,6 +480,11 @@ void accept_neighbors2(src, dst, p, datalen, level)
|
||||
ncount = *p++;
|
||||
datalen -= 4 + 4;
|
||||
|
||||
if (broken_cisco && ncount == 0) /* dumb Ciscos */
|
||||
ncount = 1;
|
||||
if (broken_cisco && ncount > 15) /* dumb Ciscos */
|
||||
ncount = ncount & 0xf;
|
||||
|
||||
/* Fix up any alias information */
|
||||
ifc_node = find_node(ifc_addr, &routers);
|
||||
if (ifc_node->tries == 0) { /* new node */
|
||||
@ -837,11 +844,7 @@ int main(argc, argv)
|
||||
{
|
||||
int flood = FALSE, graph = FALSE;
|
||||
|
||||
#ifdef SYSV
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
#else
|
||||
setlinebuf(stderr);
|
||||
#endif
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "must be root\n");
|
||||
@ -1017,3 +1020,15 @@ void accept_membership_query(src, dst, group, tmo)
|
||||
int tmo;
|
||||
{
|
||||
}
|
||||
void accept_info_request(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
void accept_info_reply(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] =
|
||||
"@(#) $Id: mrinfo.c,v 3.6 1995/06/25 19:05:34 fenner Exp $";
|
||||
"@(#) $Id: mrinfo.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
|
||||
/* original rcsid:
|
||||
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
|
||||
*/
|
||||
@ -237,8 +237,13 @@ accept_neighbors2(src, dst, p, datalen, level)
|
||||
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
|
||||
/* well, only possibly_broken_cisco, but that's too long to type. */
|
||||
|
||||
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
|
||||
printf("%s (%s) [version %d.%d", inet_fmt(src, s1), inet_name(src),
|
||||
level & 0xff, (level >> 8) & 0xff);
|
||||
if ((level >> 16) & NF_LEAF) { printf (",leaf"); }
|
||||
if ((level >> 16) & NF_PRUNE) { printf (",prune"); }
|
||||
if ((level >> 16) & NF_GENID) { printf (",genid"); }
|
||||
if ((level >> 16) & NF_MTRACE) { printf (",mtrace"); }
|
||||
printf ("]:\n");
|
||||
|
||||
while (p < ep) {
|
||||
register u_char metric;
|
||||
@ -307,23 +312,6 @@ get_number(var, deflt, pargv, pargc)
|
||||
}
|
||||
}
|
||||
|
||||
u_int32
|
||||
host_addr(name)
|
||||
char *name;
|
||||
{
|
||||
struct hostent *e;
|
||||
u_int32 addr;
|
||||
|
||||
addr = inet_addr(name);
|
||||
if ((int)addr == -1) {
|
||||
e = gethostbyname(name);
|
||||
if (e == NULL || e->h_length != sizeof(addr))
|
||||
return (0);
|
||||
memcpy(&addr, e->h_addr_list[0], e->h_length);
|
||||
}
|
||||
return(addr);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
@ -337,9 +325,13 @@ main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int tries = 0;
|
||||
int trynew = 1;
|
||||
int tries;
|
||||
int trynew;
|
||||
struct timeval et;
|
||||
struct hostent *hp;
|
||||
struct hostent bogus;
|
||||
char *host;
|
||||
int curaddr;
|
||||
|
||||
setlinebuf(stderr);
|
||||
|
||||
@ -373,11 +365,21 @@ main(argc, argv)
|
||||
if (argc > 1)
|
||||
usage();
|
||||
if (argc == 1)
|
||||
target_addr = host_addr(argv[0]);
|
||||
host = argv[0];
|
||||
else
|
||||
target_addr = host_addr("127.0.0.1");
|
||||
host = "127.0.0.1";
|
||||
|
||||
if (target_addr == 0) {
|
||||
if ((target_addr = inet_addr(host)) != -1) {
|
||||
hp = &bogus;
|
||||
hp->h_length = sizeof(target_addr);
|
||||
hp->h_addr_list = (char **)malloc(2 * sizeof(char *));
|
||||
hp->h_addr_list[0] = malloc(hp->h_length);
|
||||
memcpy(hp->h_addr_list[0], &target_addr, hp->h_length);
|
||||
hp->h_addr_list[1] = 0;
|
||||
} else
|
||||
hp = gethostbyname(host);
|
||||
|
||||
if (hp == NULL) {
|
||||
fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
@ -386,7 +388,10 @@ main(argc, argv)
|
||||
|
||||
init_igmp();
|
||||
|
||||
{ /* Find a good local address for us. */
|
||||
/* Check all addresses; mrouters often have unreachable interfaces */
|
||||
for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) {
|
||||
memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length);
|
||||
{ /* Find a good local address for us. */
|
||||
int udp;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
@ -406,20 +411,22 @@ main(argc, argv)
|
||||
}
|
||||
close(udp);
|
||||
our_addr = addr.sin_addr.s_addr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* New strategy: send 'ask2' for two timeouts, then fall back
|
||||
* to 'ask', since it's not very likely that we are going to
|
||||
* find someone who only responds to 'ask' these days
|
||||
*/
|
||||
ask2(target_addr);
|
||||
tries = 0;
|
||||
trynew = 1;
|
||||
/*
|
||||
* New strategy: send 'ask2' for two timeouts, then fall back
|
||||
* to 'ask', since it's not very likely that we are going to
|
||||
* find someone who only responds to 'ask' these days
|
||||
*/
|
||||
ask2(target_addr);
|
||||
|
||||
gettimeofday(&et, 0);
|
||||
et.tv_sec += timeout;
|
||||
gettimeofday(&et, 0);
|
||||
et.tv_sec += timeout;
|
||||
|
||||
/* Main receive loop */
|
||||
for (;;) {
|
||||
/* Main receive loop */
|
||||
for (;;) {
|
||||
fd_set fds;
|
||||
struct timeval tv, now;
|
||||
int count, recvlen, dummy = 0;
|
||||
@ -451,7 +458,7 @@ main(argc, argv)
|
||||
} else if (count == 0) {
|
||||
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
|
||||
if (++tries > retries)
|
||||
exit(1);
|
||||
break;
|
||||
/* If we've tried ASK_NEIGHBORS2 twice with
|
||||
* no response, fall back to ASK_NEIGHBORS
|
||||
*/
|
||||
@ -461,6 +468,8 @@ main(argc, argv)
|
||||
ask(target_addr);
|
||||
else
|
||||
ask2(target_addr);
|
||||
gettimeofday(&et, 0);
|
||||
et.tv_sec += timeout;
|
||||
continue;
|
||||
}
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
|
||||
@ -485,19 +494,19 @@ main(argc, argv)
|
||||
iphdrlen = ip->ip_hl << 2;
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
log(LOG_WARNING, 0,
|
||||
"packet shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
continue;
|
||||
log(LOG_WARNING, 0,
|
||||
"packet shorter (%u bytes) than hdr+data length (%u+%u)",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
continue;
|
||||
}
|
||||
igmp = (struct igmp *) (recv_buf + iphdrlen);
|
||||
group = igmp->igmp_group.s_addr;
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
log(LOG_WARNING, 0,
|
||||
"IP data field too short (%u bytes) for IGMP, from %s",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
continue;
|
||||
log(LOG_WARNING, 0,
|
||||
"IP data field too short (%u bytes) for IGMP, from %s",
|
||||
ipdatalen, inet_fmt(src, s1));
|
||||
continue;
|
||||
}
|
||||
if (igmp->igmp_type != IGMP_DVMRP)
|
||||
continue;
|
||||
@ -538,7 +547,9 @@ main(argc, argv)
|
||||
igmpdatalen, ntohl(group));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* dummies */
|
||||
@ -608,3 +619,15 @@ void accept_membership_query(src, dst, group, tmo)
|
||||
int tmo;
|
||||
{
|
||||
}
|
||||
void accept_info_request(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
void accept_info_reply(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
|
||||
'\"$Id: mrouted.8,v 3.6 1995/06/25 19:10:58 fenner Exp $
|
||||
'\"$Id: mrouted.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
|
||||
.TH MROUTED 8
|
||||
.UC 5
|
||||
.SH NAME
|
||||
@ -140,7 +140,7 @@ options may be specified as many times as necessary.
|
||||
The phyint command can be used to disable multicast routing on the physical
|
||||
interface identified by local IP address <local-addr>, or to associate a
|
||||
non-default metric or threshold with the specified physical interface.
|
||||
The local IP address <local-addr> may be alternatively replaced by the
|
||||
The local IP address <local-addr> may be replaced by the
|
||||
interface name (e.g le0).
|
||||
If a phyint is attached to multiple IP subnets, describe each additional subnet
|
||||
with the altnet keyword.
|
||||
@ -148,7 +148,12 @@ Phyint commands must precede tunnel commands.
|
||||
.PP
|
||||
The tunnel command can be used to establish a tunnel link between local
|
||||
IP address <local-addr> and remote IP address <remote-addr>, and to associate
|
||||
a non-default metric or threshold with that tunnel. The tunnel must be set
|
||||
a non-default metric or threshold with that tunnel.
|
||||
The local IP address <local-addr> may be replaced by the
|
||||
interface name (e.g. le0). The remote IP address <remote-addr> may
|
||||
be replaced by a host name, if and only if the host name has a single
|
||||
IP address associated with it.
|
||||
The tunnel must be set
|
||||
up in the mrouted.conf files of both routers before it can be used.
|
||||
'\"For backwards compatibility with older
|
||||
'\".IR mrouted s,
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: mrouted.conf,v 3.6 1995/06/25 19:11:55 fenner Exp $
|
||||
# $Id: mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel $
|
||||
#
|
||||
# This is the configuration file for "mrouted", an IP multicast router.
|
||||
# mrouted looks for it in "/etc/mrouted.conf".
|
||||
@ -35,3 +35,9 @@ tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate_limit 500 # <-- REPLACE
|
||||
#
|
||||
# You might want to specify a boundary on your tunnel to the outside world,
|
||||
# as above.
|
||||
#
|
||||
# NOTE: ONLY uncomment the following if you are running mrouted.snmp!
|
||||
#sysName "mymrouter"
|
||||
#sysContact "Me <me@me.com> +x.yyy.zzz-zzzz"
|
||||
#sysVersion "MyOS 4.1.3 and mrouted"
|
||||
#sysLocation "The MBONE"
|
||||
|
@ -29,7 +29,7 @@
|
||||
.\" Copyright (c) 1988 The Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" $Id: mtrace.8,v 3.6 1995/06/25 19:14:07 fenner Exp $
|
||||
.\" $Id: mtrace.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
|
||||
.\"
|
||||
.TH MTRACE 8 "May 8, 1995"
|
||||
.UC 6
|
||||
@ -63,9 +63,14 @@ mtrace \- print multicast path from a source to a receiver
|
||||
] [
|
||||
.B \-s
|
||||
] [
|
||||
.B \-S
|
||||
.I stat_int
|
||||
] [
|
||||
.B \-t
|
||||
.I ttl
|
||||
] [
|
||||
.B \-v
|
||||
] [
|
||||
.B \-w
|
||||
.I waittime
|
||||
]
|
||||
@ -105,6 +110,9 @@ detailed below. The two parameters can be distinguished because the
|
||||
is a unicast address and the
|
||||
.I group
|
||||
is a multicast address.
|
||||
.PP
|
||||
NOTE: For Solaris 2.4/2.5, if the multicast interface is not the default
|
||||
interface, the -i option must be used to set the local address.
|
||||
.SH OPTIONS
|
||||
.TP 8 8
|
||||
.BI \-g\ gwy
|
||||
@ -118,7 +126,7 @@ to the
|
||||
.RS 8
|
||||
.TP 12 12
|
||||
.I CAUTION!!
|
||||
Version 3.3 of
|
||||
Versions 3.3 and 3.5 of
|
||||
.B mrouted
|
||||
will crash if a trace query is received via a
|
||||
unicast packet and
|
||||
@ -129,7 +137,7 @@ address. Therefore, do not use the
|
||||
.B \-g
|
||||
option unless the target
|
||||
.B mrouted
|
||||
has been verified to be newer than 3.3.
|
||||
has been verified to be 3.4 or newer than 3.5.
|
||||
.RE
|
||||
.TP 8 8
|
||||
.BI \-i\ addr
|
||||
@ -142,7 +150,9 @@ and the response destination.
|
||||
.TP 8 8
|
||||
.B \-l
|
||||
Loop indefinitely printing packet rate and loss statistics for the
|
||||
multicast path every 10 seconds.
|
||||
multicast path every 10 seconds (see
|
||||
.B \-S
|
||||
.IR stat_int ).
|
||||
.TP 8 8
|
||||
.B \-M
|
||||
Always send the response using multicast rather than attempting
|
||||
@ -169,7 +179,7 @@ The default is 3.
|
||||
.TP 8 8
|
||||
.B \-p
|
||||
Listen passively for multicast responses from traces initiated by
|
||||
others (not implemented yet).
|
||||
others. This works best when run on a multicast router.
|
||||
.TP 8 8
|
||||
.BI \-r\ host
|
||||
Send the trace response to
|
||||
@ -183,6 +193,11 @@ for this purpose (224.0.1.32).
|
||||
Print a short form output including only the multicast path and not
|
||||
the packet rate and loss statistics.
|
||||
.TP 8 8
|
||||
.BI \-S\ n
|
||||
Change the interval between statistics gathering traces to
|
||||
.I n
|
||||
seconds (default 10 seconds).
|
||||
.TP 8 8
|
||||
.BI \-t\ ttl
|
||||
Set the
|
||||
.I ttl
|
||||
@ -190,6 +205,9 @@ Set the
|
||||
responses. The default is 64, except for local queries to the "all
|
||||
routers" multicast group which use ttl 1.
|
||||
.TP 8 8
|
||||
.B \-v
|
||||
Verbose mode; show hop times on the initial trace and statistics display.
|
||||
.TP 8 8
|
||||
.BI \-w\ n
|
||||
Set the time to wait for a trace response to
|
||||
.I n
|
||||
|
@ -46,16 +46,19 @@
|
||||
* In particular, parts of the prototype version of this program may
|
||||
* have been derived from mrouted programs sources covered by the
|
||||
* license in the accompanying file named "LICENSE".
|
||||
*
|
||||
* $Id: mtrace.c,v 3.6 1995/06/25 19:17:14 fenner Exp $
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] =
|
||||
"@(#) $Id: mtrace.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
|
||||
#endif
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/filio.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "defs.h"
|
||||
#include <arpa/inet.h>
|
||||
#ifdef __STDC__
|
||||
@ -63,6 +66,9 @@
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#ifdef SUNOS5
|
||||
#include <sys/systeminfo.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */
|
||||
#define DEFAULT_RETRIES 3 /* How many times to try */
|
||||
@ -91,6 +97,8 @@ struct resp_buf {
|
||||
#define ndata u.d
|
||||
|
||||
char names[MAXHOPS][40];
|
||||
int reset[MAXHOPS]; /* To get around 3.4 bug, ... */
|
||||
int swaps[MAXHOPS]; /* To get around 3.6 bug, ... */
|
||||
|
||||
int timeout = DEFAULT_TIMEOUT;
|
||||
int nqueries = DEFAULT_RETRIES;
|
||||
@ -98,6 +106,8 @@ int numeric = FALSE;
|
||||
int debug = 0;
|
||||
int passive = FALSE;
|
||||
int multicast = FALSE;
|
||||
int statint = 10;
|
||||
int verbose = 0;
|
||||
|
||||
u_int32 defgrp; /* Default group if not specified */
|
||||
u_int32 query_cast; /* All routers multicast addr */
|
||||
@ -140,12 +150,14 @@ u_long fixtime __P((u_long time));
|
||||
int send_recv __P((u_int32 dst, int type, int code,
|
||||
int tries, struct resp_buf *save));
|
||||
char * print_host __P((u_int32 addr));
|
||||
char * print_host2 __P((u_int32 addr1, u_int32 addr2));
|
||||
void print_trace __P((int index, struct resp_buf *buf));
|
||||
int what_kind __P((struct resp_buf *buf));
|
||||
int what_kind __P((struct resp_buf *buf, char *why));
|
||||
char * scale __P((int *hop));
|
||||
void stat_line __P((struct tr_resp *r, struct tr_resp *s,
|
||||
int have_next));
|
||||
int have_next, int *res));
|
||||
void fixup_stats __P((struct resp_buf *base,
|
||||
struct resp_buf *prev,
|
||||
struct resp_buf *new));
|
||||
int print_stats __P((struct resp_buf *base,
|
||||
struct resp_buf *prev,
|
||||
@ -313,9 +325,9 @@ int
|
||||
get_ttl(buf)
|
||||
struct resp_buf *buf;
|
||||
{
|
||||
register rno;
|
||||
register struct tr_resp *b;
|
||||
register ttl;
|
||||
int rno;
|
||||
struct tr_resp *b;
|
||||
u_int ttl;
|
||||
|
||||
if (buf && (rno = buf->len) > 0) {
|
||||
b = buf->resps + rno - 1;
|
||||
@ -361,6 +373,17 @@ fixtime(time)
|
||||
return (time);
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap bytes for poor little-endian machines that don't byte-swap
|
||||
*/
|
||||
u_long
|
||||
byteswap(v)
|
||||
u_long v;
|
||||
{
|
||||
return ((v << 24) | ((v & 0xff00) << 8) |
|
||||
((v >> 8) & 0xff00) | (v >> 24));
|
||||
}
|
||||
|
||||
int
|
||||
send_recv(dst, type, code, tries, save)
|
||||
u_int32 dst;
|
||||
@ -504,11 +527,11 @@ send_recv(dst, type, code, tries, save)
|
||||
* addresses in the response.
|
||||
*/
|
||||
if (ip->ip_src.s_addr != dst) {
|
||||
register u_int32 *p = (u_int32 *)(igmp + 1);
|
||||
register u_int32 *ep = p + (len >> 2);
|
||||
u_int32 *p = (u_int32 *)(igmp + 1);
|
||||
u_int32 *ep = p + (len >> 2);
|
||||
while (p < ep) {
|
||||
register u_int32 laddr = *p++;
|
||||
register int n = ntohl(*p++) & 0xFF;
|
||||
u_int32 laddr = *p++;
|
||||
int n = ntohl(*p++) & 0xFF;
|
||||
if (laddr == dst) {
|
||||
ep = p + 1; /* ensure p < ep after loop */
|
||||
break;
|
||||
@ -586,19 +609,155 @@ send_recv(dst, type, code, tries, save)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Most of this code is duplicated elsewhere. I'm not sure if
|
||||
* the duplication is absolutely required or not.
|
||||
*
|
||||
* Ideally, this would keep track of ongoing statistics
|
||||
* collection and print out statistics. (& keep track
|
||||
* of h-b-h traces and only print the longest) For now,
|
||||
* it just snoops on what traces it can.
|
||||
*/
|
||||
void
|
||||
passive_mode()
|
||||
{
|
||||
struct timeval tr;
|
||||
struct ip *ip;
|
||||
struct igmp *igmp;
|
||||
struct tr_resp *r;
|
||||
int ipdatalen, iphdrlen, igmpdatalen;
|
||||
int len, recvlen, dummy = 0;
|
||||
u_int32 smask;
|
||||
|
||||
init_igmp();
|
||||
|
||||
if (raddr) {
|
||||
if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);
|
||||
} else k_join(htonl(0xE0000120), INADDR_ANY);
|
||||
|
||||
while (1) {
|
||||
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
|
||||
0, (struct sockaddr *)0, &dummy);
|
||||
gettimeofday(&tr,0);
|
||||
|
||||
if (recvlen <= 0) {
|
||||
if (recvlen && errno != EINTR) perror("recvfrom");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recvlen < sizeof(struct ip)) {
|
||||
fprintf(stderr,
|
||||
"packet too short (%u bytes) for IP header", recvlen);
|
||||
continue;
|
||||
}
|
||||
ip = (struct ip *) recv_buf;
|
||||
if (ip->ip_p == 0) /* ignore cache creation requests */
|
||||
continue;
|
||||
|
||||
iphdrlen = ip->ip_hl << 2;
|
||||
ipdatalen = ip->ip_len;
|
||||
if (iphdrlen + ipdatalen != recvlen) {
|
||||
fprintf(stderr,
|
||||
"packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
|
||||
recvlen, iphdrlen, ipdatalen);
|
||||
continue;
|
||||
}
|
||||
|
||||
igmp = (struct igmp *) (recv_buf + iphdrlen);
|
||||
igmpdatalen = ipdatalen - IGMP_MINLEN;
|
||||
if (igmpdatalen < 0) {
|
||||
fprintf(stderr,
|
||||
"IP data field too short (%u bytes) for IGMP from %s\n",
|
||||
ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (igmp->igmp_type) {
|
||||
|
||||
case IGMP_MTRACE: /* For backward compatibility with 3.3 */
|
||||
case IGMP_MTRACE_RESP:
|
||||
if (igmpdatalen < QLEN) continue;
|
||||
if ((igmpdatalen - QLEN)%RLEN) {
|
||||
printf("packet with incorrect datalen\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
len = (igmpdatalen - QLEN)/RLEN;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
|
||||
(tr.tv_usec << 10) / 15625;
|
||||
base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
|
||||
(tr.tv_usec << 10) / 15625;
|
||||
base.len = len;
|
||||
bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
|
||||
/*
|
||||
* If the user specified which traces to monitor,
|
||||
* only accept traces that correspond to the
|
||||
* request
|
||||
*/
|
||||
if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
|
||||
(qdst != 0 && qdst != base.qhdr.tr_dst) ||
|
||||
(qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
|
||||
continue;
|
||||
|
||||
printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
|
||||
inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),
|
||||
inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);
|
||||
if (len == 0)
|
||||
continue;
|
||||
printf(" 0 ");
|
||||
print_host(base.qhdr.tr_dst);
|
||||
printf("\n");
|
||||
print_trace(1, &base);
|
||||
r = base.resps + base.len - 1;
|
||||
VAL_TO_MASK(smask, r->tr_smask);
|
||||
if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
|
||||
printf("%3d ", -(base.len+1));
|
||||
print_host(base.qhdr.tr_src);
|
||||
printf("\n");
|
||||
} else if (r->tr_rmtaddr != 0) {
|
||||
printf("%3d ", -(base.len+1));
|
||||
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
|
||||
"doesn't support mtrace"
|
||||
: "is the next hop");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
print_host(addr)
|
||||
u_int32 addr;
|
||||
{
|
||||
return print_host2(addr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* On some routers, one interface has a name and the other doesn't.
|
||||
* We always print the address of the outgoing interface, but can
|
||||
* sometimes get the name from the incoming interface. This might be
|
||||
* confusing but should be slightly more helpful than just a "?".
|
||||
*/
|
||||
char *
|
||||
print_host2(addr1, addr2)
|
||||
u_int32 addr1, addr2;
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (numeric) {
|
||||
printf("%s", inet_fmt(addr, s1));
|
||||
printf("%s", inet_fmt(addr1, s1));
|
||||
return ("");
|
||||
}
|
||||
name = inet_name(addr);
|
||||
printf("%s (%s)", name, inet_fmt(addr, s1));
|
||||
name = inet_name(addr1);
|
||||
if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
|
||||
name = inet_name(addr2);
|
||||
printf("%s (%s)", name, inet_fmt(addr1, s1));
|
||||
return (name);
|
||||
}
|
||||
|
||||
@ -613,16 +772,22 @@ print_trace(index, buf)
|
||||
struct tr_resp *r;
|
||||
char *name;
|
||||
int i;
|
||||
int hop;
|
||||
char *ms;
|
||||
|
||||
i = abs(index);
|
||||
r = buf->resps + i - 1;
|
||||
|
||||
for (; i <= buf->len; ++i, ++r) {
|
||||
if (index > 0) printf("%3d ", -i);
|
||||
name = print_host(r->tr_outaddr);
|
||||
printf(" %s thresh^ %d %d ms %s\n", proto_type(r->tr_rproto),
|
||||
r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
|
||||
flag_type(r->tr_rflags));
|
||||
name = print_host2(r->tr_outaddr, r->tr_inaddr);
|
||||
printf(" %s thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
|
||||
if (verbose) {
|
||||
hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);
|
||||
ms = scale(&hop);
|
||||
printf(" %d%s", hop, ms);
|
||||
}
|
||||
printf(" %s\n", flag_type(r->tr_rflags));
|
||||
memcpy(names[i-1], name, sizeof(names[0]) - 1);
|
||||
names[i-1][sizeof(names[0])-1] = '\0';
|
||||
}
|
||||
@ -632,8 +797,9 @@ print_trace(index, buf)
|
||||
* See what kind of router is the next hop
|
||||
*/
|
||||
int
|
||||
what_kind(buf)
|
||||
what_kind(buf, why)
|
||||
struct resp_buf *buf;
|
||||
char *why;
|
||||
{
|
||||
u_int32 smask;
|
||||
int retval;
|
||||
@ -666,13 +832,14 @@ what_kind(buf)
|
||||
case 10:
|
||||
type = "cisco ";
|
||||
}
|
||||
printf(" [%s%d.%d] didn't respond\n",
|
||||
type, version & 0xFF, (version >> 8) & 0xFF);
|
||||
printf(" [%s%d.%d] %s\n",
|
||||
type, version & 0xFF, (version >> 8) & 0xFF,
|
||||
why);
|
||||
VAL_TO_MASK(smask, r->tr_smask);
|
||||
while (p < ep) {
|
||||
register u_int32 laddr = *p++;
|
||||
register int flags = (ntohl(*p) & 0xFF00) >> 8;
|
||||
register int n = ntohl(*p++) & 0xFF;
|
||||
u_int32 laddr = *p++;
|
||||
int flags = (ntohl(*p) & 0xFF00) >> 8;
|
||||
int n = ntohl(*p++) & 0xFF;
|
||||
if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
|
||||
(laddr & smask) == (qsrc & smask)) {
|
||||
printf("%3d ", -(hops+2));
|
||||
@ -684,7 +851,7 @@ what_kind(buf)
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
printf(" didn't respond\n");
|
||||
printf(" %s\n", why);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -708,30 +875,37 @@ scale(hop)
|
||||
#define OUTS 2
|
||||
#define BOTH 3
|
||||
void
|
||||
stat_line(r, s, have_next)
|
||||
stat_line(r, s, have_next, rst)
|
||||
struct tr_resp *r, *s;
|
||||
int have_next;
|
||||
int *rst;
|
||||
{
|
||||
register timediff = (fixtime(ntohl(s->tr_qarr)) -
|
||||
int timediff = (fixtime(ntohl(s->tr_qarr)) -
|
||||
fixtime(ntohl(r->tr_qarr))) >> 16;
|
||||
register v_lost, v_pct;
|
||||
register g_lost, g_pct;
|
||||
register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
|
||||
register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
|
||||
register v_pps, g_pps;
|
||||
int v_lost, v_pct;
|
||||
int g_lost, g_pct;
|
||||
int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
|
||||
int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
|
||||
int v_pps, g_pps;
|
||||
char v_str[8], g_str[8];
|
||||
register have = NEITHER;
|
||||
int have = NEITHER;
|
||||
int res = *rst;
|
||||
|
||||
if (timediff == 0) timediff = 1;
|
||||
v_pps = v_out / timediff;
|
||||
g_pps = g_out / timediff;
|
||||
|
||||
if (v_out || s->tr_vifout != 0xFFFFFFFF) have |= OUTS;
|
||||
if (v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
|
||||
(r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))
|
||||
have |= OUTS;
|
||||
|
||||
if (have_next) {
|
||||
--r, --s;
|
||||
if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
|
||||
--r, --s, --rst;
|
||||
if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||
|
||||
(r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))
|
||||
have |= INS;
|
||||
if (*rst)
|
||||
res = 1;
|
||||
}
|
||||
|
||||
switch (have) {
|
||||
@ -750,61 +924,129 @@ stat_line(r, s, have_next)
|
||||
sprintf(g_str, "%3d", g_pct);
|
||||
else memcpy(g_str, " --", 4);
|
||||
|
||||
printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
|
||||
v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
|
||||
if (debug > 2) {
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(s->tr_vifout));
|
||||
printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(r->tr_vifout));
|
||||
printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
|
||||
printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
|
||||
printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
|
||||
printf("time: %d\n", timediff);
|
||||
}
|
||||
printf("%6d/%-5d=%s%%%4d pps",
|
||||
v_lost, v_out, v_str, v_pps);
|
||||
if (res)
|
||||
printf("\n");
|
||||
else
|
||||
printf("%6d/%-5d=%s%%%4d pps\n",
|
||||
g_lost, g_out, g_str, g_pps);
|
||||
break;
|
||||
|
||||
case INS:
|
||||
v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
|
||||
g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
|
||||
v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
|
||||
v_pps = v_out / timediff;
|
||||
g_pps = g_out / timediff;
|
||||
/* Fall through */
|
||||
|
||||
case OUTS:
|
||||
printf(" %-5d %4d pps %-5d %4d pps\n",
|
||||
v_out, v_pps, g_out, g_pps);
|
||||
printf(" %-5d %4d pps",
|
||||
v_out, v_pps);
|
||||
if (res)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" %-5d %4d pps\n",
|
||||
g_out, g_pps);
|
||||
break;
|
||||
|
||||
case NEITHER:
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (debug > 2) {
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(s->tr_vifout));
|
||||
printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(r->tr_vifout));
|
||||
printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
|
||||
printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
|
||||
printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
|
||||
printf("time: %d\n", timediff);
|
||||
printf("\t\t\t\tres: %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A fixup to check if any pktcnt has been reset.
|
||||
* A fixup to check if any pktcnt has been reset, and to fix the
|
||||
* byteorder bugs in mrouted 3.6 on little-endian machines.
|
||||
*/
|
||||
void
|
||||
fixup_stats(base, new)
|
||||
struct resp_buf *base, *new;
|
||||
fixup_stats(base, prev, new)
|
||||
struct resp_buf *base, *prev, *new;
|
||||
{
|
||||
register rno = base->len;
|
||||
register struct tr_resp *b = base->resps + rno;
|
||||
register struct tr_resp *n = new->resps + rno;
|
||||
int rno = base->len;
|
||||
struct tr_resp *b = base->resps + rno;
|
||||
struct tr_resp *p = prev->resps + rno;
|
||||
struct tr_resp *n = new->resps + rno;
|
||||
int *r = reset + rno;
|
||||
int *s = swaps + rno;
|
||||
int res;
|
||||
|
||||
while (--rno >= 0)
|
||||
if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt)) break;
|
||||
/* Check for byte-swappers */
|
||||
while (--rno >= 0) {
|
||||
--n; --p; --b; --s;
|
||||
if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
|
||||
/* This host sends byteswapped reports; swap 'em */
|
||||
if (!*s) {
|
||||
*s = 1;
|
||||
b->tr_qarr = byteswap(b->tr_qarr);
|
||||
b->tr_vifin = byteswap(b->tr_vifin);
|
||||
b->tr_vifout = byteswap(b->tr_vifout);
|
||||
b->tr_pktcnt = byteswap(b->tr_pktcnt);
|
||||
}
|
||||
|
||||
n->tr_qarr = byteswap(n->tr_qarr);
|
||||
n->tr_vifin = byteswap(n->tr_vifin);
|
||||
n->tr_vifout = byteswap(n->tr_vifout);
|
||||
n->tr_pktcnt = byteswap(n->tr_pktcnt);
|
||||
}
|
||||
}
|
||||
|
||||
rno = base->len;
|
||||
b = base->resps + rno;
|
||||
p = prev->resps + rno;
|
||||
n = new->resps + rno;
|
||||
|
||||
while (--rno >= 0) {
|
||||
--n; --p; --b; --r;
|
||||
res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
|
||||
(ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));
|
||||
if (debug > 2)
|
||||
printf("\t\tr=%d, res=%d\n", *r, res);
|
||||
if (*r) {
|
||||
if (res || *r > 1) {
|
||||
/*
|
||||
* This router appears to be a 3.4 with that nasty ol'
|
||||
* neighbor version bug, which causes it to constantly
|
||||
* reset. Just nuke the statistics for this node, and
|
||||
* don't even bother giving it the benefit of the
|
||||
* doubt from now on.
|
||||
*/
|
||||
p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
|
||||
*r++;
|
||||
} else {
|
||||
/*
|
||||
* This is simply the situation that the original
|
||||
* fixup_stats was meant to deal with -- that a
|
||||
* 3.3 or 3.4 router deleted a cache entry while
|
||||
* traffic was still active.
|
||||
*/
|
||||
*r = 0;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
*r = res;
|
||||
}
|
||||
|
||||
if (rno < 0) return;
|
||||
|
||||
rno = base->len;
|
||||
b = base->resps + rno;
|
||||
n = new->resps + rno;
|
||||
p = prev->resps + rno;
|
||||
|
||||
while (--rno >= 0) (--b)->tr_pktcnt = (--n)->tr_pktcnt;
|
||||
while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -815,15 +1057,17 @@ print_stats(base, prev, new)
|
||||
struct resp_buf *base, *prev, *new;
|
||||
{
|
||||
int rtt, hop;
|
||||
register char *ms;
|
||||
register u_int32 smask;
|
||||
register rno = base->len - 1;
|
||||
register struct tr_resp *b = base->resps + rno;
|
||||
register struct tr_resp *p = prev->resps + rno;
|
||||
register struct tr_resp *n = new->resps + rno;
|
||||
register u_long resptime = new->rtime;
|
||||
register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
|
||||
register ttl = n->tr_fttl;
|
||||
char *ms;
|
||||
u_int32 smask;
|
||||
int rno = base->len - 1;
|
||||
struct tr_resp *b = base->resps + rno;
|
||||
struct tr_resp *p = prev->resps + rno;
|
||||
struct tr_resp *n = new->resps + rno;
|
||||
int *r = reset + rno;
|
||||
u_long resptime = new->rtime;
|
||||
u_long qarrtime = fixtime(ntohl(n->tr_qarr));
|
||||
u_int ttl = n->tr_fttl;
|
||||
int first = (base == prev);
|
||||
|
||||
VAL_TO_MASK(smask, b->tr_smask);
|
||||
printf(" Source Response Dest");
|
||||
@ -833,12 +1077,14 @@ print_stats(base, prev, new)
|
||||
inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
|
||||
rtt = t_diff(resptime, new->qtime);
|
||||
ms = scale(&rtt);
|
||||
printf(" | __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
|
||||
rtt, ms, inet_fmt(qgrp, s2));
|
||||
hop = t_diff(resptime, qarrtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v / hop%5d%s", hop, ms);
|
||||
printf(" --------------------- --------------------\n");
|
||||
printf(" %c __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
|
||||
first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));
|
||||
if (!first) {
|
||||
hop = t_diff(resptime, qarrtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v / hop%5d%s", hop, ms);
|
||||
printf(" --------------------- --------------------\n");
|
||||
}
|
||||
if (debug > 2) {
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(n->tr_vifout));
|
||||
@ -849,6 +1095,7 @@ print_stats(base, prev, new)
|
||||
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
|
||||
printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
|
||||
printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
|
||||
printf("\t\t\t\treset: %d\n", *r);
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
@ -862,28 +1109,30 @@ print_stats(base, prev, new)
|
||||
|
||||
if (rno-- < 1) break;
|
||||
|
||||
printf(" | ^ ttl%5d ", ttl);
|
||||
if (prev == new) printf("\n");
|
||||
else stat_line(p, n, TRUE);
|
||||
resptime = qarrtime;
|
||||
qarrtime = fixtime(ntohl((n-1)->tr_qarr));
|
||||
hop = t_diff(resptime, qarrtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v | hop%5d%s", hop, ms);
|
||||
stat_line(b, n, TRUE);
|
||||
printf(" %c ^ ttl%5d ", first ? 'v' : '|', ttl);
|
||||
stat_line(p, n, TRUE, r);
|
||||
if (!first) {
|
||||
resptime = qarrtime;
|
||||
qarrtime = fixtime(ntohl((n-1)->tr_qarr));
|
||||
hop = t_diff(resptime, qarrtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v | hop%5d%s", hop, ms);
|
||||
stat_line(b, n, TRUE, r);
|
||||
}
|
||||
|
||||
--b, --p, --n;
|
||||
--b, --p, --n, --r;
|
||||
if (ttl < n->tr_fttl) ttl = n->tr_fttl;
|
||||
else ++ttl;
|
||||
}
|
||||
|
||||
printf(" | \\__ ttl%5d ", ttl);
|
||||
if (prev == new) printf("\n");
|
||||
else stat_line(p, n, FALSE);
|
||||
hop = t_diff(qarrtime, new->qtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v \\ hop%5d%s", hop, ms);
|
||||
stat_line(b, n, FALSE);
|
||||
printf(" %c \\__ ttl%5d ", first ? 'v' : '|', ttl);
|
||||
stat_line(p, n, FALSE, r);
|
||||
if (!first) {
|
||||
hop = t_diff(qarrtime, new->qtime);
|
||||
ms = scale(&hop);
|
||||
printf(" v \\ hop%5d%s", hop, ms);
|
||||
stat_line(b, n, FALSE, r);
|
||||
}
|
||||
printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
|
||||
printf(" Receiver Query Source\n\n");
|
||||
return 0;
|
||||
@ -923,11 +1172,11 @@ char *argv[];
|
||||
if (argc == 0) goto usage;
|
||||
|
||||
while (argc > 0 && *argv[0] == '-') {
|
||||
register char *p = *argv++; argc--;
|
||||
char *p = *argv++; argc--;
|
||||
p++;
|
||||
do {
|
||||
register char c = *p++;
|
||||
register char *arg = (char *) 0;
|
||||
char c = *p++;
|
||||
char *arg = (char *) 0;
|
||||
if (isdigit(*p)) {
|
||||
arg = p;
|
||||
p = "";
|
||||
@ -954,6 +1203,9 @@ char *argv[];
|
||||
case 'p': /* Passive listen for traces */
|
||||
passive = TRUE;
|
||||
break;
|
||||
case 'v': /* Verbosity */
|
||||
verbose = TRUE;
|
||||
break;
|
||||
case 's': /* Short form, don't wait for stats */
|
||||
numstats = 0;
|
||||
break;
|
||||
@ -1009,6 +1261,14 @@ char *argv[];
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
case 'S': /* Stat accumulation interval */
|
||||
if (arg && isdigit(*arg)) {
|
||||
statint = atoi(arg);
|
||||
if (statint < 1) statint = 1;
|
||||
if (arg == argv[0]) argv++, argc--;
|
||||
break;
|
||||
} else
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
@ -1032,10 +1292,15 @@ char *argv[];
|
||||
}
|
||||
}
|
||||
|
||||
if (passive) {
|
||||
passive_mode();
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (argc > 0 || qsrc == 0) {
|
||||
usage: printf("\
|
||||
Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
[-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
|
||||
[-S statint] [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -1067,6 +1332,36 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef SUNOS5
|
||||
/*
|
||||
* SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
|
||||
* This call to sysinfo will return the hostname.
|
||||
* If the default multicast interfface (set with the route
|
||||
* for 224.0.0.0) is not the same as the hostname,
|
||||
* mtrace -i [if_addr] will have to be used.
|
||||
*/
|
||||
if (addr.sin_addr.s_addr == 0) {
|
||||
char myhostname[MAXHOSTNAMELEN];
|
||||
struct hostent *hp;
|
||||
int error;
|
||||
|
||||
error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
|
||||
if (error == -1) {
|
||||
perror("Getting my hostname");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
hp = gethostbyname(myhostname);
|
||||
if (hp == NULL || hp->h_addrtype != AF_INET ||
|
||||
hp->h_length != sizeof(addr.sin_addr)) {
|
||||
perror("Finding IP address for my hostname");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default destination for path to be queried is the local host.
|
||||
*/
|
||||
@ -1136,7 +1431,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
}
|
||||
|
||||
/*
|
||||
* Try a query at the requested number of hops or MAXOPS if unspecified.
|
||||
* Try a query at the requested number of hops or MAXHOPS if unspecified.
|
||||
*/
|
||||
if (qno == 0) {
|
||||
hops = MAXHOPS;
|
||||
@ -1148,7 +1443,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
tries = nqueries;
|
||||
printf("Querying reverse path, maximum %d hops... ", qno);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
base.rtime = 0;
|
||||
base.len = 0;
|
||||
|
||||
@ -1167,9 +1462,12 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
printf("\n");
|
||||
print_trace(1, &base);
|
||||
r = base.resps + base.len - 1;
|
||||
if (r->tr_rflags == TR_OLD_ROUTER) {
|
||||
if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
|
||||
qno != 0) {
|
||||
printf("%3d ", -(base.len+1));
|
||||
what_kind(&base);
|
||||
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
|
||||
"doesn't support mtrace"
|
||||
: "is the next hop");
|
||||
} else {
|
||||
VAL_TO_MASK(smask, r->tr_smask);
|
||||
if ((r->tr_inaddr & smask) == (qsrc & smask)) {
|
||||
@ -1204,7 +1502,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
if (recvlen == 0) {
|
||||
if (hops == 1) break;
|
||||
if (hops == nexthop) {
|
||||
if (what_kind(&base)) {
|
||||
if (what_kind(&base, "didn't respond")) {
|
||||
/* the ask_neighbors determined that the
|
||||
* not-responding router is the first-hop. */
|
||||
break;
|
||||
@ -1227,36 +1525,62 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
|
||||
print_trace(nexthop, &base);
|
||||
}
|
||||
} else {
|
||||
if (base.len == hops - 1) {
|
||||
if (base.len < hops) {
|
||||
/*
|
||||
* A shorter trace than requested means a fatal error
|
||||
* occurred along the path, or that the route changed
|
||||
* to a shorter one.
|
||||
*
|
||||
* If the trace is longer than the last one we received,
|
||||
* then we are resuming from a skipped router (but there
|
||||
* is still probably a problem).
|
||||
*
|
||||
* If the trace is shorter than the last one we
|
||||
* received, then the route must have changed (and
|
||||
* there is still probably a problem).
|
||||
*/
|
||||
if (nexthop <= base.len) {
|
||||
printf("\nResuming...\n");
|
||||
print_trace(nexthop, &base);
|
||||
} else if (nexthop > base.len + 1) {
|
||||
hops = base.len;
|
||||
printf("\nRoute must have changed...\n");
|
||||
print_trace(1, &base);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The last hop address is not the same as it was;
|
||||
* the route probably changed underneath us.
|
||||
*/
|
||||
hops = base.len;
|
||||
printf("\nRoute must have changed...\n");
|
||||
print_trace(1, &base);
|
||||
}
|
||||
if (r->tr_rflags == TR_OLD_ROUTER) {
|
||||
what_kind(&base);
|
||||
break;
|
||||
}
|
||||
if (r->tr_rflags == TR_NO_SPACE) {
|
||||
printf("No space left in trace packet for more hops\n");
|
||||
break; /* XXX could do segmented trace */
|
||||
}
|
||||
}
|
||||
lastout = r->tr_outaddr;
|
||||
nexthop = hops + 1;
|
||||
|
||||
VAL_TO_MASK(smask, r->tr_smask);
|
||||
if ((r->tr_inaddr & smask) == (qsrc & smask)) {
|
||||
printf("%3d ", -nexthop);
|
||||
print_host(qsrc);
|
||||
printf("\n");
|
||||
if (base.len < hops ||
|
||||
r->tr_rmtaddr == 0 ||
|
||||
(r->tr_rflags & 0x80)) {
|
||||
VAL_TO_MASK(smask, r->tr_smask);
|
||||
if (r->tr_rmtaddr) {
|
||||
if (hops != nexthop) {
|
||||
printf("\n%3d ", -(base.len+1));
|
||||
}
|
||||
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
|
||||
"doesn't support mtrace" :
|
||||
"would be the next hop");
|
||||
/* XXX could do segmented trace if TR_NO_SPACE */
|
||||
} else if (r->tr_rflags == TR_NO_ERR &&
|
||||
(r->tr_inaddr & smask) == (qsrc & smask)) {
|
||||
printf("%3d ", -(hops + 1));
|
||||
print_host(qsrc);
|
||||
printf("\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80)) break;
|
||||
|
||||
nexthop = hops + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1284,8 +1608,9 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
|
||||
raddr = base.qhdr.tr_raddr;
|
||||
rttl = base.qhdr.tr_rttl;
|
||||
gettimeofday(&tv, 0);
|
||||
waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
|
||||
prev = new = &incr[numstats&1];
|
||||
waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
|
||||
prev = &base;
|
||||
new = &incr[numstats&1];
|
||||
|
||||
while (numstats--) {
|
||||
if (waittime < 1) printf("\n");
|
||||
@ -1304,14 +1629,23 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
|
||||
|
||||
if (rno != new->len) {
|
||||
printf("Trace length doesn't match:\n");
|
||||
/*
|
||||
* XXX Should this trace result be printed, or is that
|
||||
* too verbose? Perhaps it should just say restarting.
|
||||
* But if the path is changing quickly, this may be the
|
||||
* only snapshot of the current path. But, if the path
|
||||
* is changing that quickly, does the current path really
|
||||
* matter?
|
||||
*/
|
||||
print_trace(1, new);
|
||||
printf("Restarting.\n\n");
|
||||
numstats++;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
printf("Results after %d seconds:\n\n",
|
||||
(int)((new->qtime - base.qtime) >> 16));
|
||||
fixup_stats(&base, new);
|
||||
fixup_stats(&base, prev, new);
|
||||
if (print_stats(&base, prev, new)) {
|
||||
printf("Route changed:\n");
|
||||
print_trace(1, new);
|
||||
@ -1320,7 +1654,7 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
|
||||
}
|
||||
prev = new;
|
||||
new = &incr[numstats&1];
|
||||
waittime = 10;
|
||||
waittime = statint;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1461,3 +1795,15 @@ void accept_neighbors2(src, dst, p, datalen, level)
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
void accept_info_request(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
void accept_info_reply(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: pathnames.h,v 3.6 1995/06/25 19:17:45 fenner Exp $
|
||||
* $Id: pathnames.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: prune.c,v 3.6 1995/06/25 19:18:43 fenner Exp $
|
||||
* $Id: prune.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -55,6 +55,7 @@ static void prun_add_ttls __P((struct gtable *gt));
|
||||
static int pruning_neighbor __P((vifi_t vifi, u_int32 addr));
|
||||
static int can_mtrace __P((vifi_t vifi, u_int32 addr));
|
||||
static struct ptable * find_prune_entry __P((u_int32 vr, struct ptable *pt));
|
||||
static void expire_prune __P((vifi_t vifi, struct gtable *gt));
|
||||
static void send_prune __P((struct gtable *gt));
|
||||
static void send_graft __P((struct gtable *gt));
|
||||
static void send_graft_ack __P((u_int32 src, u_int32 dst,
|
||||
@ -84,7 +85,7 @@ prun_add_ttls(gt)
|
||||
* checks for scoped multicast addresses
|
||||
*/
|
||||
#define GET_SCOPE(gt) { \
|
||||
register int _i; \
|
||||
register vifi_t _i; \
|
||||
if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
|
||||
for (_i = 0; _i < numvifs; _i++) \
|
||||
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
|
||||
@ -633,7 +634,11 @@ add_table_entry(origin, mcastgrp)
|
||||
struct rtentry *r;
|
||||
struct gtable *gt,**gtnp,*prev_gt;
|
||||
struct stable *st,**stnp;
|
||||
int i;
|
||||
vifi_t i;
|
||||
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_MISS, origin, mcastgrp);
|
||||
#endif
|
||||
|
||||
r = determine_route(origin);
|
||||
prev_gt = NULL;
|
||||
@ -727,7 +732,7 @@ add_table_entry(origin, mcastgrp)
|
||||
gt->gt_gnext->gt_gprev = gt;
|
||||
}
|
||||
} else {
|
||||
gt->gt_gnext = gt->gt_prev = NULL;
|
||||
gt->gt_gnext = gt->gt_gprev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -748,8 +753,14 @@ add_table_entry(origin, mcastgrp)
|
||||
st->st_next = *stnp;
|
||||
*stnp = st;
|
||||
} else {
|
||||
#ifdef DEBUG_MFC
|
||||
md_log(MD_DUPE, origin, mcastgrp);
|
||||
#endif
|
||||
log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
|
||||
inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
|
||||
/* XXX Doing this should cause no harm, and may ensure
|
||||
* kernel<>mrouted synchronization */
|
||||
k_add_rg(origin, gt);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -780,60 +791,31 @@ reset_neighbor_state(vifi, addr)
|
||||
{
|
||||
struct rtentry *r;
|
||||
struct gtable *g;
|
||||
struct ptable *pt, *prev_pt;
|
||||
struct stable *st, *prev_st;
|
||||
struct ptable *pt, **ptnp;
|
||||
struct stable *st;
|
||||
|
||||
for (g = kernel_table; g; g = g->gt_gnext) {
|
||||
r = g->gt_route;
|
||||
|
||||
/*
|
||||
* If neighbor was the parent, remove the prune sent state
|
||||
* Don't send any grafts upstream.
|
||||
* and all of the source cache info so that prunes get
|
||||
* regenerated.
|
||||
*/
|
||||
if (vifi == r->rt_parent) {
|
||||
if (addr == r->rt_gateway) {
|
||||
log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
|
||||
log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
|
||||
inet_fmts(r->rt_origin, r->rt_originmask, s1),
|
||||
inet_fmt(g->gt_mcastgrp, s2));
|
||||
|
||||
pt = g->gt_pruntbl;
|
||||
while (pt) {
|
||||
/*
|
||||
* Expire prune, send again on this vif.
|
||||
*/
|
||||
VIFM_SET(pt->pt_vifi, g->gt_grpmems);
|
||||
prev_pt = pt;
|
||||
pt = prev_pt->pt_next;
|
||||
free(prev_pt);
|
||||
}
|
||||
g->gt_pruntbl = NULL;
|
||||
|
||||
st = g->gt_srctbl;
|
||||
while (st) {
|
||||
log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(g->gt_mcastgrp, s2));
|
||||
|
||||
if (k_del_rg(st->st_origin, g) < 0) {
|
||||
log(LOG_WARNING, errno,
|
||||
"reset_neighbor_state trying to delete (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(g->gt_mcastgrp, s2));
|
||||
}
|
||||
kroutes--;
|
||||
prev_st = st;
|
||||
st = prev_st->st_next;
|
||||
free(prev_st);
|
||||
}
|
||||
g->gt_srctbl = NULL;
|
||||
/*
|
||||
* Keep the group entries themselves around since the
|
||||
* state will likely just come right back, and if not,
|
||||
* the group entries will time out with no kernel entries
|
||||
* and no prune state.
|
||||
*/
|
||||
g->gt_prsent_timer = 0;
|
||||
g->gt_grftsnt = 0;
|
||||
while (st = g->gt_srctbl) {
|
||||
g->gt_srctbl = st->st_next;
|
||||
k_del_rg(st->st_origin, g);
|
||||
kroutes--;
|
||||
free(st);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -848,13 +830,13 @@ reset_neighbor_state(vifi, addr)
|
||||
/*
|
||||
* Remove any prunes that this router has sent us.
|
||||
*/
|
||||
prev_pt = (struct ptable *)&g->gt_pruntbl;
|
||||
for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
|
||||
ptnp = &g->gt_pruntbl;
|
||||
while ((pt = *ptnp) != NULL) {
|
||||
if (pt->pt_vifi == vifi && pt->pt_router == addr) {
|
||||
prev_pt->pt_next = pt->pt_next;
|
||||
*ptnp = pt->pt_next;
|
||||
free(pt);
|
||||
} else
|
||||
prev_pt = pt;
|
||||
ptnp = &pt->pt_next;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -924,9 +906,9 @@ del_table_entry(r, mcastgrp, del_flag)
|
||||
|
||||
pt = g->gt_pruntbl;
|
||||
while (pt) {
|
||||
prev_pt = pt->pt_next;
|
||||
free(pt);
|
||||
pt = prev_pt;
|
||||
prev_pt = pt;
|
||||
pt = pt->pt_next;
|
||||
free(prev_pt);
|
||||
}
|
||||
g->gt_pruntbl = NULL;
|
||||
|
||||
@ -937,14 +919,14 @@ del_table_entry(r, mcastgrp, del_flag)
|
||||
else
|
||||
kernel_table = g->gt_gnext;
|
||||
|
||||
prev_g = g->gt_next;
|
||||
#ifdef RSRR
|
||||
/* Send route change notification to reservation protocol. */
|
||||
rsrr_cache_send(g,0);
|
||||
rsrr_cache_clean(g);
|
||||
#endif /* RSRR */
|
||||
free(g);
|
||||
g = prev_g;
|
||||
prev_g = g;
|
||||
g = g->gt_next;
|
||||
free(prev_g);
|
||||
}
|
||||
r->rt_groups = NULL;
|
||||
}
|
||||
@ -968,17 +950,17 @@ del_table_entry(r, mcastgrp, del_flag)
|
||||
inet_fmt(g->gt_mcastgrp, s2));
|
||||
}
|
||||
kroutes--;
|
||||
prev_st = st->st_next;
|
||||
free(st);
|
||||
st = prev_st;
|
||||
prev_st = st;
|
||||
st = st->st_next;
|
||||
free(prev_st);
|
||||
}
|
||||
g->gt_srctbl = NULL;
|
||||
|
||||
pt = g->gt_pruntbl;
|
||||
while (pt) {
|
||||
prev_pt = pt->pt_next;
|
||||
free(pt);
|
||||
pt = prev_pt;
|
||||
prev_pt = pt;
|
||||
pt = pt->pt_next;
|
||||
free(prev_pt);
|
||||
}
|
||||
g->gt_pruntbl = NULL;
|
||||
|
||||
@ -1018,7 +1000,7 @@ update_table_entry(r)
|
||||
{
|
||||
struct gtable *g;
|
||||
struct ptable *pt, *prev_pt;
|
||||
int i;
|
||||
vifi_t i;
|
||||
|
||||
for (g = r->rt_groups; g; g = g->gt_next) {
|
||||
pt = g->gt_pruntbl;
|
||||
@ -1282,7 +1264,7 @@ accept_prune(src, dst, p, datalen)
|
||||
g->gt_timer = CACHE_LIFETIME(cache_lifetime);
|
||||
if (g->gt_timer < prun_tmr)
|
||||
g->gt_timer = prun_tmr;
|
||||
|
||||
|
||||
/*
|
||||
* check if any more packets need to be sent on the
|
||||
* vif which sent this message
|
||||
@ -1580,21 +1562,21 @@ free_all_prunes()
|
||||
while (g) {
|
||||
s = g->gt_srctbl;
|
||||
while (s) {
|
||||
prev_s = s->st_next;
|
||||
free(s);
|
||||
s = prev_s;
|
||||
prev_s = s;
|
||||
s = s->st_next;
|
||||
free(prev_s);
|
||||
}
|
||||
|
||||
p = g->gt_pruntbl;
|
||||
while (p) {
|
||||
prev_p = p->pt_next;
|
||||
free(p);
|
||||
p = prev_p;
|
||||
prev_p = p;
|
||||
p = p->pt_next;
|
||||
free(prev_p);
|
||||
}
|
||||
|
||||
prev_g = g->gt_next;
|
||||
free(g);
|
||||
g = prev_g;
|
||||
prev_g = g;
|
||||
g = g->gt_next;
|
||||
free(prev_g);
|
||||
}
|
||||
r->rt_groups = NULL;
|
||||
}
|
||||
@ -1605,9 +1587,9 @@ free_all_prunes()
|
||||
if (g->gt_srctbl)
|
||||
free(g->gt_srctbl);
|
||||
|
||||
prev_g = g->gt_next;
|
||||
free(g);
|
||||
g = prev_g;
|
||||
prev_g = g;
|
||||
g = g->gt_next;
|
||||
free(prev_g);
|
||||
}
|
||||
kernel_no_route = NULL;
|
||||
}
|
||||
@ -1742,34 +1724,8 @@ age_table_entry()
|
||||
inet_fmt(gt->gt_mcastgrp, s2),
|
||||
inet_fmt(pt->pt_router, s3),
|
||||
pt->pt_vifi);
|
||||
|
||||
/*
|
||||
* No need to send a graft, any prunes that we sent
|
||||
* will expire before any prunes that we have received.
|
||||
*/
|
||||
if (gt->gt_prsent_timer > 0) {
|
||||
log(LOG_DEBUG, 0, "prune expired with %d left on %s",
|
||||
gt->gt_prsent_timer, "prsent_timer");
|
||||
gt->gt_prsent_timer = 0;
|
||||
}
|
||||
|
||||
/* modify the kernel entry to forward packets */
|
||||
if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
|
||||
VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
|
||||
log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
|
||||
inet_fmts(r->rt_origin, r->rt_originmask, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
|
||||
pt->pt_vifi);
|
||||
|
||||
prun_add_ttls(gt);
|
||||
update_kernel(gt);
|
||||
#ifdef RSRR
|
||||
/* Send route change notification to reservation
|
||||
* protocol.
|
||||
*/
|
||||
rsrr_cache_send(gt,1);
|
||||
#endif /* RSRR */
|
||||
}
|
||||
expire_prune(pt->pt_vifi, gt);
|
||||
|
||||
/* remove the router's prune entry and await new one */
|
||||
*ptnp = pt->pt_next;
|
||||
@ -1780,94 +1736,65 @@ age_table_entry()
|
||||
}
|
||||
|
||||
/*
|
||||
* If the cache entry has expired, check for downstream prunes.
|
||||
*
|
||||
* If there are downstream prunes, refresh the cache entry's timer.
|
||||
* Otherwise, check for traffic. If no traffic, delete this
|
||||
* entry.
|
||||
* If the cache entry has expired, delete source table entries for
|
||||
* silent sources. If there are no source entries left, and there
|
||||
* are no downstream prunes, then the entry is deleted.
|
||||
* Otherwise, the cache entry's timer is refreshed.
|
||||
*/
|
||||
if (gt->gt_timer <= 0) {
|
||||
if (gt->gt_pruntbl) {
|
||||
if (gt->gt_prsent_timer == -1)
|
||||
gt->gt_prsent_timer = 0;
|
||||
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
|
||||
gtnptr = >->gt_gnext;
|
||||
continue;
|
||||
/* Check for traffic before deleting source entries */
|
||||
sg_req.grp.s_addr = gt->gt_mcastgrp;
|
||||
stnp = >->gt_srctbl;
|
||||
while ((st = *stnp) != NULL) {
|
||||
sg_req.src.s_addr = st->st_origin;
|
||||
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
|
||||
log(LOG_WARNING, errno, "%s (%s %s)",
|
||||
"age_table_entry: SIOCGETSGCNT failing for",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
/* Make sure it gets deleted below */
|
||||
sg_req.pktcnt = st->st_pktcnt;
|
||||
}
|
||||
if (sg_req.pktcnt == st->st_pktcnt) {
|
||||
*stnp = st->st_next;
|
||||
log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
if (k_del_rg(st->st_origin, gt) < 0) {
|
||||
log(LOG_WARNING, errno,
|
||||
"age_table_entry trying to delete (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
}
|
||||
kroutes--;
|
||||
free(st);
|
||||
} else {
|
||||
st->st_pktcnt = sg_req.pktcnt;
|
||||
stnp = &st->st_next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this entry was pruned, but all downstream prunes
|
||||
* have expired, then it is safe to simply delete it.
|
||||
* Otherwise, check for traffic before deleting.
|
||||
* Retain the group entry if we have downstream prunes or if
|
||||
* there is at least one source in the list that still has
|
||||
* traffic, or if our upstream prune timer is running.
|
||||
*/
|
||||
if (gt->gt_prsent_timer == 0) {
|
||||
sg_req.grp.s_addr = gt->gt_mcastgrp;
|
||||
stnp = >->gt_srctbl;
|
||||
while ((st = *stnp) != NULL) {
|
||||
sg_req.src.s_addr = st->st_origin;
|
||||
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req)
|
||||
< 0) {
|
||||
log(LOG_WARNING, errno, "%s (%s %s)",
|
||||
"age_table_entry: SIOCGETSGCNT failing for",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
/* Make sure it gets deleted below */
|
||||
sg_req.pktcnt = st->st_pktcnt;
|
||||
}
|
||||
if (sg_req.pktcnt == st->st_pktcnt) {
|
||||
*stnp = st->st_next;
|
||||
log(LOG_DEBUG, 0,
|
||||
"age_table_entry deleting (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
if (k_del_rg(st->st_origin, gt) < 0) {
|
||||
log(LOG_WARNING, errno,
|
||||
"age_table_entry trying to delete (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
}
|
||||
kroutes--;
|
||||
free(st);
|
||||
} else {
|
||||
stnp = &st->st_next;
|
||||
}
|
||||
}
|
||||
|
||||
if (gt->gt_srctbl) {
|
||||
/* At least one source in the list still has traffic */
|
||||
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
|
||||
gtnptr = >->gt_gnext;
|
||||
continue;
|
||||
}
|
||||
if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
|
||||
gt->gt_prsent_timer > 0) {
|
||||
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
|
||||
if (gt->gt_prsent_timer == -1)
|
||||
if (gt->gt_grpmems == 0)
|
||||
send_prune(gt);
|
||||
else
|
||||
gt->gt_prsent_timer = 0;
|
||||
gtnptr = >->gt_gnext;
|
||||
continue;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
|
||||
inet_fmts(r->rt_origin, r->rt_originmask, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
|
||||
/* free all the source entries */
|
||||
while ((st = gt->gt_srctbl) != NULL) {
|
||||
log(LOG_DEBUG, 0,
|
||||
"age_table_entry (P) deleting (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
if (k_del_rg(st->st_origin, gt) < 0) {
|
||||
log(LOG_WARNING, errno,
|
||||
"age_table_entry (P) trying to delete (%s %s)",
|
||||
inet_fmt(st->st_origin, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2));
|
||||
}
|
||||
kroutes--;
|
||||
gt->gt_srctbl = st->st_next;
|
||||
free(st);
|
||||
}
|
||||
|
||||
/* free all the prune list entries */
|
||||
while ((pt = gt->gt_pruntbl) != NULL) {
|
||||
gt->gt_pruntbl = pt->pt_next;
|
||||
free(pt);
|
||||
}
|
||||
|
||||
if (gt->gt_prev)
|
||||
gt->gt_prev->gt_next = gt->gt_next;
|
||||
else
|
||||
@ -1893,7 +1820,10 @@ age_table_entry()
|
||||
free((char *)gt);
|
||||
} else {
|
||||
if (gt->gt_prsent_timer == -1)
|
||||
gt->gt_prsent_timer = 0;
|
||||
if (gt->gt_grpmems == 0)
|
||||
send_prune(gt);
|
||||
else
|
||||
gt->gt_prsent_timer = 0;
|
||||
gtnptr = >->gt_gnext;
|
||||
}
|
||||
}
|
||||
@ -1928,6 +1858,44 @@ age_table_entry()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the kernel to forward packets when one or multiple prunes that
|
||||
* were received on the vif given by vifi, for the group given by gt,
|
||||
* have expired.
|
||||
*/
|
||||
static void
|
||||
expire_prune(vifi, gt)
|
||||
vifi_t vifi;
|
||||
struct gtable *gt;
|
||||
{
|
||||
/*
|
||||
* No need to send a graft, any prunes that we sent
|
||||
* will expire before any prunes that we have received.
|
||||
*/
|
||||
if (gt->gt_prsent_timer > 0) {
|
||||
log(LOG_DEBUG, 0, "prune expired with %d left on %s",
|
||||
gt->gt_prsent_timer, "prsent_timer");
|
||||
gt->gt_prsent_timer = 0;
|
||||
}
|
||||
|
||||
/* modify the kernel entry to forward packets */
|
||||
if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
|
||||
struct rtentry *rt = gt->gt_route;
|
||||
VIFM_SET(vifi, gt->gt_grpmems);
|
||||
log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
|
||||
inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
|
||||
inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
|
||||
|
||||
prun_add_ttls(gt);
|
||||
update_kernel(gt);
|
||||
#ifdef RSRR
|
||||
/* Send route change notification to reservation protocol. */
|
||||
rsrr_cache_send(gt,1);
|
||||
#endif /* RSRR */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
scaletime(t)
|
||||
u_long t;
|
||||
@ -1978,7 +1946,7 @@ dump_cache(fp2)
|
||||
register struct gtable *gt;
|
||||
register struct stable *st;
|
||||
register struct ptable *pt;
|
||||
register int i;
|
||||
register vifi_t i;
|
||||
register time_t thyme = time(0);
|
||||
|
||||
fprintf(fp2,
|
||||
@ -2091,21 +2059,6 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
|
||||
qry = (struct tr_query *)data;
|
||||
|
||||
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.
|
||||
*/
|
||||
log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if it is a packet with all reports filled, drop it
|
||||
*/
|
||||
@ -2136,6 +2089,21 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
* 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.
|
||||
*/
|
||||
log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt == NULL) {
|
||||
log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
|
||||
inet_fmt(qry->tr_src, s1));
|
||||
@ -2201,7 +2169,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
bzero(resp, sizeof(struct tr_resp));
|
||||
datalen += RLEN;
|
||||
|
||||
resp->tr_qarr = ((tp.tv_sec + JAN_1970) << 16) +
|
||||
resp->tr_qarr = htonl((tp.tv_sec + JAN_1970) << 16) +
|
||||
((tp.tv_usec >> 4) & 0xffff);
|
||||
|
||||
resp->tr_rproto = PROTO_DVMRP;
|
||||
@ -2219,7 +2187,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
*/
|
||||
v_req.vifi = vifi;
|
||||
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
|
||||
resp->tr_vifout = v_req.ocount;
|
||||
resp->tr_vifout = htonl(v_req.ocount);
|
||||
|
||||
/*
|
||||
* fill in scoping & pruning information
|
||||
@ -2236,7 +2204,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
sg_req.src.s_addr = qry->tr_src;
|
||||
sg_req.grp.s_addr = group;
|
||||
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
|
||||
resp->tr_pktcnt = sg_req.pktcnt;
|
||||
resp->tr_pktcnt = htonl(sg_req.pktcnt);
|
||||
|
||||
if (VIFM_ISSET(vifi, gt->gt_scope))
|
||||
resp->tr_rflags = TR_SCOPED;
|
||||
@ -2267,7 +2235,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
|
||||
/* get # of packets in on interface */
|
||||
v_req.vifi = rt->rt_parent;
|
||||
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
|
||||
resp->tr_vifin = v_req.icount;
|
||||
resp->tr_vifin = htonl(v_req.icount);
|
||||
|
||||
MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
|
||||
src = uvifs[rt->rt_parent].uv_lcl_addr;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: prune.h,v 3.6 1995/06/25 19:19:04 fenner Exp $
|
||||
* $Id: prune.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: route.c,v 3.6 1995/06/25 19:20:19 fenner Exp $
|
||||
* $Id: route.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
@ -353,12 +353,12 @@ discard_route(prev_r)
|
||||
void
|
||||
update_route(origin, mask, metric, src, vifi)
|
||||
u_int32 origin, mask;
|
||||
int metric;
|
||||
u_int metric;
|
||||
u_int32 src;
|
||||
vifi_t vifi;
|
||||
{
|
||||
register struct rtentry *r;
|
||||
int adj_metric;
|
||||
u_int adj_metric;
|
||||
|
||||
/*
|
||||
* Compute an adjusted metric, taking into account the cost of the
|
||||
@ -462,7 +462,8 @@ update_route(origin, mask, metric, src, vifi)
|
||||
(r->rt_gateway != 0 &&
|
||||
(adj_metric < r->rt_metric ||
|
||||
(adj_metric == r->rt_metric &&
|
||||
r->rt_timer >= ROUTE_SWITCH_TIME)))) {
|
||||
(ntohl(src) < ntohl(r->rt_gateway) ||
|
||||
r->rt_timer >= ROUTE_SWITCH_TIME))))) {
|
||||
/*
|
||||
* The report is for an origin we consider reachable; the report
|
||||
* comes either from one of our own interfaces or from a gateway
|
||||
@ -473,10 +474,15 @@ update_route(origin, mask, metric, src, vifi)
|
||||
* what our routing entry says, update the entry to use the new
|
||||
* gateway and metric. We also switch gateways if the reported
|
||||
* metric is the same as the one in the route entry and the gateway
|
||||
* associated with the route entry has not been heard from recently.
|
||||
* associated with the route entry has not been heard from recently,
|
||||
* or if the metric is the same but the reporting gateway has a lower
|
||||
* IP address than the gateway associated with the route entry.
|
||||
* Did you get all that?
|
||||
*/
|
||||
if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
|
||||
/*
|
||||
* XXX Why do we do this if we are just changing the metric?
|
||||
*/
|
||||
r->rt_parent = vifi;
|
||||
if (init_children_and_leaves(r, vifi)) {
|
||||
update_table_entry(r);
|
||||
@ -785,6 +791,12 @@ accept_report(src, dst, p, datalen, level)
|
||||
if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
|
||||
if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
|
||||
if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
|
||||
if (!inet_valid_mask(ntohl(mask))) {
|
||||
log(LOG_WARNING, 0,
|
||||
"%s reports bogus netmask 0x%08x (%s)",
|
||||
inet_fmt(src, s1), ntohl(mask), inet_fmt(mask, s2));
|
||||
return;
|
||||
}
|
||||
datalen -= 3;
|
||||
|
||||
do { /* Loop through (origin, metric) pairs */
|
||||
@ -805,6 +817,7 @@ accept_report(src, dst, p, datalen, level)
|
||||
++nrt;
|
||||
} while (!(metric & 0x80));
|
||||
}
|
||||
|
||||
qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
|
||||
start_route_updates();
|
||||
/*
|
||||
@ -815,9 +828,16 @@ accept_report(src, dst, p, datalen, level)
|
||||
|
||||
log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
for (i = 0; i < nrt; ++i)
|
||||
for (i = 0; i < nrt; ++i) {
|
||||
if (i != 0 && rt[i].origin == rt[i-1].origin &&
|
||||
rt[i].mask == rt[i-1].mask) {
|
||||
log(LOG_WARNING, 0, "%s reports duplicate route for %s",
|
||||
inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2));
|
||||
continue;
|
||||
}
|
||||
update_route(rt[i].origin, rt[i].mask, rt[i].metric,
|
||||
src, vifi);
|
||||
}
|
||||
|
||||
if (routes_changed && !delay_change_reports)
|
||||
report_to_all_neighbors(CHANGED_ROUTES);
|
||||
@ -1098,7 +1118,7 @@ dump_routes(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
register struct rtentry *r;
|
||||
register int i;
|
||||
register vifi_t i;
|
||||
|
||||
|
||||
fprintf(fp,
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: route.h,v 3.6 1995/06/25 19:21:05 fenner Exp $
|
||||
* $Id: route.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -107,7 +107,8 @@ rsrr_init()
|
||||
|
||||
/* Read a message from the RSRR socket */
|
||||
void
|
||||
rsrr_read(rfd)
|
||||
rsrr_read(f, rfd)
|
||||
int f;
|
||||
fd_set *rfd;
|
||||
{
|
||||
register int rsrr_recvlen;
|
||||
|
@ -7,14 +7,13 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: vif.c,v 3.6 1995/06/25 19:53:01 fenner Exp $
|
||||
* $Id: vif.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/*
|
||||
* Exported variables.
|
||||
*/
|
||||
@ -34,24 +33,27 @@ typedef struct {
|
||||
int q_time;
|
||||
} cbk_t;
|
||||
|
||||
static cbk_t *cbk;
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
static void start_vif __P((vifi_t vifi));
|
||||
static void start_vif2 __P((vifi_t vifi));
|
||||
static void stop_vif __P((vifi_t vifi));
|
||||
static void age_old_hosts __P((void));
|
||||
static void send_probe_on_vif __P((struct uvif *v));
|
||||
static void DelVif __P((cbk_t *cbk));
|
||||
static int info_version __P((char *p));
|
||||
static void DelVif __P((void *arg));
|
||||
static int SetTimer __P((int vifi, struct listaddr *g));
|
||||
static int DeleteTimer __P((int id));
|
||||
static void SendQuery __P((cbk_t *cbk));
|
||||
static void SendQuery __P((void *arg));
|
||||
static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire,
|
||||
int q_time));
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the virtual interfaces.
|
||||
* Initialize the virtual interfaces, but do not install
|
||||
* them in the kernel. Start routing on all vifs that are
|
||||
* not down or disabled.
|
||||
*/
|
||||
void
|
||||
init_vifs()
|
||||
@ -101,10 +103,35 @@ init_vifs()
|
||||
log(LOG_WARNING, 0,
|
||||
"no enabled interfaces, forwarding via tunnels only");
|
||||
|
||||
/*
|
||||
* Start routing on all virtual interfaces that are not down or
|
||||
* administratively disabled.
|
||||
*/
|
||||
log(LOG_INFO, 0, "Installing vifs in mrouted...");
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
||||
if (!(v->uv_flags & VIFF_DISABLED)) {
|
||||
if (!(v->uv_flags & VIFF_DOWN)) {
|
||||
if (v->uv_flags & VIFF_TUNNEL)
|
||||
log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
|
||||
inet_fmt(v->uv_lcl_addr, s1),
|
||||
inet_fmt(v->uv_rmt_addr, s2));
|
||||
else
|
||||
log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
|
||||
inet_fmt(v->uv_lcl_addr, s1));
|
||||
start_vif2(vifi);
|
||||
} else log(LOG_INFO, 0,
|
||||
"%s is not yet up; vif #%u not in service",
|
||||
v->uv_name, vifi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start routing on all virtual interfaces that are not down or
|
||||
* administratively disabled.
|
||||
*/
|
||||
void
|
||||
init_installvifs()
|
||||
{
|
||||
vifi_t vifi;
|
||||
struct uvif *v;
|
||||
|
||||
log(LOG_INFO, 0, "Installing vifs in kernel...");
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
||||
if (!(v->uv_flags & VIFF_DISABLED)) {
|
||||
@ -116,7 +143,7 @@ init_vifs()
|
||||
else
|
||||
log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
|
||||
inet_fmt(v->uv_lcl_addr, s1));
|
||||
start_vif(vifi);
|
||||
k_add_vif(vifi, &uvifs[vifi]);
|
||||
} else log(LOG_INFO, 0,
|
||||
"%s is not yet up; vif #%u not in service",
|
||||
v->uv_name, vifi);
|
||||
@ -124,7 +151,6 @@ init_vifs()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -211,11 +237,27 @@ send_probe_on_vif(v)
|
||||
}
|
||||
|
||||
/*
|
||||
* Start routing on the specified virtual interface.
|
||||
* Add a vifi to the kernel and start routing on it.
|
||||
*/
|
||||
static void
|
||||
start_vif(vifi)
|
||||
vifi_t vifi;
|
||||
{
|
||||
/*
|
||||
* Install the interface in the kernel's vif structure.
|
||||
*/
|
||||
k_add_vif(vifi, &uvifs[vifi]);
|
||||
|
||||
start_vif2(vifi);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a vifi to all the user-level data structures but don't add
|
||||
* it to the kernel yet.
|
||||
*/
|
||||
static void
|
||||
start_vif2(vifi)
|
||||
vifi_t vifi;
|
||||
{
|
||||
struct uvif *v;
|
||||
u_int32 src;
|
||||
@ -224,11 +266,6 @@ start_vif(vifi)
|
||||
v = &uvifs[vifi];
|
||||
src = v->uv_lcl_addr;
|
||||
|
||||
/*
|
||||
* Install the interface in the kernel's vif structure.
|
||||
*/
|
||||
k_add_vif(vifi, &uvifs[vifi]);
|
||||
|
||||
/*
|
||||
* Update the existing route entries to take into account the new vif.
|
||||
*/
|
||||
@ -269,7 +306,8 @@ start_vif(vifi)
|
||||
*/
|
||||
v->uv_flags |= VIFF_QUERIER;
|
||||
send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
|
||||
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
|
||||
(v->uv_flags & VIFF_IGMPV1) ? 0 :
|
||||
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
|
||||
age_old_hosts();
|
||||
}
|
||||
|
||||
@ -428,16 +466,15 @@ age_old_hosts()
|
||||
register vifi_t vifi;
|
||||
register struct uvif *v;
|
||||
register struct listaddr *g;
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
|
||||
/* -*- increment the time since an old report was heard */
|
||||
for (g = v->uv_groups; g != NULL; g = g->al_next) {
|
||||
g->al_last ++;
|
||||
if (g->al_last >= OLD_AGE_THRESHOLD){
|
||||
g->al_old = 0;
|
||||
g->al_last = OLD_AGE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the old-hosts-present timer for each
|
||||
* active group on each vif.
|
||||
*/
|
||||
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
|
||||
for (g = v->uv_groups; g != NULL; g = g->al_next)
|
||||
if (g->al_old)
|
||||
g->al_old--;
|
||||
}
|
||||
|
||||
|
||||
@ -454,6 +491,7 @@ query_groups()
|
||||
if (v->uv_flags & VIFF_QUERIER) {
|
||||
send_igmp(v->uv_lcl_addr, allhosts_group,
|
||||
IGMP_HOST_MEMBERSHIP_QUERY,
|
||||
(v->uv_flags & VIFF_IGMPV1) ? 0 :
|
||||
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
|
||||
}
|
||||
}
|
||||
@ -481,16 +519,19 @@ accept_membership_query(src, dst, group, tmo)
|
||||
|
||||
v = &uvifs[vifi];
|
||||
|
||||
/* If we consider ourselves the querier for this vif, but hear a
|
||||
/*
|
||||
* If we consider ourselves the querier for this vif, but hear a
|
||||
* query from a router with a lower IP address, yield to them.
|
||||
*
|
||||
* This is done here as well as in the neighbor discovery in case
|
||||
* there is a querier that doesn't speak DVMRP.
|
||||
*
|
||||
* XXX If this neighbor doesn't speak DVMRP, then we need to create
|
||||
* some neighbor state for him so that we can time him out!
|
||||
*/
|
||||
if ((v->uv_flags & VIFF_QUERIER) &&
|
||||
(ntohl(src) < ntohl(v->uv_lcl_addr))) {
|
||||
|
||||
v->uv_flags &= ~VIFF_QUERIER;
|
||||
v->uv_flags &= ~VIFF_QUERIER;
|
||||
|
||||
}
|
||||
}
|
||||
@ -522,17 +563,14 @@ accept_group_report(src, dst, group, r_type)
|
||||
*/
|
||||
for (g = v->uv_groups; g != NULL; g = g->al_next) {
|
||||
if (group == g->al_addr) {
|
||||
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) {
|
||||
g->al_last = OLD_AGE_THRESHOLD;
|
||||
g->al_old = 0;
|
||||
}
|
||||
else {
|
||||
g->al_last = 0;
|
||||
g->al_old = 1;
|
||||
}
|
||||
if (r_type == IGMP_HOST_MEMBERSHIP_REPORT)
|
||||
g->al_old = OLD_AGE_THRESHOLD;
|
||||
#ifdef SNMP
|
||||
g->al_genid = src;
|
||||
#endif /* SNMP */
|
||||
|
||||
/** delete old timer set a timer for expiration **/
|
||||
g->al_timer= GROUP_EXPIRE_TIME;
|
||||
/** delete old timers, set a timer for expiration **/
|
||||
g->al_timer = GROUP_EXPIRE_TIME;
|
||||
if (g->al_query)
|
||||
g->al_query = DeleteTimer(g->al_query);
|
||||
if (g->al_timerid)
|
||||
@ -551,14 +589,13 @@ accept_group_report(src, dst, group, r_type)
|
||||
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
|
||||
|
||||
g->al_addr = group;
|
||||
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) {
|
||||
g->al_last = OLD_AGE_THRESHOLD;
|
||||
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT)
|
||||
g->al_old = 0;
|
||||
}
|
||||
else {
|
||||
g->al_last = 0;
|
||||
g->al_old = 1;
|
||||
}
|
||||
else
|
||||
g->al_old = OLD_AGE_THRESHOLD;
|
||||
#ifdef SNMP
|
||||
g->al_genid = src;
|
||||
#endif
|
||||
|
||||
/** set a timer for expiration **/
|
||||
g->al_query = 0;
|
||||
@ -596,7 +633,7 @@ accept_leave_message(src, dst, group)
|
||||
|
||||
v = &uvifs[vifi];
|
||||
|
||||
if (!(v->uv_flags & VIFF_QUERIER))
|
||||
if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -857,6 +894,68 @@ accept_neighbor_request2(src, dst)
|
||||
datalen);
|
||||
}
|
||||
|
||||
void
|
||||
accept_info_request(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
u_char *q;
|
||||
int len;
|
||||
int outlen = 0;
|
||||
|
||||
q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
|
||||
|
||||
/* To be general, this must deal properly with breaking up over-sized
|
||||
* packets. That implies passing a length to each function, and
|
||||
* allowing each function to request to be called again. Right now,
|
||||
* we're only implementing the one thing we are positive will fit into
|
||||
* a single packet, so we wimp out.
|
||||
*/
|
||||
while (datalen > 0) {
|
||||
len = 0;
|
||||
switch (*p) {
|
||||
case DVMRP_INFO_VERSION:
|
||||
len = info_version(q);
|
||||
break;
|
||||
|
||||
case DVMRP_INFO_NEIGHBORS:
|
||||
default:
|
||||
log(LOG_INFO, 0, "ignoring unknown info type %d", *p);
|
||||
break;
|
||||
}
|
||||
*(q+1) = len++;
|
||||
outlen += len * 4;
|
||||
q += len * 4;
|
||||
len = (*(p+1) + 1) * 4;
|
||||
p += len;
|
||||
datalen -= len;
|
||||
}
|
||||
|
||||
if (outlen != 0)
|
||||
send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
|
||||
htonl(MROUTED_LEVEL), outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Information response -- return version string
|
||||
*/
|
||||
static int
|
||||
info_version(p)
|
||||
char *p;
|
||||
{
|
||||
int len;
|
||||
extern char versionstring[];
|
||||
|
||||
*p++ = DVMRP_INFO_VERSION;
|
||||
p++; /* skip over length */
|
||||
*p++ = 0; /* zero out */
|
||||
*p++ = 0; /* reserved fields */
|
||||
strcpy(p, versionstring); /* XXX strncpy!!! */
|
||||
|
||||
len = strlen(versionstring);
|
||||
return ((len + 3) / 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an incoming neighbor-list message.
|
||||
@ -885,6 +984,19 @@ accept_neighbors2(src, dst, p, datalen, level)
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an incoming info reply message.
|
||||
*/
|
||||
void
|
||||
accept_info_reply(src, dst, p, datalen)
|
||||
u_int32 src, dst;
|
||||
u_char *p;
|
||||
int datalen;
|
||||
{
|
||||
log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s",
|
||||
inet_fmt(src, s1), inet_fmt(dst, s2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
|
||||
@ -1215,6 +1327,7 @@ dump_vifs(fp)
|
||||
if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
|
||||
if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
|
||||
if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf");
|
||||
if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
if (v->uv_addrs != NULL) {
|
||||
@ -1272,80 +1385,98 @@ dump_vifs(fp)
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
|
||||
/**** the timeout routines ********/
|
||||
|
||||
/*
|
||||
* Time out record of a group membership on a vif
|
||||
*/
|
||||
static void
|
||||
DelVif(cbk)
|
||||
cbk_t *cbk;
|
||||
DelVif(arg)
|
||||
void *arg;
|
||||
{
|
||||
/* -*- make the list consistent */
|
||||
register vifi_t vifi = cbk->vifi;
|
||||
register struct uvif *v;
|
||||
register struct listaddr *a, *prev_a, *g = cbk->g;
|
||||
cbk_t *cbk = (cbk_t *)arg;
|
||||
vifi_t vifi = cbk->vifi;
|
||||
struct uvif *v = &uvifs[vifi];
|
||||
struct listaddr *a, **anp, *g = cbk->g;
|
||||
|
||||
v = &uvifs[vifi];
|
||||
/*
|
||||
* Group has expired
|
||||
* delete all kernel cache entries with this group
|
||||
*/
|
||||
if (g->al_query)
|
||||
DeleteTimer(g->al_query);
|
||||
|
||||
for (prev_a = (struct listaddr *)&(v->uv_groups),
|
||||
a = v->uv_groups;
|
||||
a != NULL;
|
||||
prev_a = a, a = a->al_next) {
|
||||
delete_lclgrp(vifi, g->al_addr);
|
||||
|
||||
if (a != g) continue;
|
||||
anp = &(v->uv_groups);
|
||||
while ((a = *anp) != NULL) {
|
||||
if (a == g) {
|
||||
*anp = a->al_next;
|
||||
free((char *)a);
|
||||
} else {
|
||||
anp = &a->al_next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Group has expired
|
||||
* delete all kernel cache entries with this group
|
||||
*/
|
||||
if (g->al_query) DeleteTimer(g->al_query);
|
||||
delete_lclgrp(vifi, a->al_addr);
|
||||
|
||||
prev_a->al_next = a->al_next;
|
||||
free((char *)a);
|
||||
a = prev_a;
|
||||
}
|
||||
|
||||
free(cbk);
|
||||
free(cbk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a timer to delete the record of a group membership on a vif.
|
||||
*/
|
||||
static int
|
||||
SetTimer(vifi, g)
|
||||
vifi_t vifi; struct listaddr *g;
|
||||
vifi_t vifi;
|
||||
struct listaddr *g;
|
||||
{
|
||||
cbk = (cbk_t *) malloc(sizeof(cbk_t));
|
||||
cbk->g = g;
|
||||
cbk->vifi = vifi;
|
||||
return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
|
||||
cbk_t *cbk;
|
||||
|
||||
cbk = (cbk_t *) malloc(sizeof(cbk_t));
|
||||
cbk->g = g;
|
||||
cbk->vifi = vifi;
|
||||
return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a timer that was set above.
|
||||
*/
|
||||
static int
|
||||
DeleteTimer(id)
|
||||
int id;
|
||||
int id;
|
||||
{
|
||||
timer_clearTimer(id);
|
||||
return 0;
|
||||
timer_clearTimer(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a group-specific query.
|
||||
*/
|
||||
static void
|
||||
SendQuery(cbk)
|
||||
cbk_t *cbk;
|
||||
SendQuery(arg)
|
||||
void *arg;
|
||||
{
|
||||
register struct uvif *v = &uvifs[cbk->vifi];
|
||||
cbk_t *cbk = (cbk_t *)arg;
|
||||
register struct uvif *v = &uvifs[cbk->vifi];
|
||||
|
||||
send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
|
||||
IGMP_HOST_MEMBERSHIP_QUERY,
|
||||
cbk->q_time, 0, 0);
|
||||
cbk->g->al_query = 0;
|
||||
free(cbk);
|
||||
send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
|
||||
IGMP_HOST_MEMBERSHIP_QUERY,
|
||||
cbk->q_time, cbk->g->al_addr, 0);
|
||||
cbk->g->al_query = 0;
|
||||
free(cbk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a timer to send a group-specific query.
|
||||
*/
|
||||
static int
|
||||
SetQueryTimer(g , vifi, to_expire, q_time)
|
||||
struct listaddr *g; vifi_t vifi;
|
||||
int to_expire, q_time;
|
||||
SetQueryTimer(g, vifi, to_expire, q_time)
|
||||
struct listaddr *g;
|
||||
vifi_t vifi;
|
||||
int to_expire, q_time;
|
||||
{
|
||||
cbk = (cbk_t *) malloc(sizeof(cbk_t));
|
||||
cbk->g = g;
|
||||
cbk->q_time = q_time; cbk-> vifi = vifi;
|
||||
return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
|
||||
cbk_t *cbk;
|
||||
|
||||
cbk = (cbk_t *) malloc(sizeof(cbk_t));
|
||||
cbk->g = g;
|
||||
cbk->q_time = q_time;
|
||||
cbk->vifi = vifi;
|
||||
return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Leland Stanford Junior University.
|
||||
*
|
||||
*
|
||||
* $Id: vif.h,v 3.6 1995/06/25 19:53:22 fenner Exp $
|
||||
* $Id: vif.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -41,6 +41,7 @@ struct uvif {
|
||||
#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
|
||||
#define VIFF_ONEWAY 0x0800 /* Maybe one way interface */
|
||||
#define VIFF_LEAF 0x1000 /* all neighbors are leaves */
|
||||
#define VIFF_IGMPV1 0x2000 /* Act as an IGMPv1 Router */
|
||||
|
||||
struct phaddr {
|
||||
struct phaddr *pa_next;
|
||||
@ -65,8 +66,7 @@ struct listaddr {
|
||||
u_char al_mv; /* router mrouted version */
|
||||
u_long al_timerid; /* returned by set timer */
|
||||
u_long al_query; /* second query in case of leave */
|
||||
u_short al_old; /* if old memberships are present */
|
||||
u_short al_last; /* # of query's since last old rep */
|
||||
u_short al_old; /* time since heard old report */
|
||||
u_char al_flags; /* flags related to this neighbor */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user