#include "copyright.h" #include "wattcp.h" #include "errors.h" #include "elib.h" #include #include #include "dpmi.h" #define OLD #ifdef OLD int bufcmp( char far *first, char far *last, int len ) { while ( len-- ) { if ( *first++ != *last++ ) return( 1 ); } return( 0 ); } #endif OLD #define INT_FIRST 0x60 #define INT_LAST 0x80 #define PKT_LINE "PKT DRVR" #define PD_DRIVER_INFO 0x1ff #define PD_ACCESS 0x200 #define PD_RELEASE 0x300 #define PD_SEND 0x400 #define PD_GET_ADDRESS 0x600 #define CARRY 1 /* carry bit in flags register */ static struct pkt_struct static_pkt_struct = {0x0008, 0x608}; /* intelled values */ struct pkt_struct far *pktstruct = &static_pkt_struct; struct pkt_struct far *pktstruct_raddr = &static_pkt_struct; word _pktipofs = 0; /* offset from header to start of pkt */ word pkt_interrupt; word pkt_ip_handle; word pkt_arp_handle; longword far *interrupts = 0L; #define ASMPKT /*far we may decide to use far later on */ extern void ASMPKT _pktentry(); void far (*_pktentry_raddr)() = _pktentry; extern void ASMPKT _pktasminit( void far *, int, int ); extern int qcmp( void far *, void far *, int ); void (*do_intr)() = intr; pkt_init() { struct REGPACK regs, regs2; char far *temp; int pd_type; /* packet driver type */ int class; _pktasminit( pktstruct_raddr->buf, MAXBUFS, BUFSIZE); for (pkt_interrupt = INT_FIRST; pkt_interrupt <= INT_LAST; ++pkt_interrupt ) { /* Map_real() is safe whether we're in protected mode or not. */ #ifdef WINDOWS temp = (char far *)map_real((char far *)(interrupts[pkt_interrupt]), (long)(sizeof(PKT_LINE)+3)); #else temp = (char far *)(interrupts[pkt_interrupt]); #endif #ifdef OLD class = bufcmp( &(temp[3]), PKT_LINE, sizeof( PKT_LINE )); #else class = qcmp( &(temp[3]), PKT_LINE, sizeof( PKT_LINE )); #endif OLD #ifdef WINDOWS unmap_real(temp); #endif if ( !class ) { break; } } if ( pkt_interrupt > INT_LAST ) { return(ER_NOPKTD); } /* lets find out about the driver */ regs.r_ax = PD_DRIVER_INFO; regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); /* handle old versions, assume a class and just keep trying */ if (regs.r_flags & CARRY ) { for ( class = 0; class < 2; ++class ) { _pktdevclass = (class) ? PD_SLIP : PD_ETHER; for (pd_type = 1; pd_type < 128; ++pd_type ) { regs.r_ax = PD_ACCESS | _pktdevclass; /* ETH, SLIP */ regs.r_bx = pd_type; /* type */ regs.r_dx = 0; /* if number */ regs.r_cx = sizeof( pktstruct_raddr->ip_type ); regs.r_ds = FP_SEG( &pktstruct_raddr->ip_type ); regs.r_si = FP_OFF( &pktstruct_raddr->ip_type ); regs.r_es = FP_SEG( _pktentry_raddr); regs.r_di = FP_OFF( _pktentry_raddr); regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if ( ! (regs.r_flags & CARRY) ) break; } if (pd_type == 128 ) { return(ER_PKTDINIT); } /* we have found a working type, so kill it */ regs.r_bx = regs.r_ax; /* handle */ regs.r_ax = PD_RELEASE; do_intr( pkt_interrupt, ®s ); } } else { pd_type = regs.r_dx; switch ( _pktdevclass = (regs.r_cx >> 8)) { case PD_ETHER : _pktipofs = 14; case PD_SLIP : break; default : return(ER_PKTDTYPE); } } regs.r_ax = PD_ACCESS | _pktdevclass; regs.r_bx = 0xffff; /* any type - was pd_type type */ regs.r_dx = 0; /* if number */ regs.r_cx = sizeof( pktstruct_raddr->ip_type ); regs.r_ds = FP_SEG( &pktstruct_raddr->ip_type ); regs.r_si = FP_OFF( &pktstruct_raddr->ip_type ); regs.r_es = FP_SEG( _pktentry_raddr); regs.r_di = FP_OFF( _pktentry_raddr); memcpy( ®s2, ®s, sizeof( regs )); regs2.r_si = FP_OFF( &pktstruct_raddr->arp_type ); regs2.r_ds = FP_SEG( &pktstruct_raddr->arp_type ); regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if ( regs.r_flags & CARRY ) { #ifdef WINDOWS /* nothing */ #else outs("ERROR # 0x"); outhex( regs.r_dx >> 8 ); outs(" accessing packet driver\n\r" ); #endif return(ER_PKTDACCESS); } pkt_ip_handle = regs.r_ax; if (_pktdevclass != PD_SLIP) { regs2.r_flags = CARRY; do_intr( pkt_interrupt, ®s2 ); if ( regs2.r_flags & CARRY ) { regs.r_ax = PD_RELEASE; regs.r_bx = pkt_ip_handle; do_intr( pkt_interrupt, ®s ); #ifdef WINDOWS /* nothing */ #else outs("ERROR # 0x"); outhex( regs2.r_dx >> 8 ); outs(" accessing packet driver\n\r" ); #endif return(ER_PKTDACCESS); } pkt_arp_handle = regs2.r_ax; } /* get ethernet address */ regs.r_ax = PD_GET_ADDRESS; regs.r_bx = pkt_ip_handle; regs.r_es = FP_SEG( &pktstruct_raddr->eth_addr ); regs.r_di = FP_OFF( &pktstruct_raddr->eth_addr ); regs.r_cx = sizeof( &pktstruct_raddr->eth_addr ); regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if ( regs.r_flags & CARRY ) { return(ER_ETHADDR); } return( 0 ); } pkt_release() { struct REGPACK regs; int error; error = 0; if ( _pktdevclass != PD_SLIP ) { regs.r_ax = PD_RELEASE; regs.r_bx = pkt_arp_handle; regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if (regs.r_flags & CARRY ) { error = ER_PKTDRELSE; } } regs.r_ax = PD_RELEASE; regs.r_bx = pkt_ip_handle; regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if (regs.r_flags & CARRY ) { error = ER_PKTDRELSE; } return( error ); } int pkt_send( register char *buffer, int length ) { register int i; register char far *p; struct REGPACK regs; int retries; if(length > sizeof(pktstruct->send_buf)) return(1); for(p = &pktstruct->send_buf, i = length; i > 0; --i) /* YECH! */ *p++ = *buffer++; retries = 5; while(retries--) { regs.r_ax = PD_SEND; regs.r_ds = FP_SEG( &pktstruct_raddr->send_buf ); regs.r_si = FP_OFF( &pktstruct_raddr->send_buf ); regs.r_cx = length; regs.r_flags = CARRY; do_intr( pkt_interrupt, ®s ); if ( regs.r_flags & CARRY ) continue; return( 0 ); } return( 1 ); } /* return a buffer to the pool */ pkt_buf_wipe() { char far *fp; for(fp = &pktstruct->buf[sizeof(pktstruct->buf)-1]; fp >= (char far *)pktstruct->buf;) *fp-- = 0; } pkt_buf_release( char *ptr ) { char far *fptr; *(ptr - (2 + 14)) = 0; if(pktstruct != &static_pkt_struct) { fptr=(char far *)pktstruct->buf + (ptr - (char *)static_pkt_struct.buf); *(fptr - (2 + 14)) = 0; } } void * pkt_received() { register int i; int old; word oldin, newin; /* ip sequence numbers */ register char far *fp; register char *np; /* check if there are any */ old = oldin = 0xffff; /* Scan for the packet with the lowest sequence number */ for ( i = 0 ; i < MAXBUFS; ++i ) { if ( *pktstruct->buf[i] != 1 ) continue; newin = *(word*)(&pktstruct->buf[i][ _pktipofs + 4 + 2]); if ( newin <= oldin ) { oldin = newin; old = i; } } /* If a packet was found mark it used, copy the contents over to */ /* the local buffer, and return the address of the local buffer */ if(old == -1) return NULL; else { if(pktstruct != &static_pkt_struct) { fp = pktstruct->buf[old]; np = static_pkt_struct.buf[old]; for(i = sizeof(pktstruct->buf[0]); i > 0; --i) *np++ = *fp++; } return( &static_pkt_struct.buf[old][2] ); } #ifdef OLD for (i=0; i < MAXBUFS; ++i) { if ( *pktstruct->buf[i] == 1 ) { *pktstruct->buf[i] = 2; if(pktstruct != &static_pkt_struct) { fp = pktstruct->buf[i]; np = static_pkt_struct.buf[i]; for(i = sizeof(pktstruct->buf[i]); i > 0; --i) *np++ = *fp++; } return( &static_pkt_struct.buf[i][2] ); } } #endif } void * _pkt_eth_init() { register char far *fp; register char *np; register int i; if ( pkt_init() ) { sock_exit(); return NULL; } if(pktstruct != &static_pkt_struct) { fp = &pktstruct->eth_addr, np = &static_pkt_struct.eth_addr; for(i = sizeof(pktstruct->eth_addr); i > 0; --i) *np++ = *fp++; } return( &static_pkt_struct.eth_addr ); }