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