/*** * * File: pcpkt.c - packet driver interface for wattcp * * 27-Aug-93 fr final cleanup * 21-Sep-92 lr cleanup * 18-Jun-92 lr * * modified by Luigi Rizzo for use with Microsoft C 6.0 * Dec. 1991 * * The packet driver invokes a routine in asmpkt.asm to load * new packet into a circular buffer. pkt_received() returns * a non-null pointer if a new packet is arrived. * */ #define WATTCP_KERNEL #define PCPKT #include #ifdef debug void stampa_regs(char *s,struct REGPACK *r); void print_pkt(byte *p); #else /* !debug */ #define stampa_regs(x,y) #endif /* !debug */ #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 */ #ifdef COMMENT The structure of a buffer is as follows: struct _pktbuf { short busy; /* 1 if busy, 0 if free */ char et_header[14]; char data[...]; } _pktbuf[MAXBUFS]; #endif /* COMMENT */ int farcmp(char far *f, char *d, int len) { while (len--) if (*f++ != *d++) { return(1); } return(0); } int pkt_init(void) { struct REGPACK regs, regs2; char far *temp; int pd_type; /* packet driver type */ int class; _pktasminit( (char far *)pktbuf, MAXBUFS, BUFSIZE, &lost_packets); for (pkt_interrupt=INT_FIRST;pkt_interrupt<=INT_LAST;++pkt_interrupt ) { getvect( pkt_interrupt ); temp = (char far *)(interrupts[ pkt_interrupt ] +3); if ( !farcmp( temp, PKT_LINE, strlen( PKT_LINE ))) { break; /* found */ } } if ( pkt_interrupt > INT_LAST ) { outs("NO PACKET DRIVER FOUND"); return( 1 ); } DB3((stderr,"packet driver found at interrupt 0x%2x\n",pkt_interrupt)); /* lets find out about the driver */ segread(&(regs.s)); regs.r_ax = PD_DRIVER_INFO; stampa_regs("before driver_info",®s); intr( pkt_interrupt, ®s ); stampa_regs("after driver_info",®s); /* handle old versions, assume a class and just keep trying */ if (regs.r_flags & CARRY ) { /* old version */ 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( pkt_ip_type ); { word far *fp= &pkt_ip_type; regs.r_ds = FP_SEG( fp ); regs.r_si = FP_OFF( fp ); } { void far *s= (char far *)_pktentry; regs.r_es = FP_SEG( s ); regs.r_di = FP_OFF( s ); } stampa_regs("before access (old) type",®s); intr( pkt_interrupt, ®s ); stampa_regs("after access (old) type",®s); if ( ! (regs.r_flags & CARRY) ) break; } if (pd_type == 128 ) { outs("ERROR initializing packet driver\n\r"); return( 1 ); } /* we have found a working type, so kill it */ regs.r_bx = regs.r_ax; /* handle */ regs.r_ax = PD_RELEASE; stampa_regs("before release",®s); intr( pkt_interrupt, ®s ); stampa_regs("after release",®s); } } else { pd_type = regs.r_dx; switch ( _pktdevclass = (regs.r_cx >> 8)) { case PD_ETHER : _pktipofs = 14; case PD_SLIP : break; default : outs("ERROR: only ethernet packet drivers allowed\n\r"); return( 1 ); } } 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( pkt_ip_type ); { word far *fp= &pkt_ip_type; regs.r_ds = FP_SEG( fp ); regs.r_si = FP_OFF( fp ); } { void far *s= (char far *)_pktentry; regs.r_es = FP_SEG( s ); regs.r_di = FP_OFF( s ); } memcpy( ®s2, ®s, sizeof( regs )); { word far *fp= &pkt_arp_type; regs2.r_si = FP_OFF( fp ); regs2.r_ds = FP_SEG( fp ); } stampa_regs("before access IP type",®s); intr( pkt_interrupt, ®s ); stampa_regs("after access IP type",®s); if ( regs.r_flags & CARRY ) { outs("ERROR # 0x"); outhex( (unsigned char)(regs.r_dx >> 8) ); outs(" accessing IP type on packet driver\n\r" ); return( 1 ); } pkt_ip_handle = regs.r_ax; if (_pktdevclass != PD_SLIP) { stampa_regs("before access ARP type on regs2",®s2); intr( pkt_interrupt, ®s2 ); stampa_regs("after access ARP type on regs2",®s2); if ( regs2.r_flags & CARRY ) { regs.r_ax = PD_RELEASE; regs.r_bx = pkt_ip_handle; stampa_regs("failed ARP - before release IP type",®s); intr( pkt_interrupt, ®s ); stampa_regs("failed ARP - after release IP type",®s); outs("ERROR # 0x"); outhex( (unsigned char)(regs2.r_dx >> 8) ); outs(" accessing ARP type on packet driver\n\r" ); return( 1 ); } pkt_arp_handle = regs2.r_ax; } /* get ethernet address */ regs.r_ax = PD_GET_ADDRESS; regs.r_bx = pkt_ip_handle; { char far *fp= eth_addr; regs.r_es = FP_SEG( fp ); regs.r_di = FP_OFF( fp ); } regs.r_cx = sizeof( eth_addr ); stampa_regs("before get_addr",®s); intr( pkt_interrupt, ®s ); stampa_regs("after get_addr",®s); if ( regs.r_flags & CARRY ) { outs("ERROR # reading ethernet address\n\r" ); return( 1 ); } return( 0 ); } int pkt_release(void) { struct REGPACK regs; int error; error = 0; segread(&(regs.s)); if ( _pktdevclass != PD_SLIP ) { regs.r_ax = PD_RELEASE; regs.r_bx = pkt_arp_handle; stampa_regs("before release ARP in pkt_release",®s); intr( pkt_interrupt, ®s ); stampa_regs("after release ARP in pkt_release",®s); if (regs.r_flags & CARRY ) { outs("ERROR releasing packet driver for ARP\n\r"); error = 1; } } regs.r_ax = PD_RELEASE; regs.r_bx = pkt_ip_handle; stampa_regs("before release IP in pkt_release",®s); intr( pkt_interrupt, ®s ); stampa_regs("after release IP in pkt_release",®s); if (regs.r_flags & CARRY ) { outs("ERROR releasing packet driver for IP\n\r"); error = 1; } return( error ); } int pkt_send( char *buffer, int length ) { struct REGPACK regs; int retries; segread(&(regs.s)); retries = 5; while (retries--) { regs.r_ax = PD_SEND; { char far *fp= buffer; regs.r_ds = FP_SEG( fp ); regs.r_si = FP_OFF( fp ); } regs.r_cx = length; stampa_regs("before send in pkt_send",®s); DB2((stderr, "Sending PKT:\n")); #ifdef debug print_pkt(buffer); #endif /* debug */ intr( pkt_interrupt, ®s ); stampa_regs("after send in pkt_send",®s); if ( regs.r_flags & CARRY ) continue; return( 0 ); } return( 1 ); } void pkt_buf_wipe(void ) { memset( pktbuf, 0, sizeof( pktbuf )); } /* return a buffer to the pool */ void pkt_buf_release( char *ptr ) { DB2((stderr,"called pkt_buf_release()\r\n")); *(ptr - (2 + 14)) = 0; /* 14 is ip offset, 2 is busy word */ } void * pkt_received(void) { static word i=0; /* index of the current free buffer */ word j; if (pktbuf[i][0] != 1) return NULL; /* not found */ if (debug_on) { DB2((stderr, "Received PKT:\n")); #ifdef debug print_pkt(pktbuf[i]+2); #endif } j=i; /* temporary */ if (++i == MAXBUFS ) i=0; /* update pointer */ return( &pktbuf[j][2] ); } void * _pkt_eth_init(void) { if ( pkt_init() ) { outs("Program halted"); exit( 1 ); } return( eth_addr ); } #ifdef debug void stampa_regs(char *s,struct REGPACK *r) { DB2((stderr,"%s\n",s)); DB2((stderr,"AX: %4x, BX: %4x, CX: %4x, DX: %4x, SI: %4x, DI: %4x\n", (*r).x.ax, (*r).x.bx, (*r).x.cx, (*r).x.dx, (*r).x.si, (*r).x.di)); DB2((stderr,"CS: %4x, SS: %4x, DS: %4x, ES: %4x, FLAGS: %4x\n", (*r).s.cs, (*r).s.ss, (*r).s.ds, (*r).s.es, (*r).r_flags)); getch(); } void print_ip(byte *p) { in_Header *in= (in_Header *)p; byte *s; DB2((stderr,"Hdrlen: %2d ver: %2d tos: %3d len: %5d\n", in->hdrlen, in->ver, in->tos, intel16(in->length))); switch (in->proto) { case 0x11:s="UDP"; break; case 0x06:s="TCP"; break; case 0x01:s="ICMP"; break; default: s="unknown"; } DB2((stderr,"id: %5d frag: %5d ttl: %3d proto: %d (%s)\n", intel16(in->identification), intel16(in->frag), in->ttl, in->proto,s)); s= (char *)(&in->source); DB2((stderr,"chk: %4x, src: %d.%d.%d.%d", intel16(in->checksum), s[0],s[1],s[2],s[3])); s= (char *)(&in->destination); DB2((stderr," dst: %d.%d.%d.%d\n", s[0],s[1],s[2],s[3])); } void print_arp(byte *p) { arp_Header *a= (arp_Header *)p; byte *s; DB2((stderr,"hwtype: %4x protType: %4x hwProtAddrLen: %4x opcode: %4x\n", intel16(a->hwType),intel16(a->protType), intel16(a->hwProtAddrLen), intel16(a->opcode) )); s= (byte *)(&a->srcEthAddr); DB2((stderr,"src_eth: %2x %2x %2x %2x %2x %2x", s[0],s[1],s[2],s[3],s[4],s[5])); s= (byte *)(&a->srcIPAddr); DB2((stderr," src_ip: %d.%d.%d.%d\n", s[0],s[1],s[2],s[3])); s= (byte *)(&a->dstEthAddr); DB2((stderr,"dst_eth: %2x %2x %2x %2x %2x %2x", s[0],s[1],s[2],s[3],s[4],s[5])); s= (byte *)(&a->dstIPAddr); DB2((stderr," dst_ip: %d.%d.%d.%d\n", s[0],s[1],s[2],s[3])); } void print_pkt(byte *p) { DB2((stderr,"eth_dest: %2x %2x %2x %2x %2x %2x ", p[0],p[1],p[2],p[3],p[4],p[5])); p +=6; DB2((stderr,"eth_src: %2x %2x %2x %2x %2x %2x ", p[0],p[1],p[2],p[3],p[4],p[5])); p +=6; DB2((stderr,"mac_type: %2x %2x", p[0],p[1])); switch ( *( (word *)p) ) { /* use intelled values */ case 0x08: /* IP */ DB2((stderr," IP\n")); print_ip(p+2); break; case 0x608: /* ARP */ DB2((stderr," ARP\n")); print_arp(p+2); break; default: /* unknown */ DB2((stderr," unknown\n")); break; } getch(); } #endif