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