30f165e2d7
MFC after: 1 month Sponsored by: Mellanox Technologies
1437 lines
38 KiB
C
1437 lines
38 KiB
C
/*
|
|
* File.........: pktdrvr.c
|
|
*
|
|
* Responsible..: Gisle Vanem, giva@bgnett.no
|
|
*
|
|
* Created......: 26.Sept 1995
|
|
*
|
|
* Description..: Packet-driver interface for 16/32-bit C :
|
|
* Borland C/C++ 3.0+ small/large model
|
|
* Watcom C/C++ 11+, DOS4GW flat model
|
|
* Metaware HighC 3.1+ and PharLap 386|DosX
|
|
* GNU C/C++ 2.7+ and djgpp 2.x extender
|
|
*
|
|
* References...: PC/TCP Packet driver Specification. rev 1.09
|
|
* FTP Software Inc.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dos.h>
|
|
|
|
#include "pcap-dos.h"
|
|
#include "pcap-int.h"
|
|
#include "msdos/pktdrvr.h"
|
|
|
|
#if (DOSX)
|
|
#define NUM_RX_BUF 32 /* # of buffers in Rx FIFO queue */
|
|
#else
|
|
#define NUM_RX_BUF 10
|
|
#endif
|
|
|
|
#define DIM(x) (sizeof((x)) / sizeof(x[0]))
|
|
#define PUTS(s) do { \
|
|
if (!pktInfo.quiet) \
|
|
pktInfo.error ? \
|
|
printf ("%s: %s\n", s, pktInfo.error) : \
|
|
printf ("%s\n", pktInfo.error = s); \
|
|
} while (0)
|
|
|
|
#if defined(__HIGHC__)
|
|
extern UINT _mwenv;
|
|
|
|
#elif defined(__DJGPP__)
|
|
#include <stddef.h>
|
|
#include <dpmi.h>
|
|
#include <go32.h>
|
|
#include <pc.h>
|
|
#include <sys/farptr.h>
|
|
|
|
#elif defined(__WATCOMC__)
|
|
#include <i86.h>
|
|
#include <stddef.h>
|
|
extern char _Extender;
|
|
|
|
#else
|
|
extern void far PktReceiver (void);
|
|
#endif
|
|
|
|
|
|
#if (DOSX & (DJGPP|DOS4GW))
|
|
#include <sys/pack_on.h>
|
|
|
|
struct DPMI_regs {
|
|
DWORD r_di;
|
|
DWORD r_si;
|
|
DWORD r_bp;
|
|
DWORD reserved;
|
|
DWORD r_bx;
|
|
DWORD r_dx;
|
|
DWORD r_cx;
|
|
DWORD r_ax;
|
|
WORD r_flags;
|
|
WORD r_es, r_ds, r_fs, r_gs;
|
|
WORD r_ip, r_cs, r_sp, r_ss;
|
|
};
|
|
|
|
/* Data located in a real-mode segment. This becomes far at runtime
|
|
*/
|
|
typedef struct { /* must match data/code in pkt_rx1.s */
|
|
WORD _rxOutOfs;
|
|
WORD _rxInOfs;
|
|
DWORD _pktDrop;
|
|
BYTE _pktTemp [20];
|
|
TX_ELEMENT _pktTxBuf[1];
|
|
RX_ELEMENT _pktRxBuf[NUM_RX_BUF];
|
|
WORD _dummy[2]; /* screenSeg,newInOffset */
|
|
BYTE _fanChars[4];
|
|
WORD _fanIndex;
|
|
BYTE _PktReceiver[15]; /* starts on a paragraph (16byte) */
|
|
} PktRealStub;
|
|
#include <sys/pack_off.h>
|
|
|
|
static BYTE real_stub_array [] = {
|
|
#include "pkt_stub.inc" /* generated opcode array */
|
|
};
|
|
|
|
#define rxOutOfs offsetof (PktRealStub,_rxOutOfs)
|
|
#define rxInOfs offsetof (PktRealStub,_rxInOfs)
|
|
#define PktReceiver offsetof (PktRealStub,_PktReceiver [para_skip])
|
|
#define pktDrop offsetof (PktRealStub,_pktDrop)
|
|
#define pktTemp offsetof (PktRealStub,_pktTemp)
|
|
#define pktTxBuf offsetof (PktRealStub,_pktTxBuf)
|
|
#define FIRST_RX_BUF offsetof (PktRealStub,_pktRxBuf [0])
|
|
#define LAST_RX_BUF offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1])
|
|
|
|
#else
|
|
extern WORD rxOutOfs; /* offsets into pktRxBuf FIFO queue */
|
|
extern WORD rxInOfs;
|
|
extern DWORD pktDrop; /* # packets dropped in PktReceiver() */
|
|
extern BYTE pktRxEnd; /* marks the end of r-mode code/data */
|
|
|
|
extern RX_ELEMENT pktRxBuf [NUM_RX_BUF]; /* PktDrvr Rx buffers */
|
|
extern TX_ELEMENT pktTxBuf; /* PktDrvr Tx buffer */
|
|
extern char pktTemp[20]; /* PktDrvr temp area */
|
|
|
|
#define FIRST_RX_BUF (WORD) &pktRxBuf [0]
|
|
#define LAST_RX_BUF (WORD) &pktRxBuf [NUM_RX_BUF-1]
|
|
#endif
|
|
|
|
|
|
#ifdef __BORLANDC__ /* Use Borland's inline functions */
|
|
#define memcpy __memcpy__
|
|
#define memcmp __memcmp__
|
|
#define memset __memset__
|
|
#endif
|
|
|
|
|
|
#if (DOSX & PHARLAP)
|
|
extern void PktReceiver (void); /* in pkt_rx0.asm */
|
|
static int RealCopy (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*);
|
|
|
|
#undef FP_SEG
|
|
#undef FP_OFF
|
|
#define FP_OFF(x) ((WORD)(x))
|
|
#define FP_SEG(x) ((WORD)(realBase >> 16))
|
|
#define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o))
|
|
#define r_ax eax
|
|
#define r_bx ebx
|
|
#define r_dx edx
|
|
#define r_cx ecx
|
|
#define r_si esi
|
|
#define r_di edi
|
|
#define r_ds ds
|
|
#define r_es es
|
|
LOCAL FARPTR protBase;
|
|
LOCAL REALPTR realBase;
|
|
LOCAL WORD realSeg; /* DOS para-address of allocated area */
|
|
LOCAL SWI_REGS reg;
|
|
|
|
static WORD _far *rxOutOfsFp, *rxInOfsFp;
|
|
|
|
#elif (DOSX & DJGPP)
|
|
static _go32_dpmi_seginfo rm_mem;
|
|
static __dpmi_regs reg;
|
|
static DWORD realBase;
|
|
static int para_skip = 0;
|
|
|
|
#define DOS_ADDR(s,o) (((WORD)(s) << 4) + (o))
|
|
#define r_ax x.ax
|
|
#define r_bx x.bx
|
|
#define r_dx x.dx
|
|
#define r_cx x.cx
|
|
#define r_si x.si
|
|
#define r_di x.di
|
|
#define r_ds x.ds
|
|
#define r_es x.es
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
LOCAL struct DPMI_regs reg;
|
|
LOCAL WORD rm_base_seg, rm_base_sel;
|
|
LOCAL DWORD realBase;
|
|
LOCAL int para_skip = 0;
|
|
|
|
LOCAL DWORD dpmi_get_real_vector (int intr);
|
|
LOCAL WORD dpmi_real_malloc (int size, WORD *selector);
|
|
LOCAL void dpmi_real_free (WORD selector);
|
|
#define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o))
|
|
|
|
#else /* real-mode Borland etc. */
|
|
static struct {
|
|
WORD r_ax, r_bx, r_cx, r_dx, r_bp;
|
|
WORD r_si, r_di, r_ds, r_es, r_flags;
|
|
} reg;
|
|
#endif
|
|
|
|
#ifdef __HIGHC__
|
|
#pragma Alias (pktDrop, "_pktDrop")
|
|
#pragma Alias (pktRxBuf, "_pktRxBuf")
|
|
#pragma Alias (pktTxBuf, "_pktTxBuf")
|
|
#pragma Alias (pktTemp, "_pktTemp")
|
|
#pragma Alias (rxOutOfs, "_rxOutOfs")
|
|
#pragma Alias (rxInOfs, "_rxInOfs")
|
|
#pragma Alias (pktRxEnd, "_pktRxEnd")
|
|
#pragma Alias (PktReceiver,"_PktReceiver")
|
|
#endif
|
|
|
|
|
|
PUBLIC PKT_STAT pktStat; /* statistics for packets */
|
|
PUBLIC PKT_INFO pktInfo; /* packet-driver information */
|
|
|
|
PUBLIC PKT_RX_MODE receiveMode = PDRX_DIRECT;
|
|
PUBLIC ETHER myAddress = { 0, 0, 0, 0, 0, 0 };
|
|
PUBLIC ETHER ethBroadcast = { 255,255,255,255,255,255 };
|
|
|
|
LOCAL struct { /* internal statistics */
|
|
DWORD tooSmall; /* size < ETH_MIN */
|
|
DWORD tooLarge; /* size > ETH_MAX */
|
|
DWORD badSync; /* count_1 != count_2 */
|
|
DWORD wrongHandle; /* upcall to wrong handle */
|
|
} intStat;
|
|
|
|
/***************************************************************************/
|
|
|
|
PUBLIC const char *PktGetErrorStr (int errNum)
|
|
{
|
|
static const char *errStr[] = {
|
|
"",
|
|
"Invalid handle number",
|
|
"No interfaces of specified class found",
|
|
"No interfaces of specified type found",
|
|
"No interfaces of specified number found",
|
|
"Bad packet type specified",
|
|
"Interface does not support multicast",
|
|
"Packet driver cannot terminate",
|
|
"Invalid receiver mode specified",
|
|
"Insufficient memory space",
|
|
"Type previously accessed, and not released",
|
|
"Command out of range, or not implemented",
|
|
"Cannot send packet (usually hardware error)",
|
|
"Cannot change hardware address ( > 1 handle open)",
|
|
"Hardware address has bad length or format",
|
|
"Cannot reset interface (more than 1 handle open)",
|
|
"Bad Check-sum",
|
|
"Bad size",
|
|
"Bad sync" ,
|
|
"Source hit"
|
|
};
|
|
|
|
if (errNum < 0 || errNum >= DIM(errStr))
|
|
return ("Unknown driver error.");
|
|
return (errStr [errNum]);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC const char *PktGetClassName (WORD class)
|
|
{
|
|
switch (class)
|
|
{
|
|
case PD_ETHER:
|
|
return ("DIX-Ether");
|
|
case PD_PRONET10:
|
|
return ("ProNET-10");
|
|
case PD_IEEE8025:
|
|
return ("IEEE 802.5");
|
|
case PD_OMNINET:
|
|
return ("OmniNet");
|
|
case PD_APPLETALK:
|
|
return ("AppleTalk");
|
|
case PD_SLIP:
|
|
return ("SLIP");
|
|
case PD_STARTLAN:
|
|
return ("StartLAN");
|
|
case PD_ARCNET:
|
|
return ("ArcNet");
|
|
case PD_AX25:
|
|
return ("AX.25");
|
|
case PD_KISS:
|
|
return ("KISS");
|
|
case PD_IEEE8023_2:
|
|
return ("IEEE 802.3 w/802.2 hdr");
|
|
case PD_FDDI8022:
|
|
return ("FDDI w/802.2 hdr");
|
|
case PD_X25:
|
|
return ("X.25");
|
|
case PD_LANstar:
|
|
return ("LANstar");
|
|
case PD_PPP:
|
|
return ("PPP");
|
|
default:
|
|
return ("unknown");
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode)
|
|
{
|
|
static const char *modeStr [] = {
|
|
"Receiver turned off",
|
|
"Receive only directly addressed packets",
|
|
"Receive direct & broadcast packets",
|
|
"Receive direct,broadcast and limited multicast packets",
|
|
"Receive direct,broadcast and all multicast packets",
|
|
"Receive all packets (promiscuouos mode)"
|
|
};
|
|
|
|
if (mode > DIM(modeStr))
|
|
return ("??");
|
|
return (modeStr [mode-1]);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
LOCAL __inline BOOL PktInterrupt (void)
|
|
{
|
|
BOOL okay;
|
|
|
|
#if (DOSX & PHARLAP)
|
|
_dx_real_int ((UINT)pktInfo.intr, ®);
|
|
okay = ((reg.flags & 1) == 0); /* OK if carry clear */
|
|
|
|
#elif (DOSX & DJGPP)
|
|
__dpmi_int ((int)pktInfo.intr, ®);
|
|
okay = ((reg.x.flags & 1) == 0);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
union REGS r;
|
|
struct SREGS s;
|
|
|
|
memset (&r, 0, sizeof(r));
|
|
segread (&s);
|
|
r.w.ax = 0x300;
|
|
r.x.ebx = pktInfo.intr;
|
|
r.w.cx = 0;
|
|
s.es = FP_SEG (®);
|
|
r.x.edi = FP_OFF (®);
|
|
reg.r_flags = 0;
|
|
reg.r_ss = reg.r_sp = 0; /* DPMI host provides stack */
|
|
|
|
int386x (0x31, &r, &r, &s);
|
|
okay = (!r.w.cflag);
|
|
|
|
#else
|
|
reg.r_flags = 0;
|
|
intr (pktInfo.intr, (struct REGPACK*)®);
|
|
okay = ((reg.r_flags & 1) == 0);
|
|
#endif
|
|
|
|
if (okay)
|
|
pktInfo.error = NULL;
|
|
else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8);
|
|
return (okay);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
/*
|
|
* Search for packet driver at interrupt 60h through 80h. If ASCIIZ
|
|
* string "PKT DRVR" found at offset 3 in the interrupt handler, return
|
|
* interrupt number, else return zero in pktInfo.intr
|
|
*/
|
|
PUBLIC BOOL PktSearchDriver (void)
|
|
{
|
|
BYTE intr = 0x20;
|
|
BOOL found = FALSE;
|
|
|
|
while (!found && intr < 0xFF)
|
|
{
|
|
static char str[12]; /* 3 + strlen("PKT DRVR") */
|
|
static char pktStr[9] = "PKT DRVR"; /* ASCIIZ string at ofs 3 */
|
|
DWORD rp; /* in interrupt routine */
|
|
|
|
#if (DOSX & PHARLAP)
|
|
_dx_rmiv_get (intr, &rp);
|
|
ReadRealMem (&str, (REALPTR)rp, sizeof(str));
|
|
|
|
#elif (DOSX & DJGPP)
|
|
__dpmi_raddr realAdr;
|
|
__dpmi_get_real_mode_interrupt_vector (intr, &realAdr);
|
|
rp = (realAdr.segment << 4) + realAdr.offset16;
|
|
dosmemget (rp, sizeof(str), &str);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
rp = dpmi_get_real_vector (intr);
|
|
memcpy (&str, (void*)rp, sizeof(str));
|
|
|
|
#else
|
|
_fmemcpy (&str, getvect(intr), sizeof(str));
|
|
#endif
|
|
|
|
found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0;
|
|
intr++;
|
|
}
|
|
pktInfo.intr = (found ? intr-1 : 0);
|
|
return (found);
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
static BOOL PktSetAccess (void)
|
|
{
|
|
reg.r_ax = 0x0200 + pktInfo.class;
|
|
reg.r_bx = 0xFFFF;
|
|
reg.r_dx = 0;
|
|
reg.r_cx = 0;
|
|
|
|
#if (DOSX & PHARLAP)
|
|
reg.ds = 0;
|
|
reg.esi = 0;
|
|
reg.es = RP_SEG (realBase);
|
|
reg.edi = (WORD) &PktReceiver;
|
|
|
|
#elif (DOSX & DJGPP)
|
|
reg.x.ds = 0;
|
|
reg.x.si = 0;
|
|
reg.x.es = rm_mem.rm_segment;
|
|
reg.x.di = PktReceiver;
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
reg.r_ds = 0;
|
|
reg.r_si = 0;
|
|
reg.r_es = rm_base_seg;
|
|
reg.r_di = PktReceiver;
|
|
|
|
#else
|
|
reg.r_ds = 0;
|
|
reg.r_si = 0;
|
|
reg.r_es = FP_SEG (&PktReceiver);
|
|
reg.r_di = FP_OFF (&PktReceiver);
|
|
#endif
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
pktInfo.handle = reg.r_ax;
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktReleaseHandle (WORD handle)
|
|
{
|
|
reg.r_ax = 0x0300;
|
|
reg.r_bx = handle;
|
|
return PktInterrupt();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktTransmit (const void *eth, int len)
|
|
{
|
|
if (len > ETH_MTU)
|
|
return (FALSE);
|
|
|
|
reg.r_ax = 0x0400; /* Function 4, send pkt */
|
|
reg.r_cx = len; /* total size of frame */
|
|
|
|
#if (DOSX & DJGPP)
|
|
dosmemput (eth, len, realBase+pktTxBuf);
|
|
reg.x.ds = rm_mem.rm_segment; /* DOS data segment and */
|
|
reg.x.si = pktTxBuf; /* DOS offset to buffer */
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy ((void*)(realBase+pktTxBuf), eth, len);
|
|
reg.r_ds = rm_base_seg;
|
|
reg.r_si = pktTxBuf;
|
|
|
|
#elif (DOSX & PHARLAP)
|
|
memcpy (&pktTxBuf, eth, len);
|
|
reg.r_ds = FP_SEG (&pktTxBuf);
|
|
reg.r_si = FP_OFF (&pktTxBuf);
|
|
|
|
#else
|
|
reg.r_ds = FP_SEG (eth);
|
|
reg.r_si = FP_OFF (eth);
|
|
#endif
|
|
|
|
return PktInterrupt();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
#if (DOSX & (DJGPP|DOS4GW))
|
|
LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx)
|
|
#else
|
|
LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx)
|
|
#endif
|
|
{
|
|
WORD count_1, count_2;
|
|
|
|
/*
|
|
* We got an upcall to the same RMCB with wrong handle.
|
|
* This can happen if we failed to release handle at program exit
|
|
*/
|
|
if (rx->handle != pktInfo.handle)
|
|
{
|
|
pktInfo.error = "Wrong handle";
|
|
intStat.wrongHandle++;
|
|
PktReleaseHandle (rx->handle);
|
|
return (FALSE);
|
|
}
|
|
count_1 = rx->firstCount;
|
|
count_2 = rx->secondCount;
|
|
|
|
if (count_1 != count_2)
|
|
{
|
|
pktInfo.error = "Bad sync";
|
|
intStat.badSync++;
|
|
return (FALSE);
|
|
}
|
|
if (count_1 > ETH_MAX)
|
|
{
|
|
pktInfo.error = "Large esize";
|
|
intStat.tooLarge++;
|
|
return (FALSE);
|
|
}
|
|
#if 0
|
|
if (count_1 < ETH_MIN)
|
|
{
|
|
pktInfo.error = "Small esize";
|
|
intStat.tooSmall++;
|
|
return (FALSE);
|
|
}
|
|
#endif
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktTerminHandle (WORD handle)
|
|
{
|
|
reg.r_ax = 0x0500;
|
|
reg.r_bx = handle;
|
|
return PktInterrupt();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktResetInterface (WORD handle)
|
|
{
|
|
reg.r_ax = 0x0700;
|
|
reg.r_bx = handle;
|
|
return PktInterrupt();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode)
|
|
{
|
|
if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP)
|
|
return (TRUE);
|
|
|
|
reg.r_ax = 0x1400;
|
|
reg.r_bx = pktInfo.handle;
|
|
reg.r_cx = (WORD)mode;
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
receiveMode = mode;
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode)
|
|
{
|
|
reg.r_ax = 0x1500;
|
|
reg.r_bx = pktInfo.handle;
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
*mode = reg.r_ax;
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static PKT_STAT initialStat; /* statistics at startup */
|
|
static BOOL resetStat = FALSE; /* statistics reset ? */
|
|
|
|
PUBLIC BOOL PktGetStatistics (WORD handle)
|
|
{
|
|
reg.r_ax = 0x1800;
|
|
reg.r_bx = handle;
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
#if (DOSX & PHARLAP)
|
|
ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat));
|
|
|
|
#elif (DOSX & DJGPP)
|
|
dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat));
|
|
|
|
#else
|
|
_fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat));
|
|
#endif
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktSessStatistics (WORD handle)
|
|
{
|
|
if (!PktGetStatistics(pktInfo.handle))
|
|
return (FALSE);
|
|
|
|
if (resetStat)
|
|
{
|
|
pktStat.inPackets -= initialStat.inPackets;
|
|
pktStat.outPackets -= initialStat.outPackets;
|
|
pktStat.inBytes -= initialStat.inBytes;
|
|
pktStat.outBytes -= initialStat.outBytes;
|
|
pktStat.inErrors -= initialStat.inErrors;
|
|
pktStat.outErrors -= initialStat.outErrors;
|
|
pktStat.outErrors -= initialStat.outErrors;
|
|
pktStat.lost -= initialStat.lost;
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktResetStatistics (WORD handle)
|
|
{
|
|
if (!PktGetStatistics(pktInfo.handle))
|
|
return (FALSE);
|
|
|
|
memcpy (&initialStat, &pktStat, sizeof(initialStat));
|
|
resetStat = TRUE;
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktGetAddress (ETHER *addr)
|
|
{
|
|
reg.r_ax = 0x0600;
|
|
reg.r_bx = pktInfo.handle;
|
|
reg.r_cx = sizeof (*addr);
|
|
|
|
#if (DOSX & DJGPP)
|
|
reg.x.es = rm_mem.rm_segment;
|
|
reg.x.di = pktTemp;
|
|
#elif (DOSX & DOS4GW)
|
|
reg.r_es = rm_base_seg;
|
|
reg.r_di = pktTemp;
|
|
#else
|
|
reg.r_es = FP_SEG (&pktTemp);
|
|
reg.r_di = FP_OFF (&pktTemp); /* ES:DI = address for result */
|
|
#endif
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
#if (DOSX & PHARLAP)
|
|
ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr));
|
|
|
|
#elif (DOSX & DJGPP)
|
|
dosmemget (realBase+pktTemp, sizeof(*addr), addr);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr));
|
|
|
|
#else
|
|
memcpy ((void*)addr, &pktTemp, sizeof(*addr));
|
|
#endif
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktSetAddress (const ETHER *addr)
|
|
{
|
|
/* copy addr to real-mode scrath area */
|
|
|
|
#if (DOSX & PHARLAP)
|
|
WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr));
|
|
|
|
#elif (DOSX & DJGPP)
|
|
dosmemput (addr, sizeof(*addr), realBase+pktTemp);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr));
|
|
|
|
#else
|
|
memcpy (&pktTemp, (void*)addr, sizeof(*addr));
|
|
#endif
|
|
|
|
reg.r_ax = 0x1900;
|
|
reg.r_cx = sizeof (*addr); /* address length */
|
|
|
|
#if (DOSX & DJGPP)
|
|
reg.x.es = rm_mem.rm_segment; /* DOS offset to param */
|
|
reg.x.di = pktTemp; /* DOS segment to param */
|
|
#elif (DOSX & DOS4GW)
|
|
reg.r_es = rm_base_seg;
|
|
reg.r_di = pktTemp;
|
|
#else
|
|
reg.r_es = FP_SEG (&pktTemp);
|
|
reg.r_di = FP_OFF (&pktTemp);
|
|
#endif
|
|
|
|
return PktInterrupt();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktGetDriverInfo (void)
|
|
{
|
|
pktInfo.majVer = 0;
|
|
pktInfo.minVer = 0;
|
|
memset (&pktInfo.name, 0, sizeof(pktInfo.name));
|
|
reg.r_ax = 0x01FF;
|
|
reg.r_bx = 0;
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
pktInfo.number = reg.r_cx & 0xFF;
|
|
pktInfo.class = reg.r_cx >> 8;
|
|
#if 0
|
|
pktInfo.minVer = reg.r_bx % 10;
|
|
pktInfo.majVer = reg.r_bx / 10;
|
|
#else
|
|
pktInfo.majVer = reg.r_bx; // !!
|
|
#endif
|
|
pktInfo.funcs = reg.r_ax & 0xFF;
|
|
pktInfo.type = reg.r_dx & 0xFF;
|
|
|
|
#if (DOSX & PHARLAP)
|
|
ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name));
|
|
|
|
#elif (DOSX & DJGPP)
|
|
dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name));
|
|
|
|
#else
|
|
_fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name));
|
|
#endif
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktGetDriverParam (void)
|
|
{
|
|
reg.r_ax = 0x0A00;
|
|
|
|
if (!PktInterrupt())
|
|
return (FALSE);
|
|
|
|
#if (DOSX & PHARLAP)
|
|
ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE);
|
|
|
|
#elif (DOSX & DJGPP)
|
|
dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE);
|
|
|
|
#else
|
|
_fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE);
|
|
#endif
|
|
return (TRUE);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
#if (DOSX & PHARLAP)
|
|
PUBLIC int PktReceive (BYTE *buf, int max)
|
|
{
|
|
WORD inOfs = *rxInOfsFp;
|
|
WORD outOfs = *rxOutOfsFp;
|
|
|
|
if (outOfs != inOfs)
|
|
{
|
|
RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs);
|
|
int size, len = max;
|
|
|
|
if (CheckElement(head))
|
|
{
|
|
size = min (head->firstCount, sizeof(RX_ELEMENT));
|
|
len = min (size, max);
|
|
_fmemcpy (buf, &head->destin, len);
|
|
}
|
|
else
|
|
size = -1;
|
|
|
|
outOfs += sizeof (RX_ELEMENT);
|
|
if (outOfs > LAST_RX_BUF)
|
|
outOfs = FIRST_RX_BUF;
|
|
*rxOutOfsFp = outOfs;
|
|
return (size);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
PUBLIC void PktQueueBusy (BOOL busy)
|
|
{
|
|
*rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp;
|
|
if (*rxOutOfsFp > LAST_RX_BUF)
|
|
*rxOutOfsFp = FIRST_RX_BUF;
|
|
*(DWORD _far*)(protBase + (WORD)&pktDrop) = 0;
|
|
}
|
|
|
|
PUBLIC WORD PktBuffersUsed (void)
|
|
{
|
|
WORD inOfs = *rxInOfsFp;
|
|
WORD outOfs = *rxOutOfsFp;
|
|
|
|
if (inOfs >= outOfs)
|
|
return (inOfs - outOfs) / sizeof(RX_ELEMENT);
|
|
return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
|
|
}
|
|
|
|
PUBLIC DWORD PktRxDropped (void)
|
|
{
|
|
return (*(DWORD _far*)(protBase + (WORD)&pktDrop));
|
|
}
|
|
|
|
#elif (DOSX & DJGPP)
|
|
PUBLIC int PktReceive (BYTE *buf, int max)
|
|
{
|
|
WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs);
|
|
|
|
if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs))
|
|
{
|
|
RX_ELEMENT head;
|
|
int size, len = max;
|
|
|
|
head.firstCount = _farpeekw (_dos_ds, realBase+ofs);
|
|
head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2);
|
|
head.handle = _farpeekw (_dos_ds, realBase+ofs+4);
|
|
|
|
if (CheckElement(&head))
|
|
{
|
|
size = min (head.firstCount, sizeof(RX_ELEMENT));
|
|
len = min (size, max);
|
|
dosmemget (realBase+ofs+6, len, buf);
|
|
}
|
|
else
|
|
size = -1;
|
|
|
|
ofs += sizeof (RX_ELEMENT);
|
|
if (ofs > LAST_RX_BUF)
|
|
_farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
|
|
else _farpokew (_dos_ds, realBase+rxOutOfs, ofs);
|
|
return (size);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
PUBLIC void PktQueueBusy (BOOL busy)
|
|
{
|
|
WORD ofs;
|
|
|
|
disable();
|
|
ofs = _farpeekw (_dos_ds, realBase+rxInOfs);
|
|
if (busy)
|
|
ofs += sizeof (RX_ELEMENT);
|
|
|
|
if (ofs > LAST_RX_BUF)
|
|
_farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
|
|
else _farpokew (_dos_ds, realBase+rxOutOfs, ofs);
|
|
_farpokel (_dos_ds, realBase+pktDrop, 0UL);
|
|
enable();
|
|
}
|
|
|
|
PUBLIC WORD PktBuffersUsed (void)
|
|
{
|
|
WORD inOfs, outOfs;
|
|
|
|
disable();
|
|
inOfs = _farpeekw (_dos_ds, realBase+rxInOfs);
|
|
outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs);
|
|
enable();
|
|
if (inOfs >= outOfs)
|
|
return (inOfs - outOfs) / sizeof(RX_ELEMENT);
|
|
return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
|
|
}
|
|
|
|
PUBLIC DWORD PktRxDropped (void)
|
|
{
|
|
return _farpeekl (_dos_ds, realBase+pktDrop);
|
|
}
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
PUBLIC int PktReceive (BYTE *buf, int max)
|
|
{
|
|
WORD ofs = *(WORD*) (realBase+rxOutOfs);
|
|
|
|
if (ofs != *(WORD*) (realBase+rxInOfs))
|
|
{
|
|
RX_ELEMENT head;
|
|
int size, len = max;
|
|
|
|
head.firstCount = *(WORD*) (realBase+ofs);
|
|
head.secondCount = *(WORD*) (realBase+ofs+2);
|
|
head.handle = *(WORD*) (realBase+ofs+4);
|
|
|
|
if (CheckElement(&head))
|
|
{
|
|
size = min (head.firstCount, sizeof(RX_ELEMENT));
|
|
len = min (size, max);
|
|
memcpy (buf, (const void*)(realBase+ofs+6), len);
|
|
}
|
|
else
|
|
size = -1;
|
|
|
|
ofs += sizeof (RX_ELEMENT);
|
|
if (ofs > LAST_RX_BUF)
|
|
*(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
|
|
else *(WORD*) (realBase+rxOutOfs) = ofs;
|
|
return (size);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
PUBLIC void PktQueueBusy (BOOL busy)
|
|
{
|
|
WORD ofs;
|
|
|
|
_disable();
|
|
ofs = *(WORD*) (realBase+rxInOfs);
|
|
if (busy)
|
|
ofs += sizeof (RX_ELEMENT);
|
|
|
|
if (ofs > LAST_RX_BUF)
|
|
*(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
|
|
else *(WORD*) (realBase+rxOutOfs) = ofs;
|
|
*(DWORD*) (realBase+pktDrop) = 0UL;
|
|
_enable();
|
|
}
|
|
|
|
PUBLIC WORD PktBuffersUsed (void)
|
|
{
|
|
WORD inOfs, outOfs;
|
|
|
|
_disable();
|
|
inOfs = *(WORD*) (realBase+rxInOfs);
|
|
outOfs = *(WORD*) (realBase+rxOutOfs);
|
|
_enable();
|
|
if (inOfs >= outOfs)
|
|
return (inOfs - outOfs) / sizeof(RX_ELEMENT);
|
|
return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
|
|
}
|
|
|
|
PUBLIC DWORD PktRxDropped (void)
|
|
{
|
|
return *(DWORD*) (realBase+pktDrop);
|
|
}
|
|
|
|
#else /* real-mode small/large model */
|
|
|
|
PUBLIC int PktReceive (BYTE *buf, int max)
|
|
{
|
|
if (rxOutOfs != rxInOfs)
|
|
{
|
|
RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs);
|
|
int size, len = max;
|
|
|
|
if (CheckElement(head))
|
|
{
|
|
size = min (head->firstCount, sizeof(RX_ELEMENT));
|
|
len = min (size, max);
|
|
_fmemcpy (buf, &head->destin, len);
|
|
}
|
|
else
|
|
size = -1;
|
|
|
|
rxOutOfs += sizeof (RX_ELEMENT);
|
|
if (rxOutOfs > LAST_RX_BUF)
|
|
rxOutOfs = FIRST_RX_BUF;
|
|
return (size);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
PUBLIC void PktQueueBusy (BOOL busy)
|
|
{
|
|
rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs;
|
|
if (rxOutOfs > LAST_RX_BUF)
|
|
rxOutOfs = FIRST_RX_BUF;
|
|
pktDrop = 0L;
|
|
}
|
|
|
|
PUBLIC WORD PktBuffersUsed (void)
|
|
{
|
|
WORD inOfs = rxInOfs;
|
|
WORD outOfs = rxOutOfs;
|
|
|
|
if (inOfs >= outOfs)
|
|
return ((inOfs - outOfs) / sizeof(RX_ELEMENT));
|
|
return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT));
|
|
}
|
|
|
|
PUBLIC DWORD PktRxDropped (void)
|
|
{
|
|
return (pktDrop);
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************/
|
|
|
|
LOCAL __inline void PktFreeMem (void)
|
|
{
|
|
#if (DOSX & PHARLAP)
|
|
if (realSeg)
|
|
{
|
|
_dx_real_free (realSeg);
|
|
realSeg = 0;
|
|
}
|
|
#elif (DOSX & DJGPP)
|
|
if (rm_mem.rm_segment)
|
|
{
|
|
unsigned ofs; /* clear the DOS-mem to prevent further upcalls */
|
|
|
|
for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4)
|
|
_farpokel (_dos_ds, realBase + ofs, 0);
|
|
_go32_dpmi_free_dos_memory (&rm_mem);
|
|
rm_mem.rm_segment = 0;
|
|
}
|
|
#elif (DOSX & DOS4GW)
|
|
if (rm_base_sel)
|
|
{
|
|
dpmi_real_free (rm_base_sel);
|
|
rm_base_sel = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
PUBLIC BOOL PktExitDriver (void)
|
|
{
|
|
if (pktInfo.handle)
|
|
{
|
|
if (!PktSetReceiverMode(PDRX_BROADCAST))
|
|
PUTS ("Error restoring receiver mode.");
|
|
|
|
if (!PktReleaseHandle(pktInfo.handle))
|
|
PUTS ("Error releasing PKT-DRVR handle.");
|
|
|
|
PktFreeMem();
|
|
pktInfo.handle = 0;
|
|
}
|
|
|
|
if (pcap_pkt_debug >= 1)
|
|
printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, "
|
|
"wrong-handle %lu\n",
|
|
intStat.tooSmall, intStat.tooLarge,
|
|
intStat.badSync, intStat.wrongHandle);
|
|
return (TRUE);
|
|
}
|
|
|
|
#if (DOSX & (DJGPP|DOS4GW))
|
|
static void dump_pkt_stub (void)
|
|
{
|
|
int i;
|
|
|
|
fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n",
|
|
PktReceiver);
|
|
for (i = 0; i < 15; i++)
|
|
fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]);
|
|
fputs ("\n", stderr);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Front end initialization routine
|
|
*/
|
|
PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode)
|
|
{
|
|
PKT_RX_MODE rxMode;
|
|
BOOL writeInfo = (pcap_pkt_debug >= 3);
|
|
|
|
pktInfo.quiet = (pcap_pkt_debug < 3);
|
|
|
|
#if (DOSX & PHARLAP) && defined(__HIGHC__)
|
|
if (_mwenv != 2)
|
|
{
|
|
fprintf (stderr, "Only Pharlap DOS extender supported.\n");
|
|
return (FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (DOSX & PHARLAP) && defined(__WATCOMC__)
|
|
if (_Extender != 1)
|
|
{
|
|
fprintf (stderr, "Only DOS4GW style extenders supported.\n");
|
|
return (FALSE);
|
|
}
|
|
#endif
|
|
|
|
if (!PktSearchDriver())
|
|
{
|
|
PUTS ("Packet driver not found.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!PktGetDriverInfo())
|
|
{
|
|
PUTS ("Error getting pkt-drvr information.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
#if (DOSX & PHARLAP)
|
|
if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd,
|
|
&realBase, &protBase, (USHORT*)&realSeg))
|
|
{
|
|
rxOutOfsFp = (WORD _far *) (protBase + (WORD) &rxOutOfs);
|
|
rxInOfsFp = (WORD _far *) (protBase + (WORD) &rxInOfs);
|
|
*rxOutOfsFp = FIRST_RX_BUF;
|
|
*rxInOfsFp = FIRST_RX_BUF;
|
|
}
|
|
else
|
|
{
|
|
PUTS ("Cannot allocate real-mode stub.");
|
|
return (FALSE);
|
|
}
|
|
|
|
#elif (DOSX & (DJGPP|DOS4GW))
|
|
if (sizeof(real_stub_array) > 0xFFFF)
|
|
{
|
|
fprintf (stderr, "`real_stub_array[]' too big.\n");
|
|
return (FALSE);
|
|
}
|
|
#if (DOSX & DJGPP)
|
|
rm_mem.size = (sizeof(real_stub_array) + 15) / 16;
|
|
|
|
if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0)
|
|
{
|
|
PUTS ("real-mode init failed.");
|
|
return (FALSE);
|
|
}
|
|
realBase = (rm_mem.rm_segment << 4);
|
|
dosmemput (&real_stub_array, sizeof(real_stub_array), realBase);
|
|
_farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF);
|
|
_farpokel (_dos_ds, realBase+rxInOfs, FIRST_RX_BUF);
|
|
|
|
#elif (DOSX & DOS4GW)
|
|
rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel);
|
|
if (!rm_base_seg)
|
|
{
|
|
PUTS ("real-mode init failed.");
|
|
return (FALSE);
|
|
}
|
|
realBase = (rm_base_seg << 4);
|
|
memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array));
|
|
*(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF;
|
|
*(WORD*) (realBase+rxInOfs) = FIRST_RX_BUF;
|
|
|
|
#endif
|
|
{
|
|
int pushf = PktReceiver;
|
|
|
|
while (real_stub_array[pushf++] != 0x9C && /* pushf */
|
|
real_stub_array[pushf] != 0xFA) /* cli */
|
|
{
|
|
if (++para_skip > 16)
|
|
{
|
|
fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n");
|
|
para_skip = 0;
|
|
dump_pkt_stub();
|
|
return (FALSE);
|
|
}
|
|
}
|
|
if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800)
|
|
{
|
|
fprintf (stderr, "`real_stub_array[]' is misaligned.\n");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if (pcap_pkt_debug > 2)
|
|
dump_pkt_stub();
|
|
|
|
#else
|
|
rxOutOfs = FIRST_RX_BUF;
|
|
rxInOfs = FIRST_RX_BUF;
|
|
#endif
|
|
|
|
if (!PktSetAccess())
|
|
{
|
|
PUTS ("Error setting pkt-drvr access.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!PktGetAddress(&myAddress))
|
|
{
|
|
PUTS ("Error fetching adapter address.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!PktSetReceiverMode(mode))
|
|
{
|
|
PUTS ("Error setting receiver mode.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!PktGetReceiverMode(&rxMode))
|
|
{
|
|
PUTS ("Error getting receiver mode.");
|
|
PktFreeMem();
|
|
return (FALSE);
|
|
}
|
|
|
|
if (writeInfo)
|
|
printf ("Pkt-driver information:\n"
|
|
" Version : %d.%d\n"
|
|
" Name : %.15s\n"
|
|
" Class : %u (%s)\n"
|
|
" Type : %u\n"
|
|
" Number : %u\n"
|
|
" Funcs : %u\n"
|
|
" Intr : %Xh\n"
|
|
" Handle : %u\n"
|
|
" Extended : %s\n"
|
|
" Hi-perf : %s\n"
|
|
" RX mode : %s\n"
|
|
" Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
|
|
pktInfo.majVer, pktInfo.minVer, pktInfo.name,
|
|
pktInfo.class, PktGetClassName(pktInfo.class),
|
|
pktInfo.type, pktInfo.number,
|
|
pktInfo.funcs, pktInfo.intr, pktInfo.handle,
|
|
pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No",
|
|
pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No",
|
|
PktRXmodeStr(rxMode),
|
|
myAddress[0], myAddress[1], myAddress[2],
|
|
myAddress[3], myAddress[4], myAddress[5]);
|
|
|
|
#if defined(DEBUG) && (DOSX & PHARLAP)
|
|
if (writeInfo)
|
|
{
|
|
DWORD rAdr = realBase + (WORD)&PktReceiver;
|
|
unsigned sel, ofs;
|
|
|
|
printf ("\nReceiver at %04X:%04X\n", RP_SEG(rAdr), RP_OFF(rAdr));
|
|
printf ("Realbase = %04X:%04X\n", RP_SEG(realBase),RP_OFF(realBase));
|
|
|
|
sel = _FP_SEG (protBase);
|
|
ofs = _FP_OFF (protBase);
|
|
printf ("Protbase = %04X:%08X\n", sel,ofs);
|
|
printf ("RealSeg = %04X\n", realSeg);
|
|
|
|
sel = _FP_SEG (rxOutOfsFp);
|
|
ofs = _FP_OFF (rxOutOfsFp);
|
|
printf ("rxOutOfsFp = %04X:%08X\n", sel,ofs);
|
|
|
|
sel = _FP_SEG (rxInOfsFp);
|
|
ofs = _FP_OFF (rxInOfsFp);
|
|
printf ("rxInOfsFp = %04X:%08X\n", sel,ofs);
|
|
|
|
printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n",
|
|
*rxOutOfsFp, *rxInOfsFp);
|
|
|
|
PktQueueBusy (TRUE);
|
|
printf ("Busy: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n",
|
|
*rxOutOfsFp, *rxInOfsFp);
|
|
}
|
|
#endif
|
|
|
|
memset (&pktStat, 0, sizeof(pktStat)); /* clear statistics */
|
|
PktQueueBusy (TRUE);
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* DPMI functions only for Watcom + DOS4GW extenders
|
|
*/
|
|
#if (DOSX & DOS4GW)
|
|
LOCAL DWORD dpmi_get_real_vector (int intr)
|
|
{
|
|
union REGS r;
|
|
|
|
r.x.eax = 0x200;
|
|
r.x.ebx = (DWORD) intr;
|
|
int386 (0x31, &r, &r);
|
|
return ((r.w.cx << 4) + r.w.dx);
|
|
}
|
|
|
|
LOCAL WORD dpmi_real_malloc (int size, WORD *selector)
|
|
{
|
|
union REGS r;
|
|
|
|
r.x.eax = 0x0100; /* DPMI allocate DOS memory */
|
|
r.x.ebx = (size + 15) / 16; /* Number of paragraphs requested */
|
|
int386 (0x31, &r, &r);
|
|
if (r.w.cflag & 1)
|
|
return (0);
|
|
|
|
*selector = r.w.dx;
|
|
return (r.w.ax); /* Return segment address */
|
|
}
|
|
|
|
LOCAL void dpmi_real_free (WORD selector)
|
|
{
|
|
union REGS r;
|
|
|
|
r.x.eax = 0x101; /* DPMI free DOS memory */
|
|
r.x.ebx = selector; /* Selector to free */
|
|
int386 (0x31, &r, &r);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(DOSX) && (DOSX & PHARLAP)
|
|
/*
|
|
* Description:
|
|
* This routine allocates conventional memory for the specified block
|
|
* of code (which must be within the first 64K of the protected mode
|
|
* program segment) and copies the code to it.
|
|
*
|
|
* The caller should free up the conventional memory block when it
|
|
* is done with the conventional memory.
|
|
*
|
|
* NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER.
|
|
*
|
|
* Calling arguments:
|
|
* start_offs start of real mode code in program segment
|
|
* end_offs 1 byte past end of real mode code in program segment
|
|
* real_basep returned; real mode ptr to use as a base for the
|
|
* real mode code (eg, to get the real mode FAR
|
|
* addr of a function foo(), take
|
|
* real_basep + (ULONG) foo).
|
|
* This pointer is constructed such that
|
|
* offsets within the real mode segment are
|
|
* the same as the link-time offsets in the
|
|
* protected mode program segment
|
|
* prot_basep returned; prot mode ptr to use as a base for getting
|
|
* to the conventional memory, also constructed
|
|
* so that adding the prot mode offset of a
|
|
* function or variable to the base gets you a
|
|
* ptr to the function or variable in the
|
|
* conventional memory block.
|
|
* rmem_adrp returned; real mode para addr of allocated
|
|
* conventional memory block, to be used to free
|
|
* up the conventional memory when done. DO NOT
|
|
* USE THIS TO CONSTRUCT A REAL MODE PTR, USE
|
|
* REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT
|
|
* CORRECTLY.
|
|
*
|
|
* Returned values:
|
|
* 0 if error
|
|
* 1 if success
|
|
*/
|
|
int RealCopy (ULONG start_offs,
|
|
ULONG end_offs,
|
|
REALPTR *real_basep,
|
|
FARPTR *prot_basep,
|
|
USHORT *rmem_adrp)
|
|
{
|
|
ULONG rm_base; /* base real mode para addr for accessing */
|
|
/* allocated conventional memory */
|
|
UCHAR *source; /* source pointer for copy */
|
|
FARPTR destin; /* destination pointer for copy */
|
|
ULONG len; /* number of bytes to copy */
|
|
ULONG temp;
|
|
USHORT stemp;
|
|
|
|
/* First check for valid inputs
|
|
*/
|
|
if (start_offs >= end_offs || end_offs > 0x10000)
|
|
return (FALSE);
|
|
|
|
/* Round start_offs down to a paragraph (16-byte) boundary so we can set up
|
|
* the real mode pointer easily. Round up end_offs to make sure we allocate
|
|
* enough paragraphs
|
|
*/
|
|
start_offs &= ~15;
|
|
end_offs = (15 + (end_offs << 4)) >> 4;
|
|
|
|
/* Allocate the conventional memory for our real mode code. Remember to
|
|
* round byte count UP to 16-byte paragraph size. We alloc it
|
|
* above the DOS data buffer so both the DOS data buffer and the appl
|
|
* conventional mem block can still be resized.
|
|
*
|
|
* First just try to alloc it; if we can't get it, shrink the appl mem
|
|
* block down to the minimum, try to alloc the memory again, then grow the
|
|
* appl mem block back to the maximum. (Don't try to shrink the DOS data
|
|
* buffer to free conventional memory; it wouldn't be good for this routine
|
|
* to have the possible side effect of making file I/O run slower.)
|
|
*/
|
|
len = ((end_offs - start_offs) + 15) >> 4;
|
|
if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE)
|
|
{
|
|
if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE)
|
|
return (FALSE);
|
|
|
|
if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE)
|
|
*rmem_adrp = 0;
|
|
|
|
if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE)
|
|
{
|
|
if (*rmem_adrp != 0)
|
|
_dx_real_free (*rmem_adrp);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (*rmem_adrp == 0)
|
|
return (FALSE);
|
|
}
|
|
|
|
/* Construct real mode & protected mode pointers to access the allocated
|
|
* memory. Note we know start_offs is aligned on a paragraph (16-byte)
|
|
* boundary, because we rounded it down.
|
|
*
|
|
* We make the offsets come out rights by backing off the real mode selector
|
|
* by start_offs.
|
|
*/
|
|
rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4);
|
|
RP_SET (*real_basep, 0, rm_base);
|
|
FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM);
|
|
|
|
/* Copy the real mode code/data to the allocated memory
|
|
*/
|
|
source = (UCHAR *) start_offs;
|
|
destin = *prot_basep;
|
|
FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep));
|
|
len = end_offs - start_offs;
|
|
WriteFarMem (destin, source, len);
|
|
|
|
return (TRUE);
|
|
}
|
|
#endif /* DOSX && (DOSX & PHARLAP) */
|