Files
CAP/contrib/AsyncATalk/async.c
2015-03-18 22:05:00 +01:00

1346 lines
31 KiB
C

/*
* $Date: 1993/08/05 15:53:56 $
* $Header: /mac/src/cap60/contrib/AsyncATalk/RCS/async.c,v 2.2 1993/08/05 15:53:56 djh Rel djh $
* $Log: async.c,v $
* Revision 2.2 1993/08/05 15:53:56 djh
* change wait handling
*
* Revision 2.1 91/02/15 21:20:58 djh
* CAP 6.0 Initial Revision
*
* Revision 1.6 91/01/09 02:30:45 djh
* Back out of asynchronous NBP register to avoid core dumps ... :-(
*
* Revision 1.5 91/01/09 01:52:08 djh
* Add XON/XOFF packets for AsyncTerm DA, do NBP asynchronously
* to speedup the startup of the Chooser.
*
* Revision 1.4 91/01/05 02:25:47 djh
* General cleanup and additions for use with UAB and CAP 6.0
*
* Revision 1.3 90/07/10 18:16:19 djh
* Add support for AsyncTerm DA for simultaneous logins
* Alter speedTab entries for 19200 and 38400
*
* Revision 1.2 90/03/20 16:10:29 djh
* Fix stupid bug in speedTab contents.
*
* Revision 1.1 90/03/17 22:05:27 djh
* Initial revision
*
*
* async.c
*
* Asynchronous AppleTalk for CAP UNIX boxes.
* David Hornsby, djh@munnari.oz, August 1988
* Department of Computer Science.
* The University of Melbourne, Parkville, 3052
* Victoria, Australia.
*
* Copyright 1988, The University of Melbourne.
*
* You may use, modify and redistribute BUT NOT SELL this package provided
* that all changes/bug fixes are returned to the author for inclusion.
*
*
* Ref: Async Appletalk, Dr. Dobbs Journal, October 1987, p18.
* Original Async AppleTalk by:
*
* Rich Brown
* Manager of Special Products
* Dartmouth College
* Kiewit Computer Center
* Hanover, New Hampshire 03755
* 603/646-3648
*
* CAP by:
* Charlie Kim
* Academic Computing and Communications Group
* Centre for Computing Activities
* Columbia University
*
*
* If BROAD is defined, SINGLE USE is possible without running the
* associated asyncad daemon. (NB: async must then be setuid root).
*
* if SECURE is defined, the AsyncTerm DA connects directly to a
* shell (/bin/csh), otherwise it just uses /bin/login.
*
* WARNING!
* If your C compiler is brain-damaged and pads structures
* strangely, then this code may not work.
*
*/
#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <sgtty.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netat/appletalk.h>
#include "async.h"
struct aalap_hdr rx_aalap; /* AALAP receive buffer (WRT the Mac) */
struct aalap_hdr tx_aalap; /* AALAP xmit buffer (WRT the Mac) */
struct aalap_hdr rtx_aalap; /* RTMP AALAP xmit buffer (WRT the Mac) */
struct sockaddr_in sin; /* our UDP socket */
struct sockaddr_in sin_broad; /* our UDP socket for DDP broadcasts */
struct sgttyb sgttyb; /* terminal settings from ioctl() */
struct timeval timeout; /* select() timeout */
struct stat buf; /* for biff and mesg use */
/* various */
int s; /* a socket for UDP packets */
#ifdef BROAD
int s_broad; /* a socket for DDP broadcasts (via UDP)*/
#endif BROAD
int dstSkt; /* dynamic socket used at other end */
int skt; /* a DDP socket for NBP */
int fd; /* file desc. for control terminal */
int nfds; /* for select call */
int p; /* our pseudo TTY file descriptor */
int t; /* our "real" TTY file descriptor */
int closing; /* 2 CR's or NL's outside a frame */
/* Booleans */
int alarmed; /* need to send an RTMP packet */
int inFrame; /* currently within a received frame */
int maskIt; /* next char was escaped in input */
int linkUp; /* we have established a link */
int serOpen; /* shell has been started */
int serWait; /* character buffer other end full */
int debug; /* hmmmmm ... */
/* Network info */
u_char ourNode; /* 1 <= ourNode <= MAXNODE */
unsigned short ourNet; /* one net per CAP host (atalk.local) */
char ourZone[34]; /* our local zone (atalk.local) */
u_char bridgeNode; /* local Multigate KIP node number */
unsigned short bridgeNet; /* local Multigate KIP AppleTalk net # */
unsigned long bridgeIP; /* local Multigate KIP IP address */
/* more various */
u_char lastChar; /* the last char read on input */
char nbpObj[34]; /* the object we wish to register */
char *getlogin();
EntityName en;
/* externs from modified CAP routine openatalkdb() */
/* these are all in correct network byte order */
extern char async_zone[];
extern u_short async_net;
extern u_char bridge_node;
extern u_short bridge_net;
extern struct in_addr bridge_addr;
FILE *fopen(), *dbg; /* log file */
long timeForRTMP, now;
unsigned short crctbl[16] = { /* Async AppleTalk CRC lookup table */
0x0000, 0xcc01, 0xd801, 0x1400,
0xf001, 0x3c00, 0x2800, 0xe401,
0xa001, 0x6c00, 0x7800, 0xb401,
0x5000, 0x9c01, 0x8801, 0x4400
};
short speedTab[16] = { /* Bytes/sec for various sgtty speeds */
30, 30, 30, 30,
30, 30, 30, 30,
60, 120, 180, 240,
480, 960, 1920, 3840
};
main(argc, argv)
int argc;
char *argv[];
{
char *t;
long len;
fd_set readfds;
int i, cleanup();
timeForRTMP = now = serWait = 0;
debug = inFrame = maskIt = linkUp = serOpen = alarmed = FALSE;
while(--argc > 0 && (*++argv)[0] == '-')
for(t = argv[0]+1 ; *t != '\0' ; t++)
switch (*t) {
case 'd':
debug = TRUE;
break;
}
if(debug) dbg = fopen("asyncLog", "w");
readatalkdb("/etc/atalk.local");
/* select() timeout */
timeout.tv_sec = 2;
timeout.tv_usec = 0;
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
signal(SIGQUIT, cleanup);
signal(SIGTERM, cleanup);
/* setup the CAP stuff for NBP */
abInit(0);
nbpInit();
/* set terminal line to 8 bits, no parity, 1 stop, raw mode */
if(ioctl((fd=1),TIOCGETP,&sgttyb) != -1) {
sgttyb.sg_flags |= RAW; sgttyb.sg_flags &= ~ECHO;
ioctl(fd, TIOCSETP, &sgttyb);
sgttyb.sg_flags &= ~RAW; sgttyb.sg_flags |= ECHO;
}
/* turn off 'biff' mail notification and 'mesg' delivery */
if(fstat(fd, &buf) == 0) {
buf.st_mode &= ~0122; /* go-w, u-x */
fchmod(fd, buf.st_mode);
buf.st_mode |= 0122; /* go+w, u+x */
}
if((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
fprintf(stderr, "Couldn't open UDP socket\n");
cleanup();
}
len = 6 * 1024; /* should be enough ?? */
if(setsockopt(s,SOL_SOCKET,SO_RCVBUF,(char *)&len,sizeof(long))!=0){
fprintf(stderr, "Couldn't set socket options\n");
cleanup();
}
#ifdef BROAD
if((s_broad = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
fprintf(stderr, "Couldn't open broadcast UDP socket\n");
cleanup();
}
sin_broad.sin_port = htons(aaBroad);
if(bind(s_broad, (caddr_t) &sin_broad, sizeof(sin_broad), 0) < 0) {
fprintf(stderr, "Couldn't bind broadcast UDP port\n");
cleanup();
}
#endif BROAD
skt = 0;
if(DDPOpenSocket(&skt, 0L) != noErr) {
fprintf(stderr, "Couldn't open a DDP socket\n");
cleanup();
}
nfds = 16;
if(debug) write(1, "Debug ON.\r\n", 11);
/* announce success */
write(1, "Connected ...\r\n", 15);
sleep(1);
/* send something innocuous to make the login window go away */
write(1, GOAWAY, 4);
sleep(1);
time(&now);
timeForRTMP = now + RTMPTIME;
for( ; ; ) {
if(debug) fflush(dbg);
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(s, &readfds);
#ifdef BROAD
FD_SET(s_broad, &readfds);
#endif BROAD
if(serOpen)
FD_SET(p, &readfds);
if(select(nfds, &readfds, (fd_set *) 0, (fd_set *) 0,
(struct timeval *) &timeout) > 0) {
if(FD_ISSET(0, &readfds))
doAALAPRead(&rx_aalap);
if(FD_ISSET(s, &readfds))
doDDPRead(&tx_aalap);
#ifdef BROAD
if(FD_ISSET(s_broad, &readfds))
doDDPRead_broad(&tx_aalap);
#endif BROAD
if(serOpen && !serWait && FD_ISSET(p, &readfds))
doShellRead(&tx_aalap);
}
if(linkUp) {
time(&now);
if(now > timeForRTMP) {
sendRTMP();
timeForRTMP = now + RTMPTIME;
}
}
}
}
/*
* send a UR frame back to the Mac
* (rx_aalap has the corresponding IM frame)
*
*/
sendUR(rx_aalap)
struct aalap_hdr *rx_aalap;
{
struct aalap_imur *imur;
unsigned short checkNet();
u_char checkNode();
if(rx_aalap->aalap_datalen != 3)
return; /* drop it */
/* ensure the frame has the right stuff */
imur = (struct aalap_imur *) rx_aalap->aalap_data;
rx_aalap->aalap_frame = (u_char) FrameChar;
rx_aalap->aalap_datalen = 3;
imur->aalap_net = htons(checkNet(imur->aalap_net));
imur->aalap_node = checkNode(imur->aalap_node);
if(debug) {
fprintf(dbg, "Received IM/Sent UR\n");
fprintf(dbg, "Suggested Node = %02x, Net = %04x\n",
imur->aalap_node, ntohs(imur->aalap_net));
}
doAALAPWrite(rx_aalap, URType); /* does checksum & trailing frame */
}
/*
* receive a UR frame and check it ...
*
*/
recvUR(rx_aalap)
struct aalap_hdr *rx_aalap;
{
struct aalap_imur *imur;
if(rx_aalap->aalap_datalen != 3)
return; /* drop it */
imur = (struct aalap_imur *) rx_aalap->aalap_data;
if(debug) {
fprintf(dbg, "Received UR\n");
fprintf(dbg,
"ourNode=%02x, theirNode=%02x, ourNet=%04x, theirNet=%04x\n",
ourNode, imur->aalap_node, ourNet, ntohs(imur->aalap_net));
}
if(ourNet == ntohs(imur->aalap_net) && ourNode == imur->aalap_node)
linkUp = TRUE;
else
if(ourNode == 0) {
if(checkNode(imur->aalap_node) == imur->aalap_node)
sendIM(rx_aalap);
} else
if(imur->aalap_node == ourNode)
sendIM(rx_aalap);
}
/*
* send an IM frame to the Mac
*
*/
sendIM(tx_aalap)
struct aalap_hdr *tx_aalap;
{
struct aalap_imur *imur;
unsigned short net;
if(debug) fprintf(dbg, "Sending IM\n");
/* ensure the frame has the right stuff */
tx_aalap->aalap_frame = (u_char) FrameChar;
tx_aalap->aalap_datalen = 3;
imur = (struct aalap_imur *) tx_aalap->aalap_data;
imur->aalap_net = htons(ourNet);
imur->aalap_node = ourNode;
doAALAPWrite(tx_aalap, IMType); /* does checksum & trailing frame */
}
/*
* we have to process a short DDP packet which could be:
* an RTMP request: (dst socket=1, DDP type=5, Command=1)
* respond locally
* an NBP lookup: (dst socket=2, DDP type = 2)
* repackage as long DDP and forward to gateway
* a ZIP query: (dst socket=6, DDP type=6)
* not implemented (yet)
* a ZIP/ATP Zone query: (dst socket=6, DDP type=3)
* GZL: repackage as long DDP and forward to gateway, watch
* for the return packet and repackage it as a short DDP
* GMZ: respond locally
*
*/
processShort(rx_aalap)
struct aalap_hdr *rx_aalap;
{
char *q;
int reqType;
unsigned short len, newlen, getMyZone();
struct sddp *sddp, *sddptx;
struct atp *atp, *atptx;
struct ddp *ddptx;
sddp = (struct sddp *) rx_aalap->aalap_data;
switch (sddp->ddp_type) {
case DDP_RTMP_R: /* process locally */
q = (char *) sddp->ddp_data;
if(sddp->ddp_dstSkt == RTMP_SKT && *q == 1/* command */) {
linkUp = TRUE;
sendRTMP();
}
break;
case DDP_NBP:
if(sddp->ddp_dstSkt == NBP_SKT) {
len = (ntohs(sddp->hop_and_length)&0x03ff) + 8;
tx_aalap.aalap_frame = (u_char) FrameChar;
tx_aalap.aalap_type = DDPType;
tx_aalap.aalap_datalen = len;
ddptx = (struct ddp *) tx_aalap.aalap_data;
ddptx->hop_and_length = htons(len);
ddptx->ddp_checksum = 0;
ddptx->ddp_dstNet = htons(bridgeNet);
ddptx->ddp_srcNet = htons(ourNet);
ddptx->ddp_dstNode = bridgeNode;
ddptx->ddp_srcNode = ourNode;
ddptx->ddp_dstSkt = sddp->ddp_dstSkt;
ddptx->ddp_srcSkt = sddp->ddp_srcSkt;
ddptx->ddp_type = sddp->ddp_type;
if((newlen = len - 13) < 0)
newlen = 0;
bcopy(sddp->ddp_data,ddptx->ddp_data,newlen);
doDDPWrite(&tx_aalap);
}
break;
case DDP_ATP:
if(sddp->ddp_dstSkt == ZIP_SKT) { /* ZIP GMZ/GZL req */
atp = (struct atp *) sddp->ddp_data;
reqType = atp->atp_user1;
switch (reqType) {
case ATP_GMZ: /* GetMyZone */
tx_aalap.aalap_frame = (u_char) FrameChar;
tx_aalap.aalap_type = SDDPType;
sddptx = (struct sddp *) tx_aalap.aalap_data;
sddptx->ddp_dstSkt = sddp->ddp_srcSkt;
sddptx->ddp_srcSkt = ZIP_SKT;
sddptx->ddp_type = DDP_ATP;
atptx = (struct atp *) sddptx->ddp_data;
atptx->atp_command = ATP_CMD;
atptx->atp_bitseq = ATP_SEQ;
/* bludgeon through alignment problems */
bcopy(&atp->atp_transid,&atptx->atp_transid,2);
atptx->atp_user1 = 0;
atptx->atp_user2 = 0;
atptx->atp_user3 = 0;
atptx->atp_user4 = 1; /* one zone name */
q = (char *) atptx->atp_data;
len = getMyZone(q) + 13;
tx_aalap.aalap_datalen = len;
sddptx->hop_and_length = htons(len);
doAALAPWrite(&tx_aalap, SDDPType);
break;
case ATP_GZL: /* GetZoneList */
len = (ntohs(sddp->hop_and_length)&0x03ff) + 8;
tx_aalap.aalap_frame = (u_char) FrameChar;
tx_aalap.aalap_type = DDPType;
tx_aalap.aalap_datalen = len;
ddptx = (struct ddp *) tx_aalap.aalap_data;
ddptx->hop_and_length = htons(len);
ddptx->ddp_checksum = 0;
ddptx->ddp_dstNet = htons(bridgeNet);
ddptx->ddp_srcNet = htons(ourNet);
ddptx->ddp_dstNode = bridgeNode;
ddptx->ddp_srcNode = ourNode;
ddptx->ddp_dstSkt = sddp->ddp_dstSkt;
ddptx->ddp_srcSkt = sddp->ddp_srcSkt;
ddptx->ddp_type = sddp->ddp_type;
if((newlen = len - 13) < 0)
newlen = 0;
bcopy(sddp->ddp_data,ddptx->ddp_data,newlen);
doDDPWrite(&tx_aalap);
break;
default:
if(debug)
fprintf(dbg,"Illegal request id=%d\n",reqType);
break;
}
}
break;
case DDP_ZIP: /* Not yet implemented */
break;
case SERIALType:/* pass to a shell */
processSerial(rx_aalap);
break;
default:
if(debug)
fprintf(dbg, "Unknown short DDP = %d\n",sddp->ddp_type);
break;
}
}
/*
* we have had a LAP packet of SERIALType, process it ...
*
*/
processSerial(rx_aalap)
struct aalap_hdr *rx_aalap;
{
int startShell();
struct sddp *sddp;
short len;
sddp = (struct sddp *) rx_aalap->aalap_data;
switch (sddp->ddp_data[0]) {
case SB_OPEN:
if(serOpen) {
write(p, "exit\n", 5);
close(p);
}
serOpen = startShell();
dstSkt = sddp->ddp_srcSkt;
break;
case SB_DATA:
len = (ntohs(sddp->hop_and_length)&0x03ff) - 6;
if(serOpen) write(p, sddp->ddp_data+1, len);
serWait = 0;
break;
case SB_CLOSE:
write(p, "exit\n", 5);
close(p);
serOpen = 0;
break;
case SB_XOFF:
serWait = 1;
break;
case SB_XON:
serWait = 0;
break;
default:
break;
}
}
/*
* start up a Shell to process bytes in special DDP packets.
*
*/
int
startShell()
{
int on = 1;
int pid, i;
int funeral();
char *line;
char c;
if(debug) fprintf(dbg, "Opening a Shell ...\n");
/* find and open a pseudo TTY */
p = -1;
for(c = 'p' ; c < 's' ; c++) {
struct stat statb;
line = "/dev/ptyZZ";
line[strlen("/dev/pty")] = c;
line[strlen("/dev/ptyZ")] = '0';
if(stat(line, &statb) < 0)
break;
for(i = 0 ; i < 16 ; i++) {
line[strlen("/dev/ptyZ")] = "0123456789abcdef"[i];
if((p = open(line, 2)) >= 0)
break;
}
if(p >= 0)
break;
}
if(p < 0) {
if(debug) fprintf(dbg, "Failed to open pty\n");
return(0);
}
if((pid = fork()) == 0) { /* in child */
close(p);
close(0);
close(1);
close(2);
/* dissassociate from our controlling TTY */
if((t = open("/dev/tty", 2)) >= 0) {
ioctl(t, TIOCNOTTY, 0);
setpgrp(0, 0);
close(t);
}
/* open the pseudo TTY */
line[strlen("/dev/")] = 't';
if((t = open(line, 2)) < 0) {
if(debug) fprintf(dbg, "Failed to open tty\n");
exit(1);
}
/* set nice modes */
{ struct sgttyb b;
gtty(t, &b);
b.sg_flags = ECHO|CRMOD;
stty(t, &b);
}
dup(t); /* stdout */
dup(t); /* stderr */
#ifndef SECURE
execl("/bin/login", "login", 0);
#else SECURE
execl("/bin/csh", "-asyncsh", 0);
#endif SECURE
exit(1); /* o, oh */
}
/* parent */
if(pid == -1)
return(0);
ioctl(p, FIONBIO, &on); /* non blocking */
signal(SIGTSTP, SIG_IGN);
signal(SIGCHLD, funeral);
return(1);
}
/*
* write this out as a UDP encapsulated DDP packet
*
*/
doDDPWrite(rx_aalap)
struct aalap_hdr *rx_aalap;
{
int length;
struct ap ap;
struct ddp *ddp;
ap.ldst = 0xFA; /* magic */
ap.lsrc = 0xCE; /* magic */
ap.ltype = DDPType;
ddp = (struct ddp *) rx_aalap->aalap_data;
length = rx_aalap->aalap_datalen;
bcopy(rx_aalap->aalap_data, ap.dd, length);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = bridgeIP; /* Gateway */
if(bridgeIP == inet_addr("127.0.0.1")) /* using UAB */
sin.sin_port = (word) htons(750);
else
sin.sin_port = (word) htons(ddp2ipskt(ddp->ddp_dstSkt));
length += 3;
if(debug) {
fprintf(dbg, "DDPWrite: ");
dumppacket(rx_aalap, 0);
}
if(sin.sin_port == 0) {
if(debug) fprintf(dbg, "Couldn't find the gateway UDP port\n");
return; /* drop it, do nothing */
}
if(sendto(s, (caddr_t) &ap, length, 0, &sin, sizeof(sin)) != length) {
if(debug) fprintf(dbg, "Couldn't write to the gateway\n");
return; /* drop it, do nothing */
}
}
/*
* write a frame out the serial port
*
*/
doAALAPWrite(tx_aalap, type)
struct aalap_hdr *tx_aalap;
u_char type;
{
struct aalap_trlr *trlr;
unsigned short doCRC(), crc;
unsigned char buf[2 * (AALAP + 3)];
u_char *q;
int i, j;
tx_aalap->aalap_frame = FrameChar;
tx_aalap->aalap_type = type;
q = (u_char *) tx_aalap->aalap_data;
trlr = (struct aalap_trlr *) (q + tx_aalap->aalap_datalen);
crc = doCRC(tx_aalap, (int) tx_aalap->aalap_datalen);
/* bludgeon through alignment problems */
bcopy(&crc, &trlr->aalap_crc, 2);
trlr->aalap_frame = FrameChar;
if(debug) dumppacket(tx_aalap, 0);
j = 0;
/* FrameChar and Type */
buf[j++] = tx_aalap->aalap_frame;
buf[j++] = tx_aalap->aalap_type;
/* body including CRC */
for(i = 0 ; i < (tx_aalap->aalap_datalen + 2) ; i++, q++) {
switch (*q) {
case FrameChar:
case DLEChar:
case XONChar1:
case XONChar2:
case XOFFChar1:
case XOFFChar2:
buf[j++] = DLEChar;
buf[j++] = *q ^ XOR;
break;
default:
buf[j++] = *q;
break;
}
}
/* Trailing FrameChar */
buf[j++] = trlr->aalap_frame;
/* send it */
write(1, buf, j);
}
/*
* process serial chars from the Mac
*
*/
doAALAPRead(rx_aalap)
struct aalap_hdr *rx_aalap;
{
int i, j, len;
unsigned char buf[AALAP+5];
unsigned short doCRC();
len = read(0, buf, AALAP+5);
for(i = 0 ; i < len ; i++ ) {
if(buf[i] == lastChar && buf[i] == FrameChar) /* recover */
inFrame = FALSE;
lastChar = buf[i];
if(!inFrame) {
switch (buf[i]) {
case FrameChar:
inFrame = TRUE;
rx_aalap->aalap_frame = buf[i];
rx_aalap->aalap_type = (u_char) 0;
rx_aalap->aalap_framecomplete = FALSE;
rx_aalap->aalap_datalen = 0;
closing = 0;
continue;
break;
case CR: /* 2 CR's or NL's outside the frame */
case NL: /* closes the async connection. */
case CRP: /* CR with parity bit set */
case NLP: /* NL with parity bit set */
if(++closing >= 2)
cleanup();
continue;
break;
default:
closing = 0;
continue;
break;
}
} else {
closing = 0;
/* we are in a valid frame */
switch (buf[i]) {
case FrameChar: /* end of frame */
rx_aalap->aalap_data[rx_aalap->aalap_datalen]
= buf[i];
rx_aalap->aalap_datalen -= 2; /* CRC */
if((j=doCRC(rx_aalap,rx_aalap->aalap_datalen+2))
|| rx_aalap->aalap_datalen < 0
|| rx_aalap->aalap_datalen > AALAP) {
rx_aalap->aalap_datalen = 0;
if(debug)fprintf(dbg,"Bogus pkt %s\n",
(j==0) ? "Length" : "CRC");
} else
rx_aalap->aalap_framecomplete = TRUE;
inFrame = FALSE;
break;
case DLEChar: /* an escaped character follows */
maskIt = TRUE;
continue;
break;
case XONChar1:
case XONChar2:
case XOFFChar1:
case XOFFChar2:
if(debug) fprintf(dbg, "Received %s\n",
(buf[i]&0x7f)==XONChar1?"XON":"XOFF");
/* not yet implemented */
continue;
break;
default:
if(rx_aalap->aalap_datalen == 0
&& rx_aalap->aalap_type == 0
&& (buf[i]==IMType
|| buf[i]==URType
|| buf[i]==SDDPType
|| buf[i]==DDPType)) {
rx_aalap->aalap_type = buf[i];
continue;
break;
}
if(maskIt) {
buf[i] = buf[i] ^ XOR;
maskIt = FALSE;
}
rx_aalap->aalap_data[rx_aalap->aalap_datalen]
= buf[i];
rx_aalap->aalap_datalen++;
continue;
break;
}
}
if(rx_aalap->aalap_framecomplete) {
if(debug) dumppacket(rx_aalap, 1);
switch (rx_aalap->aalap_type) {
case IMType: /* we're being probed */
sendUR(rx_aalap); /* always send */
break;
case URType:
recvUR(rx_aalap);
break;
case SDDPType: /* a short DDP packet */
processShort(rx_aalap);
break;
case DDPType: /* send it out on DDP */
doDDPWrite(rx_aalap);
break;
default: /* drop it */
if(debug) fprintf(dbg,"Unknown: %02x\n",
rx_aalap->aalap_type);
break;
}
rx_aalap->aalap_framecomplete = FALSE;
rx_aalap->aalap_datalen = 0;
}
}
}
/*
* get and process DDP packet destined for the Mac
* NB: the packets aren't really from the DDP interface
* AppleTalk gateways (EG: Multigate) direct packets
* to the UDP port (PortOffset+node#)
*
* If the packet is an ATP pkt destined for the ZIP socket,
* we have to munge the packet into a short DDP to send back
* to the mac, otherwise it is ignored. Stupid Protocol.
*
*/
doDDPRead(tx_aalap)
struct aalap_hdr *tx_aalap;
{
struct ap ap;
unsigned short junk;
int zipped; /* junk */
tx_aalap->aalap_framecomplete = FALSE;
tx_aalap->aalap_datalen = (short) read(s, (char *) &ap, sizeof(ap));
if(ap.ldst == 0xFA && ap.lsrc == 0xCE && ap.ltype == 2) {
if(ap.srcskt == ZIP_SKT && ap.type == DDP_ATP) {
tx_aalap->aalap_datalen -= 11;
if(tx_aalap->aalap_datalen < 0)
tx_aalap->aalap_datalen = 0;
bcopy(ap.dd+10, tx_aalap->aalap_data+2,
(int) tx_aalap->aalap_datalen);
/* bludgeon through alignment problems */
bcopy(ap.dd, &junk, 2);
junk = ntohs(junk) - 8;
junk = htons(junk);
bcopy(&junk, tx_aalap->aalap_data, 2);
zipped = TRUE;
} else {
tx_aalap->aalap_datalen -= 3;
if(tx_aalap->aalap_datalen < 0)
tx_aalap->aalap_datalen = 0;
bcopy(ap.dd, tx_aalap->aalap_data,
(int) tx_aalap->aalap_datalen);
zipped = FALSE;
}
tx_aalap->aalap_framecomplete = TRUE;
} else
tx_aalap->aalap_datalen = 0;
if(debug) {
fprintf(dbg,"DDPRead: ");
dumppacket(tx_aalap, 1);
}
if(tx_aalap->aalap_framecomplete) {
if(shouldSendRTMP(tx_aalap->aalap_datalen))
sendRTMP();
doAALAPWrite(tx_aalap, (zipped) ? SDDPType : DDPType);
tx_aalap->aalap_framecomplete = FALSE;
tx_aalap->aalap_datalen = 0;
}
}
#ifdef BROAD
doDDPRead_broad(tx_aalap)
struct aalap_hdr *tx_aalap;
{
struct ap ap;
tx_aalap->aalap_framecomplete = FALSE;
tx_aalap->aalap_datalen = read(s_broad, (char *) &ap, sizeof(ap));
if(ap.ldst == 0xFA && ap.lsrc == 0xCE && ap.ltype == 2) {
tx_aalap->aalap_datalen -= 3;
if(tx_aalap->aalap_datalen < 0)
tx_aalap->aalap_datalen = 0;
bcopy(ap.dd, tx_aalap->aalap_data, tx_aalap->aalap_datalen);
tx_aalap->aalap_framecomplete = TRUE;
} else
tx_aalap->aalap_datalen = 0;
if(debug) {
fprintf(dbg,"DDPRead (broad): ");
dumppacket(tx_aalap, 1);
}
if(tx_aalap->aalap_framecomplete) {
if(shouldSendRTMP(tx_aalap->aalap_datalen))
sendRTMP();
doAALAPWrite(tx_aalap, DDPType);
tx_aalap->aalap_framecomplete = FALSE;
tx_aalap->aalap_datalen = 0;
}
}
#endif BROAD
/*
* read from the shell we have forked, send it to our user
*
*/
doShellRead(tx_aalap)
struct aalap_hdr *tx_aalap;
{
short len;
struct sddp *sddp;
sddp = (struct sddp *) tx_aalap->aalap_data;
tx_aalap->aalap_framecomplete = TRUE;
if((len = read(p, (char *)sddp->ddp_data+1, 512)) <= 0)
return(0);
len += 6;
tx_aalap->aalap_datalen = len;
sddp->hop_and_length = htons(len);
sddp->ddp_dstSkt = dstSkt;
sddp->ddp_srcSkt = SERIALType;
sddp->ddp_type = SERIALType;
sddp->ddp_data[0] = SB_DATA;
if(debug) {
fprintf(dbg,"ShellRead: ");
dumppacket(tx_aalap, 1);
}
if(tx_aalap->aalap_framecomplete) {
if(shouldSendRTMP(tx_aalap->aalap_datalen))
sendRTMP();
doAALAPWrite(tx_aalap, SDDPType);
tx_aalap->aalap_framecomplete = FALSE;
tx_aalap->aalap_datalen = 0;
}
}
/*
* if we are about to send a packet, check to see
* if the time to send it will make our next RTMP
* late (Yes, this is really necessary !).
*
*/
int
shouldSendRTMP(len)
short len;
{
short i, ptime;
i = sgttyb.sg_ospeed;
if(i >= 0 && i < sizeof(speedTab)/sizeof(short)) {
ptime = (len/speedTab[i]) + 1;
time(&now);
if(now+ptime > timeForRTMP) {
timeForRTMP = now + RTMPTIME;
return(1);
}
}
return(0);
}
/*
* Try to accomodate their wishes for a node number
* (this might be a re-connect)
*
*/
u_char
checkNode(node)
u_char node;
{
if(ourNode != node) {
sin.sin_port = htons(PortOffset + node);
if(bind(s, (caddr_t) &sin, sizeof(sin), 0) < 0) {
if(debug) fprintf(dbg,
"Requested node number %x in use\n", node);
return(ourNode);
}
if(debug) fprintf(dbg, "Mac requested node number %x\n", node);
/* requested node number is OK with me */
ourNode = node;
#ifndef BROAD
notify(UP); /* tell asyncad daemon we are here */
#endif BROAD
sprintf(nbpObj, "%s#%d", getlogin(), ourNode & 0xff);
strncpy(en.objStr.s, nbpObj, sizeof(en.objStr.s));
strncpy(en.typeStr.s, NBPTYPE, sizeof(en.typeStr.s));
strncpy(en.zoneStr.s, ZONE, sizeof(en.zoneStr.s));
nbp_remove(&en); /* if one already running */
nbp_register(&en, skt); /* synchronous */
}
return(ourNode);
}
/*
* Return our network number no matter what they want
*
*/
unsigned short
checkNet(net)
short net;
{
return(ourNet);
}
/*
* return number of chars in our zone name (from atalk.local)
* copy zone name and length byte to q (pascal string)
*
*/
unsigned short
getMyZone(q)
char *q;
{
int i;
i = strlen(ourZone);
*q = (u_char) i;
bcopy(ourZone, q+1, i);
return((unsigned short) i+1);
}
/*
* read the atalk data file '/etc/atalk.local'
*
* for now, save effort by using a slightly modified
* version of the CAP routine openatalkdb(). If using
* CAP 6.0 or greater, this is all handled automagically.
*
*/
readatalkdb(db)
char *db;
{
#ifndef CAP_6_DBM
openatalkdb(db); /* CAP routine in atalkdbm.c */
#else CAP_6_DBM
{ extern short lap_proto;
if(lap_proto == LAP_KIP)
openatalkdb(db);
else
openetalkdb(NULL); /* use the default */
}
#endif CAP_6_DBM
ourNode = 0;
ourNet = ntohs(async_net);
strncpy(ourZone, async_zone, strlen(async_zone));
bridgeNode = bridge_node;
bridgeNet = ntohs(bridge_net);
bridgeIP = bridge_addr.s_addr;
if(debug) {
fprintf(dbg, "ourNode=%02x, ourNet=%02x, ourZone=%s\n",
ourNode, ourNet, ourZone);
fprintf(dbg, "bridgeNode=%02x, bridgeNet=%02x, brIP=%04x\n",
bridgeNode, bridgeNet, ntohl(bridgeIP));
}
}
/*
* send an RTMP packet
* 1. in response to a request
* 2. synchronously every ~RTMPTIME seconds to keep the link up
*
*/
sendRTMP()
{
struct sddp *sddptx;
struct rtmp *rtmp;
unsigned short senderNet;
rtx_aalap.aalap_frame = (u_char) FrameChar;
rtx_aalap.aalap_datalen = 9;
sddptx = (struct sddp *) rtx_aalap.aalap_data;
sddptx->hop_and_length = htons(9);
sddptx->ddp_dstSkt = RTMP_SKT;
sddptx->ddp_srcSkt = RTMP_SKT;
sddptx->ddp_type = DDP_RTMP_D;
rtmp = (struct rtmp *) sddptx->ddp_data;
senderNet = htons(ourNet);
/* bludgeon through alignment problems */
bcopy(&senderNet, &rtmp->rtmp_senderNet, 2);
rtmp->rtmp_idLen = NBitID;
rtmp->rtmp_senderId = bridgeNode;
doAALAPWrite(&rtx_aalap, SDDPType);
}
/*
* Dump the contents of an AALAP packet
*
*/
dumppacket(ax_aalap, dirn)
struct aalap_hdr *ax_aalap;
int dirn;
{
struct aalap_trlr *trlr;
char *q;
int i, len;
/* Heading */
fprintf(dbg, "%s: len=0x%02x, pkt=",
(dirn) ? "IN" : "\tOUT", ax_aalap->aalap_datalen);
q = (char *) ax_aalap->aalap_data;
trlr = (struct aalap_trlr *) (q + ax_aalap->aalap_datalen);
/* Frame and type */
fprintf(dbg, "%02x %02x ", ax_aalap->aalap_frame, ax_aalap->aalap_type);
#ifdef ALLPACKET
/* body including CRC */
for(i = 0 ; i < (ax_aalap->aalap_datalen + 2) ; i++, q++)
fprintf(dbg, "%02x ", (*q & 0xff));
/* trailing frame */
fprintf(dbg, "%02x\n", trlr->aalap_frame);
#else ALLPACKET
len = ax_aalap->aalap_datalen + 2;
if(len > 21) len = 21; /* just enough to cover ATP header */
for(i = 0 ; i < len ; i++, q++)
fprintf(dbg, "%02x ", (*q & 0xff));
if(len == ax_aalap->aalap_datalen+2)
fprintf(dbg, "%02x\n", trlr->aalap_frame);
else
fprintf(dbg, "\n");
#endif ALLPACKET
fflush(dbg);
}
/*
* calculate CRC
* (if we want to check the CRC, set len to the data length
* plus 2 to include the packet CRC, the result should be 0)
*
* NB: this algorithm calculates the CRC in network byte order on
* machines that are not network byte order and vice-versa.
* Hence the crap at the end.
*
*/
unsigned short
doCRC(aalap, len)
struct aalap_hdr *aalap;
register int len;
{
register int c;
register int crc;
register int index;
register char *q;
unsigned short result;
crc = 0;
q = (char *) &aalap->aalap_type;
while(len-- >= 0) { /* include type */
c = *q++;
index = c ^ crc;
index &= 0x0f;
crc >>= 4;
crc ^= crctbl[index];
c >>= 4;
c ^= crc;
c &= 0x0f;
crc >>= 4;
crc ^= crctbl[c];
}
result = (unsigned short) (crc & 0xffff);
if(result == htons(result)) /* on a network byte order machine */
result = ((crc & 0xff00) >> 8) | ((crc & 0xff) << 8);
return(result & 0xffff);
}
/*
* unregister an NBP name
*
*/
nbp_remove(en)
EntityName *en;
{
return(NBPRemove(en));
}
/*
* register an NBP name
*
*/
nbp_register(en, skt)
EntityName *en;
int skt;
{
nbpProto nbpr; /* nbp proto */
NBPTEntry nbpt[1]; /* table of entity names */
nbpr.nbpAddress.skt = skt;
nbpr.nbpRetransmitInfo.retransInterval = 5;
nbpr.nbpRetransmitInfo.retransCount = 3;
nbpr.nbpBufPtr = nbpt;
nbpr.nbpBufSize = sizeof(nbpt);
nbpr.nbpDataField = 1; /* max entries */
nbpr.nbpEntityPtr = en;
return((int) NBPRegister(&nbpr,FALSE)); /* try synchronous */
}
#ifndef BROAD
/*
* notify asyncad daemon of a change in state
* UP | DOWN
*
*/
notify(state)
int state;
{
struct ap ap;
char hostname[64];
struct hostent *host, *gethostbyname();
ap.ldst = 0xC0; /* MAGIC */
ap.lsrc = 0xDE; /* MAGIC */
ap.ltype = (u_char) state;
ap.srcskt = ourNode;
sin_broad.sin_family = AF_INET;
sin_broad.sin_port = htons(aaBroad);
gethostname(hostname, sizeof(hostname));
host = gethostbyname(hostname);
bcopy(host->h_addr, &sin_broad.sin_addr.s_addr,
sizeof(sin_broad.sin_addr.s_addr));
if(debug) fprintf(dbg, "Sent %s message to: %s (%08x) on port %d\n",
(state==UP) ? "UP" : "DOWN", hostname,
htonl(sin_broad.sin_addr.s_addr),
ntohs(sin_broad.sin_port));
if(sendto(s, (caddr_t)&ap, 16, 0, &sin_broad,sizeof(sin_broad)) != 16) {
if(debug) fprintf(dbg, "Couldn't tell asyncad we exist\n");
cleanup();
}
}
#endif BROAD
/*
* reset things to a natural state
*
*/
cleanup()
{
nbp_remove(&en);
#ifndef BROAD
notify(DOWN);
#endif BROAD
ioctl(fd, TIOCSETP, &sgttyb);
fchmod(fd, buf.st_mode);
if(debug) fclose(dbg);
if(serOpen) close(p);
exit(1);
}
int
funeral()
{
WSTATUS junk;
serOpen = 0;
#ifdef POSIX
while( waitpid(-1, &junk, WNOHANG) > 0 )
;
#else POSIX
#ifndef NOWAIT3
while( wait3(&junk, WNOHANG, 0) > 0 )
;
#else NOWAIT3
wait(&junk); /* assume there is at least one process to wait for */
#endif NOWAIT3
#endif POSIX
close(p);
}