/* | |
* 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) */ |