|
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); }