|
|
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 g
Length: 25425 (0x6351)
Types: TextFile
Names: »gw.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z«
└─⟦b503a39fe⟧
└─⟦this⟧ »kip/gw.c«
/*
* AppleTalk / Ethernet Gateway.
*
* (c) 1986, Stanford Univ. SUMEX project.
* May be used but not sold without permission.
*
* (c) 1986, Kinetics, Inc.
* May be used but not sold without permission.
*/
char rcsident[] =
"$Header: gw.c,v 4.1 88/11/01 19:49:12 sw0l Locked $";
#include "gw.h"
#include "gwctl.h"
#include "fp/pbuf.h"
#include "ab.h"
#include "ether.h"
#include "inet.h"
#include "fp/cmdmacro.h"
#include "glob.h"
#include "conf.h"
#ifndef KFPSVERSION
# include "kfpsversion.h"
#endif
#ifdef SNMP
#include "mib.h"
#include "snmp_vars.h"
#endif
/*
* Main event loop.
*/
main()
{
register struct pbuf *p;
short pri;
struct fp_mem mem;
extern char begin; /* first address in RAM */
extern char edata; /* last address in initialized data */
extern char end; /* last address in this downloaded program */
K_PROMRAM(&pvars); /* get addresses of relevant prom variables */
data_init(); /* initialize data normally done at compile time */
pq = pvars.fpr_bufs->fpb_pq; /* shorthand for queue headers */
sendq = pvars.fpr_bufs->fpb_sendq;
bcopy(pvars.fpr_state->fps_unused, (caddr_t)&conf, sizeof conf);
bcopy(conf.etheraddr, etheraddr, 6);
asminit(); /* set up ethernet interrupt vector */
/* initialize buffer pool */
K_INIPROM();
mem.fpm_count = 0;
K_GETMEM(&mem); /* gets address of the top of available mem */
topram = (int)mem.fpm_memp;
/* use all the rest of available ram for buffers */
bufs = (struct pbuf *)((int)(&end) + 2);
mem.fpm_count = topram - ((int)(bufs)) - 2;
mem.fpm_memp = (char *)bufs;
K_CLRMEM(&mem); /* initialize entire area to all zeroes */
/* set free list and queue headers to empty */
*(pvars.fpr_bufs->fpb_pfree) = 0;
pq->pq_head = 0;
pq->pq_tail = 0;
pq->pq_len = 0;
sendq->pq_head = 0;
sendq->pq_tail = 0;
sendq->pq_len = 0;
K_BUFINIT(&mem); /* divide the area into buffers */
/* initialize interface structures */
ifnet = &ifie; ifie.if_next = &ifab;
ifab.if_next = &ifet; ifet.if_next = 0;
#ifdef notdef
{ short nodenum;
K_ATINIT(&nodenum); /* initialize AppleTalk network interface */
atnode = nodenum;
}
#else
atnode = pvars.fpr_state->fps_node;
#endif
ie_init(); /* initialize Ethernet interface... */
if (conf.ipaddr == 0 || etheraddr[2] != 0x89)
panic("bad conf");
ifie.if_addr = conf.ipaddr; /* initialize internet data structures */
ipnet = ifie.if_addrnet = ipnetpart(ifie.if_addr);
ifie.if_dnode = (conf.ipaddr & 0xFF);
ifab.if_dnode = ifab.if_haddr[0] = atnode;
ifet.if_dnode = 0; /* no Ethertalk address known yet */
#ifdef notdef
checksum(&begin, &edata); /* set up RAM memory checksum protection */
#endif
if (conf.ready == confReady)
confready(0); /* finish configuration */
K_WAIT(20);
sendf("KFPS(IP) version %s node #%d lives!! - %d buffers",
KFPSVERSION, atnode,
mem.fpm_count/sizeof (struct pbuf));
K_LEDOFF();
K_SPL0(&pri); /* allow interrupts */
for (;;) {
if (pq->pq_head == 0) { /* no packets on main queue */
back(); /* perform background processing */
continue;
}
K_PDEQ(SPLIMP,pq,p); /* remove buffer from queue */
if (p->p_len < 0) { /* if error packet */
if (p->p_len != -1)
goto pan;
K_PFREE(p); /* put the buffer back on the free list */
continue;
}
switch (p->p_type) { /* switch on packet type */
case PT_ABUS:
#ifdef SNMP
/*
* Check the ddp source address to see that
* this wasn't a broadcast ddp from this node.
*/
if (p->p_off[1] != ifab.if_dnode)
mib_ifEntry[1].ifInOctets += p->p_len;
#endif
#ifdef notdef
p_if(p) = &ifab; /* should be in prom code? */
#endif
source_if = &ifab;
abreceive(p); /* receive AppleTalk packet */
break;
case PT_ENET:
#ifdef SNMP
mib_ifEntry[0].ifInOctets += p->p_len;
#endif SNMP
source_if = &ifie;
iereceive(p); /* receive ethernet packet */
break;
default:
pan:
#ifdef STATS
K_SPLIMP(&pri); /* prevent interruptions */
p_print("main",p);
dmpbf();
ieprintstats();
abprintstats();
#endif STATS
panic("main: bad pkt");
}
}
}
/*
* Complete configuration process. Called when configuration 'ready'
* via preset struct conf or aaconf packet received.
*/
confready(aa)
register struct aaconf *aa;
{
if (aa) { /* configure packet received */
bcopy(aa->stuff, (caddr_t)(&conf) + confPrefix,
sizeof conf - confPrefix);
/* will go away after KIP 06/88 */
/* prevents us from doing bad things */
if (conf.startddpWKSUnix == 0)
conf.startddpWKSUnix = defddpWKSUnix;
conf.ready = confReady;
}
if (conf.ipdynamic > NIPDAD)
conf.ipdynamic = NIPDAD;
ifab.if_dnet = conf.atneta;
ifab.if_unit = 0;
aroute[0].net = conf.atneta; /* hops=0, node=0, flags=0 */
aroute[0].port = 0;
porttoif[0] = &ifab;
ifie.if_dnet = conf.atnete;
ifie.if_unit = 1;
aroute[1].net = conf.atnete;
aroute[1].node = (conf.ipaddr & ~0xFF); /* hops=0*/
aroute[1].flags = arouteNet;
aroute[1].port = 1;
porttoif[1] = &ifie;
if (conf.anetet) {
ifet.if_dnet = aroute[2].net = conf.anetet;
ifet.if_unit = 2;
aroute[2].port = 2; /* node=0, hops=0,flags=0 */
porttoif[2] = &ifet;
conf.anetet = 0; /* some clients expect this to be 0 */
}
}
short confdelay; /* sigh, should be 'static', but checksum complains */
/*
* Configuration clock routine; get config from appletalk admin.
*/
conftimer()
{
if (confdelay && ++confdelay < 10)
return;
confdelay = 1;
confrequest(aaCONF);
}
/*
* Request configuration (or net table) from appletalk administrator.
*/
confrequest(op)
{
register struct aaconf *m;
register struct udp *u;
register struct pbuf *p;
K_PGET(PT_DATA, p);
if (p == 0)
return;
p->p_len = sizeof (struct ip) + sizeof *u + aaconfMinSize;
setiphdr(p, conf.ipadmin);
u = (struct udp *)(p->p_off + sizeof (struct ip));
u->src = aaPort;
u->dst = aaPort;
u->length = p->p_len - sizeof (struct ip);
u->checksum = 0;
#ifdef SNMP
mib_udp.udpOutDatagrams++;
#endif
m = (struct aaconf *)(u + 1);
m->magic = aaMagic;
m->type = op;
m->ipaddr = conf.ipaddr;
m->count = 0;
source_if = 0;
routeip(p, 0, 0);
}
int backclock; /* 'static' */
/*
* Backround processing. Call once per second timeout routines.
* Call 'backround' routines.
*/
/* The following used for Ethertalk startup */
iaddr_t et_probe; /* Current address we are trying */
short et_probe_count; /* number of times we've PROBEd it */
#define ETALK_NPROBE 10 /* Number of times to probe */
/*
* The Ethertalk spec requires some ungodly number of probes at an
* unreasonably short interval. In order to protect the ethernet I'm
* going to try to get away with a smaller number
*/
back()
{
register i;
nbpback(); /* NBP backround (sends 1 LkUp per loop) */
#ifdef KINETICS
msclock++;
if ((i = msclock - backclock) < 0)
i = -i;
if (i > 12000) /* ~one second */
#else
if ((i = msclock - backclock) < 0)
i = -i;
if (i > 1000) /* ~one second */
#endif
{
backclock = msclock;
arptimer(); /* timeout arp cache */
if (conf.ready != confReady) {
conftimer();
return;
}
/* Ethertalk - keep probing if address not chosen yet */
if (ifet.if_dnet && ifet.if_dnode == 0) {
/* Still probing for ethertalk address */
if (arpresolve(&ifet, (struct pbuf *) 0, &et_probe, (char *)0)) {
/* This address is known */
et_probe_count = 0;
++((char *)&et_probe)[3];
} else ++et_probe_count;
if (et_probe_count > ETALK_NPROBE) {
/* use this node address */
ifet.if_addr = et_probe;
ifet.if_dnode = ((char *)&et_probe)[3];
}
} /* end test if ETalk address set */
/* Don't send out RTMP packets until Etalk is set */
else {
rtmptimer(); /* routing table maint protocol timer */
}
arttimer(); /* arouteTuple timer */
ipdadtimer(); /* IP dynamic address assignment timer */
ziptimer(); /* zone info timer */
}
}
/*
* The functions of the "abreceive" and "ilreceive" routines below might
* normally belong in the input interrupt sections of their respective
* drivers. But since they do some protocol translation as well, we've
* stuck them here. (Another consideration is that the LAP input interrupt
* code is very time critical).
*/
/*
* Receive next packet from AppleTalk.
* Forward the packet onto the ethernet leg, possibly encapsulating
* in a UDP packet first.
*/
abreceive(p)
register struct pbuf *p;
{
register wasbroad;
int temp;
bcopy(p->p_off, (caddr_t)&lap, lapSize);
wasbroad = (lap.dst == 0xFF);
#ifdef SNMP
/*
* Check the source_if to make sure that this isn't an ethertalk packet
* off of the ethernet. Also check the ddp source address to see that
* this wasn't a broadcast ddp from this node.
*/
if (source_if == &ifab && p->p_off[1] != ifab.if_dnode)
if (wasbroad)
mib_ifEntry[1].ifInNUcastPkts++;
else
mib_ifEntry[1].ifInUcastPkts++;
#endif SNMP
p->p_off += lapSize;
p->p_len -= lapSize;
wasddp = 0; /* assume not a ddp */
/*
* Below we copy the DDP header into a global structure to
* get word alignment. Since lapSize and ddpSize are both odd,
* after handling the headers the packet is again on an even
* boundary (odd+odd=even).
*/
switch (lap.type) {
case lapDDPS:
if ((p->p_len -= ddpSSize) < 0)
goto drop;
bcopy(p->p_off, (caddr_t)&ddps, ddpSSize);
p->p_off += ddpSSize;
/* reset length in case ethertalk */
temp = ddps.length - ddpSSize;
ddp.dstSkt = ddps.dstSkt;
ddp.type = ddps.type;
break;
case lapDDP:
if ((p->p_len -= ddpSize) < 0)
goto drop;
bcopy(p->p_off, (caddr_t)&ddp, ddpSize);
/* 0 network means this_network */
if (ddp.srcNet == 0)
ddp.srcNet = source_if->if_dnet;
if (ddp.dstNet == 0)
ddp.dstNet = source_if->if_dnet;
temp = (ddp.length & ddpLengthMask) - ddpSize;
p->p_off += ddpSize;
wasddp = 1;
break;
case 'K': /* Kinetics protocol type */
K_KLAP(p);
K_PFREE(p);
return;
default:
#ifdef SNMP
/*
* Check the source_if to make sure that this isn't an ethertalk packet
* off of the ethernet. Also check the ddp source address to see that
* this wasn't a broadcast ddp from this node.
*/
if (source_if == &ifab && p->p_off[1] != ifab.if_dnode)
mib_ifEntry[1].ifInUnknownProtos++;
#endif
goto drop;
}
/* MUST BE ddp at this point */
/* reset packet length in case ethertalk */
if (temp < p->p_len) /* make sure we don't overun buffer */
p->p_len = temp;
if (conf.ready != confReady)
goto drop;
#ifdef notdef
/* Looks like EtherTalk has made it necessary to assume that */
/* incoming RTMP or ZIP may be LONG DDP */
/*
* here we switch out immediately to short-DDP-only
* handlers, to avoid having to convert them to long DDPs.
*/
switch (ddp.dstSkt) {
case 0:
goto drop;
case rtmpSkt:
if (lap.src == source_if->if_dnode)
goto drop; /* from ourself */
rtmpinput(p);
return;
case zipSkt:
if (lap.src == source_if->if_dnode)
goto drop; /* from ourself */
zipinput(p);
return;
}
#endif
if (ddp.type == ddpIP) {
#ifdef SNMP
mib_ip.ipInReceives++;
#endif
routeip(p, source_if, wasbroad);
return;
}
/* not magic type, just route as a ddp */
if (wasddp == 0)
ddps2ddp(p);
route:
p->p_off -= lapSize + ddpSize;
p->p_len += lapSize + ddpSize;
routeddp(p, source_if, wasbroad);
return;
drop:
/* put the buffer back on the free list */
K_PFREE(p);
stats.dropabin++;
return;
}
/*
* Convert packet from short DDP form to long DDP form.
*/
ddps2ddp(p)
register struct pbuf *p;
{
if (wasddp)
return;
ddp.length = ddps.length - ddpSSize + ddpSize;
ddp.checksum = 0;
ddp.dstNet = ddp.srcNet = source_if->if_dnet;
ddp.srcNode = lap.src;
ddp.dstNode = lap.dst;
ddp.srcSkt = ddps.srcSkt;
ddp.dstSkt = ddps.dstSkt;
ddp.type = ddps.type;
bcopy((caddr_t)&ddp, p->p_off - ddpSize, ddpSize);
wasddp = 1;
}
/*
* Receive next packet from intel ethernet.
*/
iereceive(p)
register struct pbuf *p;
{
struct ether_header *ehp;
register struct ip *ip;
register struct udp *up;
register int l;
int wasbroad;
#ifdef EDATA
K_WAIT(20);
p_print("ierecv", p);
#endif EDATA
ehp = (struct ether_header *)p->p_off;
wasbroad = (ehp->ether_dhost.ether_addr_octet[0] & 0x1);
#ifdef SNMP
if (wasbroad)
mib_ifEntry[0].ifInNUcastPkts++;
else
mib_ifEntry[0].ifInUcastPkts++;
#endif SNMP
p->p_off += sizeof *ehp;
p->p_len -= sizeof *ehp;
switch (ntohs(ehp->ether_type)) {
case ETHERTYPE_ETHERTALK:
if (ifet.if_dnet == 0){
goto drop; /* ignore unless enabled */
}
source_if = &ifet; /* switch virtual interfaces */
abreceive(p);
return;
case ETHERTYPE_AARPTYPE:
source_if = &ifet;
/* fall through */
case ETHERTYPE_ARPTYPE:
arpinput(p); /* pass it to ARP */
return;
case ETHERTYPE_IPTYPE:
#ifdef SNMP
mib_ip.ipInReceives++;
#endif
break;
default:
#ifdef SNMP
mib_ifEntry[0].ifInUnknownProtos++;
#endif
goto drop; /* can't handle it */
}
/*
* If the proto type is IP/UDP and the port
* number is in the magic range, remove the
* encapsulation from the DDP datagram.
*/
ip = (struct ip *)p->p_off;
/* Checksum the IP header ? */
if (p->p_len < sizeof (*ip)){
#ifdef SNMP
mib_ip.ipInHdrErrors++;
#endif
goto drop;
}
if (conf.ready != confReady) {
/* if conf not ready, only process control packets */
if (ip->ip_dst != conf.ipaddr)
goto drop;
ip4me(p);
return;
}
if (ip->ip_p != IPPROTO_UDP || ip->ip_dst != conf.ipaddr)
goto toip;
l = (ip->ip_hl << 2);
up = (struct udp *)(p->p_off + l);
if (p->p_len < (l + sizeof(*up))){
#ifdef SNMP
mib_udp.udpInErrors++;
#endif
goto drop;
}
if ((up->dst >= ddpNWKSUnix + 128 && up->dst < ddpNWKSUnix + 256)
|| (up->dst >= ddpWKSUnix && up->dst < ddpWKSUnix + 128)) {
/* decapsulate */
#ifdef SNMP
mib_udp.udpInDatagrams++;
#endif
p->p_off += (l + sizeof(*up));
p->p_len -= (l + sizeof(*up));
/* route as ddp */
if (p->p_len < ddpSize + lapSize)
goto drop;
bcopy(p->p_off + lapSize, (caddr_t)&ddp, ddpSize);
l = (ddp.length & ddpLengthMask);
if (l < p->p_len - lapSize)
p->p_len = l + lapSize; /* zap padding */
wasddp = 1;
routeddp(p, source_if, wasbroad);
return;
}
toip:
routeip(p, source_if, wasbroad);
return;
drop:
/* sendf("Got bad IP packet"); */
stats.dropiein++;
/* put the buffer back on the free list */
K_PFREE(p);
return;
}
/*
* These match routines return 0 if no match and 1 (true) if a match occurs.
* They are called from arpinput/nbpinput to determine if an IP
* address is in our range.
*
* A 'true' return value causes the arpinput code to return a 'fake ARP'
* to the requester: i.e. the requester will think that the real destination
* host responded to the ARP, whereas it was really this gateway 'faking'
* a response.
*/
/*
* Match an AppleTalk ARP. If the target is not in my own
* range, return true (match). This has the effect of forwarding all
* traffic for 'unknown' nets, to the backbone ethernet.
*/
abmatch(target)
iaddr_t target;
{
register i;
if (target == conf.ipaddr)
return (1);
if (ipnetpart(target) == 0x7F000000)
return (0);
if (conf.ready != confReady)
return (0);
i = target - conf.ipaddr;
if (i < 0)
return (1);
if (i >= conf.ipstatic + conf.ipdynamic + 1)
return (1);
return (0);
}
/*
* Match an ethernet ARP.
*/
iematch(target)
iaddr_t target;
{
register i;
i = target - conf.ipaddr;
if (i == 0)
return (1);
if (conf.ready != confReady)
return (0);
if (i >= 0 && i <= conf.ipstatic + conf.ipdynamic)
return (1);
return (0);
}
/*
* Route an IP packet. This code currently assumes only one AppleTalk and
* ether interface per gateway; instead it should scan a list of interfaces.
* If a routing table existed within the gateway, it would determine
* which interface pointer (ifp) and destination address (dst below)
* are passed to ifp->if_output.
*/
routeip(p, srcif, br)
register struct pbuf *p;
struct ifnet *srcif; /* interface packet came in on */
{
register struct ifnet *ifp = &ifie; /* default output to ether */
register struct ip *ip = (struct ip *)p->p_off;
int dst = ip->ip_dst;
register iaddr_t dstnet = ipnetpart(dst);
/* omit any bytes past the ip data */
if (p->p_len > ip->ip_len) {
p->p_len -= (p->p_len - ip->ip_len);
}
if (dst == conf.ipaddr) {
ip4me(p);
return;
}
#ifdef SNMP
/* if not from me, I must be forwarding this */
if (ip->ip_src == conf.ipaddr)
mib_ip.ipOutRequests++;
else
mib_ip.ipForwDatagrams++;
#endif
if (iematch(dst))
ifp = &ifab;
else if (dstnet != ifie.if_addrnet
|| (ipbroadcast(dst) && dst != conf.ipbroad))
dst = conf.iproutedef; /* needs to be forwarded */
if (ifp != srcif) /* do not reflect packets to same net */
return((*ifp->if_output)(ifp, p, AF_IP, &dst));
drop:
K_PFREE(p);
stats.droprouteip++;
return;
}
/* IP directed broadcast types, used by 'routeddp' */
iaddr_t ipbroadtypes[] = { 0, 0xFF, 0xFFFF, 0xFFFFFF };
/*
* Route a DDP packet. Assumes ddp has already been unpacked into
* global struct ddp. If 'si' (source interface) is 0, packet
* originates inside the gateway; otherwise this is a forward.
* 'br' is true if the packet was received as a broadcast.
*/
routeddp(p, si, br)
register struct pbuf *p;
struct ifnet *si;
int br;
{
register struct udp *u;
register struct aroute *ar;
iaddr_t idst;
struct ifnet *ifp;
int wasbroadcast;
register i, port;
u_char dst;
if (ddp.dstNet == 0 || ddp.dstNode == 0)
goto drop;
if (p->p_len < (ddpSize + lapSize))
goto drop;
wasbroadcast = br && ddp.dstNode == 0xff; /* really broadcast? */
if (si && ddp.dstNet == si->if_dnet &&
(ddp.dstNode == si->if_dnode || wasbroadcast)) {
ddp4me(p);
return;
}
for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ar++) {
if (ar->net == 0) /* empty slot */
continue;
if (ar->net == ddp.dstNet && ar->port < MAX_PORT) {
if ((ifp = porttoif[ar->port]) == 0) /* nothing defined */
continue;
goto found;
}
}
goto drop; /* didnt find it */
found:
/*
* if this packet originates externally and is addressed
* to us (or broadcast), hand it to 'ddp4me'.
*/
if (ar->hops) /* if not one of our interfaces */
goto fwd;
/* net already matched, just check node */
if (wasbroadcast || ifp->if_dnode == ddp.dstNode) {
ddp4me(p);
return;
}
fwd:
if (((ddp.length >> ddpHopShift) & 0xF) == 0xF)
goto drop;
if (si) /* if not internally sent */
p->p_off[lapSize] += 4; /* increment hop count in pbuf */
fwd2:
if (br)
goto drop; /* dont forward broadcasts */
if (ddp.type == ddpNBP && ddp.dstSkt != nbpNIS) /* NBP reply filter */
if (nbpfilter(p))
goto drop;
if (ifp->if_flags & IF_APPLETYPE) {
/* your basic "LAP" or "ELAP" output routine */
i = AF_DDP; /* assume long ddp */
/* should collapse to short ddp if we can here (internal only) */
/* short ddp allowed on interface? (and internal?) */
if (!si && (ifp->if_flags & IF_ALAP))
if (ar->hops == 0 && ddp.srcNet == ddp.dstNet) {
/* primary interface and input/output net the same */
/* move ahead to ddp short boundary */
p->p_off += (ddpSize - ddpSSize);
p->p_len -= (ddpSize - ddpSSize);
ddps.srcSkt = ddp.srcSkt;
ddps.dstSkt = ddp.dstSkt;
ddps.type = ddp.type;
ddps.length = ddp.length - (ddpSize - ddpSSize);
bcopy((caddr_t)&ddps, p->p_off+lapSize, ddpSSize);
i = AF_SDDP;
}
dst = (ar->hops ? ar->node : ddp.dstNode);
(*ifp->if_output)(ifp, p, i, &dst);
return;
}
/*
paranoia
if ((ifp->if_flags & IF_IPUDP) == 0)
goto drop;
*/
/*
* Else destination is IP address, encapsulate.
* Choose the appropriate IP host or directed broadcast address.
*/
port = ddp2ipskt(ddp.dstSkt);
switch ((i=ar->flags & arouteTYPE)) {
default:
goto drop;
case arouteKbox:
idst = ar->node;
break;
case arouteNet:
case arouteHost:
if (ddp.dstNode != 0xFF) { /* not broadcast? */
idst = (ar->node & ~0xFF) + ddp.dstNode; /* nope */
break;
}
if (i == arouteNet) {
/* problematic sometimes : also conf.ipbroad should be set on */
/* ifp */
idst = (ddp.dstNet == ifp->if_dnet) ? conf.ipbroad :
ar->node + ipbroadtypes[ar->flags&arouteBMask];
} else {
idst = ar->node;
port = rebPort;
}
break;
}
lap.dst = 0xFA;
lap.src = 0xCE;
lap.type = lapDDP;
bcopy((caddr_t)&lap, p->p_off, lapSize);
p->p_off -= sizeof (struct ip) + sizeof *u;
p->p_len += sizeof (struct ip) + sizeof *u;
setiphdr(p, idst);
u = (struct udp *)(p->p_off + sizeof (struct ip));
u->src = ddp2ipskt(ddp.srcSkt);
u->dst = port;
u->length = p->p_len - sizeof (struct ip);
u->checksum = 0;
#ifdef SNMP
mib_udp.udpOutDatagrams++;
#endif
routeip(p, 0, 0);
return;
drop:
/*
K_WAIT(20);
sendf("routeddp: dropping packet");
*/
stats.droprouteddp++;
/* put the buffer back on the free list */
K_PFREE(p);
}
/*
* AppleTalk output routine.
* Encapsulate a packet of type af for the local net.
*
* Look at a normal net output routine (such as ethernet output, iloutput),
* for the more general case of an output routine which can handle
* multiple units (using the ifp->if_unit field) with interrupt driven
* output (and output queues).
*
* Also, normally an output routine prepends only the link
* level header (e.g. LAP). However this routine is a bit unusual:
*
* Since the LAP and DDP header sizes are both odd, DDP packets are
* usually passed about with both headers on the front, so that the
* data will always be on an even boundary.
*
* Since IPs are inside DDPs, we prefix a LAP/DDP header onto them.
*/
aboutput(ifp, p, af, dst)
register struct ifnet *ifp;
register struct pbuf *p;
caddr_t dst;
{
iaddr_t idst;
AddrBlock tdst;
struct LAP l;
struct DDP d;
WDS wds[2]; /* write data structure for abuswrite */
l.src = ifp->if_dnode; /* (also done as part of atwrite) */
switch (af) {
case AF_DDP: /* DDP: already has LAP header */
l.dst = *dst;
l.type = lapDDP;
bcopy((caddr_t)&l, p->p_off, lapSize);
break;
case AF_SDDP: /* ShortDDP: already has LAP header */
l.dst = *dst;
l.type = lapDDPS;
bcopy((caddr_t)&l, p->p_off, lapSize);
break;
case AF_IP:
idst = *(iaddr_t *)dst;
if (!arpresolve(ifp, p, &idst, &tdst))
return (0); /* if not yet resolved */
lapddp:
l.type = lapDDP;
d.length = p->p_len + ddpSize;
d.checksum = 0;
d.srcNet = ifp->if_dnet;
d.dstNet = tdst.net;
d.srcNode = ifp->if_dnode;
d.dstNode = tdst.node;
d.srcSkt = d.dstSkt = ddpIPSkt;
d.type = ddpIP;
if (tdst.net == ifp->if_dnet)
l.dst = tdst.node;
else if ((l.dst = getaroute(tdst.net)) == 0)
goto drop;
p->p_off -= (lapSize + ddpSize);
p->p_len += (lapSize + ddpSize);
bcopy((caddr_t)&l, p->p_off, lapSize);
bcopy((caddr_t)&d, p->p_off+lapSize, ddpSize);
break;
default:
#ifdef SNMP
/* in case panic calls snmp_trap() */
mib_ifEntry[0].ifOutErrors++;
#endif
panic("ab%d: can't handle af%d\n", ifp->if_unit, af);
}
wds[1].size = 0; /* terminate list */
wds[0].size = p->p_len;
wds[0].ptr = p->p_off;
#ifdef SNMP
mib_ifEntry[1].ifOutOctets += p->p_len;
#endif
K_ATWRITE(&wds[0]); /* appletalk write */
if (l.dst == 0xFF) { /* if was broadcast, give myself a copy */
#ifdef SNMP
mib_ifEntry[1].ifOutNUcastPkts++;
#endif
p->p_type = PT_ABUS;
/* oops, atwrite smashes src during xmit(?) */
p->p_off[1] = ifp->if_dnode;
K_PENQ(SPLIMP, pq, p);
return;
#ifdef SNMP
} else {
mib_ifEntry[1].ifOutUcastPkts++;
#endif
}
drop:
/* put the buffer back on the free list */
K_PFREE(p);
return;
}
/*
* Panic - fatal error
*/
/*VARARGS*/
panic(s,a,b,c)
{
short pri;
K_SPLIMP(&pri);
sendf("PANIC!");
sendf(s,a,b,c);
#ifdef STATS
ieprintstats();
abprintstats();
#endif STATS
K_ERR();
K_INIPROM();
K_RESET();
}
#ifdef STATS
/*
* Send AppleTalk statistics
*/
abprintstats()
{
register struct fp_abstats *ss;
ss = pvars.fpr_abstats;
K_WAIT(20);
sendf("appletalk stats: ints %d, in %d, out %d, crc %d, ovr %d",
ss->fpa_interrupts, ss->fpa_ipackets, ss->fpa_opackets,
ss->fpa_crc, ss->fpa_ovr);
K_WAIT(20);
sendf("iund %d, bad %d, coll %d", ss->fpa_iund, ss->fpa_bad,
ss->fpa_coll);
K_WAIT(20);
sendf("defer %d, idleto %d, nodata %d, ound %d, badddp %d, spur %d",
ss->fpa_defer, ss->fpa_idleto, ss->fpa_nodata, ss->fpa_ound,
ss->fpa_badddp, ss->fpa_spur);
}
dmpbf()
{
struct pbuf *qq;
int flag;
register struct fp_bufinfo *ss;
ss = pvars.fpr_bufs;
sendf("dump pbufs - pbndrops = %d",ss->fpb_pbndrops);
sendf("pfree: 0x%x", *(ss->fpb_pfree));
sendf(" pq: head = 0x%x, tail= 0x%x, len = %d", pq->pq_head,
pq->pq_tail, pq->pq_len);
sendf("sendq: head = 0x%x, tail= 0x%x, len = %d",sendq->pq_head,
sendq->pq_tail, sendq->pq_len);
for (flag = 0, qq = bufs;
qq < (struct pbuf *)(topram - ss->fpb_bsize + 1);
qq++, flag++) {
sendf("%d=0x%x: %d 0x%x",flag,qq,qq->p_type,qq->p_next);
}
}
p_print(s, p)
char *s;
register struct pbuf *p;
{
register u_char *cp = p->p_off;
register ii,jj;
char ll[256];
char *lp;
extern char tohex[];
sendf("(%s) addr 0x%x p_type %d, p_len %d, p_off 0x%x\n",
s, p, p->p_type, p->p_len, p->p_off);
ii = p->p_len > 64 ? 64 : p->p_len;
lp = ll;
for (jj = 0 ; jj < ii ; jj++) {
*lp++ = tohex[(*cp >> 4) & 0xF];
*lp++ = tohex[*cp++ & 0xF];
*lp++ = ' ';
}
*lp = '\0';
sendf(ll);
}
#endif STATS