Home | History | Annotate | Download | only in msdos
      1 /*
      2  *  File.........: pktdrvr.c
      3  *
      4  *  Responsible..: Gisle Vanem,  giva (at) bgnett.no
      5  *
      6  *  Created......: 26.Sept 1995
      7  *
      8  *  Description..: Packet-driver interface for 16/32-bit C :
      9  *                 Borland C/C++ 3.0+ small/large model
     10  *                 Watcom C/C++ 11+, DOS4GW flat model
     11  *                 Metaware HighC 3.1+ and PharLap 386|DosX
     12  *                 GNU C/C++ 2.7+ and djgpp 2.x extender
     13  *
     14  *  References...: PC/TCP Packet driver Specification. rev 1.09
     15  *                 FTP Software Inc.
     16  *
     17  */
     18 
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <dos.h>
     23 
     24 #include "pcap-dos.h"
     25 #include "pcap-int.h"
     26 #include "msdos/pktdrvr.h"
     27 
     28 #if (DOSX)
     29 #define NUM_RX_BUF  32      /* # of buffers in Rx FIFO queue */
     30 #else
     31 #define NUM_RX_BUF  10
     32 #endif
     33 
     34 #define DIM(x)   (sizeof((x)) / sizeof(x[0]))
     35 #define PUTS(s)  do {                                           \
     36                    if (!pktInfo.quiet)                          \
     37                       pktInfo.error ?                           \
     38                         printf ("%s: %s\n", s, pktInfo.error) : \
     39                         printf ("%s\n", pktInfo.error = s);     \
     40                  } while (0)
     41 
     42 #if defined(__HIGHC__)
     43   extern UINT _mwenv;
     44 
     45 #elif defined(__DJGPP__)
     46   #include <stddef.h>
     47   #include <dpmi.h>
     48   #include <go32.h>
     49   #include <pc.h>
     50   #include <sys/farptr.h>
     51 
     52 #elif defined(__WATCOMC__)
     53   #include <i86.h>
     54   #include <stddef.h>
     55   extern char _Extender;
     56 
     57 #else
     58   extern void far PktReceiver (void);
     59 #endif
     60 
     61 
     62 #if (DOSX & (DJGPP|DOS4GW))
     63   #include <sys/pack_on.h>
     64 
     65   struct DPMI_regs {
     66          DWORD  r_di;
     67          DWORD  r_si;
     68          DWORD  r_bp;
     69          DWORD  reserved;
     70          DWORD  r_bx;
     71          DWORD  r_dx;
     72          DWORD  r_cx;
     73          DWORD  r_ax;
     74          WORD   r_flags;
     75          WORD   r_es, r_ds, r_fs, r_gs;
     76          WORD   r_ip, r_cs, r_sp, r_ss;
     77        };
     78 
     79   /* Data located in a real-mode segment. This becomes far at runtime
     80    */
     81   typedef struct  {          /* must match data/code in pkt_rx1.s */
     82           WORD       _rxOutOfs;
     83           WORD       _rxInOfs;
     84           DWORD      _pktDrop;
     85           BYTE       _pktTemp [20];
     86           TX_ELEMENT _pktTxBuf[1];
     87           RX_ELEMENT _pktRxBuf[NUM_RX_BUF];
     88           WORD       _dummy[2];        /* screenSeg,newInOffset */
     89           BYTE       _fanChars[4];
     90           WORD       _fanIndex;
     91           BYTE       _PktReceiver[15]; /* starts on a paragraph (16byte) */
     92         } PktRealStub;
     93   #include <sys/pack_off.h>
     94 
     95   static BYTE real_stub_array [] = {
     96          #include "pkt_stub.inc"       /* generated opcode array */
     97        };
     98 
     99   #define rxOutOfs      offsetof (PktRealStub,_rxOutOfs)
    100   #define rxInOfs       offsetof (PktRealStub,_rxInOfs)
    101   #define PktReceiver   offsetof (PktRealStub,_PktReceiver [para_skip])
    102   #define pktDrop       offsetof (PktRealStub,_pktDrop)
    103   #define pktTemp       offsetof (PktRealStub,_pktTemp)
    104   #define pktTxBuf      offsetof (PktRealStub,_pktTxBuf)
    105   #define FIRST_RX_BUF  offsetof (PktRealStub,_pktRxBuf [0])
    106   #define LAST_RX_BUF   offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1])
    107 
    108 #else
    109   extern WORD       rxOutOfs;    /* offsets into pktRxBuf FIFO queue   */
    110   extern WORD       rxInOfs;
    111   extern DWORD      pktDrop;     /* # packets dropped in PktReceiver() */
    112   extern BYTE       pktRxEnd;    /* marks the end of r-mode code/data  */
    113 
    114   extern RX_ELEMENT pktRxBuf [NUM_RX_BUF];       /* PktDrvr Rx buffers */
    115   extern TX_ELEMENT pktTxBuf;                    /* PktDrvr Tx buffer  */
    116   extern char       pktTemp[20];                 /* PktDrvr temp area  */
    117 
    118   #define FIRST_RX_BUF (WORD) &pktRxBuf [0]
    119   #define LAST_RX_BUF  (WORD) &pktRxBuf [NUM_RX_BUF-1]
    120 #endif
    121 
    122 
    123 #ifdef __BORLANDC__           /* Use Borland's inline functions */
    124   #define memcpy  __memcpy__
    125   #define memcmp  __memcmp__
    126   #define memset  __memset__
    127 #endif
    128 
    129 
    130 #if (DOSX & PHARLAP)
    131   extern void PktReceiver (void);     /* in pkt_rx0.asm */
    132   static int  RealCopy    (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*);
    133 
    134   #undef  FP_SEG
    135   #undef  FP_OFF
    136   #define FP_OFF(x)     ((WORD)(x))
    137   #define FP_SEG(x)     ((WORD)(realBase >> 16))
    138   #define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o))
    139   #define r_ax          eax
    140   #define r_bx          ebx
    141   #define r_dx          edx
    142   #define r_cx          ecx
    143   #define r_si          esi
    144   #define r_di          edi
    145   #define r_ds          ds
    146   #define r_es          es
    147   LOCAL FARPTR          protBase;
    148   LOCAL REALPTR         realBase;
    149   LOCAL WORD            realSeg;   /* DOS para-address of allocated area */
    150   LOCAL SWI_REGS        reg;
    151 
    152   static WORD _far *rxOutOfsFp, *rxInOfsFp;
    153 
    154 #elif (DOSX & DJGPP)
    155   static _go32_dpmi_seginfo rm_mem;
    156   static __dpmi_regs        reg;
    157   static DWORD              realBase;
    158   static int                para_skip = 0;
    159 
    160   #define DOS_ADDR(s,o)     (((WORD)(s) << 4) + (o))
    161   #define r_ax              x.ax
    162   #define r_bx              x.bx
    163   #define r_dx              x.dx
    164   #define r_cx              x.cx
    165   #define r_si              x.si
    166   #define r_di              x.di
    167   #define r_ds              x.ds
    168   #define r_es              x.es
    169 
    170 #elif (DOSX & DOS4GW)
    171   LOCAL struct DPMI_regs    reg;
    172   LOCAL WORD                rm_base_seg, rm_base_sel;
    173   LOCAL DWORD               realBase;
    174   LOCAL int                 para_skip = 0;
    175 
    176   LOCAL DWORD dpmi_get_real_vector (int intr);
    177   LOCAL WORD  dpmi_real_malloc     (int size, WORD *selector);
    178   LOCAL void  dpmi_real_free       (WORD selector);
    179   #define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o))
    180 
    181 #else              /* real-mode Borland etc. */
    182   static struct  {
    183          WORD r_ax, r_bx, r_cx, r_dx, r_bp;
    184          WORD r_si, r_di, r_ds, r_es, r_flags;
    185        } reg;
    186 #endif
    187 
    188 #ifdef __HIGHC__
    189   #pragma Alias (pktDrop,    "_pktDrop")
    190   #pragma Alias (pktRxBuf,   "_pktRxBuf")
    191   #pragma Alias (pktTxBuf,   "_pktTxBuf")
    192   #pragma Alias (pktTemp,    "_pktTemp")
    193   #pragma Alias (rxOutOfs,   "_rxOutOfs")
    194   #pragma Alias (rxInOfs,    "_rxInOfs")
    195   #pragma Alias (pktRxEnd,   "_pktRxEnd")
    196   #pragma Alias (PktReceiver,"_PktReceiver")
    197 #endif
    198 
    199 
    200 PUBLIC PKT_STAT    pktStat;    /* statistics for packets    */
    201 PUBLIC PKT_INFO    pktInfo;    /* packet-driver information */
    202 
    203 PUBLIC PKT_RX_MODE receiveMode  = PDRX_DIRECT;
    204 PUBLIC ETHER       myAddress    = {   0,  0,  0,  0,  0,  0 };
    205 PUBLIC ETHER       ethBroadcast = { 255,255,255,255,255,255 };
    206 
    207 LOCAL  struct {             /* internal statistics */
    208        DWORD  tooSmall;     /* size < ETH_MIN */
    209        DWORD  tooLarge;     /* size > ETH_MAX */
    210        DWORD  badSync;      /* count_1 != count_2 */
    211        DWORD  wrongHandle;  /* upcall to wrong handle */
    212      } intStat;
    213 
    214 /***************************************************************************/
    215 
    216 PUBLIC const char *PktGetErrorStr (int errNum)
    217 {
    218   static const char *errStr[] = {
    219                     "",
    220                     "Invalid handle number",
    221                     "No interfaces of specified class found",
    222                     "No interfaces of specified type found",
    223                     "No interfaces of specified number found",
    224                     "Bad packet type specified",
    225                     "Interface does not support multicast",
    226                     "Packet driver cannot terminate",
    227                     "Invalid receiver mode specified",
    228                     "Insufficient memory space",
    229                     "Type previously accessed, and not released",
    230                     "Command out of range, or not implemented",
    231                     "Cannot send packet (usually hardware error)",
    232                     "Cannot change hardware address ( > 1 handle open)",
    233                     "Hardware address has bad length or format",
    234                     "Cannot reset interface (more than 1 handle open)",
    235                     "Bad Check-sum",
    236                     "Bad size",
    237                     "Bad sync" ,
    238                     "Source hit"
    239                   };
    240 
    241   if (errNum < 0 || errNum >= DIM(errStr))
    242      return ("Unknown driver error.");
    243   return (errStr [errNum]);
    244 }
    245 
    246 /**************************************************************************/
    247 
    248 PUBLIC const char *PktGetClassName (WORD class)
    249 {
    250   switch (class)
    251   {
    252     case PD_ETHER:
    253          return ("DIX-Ether");
    254     case PD_PRONET10:
    255          return ("ProNET-10");
    256     case PD_IEEE8025:
    257          return ("IEEE 802.5");
    258     case PD_OMNINET:
    259          return ("OmniNet");
    260     case PD_APPLETALK:
    261          return ("AppleTalk");
    262     case PD_SLIP:
    263          return ("SLIP");
    264     case PD_STARTLAN:
    265          return ("StartLAN");
    266     case PD_ARCNET:
    267          return ("ArcNet");
    268     case PD_AX25:
    269          return ("AX.25");
    270     case PD_KISS:
    271          return ("KISS");
    272     case PD_IEEE8023_2:
    273          return ("IEEE 802.3 w/802.2 hdr");
    274     case PD_FDDI8022:
    275          return ("FDDI w/802.2 hdr");
    276     case PD_X25:
    277          return ("X.25");
    278     case PD_LANstar:
    279          return ("LANstar");
    280     case PD_PPP:
    281          return ("PPP");
    282     default:
    283          return ("unknown");
    284   }
    285 }
    286 
    287 /**************************************************************************/
    288 
    289 PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode)
    290 {
    291   static const char *modeStr [] = {
    292                     "Receiver turned off",
    293                     "Receive only directly addressed packets",
    294                     "Receive direct & broadcast packets",
    295                     "Receive direct,broadcast and limited multicast packets",
    296                     "Receive direct,broadcast and all multicast packets",
    297                     "Receive all packets (promiscuouos mode)"
    298                   };
    299 
    300   if (mode > DIM(modeStr))
    301      return ("??");
    302   return (modeStr [mode-1]);
    303 }
    304 
    305 /**************************************************************************/
    306 
    307 LOCAL __inline BOOL PktInterrupt (void)
    308 {
    309   BOOL okay;
    310 
    311 #if (DOSX & PHARLAP)
    312   _dx_real_int ((UINT)pktInfo.intr, &reg);
    313   okay = ((reg.flags & 1) == 0);  /* OK if carry clear */
    314 
    315 #elif (DOSX & DJGPP)
    316   __dpmi_int ((int)pktInfo.intr, &reg);
    317   okay = ((reg.x.flags & 1) == 0);
    318 
    319 #elif (DOSX & DOS4GW)
    320   union  REGS  r;
    321   struct SREGS s;
    322 
    323   memset (&r, 0, sizeof(r));
    324   segread (&s);
    325   r.w.ax  = 0x300;
    326   r.x.ebx = pktInfo.intr;
    327   r.w.cx  = 0;
    328   s.es    = FP_SEG (&reg);
    329   r.x.edi = FP_OFF (&reg);
    330   reg.r_flags = 0;
    331   reg.r_ss = reg.r_sp = 0;     /* DPMI host provides stack */
    332 
    333   int386x (0x31, &r, &r, &s);
    334   okay = (!r.w.cflag);
    335 
    336 #else
    337   reg.r_flags = 0;
    338   intr (pktInfo.intr, (struct REGPACK*)&reg);
    339   okay = ((reg.r_flags & 1) == 0);
    340 #endif
    341 
    342   if (okay)
    343        pktInfo.error = NULL;
    344   else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8);
    345   return (okay);
    346 }
    347 
    348 /**************************************************************************/
    349 
    350 /*
    351  * Search for packet driver at interrupt 60h through 80h. If ASCIIZ
    352  * string "PKT DRVR" found at offset 3 in the interrupt handler, return
    353  * interrupt number, else return zero in pktInfo.intr
    354  */
    355 PUBLIC BOOL PktSearchDriver (void)
    356 {
    357   BYTE intr  = 0x20;
    358   BOOL found = FALSE;
    359 
    360   while (!found && intr < 0xFF)
    361   {
    362     static char str[12];                 /* 3 + strlen("PKT DRVR") */
    363     static char pktStr[9] = "PKT DRVR";  /* ASCIIZ string at ofs 3 */
    364     DWORD  rp;                           /* in interrupt  routine  */
    365 
    366 #if (DOSX & PHARLAP)
    367     _dx_rmiv_get (intr, &rp);
    368     ReadRealMem (&str, (REALPTR)rp, sizeof(str));
    369 
    370 #elif (DOSX & DJGPP)
    371     __dpmi_raddr realAdr;
    372     __dpmi_get_real_mode_interrupt_vector (intr, &realAdr);
    373     rp = (realAdr.segment << 4) + realAdr.offset16;
    374     dosmemget (rp, sizeof(str), &str);
    375 
    376 #elif (DOSX & DOS4GW)
    377     rp = dpmi_get_real_vector (intr);
    378     memcpy (&str, (void*)rp, sizeof(str));
    379 
    380 #else
    381     _fmemcpy (&str, getvect(intr), sizeof(str));
    382 #endif
    383 
    384     found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0;
    385     intr++;
    386   }
    387   pktInfo.intr = (found ? intr-1 : 0);
    388   return (found);
    389 }
    390 
    391 
    392 /**************************************************************************/
    393 
    394 static BOOL PktSetAccess (void)
    395 {
    396   reg.r_ax = 0x0200 + pktInfo.class;
    397   reg.r_bx = 0xFFFF;
    398   reg.r_dx = 0;
    399   reg.r_cx = 0;
    400 
    401 #if (DOSX & PHARLAP)
    402   reg.ds  = 0;
    403   reg.esi = 0;
    404   reg.es  = RP_SEG (realBase);
    405   reg.edi = (WORD) &PktReceiver;
    406 
    407 #elif (DOSX & DJGPP)
    408   reg.x.ds = 0;
    409   reg.x.si = 0;
    410   reg.x.es = rm_mem.rm_segment;
    411   reg.x.di = PktReceiver;
    412 
    413 #elif (DOSX & DOS4GW)
    414   reg.r_ds = 0;
    415   reg.r_si = 0;
    416   reg.r_es = rm_base_seg;
    417   reg.r_di = PktReceiver;
    418 
    419 #else
    420   reg.r_ds = 0;
    421   reg.r_si = 0;
    422   reg.r_es = FP_SEG (&PktReceiver);
    423   reg.r_di = FP_OFF (&PktReceiver);
    424 #endif
    425 
    426   if (!PktInterrupt())
    427      return (FALSE);
    428 
    429   pktInfo.handle = reg.r_ax;
    430   return (TRUE);
    431 }
    432 
    433 /**************************************************************************/
    434 
    435 PUBLIC BOOL PktReleaseHandle (WORD handle)
    436 {
    437   reg.r_ax = 0x0300;
    438   reg.r_bx = handle;
    439   return PktInterrupt();
    440 }
    441 
    442 /**************************************************************************/
    443 
    444 PUBLIC BOOL PktTransmit (const void *eth, int len)
    445 {
    446   if (len > ETH_MTU)
    447      return (FALSE);
    448 
    449   reg.r_ax = 0x0400;             /* Function 4, send pkt */
    450   reg.r_cx = len;                /* total size of frame  */
    451 
    452 #if (DOSX & DJGPP)
    453   dosmemput (eth, len, realBase+pktTxBuf);
    454   reg.x.ds = rm_mem.rm_segment;  /* DOS data segment and */
    455   reg.x.si = pktTxBuf;           /* DOS offset to buffer */
    456 
    457 #elif (DOSX & DOS4GW)
    458   memcpy ((void*)(realBase+pktTxBuf), eth, len);
    459   reg.r_ds = rm_base_seg;
    460   reg.r_si = pktTxBuf;
    461 
    462 #elif (DOSX & PHARLAP)
    463   memcpy (&pktTxBuf, eth, len);
    464   reg.r_ds = FP_SEG (&pktTxBuf);
    465   reg.r_si = FP_OFF (&pktTxBuf);
    466 
    467 #else
    468   reg.r_ds = FP_SEG (eth);
    469   reg.r_si = FP_OFF (eth);
    470 #endif
    471 
    472   return PktInterrupt();
    473 }
    474 
    475 /**************************************************************************/
    476 
    477 #if (DOSX & (DJGPP|DOS4GW))
    478 LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx)
    479 #else
    480 LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx)
    481 #endif
    482 {
    483   WORD count_1, count_2;
    484 
    485   /*
    486    * We got an upcall to the same RMCB with wrong handle.
    487    * This can happen if we failed to release handle at program exit
    488    */
    489   if (rx->handle != pktInfo.handle)
    490   {
    491     pktInfo.error = "Wrong handle";
    492     intStat.wrongHandle++;
    493     PktReleaseHandle (rx->handle);
    494     return (FALSE);
    495   }
    496   count_1 = rx->firstCount;
    497   count_2 = rx->secondCount;
    498 
    499   if (count_1 != count_2)
    500   {
    501     pktInfo.error = "Bad sync";
    502     intStat.badSync++;
    503     return (FALSE);
    504   }
    505   if (count_1 > ETH_MAX)
    506   {
    507     pktInfo.error = "Large esize";
    508     intStat.tooLarge++;
    509     return (FALSE);
    510   }
    511 #if 0
    512   if (count_1 < ETH_MIN)
    513   {
    514     pktInfo.error = "Small esize";
    515     intStat.tooSmall++;
    516     return (FALSE);
    517   }
    518 #endif
    519   return (TRUE);
    520 }
    521 
    522 /**************************************************************************/
    523 
    524 PUBLIC BOOL PktTerminHandle (WORD handle)
    525 {
    526   reg.r_ax = 0x0500;
    527   reg.r_bx = handle;
    528   return PktInterrupt();
    529 }
    530 
    531 /**************************************************************************/
    532 
    533 PUBLIC BOOL PktResetInterface (WORD handle)
    534 {
    535   reg.r_ax = 0x0700;
    536   reg.r_bx = handle;
    537   return PktInterrupt();
    538 }
    539 
    540 /**************************************************************************/
    541 
    542 PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode)
    543 {
    544   if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP)
    545      return (TRUE);
    546 
    547   reg.r_ax = 0x1400;
    548   reg.r_bx = pktInfo.handle;
    549   reg.r_cx = (WORD)mode;
    550 
    551   if (!PktInterrupt())
    552      return (FALSE);
    553 
    554   receiveMode = mode;
    555   return (TRUE);
    556 }
    557 
    558 /**************************************************************************/
    559 
    560 PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode)
    561 {
    562   reg.r_ax = 0x1500;
    563   reg.r_bx = pktInfo.handle;
    564 
    565   if (!PktInterrupt())
    566      return (FALSE);
    567 
    568   *mode = reg.r_ax;
    569   return (TRUE);
    570 }
    571 
    572 /**************************************************************************/
    573 
    574 static PKT_STAT initialStat;         /* statistics at startup */
    575 static BOOL     resetStat = FALSE;   /* statistics reset ? */
    576 
    577 PUBLIC BOOL PktGetStatistics (WORD handle)
    578 {
    579   reg.r_ax = 0x1800;
    580   reg.r_bx = handle;
    581 
    582   if (!PktInterrupt())
    583      return (FALSE);
    584 
    585 #if (DOSX & PHARLAP)
    586   ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat));
    587 
    588 #elif (DOSX & DJGPP)
    589   dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat);
    590 
    591 #elif (DOSX & DOS4GW)
    592   memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat));
    593 
    594 #else
    595   _fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat));
    596 #endif
    597 
    598   return (TRUE);
    599 }
    600 
    601 /**************************************************************************/
    602 
    603 PUBLIC BOOL PktSessStatistics (WORD handle)
    604 {
    605   if (!PktGetStatistics(pktInfo.handle))
    606      return (FALSE);
    607 
    608   if (resetStat)
    609   {
    610     pktStat.inPackets  -= initialStat.inPackets;
    611     pktStat.outPackets -= initialStat.outPackets;
    612     pktStat.inBytes    -= initialStat.inBytes;
    613     pktStat.outBytes   -= initialStat.outBytes;
    614     pktStat.inErrors   -= initialStat.inErrors;
    615     pktStat.outErrors  -= initialStat.outErrors;
    616     pktStat.outErrors  -= initialStat.outErrors;
    617     pktStat.lost       -= initialStat.lost;
    618   }
    619   return (TRUE);
    620 }
    621 
    622 /**************************************************************************/
    623 
    624 PUBLIC BOOL PktResetStatistics (WORD handle)
    625 {
    626   if (!PktGetStatistics(pktInfo.handle))
    627      return (FALSE);
    628 
    629   memcpy (&initialStat, &pktStat, sizeof(initialStat));
    630   resetStat = TRUE;
    631   return (TRUE);
    632 }
    633 
    634 /**************************************************************************/
    635 
    636 PUBLIC BOOL PktGetAddress (ETHER *addr)
    637 {
    638   reg.r_ax = 0x0600;
    639   reg.r_bx = pktInfo.handle;
    640   reg.r_cx = sizeof (*addr);
    641 
    642 #if (DOSX & DJGPP)
    643   reg.x.es = rm_mem.rm_segment;
    644   reg.x.di = pktTemp;
    645 #elif (DOSX & DOS4GW)
    646   reg.r_es = rm_base_seg;
    647   reg.r_di = pktTemp;
    648 #else
    649   reg.r_es = FP_SEG (&pktTemp);
    650   reg.r_di = FP_OFF (&pktTemp);  /* ES:DI = address for result */
    651 #endif
    652 
    653   if (!PktInterrupt())
    654      return (FALSE);
    655 
    656 #if (DOSX & PHARLAP)
    657   ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr));
    658 
    659 #elif (DOSX & DJGPP)
    660   dosmemget (realBase+pktTemp, sizeof(*addr), addr);
    661 
    662 #elif (DOSX & DOS4GW)
    663   memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr));
    664 
    665 #else
    666   memcpy ((void*)addr, &pktTemp, sizeof(*addr));
    667 #endif
    668 
    669   return (TRUE);
    670 }
    671 
    672 /**************************************************************************/
    673 
    674 PUBLIC BOOL PktSetAddress (const ETHER *addr)
    675 {
    676   /* copy addr to real-mode scrath area */
    677 
    678 #if (DOSX & PHARLAP)
    679   WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr));
    680 
    681 #elif (DOSX & DJGPP)
    682   dosmemput (addr, sizeof(*addr), realBase+pktTemp);
    683 
    684 #elif (DOSX & DOS4GW)
    685   memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr));
    686 
    687 #else
    688   memcpy (&pktTemp, (void*)addr, sizeof(*addr));
    689 #endif
    690 
    691   reg.r_ax = 0x1900;
    692   reg.r_cx = sizeof (*addr);      /* address length       */
    693 
    694 #if (DOSX & DJGPP)
    695   reg.x.es = rm_mem.rm_segment;   /* DOS offset to param  */
    696   reg.x.di = pktTemp;             /* DOS segment to param */
    697 #elif (DOSX & DOS4GW)
    698   reg.r_es = rm_base_seg;
    699   reg.r_di = pktTemp;
    700 #else
    701   reg.r_es = FP_SEG (&pktTemp);
    702   reg.r_di = FP_OFF (&pktTemp);
    703 #endif
    704 
    705   return PktInterrupt();
    706 }
    707 
    708 /**************************************************************************/
    709 
    710 PUBLIC BOOL PktGetDriverInfo (void)
    711 {
    712   pktInfo.majVer = 0;
    713   pktInfo.minVer = 0;
    714   memset (&pktInfo.name, 0, sizeof(pktInfo.name));
    715   reg.r_ax = 0x01FF;
    716   reg.r_bx = 0;
    717 
    718   if (!PktInterrupt())
    719      return (FALSE);
    720 
    721   pktInfo.number = reg.r_cx & 0xFF;
    722   pktInfo.class  = reg.r_cx >> 8;
    723 #if 0
    724   pktInfo.minVer = reg.r_bx % 10;
    725   pktInfo.majVer = reg.r_bx / 10;
    726 #else
    727   pktInfo.majVer = reg.r_bx;  // !!
    728 #endif
    729   pktInfo.funcs  = reg.r_ax & 0xFF;
    730   pktInfo.type   = reg.r_dx & 0xFF;
    731 
    732 #if (DOSX & PHARLAP)
    733   ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name));
    734 
    735 #elif (DOSX & DJGPP)
    736   dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name);
    737 
    738 #elif (DOSX & DOS4GW)
    739   memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name));
    740 
    741 #else
    742   _fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name));
    743 #endif
    744   return (TRUE);
    745 }
    746 
    747 /**************************************************************************/
    748 
    749 PUBLIC BOOL PktGetDriverParam (void)
    750 {
    751   reg.r_ax = 0x0A00;
    752 
    753   if (!PktInterrupt())
    754      return (FALSE);
    755 
    756 #if (DOSX & PHARLAP)
    757   ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE);
    758 
    759 #elif (DOSX & DJGPP)
    760   dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer);
    761 
    762 #elif (DOSX & DOS4GW)
    763   memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE);
    764 
    765 #else
    766   _fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE);
    767 #endif
    768   return (TRUE);
    769 }
    770 
    771 /**************************************************************************/
    772 
    773 #if (DOSX & PHARLAP)
    774   PUBLIC int PktReceive (BYTE *buf, int max)
    775   {
    776     WORD inOfs  = *rxInOfsFp;
    777     WORD outOfs = *rxOutOfsFp;
    778 
    779     if (outOfs != inOfs)
    780     {
    781       RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs);
    782       int size, len = max;
    783 
    784       if (CheckElement(head))
    785       {
    786         size = min (head->firstCount, sizeof(RX_ELEMENT));
    787         len  = min (size, max);
    788         _fmemcpy (buf, &head->destin, len);
    789       }
    790       else
    791         size = -1;
    792 
    793       outOfs += sizeof (RX_ELEMENT);
    794       if (outOfs > LAST_RX_BUF)
    795           outOfs = FIRST_RX_BUF;
    796       *rxOutOfsFp = outOfs;
    797       return (size);
    798     }
    799     return (0);
    800   }
    801 
    802   PUBLIC void PktQueueBusy (BOOL busy)
    803   {
    804     *rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp;
    805     if (*rxOutOfsFp > LAST_RX_BUF)
    806         *rxOutOfsFp = FIRST_RX_BUF;
    807     *(DWORD _far*)(protBase + (WORD)&pktDrop) = 0;
    808   }
    809 
    810   PUBLIC WORD PktBuffersUsed (void)
    811   {
    812     WORD inOfs  = *rxInOfsFp;
    813     WORD outOfs = *rxOutOfsFp;
    814 
    815     if (inOfs >= outOfs)
    816        return (inOfs - outOfs) / sizeof(RX_ELEMENT);
    817     return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
    818   }
    819 
    820   PUBLIC DWORD PktRxDropped (void)
    821   {
    822     return (*(DWORD _far*)(protBase + (WORD)&pktDrop));
    823   }
    824 
    825 #elif (DOSX & DJGPP)
    826   PUBLIC int PktReceive (BYTE *buf, int max)
    827   {
    828     WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs);
    829 
    830     if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs))
    831     {
    832       RX_ELEMENT head;
    833       int  size, len = max;
    834 
    835       head.firstCount  = _farpeekw (_dos_ds, realBase+ofs);
    836       head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2);
    837       head.handle      = _farpeekw (_dos_ds, realBase+ofs+4);
    838 
    839       if (CheckElement(&head))
    840       {
    841         size = min (head.firstCount, sizeof(RX_ELEMENT));
    842         len  = min (size, max);
    843         dosmemget (realBase+ofs+6, len, buf);
    844       }
    845       else
    846         size = -1;
    847 
    848       ofs += sizeof (RX_ELEMENT);
    849       if (ofs > LAST_RX_BUF)
    850            _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
    851       else _farpokew (_dos_ds, realBase+rxOutOfs, ofs);
    852       return (size);
    853     }
    854     return (0);
    855   }
    856 
    857   PUBLIC void PktQueueBusy (BOOL busy)
    858   {
    859     WORD ofs;
    860 
    861     disable();
    862     ofs = _farpeekw (_dos_ds, realBase+rxInOfs);
    863     if (busy)
    864        ofs += sizeof (RX_ELEMENT);
    865 
    866     if (ofs > LAST_RX_BUF)
    867          _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
    868     else _farpokew (_dos_ds, realBase+rxOutOfs, ofs);
    869     _farpokel (_dos_ds, realBase+pktDrop, 0UL);
    870     enable();
    871   }
    872 
    873   PUBLIC WORD PktBuffersUsed (void)
    874   {
    875     WORD inOfs, outOfs;
    876 
    877     disable();
    878     inOfs  = _farpeekw (_dos_ds, realBase+rxInOfs);
    879     outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs);
    880     enable();
    881     if (inOfs >= outOfs)
    882        return (inOfs - outOfs) / sizeof(RX_ELEMENT);
    883     return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
    884   }
    885 
    886   PUBLIC DWORD PktRxDropped (void)
    887   {
    888     return _farpeekl (_dos_ds, realBase+pktDrop);
    889   }
    890 
    891 #elif (DOSX & DOS4GW)
    892   PUBLIC int PktReceive (BYTE *buf, int max)
    893   {
    894     WORD ofs = *(WORD*) (realBase+rxOutOfs);
    895 
    896     if (ofs != *(WORD*) (realBase+rxInOfs))
    897     {
    898       RX_ELEMENT head;
    899       int  size, len = max;
    900 
    901       head.firstCount  = *(WORD*) (realBase+ofs);
    902       head.secondCount = *(WORD*) (realBase+ofs+2);
    903       head.handle      = *(WORD*) (realBase+ofs+4);
    904 
    905       if (CheckElement(&head))
    906       {
    907         size = min (head.firstCount, sizeof(RX_ELEMENT));
    908         len  = min (size, max);
    909         memcpy (buf, (const void*)(realBase+ofs+6), len);
    910       }
    911       else
    912         size = -1;
    913 
    914       ofs += sizeof (RX_ELEMENT);
    915       if (ofs > LAST_RX_BUF)
    916            *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
    917       else *(WORD*) (realBase+rxOutOfs) = ofs;
    918       return (size);
    919     }
    920     return (0);
    921   }
    922 
    923   PUBLIC void PktQueueBusy (BOOL busy)
    924   {
    925     WORD ofs;
    926 
    927     _disable();
    928     ofs = *(WORD*) (realBase+rxInOfs);
    929     if (busy)
    930        ofs += sizeof (RX_ELEMENT);
    931 
    932     if (ofs > LAST_RX_BUF)
    933          *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
    934     else *(WORD*) (realBase+rxOutOfs) = ofs;
    935     *(DWORD*) (realBase+pktDrop) = 0UL;
    936     _enable();
    937   }
    938 
    939   PUBLIC WORD PktBuffersUsed (void)
    940   {
    941     WORD inOfs, outOfs;
    942 
    943     _disable();
    944     inOfs  = *(WORD*) (realBase+rxInOfs);
    945     outOfs = *(WORD*) (realBase+rxOutOfs);
    946     _enable();
    947     if (inOfs >= outOfs)
    948        return (inOfs - outOfs) / sizeof(RX_ELEMENT);
    949     return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
    950   }
    951 
    952   PUBLIC DWORD PktRxDropped (void)
    953   {
    954     return *(DWORD*) (realBase+pktDrop);
    955   }
    956 
    957 #else     /* real-mode small/large model */
    958 
    959   PUBLIC int PktReceive (BYTE *buf, int max)
    960   {
    961     if (rxOutOfs != rxInOfs)
    962     {
    963       RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs);
    964       int  size, len = max;
    965 
    966       if (CheckElement(head))
    967       {
    968         size = min (head->firstCount, sizeof(RX_ELEMENT));
    969         len  = min (size, max);
    970         _fmemcpy (buf, &head->destin, len);
    971       }
    972       else
    973         size = -1;
    974 
    975       rxOutOfs += sizeof (RX_ELEMENT);
    976       if (rxOutOfs > LAST_RX_BUF)
    977           rxOutOfs = FIRST_RX_BUF;
    978       return (size);
    979     }
    980     return (0);
    981   }
    982 
    983   PUBLIC void PktQueueBusy (BOOL busy)
    984   {
    985     rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs;
    986     if (rxOutOfs > LAST_RX_BUF)
    987         rxOutOfs = FIRST_RX_BUF;
    988     pktDrop = 0L;
    989   }
    990 
    991   PUBLIC WORD PktBuffersUsed (void)
    992   {
    993     WORD inOfs  = rxInOfs;
    994     WORD outOfs = rxOutOfs;
    995 
    996     if (inOfs >= outOfs)
    997        return ((inOfs - outOfs) / sizeof(RX_ELEMENT));
    998     return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
    999   }
   1000 
   1001   PUBLIC DWORD PktRxDropped (void)
   1002   {
   1003     return (pktDrop);
   1004   }
   1005 #endif
   1006 
   1007 /**************************************************************************/
   1008 
   1009 LOCAL __inline void PktFreeMem (void)
   1010 {
   1011 #if (DOSX & PHARLAP)
   1012   if (realSeg)
   1013   {
   1014     _dx_real_free (realSeg);
   1015     realSeg = 0;
   1016   }
   1017 #elif (DOSX & DJGPP)
   1018   if (rm_mem.rm_segment)
   1019   {
   1020     unsigned ofs;  /* clear the DOS-mem to prevent further upcalls */
   1021 
   1022     for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4)
   1023        _farpokel (_dos_ds, realBase + ofs, 0);
   1024     _go32_dpmi_free_dos_memory (&rm_mem);
   1025     rm_mem.rm_segment = 0;
   1026   }
   1027 #elif (DOSX & DOS4GW)
   1028   if (rm_base_sel)
   1029   {
   1030     dpmi_real_free (rm_base_sel);
   1031     rm_base_sel = 0;
   1032   }
   1033 #endif
   1034 }
   1035 
   1036 /**************************************************************************/
   1037 
   1038 PUBLIC BOOL PktExitDriver (void)
   1039 {
   1040   if (pktInfo.handle)
   1041   {
   1042     if (!PktSetReceiverMode(PDRX_BROADCAST))
   1043        PUTS ("Error restoring receiver mode.");
   1044 
   1045     if (!PktReleaseHandle(pktInfo.handle))
   1046        PUTS ("Error releasing PKT-DRVR handle.");
   1047 
   1048     PktFreeMem();
   1049     pktInfo.handle = 0;
   1050   }
   1051 
   1052   if (pcap_pkt_debug >= 1)
   1053      printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, "
   1054              "wrong-handle %lu\n",
   1055              intStat.tooSmall, intStat.tooLarge,
   1056              intStat.badSync, intStat.wrongHandle);
   1057   return (TRUE);
   1058 }
   1059 
   1060 #if (DOSX & (DJGPP|DOS4GW))
   1061 static void dump_pkt_stub (void)
   1062 {
   1063   int i;
   1064 
   1065   fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n",
   1066            PktReceiver);
   1067   for (i = 0; i < 15; i++)
   1068       fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]);
   1069   fputs ("\n", stderr);
   1070 }
   1071 #endif
   1072 
   1073 /*
   1074  * Front end initialization routine
   1075  */
   1076 PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode)
   1077 {
   1078   PKT_RX_MODE rxMode;
   1079   BOOL   writeInfo = (pcap_pkt_debug >= 3);
   1080 
   1081   pktInfo.quiet = (pcap_pkt_debug < 3);
   1082 
   1083 #if (DOSX & PHARLAP) && defined(__HIGHC__)
   1084   if (_mwenv != 2)
   1085   {
   1086     fprintf (stderr, "Only Pharlap DOS extender supported.\n");
   1087     return (FALSE);
   1088   }
   1089 #endif
   1090 
   1091 #if (DOSX & PHARLAP) && defined(__WATCOMC__)
   1092   if (_Extender != 1)
   1093   {
   1094     fprintf (stderr, "Only DOS4GW style extenders supported.\n");
   1095     return (FALSE);
   1096   }
   1097 #endif
   1098 
   1099   if (!PktSearchDriver())
   1100   {
   1101     PUTS ("Packet driver not found.");
   1102     PktFreeMem();
   1103     return (FALSE);
   1104   }
   1105 
   1106   if (!PktGetDriverInfo())
   1107   {
   1108     PUTS ("Error getting pkt-drvr information.");
   1109     PktFreeMem();
   1110     return (FALSE);
   1111   }
   1112 
   1113 #if (DOSX & PHARLAP)
   1114   if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd,
   1115                &realBase, &protBase, (USHORT*)&realSeg))
   1116   {
   1117     rxOutOfsFp  = (WORD _far *) (protBase + (WORD) &rxOutOfs);
   1118     rxInOfsFp   = (WORD _far *) (protBase + (WORD) &rxInOfs);
   1119     *rxOutOfsFp = FIRST_RX_BUF;
   1120     *rxInOfsFp  = FIRST_RX_BUF;
   1121   }
   1122   else
   1123   {
   1124     PUTS ("Cannot allocate real-mode stub.");
   1125     return (FALSE);
   1126   }
   1127 
   1128 #elif (DOSX & (DJGPP|DOS4GW))
   1129   if (sizeof(real_stub_array) > 0xFFFF)
   1130   {
   1131     fprintf (stderr, "`real_stub_array[]' too big.\n");
   1132     return (FALSE);
   1133   }
   1134 #if (DOSX & DJGPP)
   1135   rm_mem.size = (sizeof(real_stub_array) + 15) / 16;
   1136 
   1137   if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0)
   1138   {
   1139     PUTS ("real-mode init failed.");
   1140     return (FALSE);
   1141   }
   1142   realBase = (rm_mem.rm_segment << 4);
   1143   dosmemput (&real_stub_array, sizeof(real_stub_array), realBase);
   1144   _farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
   1145   _farpokel (_dos_ds, realBase+rxInOfs,  FIRST_RX_BUF);
   1146 
   1147 #elif (DOSX & DOS4GW)
   1148   rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel);
   1149   if (!rm_base_seg)
   1150   {
   1151     PUTS ("real-mode init failed.");
   1152     return (FALSE);
   1153   }
   1154   realBase = (rm_base_seg << 4);
   1155   memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array));
   1156   *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
   1157   *(WORD*) (realBase+rxInOfs)  = FIRST_RX_BUF;
   1158 
   1159 #endif
   1160   {
   1161     int pushf = PktReceiver;
   1162 
   1163     while (real_stub_array[pushf++] != 0x9C &&    /* pushf */
   1164            real_stub_array[pushf]   != 0xFA)      /* cli   */
   1165     {
   1166       if (++para_skip > 16)
   1167       {
   1168         fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n");
   1169         para_skip = 0;
   1170         dump_pkt_stub();
   1171         return (FALSE);
   1172       }
   1173     }
   1174     if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800)
   1175     {
   1176       fprintf (stderr, "`real_stub_array[]' is misaligned.\n");
   1177       return (FALSE);
   1178     }
   1179   }
   1180 
   1181   if (pcap_pkt_debug > 2)
   1182       dump_pkt_stub();
   1183 
   1184 #else
   1185   rxOutOfs = FIRST_RX_BUF;
   1186   rxInOfs  = FIRST_RX_BUF;
   1187 #endif
   1188 
   1189   if (!PktSetAccess())
   1190   {
   1191     PUTS ("Error setting pkt-drvr access.");
   1192     PktFreeMem();
   1193     return (FALSE);
   1194   }
   1195 
   1196   if (!PktGetAddress(&myAddress))
   1197   {
   1198     PUTS ("Error fetching adapter address.");
   1199     PktFreeMem();
   1200     return (FALSE);
   1201   }
   1202 
   1203   if (!PktSetReceiverMode(mode))
   1204   {
   1205     PUTS ("Error setting receiver mode.");
   1206     PktFreeMem();
   1207     return (FALSE);
   1208   }
   1209 
   1210   if (!PktGetReceiverMode(&rxMode))
   1211   {
   1212     PUTS ("Error getting receiver mode.");
   1213     PktFreeMem();
   1214     return (FALSE);
   1215   }
   1216 
   1217   if (writeInfo)
   1218      printf ("Pkt-driver information:\n"
   1219              "  Version  : %d.%d\n"
   1220              "  Name     : %.15s\n"
   1221              "  Class    : %u (%s)\n"
   1222              "  Type     : %u\n"
   1223              "  Number   : %u\n"
   1224              "  Funcs    : %u\n"
   1225              "  Intr     : %Xh\n"
   1226              "  Handle   : %u\n"
   1227              "  Extended : %s\n"
   1228              "  Hi-perf  : %s\n"
   1229              "  RX mode  : %s\n"
   1230              "  Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n",
   1231 
   1232              pktInfo.majVer, pktInfo.minVer, pktInfo.name,
   1233              pktInfo.class,  PktGetClassName(pktInfo.class),
   1234              pktInfo.type,   pktInfo.number,
   1235              pktInfo.funcs,  pktInfo.intr,   pktInfo.handle,
   1236              pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No",
   1237              pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No",
   1238              PktRXmodeStr(rxMode),
   1239              myAddress[0], myAddress[1], myAddress[2],
   1240              myAddress[3], myAddress[4], myAddress[5]);
   1241 
   1242 #if defined(DEBUG) && (DOSX & PHARLAP)
   1243   if (writeInfo)
   1244   {
   1245     DWORD    rAdr = realBase + (WORD)&PktReceiver;
   1246     unsigned sel, ofs;
   1247 
   1248     printf ("\nReceiver at   %04X:%04X\n", RP_SEG(rAdr),    RP_OFF(rAdr));
   1249     printf ("Realbase    = %04X:%04X\n",   RP_SEG(realBase),RP_OFF(realBase));
   1250 
   1251     sel = _FP_SEG (protBase);
   1252     ofs = _FP_OFF (protBase);
   1253     printf ("Protbase    = %04X:%08X\n", sel,ofs);
   1254     printf ("RealSeg     = %04X\n", realSeg);
   1255 
   1256     sel = _FP_SEG (rxOutOfsFp);
   1257     ofs = _FP_OFF (rxOutOfsFp);
   1258     printf ("rxOutOfsFp  = %04X:%08X\n", sel,ofs);
   1259 
   1260     sel = _FP_SEG (rxInOfsFp);
   1261     ofs = _FP_OFF (rxInOfsFp);
   1262     printf ("rxInOfsFp   = %04X:%08X\n", sel,ofs);
   1263 
   1264     printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n",
   1265             *rxOutOfsFp, *rxInOfsFp);
   1266 
   1267     PktQueueBusy (TRUE);
   1268     printf ("Busy:  *rxOutOfsFp = %04X *rxInOfsFp = %04X\n",
   1269             *rxOutOfsFp, *rxInOfsFp);
   1270   }
   1271 #endif
   1272 
   1273   memset (&pktStat, 0, sizeof(pktStat));  /* clear statistics */
   1274   PktQueueBusy (TRUE);
   1275   return (TRUE);
   1276 }
   1277 
   1278 
   1279 /*
   1280  * DPMI functions only for Watcom + DOS4GW extenders
   1281  */
   1282 #if (DOSX & DOS4GW)
   1283 LOCAL DWORD dpmi_get_real_vector (int intr)
   1284 {
   1285   union REGS r;
   1286 
   1287   r.x.eax = 0x200;
   1288   r.x.ebx = (DWORD) intr;
   1289   int386 (0x31, &r, &r);
   1290   return ((r.w.cx << 4) + r.w.dx);
   1291 }
   1292 
   1293 LOCAL WORD dpmi_real_malloc (int size, WORD *selector)
   1294 {
   1295   union REGS r;
   1296 
   1297   r.x.eax = 0x0100;             /* DPMI allocate DOS memory */
   1298   r.x.ebx = (size + 15) / 16;   /* Number of paragraphs requested */
   1299   int386 (0x31, &r, &r);
   1300   if (r.w.cflag & 1)
   1301      return (0);
   1302 
   1303   *selector = r.w.dx;
   1304   return (r.w.ax);              /* Return segment address */
   1305 }
   1306 
   1307 LOCAL void dpmi_real_free (WORD selector)
   1308 {
   1309   union REGS r;
   1310 
   1311   r.x.eax = 0x101;              /* DPMI free DOS memory */
   1312   r.x.ebx = selector;           /* Selector to free */
   1313   int386 (0x31, &r, &r);
   1314 }
   1315 #endif
   1316 
   1317 
   1318 #if defined(DOSX) && (DOSX & PHARLAP)
   1319 /*
   1320  * Description:
   1321  *     This routine allocates conventional memory for the specified block
   1322  *     of code (which must be within the first 64K of the protected mode
   1323  *     program segment) and copies the code to it.
   1324  *
   1325  *     The caller should free up the conventional memory block when it
   1326  *     is done with the conventional memory.
   1327  *
   1328  *     NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER.
   1329  *
   1330  * Calling arguments:
   1331  *     start_offs      start of real mode code in program segment
   1332  *     end_offs        1 byte past end of real mode code in program segment
   1333  *     real_basep      returned;  real mode ptr to use as a base for the
   1334  *                        real mode code (eg, to get the real mode FAR
   1335  *                        addr of a function foo(), take
   1336  *                        real_basep + (ULONG) foo).
   1337  *                        This pointer is constructed such that
   1338  *                        offsets within the real mode segment are
   1339  *                        the same as the link-time offsets in the
   1340  *                        protected mode program segment
   1341  *     prot_basep      returned;  prot mode ptr to use as a base for getting
   1342  *                        to the conventional memory, also constructed
   1343  *                        so that adding the prot mode offset of a
   1344  *                        function or variable to the base gets you a
   1345  *                        ptr to the function or variable in the
   1346  *                        conventional memory block.
   1347  *     rmem_adrp       returned;  real mode para addr of allocated
   1348  *                        conventional memory block, to be used to free
   1349  *                        up the conventional memory when done.  DO NOT
   1350  *                        USE THIS TO CONSTRUCT A REAL MODE PTR, USE
   1351  *                        REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT
   1352  *                        CORRECTLY.
   1353  *
   1354  * Returned values:
   1355  *     0      if error
   1356  *     1      if success
   1357  */
   1358 int RealCopy (ULONG    start_offs,
   1359               ULONG    end_offs,
   1360               REALPTR *real_basep,
   1361               FARPTR  *prot_basep,
   1362               USHORT  *rmem_adrp)
   1363 {
   1364   ULONG   rm_base;    /* base real mode para addr for accessing */
   1365                       /* allocated conventional memory          */
   1366   UCHAR  *source;     /* source pointer for copy                */
   1367   FARPTR  destin;     /* destination pointer for copy           */
   1368   ULONG   len;        /* number of bytes to copy                */
   1369   ULONG   temp;
   1370   USHORT  stemp;
   1371 
   1372   /* First check for valid inputs
   1373    */
   1374   if (start_offs >= end_offs || end_offs > 0x10000)
   1375      return (FALSE);
   1376 
   1377   /* Round start_offs down to a paragraph (16-byte) boundary so we can set up
   1378    * the real mode pointer easily. Round up end_offs to make sure we allocate
   1379    * enough paragraphs
   1380    */
   1381   start_offs &= ~15;
   1382   end_offs = (15 + (end_offs << 4)) >> 4;
   1383 
   1384   /* Allocate the conventional memory for our real mode code.  Remember to
   1385    * round byte count UP to 16-byte paragraph size.  We alloc it
   1386    * above the DOS data buffer so both the DOS data buffer and the appl
   1387    * conventional mem block can still be resized.
   1388    *
   1389    * First just try to alloc it;  if we can't get it, shrink the appl mem
   1390    * block down to the minimum, try to alloc the memory again, then grow the
   1391    * appl mem block back to the maximum.  (Don't try to shrink the DOS data
   1392    * buffer to free conventional memory;  it wouldn't be good for this routine
   1393    * to have the possible side effect of making file I/O run slower.)
   1394    */
   1395   len = ((end_offs - start_offs) + 15) >> 4;
   1396   if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE)
   1397   {
   1398     if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE)
   1399        return (FALSE);
   1400 
   1401     if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE)
   1402        *rmem_adrp = 0;
   1403 
   1404     if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE)
   1405     {
   1406       if (*rmem_adrp != 0)
   1407          _dx_real_free (*rmem_adrp);
   1408       return (FALSE);
   1409     }
   1410 
   1411     if (*rmem_adrp == 0)
   1412        return (FALSE);
   1413   }
   1414 
   1415   /* Construct real mode & protected mode pointers to access the allocated
   1416    * memory.  Note we know start_offs is aligned on a paragraph (16-byte)
   1417    * boundary, because we rounded it down.
   1418    *
   1419    * We make the offsets come out rights by backing off the real mode selector
   1420    * by start_offs.
   1421    */
   1422   rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4);
   1423   RP_SET (*real_basep, 0, rm_base);
   1424   FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM);
   1425 
   1426   /* Copy the real mode code/data to the allocated memory
   1427    */
   1428   source = (UCHAR *) start_offs;
   1429   destin = *prot_basep;
   1430   FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep));
   1431   len = end_offs - start_offs;
   1432   WriteFarMem (destin, source, len);
   1433 
   1434   return (TRUE);
   1435 }
   1436 #endif /* DOSX && (DOSX & PHARLAP) */
   1437