diff -u --recursive --new-file dosemu0.53.51/ChangeLog dosemu0.53.52/ChangeLog
--- dosemu0.53.51/ChangeLog	Thu Mar 16 21:20:04 1995
+++ dosemu0.53.52/ChangeLog	Fri Mar 17 22:46:38 1995
@@ -1,3 +1,15 @@
+Fri Mar 17	1995
+
+-	Release pre0.53.52
+-	Larry's mods to use HLT code for IRETS
+-	Markky's code to make the timer faster
+-	Scott's latest PIT additions (some probs here)
+-	Added Dong's kernel patch to ./dpmi/kernel.diff
+-	Added back in network code :-(
+-	David's updates for LPT to ./examples/config.dist
+-	Put the internal mouse call on IRQ12.
+-	Some of this and a little of that.
+
 Thr Mar 16	1995
 
 -	Release pre0.53.51
diff -u --recursive --new-file dosemu0.53.51/Makefile dosemu0.53.52/Makefile
--- dosemu0.53.51/Makefile	Thu Mar 16 21:06:12 1995
+++ dosemu0.53.52/Makefile	Fri Mar 17 22:47:00 1995
@@ -68,7 +68,11 @@
 X_SUPPORT  = 1
 X2_SUPPORT = 1
 #the -u forces the X11 shared library to be linked into ./dos
+ifdef ELF
+XLIBS = -Wl,-rpath,$(X11LIBDIR)/elf -lX11
+else
 XLIBS   = -L$(X11LIBDIR) -lX11 -u _XOpenDisplay
+endif
 XDEFS   = -DX_SUPPORT
 endif
 
@@ -84,10 +88,10 @@
 #  The next lines are for testing the new pic code.  You must do a
 #  make clean, make config if you change these lines.
 # Uncomment the next line to try new pic code on keyboard and timer only.
-NEW_PIC = -DNEW_PIC=1
+# NEW_PIC = -DNEW_PIC=1
 # Uncomment the next line to try new pic code on keyboard, timer, and serial.
 # NOTE:  The serial pic code is known to have bugs.
-# NEW_PIC = -DNEW_PIC=2
+NEW_PIC = -DNEW_PIC=2
 ifdef NEW_PIC
 PICOBJS = libpic.a
 export NEW_PIC
@@ -114,7 +118,7 @@
 EMUVER  =   0.53
 export EMUVER
 VERNUM  =   0x53
-PATCHL  =   51
+PATCHL  =   52
 LIBDOSEMU = libdosemu$(EMUVER).$(PATCHL)
 
 # DON'T CHANGE THIS: this makes libdosemu start high enough to be safe. 
@@ -129,7 +133,7 @@
 # IPX = ipxutils
 
 
-# export USING_NET = -DUSING_NET
+export USING_NET = -DUSING_NET
 ifdef USING_NET
 export NET = net
 endif
@@ -494,6 +498,8 @@
 endif
 	@echo "  - Try the ./commands/mouse.exe if your INTERNAL mouse won't work"
 	@echo "  - Try ./commands/unix.exe to run a Unix command under DOSEMU"
+	@echo "  BEWARE: This release breaks certain things like WP so "
+	@echo " 	 Do not E-mail if it does work in pl49 - Thanks " 
 	@echo ""
 
 converthd: hdimage
@@ -542,6 +548,7 @@
 DIRLIST=$(REQUIRED) $(DOCS) $(LIBS) $(SUBDIRS) $(OPTIONALSUBDIRS)
 CLEANDIRS=$(addsuffix .clean, $(DIRLIST))
 REALCLEANDIRS=$(addsuffix .realclean, $(DIRLIST))
+
 clean:: $(CLEANDIRS)
 
 realclean:: $(REALCLEANDIRS)
@@ -557,7 +564,7 @@
 
 
 pristine:	realclean
-	-rm lib/*
+	-rm -f lib/*
 
 # DEPENDS=dos.d emu.d 
 # this is to do make subdir.depend to make a dependency
diff -u --recursive --new-file dosemu0.53.51/Makefile.common dosemu0.53.52/Makefile.common
--- dosemu0.53.51/Makefile.common	Mon Mar 13 18:34:23 1995
+++ dosemu0.53.52/Makefile.common	Fri Mar 17 19:34:41 1995
@@ -32,7 +32,7 @@
 .PHONY:	clean realclean 
 
 clean::
-	rm -f $(OBJS) $(LIB) *~
+	-rm -f $(OBJS) $(LIB) *~
 
 realclean::	clean
 	rm -f *.d
diff -u --recursive --new-file dosemu0.53.51/bios/bios.S dosemu0.53.52/bios/bios.S
--- dosemu0.53.51/bios/bios.S	Sun Mar 12 19:57:28 1995
+++ dosemu0.53.52/bios/bios.S	Fri Mar 17 15:11:58 1995
@@ -491,6 +491,15 @@
 	iret
 
 /* ----------------------------------------------------------------- */   
+/* This hlt address is used to guarantee a return from a real-mode irq */
+/* It uses one byte.  see sigsegv.c */
+	.org	((PIC_SEG-BIOSSEG) << 4)+PIC_OFF
+
+	.globl	CISH(PIC_dummy_start)
+CISH(PIC_dummy_start):
+	hlt
+
+/* ----------------------------------------------------------------- */   
 	.org	((DPMI_SEG-BIOSSEG) << 4)+DPMI_OFF
 
 	.globl	CISH(DPMI_dummy_start)
diff -u --recursive --new-file dosemu0.53.51/dosemu/dosio.c dosemu0.53.52/dosemu/dosio.c
--- dosemu0.53.51/dosemu/dosio.c	Thu Mar 16 20:07:20 1995
+++ dosemu0.53.52/dosemu/dosio.c	Fri Mar 17 20:34:03 1995
@@ -469,7 +469,12 @@
       if (mice->intdrv || mice->type == MOUSE_PS2)
 	if (FD_ISSET(mice->fd, &fds)) {
 		m_printf("MOUSE: We have data\n");
+#ifdef NEW_PIC
+	  pic_request(PIC_IRQ12);
+	  m_printf("MOUSE: PIC will be requesting it\n");
+#else
 	  DOSEMUMouseEvents();
+#endif
 	}
 
       if (FD_ISSET(kbd_fd, &fds)) {
diff -u --recursive --new-file dosemu0.53.51/dosemu/int.c dosemu0.53.52/dosemu/int.c
--- dosemu0.53.51/dosemu/int.c	Thu Mar 16 19:20:12 1995
+++ dosemu0.53.52/dosemu/int.c	Fri Mar 17 20:23:11 1995
@@ -282,7 +282,7 @@
     break;
 #endif
     case 0x80:
-        LWORD(eax) = getcwd(SEG_ADR((char *), es, dx), LWORD(eax));
+        LWORD(eax) = getcwd(SEG_ADR((char *), es, dx), (u_short *)LWORD(eax));
         break;
   case 0x81:
         LWORD(eax) = chdir(SEG_ADR((char *), es, dx));
diff -u --recursive --new-file dosemu0.53.51/dosemu/sigsegv.c dosemu0.53.52/dosemu/sigsegv.c
--- dosemu0.53.51/dosemu/sigsegv.c	Sat Mar 11 08:12:51 1995
+++ dosemu0.53.52/dosemu/sigsegv.c	Fri Mar 17 15:21:37 1995
@@ -294,38 +294,13 @@
     r = cmos_read(port);
     break;
 
-#define COUNTER 2
-#if 1 /*Nov-21-94*/
   case 0x40:
-    r = do_40(1, 0);
-    break;
-  case 0x41:
-    r = do_40(1, 0);
-    break;
-#else
-  case 0x40:
-    pit.CNTR0 -= COUNTER;
-    i_printf("inb [0x40] = 0x%02x  1st timer inb\n", pit.CNTR0);
-    r = pit.CNTR0;
-    break;
   case 0x41:
-    pit.CNTR1 -= COUNTER;
-    i_printf("inb [0x41] = 0x%02x  2nd timer inb\n", pit.CNTR1);
-    r = pit.CNTR1;
-    break;
-#endif
   case 0x42:
-#if 0
-    r = do_42(1, 0);
-    break;
-#else
-    pit.CNTR2 -= COUNTER;
-    i_printf("inb [0x42] = 0x%02x  3rd timer inb\n", pit.CNTR2);
-    r = pit.CNTR2;
+    r = pit_inp(port - 0x40);
     break;
-#endif
   case 0x43:
-    r = safe_port_in_byte(0x43);
+    r = inport_43();
     break;
 
   case 0x3ba:
@@ -584,34 +559,12 @@
     break;
 #endif
   case 0x40:
-	do_40(0, byte);
-	break;
   case 0x41:
-	do_40(0, byte);
-	break;
-  case 0x43:
-#if 1
-        do_43(0, byte);
-        break;
-#else
-        safe_port_out_byte(port,  byte);
-	break;
-#endif
   case 0x42:
-#if 0
-	safe_port_out_byte(port, byte);
-#endif
-    pit.CNTR2 = byte;
-    if ((port == 0x42) && (lastport == 0x42)) {
-      if ((timer_beep == 1) &&
-	  (config.speaker == SPKR_EMULATED)) {
-	putchar('\007');
-	timer_beep = 0;
-      }
-      else {
-	timer_beep = 1;
-      }
-    }
+    pit_outp(port - 0x40, byte);
+    break;
+  case 0x43:
+    outport_43(byte);
     break;
 
   default:
@@ -853,6 +806,12 @@
       LWORD(eip) += 2;		/* skip halt and info byte to point to FAR RET */
       xms_control();
     }
+#ifdef NEW_PIC	
+    else if (lina == (unsigned char *) PIC_ADD) {
+      pic_iret();
+    }
+#endif /* NEW_PIC */
+
 #ifdef DPMI
     else if ((lina >=(unsigned char *)DPMI_ADD) &&
 	(lina <(unsigned char *)(DPMI_ADD+(unsigned long)DPMI_dummy_end-(unsigned long)DPMI_dummy_start)))
diff -u --recursive --new-file dosemu0.53.51/dosemu/timers.c dosemu0.53.52/dosemu/timers.c
--- dosemu0.53.51/dosemu/timers.c	Thu Mar 16 20:07:05 1995
+++ dosemu0.53.52/dosemu/timers.c	Fri Mar 17 22:06:01 1995
@@ -3,8 +3,8 @@
  *
  * Description: Timer emulation for DOSEMU.
  * 
- * Maintainers: Scott Bucholz
- *              J. Lawrence Stephan
+ * Maintainers: J. Lawrence Stephan
+ *              Scott Buchholz
  *
  * This is the timer emulation for DOSEMU.  It emulates the Programmable
  * Interval Timer (PIT), and also handles IRQ0 interrupt events.
@@ -103,40 +103,19 @@
 
 #define CLOCK_TICK_RATE   1193180     /* underlying clock rate in HZ */
 
-static int timer0_read_latch_value = 0;
-static int timer0_read_latch_value_orig = 0;
-static int timer0_latched_value = 0;
-static int timer0_new_value = 0;
-static boolean_t latched_counter_msb = FALSE;
+typedef struct {
+  int            state;
+  int            mode;
+  int            read_latch;
+  int            write_latch;
+  long           cntr;
+  struct timeval time;
+} pit_latch;
 
+static pit_latch pit[3];          /* values of 3 PIT counters */
 static u_long timer_div;          /* used by timer int code */
-static struct timeval clock0;     /* start time of port 0 timer */
 static u_long ticks_accum;        /* For timer_tick function, 100usec ticks */
 
-/*
- * DANG_BEGIN_FUNCTION set_timer_latch0
- *
- * description:
- *  DOS programs latch values into port 0x40 to change the timer interrupt
- *  rate.  This procedure calculates the values to attemp to generate the
- *  requested interrupt rate.
- *
- * DANG_END_FUNCTION
- */
-static void set_timer_latch0(u_long latch_value)
-{
-  ticks_accum   = 0;
-  gettimeofday(&clock0, NULL);
-
-  if (latch_value == 0)
-    latch_value = 0x10000;
-  timer_div     = (latch_value * 10000) / CLOCK_TICK_RATE;
-  if (timer_div == 0)
-    timer_div = 1;
-
-  i_printf("timer_interrupt_rate requested %.3g Hz, granted %.3g Hz\n",
-           CLOCK_TICK_RATE / (double)latch_value, 10000.0 / timer_div);
-}
 
 /*
  * DANG_BEGIN_FUNCTION initialize_timers
@@ -147,9 +126,33 @@
  */
 void initialize_timers(void)
 {
-   set_timer_latch0(0x10000);
+  struct timeval cur_time;
+
+  gettimeofday(&cur_time, NULL);
+
+  pit[0].mode = 3;
+  pit[0].cntr = 0x10000;
+  pit[0].time = cur_time;
+  pit[0].read_latch = 0;
+  pit[0].write_latch = 0;
+
+  pit[1].mode = 2;
+  pit[1].cntr = 18;
+  pit[1].time = cur_time;
+  pit[0].read_latch = 0;
+  pit[1].write_latch = 18;
+
+  pit[2].mode = 0;
+  pit[2].cntr = 0x10000;
+  pit[2].time = cur_time;
+  pit[0].read_latch = 0;
+  pit[2].write_latch = 0;
+
+  ticks_accum   = 0;
+  timer_div     = (pit[0].cntr * 10000) / CLOCK_TICK_RATE;
 }
 
+
 /*
  * DANG_BEGIN_FUNCTION initialize_timers
  *
@@ -175,8 +178,8 @@
   gettimeofday(&tp, NULL);
 
   /* compute the number of 100usecs since we started */
-  time_curr  = (tp.tv_sec - clock0.tv_sec) * 10000;
-  time_curr += (tp.tv_usec - clock0.tv_usec) / 100;
+  time_curr  = (tp.tv_sec - pit[0].time.tv_sec) * 10000;
+  time_curr += (tp.tv_usec - pit[0].time.tv_usec) / 100;
   
   /* Reset old timer value to 0 if time_curr wrapped around back to 0 */
   if (time_curr < time_old) time_old = 0;
@@ -183,27 +186,17 @@
   
   /* Compute number of 100usec ticks since the last time this function ran */
   ticks_accum += (time_curr - time_old);
-  pit.CNTR2 -= ticks_accum;
   
   /* Save old value of the timer */
   time_old = time_curr;
 
-  /* Add any missing timer events to the queue */
-  while (ticks_accum > timer_div) {
-    ticks_accum -= timer_div;
-    /* h_printf("starting timer int 8...\n"); */ /* Slows down game testing */
-#ifndef NEW_PIC
-    if (!do_hard_int(8)) h_printf("CAN'T DO TIMER INT 8...IF CLEAR\n");
-#else
-#if NEW_PIC==2
-    /* This line will be obsolete with the new serial PIC coming soon */
+  timer_int_engine();
+  #if NEW_PIC==2 /* Will be obsolete with new serial PIC soon */
     age_transmit_queues();
-#endif
-    pic_request(PIC_IRQ0);
-#endif
-  }
+  #endif
 }
 
+
 void set_ticks(unsigned long new)
 {
   unsigned long *ticks = BIOS_TICK_ADDR;
@@ -216,121 +209,213 @@
   /* warn("TIMER: update value of %d\n", (40 / (1000000 / UPDATE))); */
 }
 
-int do_40(boolean_t in_out, int val)
+
+static void latch(int latch)
 {
-  int ret;
+  struct timeval cur_time;
+  u_long         ticks;
 
-  if (in_out) {  /* true => in, false => out */
-    if (timer0_latched_value == 0) {
-      timer0_latched_value = timer_div*850;
-    }
-    switch (timer0_read_latch_value) {
-      case 0x30:
-        ret = timer0_latched_value&0xf;
-	timer0_read_latch_value = 0x20;
-	break;
-      case 0x10:
-	ret = timer0_latched_value&0xf;
-	timer0_read_latch_value = 0x0;
-	break;
-      case 0x20:
-	ret = (timer0_latched_value&0xf0)>>8;
-	timer0_read_latch_value = 0x0;
-	timer0_latched_value = 0;
-	break;
-      case 0x0:
-	if (!latched_counter_msb) {
-	  struct timeval tp;
-	  u_long count;
-	  gettimeofday(&tp, NULL);
-
-	  count = (tp.tv_sec - clock0.tv_sec) * CLOCK_TICK_RATE +
-	          ((tp.tv_usec - clock0.tv_usec) * 1193) / 1000;
-
-	  timer0_latched_value = 0x10000 - count;
-
-	  ret = timer0_latched_value & 0xff;
-	} else {
-	  ret = (timer0_latched_value >> 8) & 0xff;
-	  timer0_latched_value = 0;
-	}
-	latched_counter_msb = !latched_counter_msb;
-	break;
+  gettimeofday(&cur_time, NULL);
+    
+  /* get the number of clock ticks since the start of the timer */
+  
+  ticks = (cur_time.tv_sec - pit[latch].time.tv_sec) * CLOCK_TICK_RATE +
+          ((cur_time.tv_usec - pit[latch].time.tv_usec) * 1193) / 1000;
+  
+  switch (pit[latch].mode) {
+    case 0x00:  /* mode 0   -- countdown, interrupt, wait*/
+    case 0x01:  /* mode 1   -- countdown, wait */
+    case 0x04:  /* mode 4   -- countdown, wait */
+    case 0x05:  /* mode 5   -- countdown, wait */
+      if (pit[latch].cntr == -1 || ticks > pit[latch].cntr) {
+	pit[latch].cntr = -1;
+	pit[latch].read_latch = 0;
+      } else {
+	pit[latch].read_latch = pit[latch].cntr - ticks;
       }
-    i_printf("PORT: do_40, in = 0x%x\n",ret);
-  } else {
-    switch (timer0_read_latch_value) {
-      case 0x0:
-      case 0x30:
-        timer0_new_value = val;
-	timer0_read_latch_value = 0x20;
-	break;
-      case 0x10:
-	timer0_new_value = val;
-	timer0_read_latch_value = 0x0;
-	break;
-      case 0x20:
-	timer0_new_value |= (val<<8);
-	timer0_read_latch_value = 0x0;
-	break;
+      break;
+
+    case 0x02:  /* mode 2,6 -- countdown, reload */
+    case 0x06:
+    case 0x03:  /* mode 3,7 -- countdown by 2(?), interrupt, reload */
+    case 0x07:
+      pit[latch].read_latch = pit[latch].cntr - (ticks % pit[latch].cntr);
+      break;
+    }
+}
+
+
+int pit_inp(int port)
+{
+  int ret = 0;
+
+  if (port == 1)
+    i_printf("PORT:  someone is reading the CMOS refresh time?!?");
+
+  switch (pit[port].state) {
+    case 0: /* latch & read */
+      latch(port);
+    case 3: /* read LSB followed by MSB */
+      ret = (pit[port].read_latch & 0xff);
+      pit[port].state = 1;
+      break;
+    case 1: /* read MSB */
+      ret = (pit[port].read_latch >> 8) & 0xff;
+      pit[port].state = 0;
+      break;
+    case 2: /* read LSB */
+      ret = (pit[port].read_latch & 0xff);
+      pit[port].state = 0;
+      break;
+  }
+  i_printf("PORT: inport_%x, in = 0x%x\n", port+0x40, ret);
+  return ret;
+}
+
+
+void pit_outp(int port, int val)
+{
+  static int timer_beep;
+
+  if (port == 1)
+    i_printf("PORT:  someone is writing the CMOS refresh time?!?");
+
+  /* someone should check this code!!! */
+  if (port == 2) {
+    if (config.speaker == SPKR_NATIVE) {
+      safe_port_out_byte(0x42, val);
+      i_printf("PORT: Really do_42\n");
+    } else if (config.speaker == SPKR_EMULATED) {
+      if (timer_beep) {
+	putchar('\007');
+	timer_beep = 0;
+      } else {
+	timer_beep = 1;
       }
-    i_printf("PORT: do_40, out = 0x%x\n",val);
-    if (timer0_read_latch_value == 0)
-      set_timer_latch0(timer0_new_value);
+    }
+  }
+
+  switch (pit[port].state) {
+    case 0:
+    case 3:
+      pit[port].write_latch = val;
+      pit[port].state = 2;
+      break;
+    case 1:
+      pit[port].write_latch = (pit[port].write_latch & 0xff00) | (val&0xff);
+      pit[port].state = 0;
+      break;
+    case 2:
+      pit[port].write_latch = (pit[port].write_latch & 0xff) | (val << 8);
+      pit[port].state = 0;
+      break;
+    }
+  i_printf("PORT: outport_%x = 0x%x\n", port+0x40, val);
+
+  if (pit[port].state == 0) {
+    if (pit[port].write_latch == 0)
+      pit[port].cntr = 0x10000;
+    else
+      pit[port].cntr = pit[port].write_latch;
+
+    gettimeofday(&pit[port].time, NULL);
+
+    if (port == 0) {
+      ticks_accum   = 0;
+      timer_div     = (pit[0].cntr * 10000) / CLOCK_TICK_RATE;
+      if (timer_div == 0)
+	timer_div = 1;
+
+      i_printf("timer_interrupt_rate requested %.3g Hz, granted %.3g Hz\n",
+	       CLOCK_TICK_RATE/(double)pit[0].cntr, 10000.0/timer_div);
+    }
   }
-  return(ret);
 }
 
-#if 0
-/* return value of port -- what happens when output?  Stack trash? */
-int do_42(in_out, val)
-	boolean_t in_out;
-	int val;
+
+int inport_43()
 {
-	int ret;
-	if (in_out) {  /* true => in, false => out */
-		ioperm(0x42,1,1);
-		ret = port_in(0x42);
-		ioperm(0x42,1,0);
-		i_printf( "PORT: do_42, in = 0x%x\n",ret);
-	} else {
-		ioperm(0x42,1,1);
-		port_out(val, 0x42);
-		ioperm(0x42,1,0);
-		i_printf( "PORT: do_42, out = 0x%x\n",val);
-	}
-	return(ret);
+  return safe_port_in_byte(0x43);
 }
 
-#endif
 
-int do_43(boolean_t in_out, int val)
+void outport_43(int val)
 {
-  int ret;
-	
-  if (in_out) {  /* true => in, false => out */
-    i_printf( "PORT: do_43, in = 0x%x\n",ret);
-  } else {
-    i_printf( "PORT: do_43, out = 0x%x\n",val);
-    switch(val>>6) {
+  int mode, latch, state;
+
+  i_printf("PORT: outport_43 = 0x%x\n",val);
+
+  mode  = (val >> 1) & 0x07;
+  state = (val >> 4) & 0x03;
+  latch = (val >> 6) & 0x03;
+
+  switch (latch) {
     case 0:
-      timer0_read_latch_value = (val&0x30);
-      timer0_read_latch_value_orig = (val&0x30);
-      if (timer0_read_latch_value == 0) {
-	latched_counter_msb = FALSE;
-      }
+    case 1:
+      pit[latch].state = state;
+      pit[latch].mode  = mode;
       break;
     case 2:
-#if 0
-      ioperm(0x43,1,1);
-      port_out(val, 0x43);
-      ioperm(0x43,1,0);
-#else
+      pit[latch].mode = mode;
+      pit[latch].state = state;
+      if (config.speaker == SPKR_NATIVE) {
+        safe_port_out_byte(0x43, val);
+        i_printf("PORT: Really do_43\n");
+      }
+      break;
+    case 3:
       safe_port_out_byte(0x43, val);
-#endif
-      i_printf( "PORT: Really do_43\n");
+      i_printf("PORT: Really do_43\n");
       break;
+  }
+}
+
+
+/* DANG_BEGIN_FUNCTION timer_int_engine
+ *
+ * This is experimental TIMER-IRQ CHAIN code!
+ * This is a function to determine whether it is time to invoke a
+ * new timer irq 0 event.  Normally it is 18 times a second, but
+ * many video games set it to 100 times per second or more.  Since
+ * the kernel cannot keep an accurate timer interrupt, the job of this
+ * routine is to perform a chained timer irq 0 right after the previous
+ * timer irq 0.  This routine should, ideally, be called right after
+ * the end of a timer irq, if possible.
+ *
+ * This would speed up high frequency timer interrupts if this code
+ * can be converted into an assembly macro equivalent!
+ *
+ * DANG_END_FUNCTION
+ */
+void timer_int_engine(void)
+{
+  static continuous = 0;
+
+  if (ticks_accum < timer_div)
+    continuous = 0;                     /* Reset overflow guard */
+  else {
+
+    /* Overflow guard so that there is no more than 50 irqs in a chain */
+    continuous++;
+    
+    if (continuous > 50) 
+      continuous = 0;                   /* Reset overflow guard */
+    else {
+      #ifdef NEW_PIC
+        pic_request(PIC_IRQ0);            /* Start a timer irq */
+      #else
+        if (!do_hard_int(8)) h_printf("CAN'T DO TIMER INT 8...IF CLEAR\n");
+      #endif
     }
+
+    /* Decrement the ticks accumulator */
+    ticks_accum -= timer_div;
+    
+    /* Prevent more than 250 ms of extra timer ticks from building up.
+     * This ensures that if timer_int_engine get called less frequently
+     * than every 250ms, the code won't choke on an overload of timer 
+     * interrupts.
+     */
+    if (ticks_accum > 250) ticks_accum -= 250;
   }
-  return(ret);
 }
diff -u --recursive --new-file dosemu0.53.51/examples/config.dist dosemu0.53.52/examples/config.dist
--- dosemu0.53.51/examples/config.dist	Thu Mar 16 21:43:44 1995
+++ dosemu0.53.52/examples/config.dist	Fri Mar 17 22:47:40 1995
@@ -486,7 +486,38 @@
 #    command such as "lpr".  Don't bother fiddling with this configuration
 #    until you've got DOSEMU up and running already.
 #
+#    NOTE: Printers are assigned to LPT1:, LPT2:, and LPT3: on a one for
+#    one basis with each line below.  The first printer line is assigned
+#    to LPT1:, second to LPT2:, and third to LPT3:.  If you do not specify
+#    a base port, the emulator will setup the bios to report 0x378, 0x278,
+#    and 0x3bc for LPT1:, LPT2:, and LPT3: respectively.
+#
+#    To use standard unix lpr command for printing use this line:
+#
 #printer { options "%s"  command "lpr"  timeout 20 }
+#
+#    And for any special options like using pr to format files,
+#    add it to the options parameter:
+#
 #printer { options "-p %s"  command "lpr"  timeout 10 }    # pr format it
+#
+#    To just have your printer output end up in a file, use the following line:
+#
 #printer { file "lpt3" }
+#
+#    If you have a DOS application that is looking to access the printer
+#    port directly, and uses the bios LPT: setting to find out the port to use, 
+#    you can modify the base port the bios will report with the following:
+#
+#printer { options "%s"  command "lpr"  base 0x3bc }
+#
+#    Be sure to also add a port line to allow the application access to
+#    the port:
+#
+#ports { 0x3bc 0x3bd 0x3be }
+#
+#    NOTE: applications that require this will not interfere with applications
+#    that continue to use the standard bios calls.  These applications will
+#    continue to send the output piped to the file or unix command.
+#
 
diff -u --recursive --new-file dosemu0.53.51/include/memory.h dosemu0.53.52/include/memory.h
--- dosemu0.53.51/include/memory.h	Thu Mar 16 21:43:37 1995
+++ dosemu0.53.52/include/memory.h	Fri Mar 17 22:47:35 1995
@@ -88,9 +88,9 @@
 #define INTE7_OFF	0x4500
 #define INTE7_ADD	((INTE7_SEG << 4) + INTE7_OFF)
 
-#define INTE8_SEG       (BIOSSEG)
-#define INTE8_OFF       0xe80
-#define INTE8_ADD       ((INTE8_SEG << 4) + INTE8_OFF)
+#define PIC_SEG       (BIOSSEG + 0x100)
+#define PIC_OFF       0x47f0
+#define PIC_ADD       ((PIC_SEG << 4) + PIC_OFF)
 
 #define DPMI_SEG	(BIOSSEG + 0x100)
 #define DPMI_OFF	0x4800		/* need at least 512 bytes */
diff -u --recursive --new-file dosemu0.53.51/include/mouse.h dosemu0.53.52/include/mouse.h
--- dosemu0.53.51/include/mouse.h	Thu Mar 16 21:43:37 1995
+++ dosemu0.53.52/include/mouse.h	Fri Mar 17 22:47:35 1995
@@ -131,6 +131,8 @@
 extern void mouse_mb(void);
 extern void mouse_rb(void);
 
+extern void DOSEMUMouseEvents(void);
+
 extern void mouse_event(void);
 
 #endif /* MOUSE_H */
diff -u --recursive --new-file dosemu0.53.51/include/pic.h dosemu0.53.52/include/pic.h
--- dosemu0.53.51/include/pic.h	Thu Mar 16 21:43:37 1995
+++ dosemu0.53.52/include/pic.h	Fri Mar 17 22:47:35 1995
@@ -94,7 +94,6 @@
 void pic_request(int inum);                            /* interrupt trigger */
 void pic_creq(int inum);                   /* conditional interrupt trigger */
 void pic_iret();                             /* interrupt completion notify */
-void pic_return();			     /* interrupt completion notify */
 void pic_watch();		       /* interrupt pendiong watchdog timer */
 void do_irq0();						 /* timer interrupt */
 
@@ -104,3 +103,6 @@
 #define pic_sti() pic_iflag=0;pic_set_mask          /*    emulate STI      */
 #define pic_cli() pic_iflag=PIC_IRQALL;pic_set_mask /*    emulate CLI      */
 #endif
+
+/* Experimental TIMER-IRQ CHAIN code */
+extern void timer_int_engine(void);
diff -u --recursive --new-file dosemu0.53.51/include/timers.h dosemu0.53.52/include/timers.h
--- dosemu0.53.51/include/timers.h	Thu Mar 16 21:43:37 1995
+++ dosemu0.53.52/include/timers.h	Fri Mar 17 22:47:35 1995
@@ -5,23 +5,12 @@
 
 #define TIMER_DIVISOR   3
 
-/* Programmable Interval Timer, 8253/8254 */
-/* ports 0x40 - 0x43 */
-struct pit {
-  unsigned short
-   CNTR0,			/* 0x40, time of day clock (usu/ mode 3) */
-   CNTR1,			/* 0x41, RAM refresh cntr (usu. mode 2) */
-   CNTR2,			/* 0x42, cassette/spkr */
-   MCR;				/* 0x43, mode control register */
-  unsigned char
-   s0,				/* states */
-   s1, s2, sm;
-  unsigned long update, freq;
-};
-
-EXTERN struct pit pit;
-
-void timer_tick(void), set_ticks(unsigned long);
+extern void timer_tick(void);
+extern void set_ticks(unsigned long);
+extern int  pit_inp(int);
+extern void pit_outp(int, int);
+extern int  inport_43();
+extern void outport_43(int);
 
 #define BIOS_TICK_ADDR		(void *)0x46c
 #define TICK_OVERFLOW_ADDR	(void *)0x470
diff -u --recursive --new-file dosemu0.53.51/init/config.c dosemu0.53.52/init/config.c
--- dosemu0.53.51/init/config.c	Thu Mar 16 18:09:18 1995
+++ dosemu0.53.52/init/config.c	Fri Mar 17 15:17:28 1995
@@ -393,7 +393,28 @@
   if (config.X) {
     config.console_video = config.vga = config.graphics = 0;
   }
+
+  check_for_env_autoexec_or_config();
 }
+
+
+static void check_for_env_autoexec_or_config(void)
+{
+      char *cp;
+      cp = getenv("AUTOEXEC");
+      if(cp)
+              config.emubat = cp;
+      cp = getenv("CONFIG");
+      if(cp)
+              config.emusys = cp;
+
+
+      if(config.emubat)
+              fprintf(stderr, "autoexec extension = %s\n", config.emubat);
+      if(config.emusys)
+              fprintf(stderr, "config extension = %s\n", config.emusys);
+
+} 
 
 /* 
  * DANG_BEGIN_FUNCTION parse_debugflags
diff -u --recursive --new-file dosemu0.53.51/init/init.c dosemu0.53.52/init/init.c
--- dosemu0.53.51/init/init.c	Thu Mar 16 20:06:47 1995
+++ dosemu0.53.52/init/init.c	Fri Mar 17 20:17:24 1995
@@ -181,6 +181,10 @@
   pic_unmaski(PIC_IRQ0);
   pic_seti(PIC_IRQ1, do_irq1, 0); /* do_irq1 in dosio.c   */
   pic_unmaski(PIC_IRQ1);
+  if (mice->intdrv || mice->type == MOUSE_PS2) {
+    pic_seti(PIC_IRQ12, DOSEMUMouseEvents, 0);
+    pic_unmaski(PIC_IRQ12);
+  }
 #else 
   for (i = 0; i < 2; i++) {
     pics[i].OCW1 = 0;		/* no IRQ's serviced */
diff -u --recursive --new-file dosemu0.53.51/init/lexer.l dosemu0.53.52/init/lexer.l
--- dosemu0.53.51/init/lexer.l	Mon Mar 13 18:34:23 1995
+++ dosemu0.53.52/init/lexer.l	Fri Mar 17 15:18:25 1995
@@ -267,7 +267,9 @@
 \'[^\']*\'		{ yytext[strlen(yytext)-1] = '\0';
 			  yylval->s_value = strdup(&yytext[1]);
 			  return(STRING); }
-[a-z0-9/\~@$-_\+=:,\.]+ { yylval->s_value = strdup(yytext);
+[a-z0-9/\~@-_\+=:,\.]+  { yylval->s_value = strdup(yytext);
+			  return(STRING); }
+$[a-z0-9/\~@-_\+=:,\.]+ { yylval->s_value = strdup(getenv(&yytext[1]));
 			  return(STRING); }
 
 	/* comments & whitespace */
diff -u --recursive --new-file dosemu0.53.51/init/parser.y dosemu0.53.52/init/parser.y
--- dosemu0.53.51/init/parser.y	Thu Mar 16 17:46:26 1995
+++ dosemu0.53.52/init/parser.y	Fri Mar 17 15:18:25 1995
@@ -72,11 +72,14 @@
 static void start_mouse(void);
 static void stop_mouse(void);
 static void start_debug(void);
+static void start_video(void);
 static void stop_video(void);
 static void start_serial(void);
 static void stop_serial(void);
 static void start_printer(void);
 static void stop_printer(void);
+static void start_keyboard(void);
+static void start_terminal(void);
 static void stop_terminal(void);
 static void start_disk(void);
 static void do_part(char *);
@@ -252,18 +255,24 @@
 		| PKTDRIVER NOVELLHACK	{ config.pktflags = 1; }
 		| SPEAKER speaker
 		    {
-		    if ($2 == SPKR_NATIVE) {
-                      yywarn("allowing access to the speaker ports!");
-		      allow_io(0x42, 1, IO_RDWR, 0, 0xFFFF);
-		      allow_io(0x61, 1, IO_RDWR, 0, 0xFFFF);
-		      }
-		    else
-                      c_printf("CONF: not allowing speaker port access\n");
-		    config.speaker = $2;
-		    }
-		| VIDEO	'{' video_flags '}'
+		    if ($2 != config.speaker) {
+		      if ($2 == SPKR_NATIVE) {
+                        yywarn("allowing access to the speaker ports!");
+		        allow_io(0x42, 1, IO_RDWR, 0, 0xFFFF);
+		        allow_io(0x61, 1, IO_RDWR, 0, 0xFFFF);
+		        }
+		      else
+                        c_printf("CONF: not allowing speaker port access\n");
+		      config.speaker = $2;
+                      }
+		    }
+		| VIDEO
+		    { start_video(); }
+		  '{' video_flags '}'
 		    { stop_video(); }
-		| TERMINAL '{' term_flags '}'
+		| TERMINAL
+		    { start_terminal(); }
+                  '{' term_flags '}'
 		    { stop_terminal(); }
 		| DEBUG
 		    { start_debug(); }
@@ -275,8 +284,10 @@
 		| SERIAL
 		    { start_serial(); }
 		  '{' serial_flags '}'
-		  { stop_serial(); }
-		| KEYBOARD '{' keyboard_flags '}'
+		    { stop_serial(); }
+		| KEYBOARD
+		    { start_keyboard(); }
+	          '{' keyboard_flags '}'
 		| PORTS
 		    { start_ports(); }
 		  '{' port_flags '}'
@@ -563,6 +574,8 @@
 		| OFFSET INTEGER	{ dptr->header = $2; }
 		| DEVICE STRING
 		  {
+                  if (priv_lvl)
+                    yyerror("Can not use DISK/DEVICE in the user config file\n");
 		  if (dptr->dev_name != NULL)
 		    yyerror("Two names for a disk-image file or device given.");
 		  dptr->dev_name = $2;
@@ -583,6 +596,8 @@
 		  }
 		| WHOLEDISK STRING
 		  {
+                  if (priv_lvl)
+                    yyerror("Can not use DISK/WHOLEDISK in the user config file\n");
 		  if (dptr->dev_name != NULL)
 		    yyerror("Two names for a harddisk given.");
 		  dptr->type = HDISK;
@@ -590,6 +605,8 @@
 		  }
 		| L_FLOPPY STRING
 		  {
+                  if (priv_lvl)
+                    yyerror("Can not use DISK/FLOPPY in the user config file\n");
 		  if (dptr->dev_name != NULL)
 		    yyerror("Two names for a floppy-device given.");
 		  dptr->type = FLOPPY;
@@ -597,6 +614,8 @@
 		  }
 		| L_PARTITION STRING INTEGER
 		  {
+                  if (priv_lvl)
+                    yyerror("Can not use DISK/PARTITION in the user config file\n");
                   yywarn("{ partition \"%s\" %d } the"
 			 " token '%d' is ignored and can be removed.",
 			 $2,$3,$3);
@@ -832,6 +851,23 @@
 
 	/* video */
 
+static void start_video(void)
+{
+  config.vbios_file = NULL;
+  config.vbios_copy = 0;
+  config.vbios_seg  = 0xc000;
+  config.vbios_size = 0x10000;
+  config.console_video = 0;
+  config.cardtype = CARD_VGA;
+  config.chipset = PLAINVGA;
+  config.mapped_bios = 0;
+  config.graphics = 0;
+  config.vga = 0;
+  config.gfxmemsize = 256;
+  config.fullrestore = 0;
+  config.dualmon = 1;
+}
+
 static void stop_video(void)
 {
   if ((config.cardtype != CARD_VGA) || !config.console_video) {
@@ -880,8 +916,32 @@
 	   sptr->interrupt);
 }
 
+	/* keyboard */
+
+static void start_keyboard(void)
+{
+  keyb_layout(0);
+  config.console_keyb = 0;
+  config.keybint = 0;
+  config.keyboard = KEYB_US;	/* What's the current keyboard  */
+  config.key_map = key_map_us;	/* pointer to the keyboard-maps */
+  config.shift_map = shift_map_us;	/* Here the Shilt-map           */
+  config.alt_map = alt_map_us;	/* And the Alt-map              */
+  config.num_table = num_table_dot;	/* Numeric keypad has a dot     */
+}
+
 	/* terminal */
 
+static void start_terminal(void)
+{
+  config.term_method = METHOD_FAST;
+  config.term_updatelines = 25;
+  config.term_updatefreq = 2;
+  config.term_charset = CHARSET_LATIN;
+  config.term_color = COLOR_NORMAL;
+  config.term_corner = 1;
+}
+
 static void stop_terminal(void)
 {
   if (config.term_updatefreq > 100) {
@@ -971,9 +1031,6 @@
 
 static void start_disk(void)
 {
-  if (priv_lvl)
-    yyerror("Can not change the disk settings in the user config file\n");
-
   if (c_hdisks >= MAX_HDISKS) 
     {
     yyerror("There are too many hard disks defined");
@@ -995,7 +1052,7 @@
 static void do_part(char *dev)
 {
   if (priv_lvl)
-    yyerror("Can not change disk settings in user config file");
+    yyerror("Can not use DISK/PARTITION in the user config file\n");
 
   if (dptr->dev_name != NULL)
     yyerror("Two names for a partition given.");
diff -u --recursive --new-file dosemu0.53.51/net/Makefile dosemu0.53.52/net/Makefile
--- dosemu0.53.51/net/Makefile
+++ dosemu0.53.52/net/Makefile	Sun Feb 12 18:55:01 1995
@@ -0,0 +1,26 @@
+#
+# This is the Makefile for the net-subdirectory of the DOS-emulator
+# for Linux.
+#
+
+# The following variables may go into the Makfile in the parent-directory
+
+SUBDIR=net
+
+# let gcc do extended checking
+
+
+CFILES = ipx.c ipxglt.c libpacket.c pktnew.c inifile.c
+HFILES =       libpacket.h 
+DEPENDS= $(CFILES:.c=.d)
+OBJS=$(CFILES:.c=.o)
+
+ALL = $(CFILES) $(HFILES) libpacket.c.multi libpacket.c.single \
+	pktnew.c.multi pktnew.c.single README
+
+
+all:  lib
+
+install:
+
+include ../Makefile.common
diff -u --recursive --new-file dosemu0.53.51/net/README dosemu0.53.52/net/README
--- dosemu0.53.51/net/README
+++ dosemu0.53.52/net/README	Thu Nov  3 07:45:30 1994
@@ -0,0 +1,36 @@
+
+-- Added support for multiple type handling. 
+   So it does type demultiplexing within dosemu.
+
+   So we are able to run telbin and pdipx/netx  simultaneously ;-)
+
+-- Changed the code for F_DRIVER_INFO. If the handle is '0', it need not
+   be valid handle (when input to this function).  At least CUTCP simply
+   set this value to zero when it requests for info for the first
+   time. The current code wrongly treated it as valid handle, and
+   returned the class of first registered type.
+
+-- Some things still to be done ...
+    -- Novell Hack is currently diabled. 
+    -- Compare class along with type when a new packet arrives.
+    -- Lots of clean ups required. (I have put in lots of pd_printf's.)
+       Need to be removed even if debug is not used because function
+       call within packet handler is very costly ...
+    -- change all 'dsn0' / 'dosnet' to vnet (i.e. virtual net.) or so. 
+and 
+    -- Use of SIGIO ...
+    -- Special protocol stack to do demultiplexing of types??
+    -- Use of devices instead of the current mechanism of implementing
+       v-net?
+
+NOTE: THERE ARE STILL BUGS.  The dosemu session just hangs. -- 
+      Usually when in CUTCP. (And specially when I open two sessions.)
+      What is strange is, it seems to work fine for some time even when two
+      sessions are opened. 
+      I strongly feel  it is due to new PIC code because it is used
+      heavily by the network code ... (especially in interactive telnet
+      sessions.)
+
+Vinod
+vinod@cse.iitb.ernet.in
+
diff -u --recursive --new-file dosemu0.53.51/net/inifile.c dosemu0.53.52/net/inifile.c
--- dosemu0.53.51/net/inifile.c
+++ dosemu0.53.52/net/inifile.c	Thu Nov  3 07:45:30 1994
@@ -0,0 +1,205 @@
+/* inifile.c */
+
+/* Routines to modify INI files */
+/* by David V. Mortenson */
+
+#include <stdio.h>
+#include <stdlib.h>
+#if 0
+#define __USE_GNU
+#define __USE_SVID
+#endif
+#include <string.h>
+#include <ctype.h>
+
+#define FALSE  0
+#define TRUE   1
+
+#if 0
+extern void GetValueFromIniFile (char *, char *, char *, char *);
+extern void GetValueFromIniFilePath (char *, char *, char *, char *);
+extern void SetValueInIniFile (char *, char *, char *, char *);
+#else
+#include "inifile.h"
+#endif
+
+/****************************************
+ * An ini file should have the extension .INI, and is formatted
+ * with sections and value strings.  The following is a sample
+ * .INI file with 2 sections, each with 1 variable/value string:
+ * 
+ *      [test]
+ *      teststring=Hello World
+ *      [sample]
+ *      value=on
+ *
+ * The use of the functions to retrieve the string values and
+ * set them in the INI file should be apparent.  If an error
+ * occurs, then the value string for the requested section and
+ * variable will return with a length of 0.  Possible errors
+ * include:
+ *      1) file not found
+ *      2) section not found (only for "get" operation)
+ *      3) variable not found (only for "get" operation)
+ *
+ * GetValueFromIniFilePath is the same as GetValueFromIniFile, except
+ * that the file paramter can hold a colon delimited path of locations
+ * to look for the section and variable.  Each one is searched in turn.
+ * This mechanism could be used to allow per-user variables to override
+ * system defaults, for example.
+ ****************************************/
+
+/**********************************************************************DVM***/
+void GetValueFromIniFile (char *file, char *section, char *variable, 
+               char *value)
+{
+   FILE *srcFile;
+   char line [512];
+   char *cptr;
+
+   strcpy (value, "");
+
+   srcFile = fopen (file, "rt");
+
+   cptr = fgets (line, 512, srcFile);
+
+   while (cptr)
+   {
+      /* Is this the requested section? */
+      if (  line[0] == '['  &&  
+            !strncasecmp (&line[1], section, strlen(section))  &&
+            line [strlen(section)+1] == ']'  )
+      {
+         cptr = fgets (line, 512, srcFile);
+         while (cptr)
+         {
+            /* Is this the requested variable? */
+            if (  !strncasecmp (line, variable, strlen (variable))  &&
+                  line [strlen(variable)] == '='  )
+            {
+               strcpy (value, &line[strlen(variable)+1]);
+               if (value[strlen(value)-1] == '\n')
+                  value[strlen(value)-1] = '\0';
+               fclose (srcFile);
+               return;
+            }
+
+            /* Have we entered a new section? */
+            if (line[0] == '[')
+            {
+               break;
+            }
+
+            cptr = fgets (line, 512, srcFile);
+         }
+      }
+      else
+      {
+         cptr = fgets (line, 512, srcFile);
+      }
+   }
+
+   fclose (srcFile);
+}
+
+/**********************************************************************TRB***/
+void GetValueFromIniFilePath (char *file, char *section, char *variable, 
+               char *value)
+{
+        char *filePtr, *lastPtr;
+	int done = FALSE;
+	char *fileString;
+
+			 
+	fileString = (char *)strdup( file );
+	lastPtr = file;        
+	filePtr = strtok( fileString, ":;" );
+	while( filePtr && !done ) {
+		GetValueFromIniFile( filePtr, section, variable, value );
+		if( strlen( value ) ) {
+			done = TRUE;
+		}
+		lastPtr = filePtr;
+		filePtr = strtok( NULL, ":;" );
+	}
+	free( fileString );
+}
+
+	       
+
+/**********************************************************************DVM***/
+void SetValueInIniFile (char *file, char* section, char* variable, 
+               char *value)
+{
+   char oldFile [250];
+   FILE *srcFile, *destFile;
+   char line [512];
+   char *cptr;
+   int operationComplete = FALSE;
+
+   /* Setup The File Path */
+
+   sprintf (oldFile, "%s%s", file, ".bak");
+
+   /* Open The Files */
+
+   remove (oldFile);
+   rename (file, oldFile);
+   srcFile = fopen (oldFile, "rt");
+   destFile = fopen (file, "wt");
+
+   cptr = fgets (line, 512, srcFile);
+   while (cptr)
+   {
+      /* Is this the requested section? */
+      if (  line[0] == '['  &&  
+            !strncasecmp (&line[1], section, strlen(section))  &&
+            line [strlen(section)+1] == ']'  )
+      {
+         fprintf (destFile, "%s", line);
+
+         cptr = fgets (line, 512, srcFile);
+         while (cptr)
+         {
+            /* Is this the requested variable? */
+            if (  !strncasecmp (line, variable, strlen (variable))  &&
+                  line [strlen(variable)] == '='  )
+            {
+               if (!operationComplete)
+                  fprintf (destFile, "%s=%s\n", variable, value);
+               operationComplete = TRUE;
+            }
+            /* Is this a new Section? */
+            else if (line[0] == '[')
+            {
+               if (!operationComplete)
+               {
+                  fprintf (destFile, "%s=%s\n", variable, value);
+                  operationComplete = TRUE;
+               }
+               break;
+            }
+            else
+            {
+               fprintf (destFile, "%s", line);
+            }
+
+            cptr = fgets (line, 512, srcFile);
+         }
+      }
+      else
+      {
+         fprintf (destFile, "%s", line);
+         cptr = fgets (line, 512, srcFile);
+      }
+   }
+
+   if (!operationComplete)
+   {
+      fprintf (destFile, "[%s]\n", section);
+      fprintf (destFile, "%s=%s\n", variable, value);
+   }
+
+   fclose (srcFile);
+   fclose (destFile);
+}
diff -u --recursive --new-file dosemu0.53.51/net/ipx.c dosemu0.53.52/net/ipx.c
--- dosemu0.53.51/net/ipx.c
+++ dosemu0.53.52/net/ipx.c	Sun Feb  5 12:54:06 1995
@@ -0,0 +1,1195 @@
+/* ipx.c for the DOS emulator
+ * 		Tim Bird, tbird@novell.com
+ */
+#include "ipx.h"
+#ifdef IPX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vm86.h>
+#include <linux/sockios.h>
+#include <linux/ipx.h>
+#include <netinet/in.h>
+
+#include "timers.h"
+#include "memory.h"
+#include "emu.h"
+#include "inifile.h"
+
+#define MAX_PACKET_DATA		1500
+
+extern struct vm86_struct vm86s;
+
+/* declare some function prototypes */
+extern u_char IPXCancelEvent(far_t ECBPtr);
+far_t ESRPopRegistersReturn;
+far_t ESRPopRegistersIRet;
+
+static ipx_socket_t *ipx_socket_list = NULL;
+
+/* FIXTHIS - get a real value for my address in here !! */
+static unsigned char MyAddress[10] =
+{0x01, 0x01, 0x00, 0xe0,
+ 0x00, 0x00, 0x1b, 0x33, 0x2b, 0x13};
+
+int 
+GetMyAddress( void )
+{
+  int sock;
+  struct sockaddr_ipx ipxs;
+  struct sockaddr_ipx ipxs2;
+  int len;
+  int i;
+  
+  sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
+  if(sock==-1)
+  {
+    n_printf("IPX: could not open socket in GetMyAddress\n");
+    return(-1);
+  }
+
+  /* bind this socket to network 0 */  
+  ipxs.sipx_family=AF_IPX;
+  ipxs.sipx_network=0;
+  ipxs.sipx_port=0;
+  
+  if(bind(sock,(struct sockaddr *)&ipxs,sizeof(ipxs))==-1)
+  {
+    n_printf("IPX: could bind to network 0 in GetMyAddress\n");
+    close( sock );
+    return(-1);
+  }
+  
+  len = sizeof(ipxs2);
+  if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
+    n_printf("IPX: could not get socket name in GetMyAddress\n");
+    close( sock );
+    return(-1);
+  }
+
+  *((unsigned long *)MyAddress) = ipxs2.sipx_network;
+  for (i = 0; i < 6; i++) {
+    MyAddress[4+i] = ipxs2.sipx_node[i];
+  }
+  n_printf("IPX: using network address %02X%02X%02X%02X\n",
+    MyAddress[0], MyAddress[1], MyAddress[2], MyAddress[3] );
+  n_printf("IPX: using node address of %02X%02X%02X%02X%02X%02X\n",
+    MyAddress[4], MyAddress[5], MyAddress[6], MyAddress[7],
+    MyAddress[8], MyAddress[9] );
+  close( sock );
+  return(0);
+}
+  
+void
+InitIPXFarCallHelper(void)
+{
+  u_char *ptr;
+  char value[40];
+  int addressTemp[6];
+  int numFields;
+  int ccode;
+
+  ccode = GetMyAddress();
+  if( ccode ) {
+    n_printf("IPX: cannot initialize MyAddress\n");
+    n_printf("IPX: trying to read network and node address from DOS.INI\n");
+    
+    /* take some time here to read my address from the DOS.INI file */
+    GetValueFromIniFile( "/etc/dosemu/dos.ini", "ipx", "network", value );
+    if( strlen( value )==0 ) {
+      n_printf("IPX: cannot read IPX network address from dos.ini file\n");
+      n_printf("IPX: please create an [IPX] section in your dos.ini file\n");
+      n_printf("IPX: and add the line NETWORK=xxxxxxxx, where xxxxxxxx\n");
+      n_printf("IPX: is your IPX network number.\n");
+    } else {
+      numFields = sscanf( value, "%2x%2x%2x%2x",
+        &addressTemp[0], &addressTemp[1], &addressTemp[2], &addressTemp[3] );
+      if( numFields != 4 ) {
+        n_printf("IPX: invalid IPX network address read from dos.ini\n");
+        n_printf("IPX: please create an [IPX] section in your dos.ini file\n");
+        n_printf("IPX: and add the line NODE=xxxxxxxxxxxx, where xxxxxxxxxxxx\n");
+        n_printf("IPX: is your IPX node number.\n");
+      } else {
+        MyAddress[0] = addressTemp[0];
+        MyAddress[1] = addressTemp[1];
+        MyAddress[2] = addressTemp[2];
+        MyAddress[3] = addressTemp[3];
+      }
+    }
+    
+    GetValueFromIniFile( "/etc/dosemu/dos.ini", "ipx", "node", value );
+    if( strlen( value )==0 ) {
+      n_printf("IPX: cannot read IPX node address from dos.ini file\n");
+    } else {
+      numFields = sscanf( value, "%2x%2x%2x%2x%2x%2x",
+        &addressTemp[0], &addressTemp[1], &addressTemp[2], &addressTemp[3], 
+        &addressTemp[4], &addressTemp[5] );
+      if( numFields != 6 ) {
+        n_printf("IPX: invalid IPX node address read from dos.ini\n");
+      } else {
+        MyAddress[4] = addressTemp[0];
+        MyAddress[5] = addressTemp[1];
+        MyAddress[6] = addressTemp[2];
+        MyAddress[7] = addressTemp[3];
+        MyAddress[8] = addressTemp[4];
+        MyAddress[9] = addressTemp[5];
+      }
+    }
+  
+    n_printf("IPX: using network address %02X%02X%02X%02X\n",
+      MyAddress[0], MyAddress[1], MyAddress[2], MyAddress[3] );
+    n_printf("IPX: using node address of %02X%02X%02X%02X%02X%02X\n",
+      MyAddress[4], MyAddress[5], MyAddress[6], MyAddress[7],
+      MyAddress[8], MyAddress[6] );
+  }
+   
+#if 0
+  ptr = (u_char *) IPX_ADD;
+  *ptr++ = 0x50;		/* push ax - FarCallHandler removes this before returning */
+  *ptr++ = 0xb0;		/* mov al, 7a */
+  *ptr++ = 0x7a;
+  *ptr++ = 0xcd;		/* int 0xe6 */
+  *ptr++ = 0xe6;
+  *ptr++ = 0xcb;		/* far ret */
+
+  ESRPopRegistersReturn.segment = ((int) ptr) >> 4;
+  ESRPopRegistersReturn.offset = ((int) ptr) & 0xf;
+  *ptr++ = 0x07;		/* pop es, ds, bp, di, si, dx, cx, bx, ax */
+  *ptr++ = 0x1f;
+  *ptr++ = 0x5d;
+  *ptr++ = 0x5f;
+  *ptr++ = 0x5e;
+  *ptr++ = 0x5a;
+  *ptr++ = 0x59;
+  *ptr++ = 0x5b;
+  *ptr++ = 0x58;
+  *ptr++ = 0xcb;		/* far return */
+
+  ESRPopRegistersIRet.segment = ((int) ptr) >> 4;
+  ESRPopRegistersIRet.offset = ((int) ptr) & 0xf;
+  *ptr++ = 0x07;		/* pop es, ds, bp, di, si, dx, cx, bx, ax */
+  *ptr++ = 0x1f;
+  *ptr++ = 0x5d;
+  *ptr++ = 0x5f;
+  *ptr++ = 0x5e;
+  *ptr++ = 0x5a;
+  *ptr++ = 0x59;
+  *ptr++ = 0x5b;
+  *ptr++ = 0x58;
+  *ptr++ = 0xcf;		/* iret */
+#else
+  {
+    extern void bios_f000(), bios_IPX_PopRegistersReturn(), bios_IPX_PopRegistersIRet();
+    long i = (long)bios_IPX_PopRegistersReturn - (long)bios_f000;
+    i += BIOSSEG << 4;
+    ESRPopRegistersReturn.segment = i >> 4;
+    ESRPopRegistersReturn.offset = i & 0xf;
+    i = (long)bios_IPX_PopRegistersIRet - (long)bios_f000;
+    i += BIOSSEG << 4;
+    ESRPopRegistersIRet.segment = i >> 4;
+    ESRPopRegistersIRet.offset = i & 0xf;
+  }
+#endif
+}
+
+/*************************
+ * Check for IPX - int 2f, AH=7A
+ * returns AL=FF
+ * 	ES:DI points to helper routine which gets to FarCallHandler
+ *************************/
+int
+IPXInt2FHandler(void)
+{
+  LO(ax) = 0xff;
+  _regs.edi = IPX_OFF;
+  _regs.es = IPX_SEG;
+  n_printf("IPX: request for IPX far call handler address %lx:%lx\n",
+	   (unsigned long)_regs.es, (unsigned long)_regs.edi);
+  return 1;
+}
+
+static void 
+ipx_remove_socket(ipx_socket_t * sk)
+{
+  ipx_socket_t *s;
+
+  s = ipx_socket_list;
+  if (s == sk) {
+    ipx_socket_list = s->next;
+    free(s);
+    return;
+  }
+  while (s && s->next) {
+    if (s->next == sk) {
+      s->next = sk->next;
+      free(s);
+      return;
+    }
+    s = s->next;
+  }
+}
+
+static void 
+ipx_insert_socket(u_short socket, u_short PSP, int fd)
+{
+  ipx_socket_t *sk;
+
+  sk = (ipx_socket_t *) malloc(sizeof(ipx_socket_t));
+
+  sk->socket = socket;
+  sk->listenList.segment = 0;
+  sk->listenList.offset = 0;
+  sk->listenCount = 0;
+  sk->AESList.segment = 0;
+  sk->AESList.offset = 0;
+  sk->AESCount = 0;
+  sk->PSP = PSP;
+  sk->fd = fd;
+  sk->next = ipx_socket_list;
+  ipx_socket_list = sk;
+}
+
+static ipx_socket_t *
+ipx_find_socket(int port)
+{
+  ipx_socket_t *s;
+
+  s = ipx_socket_list;
+  while (s) {
+    if (s->socket == port) {
+      return (s);
+    }
+    s = s->next;
+  }
+  return (NULL);
+}
+
+u_short
+SwapInt(u_short value)
+{
+  u_short temp;
+
+  temp = (value & 0xff) << 8;
+  return (temp + (value >> 8));
+}
+
+void
+dumpBytes(u_char * memptr, int count)
+{
+  int i, linecounter;
+
+  linecounter = 0;
+  if (count > 64) {
+    /* dumping whole packet takes too long */
+    count = 64;
+  }
+  for (i = 0; i < count; i++) {
+    if (linecounter == 0) {
+      n_printf("%X: ", (int)memptr);
+    }
+    n_printf("%02X ", *memptr++);
+    if (linecounter == 7) {
+      n_printf("-");
+    }
+    linecounter++;
+    if (linecounter == 16) {
+      n_printf("\n");
+      linecounter = 0;
+    }
+  }
+  n_printf("\n");
+}
+
+void
+printECB(ECB_t * ECB)
+{
+  int i;
+   
+  if( d.network ) {
+    n_printf("--DOS ECB (dump)--\n");
+    dumpBytes((u_char *) ECB, 60);
+    n_printf("--DOS ECB--\n");
+    n_printf("Link             %04X:%04X\n", ECB->Link.segment, ECB->Link.offset);
+    n_printf("ESR              %04X:%04X\n", ECB->ESRAddress.segment, ECB->ESRAddress.offset);
+    n_printf("InUseFlag        %02x\n", ECB->InUseFlag);
+    n_printf("CompletionCode   %02x\n", ECB->CompletionCode);
+    n_printf("ECBSocket	     %04x\n", SwapInt(ECB->ECBSocket));
+    n_printf("ImmediateAddress %02X%02X%02X%02X%02X%02X\n",
+      ECB->ImmediateAddress[0],
+      ECB->ImmediateAddress[1],
+      ECB->ImmediateAddress[2],
+      ECB->ImmediateAddress[3],
+      ECB->ImmediateAddress[4],
+      ECB->ImmediateAddress[5]);
+    n_printf("FragmentCount	 %d\n", ECB->FragmentCount);
+    for (i = 0; i < ECB->FragmentCount; i++) {
+      n_printf("Frag[%d].Length   %d\n", i, ECB->FragTable[i].Length);
+      n_printf("Frag[%d].Address	 %04X:%04X\n", i,
+        ECB->FragTable[i].Address.segment,
+        ECB->FragTable[i].Address.offset);
+    }
+  }
+}
+
+void
+printIPXHeader(IPXPacket_t * IPXHeader)
+{
+  if (d.network) {
+    n_printf("--IPX Header (dump)--\n");
+    dumpBytes((u_char *) IPXHeader, 30);
+    n_printf("--IPX Header --\n");
+    n_printf("Checksum         %04X\n", IPXHeader->Checksum);
+    n_printf("Length           %d\n", SwapInt(IPXHeader->Length));
+    n_printf("TransportControl %d\n", IPXHeader->TransportControl);
+    n_printf("PacketType       %d\n", IPXHeader->PacketType);
+    n_printf("Destination      %02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X:%02X%02X\n",
+      IPXHeader->Destination.Network[0],
+      IPXHeader->Destination.Network[1],
+      IPXHeader->Destination.Network[2],
+      IPXHeader->Destination.Network[3],
+      IPXHeader->Destination.Node[0],
+      IPXHeader->Destination.Node[1],
+      IPXHeader->Destination.Node[2],
+      IPXHeader->Destination.Node[3],
+      IPXHeader->Destination.Node[4],
+      IPXHeader->Destination.Node[5],
+      IPXHeader->Destination.Socket[0],
+      IPXHeader->Destination.Socket[1]);
+    n_printf("Source           %02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X:%02X%02X\n",
+      IPXHeader->Source.Network[0],
+      IPXHeader->Source.Network[1],
+      IPXHeader->Source.Network[2],
+      IPXHeader->Source.Network[3],
+      IPXHeader->Source.Node[0],
+      IPXHeader->Source.Node[1],
+      IPXHeader->Source.Node[2],
+      IPXHeader->Source.Node[3],
+      IPXHeader->Source.Node[4],
+      IPXHeader->Source.Node[5],
+      IPXHeader->Source.Socket[0],
+      IPXHeader->Source.Socket[1]);
+  }
+}
+
+u_char
+IPXOpenSocket(u_short port, u_short * newPort)
+{
+  int sock;			/* sock here means Linux socket handle */
+  int opt;
+  struct sockaddr_ipx ipxs;
+  int len;
+  struct sockaddr_ipx ipxs2;
+
+  /* FIXTHIS - do something with longevity flag */
+  port = SwapInt(port);
+  n_printf("IPX: open socket %x\n", port);
+  if (port != 0 && ipx_find_socket(port) != NULL) {
+    n_printf("IPX: socket %x already open.\n", port);
+    /* someone already has this socket open */
+    return (RCODE_SOCKET_ALREADY_OPEN);
+  }
+  /* FIXTHIS - kludge to support broken linux IPX stack */
+  /* need to convert dynamic socket open into a real socket number */
+/*  if (port == 0) {
+    n_printf("IPX: using socket %x\n", nextDynamicSocket);
+    port = nextDynamicSocket++;
+  }
+*/
+  /* do a socket call, then bind to this port */
+  sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
+  if (sock == -1) {
+    n_printf("IPX: could not open IPX socket.\n");
+    /* I can't think of anything else to return */
+    return (RCODE_SOCKET_TABLE_FULL);
+  }
+
+  opt = 1;
+  /* turn on socket debugging */
+  if (d.network) {
+    if (setsockopt(sock, SOL_SOCKET, SO_DEBUG, &opt, sizeof(opt)) == -1) {
+      n_printf("IPX: could not set socket option for debugging.\n");
+      /* I can't think of anything else to return */
+      return (RCODE_SOCKET_TABLE_FULL);
+    }
+  }
+  opt = 1;
+  /* Permit broadcast output */
+  if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
+		 &opt, sizeof(opt)) == -1) {
+    /* I can't think of anything else to return */
+    n_printf("IPX: could not set socket option for broadcast.\n");
+    return (RCODE_SOCKET_TABLE_FULL);
+  }
+  /* allow setting the type field in the IPX header */
+  opt = 1;
+  if (setsockopt(sock, SOL_SOCKET, IPX_TYPE, &opt, sizeof(opt)) == -1) {
+    /* I can't think of anything else to return */
+    n_printf("IPX: could not set socket option for type.\n");
+    return (RCODE_SOCKET_TABLE_FULL);
+  }
+  ipxs.sipx_family = AF_IPX;
+  ipxs.sipx_network = *((unsigned int *)&MyAddress[0]);
+/*  ipxs.sipx_network = htonl(MyNetwork); */
+  ipxs.sipx_port = htons(port);
+
+  /* now bind to this port */
+  if (bind(sock, (struct sockaddr *) &ipxs, sizeof(ipxs)) == -1) {
+    /* I can't think of anything else to return */
+    n_printf("IPX: could not bind socket to address\n");
+    close( sock );
+    return (RCODE_SOCKET_TABLE_FULL);
+  }
+  
+  if( port==0 ) {
+    len = sizeof(ipxs2);
+    if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
+      /* I can't think of anything else to return */
+      n_printf("IPX: could not get socket name in IPXOpenSocket\n");
+      close( sock );
+      return(RCODE_SOCKET_TABLE_FULL);
+    } else {
+      port = htons(ipxs2.sipx_port);
+      n_printf("IPX: opened dynamic socket %04x\n", port);
+    }
+  }
+  
+  /* if we successfully bound to this port, then record it */
+  ipx_insert_socket(port, /* PSP */ 0, sock);
+  n_printf("IPX: successfully opened socket %04x\n", port);
+  *newPort = htons(port);
+  return (RCODE_SUCCESS);
+}
+
+u_char
+IPXCloseSocket(u_short port)
+{
+  ipx_socket_t *mysock;
+  far_t ECBPtr;
+
+  /* see if this socket is actually open */
+  port = SwapInt(port);
+  n_printf("IPX: close socket %x\n", port);
+  mysock = ipx_find_socket(port);
+  if (mysock == NULL) {
+    n_printf("IPX: close of unopened socket\n");
+    return (RCODE_SOCKET_NOT_OPEN);
+  }
+  /* cancel all pending events on this socket */
+  n_printf("IPX: canceling all listen events on socket %x\n", port);
+  ECBPtr = mysock->listenList;
+  while (ECBPtr.segment | ECBPtr.offset) {
+    IPXCancelEvent(ECBPtr);
+    ECBPtr = mysock->listenList;
+  }
+  n_printf("IPX: canceling all AES events on socket %x\n", port);
+  ECBPtr = mysock->AESList;
+  while (ECBPtr.segment | ECBPtr.offset) {
+    IPXCancelEvent(ECBPtr);
+    ECBPtr = mysock->AESList;
+  }
+  /* now close the file descriptor for the socket, and free it */
+  n_printf("IPX: closing file descriptor on socket %x\n", port);
+  close(mysock->fd);
+  ipx_remove_socket(mysock);
+  n_printf("IPX: successfully closed socket %x\n", port);
+  return (RCODE_SUCCESS);
+}
+
+int
+GatherFragmentData(char *buffer, ECB_t * ECB)
+{
+  int i;
+  int nextFragLen, totalDataCount;
+  u_char *bufptr, *memptr;
+
+  totalDataCount = 0;
+  bufptr = buffer;
+  for (i = 0; i < ECB->FragmentCount; i++) {
+    nextFragLen = ECB->FragTable[i].Length;
+    memptr = (u_char *) ((ECB->FragTable[i].Address.segment << 4) +
+			 ECB->FragTable[i].Address.offset);
+    if (i == 0) {
+      /* subtract off IPX header size from first fragment */
+      nextFragLen -= 30;
+      memptr += 30;
+    }
+    if (nextFragLen) {
+      /* FIXTHIS - dumb use of hardcoded 1500 here */
+      if (totalDataCount + nextFragLen > 1500) {
+	return (-1);
+      }
+      memcpy(bufptr, memptr, nextFragLen);
+      bufptr += nextFragLen;
+      totalDataCount += nextFragLen;
+    }
+  }
+  n_printf("IPX: gathered %d fragments for %d bytes of data\n",
+	   ECB->FragmentCount, totalDataCount);
+  if (d.network) {
+    dumpBytes(buffer, totalDataCount);
+  }
+  return (totalDataCount);
+}
+
+void
+PrepareForESR(int iretFlag, ECB_t * ECB, far_t ECBPtr, u_char AXVal)
+{
+  unsigned char *ssp;
+  unsigned long sp;
+
+  ssp = (unsigned char *)(REG(ss)<<4);
+  sp = (unsigned long) LWORD(esp);
+
+  /* push all registers */
+  pushw(ssp, sp, LWORD(eax));
+  pushw(ssp, sp, LWORD(ebx));
+  pushw(ssp, sp, LWORD(ecx));
+  pushw(ssp, sp, LWORD(edx));
+  pushw(ssp, sp, LWORD(esi));
+  pushw(ssp, sp, LWORD(edi));
+  pushw(ssp, sp, LWORD(ebp));
+  pushw(ssp, sp, LWORD(ds));
+  pushw(ssp, sp, LWORD(es));
+
+  /* push far return address for ESRPopRegisters... */
+  if (iretFlag) {
+    pushw(ssp, sp, ESRPopRegistersIRet.segment);
+    pushw(ssp, sp, ESRPopRegistersIRet.offset);
+  }
+  else {
+    pushw(ssp, sp, ESRPopRegistersReturn.segment);
+    pushw(ssp, sp, ESRPopRegistersReturn.offset);
+  }
+
+  LWORD(esp) -= 22;
+  
+  _regs.cs = ECB->ESRAddress.segment;
+  _regs.eip = ECB->ESRAddress.offset;
+  _regs.es = ECBPtr.segment;
+  _regs.esi = ECBPtr.offset;
+  _regs.eax = AXVal;
+
+  n_printf("IPX: setup for ESR address at %04X:%04lX\n",
+	   _regs.cs, _regs.eip);
+  n_printf("IPX: ES:SI = %04X:%04lX, AX = %X\n",
+	   _regs.es, _regs.esi, LWORD(eax));
+}
+
+void
+IPXSendPacket(far_t ECBPtr)
+{
+  ECB_t *ECB;
+  IPXPacket_t *IPXHeader;
+  u_char data[MAX_PACKET_DATA];
+  struct sockaddr_ipx ipxs;
+  int dataLen;
+  ipx_socket_t *mysock;
+
+  ECB = (ECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+  printECB(ECB);
+  dataLen = GatherFragmentData(data, ECB);
+  if (dataLen == -1) {
+    ECB->InUseFlag = IU_ECB_FREE;
+    ECB->CompletionCode = CC_FRAGMENT_ERROR;
+    return;
+  }
+  IPXHeader = (IPXPacket_t *) ((ECB->FragTable[0].Address.segment << 4)
+			       + ECB->FragTable[0].Address.offset);
+  /* for a complete emulation, we need to fill in fields in the */
+  /* send packet header */
+  /* first field is an IPX convention, not really a checksum */
+  IPXHeader->Checksum = 0xffff;
+  IPXHeader->Length = SwapInt(dataLen + 30);	/* in network order */
+  memcpy(&IPXHeader->Source, MyAddress, 10);
+  *(u_short *) & IPXHeader->Source.Socket = ECB->ECBSocket;
+  printIPXHeader(IPXHeader);
+  ipxs.sipx_family = AF_IPX;
+  /* get destination address from IPX packet header */
+  memcpy(&ipxs.sipx_network, IPXHeader->Destination.Network, 4);
+  /* if destination address is 0, then send to my net */
+  if (ipxs.sipx_network == 0) {
+    ipxs.sipx_network = *((unsigned int *)&MyAddress[0]);
+/*  ipxs.sipx_network = htonl(MyNetwork); */
+  }
+  memcpy(&ipxs.sipx_node, IPXHeader->Destination.Node, 6);
+  memcpy(&ipxs.sipx_port, IPXHeader->Destination.Socket, 2);
+  ipxs.sipx_type = 1;
+  /*	ipxs.sipx_port=htons(0x452); */
+  mysock = ipx_find_socket(htons(ECB->ECBSocket));
+  if (mysock == NULL) {
+    /* FIXTHIS - should do a bind, send, close here */
+    /* DOS IPX allows sending on unopened sockets */
+    n_printf("IPX: send to unopened socket %04x\n", htons( ECB->ECBSocket ));
+    return;
+  }
+  if (sendto(mysock->fd, (void *) &data, dataLen, 0,
+	     (struct sockaddr *) &ipxs, sizeof(ipxs)) == -1) {
+    n_printf("IPX: error sending packet\n");
+    ECB->InUseFlag = IU_ECB_FREE;
+    ECB->CompletionCode = CC_HARDWARE_ERROR;
+  }
+  else {
+    ECB->InUseFlag = IU_ECB_FREE;
+    ECB->CompletionCode = CC_SUCCESS;
+    n_printf("IPX: successfully sent packet!\n");
+  }
+  /* now call the ESR for the ECB */
+  /* bit of trickiness here - I will let the ESR, if any, return to */
+  /* the return address from the original far call to IPX, instead of */
+  /* to my helper routine. */
+  if ((ECB->ESRAddress.segment | ECB->ESRAddress.offset) != 0) {
+    PrepareForESR(0 /* not an iret, just a normal return */ ,
+		  ECB, ECBPtr, ESR_CALLOUT_IPX);
+  }
+  return;
+}
+
+u_char
+IPXListenForPacket(far_t ECBPtr)
+{
+  ECB_t *ECB;
+  ipx_socket_t *mysock;
+
+  ECB = (ECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+  printECB(ECB);
+  /* see if the socket is open for this ECB */
+  mysock = ipx_find_socket(htons(ECB->ECBSocket));
+  if (mysock == NULL) {
+    n_printf("IPX: listen on unopened socket\n");
+    ECB->InUseFlag = IU_ECB_FREE;
+    ECB->CompletionCode = CC_SOCKET_NOT_OPEN;
+    return (RCODE_SOCKET_NOT_OPEN);
+  }
+
+  ECB->InUseFlag = IU_ECB_LISTENING;
+  ECB->CompletionCode = CC_SUCCESS;
+  /* now put this ECB on the listen list for this socket */
+  ECB->Link = mysock->listenList;
+  mysock->listenList = ECBPtr;
+  mysock->listenCount++;
+
+  n_printf("IPX: successfully posted listen packet on socket %x!\n",
+	   mysock->socket);
+  return (RCODE_SUCCESS);
+}
+
+u_char
+IPXScheduleEvent(far_t ECBPtr, u_char inUseCode, u_short delayTime)
+{
+  ECB_t *ECB;
+  ipx_socket_t *mysock;
+
+  ECB = (ECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+  printECB(ECB);
+  /* see if the socket is open for this ECB */
+  mysock = ipx_find_socket(htons(ECB->ECBSocket));
+  if (mysock == NULL) {
+    n_printf("IPX: AES event on unopened socket\n");
+    ECB->InUseFlag = IU_ECB_FREE;
+    ECB->CompletionCode = CC_SOCKET_NOT_OPEN;
+    return (RCODE_SOCKET_NOT_OPEN);
+  }
+
+  ECB->InUseFlag = inUseCode;
+  ECB->CompletionCode = CC_SUCCESS;
+  /* now put this ECB on the AES list for this socket */
+  ECB->Link = mysock->AESList;
+  ((AESECB_t *) ECB)->TimeLeft = delayTime;
+  mysock->AESList = ECBPtr;
+  mysock->AESCount++;
+
+  n_printf("IPX: successfully posted AES event on socket %x!\n",
+	   mysock->socket);
+  n_printf("IPX: AES delay time %d!\n", ((AESECB_t *) ECB)->TimeLeft);
+  return (RCODE_SUCCESS);
+}
+
+u_char
+IPXCancelEvent(far_t ECBPtr)
+{
+  ECB_t *ECB;
+  ipx_socket_t *mysock;
+  ECB_t *prevECB;
+  far_t ECBList;
+
+  ECB = (ECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+  /* if it was a listen, cancel it */
+  if (ECB->InUseFlag == IU_ECB_LISTENING ||
+      ECB->InUseFlag == IU_ECB_IPX_WAITING ||
+      ECB->InUseFlag == IU_ECB_AES_WAITING) {
+    /* look up the socket for this ECB */
+    mysock = ipx_find_socket(htons(ECB->ECBSocket));
+    if (mysock == NULL) {
+      n_printf("IPX: cancel on unopened socket\n");
+      ECB->InUseFlag = IU_ECB_FREE;
+      ECB->CompletionCode = CC_SOCKET_NOT_OPEN;
+      return (RCODE_SOCKET_NOT_OPEN);
+    }
+    n_printf("IPX: canceling event on socket %x\n",
+	     mysock->socket);
+    /* now see if this ECB is actually on the list for this socket */
+    if (ECB->InUseFlag == IU_ECB_LISTENING) {
+      /* check the listenList */
+      ECBList = mysock->listenList;
+      n_printf("IPX: cancel a listen event from %d events\n",
+	       mysock->listenCount);
+      prevECB = (ECB_t *) (&mysock->listenList);
+    }
+    else {
+      /* check the AESList */
+      ECBList = mysock->AESList;
+      n_printf("IPX: cancel an AES event from %d events\n",
+	       mysock->AESCount);
+      prevECB = (ECB_t *) (&mysock->AESList);
+    }
+    /* this next cast is somewhat evil.  If the first item on the */
+    /* list is the one removed, then change the head pointer for */
+    /* the list as if it were a ECB.Link field. */
+    n_printf("IPX: scanning ECBList for match\n");
+    while (ECBList.segment | ECBList.offset) {
+      /* see if the list pointer equals the ECB we are canceling */
+      n_printf("IPX: ECBPtr = %x:%x, ECBList = %x:%x\n",
+	       ECBPtr.segment, ECBPtr.offset,
+	       ECBList.segment, ECBList.offset);
+      if (ECBList.segment == ECBPtr.segment &&
+	  ECBList.offset == ECBPtr.offset) {
+	/* remove it from the list */
+	prevECB->Link = ECB->Link;
+	if (ECB->InUseFlag == IU_ECB_LISTENING) {
+	  mysock->listenCount--;
+	}
+	else {
+	  mysock->AESCount--;
+	}
+	ECB->InUseFlag = IU_ECB_FREE;
+	ECB->CompletionCode = CC_EVENT_CANCELED;
+	n_printf("IPX: successfully canceled event!\n");
+	return (RCODE_SUCCESS);
+      }
+      prevECB = (ECB_t *) ((ECBList.segment << 4) + ECBList.offset);
+      ECBList = prevECB->Link;
+    }
+    n_printf("IPX: ECB was not in use.\n");
+    return (RCODE_ECB_NOT_IN_USE);
+  }
+  else {
+    if (ECB->InUseFlag == IU_ECB_FREE) {
+      return (RCODE_ECB_NOT_IN_USE);
+    }
+  }
+  return (RCODE_CANNOT_CANCEL_EVENT);
+}
+
+void
+AESTimerTick(void)
+{
+  ipx_socket_t *mysock;
+  far_t ECBPtr;
+  AESECB_t *ECB;
+  int done;
+
+  /* run through the socket list, and process any pending AES events */
+  mysock = ipx_socket_list;
+  done = 0;
+  while (mysock && !done) {
+    /* see if this socket has any AES events pending */
+    ECBPtr = mysock->AESList;
+    while ((ECBPtr.segment | ECBPtr.offset) && !done) {
+      ECB = (AESECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+      if (ECB->TimeLeft > 0) {
+	ECB->TimeLeft--;
+	n_printf("IPX: AES timer decremented to %d on ECB at %x:%x\n",
+		 ECB->TimeLeft, ECBPtr.segment, ECBPtr.offset);
+      }
+      ECBPtr = ECB->Link;
+    }
+    mysock = mysock->next;
+  }
+}
+
+void
+ipx_fdset(fd_set * set)
+{
+  ipx_socket_t *s;
+
+  s = ipx_socket_list;
+  while (s != NULL) {
+    FD_SET(s->fd, set);
+    s = s->next;
+  }
+}
+
+int
+ScatterFragmentData(int size, char *buffer, ECB_t * ECB,
+		    struct sockaddr_ipx *sipx)
+{
+  int i;
+  int nextFragLen, dataLeftCount;
+  u_char *bufptr, *memptr;
+  IPXPacket_t *IPXHeader;
+
+  n_printf("received data bytes:\n");
+  if (d.network) {
+    dumpBytes(buffer, size);
+  }
+  dataLeftCount = size;
+  bufptr = buffer;
+  if (ECB->FragmentCount < 1 || ECB->FragTable[0].Length < 30) {
+    /* posted listen has a fragment error */
+    n_printf("IPX: listen packet fragment error\n");
+    return (size);
+  }
+  i = 0;
+  while (i < ECB->FragmentCount && dataLeftCount) {
+    nextFragLen = ECB->FragTable[i].Length;
+    memptr = (u_char *) ((ECB->FragTable[i].Address.segment << 4) +
+			 ECB->FragTable[i].Address.offset);
+    n_printf("IPX: filling fragment %d at %x:%x, length %d with %d data left\n",
+	     i, ECB->FragTable[i].Address.segment,
+	     ECB->FragTable[i].Address.offset, nextFragLen,
+	     dataLeftCount);
+    if (i == 0) {
+      /* subtract off IPX header size from first fragment */
+      nextFragLen -= 30;
+      /* also, fill out IPX header */
+      /* use data from sipx to fill out source address */
+      IPXHeader = (IPXPacket_t *) memptr;
+      IPXHeader->Checksum = 0xFFFF;
+      IPXHeader->Length = size + 30;
+      /* FIXTHIS - use real values to fill out IPX header here */
+      IPXHeader->TransportControl = 1;
+      IPXHeader->PacketType = 0;
+      memcpy((u_char *) & IPXHeader->Destination, MyAddress, 10);
+      *((u_short *) &IPXHeader->Destination.Socket) = ECB->ECBSocket;
+      memcpy(IPXHeader->Source.Network, (char *) &sipx->sipx_network, 4);
+      memcpy(IPXHeader->Source.Node, sipx->sipx_node, 6);
+      *((u_short *) &IPXHeader->Source.Socket) = sipx->sipx_port;
+      /* FIXTHIS - kludge for bug in linux IPX stack */
+      /* IPX stack returns data count including IPX header */
+      /*			dataLeftCount -= 30; */
+      memptr += 30;
+    }
+    if (nextFragLen > dataLeftCount) {
+      nextFragLen = dataLeftCount;
+    }
+    if (nextFragLen) {
+      memcpy(memptr, bufptr, nextFragLen);
+      bufptr += nextFragLen;
+      dataLeftCount -= nextFragLen;
+    }
+    i++;
+  }
+  n_printf("IPX: scattered %d fragments, %d bytes left over.\n",
+	   ECB->FragmentCount, dataLeftCount);
+  return (dataLeftCount);
+}
+
+int
+IPXReceivePacket(ipx_socket_t * s)
+{
+  struct sockaddr_ipx ipxs;
+  char buffer[MAX_PACKET_DATA];
+  ECB_t *ECB;
+  far_t ECBPtr;
+  int size, sz;
+  int ESRFired = 0;
+
+  sz = sizeof(ipxs);
+  size = recvfrom(s->fd, buffer, sizeof(buffer), 0,
+		  (struct sockaddr *) &ipxs, &sz);
+  n_printf("IPX: received %d bytes of data\n", size);
+  if (size > 0 && s->listenCount) {
+    ECBPtr = s->listenList;
+    ECB = (ECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+    sz = ScatterFragmentData(size, buffer, ECB, &ipxs);
+    IPXCancelEvent(ECBPtr);
+    /* if there was packet left over, then report a fragment error */
+    if (sz) {
+      ECB->CompletionCode = CC_FRAGMENT_ERROR;
+      /* FIXTHIS - should remove this override, linux IPX kernel */
+      /* stack returns bad sizes, but we ignore this here */
+      ECB->CompletionCode = CC_SUCCESS;
+    }
+    else {
+      ECB->CompletionCode = CC_SUCCESS;
+    }
+    /* now call the ESR for this packet */
+    if ((ECB->ESRAddress.segment | ECB->ESRAddress.offset) != 0) {
+      PrepareForESR(0 /* not an iret, just a normal return */ ,
+		    ECB, ECBPtr, ESR_CALLOUT_IPX);
+      ESRFired = 1;
+    }
+  }
+  return (ESRFired);
+}
+
+int
+IPXCheckForAESReady(void)
+{
+  ipx_socket_t *s;
+  far_t ECBPtr;
+  AESECB_t *ECB;
+  int ESRFired = 0;
+  u_char waitType;
+  u_short rcode;
+
+  s = ipx_socket_list;
+  while (s != NULL && !ESRFired) {
+    if (s->AESCount) {
+      ECBPtr = s->AESList;
+      while ((ECBPtr.segment | ECBPtr.offset) && !ESRFired) {
+	ECB = (AESECB_t *) ((ECBPtr.segment << 4) + ECBPtr.offset);
+	if (ECB->TimeLeft == 0) {
+	  /* FIXTHIS - this architecture currently only supports */
+	  /* firing of one AES event per call */
+	  n_printf("IPX: AES event ready on ECB at %x:%x\n",
+		   ECBPtr.segment, ECBPtr.offset);
+	  printECB((ECB_t *) ECB);
+
+	  /* first, save off the type of event, either AES or IPX */
+	  waitType = ECB->InUseFlag;
+
+	  /* now remove the ECB from the AES list */
+	  rcode = IPXCancelEvent(ECBPtr);
+	  if (rcode == RCODE_SUCCESS) {
+	    ECB->CompletionCode = CC_SUCCESS;
+	  }
+	  /* now setup to call the ESR for this event */
+	  if ((ECB->ESRAddress.segment | ECB->ESRAddress.offset) != 0) {
+	    PrepareForESR(0 /* not an iret, just a normal return */ ,
+			  (ECB_t *) ECB, ECBPtr, ESR_CALLOUT_AES);
+	    ESRFired = 1;
+	  }
+	}
+	ECBPtr = ECB->Link;
+      }
+    }
+    s = s->next;
+  }
+  return (ESRFired);
+}
+
+int
+check_ipx_ready(fd_set * set)
+{
+  ipx_socket_t *s;
+  int ESRFired = 0;
+
+  s = ipx_socket_list;
+  while (s != NULL) {
+    /* FIXTHIS - for now, just pick up one listen per poll, because */
+    /* we can only set up one ESR callout per relinquish */
+    if (FD_ISSET(s->fd, set)) {
+      break;
+    }
+    s = s->next;
+  }
+  if (s != NULL) {
+    ESRFired = IPXReceivePacket(s);
+  }
+  return (ESRFired);
+}
+
+void
+IPXRelinquishControl(void)
+{
+  /* DOS program has given us a time slice */
+  /* let's use this as an opportunity to poll outstanding listens */
+  fd_set fds;
+  int selrtn;
+  struct timeval timeout;
+  int ESRFired = 0;
+
+  FD_ZERO(&fds);
+
+  ipx_fdset(&fds);
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 0;
+  n_printf("IPX: starting repeated select\n");
+  selrtn = RPT_SYSCALL(select(255, &fds, NULL, NULL, &timeout));
+  switch (selrtn) {
+  case 0:			/* none ready */
+    /*			n_printf("IPX: no receives ready\n"); */
+    break;
+
+  case -1:			/* error (not EINTR) */
+    error("ERROR: bad ipc_select: %s\n", strerror(errno));
+    break;
+
+  default:			/* has at least 1 descriptor ready */
+    n_printf("IPX: receive ready, checking fd\n");
+    ESRFired = check_ipx_ready(&fds);
+    break;
+  }
+
+  if (!ESRFired) {
+    /*		n_printf("IPX: checking AES events\n"); */
+    ESRFired = IPXCheckForAESReady();
+  }
+
+}
+
+int
+IPXFarCallHandler(void)
+{
+  u_short port;			/* port here means DOS IPX socket */
+  u_short newPort;
+  ECB_t *ECB;
+  unsigned short *timerticks;
+  u_char *AddrPtr;
+  far_t ECBPtr;
+  unsigned long network, *networkPtr;
+  int hops, ticks;
+  unsigned char *ssp;
+  unsigned long sp;
+
+  ssp = (unsigned char *)(REG(ss)<<4);
+  sp = (unsigned long) LWORD(esp);
+
+  LWORD(eax) = popw(ssp, sp);
+  LWORD(esp) += 2;
+  n_printf("IPX: request number 0x%lX\n", _regs.ebx);
+  switch (LWORD(ebx)) {
+  case IPX_OPEN_SOCKET:
+    port = LWORD(edx);
+    LO(ax) = IPXOpenSocket(port, &newPort);
+    LWORD(edx) = newPort;
+    break;
+  case IPX_CLOSE_SOCKET:
+    port = LWORD(edx);
+    LO(ax) = IPXCloseSocket(port);
+    break;
+  case IPX_GET_LOCAL_TARGET:
+    /* do nothing here because routing is handled by IPX */
+    /* normally this would return an ImmediateAddress, but */
+    /* the ECB ImmediateAddress is never used, so just return */
+    networkPtr = (unsigned long *)(((_regs.es & 0xffff)<<4) + LWORD(esi));
+    network = *networkPtr;
+    n_printf("IPX: GetLocalTarget for network %08lx\n", network );
+    if( network==0 || network== *((unsigned long *)&MyAddress[0]) ) {
+      n_printf("IPX: returning GLT success for local address\n");
+      LO(ax) = RCODE_SUCCESS;
+      LWORD(ecx) = 1;
+    } else {
+      if( IPXGetLocalTarget( network, &hops, &ticks )==0 ) {
+        LO(ax) = RCODE_SUCCESS;
+        LWORD(ecx) = ticks;
+      } else {
+        n_printf("IPX: GetLocalTarget failed.\n");
+        LO(ax) = RCODE_CANNOT_FIND_ROUTE;
+      }
+    }
+    break;
+  case IPX_FAST_SEND:
+    n_printf("IPX: fast send\n");
+    /* just fall through to regular send */
+  case IPX_SEND_PACKET:
+    ECBPtr.segment = _regs.es & 0xffff;
+    ECBPtr.offset = LWORD(esi);
+    n_printf("IPX: send packet ECB at %x:%x\n",
+	     ECBPtr.segment, ECBPtr.offset);
+    IPXSendPacket(ECBPtr);
+    break;
+  case IPX_LISTEN_FOR_PACKET:
+    ECBPtr.segment = _regs.es & 0xffff;
+    ECBPtr.offset = LWORD(esi);
+    n_printf("IPX: listen for packet ECB at %x:%x\n",
+	     ECBPtr.segment, ECBPtr.offset);
+    /* put this packet on the queue of listens for this socket */
+    LO(ax) = IPXListenForPacket(ECBPtr);
+    break;
+  case IPX_SCHEDULE_IPX_EVENT:
+    ECBPtr.segment = _regs.es & 0xffff;
+    ECBPtr.offset = LWORD(esi);
+    n_printf("IPX: schedule IPX event for ECB at %x:%x\n",
+	     ECBPtr.segment, ECBPtr.offset);
+    /* put this packet on the queue of AES events for this socket */
+    LO(ax) = IPXScheduleEvent(ECBPtr, IU_ECB_IPX_WAITING,
+			      LWORD(eax));
+    break;
+  case IPX_CANCEL_EVENT:
+    ECBPtr.segment = _regs.es & 0xffff;
+    ECBPtr.offset = LWORD(esi);
+    n_printf("IPX: cancel event for ECB at %x:%x\n",
+	     ECBPtr.segment, ECBPtr.offset);
+    LO(ax) = IPXCancelEvent(ECBPtr);
+    break;
+  case IPX_SCHEDULE_AES_EVENT:
+    ECB = (ECB_t *) (((_regs.es & 0xffff) << 4) + LWORD(esi));
+    ECBPtr.segment = _regs.es & 0xffff;
+    ECBPtr.offset = LWORD(esi);
+
+    n_printf("IPX: schedule AES event ECB at %x\n", (unsigned int)ECB);
+    n_printf("IPX: es:si = %x:%x\n", (unsigned int)(_regs.es & 0xffff),
+      LWORD(esi));
+
+    /* put this packet on the queue of AES events for this socket */
+    LO(ax) = IPXScheduleEvent(ECBPtr, IU_ECB_AES_WAITING,
+			      LWORD(eax));
+    break;
+  case IPX_GET_INTERVAL_MARKER:
+    /* Note that timerticks is actually an unsigned long in BIOS */
+    /* this works because of intel lo-hi architecture */
+    timerticks = BIOS_TICK_ADDR;
+    LWORD(eax) = *timerticks;
+    n_printf("IPX: get interval marker %d\n", LWORD(eax));
+    /*			n_printf("IPX: doing extra relinquish control\n"); */
+    IPXRelinquishControl();
+    break;
+  case IPX_GET_INTERNETWORK_ADDRESS:
+    n_printf("IPX: get internetwork address\n");
+    AddrPtr = (u_char *) (((_regs.es & 0xffff) << 4) + LWORD(esi));
+    memcpy(AddrPtr, MyAddress, 10);
+    break;
+  case IPX_RELINQUISH_CONTROL:
+    n_printf("IPX: relinquish control\n");
+    IPXRelinquishControl();
+    break;
+  case IPX_DISCONNECT:
+    n_printf("IPX: disconnect\n");
+    break;
+  case IPX_SHELL_HOOK:
+    n_printf("IPX: shell hook\n");
+    break;
+  case IPX_GET_MAX_PACKET_SIZE:
+    n_printf("IPX: get max packet size\n");
+    /* return max data size in AX, and suggested retries in CL */
+    /* FIXTHIS - return a real max packet size here */
+    LWORD(eax) = 1024;		/* must be a power of 2 */
+    LO(cx) = 20;
+    break;
+  case IPX_GET_MEDIA_DATA_SIZE:
+    n_printf("IPX: get max packet size\n");
+    /* return max data size in AX, and suggested retries in CL */
+    /* FIXTHIS - return a real max media size here */
+    LWORD(eax) = 1480;
+    LO(cx) = 20;
+    break;
+  case IPX_CLEAR_SOCKET:
+    n_printf("IPX: clear socket\n");
+    break;
+  default:
+    break;
+  }
+  return 1;
+}
+
+/* ipx_close is called on DOSEMU shutdown */
+void
+ipx_close(void)
+{
+  ipx_socket_t *s;
+
+  /* run through the socket list and close each socket */
+  s = ipx_socket_list;
+  while (s != NULL) {
+    IPXCloseSocket(SwapInt(s->socket));
+    s = ipx_socket_list;
+  }
+}
+#endif
diff -u --recursive --new-file dosemu0.53.51/net/ipxglt.c dosemu0.53.52/net/ipxglt.c
--- dosemu0.53.51/net/ipxglt.c
+++ dosemu0.53.52/net/ipxglt.c	Sun Feb  5 12:54:06 1995
@@ -0,0 +1,219 @@
+/*
+ *	Perform IPX Get Local Target - resolve a network address to
+ *              its immediate address (and add the route to the local
+ *              route table if necessary)
+ *
+ *
+ */
+
+#include "ipx.h"
+#ifdef IPX
+
+#include <stdio.h>
+#include <stdlib.h> 
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/ipx.h>
+#include <linux/route.h>
+#include <netinet/in.h>
+
+#include "emu.h"
+
+#define FALSE   0
+#define TRUE    1
+#define TIMEOUT 250000
+
+typedef struct
+{
+	short Operation __attribute__ ((packed));
+	unsigned long Network __attribute__ ((packed));
+        short Hops __attribute__ ((packed));
+        short Ticks __attribute__ ((packed));
+} RipPacket_t;
+                                   
+/* targetNet and network should be passed in in network order */
+int AddRoute( unsigned long targetNet, unsigned network,
+        unsigned char node[] )
+{
+	struct rtentry rt;
+	struct sockaddr_ipx	*st = (struct sockaddr_ipx *)&rt.rt_dst;
+	struct sockaddr_ipx	*sr = (struct sockaddr_ipx *)&rt.rt_gateway;
+	int sock;
+	int i;
+	
+	rt.rt_flags = RTF_GATEWAY;
+	st->sipx_network = targetNet;
+        sr->sipx_network = network;
+	for( i=0; i<6; i++ ) {
+		sr->sipx_node[i] = node[i];
+	}	
+	sr->sipx_family = st->sipx_family = AF_IPX;
+	
+	sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
+	if(sock==-1) {
+		return( -1 );
+	}
+	
+	if(ioctl(sock,SIOCADDRT,(void *)&rt) < 0) {
+                if( errno != EEXIST ) {
+                        close( sock );
+                        return( -2 );
+                }
+	}
+        close( sock );
+        return(0);
+}
+
+/* network must be passed in in network order (that is, high-low) */
+/* returns 0 on success, less than 0 on failure */
+int IPXGetLocalTarget( unsigned long network, int *hops, int *ticks )
+{
+ 	int sock;
+	struct sockaddr_ipx ipxs;
+	int opt=1;
+	static RipPacket_t RipRequest;
+	static RipPacket_t RipResponse;
+        int size, sz;
+        struct timeval timeout;
+        int retries;
+        fd_set  fds;
+        int done, retCode, selrtn;
+
+        retCode = -1;	
+	sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
+	if(sock==-1)
+	{
+		goto GLTExit;
+	}
+	
+	/* Socket debugging */
+	if(setsockopt(sock,SOL_SOCKET,SO_DEBUG,&opt,sizeof(opt))==-1)
+	{
+		goto CloseGLTExit;
+	}
+	
+	/* Permit broadcast output */
+	if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1)
+	{
+		goto CloseGLTExit;
+	}
+	
+	/* This is a special for IPX sockets that allows the superuser
+	   to change the IPX type field of a socket */
+	   
+	opt=4;		/* Remember no htons! - its a byte */
+	
+	if(setsockopt(sock,SOL_SOCKET,IPX_TYPE,&opt,sizeof(opt))==-1)
+	{
+		goto CloseGLTExit;
+	}
+	
+	ipxs.sipx_family=AF_IPX;
+	ipxs.sipx_network=htonl(0);
+	ipxs.sipx_port=htons(0);
+	
+	if(bind(sock,(struct sockaddr *)&ipxs,sizeof(ipxs))==-1)
+	{
+		goto CloseGLTExit;
+	}
+	
+        /* prepare destination for send, broadcast to local net */
+	ipxs.sipx_port=htons(0x453);
+	memset(ipxs.sipx_node,0xff,6);
+	ipxs.sipx_type = 4;
+        
+        /* prepare packet data for RIP request */        
+        RipRequest.Operation = htons(1);        /* RIP Request */
+        RipRequest.Network = network;
+        RipRequest.Hops = -1;
+        RipRequest.Ticks = -1;
+	
+        /* get ready for multiple sends and receives */
+        /* we will use a select to wait for the response */
+        retries = 5;
+        done = FALSE;
+        retCode = -1;
+        
+        /* loop here sending RIP requests and trying to get a RIP response */
+        while( !done ) {
+        	if(sendto(sock,(void *)&RipRequest,sizeof(RipRequest),0,
+                        (struct sockaddr *)&ipxs,sizeof(ipxs))==-1)
+	        {
+                        retCode = -2;
+        		goto CloseGLTExit;
+	        }
+                
+                timeout.tv_sec = 0;
+                timeout.tv_usec = TIMEOUT;
+                FD_ZERO( &fds );
+                FD_SET( sock, &fds);
+RepeatSelect:
+                selrtn = select( 255, &fds, NULL, NULL, &timeout );
+                if( selrtn == -1 ) {
+                        if( errno != EINTR ) {
+                                done = TRUE;
+                                retCode = -3;
+                                break;
+                        }
+                        goto RepeatSelect;
+                }
+                if( selrtn==0 ) {
+                        retries--;
+                        if( retries==0 ) {
+                                done = TRUE;
+                                retCode = -4;
+                        }
+                        continue;
+                }
+		if (FD_ISSET(sock, &fds)) {
+			sz = sizeof(ipxs);
+        		size=recvfrom(sock,(char *)&RipResponse,
+                                sizeof(RipResponse),0,
+                                (struct sockaddr *)&ipxs,&sz);
+        		if(size==-1 || size < sizeof (RipResponse) ||
+                                RipResponse.Operation != htons(2) ) {
+                                done = TRUE;
+                                retCode = -5;
+	        	} else {
+                                done = TRUE;
+                                retCode = 0;
+                        }
+                }
+        }
+        
+        if( retCode==0 ) {
+                n_printf("IPX: Received RIP information for network %08lx\n",
+                        htonl(network));
+        
+                *hops = htons(RipResponse.Hops);
+                *ticks = htons(RipResponse.Ticks);
+                retCode = AddRoute( network, ipxs.sipx_network,
+                        ipxs.sipx_node );
+                if( retCode < 0 ) {
+                        n_printf("IPX: Failure %d adding route <%08lx through %08lx:%02x%02x%02x%02x%02x%02x>\n",
+                                retCode,
+                                htonl(network), htonl(ipxs.sipx_network),
+                                ipxs.sipx_node[0],ipxs.sipx_node[1],ipxs.sipx_node[2],
+                                ipxs.sipx_node[3],ipxs.sipx_node[4],ipxs.sipx_node[5] );
+                } else {
+                        n_printf("IPX: Success adding route <%08lx through %08lx:%02x%02x%02x%02x%02x%02x>\n",
+                                htonl(network), htonl(ipxs.sipx_network),
+                                ipxs.sipx_node[0],ipxs.sipx_node[1],ipxs.sipx_node[2],
+                                ipxs.sipx_node[3],ipxs.sipx_node[4],ipxs.sipx_node[5] );
+                }
+        } else {
+                printf("IPX: Error %d in GetLocalTarget main packet send/receive loop\n", retCode);
+        }
+CloseGLTExit:
+        close( sock );
+GLTExit:
+        return( retCode );
+}
+                                   
+
+#endif
+
diff -u --recursive --new-file dosemu0.53.51/net/libpacket.c dosemu0.53.52/net/libpacket.c
--- dosemu0.53.51/net/libpacket.c
+++ dosemu0.53.52/net/libpacket.c	Sat Jan 14 11:31:24 1995
@@ -0,0 +1,168 @@
+/*
+ *	SOCK_PACKET support.
+ *	Placed under the GNU LGPL.
+ *
+ *	First cut at a library of handy support routines. Comments, additions
+ *	and bug fixes greatfully received.
+ *
+ *	(c) 1994 Alan Cox	iiitac@pyr.swan.ac.uk	GW4PTS@GB7SWN
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+
+#include "libpacket.h"
+
+/*
+ *	Obtain a file handle on a raw ethernet type. In actual fact
+ *	you can also request the dummy types for AX.25 or 802.3 also
+ *
+ *	-1 indicates an error
+ *	0  or higher is a file descriptor which we have set non blocking
+ *
+ *	WARNING: It is ok to listen to a service the system is using (eg arp)
+ *	but don't try and run a user mode stack on the same service or all
+ *	hell will break loose.
+ */
+
+int 
+OpenNetworkType(unsigned short netid)
+{
+  int s = socket(AF_INET, SOCK_PACKET, htons(netid));
+
+  if (s == -1)
+    return -1;
+  fcntl(s, F_SETFL, O_NDELAY);
+  return s;
+}
+
+/*
+ *	Close a file handle to a raw packet type.
+ */
+
+void 
+CloseNetworkLink(int sock)
+{
+  close(sock);
+}
+
+/*
+ *	Write a packet to the network. You have to give a device to
+ *	this function. This is a device name (eg 'eth0' for the first
+ *	ethernet card). Please don't assume eth0, make it configurable
+ *	- plip is ethernet like but not eth0, ditto for the de600's.
+ *
+ *	Return: -1 is an error
+ *		otherwise bytes written.
+ */
+
+int 
+WriteToNetwork(int sock, const char *device, const char *data, int len)
+{
+  struct sockaddr sa;
+
+  sa.sa_family = AF_INET;
+  strcpy(sa.sa_data, device);
+
+  return (sendto(sock, data, len, 0, &sa, sizeof(sa)));
+}
+
+/*
+ *	Read a packet from the network. The device parameter will
+ *	be filled in by this routine (make it 32 bytes or more).
+ *	If you wish to work with one interface only you must filter
+ *	yourself. Remember to make your buffer big enough for your
+ *	data. Oversized packets will be truncated.
+ *
+ *	Return:
+ *	 	-1	   Error
+ *		otherwise  Size of packet received.
+ */
+
+int 
+ReadFromNetwork(int sock, char *device, char *data, int len)
+{
+  struct sockaddr sa;
+  int sz = sizeof(sa);
+  int error;
+
+  error = recvfrom(sock, data, len, 0, &sa, &sz);
+
+  if (error == -1)
+    return -1;
+
+  strcpy(device, sa.sa_data);
+  return error;			/* Actually size of received packet */
+}
+
+/*
+ *	Handy support routines.
+ */
+
+/*
+ *	Obtain the hardware address of an interface.
+ *	addr should be a buffer of 8 bytes or more.
+ *
+ *	Return:
+ *	0	Success, buffer holds data.
+ *	-1	Error.
+ */
+
+/*
+ *	NET2 or NET3 - work for both.
+ */
+#ifdef OLD_SIOCGIFHWADDR
+#define NET3
+#endif
+
+int 
+GetDeviceHardwareAddress(char *device, char *addr)
+{
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  struct ifreq req;
+  int err;
+
+  strcpy(req.ifr_name, device);
+
+  err = ioctl(s, SIOCGIFHWADDR, &req);  
+  close(s);	/* Thanks Rob. for noticing this */
+  if (err == -1)
+    return err;
+#ifdef NET3    
+  memcpy(addr, req.ifr_hwaddr.sa_data,8);
+#else
+  memcpy(addr, req.ifr_hwaddr, 8);
+#endif  
+  return 0;
+}
+
+/*
+ *	Obtain the maximum packet size on an interface.
+ *
+ *	Return:
+ *	>0	Return is the mtu of the interface
+ *	-1	Error.
+ */
+
+int 
+GetDeviceMTU(char *device)
+{
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  struct ifreq req;
+  int err;
+
+  strcpy(req.ifr_name, device);
+
+  err = ioctl(s, SIOCGIFMTU, &req);
+  close(s);	/* So I'll add this one as well.  Ok Alan? - Rob */
+  if (err == -1)
+    return err;
+  return req.ifr_mtu;
+}
diff -u --recursive --new-file dosemu0.53.51/net/libpacket.c.multi dosemu0.53.52/net/libpacket.c.multi
--- dosemu0.53.51/net/libpacket.c.multi
+++ dosemu0.53.52/net/libpacket.c.multi	Thu Nov  3 07:45:30 1994
@@ -0,0 +1,235 @@
+/*
+ *	SOCK_PACKET support.
+ *	Placed under the GNU LGPL.
+ *
+ *	First cut at a library of handy support routines. Comments, additions
+ *	and bug fixes greatfully received.
+ *
+ *	(c) 1994 Alan Cox	iiitac@pyr.swan.ac.uk	GW4PTS@GB7SWN
+ */
+#include <stdio.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+
+#include "emu.h"
+#include "libpacket.h"
+
+#include  "dosnet.h"
+
+/*
+ *	Obtain a file handle on a raw ethernet type. In actual fact
+ *	you can also request the dummy types for AX.25 or 802.3 also
+ *
+ *	-1 indicates an error
+ *	0  or higher is a file descriptor which we have set non blocking
+ *
+ *	WARNING: It is ok to listen to a service the system is using (eg arp)
+ *	but don't try and run a user mode stack on the same service or all
+ *	hell will break loose.
+ */
+
+
+/* Should return an unique ID (< 255) corresponding to this invocation 
+   of DOSEMU not clashing with other DOSEMU's. 
+   We use tty number.  If someone invokes dosemu in background, we 
+   are in trouble ... ;-(. 
+*/
+
+
+static unsigned short int DosnetID=0xffff;
+int 
+GetDosnetID()
+{  
+  struct stat chkbuf;
+  int major, minor;
+
+  if (DosnetID != 0xffff) return (DosnetID) ;
+
+  fstat(STDOUT_FILENO, &chkbuf);
+  major = chkbuf.st_rdev >> 8;
+  minor = chkbuf.st_rdev & 0xff;
+
+  if (major != 4) {
+      /* Not running on tty/ttyp/ttyS. I really don't know what to do. 
+         For now, let us exit ... */
+      pd_printf( "DosNetID: Can't work without a tty/pty/ttyS, assigning an odd one ... ");
+      minor=241;
+  }
+  
+  DosnetID = (unsigned short int)DOSNET_TYPE_BASE + minor;
+  pd_printf("Assigned DosnetID=%x\n", DosnetID );
+  return(DosnetID);
+}
+
+
+int 
+DosnetOpenNetworkType(unsigned short netid)
+{
+  /* Here, netid is ignored, and instead, we send our own netid. 
+     assigned to this dosnet session. 
+   */
+  int s = socket(AF_INET, SOCK_PACKET, htons(GetDosnetID()));  
+  if (s == -1)
+    return -1;
+  fcntl(s, F_SETFL, O_NDELAY);
+  return s;
+}
+
+/* Return a socket opened in broadcast mode ... */
+int
+DosnetOpenBroadcastNetworkType()
+{
+  int s = socket(AF_INET, SOCK_PACKET, htons(DOSNET_BROADCAST_TYPE));  
+           /* this is special value !*/
+  if (s == -1) {
+    return -1;
+    pd_printf("DosnetOpenBroadcast.. couldnot open socket.\n");
+  }
+  fcntl(s, F_SETFL, O_NDELAY);
+  return s;
+}
+
+/*
+ *	Close a file handle to a raw packet type.
+ */
+
+void 
+DosnetCloseNetworkLink(int sock)
+{
+  close(sock);
+}
+
+/*
+ *	Write a packet to the network. You have to give a device to
+ *	this function. This is a device name (eg 'eth0' for the first
+ *	ethernet card). Please don't assume eth0, make it configurable
+ *	- plip is ethernet like but not eth0, ditto for the de600's.
+ *
+ *	Return: -1 is an error
+ *		otherwise bytes written.
+ */
+
+int 
+DosnetWriteToNetwork(int sock, const char *device, const char *data, int len)
+{
+  struct sockaddr sa;
+
+  sa.sa_family = AF_INET;
+  strcpy(sa.sa_data, DOSNET_DEVICE);
+
+  return (sendto(sock, data, len, 0, &sa, sizeof(sa)));
+}
+
+/*
+ *	Read a packet from the network. The device parameter will
+ *	be filled in by this routine (make it 32 bytes or more).
+ *	If you wish to work with one interface only you must filter
+ *	yourself. Remember to make your buffer big enough for your
+ *	data. Oversized packets will be truncated.
+ *
+ *	Return:
+ *	 	-1	   Error
+ *		otherwise  Size of packet received.
+ */
+
+int 
+DosnetReadFromNetwork(int sock, char *device, char *data, int len)
+{
+  struct sockaddr sa;
+  int sz = sizeof(sa);
+  int error;
+
+  error = recvfrom(sock, data, len, 0, &sa, &sz);
+
+  if (error == -1)
+    return -1;
+
+  strcpy(device, sa.sa_data);
+  return error;			/* Actually size of received packet */
+}
+
+/*
+ *	Handy support routines.
+ */
+
+/*
+ *	Obtain the hardware address of an interface.
+ *	addr should be a buffer of 8 bytes or more.
+ *
+ *	Return:
+ *	0	Success, buffer holds data.
+ *	-1	Error.
+ */
+
+/*
+ *	NET2 or NET3 - work for both.
+ */
+#ifdef OLD_SIOCGIFHWADDR
+#define NET3
+#endif
+
+
+
+/* This routine is totally local; doesn't make request to actual device. */
+
+char local_eth_addr[6]={0,0,0,0,0,0};
+int 
+DosnetGetDeviceHardwareAddress(char *device, char *addr)
+{  
+   int i;
+   memcpy(local_eth_addr,DOSNET_FAKED_ETH_ADDRESS, 6);
+   (void)GetDosnetID();
+   *(unsigned short int *)&(local_eth_addr[2])= DosnetID ;
+
+   memcpy(addr, local_eth_addr, 6);
+
+   pd_printf("Assigned Ethernet Address= " );
+   for ( i=0; i< 6 ; i++)  pd_printf("%x:", local_eth_addr[i]);
+   pd_printf( "\n");
+
+   return 0;
+}
+
+/*
+ *	Obtain the maximum packet size on an interface.
+ *
+ *	Return:
+ *	>0	Return is the mtu of the interface
+ *	-1	Error.
+ */
+
+int 
+DosnetGetDeviceMTU(char *device)
+{
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  struct ifreq req;
+  int err;
+
+  strcpy(req.ifr_name, device);
+
+  err = ioctl(s, SIOCGIFMTU, &req);
+  close(s);	/* So I'll add this one as well.  Ok Alan? - Rob */
+  if (err == -1)
+    return err;
+  return req.ifr_mtu;
+}
+
+void
+printbuf(char *mesg, struct ethhdr *buf)
+{ int i;
+  pd_printf( "%s :\n Dest.=", mesg);
+  for (i=0;i<6;i++) pd_printf("%x:",buf->h_dest[i]);
+  pd_printf( " Source=") ;
+  for (i=0;i<6;i++) pd_printf("%x:",buf->h_source[i]);
+  pd_printf( " Type= %x \n", buf->h_proto) ;
+}
diff -u --recursive --new-file dosemu0.53.51/net/libpacket.c.single dosemu0.53.52/net/libpacket.c.single
--- dosemu0.53.51/net/libpacket.c.single
+++ dosemu0.53.52/net/libpacket.c.single	Fri Oct 14 15:03:11 1994
@@ -0,0 +1,168 @@
+/*
+ *	SOCK_PACKET support.
+ *	Placed under the GNU LGPL.
+ *
+ *	First cut at a library of handy support routines. Comments, additions
+ *	and bug fixes greatfully received.
+ *
+ *	(c) 1994 Alan Cox	iiitac@pyr.swan.ac.uk	GW4PTS@GB7SWN
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+
+#include "libpacket.h"
+
+/*
+ *	Obtain a file handle on a raw ethernet type. In actual fact
+ *	you can also request the dummy types for AX.25 or 802.3 also
+ *
+ *	-1 indicates an error
+ *	0  or higher is a file descriptor which we have set non blocking
+ *
+ *	WARNING: It is ok to listen to a service the system is using (eg arp)
+ *	but don't try and run a user mode stack on the same service or all
+ *	hell will break loose.
+ */
+
+int 
+OpenNetworkType(unsigned short netid)
+{
+  int s = socket(AF_INET, SOCK_PACKET, htons(netid));
+
+  if (s == -1)
+    return -1;
+  fcntl(s, F_SETFL, O_NDELAY);
+  return s;
+}
+
+/*
+ *	Close a file handle to a raw packet type.
+ */
+
+void 
+CloseNetworkLink(int sock)
+{
+  close(sock);
+}
+
+/*
+ *	Write a packet to the network. You have to give a device to
+ *	this function. This is a device name (eg 'eth0' for the first
+ *	ethernet card). Please don't assume eth0, make it configurable
+ *	- plip is ethernet like but not eth0, ditto for the de600's.
+ *
+ *	Return: -1 is an error
+ *		otherwise bytes written.
+ */
+
+int 
+WriteToNetwork(int sock, const char *device, const char *data, int len)
+{
+  struct sockaddr sa;
+
+  sa.sa_family = AF_INET;
+  strcpy(sa.sa_data, device);
+
+  return (sendto(sock, data, len, 0, &sa, sizeof(sa)));
+}
+
+/*
+ *	Read a packet from the network. The device parameter will
+ *	be filled in by this routine (make it 32 bytes or more).
+ *	If you wish to work with one interface only you must filter
+ *	yourself. Remember to make your buffer big enough for your
+ *	data. Oversized packets will be truncated.
+ *
+ *	Return:
+ *	 	-1	   Error
+ *		otherwise  Size of packet received.
+ */
+
+int 
+ReadFromNetwork(int sock, char *device, char *data, int len)
+{
+  struct sockaddr sa;
+  int sz = sizeof(sa);
+  int error;
+
+  error = recvfrom(sock, data, len, 0, &sa, &sz);
+
+  if (error == -1)
+    return -1;
+
+  strcpy(device, sa.sa_data);
+  return error;			/* Actually size of received packet */
+}
+
+/*
+ *	Handy support routines.
+ */
+
+/*
+ *	Obtain the hardware address of an interface.
+ *	addr should be a buffer of 8 bytes or more.
+ *
+ *	Return:
+ *	0	Success, buffer holds data.
+ *	-1	Error.
+ */
+
+/*
+ *	NET2 or NET3 - work for both.
+ */
+#ifdef OLD_SIOCGIFHWADDR
+#define NET3
+#endif
+
+int 
+GetDeviceHardwareAddress(char *device, char *addr)
+{
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  struct ifreq req;
+  int err;
+
+  strcpy(req.ifr_name, device);
+
+  err = ioctl(s, SIOCGIFHWADDR, &req);  
+  close(s);	/* Thanks Rob. for noticing this */
+  if (err == -1)
+    return err;
+#ifdef NET3    
+  memcpy(addr, req.ifr_hwaddr.sa_data,8);
+#else
+  memcpy(addr, req.ifr_hwaddr, 8);
+#endif  
+  return 0;
+}
+
+/*
+ *	Obtain the maximum packet size on an interface.
+ *
+ *	Return:
+ *	>0	Return is the mtu of the interface
+ *	-1	Error.
+ */
+
+int 
+GetDeviceMTU(char *device)
+{
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  struct ifreq req;
+  int err;
+
+  strcpy(req.ifr_name, device);
+
+  err = ioctl(s, SIOCGIFMTU, &req);
+  close(s);	/* So I'll add this one as well.  Ok Alan? - Rob */
+  if (err == -1)
+    return err;
+  return req.ifr_mtu;
+}
diff -u --recursive --new-file dosemu0.53.51/net/libpacket.h dosemu0.53.52/net/libpacket.h
--- dosemu0.53.51/net/libpacket.h
+++ dosemu0.53.52/net/libpacket.h	Sun Jun 12 20:18:27 1994
@@ -0,0 +1,7 @@
+
+extern int OpenNetworkType(unsigned short);
+extern void CloseNetworkLink(int);
+extern int WriteToNetwork(int, const char *, const char *, int);
+extern int ReadFromNetwork(int, char *, char *, int);
+extern int GetDeviceHardwareAddress(char *, char *);
+extern int GetDeviceMTU(char *);
diff -u --recursive --new-file dosemu0.53.51/net/pktnew.c dosemu0.53.52/net/pktnew.c
--- dosemu0.53.51/net/pktnew.c
+++ dosemu0.53.52/net/pktnew.c	Sat Feb 25 17:53:26 1995
@@ -0,0 +1,565 @@
+/*
+ *
+ *     Packet driver emulation for the Linux DOS emulator.
+ *
+ *     Written almost from scratch by Rob Janssen, PE1CHL
+ *     (pe1chl@rabo.nl, PE1CHL@PI8UTR.#UTR.NLD.EU, pe1chl@ko23)
+ *
+ *     Now it is entirely contained in dosemu, no driver needs to
+ *     be loaded in DOS anymore.
+ *     (it looks like the PC's BIOS supports the packet driver interface)
+ *
+ *     Also added support for multiple handles, and checking the
+ *     actual type passed to access_type.  This means other protocols
+ *     than Novell 802.3 are now supported.  Don't try to run TCP/IP
+ *     over this packet driver, unless you understand what you are
+ *     doing, though...
+ */
+
+#include "pktdrvr.h"
+#include "cpu.h"
+#include "emu.h"
+#include "dosio.h"
+#include "memory.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <linux/if_ether.h>
+
+#define min(a,b)	((a) < (b)? (a) : (b))
+
+extern int OpenNetworkType(u_short);
+extern int GetDeviceHardwareAddress(char *, char *);
+extern int WriteToNetwork(int, const char *, const char *, int);
+extern int ReadFromNetwork(int, char *, char *, int);
+
+/* global data which is put at PKTDRV_SEG:PKTDRV_OFF */
+/* (not everything needs to be accessible from DOS space, but it is */
+/* often convenient to be able to look at it with DEBUG...) */
+
+struct pkt_globs
+{
+    unsigned char signature[20];	/* entry point + signature */
+    unsigned char classes[4];		/* supported classes */
+    unsigned char hw_address[8];	/* our hardware address */
+    struct pkt_param param;		/* parameters */
+    struct pkt_statistics stats;	/* counters */
+    int flags;				/* global flags */
+#define N_OPTION	0x01		/* Novell 802.3 <-> 8137 translation */
+    char driver_name[8];		/* fixed string: driver name */
+    short type;				/* our type */
+    short size;				/* current packet's size */
+    long receiver;			/* current receive handler */
+    int helpvec;			/* vector number for helper */
+    int nfds;				/* number of fd's for select() */
+    fd_set sockset;			/* set of sockets for select() */
+    unsigned char helper[72];		/* upcall helper */
+
+    struct per_handle
+    {
+	char in_use;			/* this handle in use? */
+	char class;			/* class it was access_type'd with */
+	short packet_type_len;		/* length of packet type */
+	int flags;			/* per-packet-type flags */
+	int sock;			/* fd for the socket */
+	long receiver;			/* receive handler */
+	char packet_type[16];		/* packet type for this handle */
+    } handle[MAX_HANDLE];
+
+    char buf[ETH_FRAME_LEN + 32];	/* packet buffer */
+};
+
+static char devname[] = "eth0";		/* linux device name */
+
+static struct pkt_globs *pg = NULL;
+
+/* initialize the packet driver interface (called at startup) */
+void
+pkt_init (int vec)
+
+{
+    register unsigned char *ptr;
+
+    /* initialize the globals */
+
+    pg = (struct pkt_globs *) PKTDRV_ADD;
+
+    memset(pg,0,sizeof(struct pkt_globs));
+
+    /* init the interrupt vector and signature */
+
+    SETIVEC(vec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,signature));
+    ptr = pg->signature;
+
+    *ptr++ = 0xeb;			/* JMP $+10, NOP, PKT DRVR */
+    *ptr++ = 0x0a;
+    *ptr++ = 0x90;
+    strcpy(ptr,"PKT DRVR");		/* signature as defined by driver spec */
+    ptr += 9;
+    *ptr++ = 0xcd;			/* 0xcd = INT */
+    *ptr++ = vec;
+    *ptr++ = 0xca;			/* 0xca = RETF xx */
+    *ptr++ = 2;
+
+    /* fill other global data */
+
+    strcpy(pg->driver_name,"Linux$");
+    GetDeviceHardwareAddress(devname,pg->hw_address);
+    pg->classes[0] = ETHER_CLASS;
+    pg->classes[1] = IEEE_CLASS;
+    pg->type = 12;			/* dummy type (3c503) */
+    pg->flags = config.pktflags;	/* global config flags */
+
+    pg->param.major_rev = 9;		/* pkt driver spec */
+    pg->param.minor_rev = 1;
+    pg->param.length = sizeof(struct pkt_param);
+    pg->param.addr_len = ETH_ALEN;
+    pg->param.mtu = GetDeviceMTU(devname);
+    pg->param.rcv_bufs = 8 - 1;		/* a guess */
+    pg->param.xmt_bufs = 2 - 1;
+
+    /* helper routine to transfer received packets and call receiver */
+
+    pg->helpvec = vec + 1;		/* use this for helper vec */
+    SETIVEC(pg->helpvec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,helper));
+    ptr = pg->helper;
+
+    *ptr++ = 0x60;			/* pusha */
+    *ptr++ = 0x1e;			/* push ds */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x2e; *ptr++ = 0x8b; *ptr++ = 0x0e; /* mov cx,cs:[pg->size] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0xe3; *ptr++ = 0x31;	/* jcxz nothing */
+    *ptr++ = 0x31; *ptr++ = 0xc0;	/* xor ax,ax */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x59;			/* pop cx */
+    *ptr++ = 0x8c; *ptr++ = 0xc0;	/* mov ax,es */
+    *ptr++ = 0x09; *ptr++ = 0xf8;	/* or ax,di */
+    *ptr++ = 0x74; *ptr++ = 0x1b;	/* jz norecv */
+    *ptr++ = 0x0e;			/* push cs */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xbe;			/* mov si,pg->buf */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) >> 8;
+    *ptr++ = 0x57;			/* push di */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0xfc;			/* cld */
+    *ptr++ = 0xd1; *ptr++ = 0xe9;	/* shr cx,1 */
+    *ptr++ = 0xf3; *ptr++ = 0xa5;	/* rep movsw */
+    *ptr++ = 0x73; *ptr++ = 0x01;	/* jnc nobyte */
+    *ptr++ = 0xa4;			/* movsb */
+    *ptr++ = 0x59;			/* nobyte: pop cx */
+    *ptr++ = 0x5e;			/* pop si */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xb8;			/* mov ax,1 */
+    *ptr++ = 0x01; *ptr++ = 0x00;
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x2e; *ptr++ = 0xc7; *ptr++ = 0x06; /* norecv: mov cs:[pg->size],0 */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0x00; *ptr++ = 0x00;
+    *ptr++ = 0x07;			/* nothing: pop es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0x61;			/* popa */
+    *ptr   = 0xcf;			/* iret */
+}
+
+/* this is the handler for INT calls from DOS to the packet driver */
+int
+pkt_int ()
+
+{
+    struct per_handle *hdlp;
+
+#if 0
+    pd_printf("NPKT: AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+#endif
+
+    /* first clear CARRY flag that we may later set (on error) */
+
+    NOCARRY;
+
+    /* when BX seems like a valid handle, set the handle info pointer */
+
+    if (LWORD(ebx) < MAX_HANDLE)
+	hdlp = &pg->handle[LWORD(ebx)];
+    else
+	hdlp = NULL;
+
+    /* switch on the packet driver function code */
+
+    switch (HI(ax))
+    {
+    case F_DRIVER_INFO:
+	REG(eax) = 2;				/* basic+extended functions */
+	REG(ebx) = 1;				/* version */
+	if (hdlp != NULL && hdlp->in_use)
+	    REG(ecx) = (hdlp->class << 8) + 1;	/* class, number */
+	else
+	    REG(ecx) = (pg->classes[0] << 8) + 1;
+	REG(edx) = pg->type;			/* type (dummy) */
+	REG(ds) = PKTDRV_SEG;			/* driver name */
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,driver_name);
+	return 1;
+
+    case F_ACCESS_TYPE:
+	if (strchr(pg->classes,LO(ax)) == NULL) { /* check if_class */
+	    HI(dx) = E_NO_CLASS;
+	    break;
+	}
+	if (LWORD(ebx) != 0xffff && LWORD(ebx) != pg->type) { /* check if_type */
+	    HI(dx) = E_NO_TYPE;
+	    break;
+	}
+	if (LO(dx) != 0 && LO(dx) != 1) {	/* check if_number */
+	    HI(dx) = E_NO_NUMBER;
+	    break;
+	}
+	if (LWORD(ecx) > sizeof(pg->handle[0].packet_type)) { /* check len */
+	    HI(dx) = E_BAD_TYPE;
+	    break;
+	}
+	/* now check if the type is not already in use, and find a free */
+	/* handle to use for this request */
+	{
+	    int free_handle = -1;
+	    int handle;
+	    unsigned short type;
+
+	    if (LWORD(ecx) == 0)		/* pass-all type? */
+		handle = MAX_HANDLE - 1;	/* always put it last */
+	    else
+		handle = 0;			/* else search from 1st */
+
+	    for (; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (hdlp->class == LO(ax) && /* same class? */
+			!memcmp(hdlp->packet_type, /* same type? (prefix) */
+				SEG_ADR((char *),ds,si),
+				min(LWORD(ecx),hdlp->packet_type_len)))
+		    {
+			HI(dx) = E_TYPE_INUSE;
+			CARRY;
+			return 1;
+		    }
+		} else {
+		    if (free_handle == -1)
+			free_handle = handle;	/* remember free handle */
+		}
+	    }
+
+	    /* now see if we found a free handle, and allocate it */
+	    if (free_handle == -1) {
+		HI(dx) = E_NO_SPACE;
+		break;
+	    }
+
+	    hdlp = &pg->handle[free_handle];
+	    memset(hdlp,0,sizeof(struct per_handle));
+	    hdlp->in_use = 1;
+	    hdlp->receiver = (LWORD(es) << 16) | LWORD(edi);
+	    hdlp->packet_type_len = LWORD(ecx);
+	    memcpy(hdlp->packet_type,SEG_ADR((char *),ds,si),LWORD(ecx));
+	    hdlp->class = LO(ax);
+
+	    if (hdlp->class == IEEE_CLASS)
+		type = ETH_P_802_3;
+	    else {
+		if (hdlp->packet_type_len < 2)
+		    type = ETH_P_ALL;		/* get all packet types */
+		else {
+		    type = (hdlp->packet_type[0] << 8) |
+			   ((unsigned char) hdlp->packet_type[1]);
+
+		    switch (type)
+		    {
+		    case 0:			/* sometimes this bogus type */
+			type = ETH_P_802_3;	/* is used for status calls.. */
+			break;
+
+		    case ETH_P_IPX:
+			if (hdlp->packet_type_len == 2 &&
+			    (pg->flags & N_OPTION)) /* Novell hack? */
+			{
+			    hdlp->flags |= N_OPTION;
+			    hdlp->packet_type[0] = hdlp->packet_type[1] = 0xff;
+			    hdlp->class = IEEE_CLASS;
+			    type = ETH_P_802_3;
+			}
+			break;
+		    }
+		}
+	    }
+
+	    hdlp->sock = OpenNetworkType(type); /* open the socket */
+
+	    if (hdlp->sock < 0) {
+		hdlp->in_use = 0;		/* forget about this handle */
+		HI(dx) = E_BAD_TYPE;
+		break;
+	    }
+
+	    FD_SET(hdlp->sock,&pg->sockset);	/* keep track of sockets */
+	    add_to_io_select(hdlp->sock, 1);
+	    if (hdlp->sock >= pg->nfds)
+		pg->nfds = hdlp->sock + 1;
+
+	    REG(eax) = free_handle;		/* return the handle */
+	}
+	return 1;
+
+    case F_RELEASE_TYPE:
+	if (hdlp == NULL) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+
+	if (hdlp->in_use) {
+	    int i,n;
+
+	    CloseNetworkLink(hdlp->sock);	/* close the socket */
+	    FD_CLR(hdlp->sock,&pg->sockset);	/* keep track of sockets */
+	    remove_from_io_select(hdlp->sock, 1);
+	    n = pg->nfds;
+	    pg->nfds = 0;
+
+	    for (i = 0; i < n; i++)
+		if (FD_ISSET(i,&pg->sockset))
+		    pg->nfds = i + 1;
+
+	    hdlp->in_use = 0;			/* no longer in use */
+	}
+	return 1;
+
+    case F_SEND_PKT:
+	pg->stats.packets_out++;
+	pg->stats.bytes_out += LWORD(ecx);
+
+	/* unfortunately, a handle is not passed as a parameter for the */
+	/* SEND_PKT call.  so, we will have to scan the handle table to */
+	/* find a handle which is in use, and use its socket for the send */
+	{
+	    int handle;
+
+	    for (handle = 0; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (pg->flags & N_OPTION)	/* Novell hack? */
+		    {
+			char *p;
+			short len;
+
+			p = SEG_ADR((char *),ds,si);
+			p += 2 * ETH_ALEN;	/* point to protocol type */
+
+			if (p[0] == (char)(ETH_P_IPX >> 8) &&
+			    p[1] == (char)ETH_P_IPX &&
+			    p[2] == (char)0xff && p[3] == (char)0xff)
+			{
+			    /* it is a Novell Ethernet-II packet, make it */
+			    /* "raw 802.3" by overwriting type with length */
+
+			    len = (p[4] << 8) | (unsigned char)p[5];
+			    len = (len + 1) & ~1; /* make length even */
+			    p[0] = len >> 8;
+			    p[1] = (char)len;
+			}
+		    }
+
+		    if (WriteToNetwork(hdlp->sock,devname,
+				SEG_ADR((char *),ds,si),LWORD(ecx)) >= 0)
+		    {
+			/* send was okay, check for a reply to speedup */
+			/* things (background poll is quite slow) */
+			pkt_check_receive(50000);
+			return 1;
+		    } else {
+			warn("NPKT: WriteToNetwork(%d,\"%s\",buffer,%u): error %d\n",
+			    hdlp->sock,devname,LWORD(ecx),errno);
+			break;
+		    }
+		}
+	    }
+
+	    pg->stats.errors_out++;
+	    HI(dx) = E_CANT_SEND;
+	}
+	break;
+
+    case F_TERMINATE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_TERM;
+
+	break;
+
+    case F_GET_ADDRESS:
+	if (LWORD(ecx) < ETH_ALEN) {
+	    HI(dx) = E_NO_SPACE;
+	    break;
+	}
+	REG(ecx) = ETH_ALEN;
+	memcpy(SEG_ADR((char *),es,di),pg->hw_address,ETH_ALEN);
+	return 1;
+
+    case F_RESET_IFACE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_RESET;
+
+	break;
+
+    case F_GET_PARAMS:
+	REG(es) = PKTDRV_SEG;
+	REG(edi) = PKTDRV_OFF + offsetof(struct pkt_globs,param);
+	return 1;
+
+    case F_SET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	if (LWORD(ecx) != 3) {			/* only mode 3 supported */
+	    HI(dx) = E_BAD_MODE;
+	    break;
+	}
+	return 1;
+
+    case F_GET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(eax) = 3;
+	return 1;
+
+    case F_GET_STATS:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(ds) = PKTDRV_SEG;
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,stats);
+	return 1;
+
+    default:
+	/* unhandled function, indicate an error */
+
+	HI(dx) = E_BAD_COMMAND;
+	break;
+    }
+
+    /* fell through switch, indicate an error (DH set above) */
+    CARRY;
+
+#if 0
+    pd_printf("ERR:  AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+#endif
+
+    return 1;
+}
+
+int
+pkt_check_receive(timeout)
+int timeout;
+
+{
+    int size,handle;
+    struct per_handle *hdlp;
+    char *p;
+    struct timeval tv;
+    fd_set readset;
+    char device[32];
+
+    if (pg == NULL)				/* packet driver intialized? */
+	return -1;
+
+    if (pg->nfds == 0)				/* no active sockets? */
+	return 0;
+
+    if (pg->size != 0)				/* transfer area busy? */
+	return 1;
+
+    tv.tv_sec = 0;				/* set a (small) timeout */
+    tv.tv_usec = timeout;
+    readset = pg->sockset;
+
+    if (select(pg->nfds,&readset,NULL,NULL,&tv) <= 0) /* anything ready? */
+	return 0;
+
+    for (handle = 0; handle < MAX_HANDLE; handle++) {
+	hdlp = &pg->handle[handle];
+
+	if (hdlp->in_use && FD_ISSET(hdlp->sock,&readset)) {
+	    /* somethine is available on this handle's socket */
+	    /* attempt to read it.  that should always succeed... */
+
+	    size = ReadFromNetwork(hdlp->sock,device,pg->buf,sizeof(pg->buf));
+
+	    /* check if something has been received */
+	    /* there was a check for "not multicast" here, but I think */
+	    /* it should not be there... */
+
+	    if (size >= 0) {
+		/* verify the source of the packet.  when not from eth0, */
+		/* discard it for now (multiple network cards are next) */
+
+		if (strcmp(device,devname))
+		    continue;
+
+		/* check if the packet's type matches the specified type */
+		/* in the ACCESS_TYPE call.  the position depends on the */
+		/* driver class! */
+
+		if (hdlp->class == ETHER_CLASS)
+		    p = pg->buf + 2 * ETH_ALEN;		/* Ethernet-II */
+		else
+		    p = pg->buf + 2 * ETH_ALEN + 2;	/* IEEE 802.3 */
+
+		if (size >= ((p - pg->buf) + hdlp->packet_type_len) &&
+		    !memcmp(p,hdlp->packet_type,hdlp->packet_type_len))
+		{
+		    pg->stats.packets_in++;
+		    pg->stats.bytes_in += size;
+
+		    if (hdlp->flags & N_OPTION) {	/* Novell hack? */
+			*--p = (char)ETH_P_IPX;	/* overwrite length with type */
+			*--p = (char)(ETH_P_IPX >> 8);
+		    }
+
+		    /* stuff things in global vars and queue a hardware */
+		    /* interrupt which will perform the upcall */
+		    pg->size = size;
+		    pg->receiver = hdlp->receiver;
+		    run_int(pg->helpvec);
+		    return 1;
+		} else
+		    pg->stats.packets_lost++;	/* not really lost... */
+	    } else
+		pg->stats.errors_in++;		/* select() somehow lied */
+	}
+    }
+
+    return 0;
+}
diff -u --recursive --new-file dosemu0.53.51/net/pktnew.c.multi dosemu0.53.52/net/pktnew.c.multi
--- dosemu0.53.51/net/pktnew.c.multi
+++ dosemu0.53.52/net/pktnew.c.multi	Mon Feb 13 19:34:47 1995
@@ -0,0 +1,711 @@
+/*
+ *
+ *     Packet driver emulation for the Linux DOS emulator.
+ *
+ *     Written almost from scratch by Rob Janssen, PE1CHL
+ *     (pe1chl@rabo.nl, PE1CHL@PI8UTR.#UTR.NLD.EU, pe1chl@ko23)
+ *
+ *     Now it is entirely contained in dosemu, no driver needs to
+ *     be loaded in DOS anymore.
+ *     (it looks like the PC's BIOS supports the packet driver interface)
+ *
+ *     Also added support for multiple handles, and checking the
+ *     actual type passed to access_type.  This means other protocols
+ *     than Novell 802.3 are now supported.  Don't try to run TCP/IP
+ *     over this packet driver, unless you understand what you are
+ *     doing, though...
+ */
+
+#include "emu.h"
+#include "pktdrvr.h"
+#include "cpu.h"
+#include "emu.h"
+#include "dosio.h"
+#include "memory.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <linux/if_ether.h>
+
+#define min(a,b)	((a) < (b)? (a) : (b))
+
+#include "dosnet.h"                
+
+extern int DosnetOpenNetworkType(u_short);
+extern int DosnetOpenBroadcastNetwork(u_short);
+extern int DosnetGetDeviceHardwareAddress(char *, char *);
+extern int DosnetWriteToNetwork(int, const char *, const char *, int);
+extern int DosnetReadFromNetwork(int, char *, char *, int);
+
+
+
+void Open_sockets(void);
+
+int  pkt_fd=-1, pkt_broadcast_fd=-1, max_pkt_fd;
+
+/* global data which is put at PKTDRV_SEG:PKTDRV_OFF */
+/* (not everything needs to be accessible from DOS space, but it is */
+/* often convenient to be able to look at it with DEBUG...) */
+#define MAX_PKT_TYPE_SIZE 10
+struct pkt_type {
+  int handle, no_of_chars;
+  char pkt_type[MAX_PKT_TYPE_SIZE];
+  int count;                           /* To sort the array based on counts of packet type. */
+} pkt_type_array[MAX_HANDLE]; 
+int max_pkt_type_array=0;
+
+
+struct pkt_globs
+{
+    unsigned char signature[20];	/* entry point + signature */
+    unsigned char classes[4];		/* supported classes */
+    unsigned char hw_address[8];	/* our hardware address */
+    struct pkt_param param;		/* parameters */
+    struct pkt_statistics stats;	/* counters */
+    int flags;				/* global flags */
+#define N_OPTION	0x01		/* Novell 802.3 <-> 8137 translation */
+    char driver_name[8];		/* fixed string: driver name */
+    short type;				/* our type */
+    short size;				/* current packet's size */
+    long receiver;			/* current receive handler */
+    int helpvec;			/* vector number for helper */
+    unsigned char helper[72];		/* upcall helper */
+
+    struct per_handle
+    {
+	char in_use;			/* this handle in use? */
+	char class;			/* class it was access_type'd with */
+	short packet_type_len;		/* length of packet type */
+	int flags;			/* per-packet-type flags */
+	long receiver;			/* receive handler */
+	char packet_type[16];		/* packet type for this handle */
+    } handle[MAX_HANDLE];          
+
+    char buf[ETH_FRAME_LEN + 32];	/* packet buffer */
+};
+
+static char devname[] = DOSNET_DEVICE ;		/* linux device name */
+
+static struct pkt_globs *pg = NULL;
+
+/* initialize the packet driver interface (called at startup) */
+void
+pkt_init (int vec)
+
+{
+    register unsigned char *ptr;
+
+    /* initialize the globals */
+
+    pg = (struct pkt_globs *) PKTDRV_ADD;
+
+    memset(pg,0,sizeof(struct pkt_globs));
+
+    /* init the interrupt vector and signature */
+
+    SETIVEC(vec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,signature));
+    ptr = pg->signature;
+
+    *ptr++ = 0xeb;			/* JMP $+10, NOP, PKT DRVR */
+    *ptr++ = 0x0a;
+    *ptr++ = 0x90;
+    strcpy(ptr,"PKT DRVR");		/* signature as defined by driver spec */
+    ptr += 9;
+    *ptr++ = 0xcd;			/* 0xcd = INT */
+    *ptr++ = vec;
+    *ptr++ = 0xca;			/* 0xca = RETF xx */
+    *ptr++ = 2;
+
+    /* fill other global data */
+
+    strcpy(pg->driver_name,"Linux$");
+    DosnetGetDeviceHardwareAddress(devname,pg->hw_address);
+    pg->classes[0] = ETHER_CLASS;  /* == 1. */
+    pg->classes[1] = IEEE_CLASS;   /* == 11. */
+    pg->type = 12;			/* dummy type (3c503) */
+    pg->flags = config.pktflags;	/* global config flags */
+
+    pg->param.major_rev = 9;		/* pkt driver spec */
+    pg->param.minor_rev = 1;
+    pg->param.length = sizeof(struct pkt_param);
+    pg->param.addr_len = ETH_ALEN;
+    pg->param.mtu = DosnetGetDeviceMTU(devname);
+    pg->param.rcv_bufs = 8 - 1;		/* a guess */
+    pg->param.xmt_bufs = 2 - 1;
+
+    Open_sockets();   /* VINOD: Added to receive all packets 
+                                     from dosnet device. These packets 
+                                     are of special type and are reconverted
+                                     into broadcast packets proper after being
+                                     received by dosemu. */
+
+    /* helper routine to transfer received packets and call receiver */
+
+    pg->helpvec = vec + 1;		/* use this for helper vec */
+    SETIVEC(pg->helpvec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,helper));
+    ptr = pg->helper;
+
+    *ptr++ = 0x60;			/* pusha */
+    *ptr++ = 0x1e;			/* push ds */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x2e; *ptr++ = 0x8b; *ptr++ = 0x0e; /* mov cx,cs:[pg->size] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0xe3; *ptr++ = 0x31;	/* jcxz nothing */
+    *ptr++ = 0x31; *ptr++ = 0xc0;	/* xor ax,ax */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x59;			/* pop cx */
+    *ptr++ = 0x8c; *ptr++ = 0xc0;	/* mov ax,es */
+    *ptr++ = 0x09; *ptr++ = 0xf8;	/* or ax,di */
+    *ptr++ = 0x74; *ptr++ = 0x1b;	/* jz norecv */
+    *ptr++ = 0x0e;			/* push cs */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xbe;			/* mov si,pg->buf */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) >> 8;
+    *ptr++ = 0x57;			/* push di */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0xfc;			/* cld */
+    *ptr++ = 0xd1; *ptr++ = 0xe9;	/* shr cx,1 */
+    *ptr++ = 0xf3; *ptr++ = 0xa5;	/* rep movsw */
+    *ptr++ = 0x73; *ptr++ = 0x01;	/* jnc nobyte */
+    *ptr++ = 0xa4;			/* movsb */
+    *ptr++ = 0x59;			/* nobyte: pop cx */
+    *ptr++ = 0x5e;			/* pop si */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xb8;			/* mov ax,1 */
+    *ptr++ = 0x01; *ptr++ = 0x00;
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x2e; *ptr++ = 0xc7; *ptr++ = 0x06; /* norecv: mov cs:[pg->size],0 */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0x00; *ptr++ = 0x00;
+    *ptr++ = 0x07;			/* nothing: pop es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0x61;			/* popa */
+    *ptr   = 0xcf;			/* iret */
+}
+
+/* this is the handler for INT calls from DOS to the packet driver */
+int
+pkt_int ()
+
+{
+    struct per_handle *hdlp;
+    int hdlp_handle=-1;
+
+#if 0
+    pd_printf("NPKT: AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+#endif
+
+    /* first clear CARRY flag that we may later set (on error) */
+
+    NOCARRY;
+
+    /* when BX seems like a valid handle, set the handle info pointer.
+       Actually, BX could be  zero in some "default cases". For e.g.
+       if it is zero when getting the driver info, we can't say if it is
+       the "real" handle or general default value.
+     */
+
+    if ((LWORD(ebx) > 0) && (LWORD(ebx) < MAX_HANDLE)) {
+	hdlp = &pg->handle[LWORD(ebx)];
+        hdlp_handle=LWORD(ebx);
+    }
+    else
+	hdlp = NULL;
+
+    /* switch on the packet driver function code */
+
+    switch (HI(ax))
+    {
+    case F_DRIVER_INFO:
+        pd_printf("Driver info called ...\n");
+	REG(eax) = 2;				/* basic+extended functions */
+	REG(ebx) = 1;				/* version */
+
+        /* If  hdlp_handle == 0,  it is not always a valid handle. 
+	   At least in case of CUTCP it sets it to zero for the first
+	   time.
+	*/
+	if (hdlp_handle !=0 && hdlp != NULL && hdlp->in_use)
+	    REG(ecx) = (hdlp->class << 8) + 1;	/* class, number */
+	else
+	    REG(ecx) = (pg->classes[0] << 8) + 1;
+	REG(edx) = pg->type;			/* type (dummy) */
+	REG(ds) = PKTDRV_SEG;			/* driver name */
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,driver_name);
+        pd_printf("Class returned = %d, handle=%d, pg->classes[0]=%d \n", 
+                         REG(ecx)>>8, hdlp_handle, pg->classes[0] );
+	return 1;
+
+    case F_ACCESS_TYPE:
+	if (strchr(pg->classes,LO(ax)) == NULL) { /* check if_class */
+	    HI(dx) = E_NO_CLASS;
+	    break;
+	}
+	if (LWORD(ebx) != 0xffff && LWORD(ebx) != pg->type) { /* check if_type */
+	    HI(dx) = E_NO_TYPE;
+	    break;
+	}
+	if (LO(dx) != 0 && LO(dx) != 1) {	/* check if_number */
+	    HI(dx) = E_NO_NUMBER;
+	    break;
+	}
+	if (LWORD(ecx) > sizeof(pg->handle[0].packet_type)) { /* check len */
+	    HI(dx) = E_BAD_TYPE;
+	    break;
+	}
+	/* now check if the type is not already in use, and find a free */
+	/* handle to use for this request */
+	{
+	    int free_handle = -1;
+	    int handle;
+	    unsigned short type;
+
+	    if (LWORD(ecx) == 0)		/* pass-all type? */
+		handle = MAX_HANDLE - 1;	/* always put it last */
+	    else
+		handle = 0;			/* else search from 1st */
+
+	    for (; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (hdlp->class == LO(ax) && /* same class? */
+			!memcmp(hdlp->packet_type, /* same type? (prefix) */
+				SEG_ADR((char *),ds,si),
+				min(LWORD(ecx),hdlp->packet_type_len)))
+		    {
+			HI(dx) = E_TYPE_INUSE;
+			CARRY;
+			return 1;
+		    }
+		} else {
+		    if (free_handle == -1)
+			free_handle = handle;	/* remember free handle */
+		}
+	    }
+
+	    /* now see if we found a free handle, and allocate it */
+	    if (free_handle == -1) {
+		HI(dx) = E_NO_SPACE;
+		break;
+	    }
+
+	    hdlp = &pg->handle[free_handle];
+	    memset(hdlp,0,sizeof(struct per_handle));
+	    hdlp->in_use = 1;
+	    hdlp->receiver = (LWORD(es) << 16) | LWORD(edi);
+	    hdlp->packet_type_len = LWORD(ecx);
+	    memcpy(hdlp->packet_type,SEG_ADR((char *),ds,si),LWORD(ecx));
+	    hdlp->class = LO(ax);
+
+	    if (hdlp->class == IEEE_CLASS)
+		type = ETH_P_802_3;
+	    else {
+		if (hdlp->packet_type_len < 2)
+		    type = ETH_P_ALL;		/* get all packet types */
+		else {
+		    type = (hdlp->packet_type[0] << 8) |
+			   ((unsigned char) hdlp->packet_type[1]);
+
+		    switch (type)
+		    {
+		    case 0:			/* sometimes this bogus type */
+			type = ETH_P_802_3;	/* is used for status calls.. */
+			break;
+
+		    case ETH_P_IPX:
+			if (hdlp->packet_type_len == 2 &&
+			    (pg->flags & N_OPTION)) /* Novell hack? */
+			{
+			    hdlp->flags |= N_OPTION;
+			    hdlp->packet_type[0] = hdlp->packet_type[1] = 0xff;
+			    hdlp->class = IEEE_CLASS;
+			    type = ETH_P_802_3;
+			}
+			break;
+		    }
+		}
+	    }
+            Insert_Type(free_handle, hdlp->packet_type_len, hdlp->packet_type);
+
+	    REG(eax) = free_handle;		/* return the handle */
+	}
+	return 1;
+
+    case F_RELEASE_TYPE:
+	if (hdlp == NULL) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+
+        Remove_Type(hdlp_handle);
+
+	if (hdlp->in_use) {
+	    hdlp->in_use = 0;			/* no longer in use */
+	}
+	return 1;
+
+    case F_SEND_PKT:
+	pg->stats.packets_out++;
+	pg->stats.bytes_out += LWORD(ecx);
+
+	/* unfortunately, a handle is not passed as a parameter for the */
+	/* SEND_PKT call.  so, we will have to scan the handle table to */
+	/* find a handle which is in use, and use its socket for the send */
+	{
+	    int handle;
+            char *p;
+
+	    for (handle = 0; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (pg->flags & N_OPTION)	/* Novell hack? */
+		    {
+			char *p;
+			short len;
+
+			p = SEG_ADR((char *),ds,si);
+			p += 2 * ETH_ALEN;	/* point to protocol type */
+
+			if (p[0] == (char)(ETH_P_IPX >> 8) &&
+			    p[1] == (char)ETH_P_IPX &&
+			    p[2] == (char)0xff && p[3] == (char)0xff)
+			{
+			    /* it is a Novell Ethernet-II packet, make it */
+			    /* "raw 802.3" by overwriting type with length */
+
+			    len = (p[4] << 8) | (unsigned char)p[5];
+			    len = (len + 1) & ~1; /* make length even */
+			    p[0] = len >> 8;
+			    p[1] = (char)len;
+			}
+		    }
+                    /* Now we have to write to network. We need
+                       to check if it is broadcast, and if so, use the
+                       corresponding socket. */
+		    p = SEG_ADR((char *),ds,si);
+
+		    if (DosnetWriteToNetwork( pkt_fd, devname,
+				SEG_ADR((char *),ds,si),LWORD(ecx)) >= 0)
+		    {
+			/* send was okay, check for a reply to speedup */
+			/* things (background poll is quite slow) */
+			pkt_check_receive(50000);
+			return 1;
+		    } else {
+			warn("NPKT: DosnetWriteToNetwork(%d,\"%s\",buffer,%u): error %d\n",
+			    pkt_fd,devname,LWORD(ecx),errno);
+			break;
+		    }
+		}
+	    }
+
+	    pg->stats.errors_out++;
+	    HI(dx) = E_CANT_SEND;
+	}
+	break;
+
+    case F_TERMINATE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_TERM;
+
+	break;
+
+    case F_GET_ADDRESS:
+	if (LWORD(ecx) < ETH_ALEN) {
+	    HI(dx) = E_NO_SPACE;
+	    break;
+	}
+	REG(ecx) = ETH_ALEN;
+	memcpy(SEG_ADR((char *),es,di),pg->hw_address,ETH_ALEN);
+	return 1;
+
+    case F_RESET_IFACE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_RESET;
+
+	break;
+
+    case F_GET_PARAMS:
+	REG(es) = PKTDRV_SEG;
+	REG(edi) = PKTDRV_OFF + offsetof(struct pkt_globs,param);
+	return 1;
+
+    case F_SET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	if (LWORD(ecx) != 3) {			/* only mode 3 supported */
+	    HI(dx) = E_BAD_MODE;
+	    break;
+	}
+	return 1;
+
+    case F_GET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(eax) = 3;
+	return 1;
+
+    case F_GET_STATS:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(ds) = PKTDRV_SEG;
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,stats);
+	return 1;
+
+    default:
+	/* unhandled function, indicate an error */
+
+	HI(dx) = E_BAD_COMMAND;
+	break;
+    }
+
+    /* fell through switch, indicate an error (DH set above) */
+    CARRY;
+
+    pd_printf("PD ERR:  AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+
+    return 1;
+}
+
+/* This handle is inserted to receive packets of type "dosnet broadcast". 
+   These are really speaking broadcast packets meant to be received by
+   all dosemu's. Their destination addresses are changed by dosemu, and
+   are changed back to 'ffffff..' when these packets are received by dosemu. 
+*/
+
+void
+Open_sockets(void)
+{
+    pkt_broadcast_fd = DosnetOpenBroadcastNetworkType(); /* open the socket */
+    pkt_fd = DosnetOpenNetworkType( (u_short)0 );
+    max_pkt_fd = pkt_fd + 1;
+    if ( max_pkt_fd <= pkt_broadcast_fd ) max_pkt_fd = pkt_broadcast_fd + 1; 
+}
+
+/*  Find_Handle does type demultiplexing. 
+    Given a packet, it compares the type fields and finds out which 
+    handle should take the given packet.
+    An array of types is maintained.
+*/
+int 
+Insert_Type(int handle, int no_of_chars, char *pkt_type)
+{
+  int i,nchars;
+  if(no_of_chars > MAX_PKT_TYPE_SIZE) return -1;
+  if (max_pkt_type_array >= MAX_HANDLE) return -1;
+
+  pd_printf("Trying to insert: handle %d, no_of_chars=%d \n ",handle, no_of_chars);
+
+  /* Find if the type or handle is already present ... */
+  for( i=0; i<max_pkt_type_array; i++)
+  {
+     nchars=pkt_type_array[i].no_of_chars;
+     if ( (pkt_type_array[i].handle == handle) ||
+          ((nchars > 1) && !memcmp(&pkt_type_array[i].pkt_type, pkt_type, nchars))
+        )
+        return  -1;
+  }
+  pkt_type_array[max_pkt_type_array].no_of_chars=no_of_chars;
+  pkt_type_array[max_pkt_type_array].handle=handle;
+  pkt_type_array[max_pkt_type_array].count=0;
+  memcpy(&pkt_type_array[max_pkt_type_array].pkt_type, pkt_type, no_of_chars);
+  for(i=0; i<no_of_chars; i++) pd_printf(" --%.2x--", pkt_type_array[max_pkt_type_array].pkt_type[i]);
+  pd_printf("\n");
+  pd_printf("Succeded: inserted at %d\n", max_pkt_type_array);
+  max_pkt_type_array++;
+}
+
+int
+Remove_Type(int handle)
+{ 
+  int i, shift_up;
+  shift_up=0;
+  for( i=0; i<max_pkt_type_array; i++)
+  {
+     if( shift_up )
+            pkt_type_array[i-1]=pkt_type_array[i];
+     else if (pkt_type_array[i].handle == handle) shift_up=1; 
+  }
+}
+
+
+int
+pkt_check_receive(timeout)
+int timeout;
+
+{
+    int size,handle, fd;
+    struct per_handle *hdlp;
+    char *p;
+    struct timeval tv;
+    fd_set readset;
+    char device[32];
+
+    if (pg == NULL)				/* packet driver intialized? */
+	return -1;
+
+    if (pg->size != 0)				/* transfer area busy? */
+	return 1;
+
+    tv.tv_sec = 0;				/* set a (small) timeout */
+    tv.tv_usec = timeout;
+
+    FD_SET(pkt_fd, &readset);
+    FD_SET(pkt_broadcast_fd, &readset);
+    add_to_io_select(pkt_broadcast_fd, 1);
+    add_to_io_select(pkt_fd, 1);
+
+    if (select(max_pkt_fd,&readset,NULL,NULL,&tv) <= 0) /* anything ready? */
+	return 0;
+
+    if( FD_ISSET(pkt_fd, &readset) ) 
+           fd = pkt_fd;
+    else if( FD_ISSET(pkt_broadcast_fd, &readset) ) 
+           fd = pkt_broadcast_fd;
+    else return 0;
+
+    size = DosnetReadFromNetwork(fd,device,pg->buf,sizeof(pg->buf));
+    if (size < 0) {
+		pg->stats.errors_in++;		/* select() somehow lied */
+                return 0;
+    }
+    if (strcmp(device,devname)) return 0; 
+   
+    pd_printf("========Processing New packet======\n");
+    /* if( (handle = Find_Handle(pg->buf))== -1) return 0; */
+    /* Code for Find_Handle.  */
+    {
+	  int i,nchars;
+	  struct ethhdr *eth ; 
+	  u_char *p;
+
+          eth=(struct ethhdr *) pg -> buf;
+	  /* find this packet's frame type, and hence position to compare the type. */
+	  if (ntohs(eth->h_proto) >= 1536)
+	       p = pg->buf + 2 * ETH_ALEN;		/* Ethernet-II */
+	  else 
+	       p = pg->buf + 2 * ETH_ALEN + 2;       /* All the rest frame types. */
+
+          pd_printf("Received packet type: %.2x\n", ntohs(eth->h_proto));
+
+          handle=-1;
+	  for( i=0; i<max_pkt_type_array; i++)
+	  {
+	     nchars= pkt_type_array[i].no_of_chars;
+	     if ( /* (nchars < 2)   ||                 */
+		  !memcmp(&pkt_type_array[i].pkt_type, p, nchars) )
+             {
+		  handle=pkt_type_array[i].handle;
+                  break; 
+             }
+	  }
+          pd_printf("Found handle=: %d\n", handle);
+	  if( handle==-1) return(-1);
+    }   
+    hdlp = &pg->handle[handle];
+    if (hdlp->in_use) {
+
+           printbuf("received packet:", pg->buf); 
+
+                /* VINOD: If it is broadcast type, translate it back ... */
+           if ( memcmp(pg->buf, DOSNET_BROADCAST_ADDRESS, 4) == 0 )
+           {    
+                     pd_printf("It is broadcast packet.");
+                     if(memcmp((pg->buf + ETH_ALEN), pg->hw_address, ETH_ALEN) == 0)
+                     {
+                        pd_printf("It was my own packet! Ignored.\n"); 
+                        return; /* Ignore our own ethernet broadcast. */
+                     }
+                     memcpy(pg->buf, "\x0ff\x0ff\x0ff\x0ff\x0ff\x0ff", ETH_ALEN);
+                     printbuf("Translated:", pg->buf); 
+           }
+
+           /* No need to check the type again. Also, for now, NOVELL_HACK
+              is diabled... */
+           if ( 0 ) {
+		/* check if the packet's type matches the specified type */
+		/* in the ACCESS_TYPE call.  the position depends on the */
+		/* driver class! */
+
+		if (hdlp->class == ETHER_CLASS)
+		    p = pg->buf + 2 * ETH_ALEN;		/* Ethernet-II */
+		else
+		    p = pg->buf + 2 * ETH_ALEN + 2;	/* IEEE 802.3 */
+
+		if (size >= ((p - pg->buf) + hdlp->packet_type_len) &&
+		    !memcmp(p,hdlp->packet_type,hdlp->packet_type_len))
+		{
+                }
+		    if (hdlp->flags & N_OPTION) {	/* Novell hack? */
+			*--p = (char)ETH_P_IPX;	/* overwrite length with type */
+			*--p = (char)(ETH_P_IPX >> 8);
+		    }
+             }
+             pg->stats.packets_in++;
+	     pg->stats.bytes_in += size;
+
+		    /* stuff things in global vars and queue a hardware */
+		    /* interrupt which will perform the upcall */
+	     pg->size = size;
+	     pg->receiver = hdlp->receiver;
+	     run_int(pg->helpvec);
+             pd_printf("Called the helpvector ... \n");
+	     return 1;
+    } else
+	     pg->stats.packets_lost++;	/* not really lost... */
+    pd_printf("Handle not in use. Ignored this packet.\n");
+    return 0;
+}
+
+
+int
+Find_Handle(u_char *buf)
+{
+  int i,nchars;
+  struct ethhdr *eth = (struct ethhdr *) buf;
+  u_char *p;
+  /* find this packet's frame type, and hence position to compare the type. */
+  if (ntohs(eth->h_proto) >= 1536)
+       p = buf + 2 * ETH_ALEN;		/* Ethernet-II */
+  else 
+       p = buf + 2 * ETH_ALEN + 2;       /* All the rest frame types. */
+
+  for( i=0; i<max_pkt_type_array; i++)
+  {
+     nchars= pkt_type_array[i].no_of_chars;
+     if ( (nchars < 2)   ||                 
+          !memcmp(&pkt_type_array[i].pkt_type, p, nchars) )
+         return i;
+  }
+  return(-1);
+}
diff -u --recursive --new-file dosemu0.53.51/net/pktnew.c.single dosemu0.53.52/net/pktnew.c.single
--- dosemu0.53.51/net/pktnew.c.single
+++ dosemu0.53.52/net/pktnew.c.single	Mon Feb 13 19:31:53 1995
@@ -0,0 +1,565 @@
+/*
+ *
+ *     Packet driver emulation for the Linux DOS emulator.
+ *
+ *     Written almost from scratch by Rob Janssen, PE1CHL
+ *     (pe1chl@rabo.nl, PE1CHL@PI8UTR.#UTR.NLD.EU, pe1chl@ko23)
+ *
+ *     Now it is entirely contained in dosemu, no driver needs to
+ *     be loaded in DOS anymore.
+ *     (it looks like the PC's BIOS supports the packet driver interface)
+ *
+ *     Also added support for multiple handles, and checking the
+ *     actual type passed to access_type.  This means other protocols
+ *     than Novell 802.3 are now supported.  Don't try to run TCP/IP
+ *     over this packet driver, unless you understand what you are
+ *     doing, though...
+ */
+
+#include "pktdrvr.h"
+#include "cpu.h"
+#include "emu.h"
+#include "dosio.h"
+#include "memory.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <linux/if_ether.h>
+
+#define min(a,b)	((a) < (b)? (a) : (b))
+
+extern int OpenNetworkType(u_short);
+extern int GetDeviceHardwareAddress(char *, char *);
+extern int WriteToNetwork(int, const char *, const char *, int);
+extern int ReadFromNetwork(int, char *, char *, int);
+
+/* global data which is put at PKTDRV_SEG:PKTDRV_OFF */
+/* (not everything needs to be accessible from DOS space, but it is */
+/* often convenient to be able to look at it with DEBUG...) */
+
+struct pkt_globs
+{
+    unsigned char signature[20];	/* entry point + signature */
+    unsigned char classes[4];		/* supported classes */
+    unsigned char hw_address[8];	/* our hardware address */
+    struct pkt_param param;		/* parameters */
+    struct pkt_statistics stats;	/* counters */
+    int flags;				/* global flags */
+#define N_OPTION	0x01		/* Novell 802.3 <-> 8137 translation */
+    char driver_name[8];		/* fixed string: driver name */
+    short type;				/* our type */
+    short size;				/* current packet's size */
+    long receiver;			/* current receive handler */
+    int helpvec;			/* vector number for helper */
+    int nfds;				/* number of fd's for select() */
+    fd_set sockset;			/* set of sockets for select() */
+    unsigned char helper[72];		/* upcall helper */
+
+    struct per_handle
+    {
+	char in_use;			/* this handle in use? */
+	char class;			/* class it was access_type'd with */
+	short packet_type_len;		/* length of packet type */
+	int flags;			/* per-packet-type flags */
+	int sock;			/* fd for the socket */
+	long receiver;			/* receive handler */
+	char packet_type[16];		/* packet type for this handle */
+    } handle[MAX_HANDLE];
+
+    char buf[ETH_FRAME_LEN + 32];	/* packet buffer */
+};
+
+static char devname[] = "eth0";		/* linux device name */
+
+static struct pkt_globs *pg = NULL;
+
+/* initialize the packet driver interface (called at startup) */
+void
+pkt_init (int vec)
+
+{
+    register unsigned char *ptr;
+
+    /* initialize the globals */
+
+    pg = (struct pkt_globs *) PKTDRV_ADD;
+
+    memset(pg,0,sizeof(struct pkt_globs));
+
+    /* init the interrupt vector and signature */
+
+    SETIVEC(vec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,signature));
+    ptr = pg->signature;
+
+    *ptr++ = 0xeb;			/* JMP $+10, NOP, PKT DRVR */
+    *ptr++ = 0x0a;
+    *ptr++ = 0x90;
+    strcpy(ptr,"PKT DRVR");		/* signature as defined by driver spec */
+    ptr += 9;
+    *ptr++ = 0xcd;			/* 0xcd = INT */
+    *ptr++ = vec;
+    *ptr++ = 0xca;			/* 0xca = RETF xx */
+    *ptr++ = 2;
+
+    /* fill other global data */
+
+    strcpy(pg->driver_name,"Linux$");
+    GetDeviceHardwareAddress(devname,pg->hw_address);
+    pg->classes[0] = ETHER_CLASS;
+    pg->classes[1] = IEEE_CLASS;
+    pg->type = 12;			/* dummy type (3c503) */
+    pg->flags = config.pktflags;	/* global config flags */
+
+    pg->param.major_rev = 9;		/* pkt driver spec */
+    pg->param.minor_rev = 1;
+    pg->param.length = sizeof(struct pkt_param);
+    pg->param.addr_len = ETH_ALEN;
+    pg->param.mtu = GetDeviceMTU(devname);
+    pg->param.rcv_bufs = 8 - 1;		/* a guess */
+    pg->param.xmt_bufs = 2 - 1;
+
+    /* helper routine to transfer received packets and call receiver */
+
+    pg->helpvec = vec + 1;		/* use this for helper vec */
+    SETIVEC(pg->helpvec,PKTDRV_SEG,PKTDRV_OFF + offsetof(struct pkt_globs,helper));
+    ptr = pg->helper;
+
+    *ptr++ = 0x60;			/* pusha */
+    *ptr++ = 0x1e;			/* push ds */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x2e; *ptr++ = 0x8b; *ptr++ = 0x0e; /* mov cx,cs:[pg->size] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0xe3; *ptr++ = 0x31;	/* jcxz nothing */
+    *ptr++ = 0x31; *ptr++ = 0xc0;	/* xor ax,ax */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x59;			/* pop cx */
+    *ptr++ = 0x8c; *ptr++ = 0xc0;	/* mov ax,es */
+    *ptr++ = 0x09; *ptr++ = 0xf8;	/* or ax,di */
+    *ptr++ = 0x74; *ptr++ = 0x1b;	/* jz norecv */
+    *ptr++ = 0x0e;			/* push cs */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xbe;			/* mov si,pg->buf */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,buf)) >> 8;
+    *ptr++ = 0x57;			/* push di */
+    *ptr++ = 0x51;			/* push cx */
+    *ptr++ = 0xfc;			/* cld */
+    *ptr++ = 0xd1; *ptr++ = 0xe9;	/* shr cx,1 */
+    *ptr++ = 0xf3; *ptr++ = 0xa5;	/* rep movsw */
+    *ptr++ = 0x73; *ptr++ = 0x01;	/* jnc nobyte */
+    *ptr++ = 0xa4;			/* movsb */
+    *ptr++ = 0x59;			/* nobyte: pop cx */
+    *ptr++ = 0x5e;			/* pop si */
+    *ptr++ = 0x06;			/* push es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0xb8;			/* mov ax,1 */
+    *ptr++ = 0x01; *ptr++ = 0x00;
+    *ptr++ = 0x2e; *ptr++ = 0xff; *ptr++ = 0x1e; /* call cs:[pg->receiver] */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,receiver)) >> 8;
+    *ptr++ = 0x2e; *ptr++ = 0xc7; *ptr++ = 0x06; /* norecv: mov cs:[pg->size],0 */
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) & 0xff;
+    *ptr++ = (PKTDRV_OFF + offsetof(struct pkt_globs,size)) >> 8;
+    *ptr++ = 0x00; *ptr++ = 0x00;
+    *ptr++ = 0x07;			/* nothing: pop es */
+    *ptr++ = 0x1f;			/* pop ds */
+    *ptr++ = 0x61;			/* popa */
+    *ptr   = 0xcf;			/* iret */
+}
+
+/* this is the handler for INT calls from DOS to the packet driver */
+int
+pkt_int ()
+
+{
+    struct per_handle *hdlp;
+
+#if 0
+    pd_printf("NPKT: AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+#endif
+
+    /* first clear CARRY flag that we may later set (on error) */
+
+    NOCARRY;
+
+    /* when BX seems like a valid handle, set the handle info pointer */
+
+    if (LWORD(ebx) < MAX_HANDLE)
+	hdlp = &pg->handle[LWORD(ebx)];
+    else
+	hdlp = NULL;
+
+    /* switch on the packet driver function code */
+
+    switch (HI(ax))
+    {
+    case F_DRIVER_INFO:
+	REG(eax) = 2;				/* basic+extended functions */
+	REG(ebx) = 1;				/* version */
+	if (hdlp != NULL && hdlp->in_use)
+	    REG(ecx) = (hdlp->class << 8) + 1;	/* class, number */
+	else
+	    REG(ecx) = (pg->classes[0] << 8) + 1;
+	REG(edx) = pg->type;			/* type (dummy) */
+	REG(ds) = PKTDRV_SEG;			/* driver name */
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,driver_name);
+	return 1;
+
+    case F_ACCESS_TYPE:
+	if (strchr(pg->classes,LO(ax)) == NULL) { /* check if_class */
+	    HI(dx) = E_NO_CLASS;
+	    break;
+	}
+	if (LWORD(ebx) != 0xffff && LWORD(ebx) != pg->type) { /* check if_type */
+	    HI(dx) = E_NO_TYPE;
+	    break;
+	}
+	if (LO(dx) != 0 && LO(dx) != 1) {	/* check if_number */
+	    HI(dx) = E_NO_NUMBER;
+	    break;
+	}
+	if (LWORD(ecx) > sizeof(pg->handle[0].packet_type)) { /* check len */
+	    HI(dx) = E_BAD_TYPE;
+	    break;
+	}
+	/* now check if the type is not already in use, and find a free */
+	/* handle to use for this request */
+	{
+	    int free_handle = -1;
+	    int handle;
+	    unsigned short type;
+
+	    if (LWORD(ecx) == 0)		/* pass-all type? */
+		handle = MAX_HANDLE - 1;	/* always put it last */
+	    else
+		handle = 0;			/* else search from 1st */
+
+	    for (; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (hdlp->class == LO(ax) && /* same class? */
+			!memcmp(hdlp->packet_type, /* same type? (prefix) */
+				SEG_ADR((char *),ds,si),
+				min(LWORD(ecx),hdlp->packet_type_len)))
+		    {
+			HI(dx) = E_TYPE_INUSE;
+			CARRY;
+			return 1;
+		    }
+		} else {
+		    if (free_handle == -1)
+			free_handle = handle;	/* remember free handle */
+		}
+	    }
+
+	    /* now see if we found a free handle, and allocate it */
+	    if (free_handle == -1) {
+		HI(dx) = E_NO_SPACE;
+		break;
+	    }
+
+	    hdlp = &pg->handle[free_handle];
+	    memset(hdlp,0,sizeof(struct per_handle));
+	    hdlp->in_use = 1;
+	    hdlp->receiver = (LWORD(es) << 16) | LWORD(edi);
+	    hdlp->packet_type_len = LWORD(ecx);
+	    memcpy(hdlp->packet_type,SEG_ADR((char *),ds,si),LWORD(ecx));
+	    hdlp->class = LO(ax);
+
+	    if (hdlp->class == IEEE_CLASS)
+		type = ETH_P_802_3;
+	    else {
+		if (hdlp->packet_type_len < 2)
+		    type = ETH_P_ALL;		/* get all packet types */
+		else {
+		    type = (hdlp->packet_type[0] << 8) |
+			   ((unsigned char) hdlp->packet_type[1]);
+
+		    switch (type)
+		    {
+		    case 0:			/* sometimes this bogus type */
+			type = ETH_P_802_3;	/* is used for status calls.. */
+			break;
+
+		    case ETH_P_IPX:
+			if (hdlp->packet_type_len == 2 &&
+			    (pg->flags & N_OPTION)) /* Novell hack? */
+			{
+			    hdlp->flags |= N_OPTION;
+			    hdlp->packet_type[0] = hdlp->packet_type[1] = 0xff;
+			    hdlp->class = IEEE_CLASS;
+			    type = ETH_P_802_3;
+			}
+			break;
+		    }
+		}
+	    }
+
+	    hdlp->sock = OpenNetworkType(type); /* open the socket */
+
+	    if (hdlp->sock < 0) {
+		hdlp->in_use = 0;		/* forget about this handle */
+		HI(dx) = E_BAD_TYPE;
+		break;
+	    }
+
+	    FD_SET(hdlp->sock,&pg->sockset);	/* keep track of sockets */
+	    add_to_io_select(hdlp->sock, 1);
+	    if (hdlp->sock >= pg->nfds)
+		pg->nfds = hdlp->sock + 1;
+
+	    REG(eax) = free_handle;		/* return the handle */
+	}
+	return 1;
+
+    case F_RELEASE_TYPE:
+	if (hdlp == NULL) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+
+	if (hdlp->in_use) {
+	    int i,n;
+
+	    CloseNetworkLink(hdlp->sock);	/* close the socket */
+	    FD_CLR(hdlp->sock,&pg->sockset);	/* keep track of sockets */
+	    remove_from_io_select(hdlp->sock, 1);
+	    n = pg->nfds;
+	    pg->nfds = 0;
+
+	    for (i = 0; i < n; i++)
+		if (FD_ISSET(i,&pg->sockset))
+		    pg->nfds = i + 1;
+
+	    hdlp->in_use = 0;			/* no longer in use */
+	}
+	return 1;
+
+    case F_SEND_PKT:
+	pg->stats.packets_out++;
+	pg->stats.bytes_out += LWORD(ecx);
+
+	/* unfortunately, a handle is not passed as a parameter for the */
+	/* SEND_PKT call.  so, we will have to scan the handle table to */
+	/* find a handle which is in use, and use its socket for the send */
+	{
+	    int handle;
+
+	    for (handle = 0; handle < MAX_HANDLE; handle++) {
+		hdlp = &pg->handle[handle];
+
+		if (hdlp->in_use) {
+		    if (pg->flags & N_OPTION)	/* Novell hack? */
+		    {
+			char *p;
+			short len;
+
+			p = SEG_ADR((char *),ds,si);
+			p += 2 * ETH_ALEN;	/* point to protocol type */
+
+			if (p[0] == (char)(ETH_P_IPX >> 8) &&
+			    p[1] == (char)ETH_P_IPX &&
+			    p[2] == (char)0xff && p[3] == (char)0xff)
+			{
+			    /* it is a Novell Ethernet-II packet, make it */
+			    /* "raw 802.3" by overwriting type with length */
+
+			    len = (p[4] << 8) | (unsigned char)p[5];
+			    len = (len + 1) & ~1; /* make length even */
+			    p[0] = len >> 8;
+			    p[1] = (char)len;
+			}
+		    }
+
+		    if (WriteToNetwork(hdlp->sock,devname,
+				SEG_ADR((char *),ds,si),LWORD(ecx)) >= 0)
+		    {
+			/* send was okay, check for a reply to speedup */
+			/* things (background poll is quite slow) */
+			pkt_check_receive(50000);
+			return 1;
+		    } else {
+			warn("NPKT: WriteToNetwork(%d,\"%s\",buffer,%u): error %d\n",
+			    hdlp->sock,devname,LWORD(ecx),errno);
+			break;
+		    }
+		}
+	    }
+
+	    pg->stats.errors_out++;
+	    HI(dx) = E_CANT_SEND;
+	}
+	break;
+
+    case F_TERMINATE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_TERM;
+
+	break;
+
+    case F_GET_ADDRESS:
+	if (LWORD(ecx) < ETH_ALEN) {
+	    HI(dx) = E_NO_SPACE;
+	    break;
+	}
+	REG(ecx) = ETH_ALEN;
+	memcpy(SEG_ADR((char *),es,di),pg->hw_address,ETH_ALEN);
+	return 1;
+
+    case F_RESET_IFACE:
+	if (hdlp == NULL || !hdlp->in_use)
+	    HI(dx) = E_BAD_HANDLE;
+	else
+	    HI(dx) = E_CANT_RESET;
+
+	break;
+
+    case F_GET_PARAMS:
+	REG(es) = PKTDRV_SEG;
+	REG(edi) = PKTDRV_OFF + offsetof(struct pkt_globs,param);
+	return 1;
+
+    case F_SET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	if (LWORD(ecx) != 3) {			/* only mode 3 supported */
+	    HI(dx) = E_BAD_MODE;
+	    break;
+	}
+	return 1;
+
+    case F_GET_RCV_MODE:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(eax) = 3;
+	return 1;
+
+    case F_GET_STATS:
+	if (hdlp == NULL || !hdlp->in_use) {
+	    HI(dx) = E_BAD_HANDLE;
+	    break;
+	}
+	REG(ds) = PKTDRV_SEG;
+	REG(esi) = PKTDRV_OFF + offsetof(struct pkt_globs,stats);
+	return 1;
+
+    default:
+	/* unhandled function, indicate an error */
+
+	HI(dx) = E_BAD_COMMAND;
+	break;
+    }
+
+    /* fell through switch, indicate an error (DH set above) */
+    CARRY;
+
+#if 0
+    pd_printf("ERR:  AX=%04x BX=%04x CX=%04x DX=%04x FLAGS=%08x\n",
+		LWORD(eax),LWORD(ebx),LWORD(ecx),LWORD(edx),REG(eflags));
+    pd_printf("      SI=%04x DI=%04x BP=%04x SP=%04x CS=%04x DS=%04x ES=%04x SS=%04x\n",
+		LWORD(esi),LWORD(edi),LWORD(ebp),LWORD(esp),
+		LWORD(cs),LWORD(ds),LWORD(es),LWORD(ss));
+#endif
+
+    return 1;
+}
+
+int
+pkt_check_receive(timeout)
+int timeout;
+
+{
+    int size,handle;
+    struct per_handle *hdlp;
+    char *p;
+    struct timeval tv;
+    fd_set readset;
+    char device[32];
+
+    if (pg == NULL)				/* packet driver intialized? */
+	return -1;
+
+    if (pg->nfds == 0)				/* no active sockets? */
+	return 0;
+
+    if (pg->size != 0)				/* transfer area busy? */
+	return 1;
+
+    tv.tv_sec = 0;				/* set a (small) timeout */
+    tv.tv_usec = timeout;
+    readset = pg->sockset;
+
+    if (select(pg->nfds,&readset,NULL,NULL,&tv) <= 0) /* anything ready? */
+	return 0;
+
+    for (handle = 0; handle < MAX_HANDLE; handle++) {
+	hdlp = &pg->handle[handle];
+
+	if (hdlp->in_use && FD_ISSET(hdlp->sock,&readset)) {
+	    /* somethine is available on this handle's socket */
+	    /* attempt to read it.  that should always succeed... */
+
+	    size = ReadFromNetwork(hdlp->sock,device,pg->buf,sizeof(pg->buf));
+
+	    /* check if something has been received */
+	    /* there was a check for "not multicast" here, but I think */
+	    /* it should not be there... */
+
+	    if (size >= 0) {
+		/* verify the source of the packet.  when not from eth0, */
+		/* discard it for now (multiple network cards are next) */
+
+		if (strcmp(device,devname))
+		    continue;
+
+		/* check if the packet's type matches the specified type */
+		/* in the ACCESS_TYPE call.  the position depends on the */
+		/* driver class! */
+
+		if (hdlp->class == ETHER_CLASS)
+		    p = pg->buf + 2 * ETH_ALEN;		/* Ethernet-II */
+		else
+		    p = pg->buf + 2 * ETH_ALEN + 2;	/* IEEE 802.3 */
+
+		if (size >= ((p - pg->buf) + hdlp->packet_type_len) &&
+		    !memcmp(p,hdlp->packet_type,hdlp->packet_type_len))
+		{
+		    pg->stats.packets_in++;
+		    pg->stats.bytes_in += size;
+
+		    if (hdlp->flags & N_OPTION) {	/* Novell hack? */
+			*--p = (char)ETH_P_IPX;	/* overwrite length with type */
+			*--p = (char)(ETH_P_IPX >> 8);
+		    }
+
+		    /* stuff things in global vars and queue a hardware */
+		    /* interrupt which will perform the upcall */
+		    pg->size = size;
+		    pg->receiver = hdlp->receiver;
+		    run_int(pg->helpvec);
+		    return 1;
+		} else
+		    pg->stats.packets_lost++;	/* not really lost... */
+	    } else
+		pg->stats.errors_in++;		/* select() somehow lied */
+	}
+    }
+
+    return 0;
+}
Binary files dosemu0.53.51/periph/hdinfo and dosemu0.53.52/periph/hdinfo differ
Binary files dosemu0.53.51/periph/mkhdimage and dosemu0.53.52/periph/mkhdimage differ
Binary files dosemu0.53.51/periph/putrom and dosemu0.53.52/periph/putrom differ
diff -u --recursive --new-file dosemu0.53.51/pic/pic.c dosemu0.53.52/pic/pic.c
--- dosemu0.53.51/pic/pic.c	Tue Mar 14 18:57:13 1995
+++ dosemu0.53.52/pic/pic.c	Fri Mar 17 22:02:10 1995
@@ -70,24 +70,23 @@
                       {PNULL,0x00}, {PNULL,0x00}, {PNULL,0x00}, {PNULL,0x00},
                       {PNULL,0x00}, {PNULL,0x00}, {PNULL,0x00}, {PNULL,0x00}};   
 /*
-
-run_irq)        checks for and runs any interrupts requested in pic_irr
-do_irq()          runs the dos interrupt for the current irq
-set_pic0_imr()  sets pic0 interrupt mask register       \\
-set_pic1_imr()  sets pic1 interrupt mask register       ||
-get_pic0_imr()  returns pic0 interrupt mask register    ||
-get_pic1_imr()  returns pic1 interrupt mask register    || called by read_
-get_pic0_isr()  returns pic0 in-service register        || and write_ picX
-get_pic1_isr()  returns pic1 in-service register        ||
-get_pic0_irr()  returns pic0 interrupt request register ||
-get_pic1_irr()  returns pic1 interrupt request register ||
-set_pic0_base() sets base interrupt for irq0 - irq7     ||
-set_pic1_base() sets base interrupt for irq8 - irq15    //
-write_pic0()    processes write to pic0 i/o 
-write_pic1()    processes write to pic1 i/o
-read_pic0()     processes read from pic0 i/o
-read_pic1()     processes read from pic1 i/o
-                                                                     */
+ * run_irq()       checks for and runs any interrupts requested in pic_irr
+ * do_irq()        runs the dos interrupt for the current irq
+ * set_pic0_imr()  sets pic0 interrupt mask register       \\
+ * set_pic1_imr()  sets pic1 interrupt mask register       ||
+ * get_pic0_imr()  returns pic0 interrupt mask register    ||
+ * get_pic1_imr()  returns pic1 interrupt mask register    || called by read_
+ * get_pic0_isr()  returns pic0 in-service register        || and write_ picX
+ * get_pic1_isr()  returns pic1 in-service register        ||
+ * get_pic0_irr()  returns pic0 interrupt request register ||
+ * get_pic1_irr()  returns pic1 interrupt request register ||
+ * set_pic0_base() sets base interrupt for irq0 - irq7     ||
+ * set_pic1_base() sets base interrupt for irq8 - irq15    //
+ * write_pic0()    processes write to pic0 i/o 
+ * write_pic1()    processes write to pic1 i/o
+ * read_pic0()     processes read from pic0 i/o
+ * read_pic1()     processes read from pic1 i/o
+ */
 
 #define set_pic0_imr(x) pic0_imr=pic0_to_emu(x);pic_set_mask
 #define set_pic1_imr(x) pic1_imr=(((long)x)<<3);pic_set_mask
@@ -106,37 +105,41 @@
 static unsigned char pic0_cmd; /* 0-3=>last port 0 write was none,ICW1,OCW2,3*/
 static unsigned char pic1_cmd;
                     
+
 void set_pic0_base(int_num)
 unsigned char int_num;
 {
-unsigned char int_n;
-int_n        = int_num & 0xf8;         /* it's not worth doing a loop */
-pic_iinfo[1].ivec  = int_n++;  /* irq  0 */
-pic_iinfo[2].ivec  = int_n++;  /* irq  1 */
-pic_irq2_ivec      = int_n++;  /* irq  2 */
-pic_iinfo[11].ivec = int_n++;  /* irq  3 */
-pic_iinfo[12].ivec = int_n++;  /* irq  4 */
-pic_iinfo[13].ivec = int_n++;  /* irq  5 */
-pic_iinfo[14].ivec = int_n++;  /* irq  6 */
-pic_iinfo[15].ivec = int_n;    /* irq  7 */
-return;
+  unsigned char int_n;
+  int_n        = int_num & 0xf8;         /* it's not worth doing a loop */
+  pic_iinfo[1].ivec  = int_n++;  /* irq  0 */
+  pic_iinfo[2].ivec  = int_n++;  /* irq  1 */
+  pic_irq2_ivec      = int_n++;  /* irq  2 */
+  pic_iinfo[11].ivec = int_n++;  /* irq  3 */
+  pic_iinfo[12].ivec = int_n++;  /* irq  4 */
+  pic_iinfo[13].ivec = int_n++;  /* irq  5 */
+  pic_iinfo[14].ivec = int_n++;  /* irq  6 */
+  pic_iinfo[15].ivec = int_n;    /* irq  7 */
+  return;
 }
 
+
 void set_pic1_base(int_num)
 unsigned char int_num;
 {
-unsigned char int_n;
-int_n        = int_num & 0xf8;         /* it's not worth doing a loop */
-pic_iinfo[3].ivec  = int_n++;  /* irq  8 */
-pic_iinfo[4].ivec  = int_n++;  /* irq  9 */
-pic_iinfo[5].ivec  = int_n++;  /* irq 10 */
-pic_iinfo[6].ivec  = int_n++;  /* irq 11 */
-pic_iinfo[7].ivec  = int_n++;  /* irq 12 */
-pic_iinfo[8].ivec  = int_n++;  /* irq 13 */
-pic_iinfo[9].ivec  = int_n++;  /* irq 14 */
-pic_iinfo[10].ivec = int_n;    /* irq 15 */
-return;
+  unsigned char int_n;
+  int_n        = int_num & 0xf8;         /* it's not worth doing a loop */
+  pic_iinfo[3].ivec  = int_n++;  /* irq  8 */
+  pic_iinfo[4].ivec  = int_n++;  /* irq  9 */
+  pic_iinfo[5].ivec  = int_n++;  /* irq 10 */
+  pic_iinfo[6].ivec  = int_n++;  /* irq 11 */
+  pic_iinfo[7].ivec  = int_n++;  /* irq 12 */
+  pic_iinfo[8].ivec  = int_n++;  /* irq 13 */
+  pic_iinfo[9].ivec  = int_n++;  /* irq 14 */
+  pic_iinfo[10].ivec = int_n;    /* irq 15 */
+  return;
 }
+
+
 /* DANG_BEGIN_FUNCTION write_pic0,write_pic1
  *
  * write_pic_0() and write_pic1() implement dos writes to the pic ports.
@@ -151,8 +154,9 @@
 unsigned char port,value;
 {
 
-/* if port == 0 this must be either an ICW1, OCW2, or OCW3 */
-/* if port == 1 this must be either ICW2, ICW3, ICW4, or load IMR */
+/* if port == 0 this must be either an ICW1, OCW2, or OCW3
+ * if port == 1 this must be either ICW2, ICW3, ICW4, or load IMR 
+ */
 
 #if 0
 static char  icw_state,              /* !=0 => port 1 does icw 2,3,(4) */
@@ -192,12 +196,13 @@
   }
 }  
 
+
 void write_pic1(port,value)
 unsigned char port,value;
 {
 /* if port == 0 this must be either an ICW1, OCW2, or OCW3 */
 /* if port == 1 this must be either ICW2, ICW3, ICW4, or load IMR */
-static char /* icw_state,       /* !=0 => port 1 does icw 2,3,(4) */
+static char /* icw_state, */     /* !=0 => port 1 does icw 2,3,(4) */
                icw_max_state;    /* number of icws expected        */
 
 if(!port){                            /* icw1, ocw2, ocw3 */
@@ -230,6 +235,8 @@
        if(pic1_icw_state++ >= icw_max_state) pic1_icw_state=0; 
   }
 }  
+
+
 /* DANG_BEGIN_FUNCTION read_pic0,read_pic1
  *
  * read_pic0 and read_pic1 return the values for the interrupt mask register
@@ -240,7 +247,6 @@
  *
  * DANG_END_FUNCTION
  */
-
 unsigned char read_pic0(port)
 unsigned char port;
 {
@@ -249,6 +255,7 @@
                          return((unsigned char)get_pic0_irr());
 }
 
+
 unsigned char read_pic1(port)
 unsigned char port;
 {
@@ -257,6 +264,7 @@
                          return((unsigned char)get_pic1_irr());
 }
 
+
 /* DANG_BEGIN_FUNCTION pic_mask,pic_unmask
  *
  * The pic maintains an additional interrupt mask which is not visible
@@ -268,7 +276,6 @@
  *
  * DANG_END_FUNCTION
  */
- 
 void pic_unmaski(level)
 int level;
 {
@@ -282,6 +289,8 @@
 {
   set_bit(level,&pice_imr);
 }
+
+
 /* DANG_BEGIN_FUNCTION pic_seti
  *
  * pic_seti is used to initialize an interrupt for dosemu.  It requires
@@ -295,21 +304,22 @@
  *
  * DANG_END_FUNCTION
  */
-   
-
 void pic_seti(level,func,ivec)
 unsigned int level,ivec;
 void (*func);
 {
- if(level>=32) return;
- pic_iinfo[level].func = func;
- if(level>16) pic_iinfo[level].ivec = ivec;
- if(func == (void*)0) pic_maski(level);
+  if(level>=32) return;
+  pic_iinfo[level].func = func;
+  if(level>16) pic_iinfo[level].ivec = ivec;
+  if(func == (void*)0) pic_maski(level);
 }
 
-/* this is the guts if the irq processor. it should be called from an
-  if:   if(pic_irr) run_irqs();   This will maximize speed  */
 
+/* this is the guts if the irq processor. it should be called from an if:
+ * if(pic_irr) run_irqs();     
+ * This will maximize speed.
+ */
+ 
 /* DANG_BEGIN_FUNCTION run_irqs
  *
  * run_irqs, which is initiated via the macro pic_run, is the "brains" of
@@ -324,7 +334,6 @@
  *
  * DANG_END_FUNCTION
  */
-
 #ifdef C_RUN_IRQS
 /* see assembly language version below */
 void run_irqs()
@@ -335,11 +344,12 @@
 #warning using C run_irqs
 
 /* check for and find any requested irqs.  Having found one, we atomic-ly
-   clear it and verify it was there when we cleared it.  If it wasn't, we
-   look for the next request.  There are two in_service bits for pic1 irqs.
-   This is needed, because irq 8-15 must do 2 outb20s, which, if the dos
-   irq code actually runs, will reset the bits.  We also reset them here,
-   since dos code won't necessarily run.  */
+ * clear it and verify it was there when we cleared it.  If it wasn't, we
+ * look for the next request.  There are two in_service bits for pic1 irqs.
+ * This is needed, because irq 8-15 must do 2 outb20s, which, if the dos
+ * irq code actually runs, will reset the bits.  We also reset them here,
+ * since dos code won't necessarily run.  
+ */
    
 #if 0
  if(!(pic_irr&~(pic_isr|pic_imr))) return;     /* exit if nothing to do */
@@ -375,11 +385,12 @@
 
 #else
 
-/* I got inspired.  Here's an assembly language version, somewhat faster. */
-/* This is also much shorter - fewer checks needed, because there's no
-   question of compiler behavior, and less code because we can use both 
-   results and flags from an instruction . */
-/* RE-ENTRANT CODE - uses 16 bytes of stack */
+/* I got inspired.  Here's an assembly language version, somewhat faster.
+ * This is also much shorter - fewer checks needed, because there's no
+ * question of compiler behavior, and less code because we can use both 
+ * results and flags from an instruction.
+ * RE-ENTRANT CODE - uses 16 bytes of stack
+ */
 void run_irqs()
 {
 
@@ -421,7 +432,6 @@
 #endif
                
    
-
 /* DANG_BEGIN_FUNCTION do_irq
  *
  *  do_irq() calls the correct do_int().
@@ -431,9 +441,9 @@
  *  Returns: 0 = complete, 1 = interrupt not run because it directly
  *  calls our "bios"   See run_timer_tick() in timer.c for an example
  *  To assure notification when the irq completes, we push flags, ip, and cs
- *  here and fake cs:ip to INTE8_[SEG,OFF].  This makes the irq call
- *  interrupt e8 (which calls pic_return) when it completes.  int e8
- *  then pops the real cs:ip from the stack.
+ *  here and fake cs:ip to PIC_[SEG,OFF], where there is a hlt.  This makes 
+ *  the irq generate a sigsegv, which calls pic_iret when it completes.
+ *  pic_iret then pops the real cs:ip from the stack.
  *  This routine is RE-ENTRANT - it calls run_irqs, which
  *  which may call an interrupt routine,
  *  which may call do_irq().  Be Careful!  !!!!!!!!!!!!!!!!!! 
@@ -473,8 +483,8 @@
       tmp[1] = REG(cs);
       tmp[0] = LWORD(eip);
       LWORD(esp) -= 6;
-      REG(cs) = INTE8_SEG;
-      LWORD(eip) = INTE8_OFF;
+      REG(cs) = PIC_SEG;
+      LWORD(eip) = PIC_OFF;
       
       run_int(intr);
      }
@@ -514,6 +524,7 @@
 #endif
 }
 
+
 /* DANG_BEGIN_FUNCTION pic_request
  *
  * pic_request triggers an interrupt.  There is presently no way to
@@ -529,27 +540,25 @@
  *
  * DANG_END_FUNCTION
  */
-
-
-void
-pic_request(inum)
+void pic_request(inum)
 int inum;
 {
- if (pic_iinfo[inum].func == (void *)0) {
-	return; 
- }
- if(pic_isr&(1<<inum) || inum==pic_ilevel){
- 	pic_pirr|=(1<<inum);
- }
- else {
-	pic_irr|=(1<<inum);
- }
+  if (pic_iinfo[inum].func == (void *)0)
+    return; 
+ 
+  if(pic_isr&(1<<inum) || inum==pic_ilevel)
+    pic_pirr|=(1<<inum);
+  else
+    pic_irr|=(1<<inum);
+
 #ifdef DPMI
- if (in_dpmi)
-   D_printf("DPMI: pic_request(0x%02x) set isr=%x, irr=%x\n", inum, pic_isr, pic_irr);
+  if (in_dpmi) D_printf("DPMI: pic_request(0x%02x) set isr=%x, irr=%x\n", inum, pic_isr, pic_irr);
 #endif
- return;
+
+  return;
 }
+
+
 /* DANG_BEGIN_FUNCTION pic_iret
  *
  * pic_iret is used to sense that all active interrupts are really complete,
@@ -598,10 +607,10 @@
         pic_wirr&=~pic_irr;		/* clear watchdog timer */
         REG(eflags)&=~(VIP);
     }
-/* if return is to int 0xe8, pop the real cs:ip */
-    if(tmp[0] == INTE8_SEG && tmp[1] == INTE8_OFF) {
-      LWORD(eip) == tmp[3];
-      REG(cs) == tmp[4];
+/* if return is to PIC_ADD, pop the real cs:ip */
+    if(tmp[0] == PIC_OFF && tmp[1] == PIC_SEG) {
+      LWORD(eip) = tmp[3];
+      REG(cs) = tmp[4];
       LWORD(esp) += 6;
       }
     }
@@ -608,40 +617,6 @@
  return;
 }
 
-/* DANG_BEGIN_FUNCTION pic_return
- * pic_return is called by interrupt e8.  It does the same thing as pic_iret,
- * but expects cs:ip pointing to INTE8_ [SEG,OFF] instead.  
- * DPMI never calls this function since it uses his own stackframe to indicate
- * an iret.
- */
-void
-pic_return()
-{
-unsigned short * tmp;
-
-/* if we've come from the right place, cs:ip will point to the BIOS */
-tmp = SEG_ADR((short *),ss,sp)-3;
- if (INTE8_SEG == REG(cs)) 
-  if(INTE8_OFF+2 == LWORD(eip)) {
-    if(pic_icount) 
-      if(!(--pic_icount)) {
-        pic_irr|=(pic_pirr&~pic_isr);
-        pic_pirr&=~pic_irr;
-        pic_wirr&=~pic_irr;		/* clear watchdog timer */
-        REG(eflags)&=~(VIP);
-    }
-/* simulate an iret (without the flags - they should be OK) */
-/* Note that this stuff was pushed on the stack before the irq began */
-    if(tmp[0] == INTE8_SEG && tmp[1] == INTE8_OFF) {
-      LWORD(eip) == tmp[3];
-      REG(cs) == tmp[4];
-      LWORD(esp) += 6;
-      }
-   }     
- return;
-}
-
-
  
 /* DANG_BEGIN_FUNCTION pic_watch
  *
@@ -652,18 +627,15 @@
  *
  * DANG_END_FUNCTION
  */
-  
-
-
-inline void 
-pic_watch()
+inline void pic_watch()
 {
-        pic_irr|=(pic_wirr&~pic_isr);	/* activate anything still pending */
-        pic_pirr&=~pic_irr;
-        pic_wirr&=~pic_irr;
-        pic_wirr|=pic_pirr;   	/* set a new pending list for next time    */
+  pic_irr|=(pic_wirr&~pic_isr);   /* activate anything still pending */
+  pic_pirr&=~pic_irr;
+  pic_wirr&=~pic_irr;
+  pic_wirr|=pic_pirr;   	  /* set a new pending list for next time */
 }      
 
+
 /* DANG_BEGIN_FUNCTION do_irq0
  *
  * This is the routine for timer interrupts.  It simply calls pic_watch(),
@@ -671,8 +643,7 @@
  *
  * DANG_END_FUNCTION
  */
-void
-do_irq0()
+void do_irq0()
 {
 	pic_watch();
 	do_irq();
