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