DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦76ace8f94⟧ TextFile

    Length: 18764 (0x494c)
    Types: TextFile
    Names: »rtmp.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z« 
        └─⟦b503a39fe⟧ 
            └─⟦this⟧ »kip/rtmp.c« 

TextFile

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