|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T r
Length: 18764 (0x494c)
Types: TextFile
Names: »rtmp.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z«
└─⟦b503a39fe⟧
└─⟦this⟧ »kip/rtmp.c«
/*
* RTMP / ZIP etc.
*
* (c) 1986, Stanford Univ. CSLI.
* May be used but not sold without permission.
*
* $Header: rtmp.c,v 4.1 88/11/01 19:51:00 sw0l Locked $
*/
#include "gw.h"
#include "gwctl.h"
#include "fp/pbuf.h"
#include "ab.h"
#include "inet.h"
#include "fp/cmdmacro.h"
#include "glob.h"
extern u_char broadcastaddr[];
#ifdef SNMP
#include "mib.h"
#include "snmp_vars.h"
#endif
short rtmp_delay, rtmp_vdelay; /* 'static' */
short art_delay; /* 'static' */
short zip_delay;
struct aroute *notzipped;
struct aroute *art_last; /* 'static', last aroute pointer */
/*
* RTMP clock routine.
* Broadcasts RTMP's on AppleTalk segment, age routes.
*/
rtmptimer()
{
register struct aroute *ar;
int i;
if (rtmp_delay && ++rtmp_delay < 11)
return; /* run only every 10 seconds */
rtmp_delay = 1;
/* broadcast the current routing table on appletype interfaces */
for (i = 0 ; i < MAX_PORT; i++)
if (porttoif[i] && porttoif[i]->if_flags & IF_APPLETYPE)
rtmpsend(porttoif[i]);
if (rtmp_vdelay++ == 0) /* validity timer goes off every 20 secs */
return;
rtmp_vdelay = 0;
/* age routes in our table */
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
if (ar->net == 0 || ar->hops == 0 || (ar->flags & arouteAA))
continue;
if (arouteBad(ar)) {
ar->net = 0; /* delete it */
continue;
}
if (ar->age < 255)
ar->age++;
}
}
/*
* Send an RTMP packet. If 'tuples' is true,
* include the routing tuples.
*/
/* break into send and reply */
/* rtmp send: used only to broadcast rtmp "here I ams" */
/* setup for ddp reply and call rtmpreply */
rtmpsend(ifp)
struct ifnet *ifp;
{
source_if = ifp;
ddp.srcNet = source_if->if_dnet;
ddp.srcNode = 0xff; /* broadcast */
ddp.srcSkt = rtmpSkt;
rtmpreply(1);
}
/* rtmp reply - reply to last packet (was rtmp request) */
rtmpreply(tuples)
{
register struct pbuf *p;
register struct RTMP *r;
register i;
K_PGET(PT_DATA, p);
if (p == 0)
return;
r = (struct RTMP *)(p->p_off + lapSize + ddpSize);
r->net = source_if->if_dnet;
r->idLen = 8;
r->id = source_if->if_dnode;
if (tuples)
i = rtmpsettuples((caddr_t)(r + 1));
else
i = 0;
/* setup for ddp send */
ddp.type = ddpRTMP; /* in case request */
p->p_len = i+rtmpSize+ddpSize+lapSize;
ddpreply(p, rtmpSkt);
}
/*
* Merge new routing tuples into our aroute table.
*/
rtmpmerge(cp, count, sender)
register unsigned char *cp; /* start of tuple array [3][n] */
int count; /* count of tuples */
int sender; /* node of tuple sender */
{
struct arouteTuple at;
int port;
at.node = sender;
port = source_if->if_unit;
for ( ; count > 0 ; count--) {
at.net = (*cp)<<8|(*(cp+1));
at.hops = *(cp+2);
at.flags = 0;
cp+=3; /* advance */
newroute(&at, port);
}
}
newroute(at, port)
register struct arouteTuple *at;
int port;
{
struct aroute *arfree = 0;
register struct aroute *ar;
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
if (ar->net == 0) { /* remember a free slot */
if (arfree == 0) arfree = ar;
continue;
}
if (at->net == ar->net) {
/* search for this tuple net in table */
/* [want check inside so we drop the extra aaroutes] */
if (ar->hops == 0) /* never touch local entries */
return;
if (arouteBad(ar) && at->hops < 15)
goto replace;
if (ar->hops >= (at->hops+1) && at->hops < 15)
goto replace;
if (ar->node == at->node && port == ar->port) {
if ((ar->hops = at->hops + 1) < 16)
ar->age = 0;
else
ar->net = 0;
}
return;
}
}
/* add */
/* tuple net # wasnt in our table, add it */
if ((ar = arfree) == 0)
return; /* oops, out of room */
arfree = 0;
/* until we implment zip takedown, bringup, it's probably best to */
/* to put zone setting in "replace", but .... */
ar->zone = 0;
if (!notzipped)
notzipped = ar;
replace:
ar->net = at->net;
ar->hops = at->hops + 1;
ar->node = at->node;
ar->port = port;
ar->age = 0;
ar->flags = at->flags;
}
/*
* Setup a tuple array, starting at cp; returns total size
* of the array in bytes.
*/
rtmpsettuples(cp)
register char *cp;
{
register count;
register struct aroute *ar;
count = 0;
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
if (ar->net == 0 || arouteBad(ar))
continue;
if (ar->zone == 0 && notzipped == 0)
notzipped = ar;
/* copy in the net, hops, but be careful of byte aligment */
*cp++ = ar->net >> 8;
*cp++ = ar->net & 0xff;
*cp++ = ar->hops;
count += 3;
}
return (count);
}
/*
* RTMP received from AppleTalk.
*/
rtmpinput(p)
struct pbuf *p;
{
register struct RTMP *r;
register tbytes, tuples;
int src;
p->p_len -= (lapSize+ddpSize); /* skip lap+ddp */
p->p_off += (lapSize+ddpSize);
/* rtmp from ourselfs */
if ((ddp.dstNet == source_if->if_dnet && ddp.dstNode==source_if->if_dnode) ||
p->p_len < 1)
goto drop;
if (ddp.type == ddpRTMPR) {
/* RTMP request from Mac trying to get his net # */
if (*p->p_off != 1)
goto drop; /* only opcode defined now is 1 */
rtmpreply(0); /* reply */
goto drop;
}
r = (struct RTMP *)p->p_off;
src = r->id;
if (p->p_len < sizeof(struct RTMP) ||
(tbytes = ddp.length-ddpSize-sizeof(struct RTMP)) <= 0 ||
r->idLen != 8 || r->id == source_if->if_dnode)
goto drop;
if ((tuples = tbytes/3)) /* if we have any tuples, merge them in */
rtmpmerge((caddr_t)(r+1), tuples, src);
drop:
K_PFREE(p);
}
/*
* Send arouteTuple's to gateway at 'ia'.
* If 'all' flag is true, sends all routes not configured by AA.
* If 'all' is 0, only sends locally discovered routes (new atalk
* segments dynamically plugged in).
*/
artsend(ia, all)
iaddr_t ia;
register all;
{
register struct aroute *ar;
register struct arouteTuple *at;
struct pbuf *p;
register count;
count = 0;
K_PGET(PT_DATA, p);
if (p == 0)
return(0);
at = (struct arouteTuple *)m_stuff(p->p_off);
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
if (ar->net == 0 || ar->hops == 0)
continue; /* skip null & local entries */
if (all) {
if (ar->flags & arouteAA)
continue; /* skip AA entries */
} else {
if (arouteIP(ar))
continue; /* skip IP entries */
}
if (arouteIP(ar)) {
at->node = ar->node;
at->flags = ar->flags;
} else {
/* if node was an atalk address, subst. our IP addr */
at->node = conf.ipaddr;
at->flags = arouteKbox;
}
at->net = ar->net;
at->hops = ar->hops;
at++;
count++;
}
if (count == 0 && all)
goto drop; /* dont sent null aaROUTE packets */
kipit(p, ia, all ? aaROUTE : aaROUTEQ, count * sizeof *at);
/* (but we would send a null aaROUTEQ query packet) */
return (1);
drop:
K_PFREE(p);
return (0);
}
/*
* arouteTuple timer routine. Once per minute send arouteTuple's
* to 'core' gateways.
*/
arttimer()
{
register struct aroute *ar;
register count;
if (art_delay && ++art_delay < 60)
return; /* run only every 60 seconds */
art_delay = 1;
if (arouteinit == 0) {
/* if routes not yet received from AA */
confrequest(aaROUTEI);
}
/*
* send local additions to one of the core's,
* chosen circularly.
*/
if ((ar = art_last) == 0)
ar = &aroute[0];
for (count = 0 ; count < NAROUTE ; count++) {
ar++;
if (ar >= &aroute[NAROUTE])
ar = &aroute[0];
if (ar->net == 0 || (ar->flags & arouteCore) == 0)
continue;
art_last = ar;
artsend(ar->node, 0);
return;
}
/* else no core gateways found */
return;
}
/*
* arouteTuples received from another gateway or AA.
* Merge into our table and send reply if requested.
*/
artinput(aa, ipsrc)
register struct aaconf *aa;
iaddr_t ipsrc;
{
register struct arouteTuple *at;
register struct aroute *ar;
register count, type;
if ((type = aa->type) == aaROUTEI) {
/* if init table from AA, clear all entries */
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar)
if (ar->flags & arouteAA)
ar->net = 0;
}
at = (struct arouteTuple *)aa->stuff;
for (count = aa->count / sizeof *at ; count > 0 ; count--, at++) {
if (type == aaROUTEI)
at->flags |= arouteAA;
newroute(at, 1); /* 1 is the ip port */
}
if (type == aaROUTEQ)
artsend(ipsrc, 1);
else if (type == aaROUTEI) {
artsend(ipsrc, 0);
arouteinit = 1;
}
}
/*
* Get the aroute entry corresponding to the atalk net number
* supplied. Returns 0 if not routed via LocalTalk, otherwise the bridge's
* node number on our atalk segment (or -1 if local segment).
*/
getaroute(net)
register net;
{
register struct aroute *ar;
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
if (ar->net == 0 || ar->net != net) /* empty slot */
continue;
/* not a LocalTalk port or invalid port */
/* if (ar->port > MAX_PORT) return(0); - paranoia */
if (!porttoif[ar->port] || (porttoif[ar->port]->if_flags & IF_ALAP) == 0)
return(0);
return(ar->node ? ar->node : -1);
}
return (0);
}
/*
* Ziptimer; gets aaZONE table from AA. Perhaps should
* also zipQuery unzoned nets...
*/
ziptimer()
{
if (arouteinit == 0)
return; /* wait until routing table received */
#ifdef notdef
if (azoneinit == 0) { /* if aaZONE not yet received */
confrequest(aaZONE);
return;
}
#endif
if (notzipped == 0 || (zip_delay && ++zip_delay < 5)) /* once every 5 sec*/
return;
zip_delay = 1;
zipquery();
}
zipquery()
{
struct pbuf *p;
register struct aroute *ar;
struct ZIP *z;
u_short *n;
int count;
u_char port;
long node;
int toadmin = 0;
if (notzipped == 0)
return;
if (notzipped->zone) {
notzipped = 0;
return;
}
K_PGET(PT_DATA, p);
if (p == 0)
return;
port = notzipped->port;
node = notzipped->node;
/* necessary to fake ddp reply */
source_if = porttoif[notzipped->port];
if (source_if->if_flags & IF_IPUDP) {
toadmin = (notzipped->flags & arouteAA) || notzipped->hops == 0 ;
z = (struct ZIP *)m_stuff(p->p_off);
count = sizeof(struct ZIP);
} else {
/* pretend replying to bridge that advertised this rtmp */
ddp.srcNet = source_if->if_dnet;
ddp.srcNode = notzipped->node;
ddp.srcSkt = zipSkt;
ddp.type = ddpZIP;
count = sizeof(struct ZIP);
z = (struct ZIP *)(p->p_off + lapSize + ddpSize);
}
z->command = zipQuery;
z->count = 0;
n = (u_short *)(z+1); /* point to start of nets */
notzipped = 0;
for (ar = &aroute[0] ; ar < &aroute[NAROUTE]; ++ar) {
if (ar->net && ar->zone == 0) {
if (!toadmin) {
if (ar->node != node || ar->port != port) {
if (!notzipped) /* if no new selection */
notzipped = ar; /* try one! */
continue;
}
} else if ((ar->flags & arouteAA) == 0 && ar->hops != 0)
continue;
*n = ar->net;
n++;
z->count++;
count +=2;
}
}
if (source_if->if_flags & IF_IPUDP) {
kipit(p, toadmin ? conf.ipadmin : node, aaZONEQ, count);
} else {
p->p_len = lapSize+ddpSize+count;
ddpreply(p, zipSkt);
}
}
u_char *azonep;
int numzones;
newzone(s)
u_char *s;
{
u_char i;
int zi;
if (azonep == 0)
azonep = azonenames;
if ((zi=zipfind(s, 0)) > 0)
return(zi);
if (numzones >= (NAZONE-2)) /* no more room */
return(0);
i = *s++; /* get the length */
if ((i + azonep + 2) > (azonenames+sizeof(azonenames))) /* check it */
return(0);
azone[++numzones] = azonep; /* set dp */
azone[numzones+1] = 0; /* tie off end */
*azonep++ = i;
/* Check for special zone that gets all requests */
if (strncmp(s, ALLZONES, i) == 0)
allzones = numzones;
bcopy(s, azonep, i);
azonep += i;
return(numzones); /* return index */
}
#ifdef notdef
/*
* Called from ip4me() when aaZONE arrives from AA.
* Setup our zone table and zone indexes in aroute.
*/
zipinit(aa)
struct aaconf *aa;
{
register u_char *cp,*ncp;
register i,l,iz;
register unsigned n;
/*
* parse aaZONE table; format:
* net# net# ... 0 zonename
* net# net# ... 0 zonename
* 0xFFFF
*/
for (cp = aa->stuff;;) {
ncp = cp;
do {
n = *cp++;
n <<= 8;
n |= *cp++;
} while (n && n != 0xffff);
if (n == 0xFFFF)
break; /* end of table */
l = *cp; /* length of str */
iz = newzone(cp);
if (iz == 0) /* no more room */
break;
/* Check for special zone that gets all requests */
if (strncmp(cp+1, ALLZONES, l) == 0)
allzones = iz;
do {
n = *ncp++;
n <<= 8;
n |= *ncp++;
if (n == 0)
break;
for (i = 0 ; i < NAROUTE ; ++i)
if (n == aroute[i].net)
break;
if (i < NAROUTE)
aroute[i].zone = iz;
} while (n);
cp += l + 1;
}
/* end of table */
azone[0] = azone[aroute[0].zone]; /* my own zone */
azoneinit = 1; /* dont ask for aaZONE anymore */
}
#endif
/*
* Find the zone index, given the name; returns -1 if not found.
* set flag true if want (conf.flags).
*/
zipfind(s, flag)
register u_char *s;
int flag;
{
register i;
for (i = 1 ; ; i++) {
if (azone[i] == 0)
return (-1); /* reached end of table */
if (*azone[i] != *s) /* lengths must match */
continue;
if (strncmpci(s+1, azone[i]+1, *s) != 0)
continue;
if (flag && (conf.flags & conf_stayinzone))
if (aroute[0].zone && azone[i] != azone[aroute[0].zone])
return (-1);
return (i);
}
}
/*
* String compare, case independent;
* returns zero if equal, one otherwise
*/
strncmpci(s,t,n)
char *s,*t;
int n;
{
register char c,d;
while (n--) {
c = *s++;
if (c >= 'A' && c <= 'Z')
c += ('a'-'A'); /* convert to lower case */
d = *t++;
if (d >= 'A' && d <= 'Z')
d += ('a'-'A'); /* convert to lower case */
if (c != d)
return(1);
if (c == '\0')
return(0);
}
return(0); /* success on runnout */
}
/*
* Process ZIP packet received on input.
*/
zipatp(ip)
struct pbuf *ip;
{
union zipatp {
struct ATP a; /* atp */
u_char c[sizeof(struct ATP)]; /* 8 bytes */
u_short s[sizeof(struct ATP)/sizeof(u_short)]; /* 4 words */
} zipatp, *zap;
u_char *po, *pi;
int zl; /* zone length */
int zi; /* zone index */
int fzones; /* # of found zones */
int len, count, i,j ;
register struct aroute *ar;
/* we can reuse the input packet (query needs too much out of it) */
#define GMZ 7 /* get my zone */
#define GZL 8 /* get zone list */
/* big enough? */
if (ip->p_len < (lapSize+ddpSize+sizeof(struct ATP)))
goto drop;
po = ip->p_off + lapSize + ddpSize;
bcopy(po, &zipatp, sizeof(zipatp));
if (zipatp.a.control != atpReqCode ||
(zipatp.a.bitmap & 0x1) == 0 || /* at least 1 packet */
(zipatp.c[4] != GMZ && zipatp.c[4] != GZL) ||
zipatp.c[5] != 0)
goto drop;
zap = (union zipatp *)po;
po += sizeof(zipatp); /* move ahead */
zap->a.control = atpRspCode|atpEOM; /*rsp+EOM */
zap->a.bitmap = 0; /* set seq to match bitmap */
/* tid already set */
len = 0;
switch (zipatp.c[4]) {
case GMZ:
zap->c[4] = 0;
/* Find the zone for the interface request came in on */
/* cck: modify to find the zone for the source network */
/* of the packet that came in */
for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar)
if (ar->net == ddp.srcNet)
break;
if (ar == &aroute[NAROUTE] || ar->zone == 0)
goto drop;
pi = azone[ar->zone];
zl = *pi + 1;
bcopy(pi, po, zl); /* get zone */
len += zl; /* and move ptr */
zap->s[3] = 1; /* set count */
break;
case GZL:
if (conf.flags & conf_stayinzone)
break;
/* not clear which bit "lastflag" is */
zap->c[4] = 0xff;
/* first index is 1 */
for (fzones = 0, zi=zipatp.s[3]; azone[zi] ; ++zi) {
if (zi == allzones)
continue;
pi = azone[zi];
zl = *pi + 1;
/* enable this if azone is defined larger than atpMaxData */
if (len + zl > 512) { /* less than maxsize */
zap->c[4] = 0; /* clear lastflag */
break;
}
bcopy(pi, po, zl);
fzones++; /* increment count */
po += zl;
len += zl;
}
zap->s[3] = fzones; /* set count */
break;
}
ip->p_len = lapSize+ddpSize+sizeof(zipatp)+len;
ddpreply(ip, zipSkt);
return;
drop:
K_PFREE(ip);
}
zipinput(z, zlen,ia)
struct ZIP *z;
int zlen;
long ia;
{
register u_char *pi, *po, *zn;
register struct aroute *ar;
register count, i, len;
int j;
u_short *sp;
struct pbuf *op;
union {
u_short s;
u_char c[2];
} u;
zlen -= sizeof(struct ZIP);
if (zlen <= 0) /* bad or empty */
return;
if (z->command == zipQuery)
goto query;
if (z->command == zipReply)
goto reply;
#ifdef notdef
if (z->command == zipTakedown)
goto takedown;
#endif
return;
reply:
/* assume (ha) that length is right */
pi = (u_char *)(z+1); /* point past header */
j = z->count;
while (j-- != 0) {
u.c[0] = *pi++; /* network */
u.c[1] = *pi++;
zn = pi; /* remeber zone name */
pi += ((*pi)+1); /* skip past zone name */
for (ar = &aroute[0] ; ar < &aroute[NAROUTE]; ++ar) {
if (u.s != ar->net)
continue;
if (ar->zone == 0)
ar->zone = newzone(zn);
break; /* break anyway since already zipped */
}
}
return;
query:
K_PGET(PT_DATA, op);
if (op == 0)
return;
j = z->count;
sp = (u_short *)(z+1);
/* setup output packet */
z = (struct ZIP *)(ia ? m_stuff(op->p_off) : (op->p_off + lapSize+ddpSize));
z->command = zipReply;
po = (u_char *)(z+1);
len = sizeof(struct ZIP);
for (count = 0; j && len < 512 ; j--) {
u.s = i = *sp++; /* network */
for (ar = &aroute[0]; ar < &aroute[NAROUTE] ; ++ar) {
if (i == ar->net)
break;
}
if (ar >= &aroute[NAROUTE] || ar->zone == 0)
continue; /* no match */
count++; /* found one */
pi = azone[ar->zone];
*po++ = u.c[0]; /* copy in network */
*po++ = u.c[1];
bcopy(pi, po, *pi + 1); /* copy in zone */
po += (*pi + 1); /* string + count */
len += (*pi + 3); /* string + count + netnumber */
}
z->count = count;
if (ia) {
kipit(op, ia, aaZONEQ, len);
} else {
op->p_len = lapSize + ddpSize + len;
ddpreply(op, zipSkt);
}
return;
}
kipit(p, ia, type, len)
struct pbuf *p;
long ia;
int type;
int len;
{
register struct aaconf *m;
struct udp u;
m = (struct aaconf *)(p->p_off + sizeof (struct ip) + sizeof u);
m->magic = aaMagic;
m->type = type;
m->flags = 0;
m->count = len;
m->ipaddr = conf.ipaddr;
u.src = u.dst = aaPort;
u.length = len + aaconfMinSize + sizeof u;
u.checksum = 0;
#ifdef SNMP
mib_udp.udpOutDatagrams++;
#endif
*(struct udp *)(p->p_off + sizeof (struct ip)) = u;
p->p_len = u.length + sizeof (struct ip);
setiphdr(p, ia);
routeip(p, 0, 0);
}