diff --git a/FILES b/FILES index 95a4505..95b75cf 100644 --- a/FILES +++ b/FILES @@ -53,6 +53,19 @@ lbl/os-ultrix4.h llc.h missing/snprintf.c mkdep +msdos/bin2c.c +msdos/common.dj +msdos/makefile +msdos/makefile.dj +msdos/makefile.wc +msdos/ndis2.c +msdos/ndis2.h +msdos/ndis_0.asm +msdos/pkt_rx0.asm +msdos/pkt_rx1.s +msdos/pktdrvr.c +msdos/pktdrvr.h +msdos/readme.dos nametoaddr.c nlpid.h optimize.c @@ -63,6 +76,8 @@ pcap-bpf.h pcap-dag.c pcap-dag.h pcap-dlpi.c +pcap-dos.c +pcap-dos.h pcap-enet.c pcap-int.h pcap-linux.c diff --git a/INSTALL.txt b/INSTALL.txt index 3a2d2ad..2496d98 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,4 +1,4 @@ -@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.11 2004-10-18 09:51:02 guy Exp $ (LBL) +@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.12 2004-12-18 08:52:08 guy Exp $ (LBL) To build libpcap, run "./configure" (a shell script). The configure script will determine your system attributes and generate an @@ -341,6 +341,7 @@ lbl/os-*.h - OS-dependent defines and prototypes llc.h - 802.2 LLC SAP definitions missing/* - replacements for missing library functions mkdep - construct Makefile dependency list +msdos/* - drivers for MS-DOS capture support nametoaddr.c - hostname to address routines nlpid.h - OSI network layer protocol identifier definitions net - symlink to bpf/net @@ -351,6 +352,8 @@ pcap-bpf.h - BPF definitions pcap-dag.c - Endace DAG device capture support pcap-dag.h - Endace DAG device capture support pcap-dlpi.c - Data Link Provider Interface support +pcap-dos.c - MS-DOS capture support +pcap-dos.h - headers for MS-DOS capture support pcap-enet.c - enet support pcap-int.h - internal libpcap definitions pcap-linux.c - Linux packet socket support diff --git a/gencode.c b/gencode.c index 023e14d..af7fcce 100644 --- a/gencode.c +++ b/gencode.c @@ -21,7 +21,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.214 2004-12-17 20:16:44 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.215 2004-12-18 08:52:09 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -58,6 +58,10 @@ static const char rcsid[] _U_ = #include #include +#ifdef MSDOS +#include "pcap-dos.h" +#endif + #include "pcap-int.h" #include "ethertype.h" diff --git a/inet.c b/inet.c index 6cce801..20b2cac 100644 --- a/inet.c +++ b/inet.c @@ -34,7 +34,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.62 2004-12-17 20:32:35 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.63 2004-12-18 08:52:09 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -46,7 +46,9 @@ static const char rcsid[] _U_ = #else /* WIN32 */ #include +#ifndef MSDOS #include +#endif #include #include #ifdef HAVE_SYS_SOCKIO_H @@ -65,9 +67,9 @@ struct rtentry; /* declarations in */ #include #include #include -#ifndef WIN32 +#if !defined(WIN32) && !defined(__BORLANDC__) #include -#endif /* WIN32 */ +#endif /* !WIN32 && !__BORLANDC__ */ #ifdef HAVE_LIMITS_H #include #else @@ -446,7 +448,7 @@ pcap_freealldevs(pcap_if_t *alldevs) } } -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) /* * Return the name of a network interface attached to the system, or NULL @@ -570,7 +572,7 @@ pcap_lookupnet(device, netp, maskp, errbuf) return (0); } -#else /* WIN32 */ +#elif defined(WIN32) /* * Return the name of a network interface attached to the system, or NULL @@ -696,4 +698,4 @@ pcap_lookupnet(device, netp, maskp, errbuf) return (0); } -#endif /* WIN32 */ +#endif /* !WIN32 && !MSDOS */ diff --git a/msdos/bin2c.c b/msdos/bin2c.c new file mode 100644 index 0000000..d82056e --- /dev/null +++ b/msdos/bin2c.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +static void Abort (char *fmt,...) +{ + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + exit (1); +} + +int main (int argc, char **argv) +{ + FILE *inFile; + FILE *outFile = stdout; + time_t now = time (NULL); + int ch, i; + + if (argc != 2) + Abort ("Usage: %s bin-file [> result]", argv[0]); + + if ((inFile = fopen(argv[1],"rb")) == NULL) + Abort ("Cannot open %s\n", argv[1]); + + fprintf (outFile, + "/* data statements for file %s at %.24s */\n" + "/* Generated by BIN2C, G.Vanem 1995 */\n", + argv[1], ctime(&now)); + + i = 0; + while ((ch = fgetc(inFile)) != EOF) + { + if (i++ % 12 == 0) + fputs ("\n ", outFile); + fprintf (outFile, "0x%02X,", ch); + } + fputc ('\n', outFile); + fclose (inFile); + return (0); +} diff --git a/msdos/common.dj b/msdos/common.dj new file mode 100644 index 0000000..c731361 --- /dev/null +++ b/msdos/common.dj @@ -0,0 +1,79 @@ +# +# Common defines for libpcap and 16/32-bit network drivers (djgpp) +# + +.SUFFIXES: .exe .wlm .dxe .l .y +.PHONY: check_gcclib + +default: check_gcclib all + +GCCLIB = /djgpp/lib/gcc-lib/djgpp/3.31 +MAKEFILE = Makefile.dj + +# +# DLX 2.91+ lib. Change path to suite. +# Not used anymore. Uses DXE3 now. +# +# DLX_LIB = $(DJDIR)/contrib/dlx.291/libdlx.a +# DLX_LINK = $(DJDIR)/bin/dlxgen.exe + +WATT32_ROOT = $(subst \,/,$(WATT_ROOT)) + + +ifeq ($(wildcard $(GCCLIB)/libgcc.a),) +check_gcclib: + @echo libgcc.a not found. Set \"$(GCCLIB)\" to \"/djgpp/lib/gcc-lib/djgpp/3.X\" +endif + + +# +# Include 32-bit driver support +# +USE_32BIT_DRIVERS = 1 + +# +# Use loadable driver modules instead of statically linking +# all drivers. +# +USE_32BIT_MODULES = 0 + +# +# Put interrupt sensitive code/data in locked sections +# Do `make clean' in all affected directories after changing this. +# +USE_SECTION_LOCKING = 0 + +# +# Set to 1 to use exception handler lib (only for me) +# +USE_EXCEPT = 0 + +CC = gcc.exe +LD = ld.exe +ASM = nasm.exe -fbin -dDEBUG +YACC = bison.exe +LEX = flex.exe + +CFLAGS = -g -gcoff -O2 -Wall -I. -I$(WATT32_ROOT)/inc + +ifeq ($(USE_EXCEPT),1) + CFLAGS += -DUSE_EXCEPT + EXC_LIB = d:/prog/mw/except/lib/libexc.a +endif + +ifeq ($(USE_SECTION_LOCKING),1) + CFLAGS += -DUSE_SECTION_LOCKING +endif + +ifeq ($(USE_32BIT_DRIVERS),1) + CFLAGS += -DUSE_32BIT_DRIVERS +endif + +%.o: %.c + $(CC) -c $(CFLAGS) $< + @echo + +%.o: %.s + $(CC) -c $(CFLAGS) -x assembler-with-cpp -o $@ $< + @echo + diff --git a/msdos/makefile b/msdos/makefile new file mode 100644 index 0000000..cdb4e7c --- /dev/null +++ b/msdos/makefile @@ -0,0 +1,184 @@ +# +# Makefile for dos-libpcap. NB. This makefile requires a Borland +# compatible make tool. +# +# Targets: +# Borland C 4.0+ (DOS large model) +# Metaware HighC 3.3+ (PharLap 386|DosX) +# + +.AUTODEPEND +.SWAP + +!if "$(WATT_ROOT)" == "" +!error Environment variable "WATT_ROOT" not set. +!endif + +WATT_INC = $(WATT_ROOT)\inc + +DEFS = -DMSDOS -DDEBUG -DNDIS_DEBUG -D_U_= -Dinline= \ + -DHAVE_STRERROR -DHAVE_LIMITS_H + +ASM = tasm.exe -t -l -mx -m2 -DDEBUG + +SOURCE = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ + etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ + savefile.c pcap.c inet.c msdos\ndis2.c msdos\pktdrvr.c \ + missing\snprintf.c + +BORLAND_OBJ = $(SOURCE:.c=.obj) msdos\pkt_rx0.obj msdos\ndis_0.obj + +HIGHC_OBJ = $(SOURCE:.c=.o32) msdos\pkt_rx0.o32 + +all: + @echo Usage: make pcap_bc.lib or pcap_hc.lib + + +pcap_bc.lib: bcc.arg $(BORLAND_OBJ) pcap_bc + + +pcap_hc.lib: hc386.arg $(HIGHC_OBJ) + 386lib $< @&&| + -nowarn -nobackup -twocase -replace $(HIGHC_OBJ) +| + +pcap_bc: $(BORLAND_OBJ) + @tlib pcap_bc.lib /C @&&| + -+$(**:.obj=-+) +| + +.c.obj: + bcc.exe @bcc.arg -o$*.obj $*.c + +.c.o32: + hc386.exe @hc386.arg -o $*.o32 $*.c + +.asm.obj: + $(ASM) $*.asm, $*.obj + +.asm.o32: + $(ASM) -DDOSX=1 $*.asm, $*.o32 + +scanner.c: scanner.l + flex -Ppcap_ -7 -oscanner.c scanner.l + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines grammar.y + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +bcc.arg: msdos\Makefile + @copy &&| + $(DEFS) -ml -c -v -3 -O2 -po -RT- -w- + -I$(WATT_INC) -I. -I.\msdos\pm_drvr -H=$(TEMP)\bcc.sym +| $< + +hc386.arg: msdos\Makefile + @copy &&| + # -DUSE_32BIT_DRIVERS + $(DEFS) -DDOSX=1 -w3 -c -g -O5 + -I$(WATT_INC) -I. -I.\msdos\pm_drvr + -Hsuffix=.o32 + -Hnocopyr + -Hpragma=Offwarn(491,553,572) + -Hon=Recognize_library # make memcpy/strlen etc. inline + -Hoff=Behaved # turn off some optimiser warnings +| $< + +clean: + @del *.obj + @del *.o32 + @del *.lst + @del *.map + @del bcc.arg + @del hc386.arg + @del grammar.c + @del tokdefs.h + @del scanner.c + @echo Cleaned + +# +# dependencies +# +pkt_rx0.obj: msdos\pkt_rx0.asm + +bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h + +grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + +pkt_rx0.o32: msdos\pkt_rx0.asm + +bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +bpf_imag.o32: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.o32: bpf_dump.c pcap.h pcap-bpf.h + +etherent.o32: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.o32: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.o32: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.o32: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +inet.o32: inet.c pcap-int.h pcap.h pcap-bpf.h + +grammar.o32: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.o32: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.o32: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.o32: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.o32: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.o32: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.o32: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + diff --git a/msdos/makefile.dj b/msdos/makefile.dj new file mode 100644 index 0000000..cbfb9cb --- /dev/null +++ b/msdos/makefile.dj @@ -0,0 +1,147 @@ +# +# GNU Makefile for DOS-libpcap. djgpp version. +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> make -f msdos/makefile.dj +# + +VPATH = missing msdos + +PREREQUISITES = scanner.c grammar.c tokdefs.h msdos/pkt_stub.inc + +include msdos/common.dj + +DRIVER_DIR = ./msdos/pm_drvr + +CFLAGS += -DDEBUG -DNDIS_DEBUG -DHAVE_LIMITS_H -DHAVE_STRERROR \ + -D_U_='__attribute__((unused))' + +# CFLAGS += -Dyylval=pcap_lval -DBDEBUG -DNDEBUG + +SOURCES = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ + etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ + savefile.c pcap.c inet.c msdos\pktdrvr.c msdos/ndis2.c \ + missing/snprintf.c + +OBJECTS = $(notdir $(SOURCES:.c=.o)) +TEMPBIN = tmp.bin + +ifeq ($(USE_32BIT_DRIVERS),1) + PM_OBJECTS = $(addprefix $(DRIVER_DIR)/, \ + printk.o pci.o pci-scan.o bios32.o dma.o irq.o intwrap.o \ + lock.o kmalloc.o quirks.o timer.o net_init.o) + # + # Static link of drivers + # + ifeq ($(USE_32BIT_MODULES),0) + PM_OBJECTS += $(addprefix $(DRIVER_DIR)/, \ + accton.o 8390.o 3c503.o 3c509.o 3c59x.o 3c515.o \ + 3c575_cb.o 3c90x.o ne.o wd.o cs89x0.o rtl8139.o) + endif +endif + +all: libpcap.a + +ifeq ($(USE_32BIT_DRIVERS),1) +$(PM_OBJECTS): + $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) $(notdir $@) +endif + +libpcap.a: $(OBJECTS) $(PM_OBJECTS) + rm -f $@ + ar rs $@ $^ + +msdos/pkt_stub.inc: msdos/bin2c.exe msdos/pkt_rx1.S + $(ASM) -o $(TEMPBIN) -lmsdos/pkt_rx1.lst msdos/pkt_rx1.S + ./msdos/bin2c $(TEMPBIN) > $@ + rm -f $(TEMPBIN) + +grammar.c tokdefs.h: grammar.y + rm -f grammar.c tokdefs.h + $(YACC) --name-prefix=pcap_ --yacc --defines grammar.y + mv -f y_tab.c grammar.c + mv -f y_tab.h tokdefs.h + +scanner.c: scanner.l + $(LEX) -Ppcap_ -7 -t $^ > $@ + @echo + +msdos/bin2c.exe: msdos/bin2c.c + $(CC) $*.c -o $*.exe + +clean: + $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) clean + $(MAKE) -f Makefile.dj -C libcpcap clean + rm -f $(OBJECTS) msdos/pkt_rx1.lst Makefile.bak $(PREREQUISITES) + +vclean: clean + rm -f libpcap.a msdos/bin2c.exe + +# +# Generated dependencies; Due to some hacks in gcc 2.95 and djgpp 2.03 +# we must prevent "$(DJDIR)/bin/../include/sys/version.h" from beeing +# included in dependency output (or else this makefile cannot be used on +# another machine). We therefore use a special 'specs' file during +# pre-processing. +# +MM_SPECS = specs.tmp +MAKEFILE = msdos/Makefile.dj + +depend: $(PREREQUISITES) + @echo Generating dependencies.. + @cp $(MAKEFILE) Makefile.bak + @echo "*cpp: %(cpp_cpu) %{posix:-D_POSIX_SOURCE} -remap" > $(MM_SPECS) + sed -e "/^# DO NOT DELETE THIS LINE/,$$d" < Makefile.bak > $(MAKEFILE) + echo "# DO NOT DELETE THIS LINE" >> $(MAKEFILE) + $(CC) -MM -specs=$(MM_SPECS) $(CFLAGS) $(SOURCES) >> $(MAKEFILE) + rm -f $(MM_SPECS) + +# +# Manually generated dependencies +# +msdos/pktdrvr.c: msdos/pkt_stub.inc +scanner.c: scanner.l +grammar.c tokdefs.h: grammar.y +grammar.h: grammar.y +scanner.l: pcap-int.h pcap-namedb.h gencode.h grammar.h gnuc.h +grammar.y: pcap-int.h gencode.h pcap-namedb.h gnuc.h + +# +# Automatically generated dependencies +# +# DO NOT DELETE THIS LINE +grammar.o: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h pf.h \ + pcap-namedb.h +scanner.o: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h pcap-namedb.h \ + tokdefs.h +bpf_filt.o: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h +bpf_imag.o: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h +bpf_dump.o: bpf_dump.c pcap.h pcap-bpf.h +etherent.o: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h +gencode.o: gencode.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h \ + ppp.h sll.h arcnet.h pf.h pcap-namedb.h +nametoad.o: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h +pcap-dos.o: pcap-dos.c msdos/pm_drvr/pmdrvr.h msdos/pm_drvr/iface.h \ + msdos/pm_drvr/lock.h msdos/pm_drvr/ioport.h pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos/pm_drvr/kmalloc.h msdos/pm_drvr/bitops.h \ + msdos/pm_drvr/timer.h msdos/pm_drvr/dma.h msdos/pm_drvr/irq.h \ + msdos/pm_drvr/printk.h msdos/pm_drvr/pci.h msdos/pm_drvr/bios32.h \ + msdos/pm_drvr/module.h msdos/pm_drvr/3c501.h msdos/pm_drvr/3c503.h \ + msdos/pm_drvr/3c509.h msdos/pm_drvr/3c59x.h msdos/pm_drvr/3c515.h \ + msdos/pm_drvr/3c90x.h msdos/pm_drvr/3c575_cb.h msdos/pm_drvr/ne.h \ + msdos/pm_drvr/wd.h msdos/pm_drvr/accton.h msdos/pm_drvr/cs89x0.h \ + msdos/pm_drvr/rtl8139.h msdos/pm_drvr/ne2k-pci.h msdos/pktdrvr.h +optimize.o: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h +savefile.o: savefile.c pcap-int.h pcap.h pcap-bpf.h +pcap.o: pcap.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h +inet.o: inet.c pcap-int.h pcap.h pcap-bpf.h +pktdrvr.o: msdos/pktdrvr.c gnuc.h pcap-dos.h msdos/pm_drvr/lock.h \ + pcap-int.h pcap.h pcap-bpf.h msdos/pktdrvr.h msdos/pkt_stub.inc +ndis2.o: msdos/ndis2.c pcap-dos.h msdos/pm_drvr/lock.h pcap-int.h pcap.h \ + pcap-bpf.h msdos/ndis2.h +snprintf.o: missing/snprintf.c pcap-int.h pcap.h pcap-bpf.h diff --git a/msdos/makefile.wc b/msdos/makefile.wc new file mode 100644 index 0000000..e0d5672 --- /dev/null +++ b/msdos/makefile.wc @@ -0,0 +1,131 @@ +# +# Watcom Makefile for dos-libpcap. +# +# Specify MODEL = `3r' or `3s' +# Specify TARGET = `pharlap' or `dos4g' +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> wmake -f msdos\makefile.wc +# + +MODEL = 3s +TARGET = dos4g + +OBJDIR = msdos\$(TARGET).w$(MODEL) +LIB = $(OBJDIR)\pcap.lib + +.EXTENSIONS: .l .y + +DEFS = -dDEBUG -dNDIS_DEBUG -d_U_= -dHAVE_LIMITS_H -dHAVE_STRERROR & + -dHAVE_SNPRINTF -dHAVE_VSNPRINTF + +CC = wcc386.exe +ASM = wasm.exe -$(MODEL) $(DEFS) -dDOSX -dDOS4GW -zq -bt=dos -fr=nul -d3 -s + +OBJS = $(OBJDIR)\grammar.obj $(OBJDIR)\scanner.obj $(OBJDIR)\pcap.obj & + $(OBJDIR)\bpf_filt.obj $(OBJDIR)\bpf_imag.obj $(OBJDIR)\bpf_dump.obj & + $(OBJDIR)\etherent.obj $(OBJDIR)\gencode.obj $(OBJDIR)\nametoad.obj & + $(OBJDIR)\pcap-dos.obj $(OBJDIR)\pktdrvr.obj $(OBJDIR)\optimize.obj & + $(OBJDIR)\savefile.obj $(OBJDIR)\inet.obj $(OBJDIR)\ndis2.obj + +CFLAGS = $(DEFS) $(YYDEFS) -I. -I$(%watt_root)\inc -I.\msdos\pm_drvr & + -$(MODEL) -mf -zff -zgf -zq -bt=dos -fr=nul -w6 -fpi & + -oilrtf -zm + +TEMPBIN = tmp.bin + +all: $(OBJDIR) $(OBJDIR)\pcap.lib + +$(OBJDIR): + - mkdir $(OBJDIR) + +$(OBJDIR)\pcap.lib: $(OBJS) wlib.arg + wlib -q -b -c $(OBJDIR)\pcap.lib @wlib.arg + +wlib.arg: msdos\makefile.wc + %create $^@ + for %f in ($(OBJS)) do %append $^@ +- %f + +$(OBJDIR)\pktdrvr.obj: msdos\pkt_stub.inc msdos\pktdrvr.c gnuc.h & + pcap-dos.h pcap-int.h pcap.h msdos\pktdrvr.h + *$(CC) $(CFLAGS) msdos\pktdrvr.c -fo=$@ + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c + *$(CC) $(CFLAGS) msdos\ndis2.c -fo=$@ + +.ERASE +.c{$(OBJDIR)}.obj: + *$(CC) $(CFLAGS) $[@ -fo=$@ + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines $[@ + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +scanner.c: scanner.l + flex -Ppcap_ -7 -o$@ $[@ + +msdos\pkt_stub.inc: bin2c.exe msdos\pkt_rx1.S + nasm -fbin -dDEBUG -o $(TEMPBIN) -lmsdos\pkt_rx1.lst msdos\pkt_rx1.S + bin2c.exe $(TEMPBIN) > $@ + @del $(TEMPBIN) + +bin2c.exe: msdos\bin2c.c + wcl $[@ + +clean realclean vclean: .SYMBOLIC + for %f in (dos4g.w3r dos4g.w3s pharlap.w3r pharlap.w3s) do & + @del %f\*.obj + @del grammar.c + @del tokdefs.h + @del scanner.c + @del bin2c.exe + @del bin2c.obj + @del msdos\pkt_stub.inc + @echo Cleaned + +# +# dependencies +# +$(OBJDIR)\bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h + +$(OBJDIR)\bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +$(OBJDIR)\etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-nam.h + +$(OBJDIR)\optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +$(OBJDIR)\savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\inet.obj: inet.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pf.h pcap-nam.h + +$(OBJDIR)\scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-nam.h tokdefs.h + +$(OBJDIR)\gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + ethertyp.h nlpid.h llc.h gencode.h atmuni31.h sunatmpo.h ppp.h sll.h & + arcnet.h pf.h pcap-nam.h + +$(OBJDIR)\nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-nam.h ethertyp.h + +$(OBJDIR)\pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h & + msdos\pktdrvr.h + +$(OBJDIR)\pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h & + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + msdos\ndis2.h + diff --git a/msdos/ndis2.c b/msdos/ndis2.c new file mode 100644 index 0000000..0a5ea2a --- /dev/null +++ b/msdos/ndis2.c @@ -0,0 +1,860 @@ +/* + * Copyright (c) 1993,1994 + * Texas A&M University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Texas A&M University + * and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Developers: + * David K. Hess, Douglas Lee Schales, David R. Safford + * + * Heavily modified for Metaware HighC + GNU C 2.8+ + * Gisle Vanem 1998 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/ndis2.h" + +#if defined(USE_NDIS2) + +/* + * Packet buffer handling + */ +extern int FreePktBuf (PktBuf *buf); +extern int EnquePktBuf (PktBuf *buf); +extern PktBuf* AllocPktBuf (void); + +/* + * Various defines + */ +#define MAX_NUM_DEBUG_STRINGS 90 +#define DEBUG_STRING_LENGTH 80 +#define STACK_POOL_SIZE 6 +#define STACK_SIZE 256 + +#define MEDIA_FDDI 1 +#define MEDIA_ETHERNET 2 +#define MEDIA_TOKEN 3 + +static int startDebug = 0; +static int stopDebug = 0; + +static DWORD droppedPackets = 0L; +static WORD frameSize = 0; +static WORD headerSize = 0; +static int mediaType = 0; +static char *lastErr = NULL; + +static BYTE debugStrings [MAX_NUM_DEBUG_STRINGS][DEBUG_STRING_LENGTH]; +static BYTE *freeStacks [STACK_POOL_SIZE]; +static int freeStackPtr = STACK_POOL_SIZE - 1; + +static ProtMan protManEntry = NULL; +static WORD protManDS = 0; +static volatile int xmitPending; + +static struct _PktBuf *txBufPending; +static struct _CardHandle *handle; +static struct _CommonChars common; +static struct _ProtocolChars protChars; +static struct _ProtDispatch lowerTable; + +static struct _FailingModules failingModules; +static struct _BindingsList bindings; + +static struct { + WORD err_num; + char *err_text; + } ndis_errlist[] = { + + { ERR_SUCCESS, + "The function completed successfully.\n" }, + + { ERR_WAIT_FOR_RELEASE, + "The ReceiveChain completed successfully but the protocol has\n" + "retained control of the buffer.\n" }, + + { ERR_REQUEST_QUEUED, + "The current request has been queued.\n" }, + + { ERR_FRAME_NOT_RECOGNIZED, + "Frame not recognized.\n" }, + + { ERR_FRAME_REJECTED, + "Frame was discarded.\n" }, + + { ERR_FORWARD_FRAME, + "Protocol wishes to forward frame to another protocol.\n" }, + + { ERR_OUT_OF_RESOURCE, + "Out of resource.\n" }, + + { ERR_INVALID_PARAMETER, + "Invalid parameter.\n" }, + + { ERR_INVALID_FUNCTION, + "Invalid function.\n" }, + + { ERR_NOT_SUPPORTED, + "Not supported.\n" }, + + { ERR_HARDWARE_ERROR, + "Hardware error.\n" }, + + { ERR_TRANSMIT_ERROR, + "The packet was not transmitted due to an error.\n" }, + + { ERR_NO_SUCH_DESTINATION, + "Token ring packet was not recognized when transmitted.\n" }, + + { ERR_BUFFER_TOO_SMALL, + "Provided buffer was too small.\n" }, + + { ERR_ALREADY_STARTED, + "Network drivers already started.\n" }, + + { ERR_INCOMPLETE_BINDING, + "Protocol driver could not complete its bindings.\n" }, + + { ERR_DRIVER_NOT_INITIALIZED, + "MAC did not initialize properly.\n" }, + + { ERR_HARDWARE_NOT_FOUND, + "Hardware not found.\n" }, + + { ERR_HARDWARE_FAILURE, + "Hardware failure.\n" }, + + { ERR_CONFIGURATION_FAILURE, + "Configuration failure.\n" }, + + { ERR_INTERRUPT_CONFLICT, + "Interrupt conflict.\n" }, + + { ERR_INCOMPATIBLE_MAC, + "The MAC is not compatible with the protocol.\n" }, + + { ERR_INITIALIZATION_FAILED, + "Initialization failed.\n" }, + + { ERR_NO_BINDING, + "Binding did not occur.\n" }, + + { ERR_NETWORK_MAY_NOT_BE_CONNECTED, + "The network may not be connected to the adapter.\n" }, + + { ERR_INCOMPATIBLE_OS_VERSION, + "The version of the operating system is incompatible with the protocol.\n" }, + + { ERR_ALREADY_REGISTERED, + "The protocol is already registered.\n" }, + + { ERR_PATH_NOT_FOUND, + "PROTMAN.EXE could not be found.\n" }, + + { ERR_INSUFFICIENT_MEMORY, + "Insufficient memory.\n" }, + + { ERR_INFO_NOT_FOUND, + "Protocol Mananger info structure is lost or corrupted.\n" }, + + { ERR_GENERAL_FAILURE, + "General failure.\n" } +}; + +/* + * Some handy macros + */ +#define PERROR(str) printf("%s (%d): %s\n", __FILE__,__LINE__,str) +#define DEBUG_RING() (debugStrings[stopDebug+1 == MAX_NUM_DEBUG_STRINGS ? \ + stopDebug = 0 : ++stopDebug]) + +/* + * needs rewrite for DOSX + */ +#define MAC_DISPATCH(hnd) ((struct _MacUpperDispatch*)(hnd)->common->upperDispatchTable) +#define MAC_STATUS(hnd) ((struct _MacStatusTable*) (hnd)->common->serviceStatus) +#define MAC_CHAR(hnd) ((struct _MacChars*) (hnd)->common->serviceChars) + +#ifdef NDIS_DEBUG + #define DEBUG0(str) printf (str) + #define DEBUG1(fmt,a) printf (fmt,a) + #define DEBUG2(fmt,a,b) printf (fmt,a,b) + #define TRACE0(str) sprintf (DEBUG_RING(),str) + #define TRACE1(fmt,a) sprintf (DEBUG_RING(),fmt,a) +#else + #define DEBUG0(str) ((void)0) + #define DEBUG1(fmt,a) ((void)0) + #define DEBUG2(fmt,a,b) ((void)0) + #define TRACE0(str) ((void)0) + #define TRACE1(fmt,a) ((void)0) +#endif + +/* + * This routine is called from both threads + */ +void NdisFreeStack (BYTE *aStack) +{ + GUARD(); + + if (freeStackPtr == STACK_POOL_SIZE - 1) + PERROR ("tried to free too many stacks"); + + freeStacks[++freeStackPtr] = aStack; + + if (freeStackPtr == 0) + TRACE0 ("freeStackPtr went positive\n"); + + UNGUARD(); +} + +/* + * This routine is called from callbacks to allocate local data + */ +BYTE *NdisAllocStack (void) +{ + BYTE *stack; + + GUARD(); + + if (freeStackPtr < 0) + { + /* Ran out of stack buffers. Return NULL which will start + * dropping packets + */ + TRACE0 ("freeStackPtr went negative\n"); + stack = 0; + } + else + stack = freeStacks[freeStackPtr--]; + + UNGUARD(); + return (stack); +} + +CALLBACK (NdisSystemRequest (DWORD param1, DWORD param2, WORD param3, + WORD opcode, WORD targetDS)) +{ + static int bindEntry = 0; + struct _CommonChars *macCommon; + volatile WORD result; + + switch (opcode) + { + case REQ_INITIATE_BIND: + macCommon = (struct _CommonChars*) param2; + if (macCommon == NULL) + { + printf ("There is an NDIS misconfiguration.\n"); + result = ERR_GENERAL_FAILURE; + break; + } + DEBUG2 ("module name %s\n" + "module type %s\n", + macCommon->moduleName, + ((MacChars*) macCommon->serviceChars)->macName); + + /* Binding to the MAC */ + result = macCommon->systemRequest ((DWORD)&common, (DWORD)&macCommon, + 0, REQ_BIND, + macCommon->moduleDS); + + if (!strcmp(bindings.moduleName[bindEntry], handle->moduleName)) + handle->common = macCommon; + else PERROR ("unknown module"); + ++bindEntry; + break; + + case REQ_INITIATE_UNBIND: + macCommon = (struct _CommonChars*) param2; + result = macCommon->systemRequest ((DWORD)&common, 0, + 0, REQ_UNBIND, + macCommon->moduleDS); + break; + + default: + result = ERR_GENERAL_FAILURE; + break; + } + ARGSUSED (param1); + ARGSUSED (param3); + ARGSUSED (targetDS); + return (result); +} + +CALLBACK (NdisRequestConfirm (WORD protId, WORD macId, WORD reqHandle, + WORD status, WORD request, WORD protDS)) +{ + ARGSUSED (protId); ARGSUSED (macId); + ARGSUSED (reqHandle); ARGSUSED (status); + ARGSUSED (request); ARGSUSED (protDS); + return (ERR_SUCCESS); +} + +CALLBACK (NdisTransmitConfirm (WORD protId, WORD macId, WORD reqHandle, + WORD status, WORD protDS)) +{ + xmitPending--; + FreePktBuf (txBufPending); /* Add passed ECB back to the free list */ + + ARGSUSED (reqHandle); + ARGSUSED (status); + ARGSUSED (protDS); + return (ERR_SUCCESS); +} + + +/* + * The primary function for receiving packets + */ +CALLBACK (NdisReceiveLookahead (WORD macId, WORD frameSize, + WORD bytesAvail, BYTE *buffer, + BYTE *indicate, WORD protDS)) +{ + int result; + PktBuf *pktBuf; + WORD bytesCopied; + struct _TDBufDescr tDBufDescr; + +#if 0 + TRACE1 ("lookahead length = %d, ", bytesAvail); + TRACE1 ("ecb = %08lX, ", *ecb); + TRACE1 ("count = %08lX\n", count); + TRACE1 ("offset = %08lX, ", offset); + TRACE1 ("timesAllowed = %d, ", timesAllowed); + TRACE1 ("packet size = %d\n", look->dataLookAheadLen); +#endif + + /* Allocate a buffer for the packet + */ + if ((pktBuf = AllocPktBuf()) == NULL) + { + droppedPackets++; + return (ERR_FRAME_REJECTED); + } + + /* + * Now kludge things. Note we will have to undo this later. This will + * make the packet contiguous after the MLID has done the requested copy. + */ + + tDBufDescr.tDDataCount = 1; + tDBufDescr.tDBufDescrRec[0].tDPtrType = NDIS_PTR_PHYSICAL; + tDBufDescr.tDBufDescrRec[0].tDDataPtr = pktBuf->buffer; + tDBufDescr.tDBufDescrRec[0].tDDataLen = pktBuf->length; + tDBufDescr.tDBufDescrRec[0].dummy = 0; + + result = MAC_DISPATCH(handle)->transferData (&bytesCopied, 0, &tDBufDescr, + handle->common->moduleDS); + pktBuf->packetLength = bytesCopied; + + if (result == ERR_SUCCESS) + EnquePktBuf(pktBuf); + else FreePktBuf (pktBuf); + + ARGSUSED (frameSize); + ARGSUSED (bytesAvail); + ARGSUSED (indicate); + ARGSUSED (protDS); + + return (ERR_SUCCESS); +} + +CALLBACK (NdisIndicationComplete (WORD macId, WORD protDS)) +{ + ARGSUSED (macId); + ARGSUSED (protDS); + + /* We don't give a hoot about these. Just return + */ + return (ERR_SUCCESS); +} + +/* + * This is the OTHER way we may receive packets + */ +CALLBACK (NdisReceiveChain (WORD macId, WORD frameSize, WORD reqHandle, + struct _RxBufDescr *rxBufDescr, + BYTE *indicate, WORD protDS)) +{ + struct _PktBuf *pktBuf; + int i; + + /* + * For now we copy the entire packet over to a PktBuf structure. This may be + * a performance hit but this routine probably isn't called very much, and + * it is a lot of work to do it otherwise. Also if it is a filter protocol + * packet we could end up sucking up MAC buffes. + */ + + if ((pktBuf = AllocPktBuf()) == NULL) + { + droppedPackets++; + return (ERR_FRAME_REJECTED); + } + pktBuf->packetLength = 0; + + /* Copy the packet to the buffer + */ + for (i = 0; i < rxBufDescr->rxDataCount; ++i) + { + struct _RxBufDescrRec *rxDescr = &rxBufDescr->rxBufDescrRec[i]; + + memcpy (pktBuf->buffer + pktBuf->packetLength, + rxDescr->rxDataPtr, rxDescr->rxDataLen); + pktBuf->packetLength += rxDescr->rxDataLen; + } + + EnquePktBuf (pktBuf); + + ARGSUSED (frameSize); + ARGSUSED (reqHandle); + ARGSUSED (indicate); + ARGSUSED (protDS); + + /* This frees up the buffer for the MAC to use + */ + return (ERR_SUCCESS); +} + +CALLBACK (NdisStatusProc (WORD macId, WORD param1, BYTE *indicate, + WORD opcode, WORD protDS)) +{ + switch (opcode) + { + case STATUS_RING_STATUS: + break; + case STATUS_ADAPTER_CHECK: + break; + case STATUS_START_RESET: + break; + case STATUS_INTERRUPT: + break; + case STATUS_END_RESET: + break; + default: + break; + } + ARGSUSED (macId); + ARGSUSED (param1); + ARGSUSED (indicate); + ARGSUSED (opcode); + ARGSUSED (protDS); + + /* We don't need to do anything about this stuff yet + */ + return (ERR_SUCCESS); +} + +/* + * Tell the NDIS driver to start the delivery of the packet + */ +int NdisSendPacket (struct _PktBuf *pktBuf, int macId) +{ + struct _TxBufDescr txBufDescr; + int result; + + xmitPending++; + txBufPending = pktBuf; /* we only have 1 pending Tx at a time */ + + txBufDescr.txImmedLen = 0; + txBufDescr.txImmedPtr = NULL; + txBufDescr.txDataCount = 1; + txBufDescr.txBufDescrRec[0].txPtrType = NDIS_PTR_PHYSICAL; + txBufDescr.txBufDescrRec[0].dummy = 0; + txBufDescr.txBufDescrRec[0].txDataLen = pktBuf->packetLength; + txBufDescr.txBufDescrRec[0].txDataPtr = pktBuf->buffer; + + result = MAC_DISPATCH(handle)->transmitChain (common.moduleId, + pktBuf->handle, + &txBufDescr, + handle->common->moduleDS); + switch (result) + { + case ERR_OUT_OF_RESOURCE: + /* Note that this should not happen but if it does there is not + * much we can do about it + */ + printf ("ERROR: transmit queue overflowed\n"); + return (0); + + case ERR_SUCCESS: + /* Everything was hunky dory and synchronous. Free up the + * packet buffer + */ + xmitPending--; + FreePktBuf (pktBuf); + return (1); + + case ERR_REQUEST_QUEUED: + /* Everything was hunky dory and asynchronous. Do nothing + */ + return (1); + + default: + printf ("Tx fail, code = %04X\n", result); + return (0); + } +} + + + +static int ndis_nerr = sizeof(ndis_errlist) / sizeof(ndis_errlist[0]); + +static char *Ndis_strerror (WORD errorCode) +{ + static char buf[30]; + int i; + + for (i = 0; i < ndis_nerr; i++) + if (errorCode == ndis_errlist[i].err_num) + return (ndis_errlist[i].err_text); + + sprintf (buf,"unknown error %d",errorCode); + return (buf); +} + + +char *NdisLastError (void) +{ + char *errStr = lastErr; + lastErr = NULL; + return (errStr); +} + +int NdisOpen (void) +{ + struct _ReqBlock reqBlock; + int result; + int ndisFd = open (NDIS_PATH, O_RDONLY); + + if (ndisFd < 0) + { + printf ("Could not open NDIS Protocol Manager device.\n"); + return (0); + } + + memset (&reqBlock, 0, sizeof(ReqBlock)); + + reqBlock.opcode = PM_GET_PROTOCOL_MANAGER_LINKAGE; + + result = NdisGetLinkage (ndisFd, (char*)&reqBlock, sizeof(ReqBlock)); + if (result != 0) + { + printf ("Could not get Protocol Manager linkage.\n"); + close (ndisFd); + return (0); + } + + close (ndisFd); + protManEntry = (ProtMan) reqBlock.pointer1; + protManDS = reqBlock.word1; + + DEBUG2 ("Entry Point = %04X:%04X\n", FP_SEG(protManEntry),FP_OFF(protManEntry)); + DEBUG1 ("ProtMan DS = %04X\n", protManDS); + return (1); +} + + +int NdisRegisterAndBind (int promis) +{ + struct _ReqBlock reqBlock; + WORD result; + + memset (&common,0,sizeof(common)); + + common.tableSize = sizeof (common); + + common.majorNdisVersion = 2; + common.minorNdisVersion = 0; + common.majorModuleVersion = 2; + common.minorModuleVersion = 0; + + /* Indicates binding from below and dynamically loaded + */ + common.moduleFlags = 0x00000006L; + + strcpy (common.moduleName, "PCAP"); + + common.protocolLevelUpper = 0xFF; + common.protocolLevelLower = 1; + common.interfaceLower = 1; +#ifdef __DJGPP__ + common.moduleDS = _dos_ds; /* the callback data segment */ +#else + common.moduleDS = _DS; +#endif + + common.systemRequest = (SystemRequest) systemRequestGlue; + common.serviceChars = (BYTE*) &protChars; + common.serviceStatus = NULL; + common.upperDispatchTable = NULL; + common.lowerDispatchTable = (BYTE*) &lowerTable; + + protChars.length = sizeof (protChars); + protChars.name[0] = 0; + protChars.type = 0; + + lowerTable.backPointer = &common; + lowerTable.requestConfirm = requestConfirmGlue; + lowerTable.transmitConfirm = transmitConfirmGlue; + lowerTable.receiveLookahead = receiveLookaheadGlue; + lowerTable.indicationComplete = indicationCompleteGlue; + lowerTable.receiveChain = receiveChainGlue; + lowerTable.status = statusGlue; + lowerTable.flags = 3; + if (promis) + lowerTable.flags |= 4; /* promiscous mode (receive everything) */ + + bindings.numBindings = 1; + strcpy (bindings.moduleName[0], handle->moduleName); + + /* Register ourselves with NDIS + */ + reqBlock.opcode = PM_REGISTER_MODULE; + reqBlock.pointer1 = (BYTE FAR*) &common; + reqBlock.pointer2 = (BYTE FAR*) &bindings; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + { + printf ("Protman registering failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* Start the binding process + */ + reqBlock.opcode = PM_BIND_AND_START; + reqBlock.pointer1 = (BYTE FAR*) &failingModules; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + { + printf ("Start binding failed: %s\n", Ndis_strerror(result)); + return (0); + } + return (1); +} + +static int CheckMacFeatures (CardHandle *card) +{ + DWORD serviceFlags; + BYTE _far *mediaString; + BYTE _far *mac_addr; + + DEBUG2 ("checking card features\n" + "common table address = %08lX, macId = %d\n", + card->common, card->common->moduleId); + + serviceFlags = MAC_CHAR (handle)->serviceFlags; + + if ((serviceFlags & SF_PROMISCUOUS) == 0) + { + printf ("The MAC %s does not support promiscuous mode.\n", + card->moduleName); + return (0); + } + + mediaString = MAC_CHAR (handle)->macName; + + DEBUG1 ("media type = %s\n",mediaString); + + /* Get the media type. And set the header size + */ + if (!strncmp(mediaString,"802.3",5) || + !strncmp(mediaString,"DIX",3) || + !strncmp(mediaString,"DIX+802.3",9)) + headerSize = sizeof (EthernetIIHeader); + + else if (!strncmp(mediaString,"FDDI",4)) + headerSize = sizeof (FddiHeader) + + sizeof (Ieee802Dot2SnapHeader); + else + { + printf ("Unsupported MAC type: `%s'\n", mediaString); + return (0); + } + + frameSize = MAC_CHAR (handle)->maxFrameSize; + mac_addr = MAC_CHAR (handle)->currentAddress; + + printf ("Hardware address: %02X:%02X:%02X:%02X:%02X:%02X\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + return (1); +} + +static int NdisStartMac (CardHandle *card) +{ + WORD result; + + /* Set the lookahead length + */ + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, + headerSize, 0, + REQ_SET_LOOKAHEAD, + card->common->moduleDS); + + /* We assume that if we got INVALID PARAMETER then either this + * is not supported or will work anyway. NE2000 does this. + */ + if (result != ERR_SUCCESS && result != ERR_INVALID_PARAMETER) + { + DEBUG1 ("Set lookahead failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* Set the packet filter. Note that for some medias and drivers we + * must specify all three flags or the card(s) will not operate correctly. + */ + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, + /* all packets */ FILTER_PROMISCUOUS | + /* packets to us */ FILTER_DIRECTED | + /* broadcasts */ FILTER_BROADCAST, + 0, REQ_SET_PACKET_FILTER, + card->common->moduleDS); + if (result != ERR_SUCCESS) + { + DEBUG1 ("Set packet filter failed: %s\n", Ndis_strerror(result)); + return (0); + } + + /* If OPEN/CLOSE supported then open the adapter + */ + if (MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) + { + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, NULL, + REQ_OPEN_ADAPTER, + card->common->moduleDS); + if (result != ERR_SUCCESS) + { + DEBUG1 ("Opening the MAC failed: %s\n", Ndis_strerror(result)); + return (0); + } + } + return (1); +} + +void NdisShutdown (void) +{ + struct _ReqBlock reqBlock; + int result, i; + + if (!handle) + return; + + /* If the adapters support open and are open then close them + */ + if ((MAC_CHAR(handle)->serviceFlags & SF_OPEN_CLOSE) && + (MAC_STATUS(handle)->macStatus & MAC_OPEN)) + { + result = MAC_DISPATCH(handle)->request (common.moduleId, 0, 0, 0, + REQ_CLOSE_ADAPTER, + handle->common->moduleDS); + if (result != ERR_SUCCESS) + { + printf ("Closing the MAC failed: %s\n", Ndis_strerror(result)); + return; + } + } + + /* Tell the Protocol Manager to unbind and stop + */ + reqBlock.opcode = PM_UNBIND_AND_STOP; + reqBlock.pointer1 = (BYTE FAR*) &failingModules; + reqBlock.pointer2 = NULL; + + result = (*protManEntry) (&reqBlock, protManDS); + if (result) + printf ("Unbind failed: %s\n", Ndis_strerror(result)); + + for (i = 0; i < STACK_POOL_SIZE; ++i) + free (freeStacks[i] - STACK_SIZE); + + handle = NULL; +} + +int NdisInit (int promis) +{ + int i, result; + + /* Allocate the real mode stacks used for NDIS callbacks + */ + for (i = 0; i < STACK_POOL_SIZE; ++i) + { + freeStacks[i] = malloc (STACK_SIZE); + if (!freeStacks[i]) + return (0); + freeStacks[i] += STACK_SIZE; + } + + if (!NdisOpen()) + return (0); + + if (!NdisRegisterAndBind(promis)) + return (0); + + DEBUG1 ("My module id: %d\n", common.moduleId); + DEBUG1 ("Handle id; %d\n", handle->common->moduleId); + DEBUG1 ("MAC card: %-16s - ", handle->moduleName); + + atexit (NdisShutdown); + + if (!CheckMacFeatures(&handle)) + return (0); + + switch (mediaType) + { + case MEDIA_FDDI: + DEBUG0 ("Media type: FDDI"); + break; + case MEDIA_ETHERNET: + DEBUG0 ("Media type: ETHERNET"); + break; + default: + DEBUG0 ("Unsupported media.\n"); + return (0); + } + + DEBUG1 (" - Frame size: %d\n", frameSize); + + if (!NdisStartMac(&handle)) + return (0); + return (1); +} +#endif /* USE_NDIS2 */ + diff --git a/msdos/ndis2.h b/msdos/ndis2.h new file mode 100644 index 0000000..dc72f4c --- /dev/null +++ b/msdos/ndis2.h @@ -0,0 +1,559 @@ +/* + * Copyright (c) 1993,1994 + * Texas A&M University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Texas A&M University + * and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Developers: + * David K. Hess, Douglas Lee Schales, David R. Safford + * + * Heavily modified for Metaware HighC + GNU C 2.8+ + * Gisle Vanem 1998 + */ + +#ifndef __PCAP_NDIS_H +#define __PCAP_NDIS_H + +#if defined (__HIGHC__) + #define pascal _CC(_CALLEE_POPS_STACK & ~_REVERSE_PARMS) /* calling convention */ + #define CALLBACK(foo) pascal WORD foo + #define PAS_PTR(x,arg) typedef FAR WORD pascal (*x) arg + #define GUARD() _inline (0x9C,0xFA) /* pushfd, cli */ + #define UNGUARD() _inline (0x9D) /* popfd */ + #define FAR _far + +#elif defined(__GNUC__) + #define CALLBACK(foo) WORD foo __attribute__((stdcall)) + #define PAS_PTR(x,arg) typedef WORD (*x) arg __attribute__((stdcall)) + #define GUARD() __asm__ __volatile__ ("pushfd; cli") + #define UNGUARD() __asm__ __volatile__ ("popfd") + #define FAR + +#elif defined (__TURBOC__) + #define CALLBACK(foo) WORD pascal foo + #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg + #define GUARD() _asm { pushf; cli } + #define UNGUARD() _asm { popf } + #define FAR _far + +#elif defined (__WATCOMC__) + #define CALLBACK(foo) WORD pascal foo + #define PAS_PTR(x,arg) typedef WORD pascal (_far *x) arg + #define GUARD() _disable() + #define UNGUARD() _enable() + #define FAR _far + +#else + #error Unsupported compiler +#endif + + +/* + * Forwards + */ +struct _ReqBlock; +struct _TxBufDescr; +struct _TDBufDescr; + +/* + * Protocol Manager API + */ +PAS_PTR (ProtMan, (struct _ReqBlock FAR*, WORD)); + +/* + * System request + */ +PAS_PTR (SystemRequest, (DWORD, DWORD, WORD, WORD, WORD)); + +/* + * MAC API + */ +PAS_PTR (TransmitChain, (WORD, WORD, struct _TxBufDescr FAR*, WORD)); +PAS_PTR (TransferData, (WORD*,WORD, struct _TDBufDescr FAR*, WORD)); +PAS_PTR (Request, (WORD, WORD, WORD, DWORD, WORD, WORD)); +PAS_PTR (ReceiveRelease,(WORD, WORD)); +PAS_PTR (IndicationOn, (WORD)); +PAS_PTR (IndicationOff, (WORD)); + + +typedef enum { + HARDWARE_NOT_INSTALLED = 0, + HARDWARE_FAILED_DIAG = 1, + HARDWARE_FAILED_CONFIG = 2, + HARDWARE_HARD_FAULT = 3, + HARDWARE_SOFT_FAULT = 4, + HARDWARE_OK = 7, + HARDWARE_MASK = 0x0007, + MAC_BOUND = 0x0008, + MAC_OPEN = 0x0010, + DIAG_IN_PROGRESS = 0x0020 + } NdisMacStatus; + +typedef enum { + STATUS_RING_STATUS = 1, + STATUS_ADAPTER_CHECK = 2, + STATUS_START_RESET = 3, + STATUS_INTERRUPT = 4, + STATUS_END_RESET = 5 + } NdisStatus; + +typedef enum { + FILTER_DIRECTED = 1, + FILTER_BROADCAST = 2, + FILTER_PROMISCUOUS = 4, + FILTER_SOURCE_ROUTE = 8 + } NdisPacketFilter; + +typedef enum { + REQ_INITIATE_DIAGNOSTICS = 1, + REQ_READ_ERROR_LOG = 2, + REQ_SET_STATION_ADDRESS = 3, + REQ_OPEN_ADAPTER = 4, + REQ_CLOSE_ADAPTER = 5, + REQ_RESET_MAC = 6, + REQ_SET_PACKET_FILTER = 7, + REQ_ADD_MULTICAST_ADDRESS = 8, + REQ_DELETE_MULTICAST_ADDRESS = 9, + REQ_UPDATE_STATISTICS = 10, + REQ_CLEAR_STATISTICS = 11, + REQ_INTERRUPT_REQUEST = 12, + REQ_SET_FUNCTIONAL_ADDRESS = 13, + REQ_SET_LOOKAHEAD = 14 + } NdisGeneralRequest; + +typedef enum { + SF_BROADCAST = 0x00000001L, + SF_MULTICAST = 0x00000002L, + SF_FUNCTIONAL = 0x00000004L, + SF_PROMISCUOUS = 0x00000008L, + SF_SOFT_ADDRESS = 0x00000010L, + SF_STATS_CURRENT = 0x00000020L, + SF_INITIATE_DIAGS = 0x00000040L, + SF_LOOPBACK = 0x00000080L, + SF_RECEIVE_CHAIN = 0x00000100L, + SF_SOURCE_ROUTING = 0x00000200L, + SF_RESET_MAC = 0x00000400L, + SF_OPEN_CLOSE = 0x00000800L, + SF_INTERRUPT_REQUEST = 0x00001000L, + SF_SOURCE_ROUTING_BRIDGE = 0x00002000L, + SF_VIRTUAL_ADDRESSES = 0x00004000L + } NdisMacServiceFlags; + +typedef enum { + REQ_INITIATE_BIND = 1, + REQ_BIND = 2, + REQ_INITIATE_PREBIND = 3, + REQ_INITIATE_UNBIND = 4, + REQ_UNBIND = 5 + } NdisSysRequest; + +typedef enum { + PM_GET_PROTOCOL_MANAGER_INFO = 1, + PM_REGISTER_MODULE = 2, + PM_BIND_AND_START = 3, + PM_GET_PROTOCOL_MANAGER_LINKAGE = 4, + PM_GET_PROTOCOL_INI_PATH = 5, + PM_REGISTER_PROTOCOL_MANAGER_INFO = 6, + PM_INIT_AND_REGISTER = 7, + PM_UNBIND_AND_STOP = 8, + PM_BIND_STATUS = 9, + PM_REGISTER_STATUS = 10 + } NdisProtManager; + + +typedef enum { + ERR_SUCCESS = 0x00, + ERR_WAIT_FOR_RELEASE = 0x01, + ERR_REQUEST_QUEUED = 0x02, + ERR_FRAME_NOT_RECOGNIZED = 0x03, + ERR_FRAME_REJECTED = 0x04, + ERR_FORWARD_FRAME = 0x05, + ERR_OUT_OF_RESOURCE = 0x06, + ERR_INVALID_PARAMETER = 0x07, + ERR_INVALID_FUNCTION = 0x08, + ERR_NOT_SUPPORTED = 0x09, + ERR_HARDWARE_ERROR = 0x0A, + ERR_TRANSMIT_ERROR = 0x0B, + ERR_NO_SUCH_DESTINATION = 0x0C, + ERR_BUFFER_TOO_SMALL = 0x0D, + ERR_ALREADY_STARTED = 0x20, + ERR_INCOMPLETE_BINDING = 0x21, + ERR_DRIVER_NOT_INITIALIZED = 0x22, + ERR_HARDWARE_NOT_FOUND = 0x23, + ERR_HARDWARE_FAILURE = 0x24, + ERR_CONFIGURATION_FAILURE = 0x25, + ERR_INTERRUPT_CONFLICT = 0x26, + ERR_INCOMPATIBLE_MAC = 0x27, + ERR_INITIALIZATION_FAILED = 0x28, + ERR_NO_BINDING = 0x29, + ERR_NETWORK_MAY_NOT_BE_CONNECTED = 0x2A, + ERR_INCOMPATIBLE_OS_VERSION = 0x2B, + ERR_ALREADY_REGISTERED = 0x2C, + ERR_PATH_NOT_FOUND = 0x2D, + ERR_INSUFFICIENT_MEMORY = 0x2E, + ERR_INFO_NOT_FOUND = 0x2F, + ERR_GENERAL_FAILURE = 0xFF + } NdisError; + +#define NDIS_PARAM_INTEGER 0 +#define NDIS_PARAM_STRING 1 + +#define NDIS_TX_BUF_LENGTH 8 +#define NDIS_TD_BUF_LENGTH 1 +#define NDIS_RX_BUF_LENGTH 8 + +#define NDIS_PTR_PHYSICAL 0 +#define NDIS_PTR_VIRTUAL 2 + +#define NDIS_PATH "PROTMAN$" + + +typedef struct _CommonChars { + WORD tableSize; + BYTE majorNdisVersion; /* 2 - Latest version */ + BYTE minorNdisVersion; /* 0 */ + WORD reserved1; + BYTE majorModuleVersion; + BYTE minorModuleVersion; + DWORD moduleFlags; + /* 0 - Binding at upper boundary supported + * 1 - Binding at lower boundary supported + * 2 - Dynamically bound. + * 3-31 - Reserved, must be zero. + */ + BYTE moduleName[16]; + BYTE protocolLevelUpper; + /* 1 - MAC + * 2 - Data Link + * 3 - Network + * 4 - Transport + * 5 - Session + * -1 - Not specified + */ + BYTE interfaceUpper; + BYTE protocolLevelLower; + /* 0 - Physical + * 1 - MAC + * 2 - Data Link + * 3 - Network + * 4 - Transport + * 5 - Session + * -1 - Not specified + */ + BYTE interfaceLower; + WORD moduleId; + WORD moduleDS; + SystemRequest systemRequest; + BYTE *serviceChars; + BYTE *serviceStatus; + BYTE *upperDispatchTable; + BYTE *lowerDispatchTable; + BYTE *reserved2; /* Must be NULL */ + BYTE *reserved3; /* Must be NULL */ + } CommonChars; + + +typedef struct _MulticastList { + WORD maxMulticastAddresses; + WORD numberMulticastAddresses; + BYTE multicastAddress[16][16]; + } MulticastList; + + +typedef struct _MacChars { + WORD tableSize; + BYTE macName[16]; + WORD addressLength; + BYTE permanentAddress[16]; + BYTE currentAddress[16]; + DWORD currentFunctionalAddress; + MulticastList *multicastList; + DWORD linkSpeed; + DWORD serviceFlags; + WORD maxFrameSize; + DWORD txBufferSize; + WORD txBufferAllocSize; + DWORD rxBufferSize; + WORD rxBufferAllocSize; + BYTE ieeeVendor[3]; + BYTE vendorAdapter; + BYTE *vendorAdapterDescription; + WORD interruptLevel; + WORD txQueueDepth; + WORD maxDataBlocks; + } MacChars; + + +typedef struct _ProtocolChars { + WORD length; + BYTE name[16]; + WORD type; + } ProtocolChars; + + +typedef struct _MacUpperDispatch { + CommonChars *backPointer; + Request request; + TransmitChain transmitChain; + TransferData transferData; + ReceiveRelease receiveRelease; + IndicationOn indicationOn; + IndicationOff indicationOff; + } MacUpperDispatch; + + +typedef struct _MacStatusTable { + WORD tableSize; + DWORD lastDiag; + DWORD macStatus; + WORD packetFilter; + BYTE *mediaSpecificStats; + DWORD lastClear; + DWORD totalFramesRx; + DWORD totalFramesCrc; + DWORD totalBytesRx; + DWORD totalDiscardBufSpaceRx; + DWORD totalMulticastRx; + DWORD totalBroadcastRx; + DWORD obsolete1[5]; + DWORD totalDiscardHwErrorRx; + DWORD totalFramesTx; + DWORD totalBytesTx; + DWORD totalMulticastTx; + DWORD totalBroadcastTx; + DWORD obsolete2[2]; + DWORD totalDiscardTimeoutTx; + DWORD totalDiscardHwErrorTx; + } MacStatusTable; + + +typedef struct _ProtDispatch { + CommonChars *backPointer; + DWORD flags; + /* 0 - handles non-LLC frames + * 1 - handles specific-LSAP LLC frames + * 2 - handles specific-LSAP LLC frames + * 3-31 - reserved must be 0 + */ + void (*requestConfirm) (void); + void (*transmitConfirm) (void); + void (*receiveLookahead) (void); + void (*indicationComplete) (void); + void (*receiveChain) (void); + void (*status) (void); + } ProtDispatch; + + +typedef struct _ReqBlock { + WORD opcode; + WORD status; + BYTE FAR *pointer1; + BYTE FAR *pointer2; + WORD word1; + } ReqBlock; + + +typedef struct _TxBufDescrRec { + BYTE txPtrType; + BYTE dummy; + WORD txDataLen; + BYTE *txDataPtr; + } TxBufDescrRec; + + +typedef struct _TxBufDescr { + WORD txImmedLen; + BYTE *txImmedPtr; + WORD txDataCount; + TxBufDescrRec txBufDescrRec[NDIS_TX_BUF_LENGTH]; + } TxBufDescr; + + +typedef struct _TDBufDescrRec { + BYTE tDPtrType; + BYTE dummy; + WORD tDDataLen; + BYTE *tDDataPtr; + } TDBufDescrRec; + + +typedef struct _TDBufDescr { + WORD tDDataCount; + TDBufDescrRec tDBufDescrRec[NDIS_TD_BUF_LENGTH]; + } TDBufDescr; + + +typedef struct _RxBufDescrRec { + WORD rxDataLen; + BYTE *rxDataPtr; + } RxBufDescrRec; + + +typedef struct _RxBufDescr { + WORD rxDataCount; + RxBufDescrRec rxBufDescrRec[NDIS_RX_BUF_LENGTH]; + } RxBufDescr; + + +typedef struct _PktBuf { + struct _PktBuf *nextLink; + struct _PktBuf *prevLink; + int handle; + int length; + int packetLength; + DWORD sequence; + BYTE *buffer; + } PktBuf; + + +typedef struct _CardHandle { + BYTE moduleName[16]; + CommonChars *common; + } CardHandle; + + +typedef struct _BindingsList { + WORD numBindings; + BYTE moduleName[2][16]; + } BindingsList; + + +typedef struct _FailingModules { + BYTE upperModuleName[16]; + BYTE lowerModuleName[16]; + } FailingModules; + + +typedef union _HardwareAddress { + BYTE bytes[6]; + WORD words[3]; + struct { + BYTE bytes[6]; + } addr; + } HardwareAddress; + + +typedef struct _FddiHeader { + BYTE frameControl; + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + } FddiHeader; + + +typedef struct _EthernetIIHeader { + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + WORD etherType; + } EthernetIIHeader; + + +typedef struct _Ieee802Dot5Header { + HardwareAddress etherDestHost; + HardwareAddress etherSrcHost; + BYTE routeInfo[30]; + } Ieee802Dot5Header; + + +typedef struct _Ieee802Dot2SnapHeader { + BYTE dsap; /* 0xAA */ + BYTE ssap; /* 0xAA */ + BYTE control; /* 3 */ + BYTE protocolId[5]; + } Ieee802Dot2SnapHeader; + + +/* + * Prototypes + */ +extern char *NdisLastError (void); +extern int NdisOpen (void); +extern int NdisInit (int promis); +extern int NdisRegisterAndBind (int promis); +extern void NdisShutdown (void); +extern void NdisCheckMacFeatures (struct _CardHandle *card); +extern int NdisSendPacket (struct _PktBuf *pktBuf, int macId); + +/* + * Assembly "glue" functions + */ +extern int systemRequestGlue(); +extern int requestConfirmGlue(); +extern int transmitConfirmGlue(); +extern int receiveLookaheadGlue(); +extern int indicationCompleteGlue(); +extern int receiveChainGlue(); +extern int statusGlue(); + +/* + * IOCTL function + */ +#ifdef __SMALL__ +extern int _far NdisGetLinkage (int handle, char *data, int size); +#else +extern int NdisGetLinkage (int handle, char *data, int size); +#endif + +/* + * NDIS callback handlers + */ +CALLBACK (NdisSystemRequest (DWORD,DWORD, WORD, WORD, WORD)); +CALLBACK (NdisRequestConfirm ( WORD, WORD, WORD, WORD, WORD,WORD)); +CALLBACK (NdisTransmitConfirm ( WORD, WORD, WORD, WORD, WORD)); +CALLBACK (NdisReceiveLookahead ( WORD, WORD, WORD, BYTE*, BYTE*, WORD)); +CALLBACK (NdisReceiveChain ( WORD, WORD, WORD, struct _RxBufDescr*, BYTE*, WORD)); +CALLBACK (NdisStatusProc ( WORD, WORD, BYTE*, WORD,WORD)); +CALLBACK (NdisIndicationComplete( WORD, WORD)); + +BYTE *NdisAllocStack (void); +void NdisFreeStack (BYTE*); + +#ifdef __HIGHC__ + #define RENAME_ASM_SYM(x) pragma Alias(x,"@" #x "") /* prepend `@' */ + #define RENAME_C_SYM(x) pragma Alias(x,"_" #x "") /* prepend `_' */ + + RENAME_ASM_SYM (systemRequestGlue); + RENAME_ASM_SYM (requestConfirmGlue); + RENAME_ASM_SYM (transmitConfirmGlue); + RENAME_ASM_SYM (receiveLookaheadGlue); + RENAME_ASM_SYM (indicationCompleteGlue); + RENAME_ASM_SYM (receiveChainGlue); + RENAME_ASM_SYM (statusGlue); + RENAME_ASM_SYM (NdisGetLinkage); + RENAME_C_SYM (NdisSystemRequest); + RENAME_C_SYM (NdisRequestConfirm); + RENAME_C_SYM (NdisTransmitConfirm); + RENAME_C_SYM (NdisReceiveLookahead); + RENAME_C_SYM (NdisIndicationComplete); + RENAME_C_SYM (NdisReceiveChain); + RENAME_C_SYM (NdisStatusProc); + RENAME_C_SYM (NdisAllocStack); + RENAME_C_SYM (NdisFreeStack); +#endif + +#endif diff --git a/msdos/ndis_0.asm b/msdos/ndis_0.asm new file mode 100644 index 0000000..2990985 --- /dev/null +++ b/msdos/ndis_0.asm @@ -0,0 +1,188 @@ +PAGE 60,132 +NAME NDIS_0 + +ifdef DOSX + .386 + _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD USE16 'CODE' + _DATA ENDS + _TEXT32 SEGMENT PUBLIC BYTE USE32 'CODE' + _TEXT32 ENDS + CB_DSEG EQU ; DOSX is tiny-model + D_SEG EQU <_TEXT SEGMENT> + D_END EQU <_TEXT ENDS> + ASSUME CS:_TEXT,DS:_TEXT + + PUSHREGS equ + POPREGS equ + + PUBPROC macro name + align 4 + public @&name + @&name label near + endm +else + .286 + _TEXT SEGMENT PUBLIC DWORD 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD 'DATA' + _DATA ENDS + CB_DSEG EQU ; 16bit is small/large model + D_SEG EQU <_DATA SEGMENT> + D_END EQU <_DATA ENDS> + ASSUME CS:_TEXT,DS:_DATA + + PUSHREGS equ + POPREGS equ + + PUBPROC macro name + public _&name + _&name label far + endm +endif + +;------------------------------------------- + +D_SEG + +D_END + + +_TEXT SEGMENT + +EXTRN _NdisSystemRequest : near +EXTRN _NdisRequestConfirm : near +EXTRN _NdisTransmitConfirm : near +EXTRN _NdisReceiveLookahead : near +EXTRN _NdisIndicationComplete : near +EXTRN _NdisReceiveChain : near +EXTRN _NdisStatusProc : near +EXTRN _NdisAllocStack : near +EXTRN _NdisFreeStack : near + +; +; *ALL* interrupt threads come through this macro. +; +CALLBACK macro callbackProc, argsSize + + pushf + PUSHREGS ;; Save the registers + + push es + push ds + mov ax,CB_DSEG ;; Load DS + mov ds,ax + call _NdisAllocStack ;; Get and install a stack. + + mov bx,ss ;; Save off the old stack in other regs + mov cx,sp + mov ss,dx ;; Install the new one + mov sp,ax + push bx ;; Save the old one on to the new stack + push cx + sub sp,&argsSize ;; Allocate space for arguments on the stack + + mov ax,ss ;; Set up the destination for the move + mov es,ax + mov di,sp + mov ds,bx ;; Set up the source for the move. + mov si,cx + add si,4+6+32 + + mov cx,&argsSize ;; Move the arguments to the stack. + shr cx,1 + cld + rep movsw + + mov ax,CB_DSEG ;; Set my data segment again. + mov ds,ax + + call &callbackProc ;; Call the real callback. + pop di ;; Pop off the old stack + pop si + mov bx,ss ;; Save off the current allocated stack. + mov cx,sp + mov ss,si ;; Restore the old stack + mov sp,di + push ax ;; Save the return code + push bx ;; Free the stack. Push the pointer to it + push cx + call _NdisFreeStack + add sp,4 + pop ax ;; Get the return code back + add di,32 ;; Get a pointer to ax on the stack + mov word ptr ss:[di],ax + pop ds + pop es + + POPREGS + popf +endm + +; +; Define all of the callbacks for the NDIS procs. +; + +PUBPROC systemRequestGlue +CALLBACK _NdisSystemRequest,14 +RETF + +PUBPROC requestConfirmGlue +CALLBACK _NdisRequestConfirm,12 +RETF + +PUBPROC transmitConfirmGlue +CALLBACK _NdisTransmitConfirm,10 +RETF + +PUBPROC receiveLookaheadGlue +CALLBACK _NdisReceiveLookahead,16 +RETF + +PUBPROC indicationCompleteGlue +CALLBACK _NdisIndicationComplete,4 +RETF + +PUBPROC receiveChainGlue +CALLBACK _NdisReceiveChain,16 +RETF + +PUBPROC statusGlue +CALLBACK _NdisStatusProc,12 +RETF + +; +; int FAR NdisGetLinkage (int handle, char *data, int size); +; + +ifdef DOSX + PUBPROC NdisGetLinkage + push ebx + mov ebx, [esp+8] ; device handle + mov eax, 4402h ; IOCTRL read function + mov edx, [esp+12] ; DS:EDX -> result data + mov ecx, [esp+16] ; ECX = length + int 21h + pop ebx + jc @fail + xor eax, eax + @fail: ret + +else + PUBPROC NdisGetLinkage + enter 0, 0 + mov bx, [bp+6] + mov ax, 4402h + mov dx, [bp+8] + mov cx, [bp+12] + int 21h + jc @fail + xor ax, ax + @fail: leave + retf +endif + +ENDS + +END diff --git a/msdos/pkt_rx0.asm b/msdos/pkt_rx0.asm new file mode 100644 index 0000000..94f3d09 --- /dev/null +++ b/msdos/pkt_rx0.asm @@ -0,0 +1,197 @@ +PAGE 60,132 +NAME PKT_RX + +ifdef ??version ; using TASM + masm + jumps +endif + +PUBLIC _pktDrop, _pktRxBuf, _pktTxBuf, _pktTemp +PUBLIC _rxOutOfs, _rxInOfs, _PktReceiver, _pktRxEnd + +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; + +RX_BUF_SIZE = 1500 ; max message size on Ethernet +TX_BUF_SIZE = 1500 + +ifdef DOSX + .386 + NUM_RX_BUF = 32 ; # of RX element buffers + _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD USE16 'CODE' + _DATA ENDS + D_SEG EQU <_TEXT SEGMENT> + D_END EQU <_TEXT ENDS> + ASSUME CS:_TEXT,DS:_TEXT +else + .286 + NUM_RX_BUF = 10 + _TEXT SEGMENT PUBLIC DWORD 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD 'DATA' + _DATA ENDS + D_SEG EQU <_DATA SEGMENT> + D_END EQU <_DATA ENDS> + ASSUME CS:_TEXT,DS:_DATA +endif + +;------------------------------------------- + +D_SEG + +RX_ELEMENT STRUC + firstCount dw 0 ; # of bytes on 1st call + secondCount dw 0 ; # of bytes on 2nd call + handle dw 0 ; handle for upcall + destinAdr db 6 dup (0) ; packet destination address + sourceAdr db 6 dup (0) ; packet source address + protocol dw 0 ; packet protocol number + rxBuffer db RX_BUF_SIZE dup (0) ; RX buffer +ENDS + align 4 +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp db 20 dup (0) ; temp work area +_pktTxBuf db (TX_BUF_SIZE+14) dup (0) ; TX buffer +_pktRxBuf RX_ELEMENT NUM_RX_BUF dup (<>) ; RX structures + LAST_OFS = offset $ + + screenSeg dw 0B800h + newInOffset dw 0 + + fanChars db '-\|/' + fanIndex dw 0 + +D_END + +_TEXT SEGMENT + + +SHOW_RX MACRO + push es + push bx + mov bx, screenSeg + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, fanIndex + mov al, fanChars[bx] ;; get write char + mov ah, 15 ;; and white colour + stosw ;; write to screen at ES:EDI + inc fanIndex ;; update next index + and fanIndex, 3 + pop bx + pop es +ENDM + +;------------------------------------------------------------------------ +; +; This macro return ES:DI to tail of Rx queue + +ENQUEUE MACRO + LOCAL @noWrap + mov ax, _rxInOfs ;; DI = current in-offset + add ax, SIZE RX_ELEMENT ;; point to next _pktRxBuf buffer + cmp ax, LAST_OFS ;; pointing past last ? + jb @noWrap ;; no - jump + lea ax, _pktRxBuf ;; yes, point to 1st buffer + align 4 +@noWrap: cmp ax, _rxOutOfs ;; in-ofs = out-ofs ? + je @dump ;; yes, queue is full + mov di, _rxInOfs ;; ES:DI -> buffer at queue input + mov newInOffset, ax ;; remember new input offset + + ;; NOTE. rxInOfs is updated after the packet has been copied + ;; to ES:DI (= DS:SI on 2nd call) by the packet driver + +ENDM + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx +ifdef DOSX + mov bx, cs +else + mov bx, SEG _DATA +endif + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +ifdef DEBUG + SHOW_RX ; show that a packet is received +endif + cmp cx, RX_BUF_SIZE+14 ; size OK ? + ja @skip ; no, packet to large for us + + ENQUEUE ; ES:DI -> _pktRxBuf[n] + + mov [di].firstCount, cx ; remember the first count. + mov [di].handle, bx ; remember the handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + + align 4 +@dump: inc _pktDrop[0] ; discard the packet on 1st call + adc _pktDrop[2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + + align 4 +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + sub si, 6 ; DS:SI -> _pktRxBuf[n].destinAdr + ; + ; push si + ; push [si].firstCount + ; call bpf_filter_match ; run the filter here some day? + ; add sp, 4 + ; cmp ax, 0 + ; je @discard + + mov [si].secondCount, cx + mov ax, newInOffset + mov _rxInOfs, ax ; update _pktRxBuf input offset + + align 4 +@discard:pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +_TEXT ENDS + +END diff --git a/msdos/pkt_rx1.s b/msdos/pkt_rx1.s new file mode 100644 index 0000000..b294a36 --- /dev/null +++ b/msdos/pkt_rx1.s @@ -0,0 +1,155 @@ +; +; This file requires NASM 0.97+ to assemble +; +; Currently used only for djgpp + DOS4GW targets +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; +%define ETH_MTU 1500 ; max data size on Ethernet +%define ETH_MIN 60 ; min/max total frame size +%define ETH_MAX (ETH_MTU+2*6+2) +%define NUM_RX_BUF 32 ; # of RX element buffers +%define RX_SIZE (ETH_MAX+6) ; sizeof(RX_ELEMENT) = 1514+6 +%idefine offset + +struc RX_ELEMENT + .firstCount resw 1 ; # of bytes on 1st call + .secondCount resw 1 ; # of bytes on 2nd call + .handle resw 1 ; handle for upcall + ; .timeStamp resw 4 ; 64-bit RDTSC value + .destinAdr resb 6 ; packet destination address + .sourceAdr resb 6 ; packet source address + .protocol resw 1 ; packet protocol number + .rxBuffer resb ETH_MTU ; RX buffer +endstruc + +;------------------------------------------- + +[org 0] ; assemble to .bin file + +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp resb 20 ; temp work area +_pktTxBuf resb (ETH_MAX) ; TX buffer +_pktRxBuf resb (RX_SIZE*NUM_RX_BUF) ; RX structures + LAST_OFS equ $ + +screenSeg dw 0B800h +newInOffset dw 0 + +fanChars db '-\|/' +fanIndex dw 0 + +%macro SHOW_RX 0 + push es + push bx + mov bx, [screenSeg] + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, [fanIndex] + mov al, [fanChars+bx] ;; get write char + mov ah, 15 ;; and white colour + cld ;; Needed? + stosw ;; write to screen at ES:EDI + inc word [fanIndex] ;; update next index + and word [fanIndex], 3 + pop bx + pop es +%endmacro + +;PutTimeStamp +; rdtsc +; mov [si].timeStamp, eax +; mov [si+4].timeStamp, edx +; ret + + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx + mov bx, cs + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +%ifdef DEBUG + SHOW_RX ; show that a packet is received +%endif + + cmp cx, ETH_MAX ; size OK ? + ja @skip ; no, too big + + mov ax, [_rxInOfs] + add ax, RX_SIZE + cmp ax, LAST_OFS + jb @noWrap + mov ax, offset _pktRxBuf +@noWrap: + cmp ax, [_rxOutOfs] + je @dump + mov di, [_rxInOfs] ; ES:DI -> _pktRxBuf[n] + mov [newInOffset], ax + + mov [di], cx ; remember firstCount. + mov [di+4], bx ; remember handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + +@dump: add word [_pktDrop+0], 1 ; discard the packet on 1st call + adc word [_pktDrop+2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + ; + ; push si + ; call bpf_filter_match ; run the filter here some day + ; pop si + ; cmp ax, 0 + ; je @discard + + mov [si-6+2], cx ; store _pktRxBuf[n].secondCount + mov ax, [newInOffset] + mov [_rxInOfs], ax ; update _pktRxBuf input offset + + ; call PutTimeStamp + +@discard: + pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +END + diff --git a/msdos/pktdrvr.c b/msdos/pktdrvr.c new file mode 100644 index 0000000..204ab90 --- /dev/null +++ b/msdos/pktdrvr.c @@ -0,0 +1,1437 @@ +/* + * File.........: pktdrvr.c + * + * Responsible..: Gisle Vanem, giva@bgnett.no + * + * Created......: 26.Sept 1995 + * + * Description..: Packet-driver interface for 16/32-bit C : + * Borland C/C++ 3.0+ small/large model + * Watcom C/C++ 11+, DOS4GW flat model + * Metaware HighC 3.1+ and PharLap 386|DosX + * GNU C/C++ 2.7+ and djgpp 2.x extender + * + * References...: PC/TCP Packet driver Specification. rev 1.09 + * FTP Software Inc. + * + */ + +#include +#include +#include +#include + +#include "gnuc.h" +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#if (DOSX) +#define NUM_RX_BUF 32 /* # of buffers in Rx FIFO queue */ +#else +#define NUM_RX_BUF 10 +#endif + +#define DIM(x) (sizeof((x)) / sizeof(x[0])) +#define PUTS(s) do { \ + if (!pktInfo.quiet) \ + pktInfo.error ? \ + printf ("%s: %s\n", s, pktInfo.error) : \ + printf ("%s\n", pktInfo.error = s); \ + } while (0) + +#if defined(__HIGHC__) + extern UINT _mwenv; + +#elif defined(__DJGPP__) + #include + #include + #include + #include + #include + +#elif defined(__WATCOMC__) + #include + #include + extern char _Extender; + +#else + extern void far PktReceiver (void); +#endif + + +#if (DOSX & (DJGPP|DOS4GW)) + #include + + struct DPMI_regs { + DWORD r_di; + DWORD r_si; + DWORD r_bp; + DWORD reserved; + DWORD r_bx; + DWORD r_dx; + DWORD r_cx; + DWORD r_ax; + WORD r_flags; + WORD r_es, r_ds, r_fs, r_gs; + WORD r_ip, r_cs, r_sp, r_ss; + }; + + /* Data located in a real-mode segment. This becomes far at runtime + */ + typedef struct { /* must match data/code in pkt_rx1.s */ + WORD _rxOutOfs; + WORD _rxInOfs; + DWORD _pktDrop; + BYTE _pktTemp [20]; + TX_ELEMENT _pktTxBuf[1]; + RX_ELEMENT _pktRxBuf[NUM_RX_BUF]; + WORD _dummy[2]; /* screenSeg,newInOffset */ + BYTE _fanChars[4]; + WORD _fanIndex; + BYTE _PktReceiver[15]; /* starts on a paragraph (16byte) */ + } PktRealStub; + #include + + static BYTE real_stub_array [] = { + #include "pkt_stub.inc" /* generated opcode array */ + }; + + #define rxOutOfs offsetof (PktRealStub,_rxOutOfs) + #define rxInOfs offsetof (PktRealStub,_rxInOfs) + #define PktReceiver offsetof (PktRealStub,_PktReceiver [para_skip]) + #define pktDrop offsetof (PktRealStub,_pktDrop) + #define pktTemp offsetof (PktRealStub,_pktTemp) + #define pktTxBuf offsetof (PktRealStub,_pktTxBuf) + #define FIRST_RX_BUF offsetof (PktRealStub,_pktRxBuf [0]) + #define LAST_RX_BUF offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1]) + +#else + extern WORD rxOutOfs; /* offsets into pktRxBuf FIFO queue */ + extern WORD rxInOfs; + extern DWORD pktDrop; /* # packets dropped in PktReceiver() */ + extern BYTE pktRxEnd; /* marks the end of r-mode code/data */ + + extern RX_ELEMENT pktRxBuf [NUM_RX_BUF]; /* PktDrvr Rx buffers */ + extern TX_ELEMENT pktTxBuf; /* PktDrvr Tx buffer */ + extern char pktTemp[20]; /* PktDrvr temp area */ + + #define FIRST_RX_BUF (WORD) &pktRxBuf [0] + #define LAST_RX_BUF (WORD) &pktRxBuf [NUM_RX_BUF-1] +#endif + + +#ifdef __BORLANDC__ /* Use Borland's inline functions */ + #define memcpy __memcpy__ + #define memcmp __memcmp__ + #define memset __memset__ +#endif + + +#if (DOSX & PHARLAP) + extern void PktReceiver (void); /* in pkt_rx0.asm */ + static int RealCopy (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*); + + #undef FP_SEG + #undef FP_OFF + #define FP_OFF(x) ((WORD)(x)) + #define FP_SEG(x) ((WORD)(realBase >> 16)) + #define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o)) + #define r_ax eax + #define r_bx ebx + #define r_dx edx + #define r_cx ecx + #define r_si esi + #define r_di edi + #define r_ds ds + #define r_es es + LOCAL FARPTR protBase; + LOCAL REALPTR realBase; + LOCAL WORD realSeg; /* DOS para-address of allocated area */ + LOCAL SWI_REGS reg; + + static WORD _far *rxOutOfsFp, *rxInOfsFp; + +#elif (DOSX & DJGPP) + static _go32_dpmi_seginfo rm_mem; + static __dpmi_regs reg; + static DWORD realBase; + static int para_skip = 0; + + #define DOS_ADDR(s,o) (((WORD)(s) << 4) + (o)) + #define r_ax x.ax + #define r_bx x.bx + #define r_dx x.dx + #define r_cx x.cx + #define r_si x.si + #define r_di x.di + #define r_ds x.ds + #define r_es x.es + +#elif (DOSX & DOS4GW) + LOCAL struct DPMI_regs reg; + LOCAL WORD rm_base_seg, rm_base_sel; + LOCAL DWORD realBase; + LOCAL int para_skip = 0; + + LOCAL DWORD dpmi_get_real_vector (int intr); + LOCAL WORD dpmi_real_malloc (int size, WORD *selector); + LOCAL void dpmi_real_free (WORD selector); + #define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o)) + +#else /* real-mode Borland etc. */ + static struct { + WORD r_ax, r_bx, r_cx, r_dx, r_bp; + WORD r_si, r_di, r_ds, r_es, r_flags; + } reg; +#endif + +#ifdef __HIGHC__ + #pragma Alias (pktDrop, "_pktDrop") + #pragma Alias (pktRxBuf, "_pktRxBuf") + #pragma Alias (pktTxBuf, "_pktTxBuf") + #pragma Alias (pktTemp, "_pktTemp") + #pragma Alias (rxOutOfs, "_rxOutOfs") + #pragma Alias (rxInOfs, "_rxInOfs") + #pragma Alias (pktRxEnd, "_pktRxEnd") + #pragma Alias (PktReceiver,"_PktReceiver") +#endif + + +PUBLIC PKT_STAT pktStat; /* statistics for packets */ +PUBLIC PKT_INFO pktInfo; /* packet-driver information */ + +PUBLIC PKT_RX_MODE receiveMode = PDRX_DIRECT; +PUBLIC ETHER myAddress = { 0, 0, 0, 0, 0, 0 }; +PUBLIC ETHER ethBroadcast = { 255,255,255,255,255,255 }; + +LOCAL struct { /* internal statistics */ + DWORD tooSmall; /* size < ETH_MIN */ + DWORD tooLarge; /* size > ETH_MAX */ + DWORD badSync; /* count_1 != count_2 */ + DWORD wrongHandle; /* upcall to wrong handle */ + } intStat; + +/***************************************************************************/ + +PUBLIC const char *PktGetErrorStr (int errNum) +{ + static const char *errStr[] = { + "", + "Invalid handle number", + "No interfaces of specified class found", + "No interfaces of specified type found", + "No interfaces of specified number found", + "Bad packet type specified", + "Interface does not support multicast", + "Packet driver cannot terminate", + "Invalid receiver mode specified", + "Insufficient memory space", + "Type previously accessed, and not released", + "Command out of range, or not implemented", + "Cannot send packet (usually hardware error)", + "Cannot change hardware address ( > 1 handle open)", + "Hardware address has bad length or format", + "Cannot reset interface (more than 1 handle open)", + "Bad Check-sum", + "Bad size", + "Bad sync" , + "Source hit" + }; + + if (errNum < 0 || errNum >= DIM(errStr)) + return ("Unknown driver error."); + return (errStr [errNum]); +} + +/**************************************************************************/ + +PUBLIC const char *PktGetClassName (WORD class) +{ + switch (class) + { + case PD_ETHER: + return ("DIX-Ether"); + case PD_PRONET10: + return ("ProNET-10"); + case PD_IEEE8025: + return ("IEEE 802.5"); + case PD_OMNINET: + return ("OmniNet"); + case PD_APPLETALK: + return ("AppleTalk"); + case PD_SLIP: + return ("SLIP"); + case PD_STARTLAN: + return ("StartLAN"); + case PD_ARCNET: + return ("ArcNet"); + case PD_AX25: + return ("AX.25"); + case PD_KISS: + return ("KISS"); + case PD_IEEE8023_2: + return ("IEEE 802.3 w/802.2 hdr"); + case PD_FDDI8022: + return ("FDDI w/802.2 hdr"); + case PD_X25: + return ("X.25"); + case PD_LANstar: + return ("LANstar"); + case PD_PPP: + return ("PPP"); + default: + return ("unknown"); + } +} + +/**************************************************************************/ + +PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode) +{ + static const char *modeStr [] = { + "Receiver turned off", + "Receive only directly addressed packets", + "Receive direct & broadcast packets", + "Receive direct,broadcast and limited multicast packets", + "Receive direct,broadcast and all multicast packets", + "Receive all packets (promiscuouos mode)" + }; + + if (mode > DIM(modeStr)) + return ("??"); + return (modeStr [mode-1]); +} + +/**************************************************************************/ + +LOCAL __inline BOOL PktInterrupt (void) +{ + BOOL okay; + +#if (DOSX & PHARLAP) + _dx_real_int ((UINT)pktInfo.intr, ®); + okay = ((reg.flags & 1) == 0); /* OK if carry clear */ + +#elif (DOSX & DJGPP) + __dpmi_int ((int)pktInfo.intr, ®); + okay = ((reg.x.flags & 1) == 0); + +#elif (DOSX & DOS4GW) + union REGS r; + struct SREGS s; + + memset (&r, 0, sizeof(r)); + segread (&s); + r.w.ax = 0x300; + r.x.ebx = pktInfo.intr; + r.w.cx = 0; + s.es = FP_SEG (®); + r.x.edi = FP_OFF (®); + reg.r_flags = 0; + reg.r_ss = reg.r_sp = 0; /* DPMI host provides stack */ + + int386x (0x31, &r, &r, &s); + okay = (!r.w.cflag); + +#else + reg.r_flags = 0; + intr (pktInfo.intr, (struct REGPACK*)®); + okay = ((reg.r_flags & 1) == 0); +#endif + + if (okay) + pktInfo.error = NULL; + else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8); + return (okay); +} + +/**************************************************************************/ + +/* + * Search for packet driver at interrupt 60h through 80h. If ASCIIZ + * string "PKT DRVR" found at offset 3 in the interrupt handler, return + * interrupt number, else return zero in pktInfo.intr + */ +PUBLIC BOOL PktSearchDriver (void) +{ + BYTE intr = 0x20; + BOOL found = FALSE; + + while (!found && intr < 0xFF) + { + static char str[12]; /* 3 + strlen("PKT DRVR") */ + static char pktStr[9] = "PKT DRVR"; /* ASCIIZ string at ofs 3 */ + DWORD rp; /* in interrupt routine */ + +#if (DOSX & PHARLAP) + _dx_rmiv_get (intr, &rp); + ReadRealMem (&str, (REALPTR)rp, sizeof(str)); + +#elif (DOSX & DJGPP) + __dpmi_raddr realAdr; + __dpmi_get_real_mode_interrupt_vector (intr, &realAdr); + rp = (realAdr.segment << 4) + realAdr.offset16; + dosmemget (rp, sizeof(str), &str); + +#elif (DOSX & DOS4GW) + rp = dpmi_get_real_vector (intr); + memcpy (&str, (void*)rp, sizeof(str)); + +#else + _fmemcpy (&str, getvect(intr), sizeof(str)); +#endif + + found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0; + intr++; + } + pktInfo.intr = (found ? intr-1 : 0); + return (found); +} + + +/**************************************************************************/ + +static BOOL PktSetAccess (void) +{ + reg.r_ax = 0x0200 + pktInfo.class; + reg.r_bx = 0xFFFF; + reg.r_dx = 0; + reg.r_cx = 0; + +#if (DOSX & PHARLAP) + reg.ds = 0; + reg.esi = 0; + reg.es = RP_SEG (realBase); + reg.edi = (WORD) &PktReceiver; + +#elif (DOSX & DJGPP) + reg.x.ds = 0; + reg.x.si = 0; + reg.x.es = rm_mem.rm_segment; + reg.x.di = PktReceiver; + +#elif (DOSX & DOS4GW) + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = rm_base_seg; + reg.r_di = PktReceiver; + +#else + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = FP_SEG (&PktReceiver); + reg.r_di = FP_OFF (&PktReceiver); +#endif + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.handle = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktReleaseHandle (WORD handle) +{ + reg.r_ax = 0x0300; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTransmit (const void *eth, int len) +{ + if (len > ETH_MTU) + return (FALSE); + + reg.r_ax = 0x0400; /* Function 4, send pkt */ + reg.r_cx = len; /* total size of frame */ + +#if (DOSX & DJGPP) + dosmemput (eth, len, realBase+pktTxBuf); + reg.x.ds = rm_mem.rm_segment; /* DOS data segment and */ + reg.x.si = pktTxBuf; /* DOS offset to buffer */ + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTxBuf), eth, len); + reg.r_ds = rm_base_seg; + reg.r_si = pktTxBuf; + +#elif (DOSX & PHARLAP) + memcpy (&pktTxBuf, eth, len); + reg.r_ds = FP_SEG (&pktTxBuf); + reg.r_si = FP_OFF (&pktTxBuf); + +#else + reg.r_ds = FP_SEG (eth); + reg.r_si = FP_OFF (eth); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +#if (DOSX & (DJGPP|DOS4GW)) +LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx) +#else +LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx) +#endif +{ + WORD count_1, count_2; + + /* + * We got an upcall to the same RMCB with wrong handle. + * This can happen if we failed to release handle at program exit + */ + if (rx->handle != pktInfo.handle) + { + pktInfo.error = "Wrong handle"; + intStat.wrongHandle++; + PktReleaseHandle (rx->handle); + return (FALSE); + } + count_1 = rx->firstCount; + count_2 = rx->secondCount; + + if (count_1 != count_2) + { + pktInfo.error = "Bad sync"; + intStat.badSync++; + return (FALSE); + } + if (count_1 > ETH_MAX) + { + pktInfo.error = "Large esize"; + intStat.tooLarge++; + return (FALSE); + } +#if 0 + if (count_1 < ETH_MIN) + { + pktInfo.error = "Small esize"; + intStat.tooSmall++; + return (FALSE); + } +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTerminHandle (WORD handle) +{ + reg.r_ax = 0x0500; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetInterface (WORD handle) +{ + reg.r_ax = 0x0700; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode) +{ + if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP) + return (TRUE); + + reg.r_ax = 0x1400; + reg.r_bx = pktInfo.handle; + reg.r_cx = (WORD)mode; + + if (!PktInterrupt()) + return (FALSE); + + receiveMode = mode; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode) +{ + reg.r_ax = 0x1500; + reg.r_bx = pktInfo.handle; + + if (!PktInterrupt()) + return (FALSE); + + *mode = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +static PKT_STAT initialStat; /* statistics at startup */ +static BOOL resetStat = FALSE; /* statistics reset ? */ + +PUBLIC BOOL PktGetStatistics (WORD handle) +{ + reg.r_ax = 0x1800; + reg.r_bx = handle; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat); + +#elif (DOSX & DOS4GW) + memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat)); + +#else + _fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSessStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + if (resetStat) + { + pktStat.inPackets -= initialStat.inPackets; + pktStat.outPackets -= initialStat.outPackets; + pktStat.inBytes -= initialStat.inBytes; + pktStat.outBytes -= initialStat.outBytes; + pktStat.inErrors -= initialStat.inErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.lost -= initialStat.lost; + } + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + memcpy (&initialStat, &pktStat, sizeof(initialStat)); + resetStat = TRUE; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetAddress (ETHER *addr) +{ + reg.r_ax = 0x0600; + reg.r_bx = pktInfo.handle; + reg.r_cx = sizeof (*addr); + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; + reg.x.di = pktTemp; +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); /* ES:DI = address for result */ +#endif + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemget (realBase+pktTemp, sizeof(*addr), addr); + +#elif (DOSX & DOS4GW) + memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr)); + +#else + memcpy ((void*)addr, &pktTemp, sizeof(*addr)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetAddress (const ETHER *addr) +{ + /* copy addr to real-mode scrath area */ + +#if (DOSX & PHARLAP) + WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemput (addr, sizeof(*addr), realBase+pktTemp); + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr)); + +#else + memcpy (&pktTemp, (void*)addr, sizeof(*addr)); +#endif + + reg.r_ax = 0x1900; + reg.r_cx = sizeof (*addr); /* address length */ + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; /* DOS offset to param */ + reg.x.di = pktTemp; /* DOS segment to param */ +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverInfo (void) +{ + pktInfo.majVer = 0; + pktInfo.minVer = 0; + memset (&pktInfo.name, 0, sizeof(pktInfo.name)); + reg.r_ax = 0x01FF; + reg.r_bx = 0; + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.number = reg.r_cx & 0xFF; + pktInfo.class = reg.r_cx >> 8; +#if 0 + pktInfo.minVer = reg.r_bx % 10; + pktInfo.majVer = reg.r_bx / 10; +#else + pktInfo.majVer = reg.r_bx; // !! +#endif + pktInfo.funcs = reg.r_ax & 0xFF; + pktInfo.type = reg.r_dx & 0xFF; + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); + +#else + _fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverParam (void) +{ + reg.r_ax = 0x0A00; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE); + +#else + _fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE); +#endif + return (TRUE); +} + +/**************************************************************************/ + +#if (DOSX & PHARLAP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (outOfs != inOfs) + { + RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + outOfs += sizeof (RX_ELEMENT); + if (outOfs > LAST_RX_BUF) + outOfs = FIRST_RX_BUF; + *rxOutOfsFp = outOfs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + *rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp; + if (*rxOutOfsFp > LAST_RX_BUF) + *rxOutOfsFp = FIRST_RX_BUF; + *(DWORD _far*)(protBase + (WORD)&pktDrop) = 0; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (*(DWORD _far*)(protBase + (WORD)&pktDrop)); + } + +#elif (DOSX & DJGPP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs); + + if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = _farpeekw (_dos_ds, realBase+ofs); + head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2); + head.handle = _farpeekw (_dos_ds, realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + dosmemget (realBase+ofs+6, len, buf); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + disable(); + ofs = _farpeekw (_dos_ds, realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + _farpokel (_dos_ds, realBase+pktDrop, 0UL); + enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + disable(); + inOfs = _farpeekw (_dos_ds, realBase+rxInOfs); + outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs); + enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return _farpeekl (_dos_ds, realBase+pktDrop); + } + +#elif (DOSX & DOS4GW) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = *(WORD*) (realBase+rxOutOfs); + + if (ofs != *(WORD*) (realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = *(WORD*) (realBase+ofs); + head.secondCount = *(WORD*) (realBase+ofs+2); + head.handle = *(WORD*) (realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + memcpy (buf, (const void*)(realBase+ofs+6), len); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + _disable(); + ofs = *(WORD*) (realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + *(DWORD*) (realBase+pktDrop) = 0UL; + _enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + _disable(); + inOfs = *(WORD*) (realBase+rxInOfs); + outOfs = *(WORD*) (realBase+rxOutOfs); + _enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return *(DWORD*) (realBase+pktDrop); + } + +#else /* real-mode small/large model */ + + PUBLIC int PktReceive (BYTE *buf, int max) + { + if (rxOutOfs != rxInOfs) + { + RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + rxOutOfs += sizeof (RX_ELEMENT); + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs; + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + pktDrop = 0L; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = rxInOfs; + WORD outOfs = rxOutOfs; + + if (inOfs >= outOfs) + return ((inOfs - outOfs) / sizeof(RX_ELEMENT)); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (pktDrop); + } +#endif + +/**************************************************************************/ + +LOCAL __inline void PktFreeMem (void) +{ +#if (DOSX & PHARLAP) + if (realSeg) + { + _dx_real_free (realSeg); + realSeg = 0; + } +#elif (DOSX & DJGPP) + if (rm_mem.rm_segment) + { + unsigned ofs; /* clear the DOS-mem to prevent further upcalls */ + + for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4) + _farpokel (_dos_ds, realBase + ofs, 0); + _go32_dpmi_free_dos_memory (&rm_mem); + rm_mem.rm_segment = 0; + } +#elif (DOSX & DOS4GW) + if (rm_base_sel) + { + dpmi_real_free (rm_base_sel); + rm_base_sel = 0; + } +#endif +} + +/**************************************************************************/ + +PUBLIC BOOL PktExitDriver (void) +{ + if (pktInfo.handle) + { + if (!PktSetReceiverMode(PDRX_BROADCAST)) + PUTS ("Error restoring receiver mode."); + + if (!PktReleaseHandle(pktInfo.handle)) + PUTS ("Error releasing PKT-DRVR handle."); + + PktFreeMem(); + pktInfo.handle = 0; + } + + if (pcap_pkt_debug >= 1) + printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, " + "wrong-handle %lu\n", + intStat.tooSmall, intStat.tooLarge, + intStat.badSync, intStat.wrongHandle); + return (TRUE); +} + +#if (DOSX & (DJGPP|DOS4GW)) +static void dump_pkt_stub (void) +{ + int i; + + fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n", + PktReceiver); + for (i = 0; i < 15; i++) + fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]); + fputs ("\n", stderr); +} +#endif + +/* + * Front end initialization routine + */ +PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode) +{ + PKT_RX_MODE rxMode; + BOOL writeInfo = (pcap_pkt_debug >= 3); + + pktInfo.quiet = (pcap_pkt_debug < 3); + +#if (DOSX & PHARLAP) && defined(__HIGHC__) + if (_mwenv != 2) + { + fprintf (stderr, "Only Pharlap DOS extender supported.\n"); + return (FALSE); + } +#endif + +#if (DOSX & PHARLAP) && defined(__WATCOMC__) + if (_Extender != 1) + { + fprintf (stderr, "Only DOS4GW style extenders supported.\n"); + return (FALSE); + } +#endif + + if (!PktSearchDriver()) + { + PUTS ("Packet driver not found."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetDriverInfo()) + { + PUTS ("Error getting pkt-drvr information."); + PktFreeMem(); + return (FALSE); + } + +#if (DOSX & PHARLAP) + if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd, + &realBase, &protBase, (USHORT*)&realSeg)) + { + rxOutOfsFp = (WORD _far *) (protBase + (WORD) &rxOutOfs); + rxInOfsFp = (WORD _far *) (protBase + (WORD) &rxInOfs); + *rxOutOfsFp = FIRST_RX_BUF; + *rxInOfsFp = FIRST_RX_BUF; + } + else + { + PUTS ("Cannot allocate real-mode stub."); + return (FALSE); + } + +#elif (DOSX & (DJGPP|DOS4GW)) + if (sizeof(real_stub_array) > 0xFFFF) + { + fprintf (stderr, "`real_stub_array[]' too big.\n"); + return (FALSE); + } +#if (DOSX & DJGPP) + rm_mem.size = (sizeof(real_stub_array) + 15) / 16; + + if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_mem.rm_segment << 4); + dosmemput (&real_stub_array, sizeof(real_stub_array), realBase); + _farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + _farpokel (_dos_ds, realBase+rxInOfs, FIRST_RX_BUF); + +#elif (DOSX & DOS4GW) + rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel); + if (!rm_base_seg) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_base_seg << 4); + memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array)); + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + *(WORD*) (realBase+rxInOfs) = FIRST_RX_BUF; + +#endif + { + int pushf = PktReceiver; + + while (real_stub_array[pushf++] != 0x9C && /* pushf */ + real_stub_array[pushf] != 0xFA) /* cli */ + { + if (++para_skip > 16) + { + fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n"); + para_skip = 0; + dump_pkt_stub(); + return (FALSE); + } + } + if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800) + { + fprintf (stderr, "`real_stub_array[]' is misaligned.\n"); + return (FALSE); + } + } + + if (pcap_pkt_debug > 2) + dump_pkt_stub(); + +#else + rxOutOfs = FIRST_RX_BUF; + rxInOfs = FIRST_RX_BUF; +#endif + + if (!PktSetAccess()) + { + PUTS ("Error setting pkt-drvr access."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetAddress(&myAddress)) + { + PUTS ("Error fetching adapter address."); + PktFreeMem(); + return (FALSE); + } + + if (!PktSetReceiverMode(mode)) + { + PUTS ("Error setting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetReceiverMode(&rxMode)) + { + PUTS ("Error getting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (writeInfo) + printf ("Pkt-driver information:\n" + " Version : %d.%d\n" + " Name : %.15s\n" + " Class : %u (%s)\n" + " Type : %u\n" + " Number : %u\n" + " Funcs : %u\n" + " Intr : %Xh\n" + " Handle : %u\n" + " Extended : %s\n" + " Hi-perf : %s\n" + " RX mode : %s\n" + " Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n", + + pktInfo.majVer, pktInfo.minVer, pktInfo.name, + pktInfo.class, PktGetClassName(pktInfo.class), + pktInfo.type, pktInfo.number, + pktInfo.funcs, pktInfo.intr, pktInfo.handle, + pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No", + pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No", + PktRXmodeStr(rxMode), + myAddress[0], myAddress[1], myAddress[2], + myAddress[3], myAddress[4], myAddress[5]); + +#if defined(DEBUG) && (DOSX & PHARLAP) + if (writeInfo) + { + DWORD rAdr = realBase + (WORD)&PktReceiver; + unsigned sel, ofs; + + printf ("\nReceiver at %04X:%04X\n", RP_SEG(rAdr), RP_OFF(rAdr)); + printf ("Realbase = %04X:%04X\n", RP_SEG(realBase),RP_OFF(realBase)); + + sel = _FP_SEG (protBase); + ofs = _FP_OFF (protBase); + printf ("Protbase = %04X:%08X\n", sel,ofs); + printf ("RealSeg = %04X\n", realSeg); + + sel = _FP_SEG (rxOutOfsFp); + ofs = _FP_OFF (rxOutOfsFp); + printf ("rxOutOfsFp = %04X:%08X\n", sel,ofs); + + sel = _FP_SEG (rxInOfsFp); + ofs = _FP_OFF (rxInOfsFp); + printf ("rxInOfsFp = %04X:%08X\n", sel,ofs); + + printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + + PktQueueBusy (TRUE); + printf ("Busy: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + } +#endif + + memset (&pktStat, 0, sizeof(pktStat)); /* clear statistics */ + PktQueueBusy (TRUE); + return (TRUE); +} + + +/* + * DPMI functions only for Watcom + DOS4GW extenders + */ +#if (DOSX & DOS4GW) +LOCAL DWORD dpmi_get_real_vector (int intr) +{ + union REGS r; + + r.x.eax = 0x200; + r.x.ebx = (DWORD) intr; + int386 (0x31, &r, &r); + return ((r.w.cx << 4) + r.w.dx); +} + +LOCAL WORD dpmi_real_malloc (int size, WORD *selector) +{ + union REGS r; + + r.x.eax = 0x0100; /* DPMI allocate DOS memory */ + r.x.ebx = (size + 15) / 16; /* Number of paragraphs requested */ + int386 (0x31, &r, &r); + if (r.w.cflag & 1) + return (0); + + *selector = r.w.dx; + return (r.w.ax); /* Return segment address */ +} + +LOCAL void dpmi_real_free (WORD selector) +{ + union REGS r; + + r.x.eax = 0x101; /* DPMI free DOS memory */ + r.x.ebx = selector; /* Selector to free */ + int386 (0x31, &r, &r); +} +#endif + + +#if defined(DOSX) && (DOSX & PHARLAP) +/* + * Description: + * This routine allocates conventional memory for the specified block + * of code (which must be within the first 64K of the protected mode + * program segment) and copies the code to it. + * + * The caller should free up the conventional memory block when it + * is done with the conventional memory. + * + * NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER. + * + * Calling arguments: + * start_offs start of real mode code in program segment + * end_offs 1 byte past end of real mode code in program segment + * real_basep returned; real mode ptr to use as a base for the + * real mode code (eg, to get the real mode FAR + * addr of a function foo(), take + * real_basep + (ULONG) foo). + * This pointer is constructed such that + * offsets within the real mode segment are + * the same as the link-time offsets in the + * protected mode program segment + * prot_basep returned; prot mode ptr to use as a base for getting + * to the conventional memory, also constructed + * so that adding the prot mode offset of a + * function or variable to the base gets you a + * ptr to the function or variable in the + * conventional memory block. + * rmem_adrp returned; real mode para addr of allocated + * conventional memory block, to be used to free + * up the conventional memory when done. DO NOT + * USE THIS TO CONSTRUCT A REAL MODE PTR, USE + * REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT + * CORRECTLY. + * + * Returned values: + * 0 if error + * 1 if success + */ +int RealCopy (ULONG start_offs, + ULONG end_offs, + REALPTR *real_basep, + FARPTR *prot_basep, + USHORT *rmem_adrp) +{ + ULONG rm_base; /* base real mode para addr for accessing */ + /* allocated conventional memory */ + UCHAR *source; /* source pointer for copy */ + FARPTR destin; /* destination pointer for copy */ + ULONG len; /* number of bytes to copy */ + ULONG temp; + USHORT stemp; + + /* First check for valid inputs + */ + if (start_offs >= end_offs || end_offs > 0x10000) + return (FALSE); + + /* Round start_offs down to a paragraph (16-byte) boundary so we can set up + * the real mode pointer easily. Round up end_offs to make sure we allocate + * enough paragraphs + */ + start_offs &= ~15; + end_offs = (15 + (end_offs << 4)) >> 4; + + /* Allocate the conventional memory for our real mode code. Remember to + * round byte count UP to 16-byte paragraph size. We alloc it + * above the DOS data buffer so both the DOS data buffer and the appl + * conventional mem block can still be resized. + * + * First just try to alloc it; if we can't get it, shrink the appl mem + * block down to the minimum, try to alloc the memory again, then grow the + * appl mem block back to the maximum. (Don't try to shrink the DOS data + * buffer to free conventional memory; it wouldn't be good for this routine + * to have the possible side effect of making file I/O run slower.) + */ + len = ((end_offs - start_offs) + 15) >> 4; + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + { + if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE) + return (FALSE); + + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + *rmem_adrp = 0; + + if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE) + { + if (*rmem_adrp != 0) + _dx_real_free (*rmem_adrp); + return (FALSE); + } + + if (*rmem_adrp == 0) + return (FALSE); + } + + /* Construct real mode & protected mode pointers to access the allocated + * memory. Note we know start_offs is aligned on a paragraph (16-byte) + * boundary, because we rounded it down. + * + * We make the offsets come out rights by backing off the real mode selector + * by start_offs. + */ + rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4); + RP_SET (*real_basep, 0, rm_base); + FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM); + + /* Copy the real mode code/data to the allocated memory + */ + source = (UCHAR *) start_offs; + destin = *prot_basep; + FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep)); + len = end_offs - start_offs; + WriteFarMem (destin, source, len); + + return (TRUE); +} +#endif /* DOSX && (DOSX & PHARLAP) */ diff --git a/msdos/pktdrvr.h b/msdos/pktdrvr.h new file mode 100644 index 0000000..08898ae --- /dev/null +++ b/msdos/pktdrvr.h @@ -0,0 +1,153 @@ +#ifndef __PKTDRVR_H +#define __PKTDRVR_H + +#define PUBLIC +#define LOCAL static + +#define RX_BUF_SIZE ETH_MTU /* buffer size variables. NB !! */ +#define TX_BUF_SIZE ETH_MTU /* must be same as in pkt_rx*.* */ + +#ifdef __HIGHC__ +#pragma Off(Align_members) +#else +#pragma pack(1) +#endif + +typedef enum { /* Packet-driver classes */ + PD_ETHER = 1, + PD_PRONET10 = 2, + PD_IEEE8025 = 3, + PD_OMNINET = 4, + PD_APPLETALK = 5, + PD_SLIP = 6, + PD_STARTLAN = 7, + PD_ARCNET = 8, + PD_AX25 = 9, + PD_KISS = 10, + PD_IEEE8023_2 = 11, + PD_FDDI8022 = 12, + PD_X25 = 13, + PD_LANstar = 14, + PD_PPP = 18 + } PKT_CLASS; + +typedef enum { /* Packet-driver receive modes */ + PDRX_OFF = 1, /* turn off receiver */ + PDRX_DIRECT, /* receive only to this interface */ + PDRX_BROADCAST, /* DIRECT + broadcast packets */ + PDRX_MULTICAST1, /* BROADCAST + limited multicast */ + PDRX_MULTICAST2, /* BROADCAST + all multicast */ + PDRX_ALL_PACKETS, /* receive all packets on network */ + } PKT_RX_MODE; + +typedef struct { + char type[8]; + char len; + } PKT_FRAME; + + +typedef struct { + BYTE class; /* = 1 for DEC/Interl/Xerox Ethernet */ + BYTE number; /* = 0 for single LAN adapter */ + WORD type; /* = 13 for 3C523 */ + BYTE funcs; /* Basic/Extended/HiPerf functions */ + WORD intr; /* user interrupt vector number */ + WORD handle; /* Handle associated with session */ + BYTE name [15]; /* Name of adapter interface,ie.3C523*/ + BOOL quiet; /* (don't) print errors to stdout */ + const char *error; /* address of error string */ + BYTE majVer; /* Major driver implementation ver. */ + BYTE minVer; /* Minor driver implementation ver. */ + BYTE dummyLen; /* length of following data */ + WORD MAClength; /* HiPerformance data, N/A */ + WORD MTU; /* HiPerformance data, N/A */ + WORD multicast; /* HiPerformance data, N/A */ + WORD rcvrBuffers; /* valid for */ + WORD UMTbufs; /* High Performance drivers only */ + WORD postEOIintr; /* Usage ?? */ + } PKT_INFO; + +#define PKT_PARAM_SIZE 14 /* members majVer - postEOIintr */ + + +typedef struct { + DWORD inPackets; /* # of packets received */ + DWORD outPackets; /* # of packets transmitted */ + DWORD inBytes; /* # of bytes received */ + DWORD outBytes; /* # of bytes transmitted */ + DWORD inErrors; /* # of reception errors */ + DWORD outErrors; /* # of transmission errors */ + DWORD lost; /* # of packets lost (RX) */ + } PKT_STAT; + + +typedef struct { + ETHER destin; + ETHER source; + WORD proto; + BYTE data [TX_BUF_SIZE]; + } TX_ELEMENT; + +typedef struct { + WORD firstCount; /* # of bytes on 1st */ + WORD secondCount; /* and 2nd upcall */ + WORD handle; /* instance that upcalled */ + ETHER destin; /* E-net destination address */ + ETHER source; /* E-net source address */ + WORD proto; /* protocol number */ + BYTE data [RX_BUF_SIZE]; + } RX_ELEMENT; + + +#ifdef __HIGHC__ +#pragma pop(Align_members) +#else +#pragma pack() +#endif + + +/* + * Prototypes for publics + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern PKT_STAT pktStat; /* statistics for packets */ +extern PKT_INFO pktInfo; /* packet-driver information */ + +extern PKT_RX_MODE receiveMode; +extern ETHER myAddress, ethBroadcast; + +extern BOOL PktInitDriver (PKT_RX_MODE mode); +extern BOOL PktExitDriver (void); + +extern const char *PktGetErrorStr (int errNum); +extern const char *PktGetClassName (WORD class); +extern const char *PktRXmodeStr (PKT_RX_MODE mode); +extern BOOL PktSearchDriver (void); +extern int PktReceive (BYTE *buf, int max); +extern BOOL PktTransmit (const void *eth, int len); +extern DWORD PktRxDropped (void); +extern BOOL PktReleaseHandle (WORD handle); +extern BOOL PktTerminHandle (WORD handle); +extern BOOL PktResetInterface (WORD handle); +extern BOOL PktSetReceiverMode(PKT_RX_MODE mode); +extern BOOL PktGetReceiverMode(PKT_RX_MODE *mode); +extern BOOL PktGetStatistics (WORD handle); +extern BOOL PktSessStatistics (WORD handle); +extern BOOL PktResetStatistics(WORD handle); +extern BOOL PktGetAddress (ETHER *addr); +extern BOOL PktSetAddress (const ETHER *addr); +extern BOOL PktGetDriverInfo (void); +extern BOOL PktGetDriverParam (void); +extern void PktQueueBusy (BOOL busy); +extern WORD PktBuffersUsed (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PKTDRVR_H */ + diff --git a/msdos/readme.dos b/msdos/readme.dos new file mode 100644 index 0000000..306f69f --- /dev/null +++ b/msdos/readme.dos @@ -0,0 +1,156 @@ +libpcap for DOS +--------------- + +This file contains some notes on building and using libpcap for MS-DOS. +Look in `README' and `pcap.man' for usage and details. These targets are +supported: + + - Borland C 4.0+ small or large model. + - Metaware HighC 3.1+ with PharLap DOS-extender + - GNU C 2.7+ with djgpp 2.01+ DOS extender + - Watcom C 11.x with DOS4GW extender + +Note: the files in the libpcap.zip contains short trucated filenames. + So for djgpp to work with these, disable the use of long file names by + setting "LFN=n" in the environment. + +Files specific to DOS are pcap-dos.[ch] and the assembly and C files in +the MSDOS sub-directory. Remember to built lipcap libraries from the top +install directory. And not from the MSDOS sub-directory. + + +Requirements +------------ + +DOS-libpcap currently only works reliably with a real-mode Ethernet packet- +driver. This driver must be installed prior to using any program (e.g. +tcpdump) compiled with libpcap. Work is underway to implement protected- +mode drivers for 32-bit targets (djgpp only). The 3Com 3c509 driver is +working almost perfectly. Due to lack of LAN-cards, I've not had the +opporunity to test other drivers. These 32-bit drivers are modified +Linux drivers. + + +Required packages +----------------- + +The following packages and tools must be present for all targets. + +1. Watt-32 tcp/ip library. This library is *not* used to send or + receive network data. It's mostly used to access the 'hosts' + file and other features. Get 'watt32s*.zip' at: + + http://www.bgnett.no/~giva/ + +2. Exception handler and disassember library (libexc.a) is needed if + "USE_EXCEPT = 1" in common.dj. Available at: + + http://www.bgnett.no/~giva/misc/exc_dx07.zip + +3. Flex & Bison is used to generate parser for the filter handler + pcap_compile: + + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/flx254b.zip + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsn128b.zip + +4. NASM assembler v 0.98 or later is required when building djgpp and + Watcom targets: + + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2tk/nasm098p.zip + +5. sed (Stream Editor) is required for doing `make depend'. + It's available at + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/sed*.zip + + A touch tool to update the time-stamp of a file. E.g. + ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/grep*.zip + +6. For djgpp rm.exe and cp.exe are required. These should already be + part of your djgpp installation. Also required (experimental at the + time) for djgpp is DLX 2.91 or later. This tool is for the generation + of dynamically loadable modules. + + +Compiling libpcap +----------------- + +Follow these steps in building libpcap: + +1. Make sure you've installed Watt-32 properly (see it's `INSTALL' file). + During that installation a environment variable `WATT_ROOT' is set. + This variable is used for building libpcap also (`WATT_INC' is + deducted from `WATT_ROOT'). djgpp users should also define environment + variables `C_INCLUDE_PATH' and `LIBRARY_PATH' to point to the include + directory and library directory respectively. E.g. put this in your + AUTOEXEC.BAT: + set C_INCLUDE_PATH=c:/net/watt/inc + set LIBRARY_PATH=c:/net/watt/lib + +2. Revise the msdos/common.dj file for your djgpp/gcc installation; + - change the value of `GCCLIB' to match location of libgcc.a. + - set `USE_32BIT_DRIVERS = 1' to build 32-bit driver objects. + + +3. Build pcap by using appropriate makefile. For djgpp, use: + `make -f msdos/makefile.dj' (i.e. GNU `make') + + For a Watcom target say: + `wmake -f msdos\makefile.wc' + + For a Borland target say: + `maker -f msdos\Makefile pcap_bc.lib' (Borland's `maker.exe') + + And for a HighC/Pharlap target say: + `maker -f msdos\Makefile pcap_hc.lib' (Borland's `maker.exe') + + You might like to change some `CFLAGS' -- only `DEBUG' define currently + have any effect. It shows a rotating "fan" in upper right corner of + screen. Remove `DEBUG' if you don't like it. You could add + `-fomit-frame-pointer' to `CFLAGS' to speed up the generated code. + But note, this makes debugging and crash-traceback difficult. Only + add it if you're fully confident your application is 100% stable. + + Note: Code in `USE_NDIS2' does not work at the moment. + +4. The resulting libraries are put in current directory. There's no + test-program for `libpcap'. Linking the library with `tcpdump' is + the ultimate test anyway. + + + +Extensions to libpcap +--------------------- + +I've included some extra functions to DOS-libpcap: + + `pcap_config_hook (const char *name, const char *value)' + + Allows an application to set values of internal libpcap variables. + `name' is typically a left-side keyword with an associated `value' + that is called from application's configure process (see tcpdump's + config.c file). libpcap keeps a set of tables that are searched for + a name/value match. Currently only used to set debug-levels and + parameters for the 32-bit network drivers. + + `pcap_set_wait (pcap_t *, void (*)(void), int)' : + + Only effective when reading offline traffic from dump-files. + Function `pcap_offline_read()' will wait (and optionally yield) + before printing next packet. This will simulate the pace the packets + where actually recorded. + + `pcap_verbose (int mode)' : + Sets the internal verbosity mode. Currently only effective while + capturing packets to file (the `-w' option in tcpdump). `pcap_dump()' + will print to `stderr' number of packets dumped. + + + +Happy sniffing ! + + +Gisle Vanem + + +October 1999, 2004 + diff --git a/optimize.c b/optimize.c index f80a75f..a2c2a98 100644 --- a/optimize.c +++ b/optimize.c @@ -22,7 +22,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.83 2004-11-14 03:10:33 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.84 2004-12-18 08:52:09 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -32,6 +32,7 @@ static const char rcsid[] _U_ = #include #include #include +#include #include @@ -47,6 +48,11 @@ static const char rcsid[] _U_ = extern int dflag; #endif +#if defined(MSDOS) && !defined(__DJGPP__) +extern int _w32_ffs (int mask); +#define ffs _w32_ffs +#endif + /* * Represents a deleted instruction. */ diff --git a/pcap-bpf.h b/pcap-bpf.h index 831d1b0..18454d5 100644 --- a/pcap-bpf.h +++ b/pcap-bpf.h @@ -37,7 +37,7 @@ * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 * - * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.27 2004-12-09 19:03:36 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.28 2004-12-18 08:52:10 guy Exp $ (LBL) */ /* @@ -60,8 +60,13 @@ extern "C" { /* BSD style release date */ #define BPF_RELEASE 199606 +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else typedef int bpf_int32; typedef u_int bpf_u_int32; +#endif /* * Alignment macros. BPF_WORDALIGN rounds up to the next diff --git a/pcap-dos.c b/pcap-dos.c new file mode 100644 index 0000000..26a925b --- /dev/null +++ b/pcap-dos.c @@ -0,0 +1,1473 @@ +/* + * This file is part of DOS-libpcap + * Ported to DOS/DOSX by G. Vanem + * + * pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode + * network drivers. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-dos.c,v 1.1 2004-12-18 08:52:10 guy Exp $ (LBL) + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/pmdrvr.h" + #include "msdos/pm_drvr/pci.h" + #include "msdos/pm_drvr/bios32.h" + #include "msdos/pm_drvr/module.h" + #include "msdos/pm_drvr/3c501.h" + #include "msdos/pm_drvr/3c503.h" + #include "msdos/pm_drvr/3c509.h" + #include "msdos/pm_drvr/3c59x.h" + #include "msdos/pm_drvr/3c515.h" + #include "msdos/pm_drvr/3c90x.h" + #include "msdos/pm_drvr/3c575_cb.h" + #include "msdos/pm_drvr/ne.h" + #include "msdos/pm_drvr/wd.h" + #include "msdos/pm_drvr/accton.h" + #include "msdos/pm_drvr/cs89x0.h" + #include "msdos/pm_drvr/rtl8139.h" + #include "msdos/pm_drvr/ne2k-pci.h" +#endif + +#include "pcap.h" +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#ifdef USE_NDIS2 +#include "msdos/ndis2.h" +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(USE_32BIT_DRIVERS) + #define FLUSHK() do { _printk_safe = 1; _printk_flush(); } while (0) + #define NDIS_NEXT_DEV &rtl8139_dev + + static char *rx_pool = NULL; + static void init_32bit (void); + + static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool); + static int pktq_check (struct rx_ringbuf *q); + static int pktq_inc_out (struct rx_ringbuf *q); + static int pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC; + static void pktq_clear (struct rx_ringbuf *q) LOCKED_FUNC; + + static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) LOCKED_FUNC; + static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q); + +#else + #define FLUSHK() ((void)0) + #define NDIS_NEXT_DEV NULL +#endif + +/* + * Internal variables/functions in Watt-32 + */ +extern WORD _pktdevclass; +extern BOOL _eth_is_init; +extern int _w32_dynamic_host; +extern int _watt_do_exit; +extern int _watt_is_init; +extern int _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req; +extern void (*_w32_usr_post_init) (void); +extern void (*_w32_print_hook)(); + +extern void dbug_write (const char *); /* Watt-32 lib, pcdbug.c */ +extern int pkt_get_mtu (void); + +static int ref_count = 0; + +static u_long mac_count = 0; +static u_long filter_count = 0; + +static volatile BOOL exc_occured = 0; + +static struct device *handle_to_device [20]; + +static int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, + u_char *data); +static void pcap_close_dos (pcap_t *p); +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps); +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len); +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp); + +static int ndis_probe (struct device *dev); +static int pkt_probe (struct device *dev); + +static void close_driver (void); +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf); +static int first_init (const char *name, char *ebuf, int promisc); + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf); + +/* + * These are the device we always support + */ +static struct device ndis_dev = { + "ndis", + "NDIS2 LanManager", + 0, + 0,0,0,0,0,0, + NDIS_NEXT_DEV, /* NULL or a 32-bit device */ + ndis_probe + }; + +static struct device pkt_dev = { + "pkt", + "Packet-Driver", + 0, + 0,0,0,0,0,0, + &ndis_dev, + pkt_probe + }; + +static struct device *get_device (int fd) +{ + if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0])) + return (NULL); + return handle_to_device [fd-1]; +} + +/* + * Open MAC-driver with name 'device_name' for live capture of + * network packets. + */ +pcap_t *pcap_open_live (const char *device_name, int snaplen, int promisc, + int timeout_ms, char *errbuf) +{ + struct pcap *pcap; + + if (snaplen < ETH_MIN) + snaplen = ETH_MIN; + + if (snaplen > ETH_MAX) /* silently accept and truncate large MTUs */ + snaplen = ETH_MAX; + + pcap = calloc (sizeof(*pcap), 1); + if (!pcap) + { + strcpy (errbuf, "Not enough memory (pcap)"); + return (NULL); + } + + pcap->snapshot = max (ETH_MIN+8, snaplen); + pcap->linktype = DLT_EN10MB; /* !! */ + pcap->inter_packet_wait = timeout_ms; + pcap->close_op = pcap_close_dos; + pcap->read_op = pcap_read_dos; + pcap->stats_op = pcap_stats_dos; + pcap->inject_op = pcap_sendpacket_dos; + pcap->setfilter_op = pcap_setfilter_dos; + pcap->fd = ++ref_count; + + if (pcap->fd == 1) /* first time we're called */ + { + if (!init_watt32(pcap, device_name, errbuf) || + !first_init(device_name, errbuf, promisc)) + { + free (pcap); + return (NULL); + } + atexit (close_driver); + } + else if (stricmp(active_dev->name,device_name)) + { + snprintf (errbuf, PCAP_ERRBUF_SIZE, + "Cannot use different devices simultaneously " + "(`%s' vs. `%s')", active_dev->name, device_name); + free (pcap); + pcap = NULL; + } + handle_to_device [pcap->fd-1] = active_dev; + return (pcap); +} + +/* + * Poll the receiver queue and call the pcap callback-handler + * with the packet. + */ +static int +pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data) +{ + struct pcap_pkthdr pcap; + struct bpf_insn *fcode = p->fcode.bf_insns; + struct timeval now, expiry; + BYTE *rx_buf; + int rx_len = 0; + + if (p->inter_packet_wait > 0) + { + gettimeofday2 (&now, NULL); + expiry.tv_usec = now.tv_usec + 1000UL * p->inter_packet_wait; + expiry.tv_sec = now.tv_sec; + while (expiry.tv_usec >= 1000000L) + { + expiry.tv_usec -= 1000000L; + expiry.tv_sec++; + } + } + + while (!exc_occured) + { + volatile struct device *dev; /* might be reset by sig_handler */ + + dev = get_device (p->fd); + if (!dev) + break; + + PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf); + FLUSHK(); + + /* If driver has a zero-copy receive facility, peek at the queue, + * filter it, do the callback and release the buffer. + */ + if (dev->peek_rx_buf) + { + PCAP_ASSERT (dev->release_rx_buf); + rx_len = (*dev->peek_rx_buf) (&rx_buf); + } + else + { + BYTE buf [ETH_MAX+100]; /* add some margin */ + rx_len = (*dev->copy_rx_buf) (buf, p->snapshot); + rx_buf = buf; + } + + if (rx_len > 0) /* got a packet */ + { + mac_count++; + + FLUSHK(); + + pcap.caplen = min (rx_len, p->snapshot); + pcap.len = rx_len; + + if (callback && + (!fcode || bpf_filter(fcode, rx_buf, pcap.len, pcap.caplen))) + { + filter_count++; + + /* Fix-me!! Should be time of arrival. Not time of + * capture. + */ + gettimeofday2 (&pcap.ts, NULL); + (*callback) (data, &pcap, rx_buf); + } + + if (dev->release_rx_buf) + (*dev->release_rx_buf) (rx_buf); + + if (pcap_pkt_debug > 0) + { + if (callback == watt32_recv_hook) + dbug_write ("pcap_recv_hook\n"); + else dbug_write ("pcap_read_op\n"); + } + FLUSHK(); + return (1); + } + + /* If not to wait for a packet or pcap_close() called from + * e.g. SIGINT handler, exit loop now. + */ + if (p->inter_packet_wait <= 0 || (volatile int)p->fd <= 0) + break; + + gettimeofday2 (&now, NULL); + + if (timercmp(&now, &expiry, >)) + break; + +#ifndef DJGPP + kbhit(); /* a real CPU hog */ +#endif + + if (p->wait_proc) + (*p->wait_proc)(); /* call yield func */ + } + + if (rx_len < 0) /* receive error */ + { + p->md.stat.ps_drop++; +#ifdef USE_32BIT_DRIVERS + if (pcap_pkt_debug > 1) + printk ("pkt-err %s\n", pktInfo.error); +#endif + return (-1); + } + return (0); +} + +static int +pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data) +{ + int rc, num = 0; + + while (num <= cnt || (cnt < 0)) + { + if (p->fd <= 0) + return (-1); + rc = pcap_read_one (p, callback, data); + if (rc > 0) + num++; + if (rc < 0) + break; + _w32_os_yield(); /* allow SIGINT generation, yield to Win95/NT */ + } + return (num); +} + +/* + * Return network statistics + */ +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps) +{ + struct net_device_stats *stats; + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev) + { + strcpy (p->errbuf, "illegal pcap handle"); + return (-1); + } + + if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL) + { + strcpy (p->errbuf, "device statistics not available"); + return (-1); + } + + FLUSHK(); + + p->md.stat.ps_recv = stats->rx_packets; + p->md.stat.ps_drop += stats->rx_missed_errors; + p->md.stat.ps_ifdrop = stats->rx_dropped + /* queue full */ + stats->rx_errors; /* HW errors */ + if (ps) + *ps = p->md.stat; + + return (0); +} + +/* + * Return detailed network/device statistics. + * May be called after 'dev->close' is called. + */ +int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) +{ + struct device *dev = p ? get_device (p->fd) : NULL; + + if (!dev || !dev->get_stats) + { + strlcpy (p->errbuf, "detailed device statistics not available", + PCAP_ERRBUF_SIZE); + return (-1); + } + + if (!strnicmp(dev->name,"pkt",3)) + { + strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", + PCAP_ERRBUF_SIZE); + return (-1); + } + memcpy (se, (*dev->get_stats)(dev), sizeof(*se)); + return (0); +} + +/* + * Simply store the filter-code for the pcap_read_dos() callback + * Some day the filter-code could be handed down to the active + * device (pkt_rx1.s or 32-bit device interrupt handler). + */ +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp) +{ + if (!p) + return (-1); + p->fcode = *fp; + return (0); +} + +/* + * Return # of packets received in pcap_read_dos() + */ +u_long pcap_mac_packets (void) +{ + return (mac_count); +} + +/* + * Return # of packets passed through filter in pcap_read_dos() + */ +u_long pcap_filter_packets (void) +{ + return (filter_count); +} + +/* + * Close pcap device. Not called for offline captures. + */ +static void pcap_close_dos (pcap_t *p) +{ + if (p && !exc_occured) + { + if (pcap_stats(p,NULL) < 0) + p->md.stat.ps_drop = 0; + if (!get_device(p->fd)) + return; + + handle_to_device [p->fd-1] = NULL; + p->fd = 0; + if (ref_count > 0) + ref_count--; + if (ref_count > 0) + return; + } + close_driver(); +} + +/* + * Return the name of the 1st network interface, + * or NULL if none can be found. + */ +char *pcap_lookupdev (char *ebuf) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if ((*dev->probe)(dev)) + { + FLUSHK(); + probed_dev = (struct device*) dev; /* remember last probed device */ + return (char*) dev->name; + } + } + + if (ebuf) + strcpy (ebuf, "No driver found"); + return (NULL); +} + +/* + * Gets localnet & netmask from Watt-32. + */ +int pcap_lookupnet (const char *device, bpf_u_int32 *localnet, + bpf_u_int32 *netmask, char *errbuf) +{ + if (!_watt_is_init) + { + strcpy (errbuf, "pcap_open_offline() or pcap_open_live() must be " + "called first"); + return (-1); + } + + *netmask = _w32_sin_mask; + *localnet = my_ip_addr & *netmask; + if (*localnet == 0) + { + if (IN_CLASSA(*netmask)) + *localnet = IN_CLASSA_NET; + else if (IN_CLASSB(*netmask)) + *localnet = IN_CLASSB_NET; + else if (IN_CLASSC(*netmask)) + *localnet = IN_CLASSC_NET; + else + { + sprintf (errbuf, "inet class for 0x%lx unknown", *netmask); + return (-1); + } + } + ARGSUSED (device); + return (0); +} + +/* + * Get a list of all interfaces that are present and that we probe okay. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + */ +int pcap_findalldevs (pcap_if_t **alldevsp, char *errbuf) +{ + struct device *dev; + struct sockaddr_ll sa_ll_1, sa_ll_2; + struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; + pcap_if_t *devlist = NULL; + int ret = 0; + size_t addr_size = sizeof(struct sockaddr_ll); + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) + continue; + + PCAP_ASSERT (dev->close); /* set by probe routine */ + FLUSHK(); + (*dev->close) (dev); + + memset (&sa_ll_1, 0, sizeof(sa_ll_1)); + memset (&sa_ll_2, 0, sizeof(sa_ll_2)); + sa_ll_1.sll_family = AF_PACKET; + sa_ll_2.sll_family = AF_PACKET; + + addr = (struct sockaddr*) &sa_ll_1; + netmask = (struct sockaddr*) &sa_ll_1; + dstaddr = (struct sockaddr*) &sa_ll_1; + broadaddr = (struct sockaddr*) &sa_ll_2; + memset (&sa_ll_2.sll_addr, 0xFF, sizeof(sa_ll_2.sll_addr)); + + if (pcap_add_if(&devlist, dev->name, dev->flags, + dev->long_name, errbuf) < 0) + { + ret = -1; + break; + } + if (add_addr_to_iflist(&devlist,dev->name, dev->flags, addr, addr_size, + netmask, addr_size, broadaddr, addr_size, + dstaddr, addr_size, errbuf) < 0) + { + ret = -1; + break; + } + } + + if (devlist && ret < 0) + { + pcap_freealldevs (devlist); + devlist = NULL; + } + else + if (!devlist) + strcpy (errbuf, "No drivers found"); + + *alldevsp = devlist; + return (ret); +} + +/* + * pcap_assert() is mainly used for debugging + */ +void pcap_assert (const char *what, const char *file, unsigned line) +{ + FLUSHK(); + fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n", + file, line, what); + close_driver(); + _exit (-1); +} + +/* + * For pcap_offline_read(): wait and yield between printing packets + * to simulate the pace packets where actually recorded. + */ +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait) +{ + if (p) + { + p->wait_proc = yield; + p->inter_packet_wait = wait; + } +} + +/* + * Initialise a named network device. + */ +static struct device * +open_driver (const char *dev_name, char *ebuf, int promisc) +{ + struct device *dev; + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->name); + + if (strcmp (dev_name,dev->name)) + continue; + + if (!probed_dev) /* user didn't call pcap_lookupdev() first */ + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) /* call the xx_probe() function */ + { + sprintf (ebuf, "failed to detect device `%s'", dev_name); + return (NULL); + } + probed_dev = dev; /* device is probed okay and may be used */ + } + else if (dev != probed_dev) + { + goto not_probed; + } + + FLUSHK(); + + /* Select what traffic to receive + */ + if (promisc) + dev->flags |= (IFF_ALLMULTI | IFF_PROMISC); + else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC); + + PCAP_ASSERT (dev->open); + + if (!(*dev->open)(dev)) + { + sprintf (ebuf, "failed to activate device `%s'", dev_name); + if (pktInfo.error && !strncmp(dev->name,"pkt",3)) + { + strcat (ebuf, ": "); + strcat (ebuf, pktInfo.error); + } + return (NULL); + } + + /* Some devices need this to operate in promiscous mode + */ + if (promisc && dev->set_multicast_list) + (*dev->set_multicast_list) (dev); + + active_dev = dev; /* remember our active device */ + break; + } + + /* 'dev_name' not matched in 'dev_base' list. + */ + if (!dev) + { + sprintf (ebuf, "device `%s' not supported", dev_name); + return (NULL); + } + +not_probed: + if (!probed_dev) + { + sprintf (ebuf, "device `%s' not probed", dev_name); + return (NULL); + } + return (dev); +} + +/* + * Deinitialise MAC driver. + * Set receive mode back to default mode. + */ +static void close_driver (void) +{ + /* !!todo: loop over all 'handle_to_device[]' ? */ + struct device *dev = active_dev; + + if (dev && dev->close) + { + (*dev->close) (dev); + FLUSHK(); + } + + active_dev = NULL; + +#ifdef USE_32BIT_DRIVERS + if (rx_pool) + { + k_free (rx_pool); + rx_pool = NULL; + } + if (dev) + pcibios_exit(); +#endif +} + + +#ifdef __DJGPP__ +static void setup_signals (void (*handler)(int)) +{ + signal (SIGSEGV,handler); + signal (SIGILL, handler); + signal (SIGFPE, handler); +} + +static void exc_handler (int sig) +{ +#ifdef USE_32BIT_DRIVERS + if (active_dev->irq > 0) /* excludes IRQ 0 */ + { + disable_irq (active_dev->irq); + irq_eoi_cmd (active_dev->irq); + _printk_safe = 1; + } +#endif + + switch (sig) + { + case SIGSEGV: + fputs ("Catching SIGSEGV.\n", stderr); + break; + case SIGILL: + fputs ("Catching SIGILL.\n", stderr); + break; + case SIGFPE: + _fpreset(); + fputs ("Catching SIGFPE.\n", stderr); + break; + default: + fprintf (stderr, "Catching signal %d.\n", sig); + } + exc_occured = 1; + pcap_close_dos (NULL); +} +#endif /* __DJGPP__ */ + + +/* + * Open the pcap device for the first client calling pcap_open_live() + */ +static int first_init (const char *name, char *ebuf, int promisc) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE); + if (!rx_pool) + { + strcpy (ebuf, "Not enough memory (Rx pool)"); + return (0); + } +#endif + +#ifdef __DJGPP__ + setup_signals (exc_handler); +#endif + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + dev = open_driver (name, ebuf, promisc); + if (!dev) + { +#ifdef USE_32BIT_DRIVERS + k_free (rx_pool); + rx_pool = NULL; +#endif + +#ifdef __DJGPP__ + setup_signals (SIG_DFL); +#endif + return (0); + } + +#ifdef USE_32BIT_DRIVERS + /* + * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf' + * set in it's probe handler), initialise near-memory ring-buffer for + * the 32-bit device. + */ + if (dev->copy_rx_buf == NULL) + { + dev->get_rx_buf = get_rxbuf; + dev->peek_rx_buf = peek_rxbuf; + dev->release_rx_buf = release_rxbuf; + pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool); + } +#endif + return (1); +} + +#ifdef USE_32BIT_DRIVERS +static void init_32bit (void) +{ + static int init_pci = 0; + + if (!_printk_file) + _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */ + + if (!init_pci) + (void)pci_init(); /* init BIOS32+PCI interface */ + init_pci = 1; +} +#endif + + +/* + * Hook functions for using Watt-32 together with pcap + */ +static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */ +static WORD etype; +static pcap_t pcap_save; + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf) +{ + /* Fix me: assumes Ethernet II only */ + struct ether_header *ep = (struct ether_header*) buf; + + memcpy (rxbuf, buf, pcap->caplen); + etype = ep->ether_type; + ARGSUSED (dummy); +} + +#if (WATTCP_VER >= 0x0224) +/* + * This function is used by Watt-32 to poll for a packet. + * i.e. it's set to bypass _eth_arrived() + */ +static void *pcap_recv_hook (WORD *type) +{ + int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL); + + if (len < 0) + return (NULL); + + *type = etype; + return (void*) &rxbuf; +} + +/* + * This function is called by Watt-32 (via _eth_xmit_hook). + * If dbug_init() was called, we should trace packets sent. + */ +static int pcap_xmit_hook (const void *buf, unsigned len) +{ + int rc = 0; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit_hook: "); + + if (active_dev && active_dev->xmit) + if ((*active_dev->xmit) (active_dev, buf, len) > 0) + rc = len; + + if (pcap_pkt_debug > 0) + dbug_write (rc ? "ok\n" : "fail\n"); + return (rc); +} +#endif + +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len) +{ + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev || !dev->xmit) + return (-1); + return (*dev->xmit) (dev, buf, len); +} + +/* + * This function is called by Watt-32 in tcp_post_init(). + * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc. + */ +static void (*prev_post_hook) (void); + +static void pcap_init_hook (void) +{ + _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0; + _w32__do_mask_req = 0; + _w32_dynamic_host = 0; + if (prev_post_hook) + (*prev_post_hook)(); +} + +/* + * Supress PRINT message from Watt-32's sock_init() + */ +static void null_print (void) {} + +/* + * To use features of Watt-32 (netdb functions and socket etc.) + * we must call sock_init(). But we set various hooks to prevent + * using normal PKTDRVR functions in pcpkt.c. This should hopefully + * make Watt-32 and pcap co-operate. + */ +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf) +{ + char *env; + int rc, MTU, has_ip_addr; + int using_pktdrv = 1; + + /* If user called sock_init() first, we need to reinit in + * order to open debug/trace-file properly + */ + if (_watt_is_init) + sock_exit(); + + env = getenv ("PCAP_DEBUG"); + if (env && atoi(env) > 0 && + pcap_pkt_debug < 0) /* if not already set */ + { + dbug_init(); + pcap_pkt_debug = atoi (env); + } + + _watt_do_exit = 0; /* prevent sock_init() calling exit() */ + prev_post_hook = _w32_usr_post_init; + _w32_usr_post_init = pcap_init_hook; + _w32_print_hook = null_print; + + if (dev_name && strncmp(dev_name,"pkt",3)) + using_pktdrv = FALSE; + + rc = sock_init(); + has_ip_addr = (rc != 8); /* IP-address assignment failed */ + + /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we + * just pretend Watt-32 is initialised okay. + * + * !! fix-me: The Watt-32 config isn't done if no pktdrvr + * was found. In that case my_ip_addr + sin_mask + * have default values. Should be taken from another + * ini-file/environment in any case (ref. tcpdump.ini) + */ + _watt_is_init = 1; + + if (!using_pktdrv || !has_ip_addr) /* for now .... */ + { + static const char myip[] = "192.168.0.1"; + static const char mask[] = "255.255.255.0"; + + printf ("Just guessing, using IP %s and netmask %s\n", myip, mask); + my_ip_addr = aton (myip); + _w32_sin_mask = aton (mask); + } + else if (rc && using_pktdrv) + { + sprintf (err_buf, "sock_init() failed, code %d", rc); + return (0); + } + + /* Set recv-hook for peeking in _eth_arrived(). + */ +#if (WATTCP_VER >= 0x0224) + _eth_recv_hook = pcap_recv_hook; + _eth_xmit_hook = pcap_xmit_hook; +#endif + + /* Free the pkt-drvr handle allocated in pkt_init(). + * The above hooks should thus use the handle reopened in open_driver() + */ + if (using_pktdrv) + { + _eth_release(); +/* _eth_is_init = 1; */ /* hack to get Rx/Tx-hooks in Watt-32 working */ + } + + memcpy (&pcap_save, pcap, sizeof(pcap_save)); + MTU = pkt_get_mtu(); + pcap_save.fcode.bf_insns = NULL; + pcap_save.linktype = _eth_get_hwtype (NULL, NULL); + pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */ + +#if 1 + /* prevent use of resolve() and resolve_ip() + */ + last_nameserver = 0; +#endif + return (1); +} + +int EISA_bus = 0; /* Where is natural place for this? */ + +/* + * Application config hooks to set various driver parameters. + */ + +static struct config_table debug_tab[] = { + { "PKT.DEBUG", ARG_ATOI, &pcap_pkt_debug }, + { "PKT.VECTOR", ARG_ATOX_W, NULL }, + { "NDIS.DEBUG", ARG_ATOI, NULL }, +#ifdef USE_32BIT_DRIVERS + { "3C503.DEBUG", ARG_ATOI, &ei_debug }, + { "3C503.IO_BASE", ARG_ATOX_W, &el2_dev.base_addr }, + { "3C503.MEMORY", ARG_ATOX_W, &el2_dev.mem_start }, + { "3C503.IRQ", ARG_ATOI, &el2_dev.irq }, + { "3C505.DEBUG", ARG_ATOI, NULL }, + { "3C505.BASE", ARG_ATOX_W, NULL }, + { "3C507.DEBUG", ARG_ATOI, NULL }, + { "3C509.DEBUG", ARG_ATOI, &el3_debug }, + { "3C509.ILOOP", ARG_ATOI, &el3_max_loop }, + { "3C529.DEBUG", ARG_ATOI, NULL }, + { "3C575.DEBUG", ARG_ATOI, &debug_3c575 }, + { "3C59X.DEBUG", ARG_ATOI, &vortex_debug }, + { "3C59X.IFACE0", ARG_ATOI, &vortex_options[0] }, + { "3C59X.IFACE1", ARG_ATOI, &vortex_options[1] }, + { "3C59X.IFACE2", ARG_ATOI, &vortex_options[2] }, + { "3C59X.IFACE3", ARG_ATOI, &vortex_options[3] }, + { "3C90X.DEBUG", ARG_ATOX_W, &tc90xbc_debug }, + { "ACCT.DEBUG", ARG_ATOI, ðpk_debug }, + { "CS89.DEBUG", ARG_ATOI, &cs89_debug }, + { "RTL8139.DEBUG", ARG_ATOI, &rtl8139_debug }, + /* { "RTL8139.FDUPLEX", ARG_ATOI, &rtl8139_options }, */ + { "SMC.DEBUG", ARG_ATOI, &ei_debug }, + /* { "E100.DEBUG", ARG_ATOI, &e100_debug }, */ + { "PCI.DEBUG", ARG_ATOI, &pci_debug }, + { "BIOS32.DEBUG", ARG_ATOI, &bios32_debug }, + { "IRQ.DEBUG", ARG_ATOI, &irq_debug }, + { "TIMER.IRQ", ARG_ATOI, &timer_irq }, +#endif + { NULL } + }; + +/* + * pcap_config_hook() is an extension to application's config + * handling. Uses Watt-32's config-table function. + */ +int pcap_config_hook (const char *name, const char *value) +{ + return parse_config_table (debug_tab, NULL, name, value); +} + +/* + * Linked list of supported devices + */ +struct device *active_dev = NULL; /* the device we have opened */ +struct device *probed_dev = NULL; /* the device we have probed */ +const struct device *dev_base = &pkt_dev; /* list of network devices */ + +/* + * PKTDRVR device functions + */ +int pcap_pkt_debug = -1; + +static void pkt_close (struct device *dev) +{ + BOOL okay = PktExitDriver(); + + if (pcap_pkt_debug > 1) + fprintf (stderr, "pkt_close(): %d\n", okay); + + if (dev->priv) + free (dev->priv); + dev->priv = NULL; +} + +static int pkt_open (struct device *dev) +{ + PKT_RX_MODE mode; + + if (dev->flags & IFF_PROMISC) + mode = PDRX_ALL_PACKETS; + else mode = PDRX_BROADCAST; + + if (!PktInitDriver(mode)) + return (0); + + PktResetStatistics (pktInfo.handle); + PktQueueBusy (FALSE); + return (1); +} + +static int pkt_xmit (struct device *dev, const void *buf, int len) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit\n"); + + if (!PktTransmit(buf,len)) + { + stats->tx_errors++; + return (0); + } + return (len); +} + +static void *pkt_stats (struct device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (!stats || !PktSessStatistics(pktInfo.handle)) + return (NULL); + + stats->rx_packets = pktStat.inPackets; + stats->rx_errors = pktStat.lost; + stats->rx_missed_errors = PktRxDropped(); + return (stats); +} + +static int pkt_probe (struct device *dev) +{ + if (!PktSearchDriver()) + return (0); + + dev->open = pkt_open; + dev->xmit = pkt_xmit; + dev->close = pkt_close; + dev->get_stats = pkt_stats; + dev->copy_rx_buf = PktReceive; /* farmem peek and copy routine */ + dev->get_rx_buf = NULL; + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + dev->priv = calloc (sizeof(struct net_device_stats), 1); + if (!dev->priv) + return (0); + return (1); +} + +/* + * NDIS device functions + */ +static void ndis_close (struct device *dev) +{ +#ifdef USE_NDIS2 + NdisShutdown(); +#endif + ARGSUSED (dev); +} + +static int ndis_open (struct device *dev) +{ + int promis = (dev->flags & IFF_PROMISC); + +#ifdef USE_NDIS2 + if (!NdisInit(promis)) + return (0); + return (1); +#else + ARGSUSED (promis); + return (0); +#endif +} + +static void *ndis_stats (struct device *dev) +{ + static struct net_device_stats stats; + + /* to-do */ + ARGSUSED (dev); + return (&stats); +} + +static int ndis_probe (struct device *dev) +{ +#ifdef USE_NDIS2 + if (!NdisOpen()) + return (0); +#endif + + dev->open = ndis_open; + dev->xmit = NULL; + dev->close = ndis_close; + dev->get_stats = ndis_stats; + dev->copy_rx_buf = NULL; /* to-do */ + dev->get_rx_buf = NULL; /* upcall is from rmode driver */ + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + return (0); +} + +/* + * Search & probe for supported 32-bit (pmode) pcap devices + */ +#if defined(USE_32BIT_DRIVERS) + +struct device el2_dev LOCKED_VAR = { + "3c503", + "EtherLink II", + 0, + 0,0,0,0,0,0, + NULL, + el2_probe + }; + +struct device el3_dev LOCKED_VAR = { + "3c509", + "EtherLink III", + 0, + 0,0,0,0,0,0, + &el2_dev, + el3_probe + }; + +struct device tc515_dev LOCKED_VAR = { + "3c515", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &el3_dev, + tc515_probe + }; + +struct device tc59_dev LOCKED_VAR = { + "3c59x", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &tc515_dev, + tc59x_probe + }; + +struct device tc90xbc_dev LOCKED_VAR = { + "3c90x", + "EtherLink 90X", + 0, + 0,0,0,0,0,0, + &tc59_dev, + tc90xbc_probe + }; + +struct device wd_dev LOCKED_VAR = { + "wd", + "Westen Digital", + 0, + 0,0,0,0,0,0, + &tc90xbc_dev, + wd_probe + }; + +struct device ne_dev LOCKED_VAR = { + "ne", + "NEx000", + 0, + 0,0,0,0,0,0, + &wd_dev, + ne_probe + }; + +struct device acct_dev LOCKED_VAR = { + "acct", + "Accton EtherPocket", + 0, + 0,0,0,0,0,0, + &ne_dev, + ethpk_probe + }; + +struct device cs89_dev LOCKED_VAR = { + "cs89", + "Crystal Semiconductor", + 0, + 0,0,0,0,0,0, + &acct_dev, + cs89x0_probe + }; + +struct device rtl8139_dev LOCKED_VAR = { + "rtl8139", + "RealTek PCI", + 0, + 0,0,0,0,0,0, + &cs89_dev, + rtl8139_probe /* dev->probe routine */ + }; + +/* + * Dequeue routine is called by polling. + * NOTE: the queue-element is not copied, only a pointer is + * returned at '*buf' + */ +int peek_rxbuf (BYTE **buf) +{ + struct rx_elem *tail, *head; + + PCAP_ASSERT (pktq_check (&active_dev->queue)); + + DISABLE(); + tail = pktq_out_elem (&active_dev->queue); + head = pktq_in_elem (&active_dev->queue); + ENABLE(); + + if (head != tail) + { + PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2); + + *buf = &tail->data[0]; + return (tail->size); + } + *buf = NULL; + return (0); +} + +/* + * Release buffer we peeked at above. + */ +int release_rxbuf (BYTE *buf) +{ +#ifndef NDEBUG + struct rx_elem *tail = pktq_out_elem (&active_dev->queue); + + PCAP_ASSERT (&tail->data[0] == buf); +#else + ARGSUSED (buf); +#endif + pktq_inc_out (&active_dev->queue); + return (1); +} + +/* + * get_rxbuf() routine (in locked code) is called from IRQ handler + * to request a buffer. Interrupts are disabled and we have a 32kB stack. + */ +BYTE *get_rxbuf (int len) +{ + int idx; + + if (len < ETH_MIN || len > ETH_MAX) + return (NULL); + + idx = pktq_in_index (&active_dev->queue); + +#ifdef DEBUG + { + static int fan_idx LOCKED_VAR = 0; + writew ("-\\|/"[fan_idx++] | (15 << 8), /* white on black colour */ + 0xB8000 + 2*79); /* upper-right corner, 80-col colour screen */ + fan_idx &= 3; + } +/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */ +#endif + + if (idx != active_dev->queue.out_index) + { + struct rx_elem *head = pktq_in_elem (&active_dev->queue); + + head->size = len; + active_dev->queue.in_index = idx; + return (&head->data[0]); + } + + /* !!to-do: drop 25% of the oldest element + */ + pktq_clear (&active_dev->queue); + return (NULL); +} + +/* + * Simple ring-buffer queue handler for reception of packets + * from network driver. + */ +#define PKTQ_MARKER 0xDEADBEEF + +static int pktq_check (struct rx_ringbuf *q) +{ +#ifndef NDEBUG + int i; + char *buf; +#endif + + if (!q || !q->num_elem || !q->buf_start) + return (0); + +#ifndef NDEBUG + buf = q->buf_start; + + for (i = 0; i < q->num_elem; i++) + { + buf += q->elem_size; + if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER) + return (0); + } +#endif + return (1); +} + +static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool) +{ + int i; + + q->elem_size = size; + q->num_elem = num; + q->buf_start = pool; + q->in_index = 0; + q->out_index = 0; + + PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD)); + PCAP_ASSERT (num); + PCAP_ASSERT (pool); + + for (i = 0; i < num; i++) + { +#if 0 + struct rx_elem *elem = (struct rx_elem*) pool; + + /* assert dword aligned elements + */ + PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0); +#endif + pool += size; + *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER; + } + return (1); +} + +/* + * Increment the queue 'out_index' (tail). + * Check for wraps. + */ +static int pktq_inc_out (struct rx_ringbuf *q) +{ + q->out_index++; + if (q->out_index >= q->num_elem) + q->out_index = 0; + return (q->out_index); +} + +/* + * Return the queue's next 'in_index' (head). + * Check for wraps. + */ +static int pktq_in_index (struct rx_ringbuf *q) +{ + volatile int index = q->in_index + 1; + + if (index >= q->num_elem) + index = 0; + return (index); +} + +/* + * Return the queue's head-buffer. + */ +static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index)); +} + +/* + * Return the queue's tail-buffer. + */ +static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index)); +} + +/* + * Clear the queue ring-buffer by setting head=tail. + */ +static void pktq_clear (struct rx_ringbuf *q) +{ + q->in_index = q->out_index; +} + +/* + * Symbols that must be linkable for "gcc -O0" + */ +#undef __IOPORT_H +#undef __DMA_H + +#define extern +#define __inline__ + +#include "msdos/pm_drvr/ioport.h" +#include "msdos/pm_drvr/dma.h" + +#endif /* USE_32BIT_DRIVERS */ + diff --git a/pcap-dos.h b/pcap-dos.h new file mode 100644 index 0000000..f474437 --- /dev/null +++ b/pcap-dos.h @@ -0,0 +1,227 @@ +/* + * Internal details for libpcap on DOS. + * 32-bit targets: djgpp, Pharlap or DOS4GW. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-dos.h,v 1.1 2004-12-18 08:52:10 guy Exp $ (LBL) + */ + +#ifndef __PCAP_DOS_H +#define __PCAP_DOS_H + +#ifdef __DJGPP__ +#include /* simple non-conio kbhit */ +#else +#include +#endif + +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef BYTE ETHER[6]; + +#define ETH_ALEN sizeof(ETHER) /* Ether address length */ +#define ETH_HLEN (2*ETH_ALEN+2) /* Ether header length */ +#define ETH_MTU 1500 +#define ETH_MIN 60 +#define ETH_MAX (ETH_MTU+ETH_HLEN) + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define PHARLAP 1 +#define DJGPP 2 +#define DOS4GW 4 + +#ifdef __DJGPP__ + #undef DOSX + #define DOSX DJGPP +#endif + +#ifdef __WATCOMC__ + #undef DOSX + #define DOSX DOS4GW +#endif + +#ifdef __HIGHC__ + #include + #undef DOSX + #define DOSX PHARLAP + #define inline +#else + typedef unsigned int UINT; +#endif + + +#if defined(__GNUC__) || defined(__HIGHC__) + typedef unsigned long long uint64; + typedef unsigned long long QWORD; +#endif + +#if defined(__WATCOMC__) + typedef unsigned __int64 uint64; + typedef unsigned __int64 QWORD; +#endif + +#define ARGSUSED(x) (void) x + +#if defined (__SMALL__) || defined(__LARGE__) + #define DOSX 0 + +#elif !defined(DOSX) + #error DOSX not defined; 1 = PharLap, 2 = djgpp, 4 = DOS4GW +#endif + +#ifdef __HIGHC__ +#define min(a,b) _min(a,b) +#define max(a,b) _max(a,b) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) < (b) ? (b) : (a)) +#endif + +#if !defined(_U_) && defined(__GNUC__) +#define _U_ __attribute__((unused)) +#endif + +#ifndef _U_ +#define _U_ +#endif + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/lock.h" + + #ifndef RECEIVE_QUEUE_SIZE + #define RECEIVE_QUEUE_SIZE 60 + #endif + + #ifndef RECEIVE_BUF_SIZE + #define RECEIVE_BUF_SIZE (ETH_MAX+20) + #endif + + extern struct device el2_dev LOCKED_VAR; /* 3Com EtherLink II */ + extern struct device el3_dev LOCKED_VAR; /* EtherLink III */ + extern struct device tc59_dev LOCKED_VAR; /* 3Com Vortex Card (?) */ + extern struct device tc515_dev LOCKED_VAR; + extern struct device tc90x_dev LOCKED_VAR; + extern struct device tc90bcx_dev LOCKED_VAR; + extern struct device wd_dev LOCKED_VAR; + extern struct device ne_dev LOCKED_VAR; + extern struct device acct_dev LOCKED_VAR; + extern struct device cs89_dev LOCKED_VAR; + extern struct device rtl8139_dev LOCKED_VAR; + + struct rx_ringbuf { + volatile int in_index; /* queue index head */ + int out_index; /* queue index tail */ + int elem_size; /* size of each element */ + int num_elem; /* number of elements */ + char *buf_start; /* start of buffer pool */ + }; + + struct rx_elem { + DWORD size; /* size copied to this element */ + BYTE data[ETH_MAX+10]; /* add some margin. data[0] should be */ + }; /* dword aligned */ + + extern BYTE *get_rxbuf (int len) LOCKED_FUNC; + extern int peek_rxbuf (BYTE **buf); + extern int release_rxbuf (BYTE *buf); + +#else + #define LOCKED_VAR + #define LOCKED_FUNC + + struct device { + const char *name; + const char *long_name; + DWORD base_addr; /* device I/O address */ + int irq; /* device IRQ number */ + int dma; /* DMA channel */ + DWORD mem_start; /* shared mem start */ + DWORD mem_end; /* shared mem end */ + DWORD rmem_start; /* shmem "recv" start */ + DWORD rmem_end; /* shared "recv" end */ + + struct device *next; /* next device in list */ + + /* interface service routines */ + int (*probe)(struct device *dev); + int (*open) (struct device *dev); + void (*close)(struct device *dev); + int (*xmit) (struct device *dev, const void *buf, int len); + void *(*get_stats)(struct device *dev); + void (*set_multicast_list)(struct device *dev); + + /* driver-to-pcap receive buffer routines */ + int (*copy_rx_buf) (BYTE *buf, int max); /* rx-copy (pktdrvr only) */ + BYTE *(*get_rx_buf) (int len); /* rx-buf fetch/enqueue */ + int (*peek_rx_buf) (BYTE **buf); /* rx-non-copy at queue */ + int (*release_rx_buf) (BYTE *buf); /* release after peek */ + + WORD flags; /* Low-level status flags. */ + void *priv; /* private data */ + }; + + /* + * Network device statistics + */ + typedef struct net_device_stats { + DWORD rx_packets; /* total packets received */ + DWORD tx_packets; /* total packets transmitted */ + DWORD rx_bytes; /* total bytes received */ + DWORD tx_bytes; /* total bytes transmitted */ + DWORD rx_errors; /* bad packets received */ + DWORD tx_errors; /* packet transmit problems */ + DWORD rx_dropped; /* no space in Rx buffers */ + DWORD tx_dropped; /* no space available for Tx */ + DWORD multicast; /* multicast packets received */ + + /* detailed rx_errors: */ + DWORD rx_length_errors; + DWORD rx_over_errors; /* recv'r overrun error */ + DWORD rx_osize_errors; /* recv'r over-size error */ + DWORD rx_crc_errors; /* recv'd pkt with crc error */ + DWORD rx_frame_errors; /* recv'd frame alignment error */ + DWORD rx_fifo_errors; /* recv'r fifo overrun */ + DWORD rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + DWORD tx_aborted_errors; + DWORD tx_carrier_errors; + DWORD tx_fifo_errors; + DWORD tx_heartbeat_errors; + DWORD tx_window_errors; + DWORD tx_collisions; + DWORD tx_jabbers; + } NET_STATS; +#endif + +extern struct device *active_dev LOCKED_VAR; +extern const struct device *dev_base LOCKED_VAR; +extern struct device *probed_dev; + +extern int pcap_pkt_debug; + +extern void _w32_os_yield (void); /* Watt-32's misc.c */ + +#ifdef NDEBUG + #define PCAP_ASSERT(x) ((void)0) + +#else + void pcap_assert (const char *what, const char *file, unsigned line); + + #define PCAP_ASSERT(x) do { \ + if (!(x)) \ + pcap_assert (#x, __FILE__, __LINE__); \ + } while (0) +#endif + +#endif /* __PCAP_DOS_H */ diff --git a/pcap-int.h b/pcap-int.h index 5e1c3f7..2248216 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.67 2004-12-17 20:32:35 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.68 2004-12-18 08:52:10 guy Exp $ (LBL) */ #ifndef pcap_int_h @@ -46,6 +46,11 @@ extern "C" { #include #endif /* WIN32 */ +#ifdef MSDOS +#include +#include +#endif + /* * Savefile */ @@ -116,6 +121,11 @@ struct pcap { int fddipad; #endif +#ifdef MSDOS + int inter_packet_wait; /* offline: wait between packets */ + void (*wait_proc)(void); /* call proc while waiting */ +#endif + struct pcap_sf sf; struct pcap_md md; @@ -259,7 +269,7 @@ extern int vsnprintf (char *, size_t, const char *, va_list ap); /* * Routines that most pcap implementations can use for non-blocking mode. */ -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *, char *); int pcap_setnonblock_fd(pcap_t *p, int, char *); #endif diff --git a/pcap.c b/pcap.c index 80fab60..1ab2edc 100644 --- a/pcap.c +++ b/pcap.c @@ -33,7 +33,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.79 2004-12-17 23:25:36 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.80 2004-12-18 08:52:11 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -49,7 +49,7 @@ static const char rcsid[] _U_ = #include #include #include -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__BORLANDC__) #include #endif #include @@ -59,6 +59,10 @@ static const char rcsid[] _U_ = #include "os-proto.h" #endif +#ifdef MSDOS +#include "pcap-dos.h" +#endif + #include "pcap-int.h" #ifdef HAVE_DAG_API @@ -528,7 +532,7 @@ pcap_fileno(pcap_t *p) #endif } -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) int pcap_get_selectable_fd(pcap_t *p) { @@ -561,7 +565,7 @@ pcap_getnonblock(pcap_t *p, char *errbuf) * We don't look at "p->nonblock", in case somebody tweaked the FD * directly. */ -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *p, char *errbuf) { @@ -586,7 +590,7 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) return p->setnonblock_op(p, nonblock, errbuf); } -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) /* * Set non-blocking mode, under the assumption that it's just the * standard POSIX non-blocking flag. (This can be called by the @@ -629,6 +633,7 @@ pcap_win32strerror(void) DWORD error; static char errbuf[PCAP_ERRBUF_SIZE+1]; int errlen; + char *p; error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, @@ -643,6 +648,8 @@ pcap_win32strerror(void) errbuf[errlen - 1] = '\0'; errbuf[errlen - 2] = '\0'; } + p = strchr(errbuf, '\0'); + snprintf (p, sizeof(errbuf)-(p-errbuf), " (%lu)", error); return (errbuf); } #endif @@ -692,7 +699,7 @@ pcap_close_common(pcap_t *p) { if (p->buffer != NULL) free(p->buffer); -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) if (p->fd >= 0) close(p->fd); #endif @@ -778,7 +785,7 @@ static const char pcap_version_string[] = "libpcap version 0.9[.x]"; * version numbers when building WinPcap. (It'd be nice to do so for * the packet.dll version number as well.) */ -static const char wpcap_version_string[] = "3.0"; +static const char wpcap_version_string[] = "3.1"; static const char pcap_version_string_fmt[] = "WinPcap version %s, based on %s"; static const char pcap_version_string_packet_dll_fmt[] = @@ -833,7 +840,34 @@ pcap_lib_version(void) } return (full_pcap_version_string); } -#else + +#elif defined(MSDOS) + +static char *full_pcap_version_string; + +const char * +pcap_lib_version (void) +{ + char *packet_version_string; + size_t full_pcap_version_string_len; + static char dospfx[] = "DOS-"; + + if (full_pcap_version_string == NULL) { + /* + * Generate the version string. + */ + full_pcap_version_string_len = + sizeof dospfx + strlen(pcap_version_string); + full_pcap_version_string = + malloc(full_pcap_version_string_len); + strcpy(full_pcap_version_string, dospfx); + strcat(full_pcap_version_string, pcap_version_string); + } + return (full_pcap_version_string); +} + +#else /* UN*X */ + const char * pcap_lib_version(void) { diff --git a/pcap.h b/pcap.h index b4fd091..bfa8199 100644 --- a/pcap.h +++ b/pcap.h @@ -31,18 +31,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.51 2004-11-07 21:40:48 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.52 2004-12-18 08:52:11 guy Exp $ (LBL) */ #ifndef lib_pcap_h #define lib_pcap_h -#ifdef WIN32 -#include -#else /* WIN32 */ -#include -#include -#endif /* WIN32 */ +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H #include @@ -140,6 +143,39 @@ struct pcap_stat { #endif /* WIN32 */ }; +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + /* * Item in a list of interfaces. */ @@ -227,7 +263,8 @@ int bpf_validate(struct bpf_insn *f, int len); char *bpf_image(struct bpf_insn *, int); void bpf_dump(struct bpf_program *, int); -#ifdef WIN32 +#if defined(WIN32) + /* * Win32 definitions */ @@ -239,20 +276,31 @@ int pcap_setmintocopy(pcap_t *p, int size); #ifdef WPCAP /* Include file with the wpcap-specific extensions */ #include -#endif +#endif /* WPCAP */ #define MODE_CAPT 0 #define MODE_STAT 1 #define MODE_MON 2 -#else +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + /* * UN*X definitions */ int pcap_get_selectable_fd(pcap_t *); -#endif /* WIN32 */ +#endif /* WIN32/MSDOS/UN*X */ #ifdef __cplusplus } diff --git a/savefile.c b/savefile.c index 89c56ae..f016e83 100644 --- a/savefile.c +++ b/savefile.c @@ -30,7 +30,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.118 2004-12-17 20:26:16 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.119 2004-12-18 08:52:11 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -88,6 +88,19 @@ static const char rcsid[] _U_ = #define SFERR_BADF 3 #define SFERR_EOF 4 /* not really an error, just a status */ +/* + * Setting O_BINARY on DOS/Windows is a bit tricky + */ +#if defined(WIN32) + #define SET_BINMODE(f) _setmode(fileno(f), O_BINARY) +#elif defined(MSDOS) + #if defined(__HIGHC__) + #define SET_BINMODE(f) setmode(f, O_BINARY) + #else + #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) + #endif +#endif + /* * We don't write DLT_* values to the capture file header, because * they're not the same on all platforms. @@ -657,7 +670,7 @@ pcap_open_offline(const char *fname, char *errbuf) if (fname[0] == '-' && fname[1] == '\0') fp = stdin; else { -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) fp = fopen(fname, "r"); #else fp = fopen(fname, "rb"); @@ -816,7 +829,7 @@ pcap_fopen_offline(FILE *fp, char *errbuf) break; } -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) /* * You can do "select()" and "poll()" on plain files on most * platforms, and should be able to do so on pipes. @@ -836,13 +849,13 @@ pcap_fopen_offline(FILE *fp, char *errbuf) p->stats_op = sf_stats; p->close_op = sf_close; -#ifdef WIN32 +#if defined(WIN32) || defined(MSDOS) /* * If we're reading from the standard input, put it in binary * mode, as savefiles are binary files. */ if (fp == stdin) - _setmode(_fileno(f), _O_BINARY); + SET_BINMODE(fp); #endif return (p); @@ -1067,7 +1080,7 @@ static pcap_dumper_t * pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) { -#ifdef WIN32 +#if defined(WIN32) || defined(MSDOS) /* * If we're writing to the standard output, put it in binary * mode, as savefiles are binary files. @@ -1076,7 +1089,7 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) * XXX - why? And why not on the standard output? */ if (f == stdout) - _setmode(_fileno(f), _O_BINARY); + SET_BINMODE(f); else setbuf(f, NULL); #endif @@ -1111,7 +1124,7 @@ pcap_dump_open(pcap_t *p, const char *fname) f = stdout; fname = "standard output"; } else { -#ifndef WIN32 +#if !defined(WIN32) && !defined(MSDOS) f = fopen(fname, "w"); #else f = fopen(fname, "wb");