home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / NCSATELN / TEL23SRC.ZIP / NET / ENET / DNDLL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  14.2 KB  |  509 lines

  1. /* 1152, Wed 29 Aug 90
  2.  
  3.    DNDLL:  DECnet DLL driver for NCSA TELNET
  4.  
  5.    This driver allows TELNET to work through the DECNET-DOS
  6.    Datalink Layer, using the DLL interface documented in the
  7.    VAXmate Technical Reference Manual Volume 2, AA-HD95A-TK.
  8.  
  9.    Support for DECNET-DOS is provided on the PC by a set of TSRs.
  10.    The minimum set of these is just SCH (the DECnet process scheduler)
  11.    and DLL (the Datalink Layer driver).  Other TSRs can be loaded
  12.    into memory to provide other services, e.g. LAT (Local Area Transport)
  13.    and DNP (DECNET).
  14.  
  15.    DEC supply (as part of DECNET-DOS) DLL drivers for their own
  16.    ethernet card (the DEPCA), and a range of other cards from
  17.    MICOM and 3COM.  DLL drivers for the Western Digital 8003 card
  18.    (marketed here in New Zealand as the Amtec Ethercard) are also
  19.    available.  This TELNET driver will work with any of the DLL
  20.    drivers - I have tested it with the WD8003 as well as the DEPCA.
  21.  
  22.    DLL allows you to open a 'portal' to ethernet, specifying which
  23.    protocol id it will carry.  Any incoming packets with this
  24.    protocol will then be passed to you as received packets.
  25.    For TELNET I open three portals, one for IP, ARP and RARP.
  26.    Since the TELNET interface routines expect a complete packet
  27.    (i.e. source, dest, protocol + data), I have to move the header
  28.    fields into and out of the DLL data structures, but this is no
  29.    problem.
  30.  
  31.    One advantage of using DLL is that you can start a TELNET session,
  32.    use Alt-E to get into DOS, run a short LAT or DECNET session, then
  33.    exit back into TELNET.
  34.  
  35.    Nevil Brownlee,  n.brownlee@aukuni.ac.nz
  36.    Computer Centre,  University of Auckland */
  37.  
  38. #define noDCBERR
  39. #define noDCBTRACE
  40.  
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <string.h>
  44. #include <stdlib.h>
  45. #ifdef MSC
  46. #ifdef __TURBOC__
  47. #include <alloc.h>
  48. #else
  49. #include <malloc.h>
  50. #endif
  51. #endif
  52. #include <dos.h>
  53.  
  54. #ifdef MEMORY_DEBUG
  55. #include "memdebug.h"
  56. #endif
  57. #include "protocol.h"
  58. #include "decnet.h"        /* header information for the decnet driver */
  59. #include "externs.h"
  60. #include "data.h"
  61.  
  62. #ifdef Lattice
  63. #include <stdlib.h>
  64. #define far
  65. #endif
  66.  
  67. /* external packet variables */
  68. extern unsigned char
  69.    rstat,     /* Last status from read */
  70.    *buforg,   /* Pointer to beginning of buffer */
  71.    *bufread,  /* Pointer to where program is reading */
  72.    *bufpt,    /* Current buffer pointer */
  73.    *bufend;   /* Pointer to end of buffer */
  74. extern int
  75.    bufbig,    /* Number of bytes currently in buffer */
  76.    buflim;    /* Max nbr of bytes in buffer */
  77.  
  78. /* Headers for assembler interface routines */
  79.  
  80. #ifdef Lattice
  81. int DLLfn();
  82. #else
  83. int DLLfn (                   /* Invoke DLL function */
  84.    int fn,                    /* Function nbr */
  85.    struct dcb far *dp);       /* Datalink Control Block */
  86. #endif
  87.  
  88. #ifdef NOT_NEEDED
  89. void a_dgroup();              /* Point ds to dgroup, i.e. access globals */
  90. #endif
  91.  
  92. struct ucb far *ucb_addr();   /* Get ucb address in callback routines */
  93.  
  94.  
  95. /* DEC DLL callback handlers */
  96.  
  97. struct cba r_cba;
  98. struct cba far *r_cbp = &r_cba;
  99.  
  100. extern void r_callback();  /* ASM receive routine, calls c_r_callback() */
  101.  
  102. int tx_ncbp;  /* Nbr of pending tx callbacks */
  103.  
  104. struct cba t_cba;
  105. struct cba far *t_cbp = &t_cba;
  106.  
  107. extern void t_callback();  /* ASM transmit routine, calls c_t_callback() */
  108.  
  109. void c_r_callback(u)  /* Received data routine */
  110. struct ucb far *u;
  111. {
  112.    int n;
  113.  
  114.    n = r_cbp->inx;
  115.    memcpy(&r_cbp->uc[n], u,sizeof(struct ucb));
  116.    r_cbp->inx = (n+1) & CBAMASK;
  117. }
  118.  
  119. void c_t_callback(u)  /* Transmitted data routine */
  120. struct ucb far *u;
  121. {
  122.    int n;
  123.  
  124.    n = t_cbp->inx;
  125.    memcpy(&t_cbp->uc[n], u,sizeof(struct ucb));
  126.    t_cbp->inx = (n+1) & CBAMASK;
  127. }
  128.  
  129.  
  130. /* Trace routines */
  131.  
  132. int dn_errs;  /* Nbr of Decnet DLL failures observed */
  133.  
  134. #ifdef DCBERR
  135. FILE *dnlog;  /* Diagnostic trace file */
  136.  
  137. void p_farptr(fp)
  138. unsigned char far *fp;
  139. {
  140.    fprintf(dnlog,"%04x:%04x  ", FP_SEG(fp),FP_OFF(fp));
  141. }
  142. #endif
  143.  
  144. #ifdef DCBTRACE
  145. void p_en_addr(e)
  146. unsigned char *e;
  147. {
  148.    fprintf(dnlog,"%02x:%02x:%02x:%02x:%02x:%02x  ", e[0],e[1],e[2],e[3],e[4],e[5]);
  149. }
  150.  
  151. unsigned char *p_hex(fp,n)
  152. unsigned char far *fp;
  153. int n;
  154. {
  155.     fprintf(dnlog,"   ");
  156.     while (n != 0) {
  157.         fprintf(dnlog,"%02x ", *fp++);
  158.         --n;
  159.       }    /* end while */
  160.     fprintf(dnlog, "\n");
  161.     return(fp);
  162. }
  163.  
  164. void dcbdump(d)
  165. struct dcb *d;
  166. {
  167.    fprintf(dnlog,"\n   %2d  ", d->portal_id);
  168.    p_en_addr(d->source_addr);
  169.    p_en_addr(d->dest_addr);
  170.    p_farptr(d->bh);
  171.    fprintf(dnlog,"%d\n", d->bl);
  172.    fprintf(dnlog,"   %d %d %d  ", d->operation,d->pad,d->mode);
  173.    p_farptr(d->line_state);
  174.    p_farptr(d->rcv_callback);
  175.    p_farptr(d->xmit_callback);
  176.    fprintf(dnlog," %d %02x%02x %d\n",
  177.       d->max_outstanding,d->ptype[0],d->ptype[1],d->buffers_lost);
  178.    }
  179. #endif
  180.  
  181.  
  182. unsigned char *nbcpy(d, s,n)
  183. unsigned char *d, *s;
  184. int n;
  185. {
  186.    while (n != 0) {
  187.       *d++ = *s++;  --n;
  188.       }
  189.    return d;
  190.    }
  191.  
  192. void dll_read_chan(d)
  193. struct dcb *d;
  194. {
  195.    unsigned int r;
  196.    r = DLLfn(0x08, d);  /* Read Channel Status */
  197.    if (r != 0) {
  198.       ++dn_errs;
  199. #ifdef DCBERR
  200.       fprintf(dnlog,"CHANNEL STATUS failed: result = %04x",r);
  201. #endif
  202.       }
  203.    }
  204.  
  205.  
  206. int dll_deallocate(d,b)
  207. struct dcb *d;
  208. unsigned char far *b;
  209. {
  210.    unsigned int r;
  211.    d->bh = b;
  212.    r = DLLfn(0x07, d);  /* Deallocate transmit buffer */
  213.    if (r != 0) {
  214.       ++dn_errs;
  215. #ifdef DCBERR
  216.       fprintf(dnlog,"DEALLOC BUF failed:\n");
  217.       fprintf(dnlog,"   result %d  portal %d  prot %02x%02x  buf ",
  218.          r, d->portal_id, d->ptype[0],d->ptype[1]);
  219.       p_farptr(b);  fprintf(dnlog,"\n");
  220. #endif
  221.       }
  222.    return r;
  223.    }
  224.  
  225. struct userdcb dcbs[4];  /* User info for the dcbs + zero end marker */
  226.  
  227. int dll_open(prot,nb)
  228. unsigned int prot;  /* Protocol (bytes reversed) */
  229. int nb;  /* Nbr of dll buffers to use */
  230. {
  231.    struct userdcb *ud;
  232.    struct dcb *d;
  233.    int r;
  234.  
  235.    for (ud = dcbs;  ud->ptype != 0;  ++ud) {
  236.       if (ud->ptype == prot) return 0;  /* Already open */
  237.       }
  238.    d = &(ud->d);
  239.  
  240.    d->pad = 0;  /* 0 = NOPAD, 1 = PAD */
  241.    d->mode = 1;  /* 0 = 802.3, 1 = Ethernet, 2 = promiscuous */
  242.    d->ptype[0] = (char)(prot & 0x00FF);  /* Low-memory byte */
  243.    d->ptype[1] = (char)(prot >> 8);  /* High-memory byte */
  244.    d->line_state = NULL;
  245. /*   d->line_state = MK_FP(0,0); */   /* CGW */
  246.    d->rcv_callback = r_callback;
  247.    d->xmit_callback = t_callback;
  248.    d->max_outstanding = (unsigned char)nb;  /* 0 => Default, i.e. 1 rcv + 1 xmit */
  249.    r = DLLfn(0x01, d);  /* Open portal */
  250.    if (r != 0) {
  251.       ++dn_errs;
  252. #ifdef DCBERR
  253.       fprintf(dnlog,"OPEN failed:\n");
  254.       fprintf(dnlog,"   result %d  prot %02x%02x\n",
  255.          r, d->ptype[0],d->ptype[1]);
  256. #endif
  257. #ifdef Lattice
  258.       exit(1);
  259. #else
  260.       printf("DECNET OPEN failed:\n   result=%d, protocol=%02x%02x\n",
  261.          r, d->ptype[0],d->ptype[1]);
  262.       exit(1);
  263. #endif
  264.    }
  265.  
  266.    ud->portal_id = d->portal_id;
  267.    ud->ptype = prot;
  268. #ifdef DCBTRACE
  269.    fprintf(dnlog,"Portal %d open for protocol %02x%02x\n",
  270.       d->portal_id, d->ptype[0],d->ptype[1]);
  271. #endif
  272.    return 0;
  273.    }
  274.  
  275. struct dcb *dcb_for_prot(prot)
  276. unsigned int prot;
  277. {
  278.    struct userdcb *ud;
  279.    for (ud = dcbs;  ud->portal_id != 0;  ++ud) {
  280.       if (ud->ptype == prot) return &(ud->d);
  281.       }
  282.    ++dn_errs;
  283. #ifdef DCBERR
  284.    fprintf(dnlog,"DCB_FOR_PORT failed:\n   prot %02x%02x\n",
  285.       prot & 0x00FF,prot >> 8);
  286. #endif
  287.    return &(dcbs[0].d);
  288.    }
  289.  
  290. struct dcb *dcb_for_ucb(u)
  291. struct ucb far *u;
  292. {
  293.    struct userdcb *ud;
  294.    unsigned int p = u->portal_id;
  295.    for (ud = dcbs;  ud->portal_id != 0;  ++ud) {
  296.       if (ud->portal_id == p) return &(ud->d);
  297.       }
  298.    ++dn_errs;
  299. #ifdef DCBERR
  300.    fprintf(dnlog,"DCB_FOR_UCB failed:\n   portal %d\n", p);
  301. #endif
  302.    return &(dcbs[0].d);
  303.    }
  304.  
  305. int check_tx()  /* Returns 1 if there was a tx callback */
  306. {
  307.    int n,m;
  308.    struct ucb far *u;
  309.    struct dcb *du;
  310.  
  311.    n = t_cbp->outx;   m = t_cbp->inx;
  312.    if (n == m) return 0;  /* No tx callbacks */
  313.  
  314.    du = dcb_for_ucb(u = &t_cbp->uc[n]);
  315. #ifdef DCBTRACE
  316.    fprintf(dnlog,"Tx callback: n %d  buf ", n);
  317.    p_farptr(u->buffer);  fprintf(dnlog,"\n");
  318. #endif
  319.    dll_deallocate(du, u->buffer);
  320.    t_cbp->outx = (n+1) & CBAMASK;
  321.    --tx_ncbp;
  322.    return 1;  /* We have processed a tx callback */
  323.    }
  324.  
  325.  
  326. extern unsigned char
  327.    rstat,     /* Last status from read */
  328.    *buforg,   /* Pointer to beginning of buffer */
  329.    *bufread,  /* Pointer to where program is reading */
  330.    *bufpt,    /* Current buffer pointer */
  331.    *bufend;   /* Pointer to end of buffer */
  332. extern int
  333.    bufbig,    /* Number of bytes currently in buffer */
  334.    buflim;    /* Max nbr of bytes in buffer */
  335.  
  336.  
  337. int DNetopen(s, irq,addr,ioaddr)  /* Initialise ethernet interface */
  338. unsigned char *s;            /* Ethernet address to use */
  339. unsigned int irq,addr,ioaddr;  /* IRQ, base memory address, i/o port address */
  340. {
  341.     s=s;        /* get rid of compiler warning */
  342.     irq=irq;
  343.     addr=addr;
  344.     ioaddr=ioaddr;
  345. #ifdef DCBERR
  346.     dnlog = fopen("dndll.log","w");
  347. #endif
  348.     dll_open(EIP,4);  /* Open a dll portal for each packet type */
  349.     dll_open(EARP,2);
  350.    if (nnipnum[0] == 'R')  /* Don't open RARP portal if we don't need to! */
  351.       dll_open(ERARP,2);
  352.     return(0);
  353. }
  354.  
  355. int DNgetaddr(s, address,ioaddr)  /* Get ethernet address from board */
  356. unsigned char *s;              /* Ethernet address from board */
  357. unsigned int address,ioaddr;   /* Base memory address, i/o port address */
  358. {
  359.     address=address;        /* get rid of compiler warning */
  360.     ioaddr=ioaddr;
  361.     dll_read_chan(&dcbs[0].d);  /* Check channel status */
  362.     memcpy(s, dcbs[0].d.source_addr,6);
  363.     return(0);
  364. }
  365.  
  366. int DNetclose()  /* Shut down ethernet interface */
  367. {
  368.    struct userdcb *ud;  /* Close all the dll portals */
  369.    int r;
  370.    while (tx_ncbp != 0) check_tx();  /* Clear pending tx callbacks */
  371.    for (ud = dcbs;  ud->portal_id != 0;  ++ud) {
  372.       r = DLLfn(0x02, &(ud->d));  /* Close portal */
  373.       if (r != 0) {
  374.          ++dn_errs;
  375. #ifdef DCBERR
  376.      fprintf(dnlog,"CLOSE failed:\n   result %d  portal %d\n",
  377.         r, ud->portal_id);
  378. #endif
  379.          }
  380. #ifdef DCBTRACE
  381.       else fprintf(dnlog,"Portal %d closed\n", ud->portal_id);
  382. #endif
  383.       }
  384. #ifdef DCBERR
  385.    if (dn_errs != 0) fprintf(dnlog,">>> %d DECnet DLL errors <<<\n", dn_errs);
  386.    fclose(dnlog);
  387. #endif
  388.    if (dn_errs != 0) printf(">>> %d DECnet DLL errors <<<\n", dn_errs);
  389.    return(0);
  390.    }
  391.  
  392. void DNrecv()  /* Move any received packet(s) into buffer */
  393. {
  394.    int n,m, sz;
  395.    struct ucb far *u;
  396.    struct dcb *du;
  397.    unsigned char far *ucp;
  398.    unsigned int *uip;
  399.  
  400.    for (;;) {
  401.       n = r_cbp->outx;   m = r_cbp->inx;
  402.       if (n == m) return;  /* No receive callbacks */
  403.       du = dcb_for_ucb(u = &r_cbp->uc[n]);
  404.  
  405. #ifdef DCBTRACE
  406.       fprintf(dnlog,"Rx callback: n %d  buf ", n);
  407.          p_farptr(u->buffer);
  408.       fprintf(dnlog,"portal %d  prot %02x%02x  status %d  length %d\n",
  409.      du->portal_id, du->ptype[0],du->ptype[1], u->buffer_status, u->bl);
  410.       ucp = p_hex(u->buffer,20);  ucp = p_hex(ucp,20);  p_hex(ucp,20);
  411. #endif
  412.  
  413.       if (u->buffer_status == 1) {  /* Received with no errors */
  414.          if (bufbig <= buflim) {  /* Room for packet in TELNET buffer */
  415.             if (bufpt >= bufend)  /* Wraparound top of buffer */
  416.                bufpt = buforg;
  417.             uip = (unsigned int *)bufpt;  /* Length of received packet */
  418.             ucp = nbcpy(bufpt+2, u->dest,6);
  419.             ucp = nbcpy(ucp, u->source,6);
  420.             ucp = nbcpy(ucp, du->ptype,2);
  421.             ucp = nbcpy(ucp, u->buffer,u->bl);
  422.         sz = ucp-bufpt;
  423.             if (dll_deallocate(du, u->buffer) == 0) {  /* No problems */
  424.                *uip = sz;  bufpt = ucp;
  425.                bufbig += sz;  /* Bytes in TELNET buffer */
  426.                }
  427.             }
  428.          }
  429.       else dll_deallocate(du, u->buffer);  /* Errors - discard packet */
  430.       r_cbp->outx = (n+1) & CBAMASK;
  431.       }
  432.    }
  433.  
  434. void DNetupdate()  /* Update pointers and/or restart receiver
  435.                      after read routine has handled the current packet */
  436. {
  437.    unsigned int *uip;
  438.    int sz;
  439.  
  440.    uip = (unsigned int *)bufread;  /* Packet size */
  441.    sz = *uip;
  442.    bufread += sz;
  443.    if (bufread >= bufend) bufread = buforg;
  444.    bufbig -= sz;
  445.    }
  446.  
  447. int DNxmit(pkt,count)  /* Send an ethernet packet */
  448. DLAYER *pkt;       /* Packet data bytes */
  449. int count;                   /* length of packet */
  450. {
  451.    int r;
  452.    struct dcb *du;
  453.    unsigned char far *buf;
  454.    unsigned char *packet = (unsigned char *)pkt;
  455.    unsigned int *uip;
  456.  
  457.    uip = (unsigned int *)packet;  /* Protocol type from packet header */
  458.    du = dcb_for_prot(uip[6]);
  459. #ifdef DCBTRACE
  460.    fprintf(dnlog,"Send packet: prot %02x%02x  portal %d  count %d\n",
  461.       du->ptype[0],du->ptype[1], du->portal_id,count);
  462. #endif
  463.  
  464.    for (;;) {  /* Get a transmit buffer */
  465.       while (check_tx() != 0 || tx_ncbp == 2) ;  /* Clear pending tx callbacks */
  466.       r = DLLfn(0x06, du);  /* Request transmit buffer */
  467.       if (r == 0) break;  /* Got the buffer */
  468.       else if (r == 8) {  /* No resources */
  469.          if (tx_ncbp == 0) return 1;  /* Couldn't get buffer */
  470.          continue;  /* Wait for a tx callback */
  471.          }
  472.       else {
  473.          ++dn_errs;
  474. #ifdef DCBERR
  475.          fprintf(dnlog,"REQ TX BUF failed:\n");
  476.          fprintf(dnlog,"   result %d  portal %d  prot %02x%02x\n",
  477.             r, du->portal_id,du->ptype[0],du->ptype[1]);
  478. #endif
  479.          return 1;  /* Couldn't get buffer */
  480.          }
  481.       }
  482.  
  483.    memcpy(du->dest_addr, packet, 6);
  484.    buf = du->bh;
  485.    memcpy(buf, &packet[14], count -= 14);  /* Allow for ethernet header */
  486.    du->bl = (count <= 46) ? 46 : count;
  487. #ifdef DCBTRACE
  488.    fprintf(dnlog,"   dest ");  p_en_addr(du->dest_addr);
  489.    fprintf(dnlog,"source ");  p_en_addr(&packet[6]);
  490.    fprintf(dnlog,"buffer ");  p_farptr(du->bh);
  491.    fprintf(dnlog,"\n");
  492.    p_hex(du->bh,20);
  493. #endif
  494.  
  495.    r = DLLfn(0x05, du);  /* Transmit */
  496.    if (r != 0) {
  497.       ++dn_errs;
  498. #ifdef DCBERR
  499.       fprintf(dnlog,"TRANSMIT failed:\n");
  500.       fprintf(dnlog,"   result %d  portal %d  prot %02x%02x  buf ",
  501.          r, du->portal_id,du->ptype[0],du->ptype[1]);
  502.       p_farptr(du->bh);  fprintf(dnlog,"\n");
  503. #endif
  504.       return 2;  /* Transmit failed */
  505.       }
  506.    ++tx_ncbp;
  507.    return 0;  /* No problems */
  508.    }
  509.