home *** CD-ROM | disk | FTP | other *** search
- /* Driver for FTP Software's packet driver interface. (PC specific code)
- * Copyright 1991 Phil Karn, KA9Q
- */
- #include <stdio.h>
- #include <dos.h>
- #include "global.h"
- #include "proc.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "enet.h"
- #include "arcnet.h"
- #include "ax25.h"
- #include "slip.h"
- #include "kiss.h"
- #include "iface.h"
- #include "arp.h"
- #include "trace.h"
- #include "pktdrvr.h"
- #include "config.h"
- #include "devparam.h"
-
- static long access_type __ARGS((int intno,int if_class,int if_type,
- int if_number, char *type,unsigned typelen,
- INTERRUPT (*receiver) __ARGS((void)) ));
- static int driver_info __ARGS((int intno,int handle,int *version,
- int *class,int *type,int *number,int *basic));
- static int release_type __ARGS((int intno,int handle));
- static int get_address __ARGS((int intno,int handle,char *buf,int len));
- static int pk_raw __ARGS((struct iface *iface,struct mbuf *bp));
- static int pk_stop __ARGS((struct iface *iface));
- static int send_pkt __ARGS((int intno,char *buffer,unsigned length));
-
-
- static INTERRUPT (*Pkvec[])() = { pkvec0,pkvec1,pkvec2 };
- static struct pktdrvr Pktdrvr[PK_MAX];
- static int Derr;
- static char Pkt_sig[] = "PKT DRVR"; /* Packet driver signature */
-
- /*
- * Send routine for packet driver
- */
-
- int
- pk_send(bp,iface,gateway,tos)
- struct mbuf *bp; /* Buffer to send */
- struct iface *iface; /* Pointer to interface control block */
- int32 gateway; /* Ignored */
- int tos;
- {
- if(iface == NULLIF){
- free_p(bp);
- return -1;
- }
- return (*iface->raw)(iface,bp);
- }
-
- /* Send raw packet (caller provides header) */
- static int
- pk_raw(iface,bp)
- struct iface *iface; /* Pointer to interface control block */
- struct mbuf *bp; /* Data field */
- {
- register struct pktdrvr *pp;
- int16 size;
- struct mbuf *bp1;
-
- pp = &Pktdrvr[iface->dev];
- size = len_p(bp);
-
- dump(iface,IF_TRACE_OUT,bp);
- iface->rawsndcnt++;
- iface->lastsent = secclock();
-
- /* Perform class-specific processing, if any */
- switch(pp->class){
- case CL_ETHERNET:
- if(size < RUNT){
- /* Pad the packet out to the minimum */
- if((bp1 = alloc_mbuf(RUNT-size)) == NULLBUF){
- free_p(bp);
- return -1;
- }
- memset(bp1->data,0,RUNT-size);
- bp1->cnt = RUNT-size;
- append(&bp,bp1);
- size = RUNT;
- }
- break;
- case CL_KISS:
- /* This *really* shouldn't be done here, but it was the
- * easiest way. Put the type field for KISS TNC on front.
- */
- bp = pushdown(bp,1);
- bp->data[0] = PARAM_DATA;
- size++;
- break;
- }
- if(bp->next != NULLBUF){
- /* Copy to contiguous buffer, since driver can't handle mbufs */
- bp1 = copy_p(bp,size);
- free_p(bp);
- bp = bp1;
- if(bp == NULLBUF)
- return -1;
- }
- send_pkt(pp->intno,bp->data,bp->cnt);
- free_p(bp);
- return 0;
- }
-
- /* Packet driver receive routine. Called from an assembler hook that pushes
- * the caller's registers on the stack so we can access and modify them.
- * This is a rare example of call-by-location in C.
- */
- INTERRUPT
- pkint(bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags, dev)
- unsigned short bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags;
- int dev;
- {
- register struct pktdrvr *pp;
-
- if(dev < 0 || dev >= PK_MAX)
- return; /* Unknown device */
- pp = &Pktdrvr[dev];
- if(pp->iface == NULLIF)
- return; /* Unknown device */
- switch(ax){
- case 0: /* Space allocate call */
- if((pp->buffer = alloc_mbuf(cx+sizeof(struct iface *))) != NULLBUF){
- pp->buffer->data += sizeof(struct iface *);
- es = FP_SEG(pp->buffer->data);
- di = FP_OFF(pp->buffer->data);
- pp->buffer->cnt = cx;
- } else {
- es = di = 0;
- }
- break;
- case 1: /* Packet complete call */
- net_route(pp->iface,pp->buffer);
- pp->buffer = NULLBUF;
- break;
- default:
- break;
- }
- }
-
- /* Shut down the packet interface */
- static int
- pk_stop(iface)
- struct iface *iface;
- {
- struct pktdrvr *pp;
-
- pp = &Pktdrvr[iface->dev];
- /* Call driver's release_type() entry */
- if(release_type(pp->intno,pp->handle1) == -1)
- printf("%s: release_type error code %u\n",iface->name,Derr);
-
- if(pp->class == CL_ETHERNET || pp->class == CL_ARCNET){
- release_type(pp->intno,pp->handle2);
- release_type(pp->intno,pp->handle3);
- }
- pp->iface = NULLIF;
- return 0;
- }
- /* Attach a packet driver to the system
- * argv[0]: hardware type, must be "packet"
- * argv[1]: software interrupt vector, e.g., x7e
- * argv[2]: interface label, e.g., "trw0"
- * argv[3]: maximum number of packets allowed on transmit queue, e.g., "5"
- * argv[4]: maximum transmission unit, bytes, e.g., "1500"
- */
- int
- pk_attach(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register struct iface *if_pk;
- int class,type;
- unsigned int intno;
- static char iptype[] = {IP_TYPE >> 8,IP_TYPE};
- static char arptype[] = {ARP_TYPE >> 8,ARP_TYPE};
- static char revarptype[] = {REVARP_TYPE >> 8, REVARP_TYPE};
- long handle;
- int i;
- #ifdef ARCNET
- static char arcip[] = {ARC_IP};
- static char arcarp[] = {ARC_ARP};
- #endif
-
- long drvvec;
- char sig[8]; /* Copy of driver signature "PKT DRVR" */
- register struct pktdrvr *pp;
- char tmp[25];
- char *cp;
-
- for(i=0;i<PK_MAX;i++){
- if(Pktdrvr[i].iface == NULLIF)
- break;
- }
- if(i >= PK_MAX){
- printf("Too many packet drivers\n");
- return -1;
- }
- if(if_lookup(argv[2]) != NULLIF){
- printf("Interface %s already exists\n",argv[2]);
- return -1;
- }
-
- intno = htoi(argv[1]);
- /* Verify that there's really a packet driver there, so we don't
- * go off into the ozone (if there's any left)
- */
- drvvec = (long)getvect(intno);
- movblock(FP_OFF(drvvec)+3, FP_SEG(drvvec),
- FP_OFF(sig),FP_SEG(sig),strlen(Pkt_sig));
- if(strncmp(sig,Pkt_sig,strlen(Pkt_sig)) != 0){
- printf("No packet driver loaded at int 0x%x\n",intno);
- return -1;
- }
- if_pk = (struct iface *)callocw(1,sizeof(struct iface));
- if_pk->name = strdup(argv[2]);
- if_pk->addr = Ip_addr;
- pp = &Pktdrvr[i];
- if_pk->mtu = atoi(argv[4]);
- if_pk->dev = i;
- if_pk->raw = pk_raw;
- if_pk->stop = pk_stop;
- pp->intno = intno;
- pp->iface = if_pk;
-
- /* Version 1.08 of the packet driver spec dropped the handle
- * requirement from the driver_info call. However, if we are using
- * a version 1.05 packet driver, the following call will fail.
- */
- if(driver_info(intno,-1,NULL,&class,&type,NULL,NULL) < 0){
- /* Find out by exhaustive search what class this driver is (ugh) */
- for(class=1;class<=NCLASS;class++){
- /* Store handle in temp long so we can tell an
- * error return (-1) from a handle of 0xffff
- */
- handle = access_type(intno,class,ANYTYPE,0,iptype,2,
- Pkvec[if_pk->dev]);
- if(handle != -1 || Derr == TYPE_INUSE){
- pp->handle1 = handle;
- break;
- }
- }
- /* Now that we know, release it and do it all over again with the
- * right type fields
- */
- release_type(intno,pp->handle1);
- }
- switch(class){
- case CL_ETHERNET:
- pp->handle1 = access_type(intno,class,ANYTYPE,0,iptype,2,
- Pkvec[if_pk->dev]);
- pp->handle2 = access_type(intno,class,ANYTYPE,0,arptype,2,
- Pkvec[if_pk->dev]);
- pp->handle3 = access_type(intno,class,ANYTYPE,0,revarptype,2,
- Pkvec[if_pk->dev]);
- setencap(if_pk,"Ethernet");
- /* Get hardware Ethernet address from driver */
- if_pk->hwaddr = mallocw(EADDR_LEN);
- get_address(intno,pp->handle1,if_pk->hwaddr,EADDR_LEN);
- if(if_pk->hwaddr[0] & 1){
- printf("Warning! Interface '%s' has a multicast address:",
- if_pk->name);
- printf(" (%s)\n",
- (*if_pk->iftype->format)(tmp,if_pk->hwaddr));
- }
- break;
- #ifdef ARCNET
- case CL_ARCNET:
- pp->handle1 = access_type(intno,class,ANYTYPE,0,arcip,1,
- Pkvec[if_pk->dev]);
- pp->handle2 = access_type(intno,class,ANYTYPE,0,arcarp,1,
- Pkvec[if_pk->dev]);
- if_pk->output = anet_output;
- /* Get hardware ARCnet address from driver */
- if_pk->hwaddr = mallocw(AADDR_LEN);
- get_address(intno,pp->handle1,if_pk->hwaddr,AADDR_LEN);
- break;
- #endif
- case CL_SERIAL_LINE:
- pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
- Pkvec[if_pk->dev]);
- setencap(if_pk,"SLIP");
- break;
- #ifdef AX25
- case CL_KISS: /* Note that the raw routine puts on the command */
- case CL_AX25:
- pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
- Pkvec[if_pk->dev]);
- setencap(if_pk,"AX25");
- if_pk->hwaddr = mallocw(AXALEN);
- memcpy(if_pk->hwaddr,Mycall,AXALEN);
- break;
- #endif
- case CL_SLFP:
- pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
- Pkvec[if_pk->dev]);
- setencap(if_pk,"SLFP");
- get_address(intno,pp->handle1,(char *)&if_pk->addr,4);
- break;
- default:
- printf("Packet driver has unsupported class %u\n",class);
- free(if_pk->name);
- free((char *)if_pk);
- return -1;
- }
- pp->class = class;
- if_pk->next = Ifaces;
- Ifaces = if_pk;
- cp = if_name(if_pk," tx");
- if_pk->txproc = newproc(cp,768,if_tx,if_pk->dev,if_pk,NULL,0);
- free(cp);
-
- return 0;
- }
- static long
- access_type(intno,if_class,if_type,if_number,type,typelen,receiver)
- int intno;
- int if_class;
- int if_type;
- int if_number;
- char *type;
- unsigned typelen;
- INTERRUPT (*receiver)();
- {
- union REGS regs;
- struct SREGS sregs;
-
- segread(&sregs);
- regs.h.dl = if_number; /* Number */
- sregs.ds = FP_SEG(type); /* Packet type template */
- regs.x.si = FP_OFF(type);
- regs.x.cx = typelen; /* Length of type */
- sregs.es = FP_SEG(receiver); /* Address of receive handler */
- regs.x.di = FP_OFF(receiver);
- regs.x.bx = if_type; /* Type */
- regs.h.ah = ACCESS_TYPE; /* Access_type() function */
- regs.h.al = if_class; /* Class */
- int86x(intno,®s,®s,&sregs);
- if(regs.x.cflag){
- Derr = regs.h.dh;
- return -1;
- } else
- return regs.x.ax;
- }
- static int
- release_type(intno,handle)
- int intno;
- int handle;
- {
- union REGS regs;
-
- regs.x.bx = handle;
- regs.h.ah = RELEASE_TYPE;
- int86(intno,®s,®s);
- if(regs.x.cflag){
- Derr = regs.h.dh;
- return -1;
- } else
- return 0;
- }
- static int
- send_pkt(intno,buffer,length)
- int intno;
- char *buffer;
- unsigned length;
- {
- union REGS regs;
- struct SREGS sregs;
-
- segread(&sregs);
- sregs.ds = FP_SEG(buffer);
- sregs.es = FP_SEG(buffer); /* for buggy univation pkt driver - CDY */
- regs.x.si = FP_OFF(buffer);
- regs.x.cx = length;
- regs.h.ah = SEND_PKT;
- int86x(intno,®s,®s,&sregs);
- if(regs.x.cflag){
- Derr = regs.h.dh;
- return -1;
- } else
- return 0;
- }
- static int
- driver_info(intno,handle,version,class,type,number,basic)
- int intno;
- int handle;
- int *version,*class,*type,*number,*basic;
- {
- union REGS regs;
-
- regs.x.bx = handle;
- regs.h.ah = DRIVER_INFO;
- regs.h.al = 0xff;
- int86(intno,®s,®s);
- if(regs.x.cflag){
- Derr = regs.h.dh;
- return -1;
- }
- if(version != NULL)
- *version = regs.x.bx;
- if(class != NULL)
- *class = regs.h.ch;
- if(type != NULL)
- *type = regs.x.dx;
- if(number != NULL)
- *number = regs.h.cl;
- if(basic != NULL)
- *basic = regs.h.al;
- return 0;
- }
- static int
- get_address(intno,handle,buf,len)
- int intno;
- int handle;
- char *buf;
- int len;
- {
- union REGS regs;
- struct SREGS sregs;
-
- segread(&sregs);
- sregs.es = FP_SEG(buf);
- regs.x.di = FP_OFF(buf);
- regs.x.cx = len;
- regs.x.bx = handle;
- regs.h.ah = GET_ADDRESS;
- int86x(intno,®s,®s,&sregs);
- if(regs.x.cflag){
- Derr = regs.h.dh;
- return -1;
- }
- return 0;
- }
-