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