xref: /freebsd/contrib/libpcap/msdos/pktdrvr.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
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) */
1437