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