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