Category : C Source Code
Archive   : TEL2307S.ZIP
Filename : DNDLL.C

 
Output of file : DNDLL.C contained in archive : TEL2307S.ZIP

/* 1152, Wed 29 Aug 90

DNDLL: DECnet DLL driver for NCSA TELNET

This driver allows TELNET to work through the DECNET-DOS
Datalink Layer, using the DLL interface documented in the
VAXmate Technical Reference Manual Volume 2, AA-HD95A-TK.

Support for DECNET-DOS is provided on the PC by a set of TSRs.
The minimum set of these is just SCH (the DECnet process scheduler)
and DLL (the Datalink Layer driver). Other TSRs can be loaded
into memory to provide other services, e.g. LAT (Local Area Transport)
and DNP (DECNET).

DEC supply (as part of DECNET-DOS) DLL drivers for their own
ethernet card (the DEPCA), and a range of other cards from
MICOM and 3COM. DLL drivers for the Western Digital 8003 card
(marketed here in New Zealand as the Amtec Ethercard) are also
available. This TELNET driver will work with any of the DLL
drivers - I have tested it with the WD8003 as well as the DEPCA.

DLL allows you to open a 'portal' to ethernet, specifying which
protocol id it will carry. Any incoming packets with this
protocol will then be passed to you as received packets.
For TELNET I open three portals, one for IP, ARP and RARP.
Since the TELNET interface routines expect a complete packet
(i.e. source, dest, protocol + data), I have to move the header
fields into and out of the DLL data structures, but this is no
problem.

One advantage of using DLL is that you can start a TELNET session,
use Alt-E to get into DOS, run a short LAT or DECNET session, then
exit back into TELNET.

Nevil Brownlee, [email protected]
Computer Centre, University of Auckland */

#define noDCBERR
#define noDCBTRACE

#include
#include
#include
#include
#ifdef MSC
#ifdef __TURBOC__
#include
#else
#include
#endif
#endif
#include

#include "protocol.h"
#include "decnet.h" /* header information for the decnet driver */
#include "externs.h"
#include "data.h"

#ifdef Lattice
#include
#define far
#endif

/* external packet variables */
extern unsigned char
rstat, /* Last status from read */
*buforg, /* Pointer to beginning of buffer */
*bufread, /* Pointer to where program is reading */
*bufpt, /* Current buffer pointer */
*bufend; /* Pointer to end of buffer */
extern int
bufbig, /* Number of bytes currently in buffer */
buflim; /* Max nbr of bytes in buffer */

/* Headers for assembler interface routines */

#ifdef Lattice
int DLLfn();
#else
int DLLfn ( /* Invoke DLL function */
int fn, /* Function nbr */
struct dcb far *dp); /* Datalink Control Block */
#endif

#ifdef NOT_NEEDED
void a_dgroup(); /* Point ds to dgroup, i.e. access globals */
#endif

struct ucb far *ucb_addr(); /* Get ucb address in callback routines */


/* DEC DLL callback handlers */

struct cba r_cba;
struct cba far *r_cbp = &r_cba;

extern void r_callback(); /* ASM receive routine, calls c_r_callback() */

int tx_ncbp; /* Nbr of pending tx callbacks */

struct cba t_cba;
struct cba far *t_cbp = &t_cba;

extern void t_callback(); /* ASM transmit routine, calls c_t_callback() */

void c_r_callback(struct ucb far *u) /* Received data routine */
{
int n;

n = r_cbp->inx;
memcpy(&r_cbp->uc[n], u,sizeof(struct ucb));
r_cbp->inx = (n+1) & CBAMASK;
}

void c_t_callback(struct ucb far *u) /* Transmitted data routine */
{
int n;

n = t_cbp->inx;
memcpy(&t_cbp->uc[n], u,sizeof(struct ucb));
t_cbp->inx = (n+1) & CBAMASK;
}


/* Trace routines */

int dn_errs; /* Nbr of Decnet DLL failures observed */

#ifdef DCBERR
FILE *dnlog; /* Diagnostic trace file */

void p_farptr(unsigned char far *fp)
{
fprintf(dnlog,"%04x:%04x ", FP_SEG(fp),FP_OFF(fp));
}
#endif

#ifdef DCBTRACE
void p_en_addr(unsigned char *e)
{
fprintf(dnlog,"%02x:%02x:%02x:%02x:%02x:%02x ", e[0],e[1],e[2],e[3],e[4],e[5]);
}

unsigned char *p_hex(unsigned char far *fp,int n)
{
fprintf(dnlog," ");
while (n != 0) {
fprintf(dnlog,"%02x ", *fp++);
--n;
} /* end while */
fprintf(dnlog, "\n");
return(fp);
}

void dcbdump(struct dcb *d)
{
fprintf(dnlog,"\n %2d ", d->portal_id);
p_en_addr(d->source_addr);
p_en_addr(d->dest_addr);
p_farptr(d->bh);
fprintf(dnlog,"%d\n", d->bl);
fprintf(dnlog," %d %d %d ", d->operation,d->pad,d->mode);
p_farptr(d->line_state);
p_farptr(d->rcv_callback);
p_farptr(d->xmit_callback);
fprintf(dnlog," %d %02x%02x %d\n",
d->max_outstanding,d->ptype[0],d->ptype[1],d->buffers_lost);
}
#endif


unsigned char *nbcpy(unsigned char *d,unsigned char *s,int n)
{
while(n != 0) {
*d++=*s++;
--n;
}
return(d);
}

void dll_read_chan(struct dcb *d)
{
unsigned int r;
r = DLLfn(0x08, d); /* Read Channel Status */
if (r != 0) {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"CHANNEL STATUS failed: result = %04x",r);
#endif
}
}

int dll_deallocate(struct dcb *d,unsigned char far *b)
{
unsigned int r;
d->bh = b;
r = DLLfn(0x07, d); /* Deallocate transmit buffer */
if (r != 0) {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"DEALLOC BUF failed:\n");
fprintf(dnlog," result %d portal %d prot %02x%02x buf ",
r, d->portal_id, d->ptype[0],d->ptype[1]);
p_farptr(b); fprintf(dnlog,"\n");
#endif
}
return r;
}

struct userdcb dcbs[4]; /* User info for the dcbs + zero end marker */

/* unsigned int prot; Protocol (bytes reversed) */
/* int nb; Nbr of dll buffers to use */
int dll_open(unsigned int prot,int nb)
{
struct userdcb *ud;
struct dcb *d;
int r;

for (ud = dcbs; ud->ptype != 0; ++ud) {
if (ud->ptype == prot) return 0; /* Already open */
}
d = &(ud->d);

d->pad = 0; /* 0 = NOPAD, 1 = PAD */
d->mode = 1; /* 0 = 802.3, 1 = Ethernet, 2 = promiscuous */
d->ptype[0] = (char)(prot & 0x00FF); /* Low-memory byte */
d->ptype[1] = (char)(prot >> 8); /* High-memory byte */
d->line_state = NULL;
/* d->line_state = MK_FP(0,0); */ /* CGW */
d->rcv_callback = r_callback;
d->xmit_callback = t_callback;
d->max_outstanding = (unsigned char)nb; /* 0 => Default, i.e. 1 rcv + 1 xmit */
r = DLLfn(0x01, d); /* Open portal */
if (r != 0) {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"OPEN failed:\n");
fprintf(dnlog," result %d prot %02x%02x\n",
r, d->ptype[0],d->ptype[1]);
#endif
#ifdef Lattice
exit(1);
#else
printf("DECNET OPEN failed:\n result=%d, protocol=%02x%02x\n",
r, d->ptype[0],d->ptype[1]);
exit(1);
#endif
}

ud->portal_id = d->portal_id;
ud->ptype = prot;
#ifdef DCBTRACE
fprintf(dnlog,"Portal %d open for protocol %02x%02x\n",
d->portal_id, d->ptype[0],d->ptype[1]);
#endif
return 0;
}

struct dcb *dcb_for_prot(unsigned int prot)
{
struct userdcb *ud;
for (ud = dcbs; ud->portal_id != 0; ++ud) {
if (ud->ptype == prot) return &(ud->d);
}
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"DCB_FOR_PORT failed:\n prot %02x%02x\n",
prot & 0x00FF,prot >> 8);
#endif
return &(dcbs[0].d);
}

struct dcb *dcb_for_ucb(struct ucb far *u)
{
struct userdcb *ud;
unsigned int p = u->portal_id;
for (ud = dcbs; ud->portal_id != 0; ++ud) {
if (ud->portal_id == p) return &(ud->d);
}
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"DCB_FOR_UCB failed:\n portal %d\n", p);
#endif
return &(dcbs[0].d);
}

int check_tx(void) /* Returns 1 if there was a tx callback */
{
int n,m;
struct ucb far *u;
struct dcb *du;

n = t_cbp->outx; m = t_cbp->inx;
if (n == m) return 0; /* No tx callbacks */

du = dcb_for_ucb(u = &t_cbp->uc[n]);
#ifdef DCBTRACE
fprintf(dnlog,"Tx callback: n %d buf ", n);
p_farptr(u->buffer); fprintf(dnlog,"\n");
#endif
dll_deallocate(du, u->buffer);
t_cbp->outx = (n+1) & CBAMASK;
--tx_ncbp;
return 1; /* We have processed a tx callback */
}


extern unsigned char
rstat, /* Last status from read */
*buforg, /* Pointer to beginning of buffer */
*bufread, /* Pointer to where program is reading */
*bufpt, /* Current buffer pointer */
*bufend; /* Pointer to end of buffer */
extern int
bufbig, /* Number of bytes currently in buffer */
buflim; /* Max nbr of bytes in buffer */


int CDECL DNetopen(unsigned char *s,unsigned int irq,unsigned int addr,unsigned int ioaddr) /* Initialise ethernet interface */
{
s=s; /* get rid of compiler warning */
irq=irq;
addr=addr;
ioaddr=ioaddr;
#ifdef DCBERR
dnlog = fopen("dndll.log","w");
#endif
dll_open(EIP,4); /* Open a dll portal for each packet type */
dll_open(EARP,2);
if(nnipnum[0] == 'R') /* Don't open RARP portal if we don't need to! */
dll_open(ERARP,2);
return(0);
}

int CDECL DNgetaddr(unsigned char *s,unsigned int address,unsigned int ioaddr) /* Get ethernet address from board */
{
address=address; /* get rid of compiler warning */
ioaddr=ioaddr;
dll_read_chan(&dcbs[0].d); /* Check channel status */
memcpy(s, dcbs[0].d.source_addr,6);
return(0);
}

int CDECL DNetclose(void) /* Shut down ethernet interface */
{
struct userdcb *ud; /* Close all the dll portals */
int r;
while (tx_ncbp != 0) check_tx(); /* Clear pending tx callbacks */
for (ud = dcbs; ud->portal_id != 0; ++ud) {
r = DLLfn(0x02, &(ud->d)); /* Close portal */
if (r != 0) {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"CLOSE failed:\n result %d portal %d\n",
r, ud->portal_id);
#endif
}
#ifdef DCBTRACE
else fprintf(dnlog,"Portal %d closed\n", ud->portal_id);
#endif
}
#ifdef DCBERR
if (dn_errs != 0) fprintf(dnlog,">>> %d DECnet DLL errors <<<\n", dn_errs);
fclose(dnlog);
#endif
if (dn_errs != 0) printf(">>> %d DECnet DLL errors <<<\n", dn_errs);
return(0);
}

void CDECL DNrecv(void) /* Move any received packet(s) into buffer */
{
int n,m, sz;
struct ucb far *u;
struct dcb *du;
unsigned char far *ucp;
unsigned int *uip;

for (;;) {
n = r_cbp->outx; m = r_cbp->inx;
if (n == m) return; /* No receive callbacks */
du = dcb_for_ucb(u = &r_cbp->uc[n]);

#ifdef DCBTRACE
fprintf(dnlog,"Rx callback: n %d buf ", n);
p_farptr(u->buffer);
fprintf(dnlog,"portal %d prot %02x%02x status %d length %d\n",
du->portal_id, du->ptype[0],du->ptype[1], u->buffer_status, u->bl);
ucp = p_hex(u->buffer,20); ucp = p_hex(ucp,20); p_hex(ucp,20);
#endif

if (u->buffer_status == 1) { /* Received with no errors */
if (bufbig <= buflim) { /* Room for packet in TELNET buffer */
if (bufpt >= bufend) /* Wraparound top of buffer */
bufpt = buforg;
uip = (unsigned int *)bufpt; /* Length of received packet */
ucp = nbcpy(bufpt+2, u->dest,6);
ucp = nbcpy(ucp, u->source,6);
ucp = nbcpy(ucp, du->ptype,2);
ucp = nbcpy(ucp, u->buffer,u->bl);
sz = ucp-bufpt;
if (dll_deallocate(du, u->buffer) == 0) { /* No problems */
*uip = sz; bufpt = ucp;
bufbig += sz; /* Bytes in TELNET buffer */
}
}
}
else dll_deallocate(du, u->buffer); /* Errors - discard packet */
r_cbp->outx = (n+1) & CBAMASK;
}
}

void CDECL DNetupdate(void) /* Update pointers and/or restart receiver
after read routine has handled the current packet */
{
unsigned int *uip;
int sz;

uip = (unsigned int *)bufread; /* Packet size */
sz = *uip;
bufread += sz;
if (bufread >= bufend) bufread = buforg;
bufbig -= sz;
}

int CDECL DNxmit(DLAYER *pkt,unsigned int count) /* Send an ethernet packet */
{
int r;
struct dcb *du;
unsigned char far *buf;
unsigned char *packet = (unsigned char *)pkt;
unsigned int *uip;

uip = (unsigned int *)packet; /* Protocol type from packet header */
du = dcb_for_prot(uip[6]);
#ifdef DCBTRACE
fprintf(dnlog,"Send packet: prot %02x%02x portal %d count %d\n",
du->ptype[0],du->ptype[1], du->portal_id,count);
#endif

for (;;) { /* Get a transmit buffer */
while (check_tx() != 0 || tx_ncbp == 2) ; /* Clear pending tx callbacks */
r = DLLfn(0x06, du); /* Request transmit buffer */
if (r == 0) break; /* Got the buffer */
else if (r == 8) { /* No resources */
if (tx_ncbp == 0) return 1; /* Couldn't get buffer */
continue; /* Wait for a tx callback */
}
else {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"REQ TX BUF failed:\n");
fprintf(dnlog," result %d portal %d prot %02x%02x\n",
r, du->portal_id,du->ptype[0],du->ptype[1]);
#endif
return 1; /* Couldn't get buffer */
}
}

memcpy(du->dest_addr, packet, 6);
buf = du->bh;
memcpy(buf, &packet[14], count -= 14); /* Allow for ethernet header */
du->bl = (count <= 46) ? 46 : count;
#ifdef DCBTRACE
fprintf(dnlog," dest "); p_en_addr(du->dest_addr);
fprintf(dnlog,"source "); p_en_addr(&packet[6]);
fprintf(dnlog,"buffer "); p_farptr(du->bh);
fprintf(dnlog,"\n");
p_hex(du->bh,20);
#endif

r = DLLfn(0x05, du); /* Transmit */
if (r != 0) {
++dn_errs;
#ifdef DCBERR
fprintf(dnlog,"TRANSMIT failed:\n");
fprintf(dnlog," result %d portal %d prot %02x%02x buf ",
r, du->portal_id,du->ptype[0],du->ptype[1]);
p_farptr(du->bh); fprintf(dnlog,"\n");
#endif
return 2; /* Transmit failed */
}
++tx_ncbp;
return 0; /* No problems */
}