Watt-32 tcp/ip  2.2 dev-rel.10
pcpkt.c
Go to the documentation of this file.
1 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stddef.h>
12 #include <string.h>
13 #include <limits.h>
14 
15 #include "copyrigh.h"
16 #include "wattcp.h"
17 
18 /* All this is for MS-DOS only. For Win32, refer winpkt.c instead.
19  */
20 #if defined(__MSDOS__)
21 
22 #if defined(__DJGPP__)
23  #include <sys/exceptn.h>
24  #include <sys/nearptr.h>
25  #include <crt0.h>
26 #endif
27 
28 #include "wdpmi.h"
29 #include "x32vm.h"
30 #include "powerpak.h"
31 #include "asmpkt.h"
32 #include "strings.h"
33 #include "language.h"
34 #include "sock_ini.h"
35 #include "cpumodel.h"
36 #include "misc.h"
37 #include "timer.h"
38 #include "profile.h"
39 #include "pcsed.h"
40 #include "pcstat.h"
41 #include "pcconfig.h"
42 #include "pcdbug.h"
43 #include "pcigmp.h"
44 #include "pcqueue.h"
45 #include "pcpkt.h"
46 #include "pcpkt32.h"
47 
48 
49 /*@-usedef@*/
50 
51 WORD _pktdevclass = PDCLASS_UNKNOWN;
52 WORD _pkt_ip_ofs = 0;
53 WORD _pkt_type_ofs = 0;
54 BOOL _pktserial = FALSE;
55 BYTE _pktdevlevel = 1;
57 int _pkt_rxmode0 = -1;
58 int _pkt_errno = 0;
59 const char *pkt_error = NULL;
62 char _pktdrvrname[20] = "unknown";
63 
64 struct pkt_info *_pkt_inf = NULL;
66 static char pkt_sign[] = "PKT DRVR";
67 static WORD pkt_interrupt = 0;
68 static DWORD pkt_drop_cnt = 0;
69 static BYTE pkt_txretries = 2;
70 static int pkt_txwait = 0; /* # msec to wait if Tx fails */
71 static BOOL pkt_use_near = FALSE; /* Use near-ptr if enabled */
72 static BOOL pkt_do_reset = FALSE; /* reset handle at exit */
73 static int pkt_drvr_ver = 0; /* Driver internal version */
74 static int pkt_num_rx_bufs = RX_BUFS;
75 
76 #if defined(USE_STATISTICS)
77  static struct PktStats init_stats;
78  static void get_init_stats (void);
79 #endif
80 
81 static struct PktParameters pkt_params;
82 static BOOL got_params = FALSE;
83 
84 int pkt_release_handle (WORD handle);
85 int pkt_reset_handle (WORD handle);
86 
91 #define PKT_FIRST_VEC 0x60
92 #define PKT_LAST_VEC 0x80
93 #define PKT_FIRST_VEC_11 0x20
94 #define PKT_LAST_VEC_11 0xFF
95 
96 
97 #if (DOSX & PHARLAP)
98  #include <mw/exc.h>
99 
100  REALPTR rm_base;
101 
102  /*
103  * real-data is organised as follows: PKT_TMP at rm_base + 0x40
104  * TX_BUF at PKT_TMP + PKT_TMP_SIZE
105  * RX_BUF at TX_BUF + RX_SIZE
106  */
107  #define PKT_TMP() (WORD) 0x40
108  #define TX_BUF() (PKT_TMP() + PKT_TMP_SIZE) /* DWORD boundary */
109  #define RX_BUF() (TX_BUF() + RX_SIZE)
110  #define RDATA_SIZE (RX_BUF() + RX_SIZE)
111  #define RP_SEGM() RP_SEG (rm_base)
112 
113 #elif (DOSX & X32VM) /* X32VM is very similar to Pharlap except that it */
114  REALPTR rm_base; /* automatically maps DOS memory into our DS */
115 
116  #define PKT_TMP() (WORD) 0x40
117  #define TX_BUF() (PKT_TMP() + PKT_TMP_SIZE)
118  #define RX_BUF() (TX_BUF() + RX_SIZE)
119  #define RDATA_SIZE (RX_BUF() + RX_SIZE)
120  #define RP_SEGM() RP_SEG (rm_base)
121 
122 #elif (DOSX & DJGPP)
123  #if !defined(USE_FAST_PKT)
124  #define RMCB_STK_SIZE 2048
125  #include "gormcb_c.inc"
126  static _go32_dpmi_seginfo rm_cb;
127  #endif
128 
129  static DWORD rm_base;
130 
131  /*
132  * real-data is organised as follows: PKT_TMP at rm_base + 0
133  * TX_BUF at PKT_TMP + PKT_TMP_SIZE
134  * RX_BUF at TX_BUF + RX_SIZE
135  */
136  #define PKT_TMP() 0
137  #define TX_BUF() (PKT_TMP() + PKT_TMP_SIZE)
138  #define RX_BUF() (TX_BUF() + RX_SIZE)
139  #define RDATA_SIZE (RX_BUF() + RX_SIZE)
140  #define RP_SEGM() _pkt_inf->rm_seg
141 
142 #elif (DOSX & DOS4GW) /* All DOS4GW type extenders */
143 
144  static DWORD rm_base; /* Linear address (in DOS) for allocated area */
145  #if !defined(USE_FAST_PKT)
146  static WORD pkt_inf_sel; /* selector returned from `_pkt_inf' allocation */
147  #endif
148 
149  /*
150  * The DOS-area (0-1MB) is automagically mapped into application
151  * data. This eases communication with packet-driver, but clean
152  * crashes can not be expected. i.e. bugs (dereferencing null-ptr)
153  * in application will most likely hang the machine.
154  *
155  * Real-mode code/data is organised like this:
156  * pkt_receiver4_start() copied to allocated area at rm_base
157  * PKT_TMP at rm_base + (pkt_receiver4_end() - pkt_receiver4_start())
158  * TX_BUF at PKT_TMP + PKT_TMP_SIZE
159  * end area at TX_BUF + RX_SIZE
160  * RX_BUF is in DOS-allocated `_pkt_inf' structure.
161  */
162  #define PKT_TMP() ((DWORD)pkt_receiver4_end - \
163  (DWORD)pkt_receiver4_start)
164  #define TX_BUF() (PKT_TMP() + PKT_TMP_SIZE)
165  #define RCV_OFS() ((DWORD)pkt_receiver4_rm - \
166  (DWORD)pkt_receiver4_start)
167  #define RP_SEGM() _pkt_inf->rm_seg
168 
169 #elif (DOSX & POWERPAK)
170  static REALPTR rm_base;
171  #if !defined(USE_FAST_PKT)
172  static DPMI_callback rm_cb;
173  #endif
174 
175  #define PKT_TMP() 0
176  #define TX_BUF() (PKT_TMP() + PKT_TMP_SIZE)
177  #define RX_BUF() (TX_BUF() + RX_SIZE)
178  #define RDATA_SIZE (RX_BUF() + RX_SIZE)
179  #define RP_SEGM() _pkt_inf->rm_seg
180 
181 #elif (DOSX == 0)
182  void (__cdecl _far * pkt_enque_ptr) (BYTE _far *buf, WORD len);
183  void (__cdecl _far *_pkt_enque_ptr) (BYTE _far *buf, WORD len);
184 
185 #else
186  #error Help me!
187 #endif
188 
189 
190 #if defined(USE_FAST_PKT)
191  #include "pcpkt2.c"
192 
193 #elif (DOSX)
194  static int setup_rmode_callback (void);
195  static int lock_code_and_data (void);
196  static int unlock_code_and_data (void);
197 #endif
198 
199 static int find_vector (int first, int num);
200 static int setup_pkt_inf (void);
201 static void get_rmode_data (void *dest, unsigned size, WORD seg, WORD ofs);
202 static BOOL pkt_api_entry (IREGS *reg, unsigned called_from_line);
203 
204 #define PKT_API(reg) pkt_api_entry (reg, __LINE__)
205 #define CARRY_BIT 1 /* carry bit in (e)flags register */
206 
207 #define PKT_ERR(str,code) do { \
208  const char *err = pkt_strerror (code); \
209  outs (_LANG(str)); \
210  outsnl (err); \
211  } while (0)
212 
216 const char * W32_CALL pkt_strerror (int code)
217 {
218  static char buf[50];
219  static const char *errors[] = {
220  __LANG("Unknown driver error (0x--)"),
221  /* 1 */ __LANG("Invalid handle number"),
222  __LANG("No interfaces of specified class found"),
223  /* 3 */ __LANG("No interfaces of specified type found"),
224  __LANG("No interfaces of specified number found"),
225  /* 5 */ __LANG("Bad packet type specified"),
226  __LANG("This interface does not support multicast"),
227  /* 7 */ __LANG("This packet driver cannot terminate"),
228  __LANG("An invalid receiver mode was specified"),
229  /* 9 */ __LANG("Operation failed because of insufficient space"),
230  __LANG("Type previously accessed, and not released"),
231  /* 11 */ __LANG("The command was out of range, or not implemented"),
232  __LANG("Cannot send packet (hardware error)"),
233  /* 13 */ __LANG("Cannot change hardware address"),
234  __LANG("Hardware address has bad length/format"),
235  /* 15 */ __LANG("Could not reset interface"),
236  __LANG("Extended driver needed")
237  };
238  const char *rc;
239  char *p;
240 
241  if (code > 0 && code < DIM(errors))
242  return (_LANG(errors[code]));
243 
244  rc = _strlcpy (buf, _LANG(errors[0]), sizeof(buf));
245  p = strchr (rc, '(');
246  if (p && strlen(p) >= 5)
247  {
248  code &= 0xFF;
249  p[3] = hex_chars_upper [code >> 4];
250  p[4] = hex_chars_upper [code & 15];
251  }
252  return (buf);
253 }
254 
255 /* Return TRUE is adapter is up.
256  */
257 BOOL W32_CALL pkt_is_init (void)
258 {
259  return (_pkt_inf != NULL);
260 }
261 
262 /*
263  * Only for testing asmpkt4.asm
264  */
265 #if (DOSX & DOS4GW) && 0
266 static void dump_asm4 (void)
267 {
268  const BYTE *p = (const BYTE*) rm_base;
269  int i;
270 
271  printf ("PKT_INF %08lX, HEAD %08lX, QUEUE %08lX, INDEX %04X, XYPOS %d\n",
272  *(DWORD*)p, *(DWORD*)(p+4), *(DWORD*)(p+8), *(WORD*)(p+12),
273  *(WORD*)(p+14));
274 
275  printf ("rm_base %08lX, handle %04X, is_serial %d\n",
276  rm_base, _pkt_inf->handle, _pkt_inf->is_serial);
277 
278  printf ("VAR_1-14: ");
279  for (i = 16; i <= 42; i += 2)
280  printf ("%04X ", *(WORD*)(p+i));
281 
282 #if 0
283  printf ("PKT_RECV: ");
284  for (i = RCV_OFS(); i < RCV_OFS()+10; i++)
285  printf ("%02X ", p[i]);
286 
287  printf ("\nPKT_TMP: ");
288  for (i = PKT_TMP(); i < PKT_TMP()+PKT_TMP_SIZE; i++)
289  printf ("%02X ", p[i]);
290 #endif
291  fflush (stdout);
292 }
293 #endif
294 
295 
301 #if (DOSX & DOS4GW)
302 void *pkt_tx_buf (void)
303 {
304  return (void*)(rm_base + TX_BUF());
305 }
306 
307 #elif (DOSX & DJGPP)
308 void *pkt_tx_buf (void)
309 {
310  if (_pkt_inf && _pkt_inf->use_near_ptr)
311  return (void*)(rm_base + TX_BUF() + __djgpp_conventional_base);
312  fprintf (stderr, "%s (%d): wrong usage of pkt_tx_buf()\n",
313  __FILE__, __LINE__);
314  exit (-1);
315  /*@-unreachable-*/
316  return (NULL);
317 }
318 
319 #elif (DOSX & X32VM)
320 void *pkt_tx_buf (void)
321 {
322  return (void*) ((RP_SEG(rm_base) << 4) + RP_OFF(rm_base) +
323  (DWORD)_x386_zero_base_ptr + TX_BUF());
324 }
325 #endif
326 
332 static int pkt_set_access (void)
333 {
334  IREGS regs;
335 
336  ASSERT_PKT_INF (0);
337 
338  memset (&regs, 0, sizeof(regs));
339 
340  regs.r_ax = PD_ACCESS | _pktdevclass;
341  regs.r_bx = 0xFFFF; /* any type */
342  regs.r_dx = 0; /* generic interface */
343  regs.r_cx = 0; /* receive any proto */
344 
345 #if defined(USE_FAST_PKT)
346  regs.r_es = _pkt_inf->rm_seg;
347  regs.r_di = PktReceiver;
348 
349 #elif (DOSX & DJGPP)
350  regs.r_es = rm_cb.rm_segment;
351  regs.r_di = rm_cb.rm_offset;
352 
353 #elif (DOSX & (PHARLAP|X32VM))
354  regs.r_es = RP_SEGM();
355  regs.r_di = 0; /* RMCB aligned at para address */
356 
357 #elif (DOSX & POWERPAK)
358  regs.r_es = RP_SEG (rm_cb.rm_addr);
359  regs.r_di = RP_OFF (rm_cb.rm_addr);
360 
361 #elif (DOSX & DOS4GW)
362  regs.r_es = RP_SEGM();
363  regs.r_di = RCV_OFS();
364 
365 #else /* real-mode targets */
366  regs.r_es = FP_SEG (pkt_receiver_rm); /* = this CS */
367  regs.r_di = FP_OFF (pkt_receiver_rm);
368 #endif
369 
370  if (!PKT_API(&regs))
371  {
372  PKT_ERR ("Error allocating handle: ", _pkt_errno);
373  return (0);
374  }
375  _pkt_inf->handle = (WORD) regs.r_ax;
376  return (1);
377 }
378 
382 static int pkt_drvr_info (void)
383 {
384  IREGS regs;
385  int rc = 1; /* assume okay */
386 
387  ASSERT_PKT_INF (0);
388 
389  /* Lets find out about the driver
390  */
391  memset (&regs, 0, sizeof(regs));
392  regs.r_ax = PD_DRIVER_INFO;
393 
394  if (!PKT_API(&regs))
395  {
396  TCP_CONSOLE_MSG (0, ("Warning: old-type PKTDRVR\n"));
397  _pktdevclass = PDCLASS_ETHER; /* assume Ethernet */
398  _pkt_ip_ofs = sizeof(eth_Header);
399  _pkt_type_ofs = offsetof (struct eth_Header, type);
400  _pkt_errno = 0;
401  }
402  else /* new Packet-Driver (1.09+) */
403  {
404  _pktdevlevel = loBYTE (regs.r_ax);
405  _pktdevclass = hiBYTE (regs.r_cx);
406  pkt_drvr_ver = regs.r_bx & 0xFFFF;
407 
408  switch (_pktdevclass)
409  {
410  case PDCLASS_TOKEN:
411  case PDCLASS_TOKEN_RIF: /* !! fix me */
412  _pkt_ip_ofs = sizeof(tok_Header);
413  _pkt_type_ofs = offsetof (struct tok_Header, type);
414  break;
415 
416  case PDCLASS_ETHER:
417  _pkt_ip_ofs = sizeof(eth_Header);
418  _pkt_type_ofs = offsetof (struct eth_Header, type);
419  break;
420 
421  case PDCLASS_FDDI:
422  _pkt_ip_ofs = sizeof(fddi_Header);
423  _pkt_type_ofs = offsetof (struct fddi_Header, type);
424  break;
425 
426  case PDCLASS_ARCNET:
427  _pkt_ip_ofs = ARC_HDRLEN;
428  _pkt_type_ofs = ARC_TYPE_OFS;
429  break;
430 
431  case PDCLASS_SLIP:
432  case PDCLASS_PPP:
433  case PDCLASS_AX25: /* !! for now */
434  _pkt_ip_ofs = 0;
435  _pkt_type_ofs = 0;
436  break;
437 
438  default:
439  outs (_LANG("PKT-ERROR: Unsupported driver class "));
440  outhex ((char)_pktdevclass);
441  outsnl ("h");
442  _pkt_errno = PDERR_NO_CLASS;
443  rc = 0;
444  }
445  get_rmode_data (_pktdrvrname, sizeof(_pktdrvrname), regs.r_ds, regs.r_si);
446  _pktdrvrname [sizeof(_pktdrvrname)-1] = '\0';
447 
448  if (pkt_txwait == 0 &&
449  !strcmp(_pktdrvrname,"NDIS3PKT"))
450  pkt_txwait = 1; /* This helps when using NDIS3PKT */
451  }
452 
453  _pktserial = (_pktdevclass == PDCLASS_SLIP ||
454  _pktdevclass == PDCLASS_PPP ||
455  _pktdevclass == PDCLASS_AX25);
456 
457  _pkt_inf->is_serial = _pktserial;
458  _pkt_inf->pkt_ip_ofs = _pkt_ip_ofs;
459  _pkt_inf->pkt_type_ofs = _pkt_type_ofs;
460  return (rc);
461 }
462 
466 int pkt_get_params (struct PktParameters *params)
467 {
468  IREGS regs;
469  int rc = 0;
470 
471  memset (&regs, 0, sizeof(regs));
472  regs.r_ax = PD_GET_PARAM; /* get driver parameters */
473 
474  DISABLE();
475  if (PKT_API(&regs))
476  {
477  get_rmode_data (params, sizeof(*params), regs.r_es, regs.r_di);
478  got_params = TRUE;
479  rc = 1;
480  }
481  ENABLE();
482  return (rc);
483 }
484 
489 int pkt_get_mtu (void)
490 {
491  if (_pktdevclass == PDCLASS_ARCNET)
492  return (ARCNET_MAX_DATA - 8);
493 
494  if (got_params)
495  return (pkt_params.mtu);
496  return (-1);
497 }
498 
499 #ifdef NOT_USED
500 
504 int pkt_get_mac_len (void)
505 {
506  if (_pktdevclass == PDCLASS_ARCNET)
507  return (sizeof(arcnet_address));
508  if (got_params)
509  return (pkt_params.addr_len);
510  return (-1);
511 }
512 #endif
513 
519 int pkt_get_api_ver (WORD *ver)
520 {
521  if (got_params)
522  {
523  *ver = ((pkt_params.major_rev << 8) + pkt_params.minor_rev);
524  return (1);
525  }
526  return (0);
527 }
528 
532 int pkt_get_drvr_ver (WORD *major, WORD *minor, WORD *unused1, WORD *unused2)
533 {
534  if (!pkt_drvr_ver)
535  return (0);
536  *major = pkt_drvr_ver >> 8;
537  *minor = pkt_drvr_ver & 255;
538  ARGSUSED (unused1);
539  ARGSUSED (unused2);
540  return (1);
541 }
542 
546 W32_FUNC int W32_CALL pkt_get_vector (void)
547 {
548  return (pkt_interrupt);
549 }
550 
551 /*
552  * Return driver class
553  */
554 W32_FUNC WORD W32_CALL pkt_get_drvr_class (void)
555 {
556  return (_pktdevclass);
557 }
558 
559 /*
560  * Returns low-level PktDriver name.
561  */
562 const char * W32_CALL pkt_get_device_name (void)
563 {
564  return (_pktdrvrname);
565 }
566 
578 static int pkt16_drvr_init (mac_address *mac_addr)
579 {
580  /* If interrupt specified in config-file ("PKT.VECTOR = 0xNN"),
581  * check a single vector. Else, search for the 1st driver in range
582  * 0x60-0x80.
583  */
584  if (pkt_interrupt)
585  pkt_interrupt = find_vector (pkt_interrupt, 1);
586  else pkt_interrupt = find_vector (PKT_FIRST_VEC,
587  PKT_LAST_VEC - PKT_FIRST_VEC + 1);
588 
589  if (pkt_interrupt == 0)
590  {
591  outsnl (_LANG("NO PACKET DRIVER FOUND."));
592  return (WERR_NO_DRIVER);
593  }
594 
595  if (!setup_pkt_inf())
596  {
597  outsnl (_LANG("Failed to allocate PACKET DRIVER data."));
598  return (WERR_NO_MEM);
599  }
600 
601 #if defined(USE_FAST_PKT)
602  switch (setup_rmode_receiver())
603  {
604  case -1:
605  outsnl (_LANG("Error in PACKET DRIVER stub code."));
606  return (WERR_PKT_ERROR);
607  }
608 #elif (DOSX)
609  switch (setup_rmode_callback())
610  {
611  case -1:
612  outsnl (_LANG("Failed to allocate callback for PACKET DRIVER."));
613  return (WERR_NO_MEM);
614  case -2:
615  outsnl (_LANG("Failed to allocate DOS-mem for PACKET DRIVER."));
616  case -3: /* msg already printed */
617  return (WERR_NO_MEM);
618  }
619 
620  if (lock_code_and_data() < 0)
621  {
622  outsnl (_LANG("Failed to lock code/data for PACKET DRIVER."));
623  return (WERR_PKT_ERROR);
624  }
625 #endif /* USE_FAST_PKT */
626 
627  if (!pkt_drvr_info()) /* get device class etc. of driver */
628  return (WERR_PKT_ERROR);
629 
630  if (!pkt_set_access()) /* set upcall receive handler */
631  {
632  pkt_release();
633  return (WERR_PKT_ERROR);
634  }
635 
636  if (!pkt_get_addr(mac_addr)) /* get our MAC address */
637  {
638  pkt_release();
639  return (WERR_PKT_ERROR);
640  }
641 
642  memset (&pkt_params, 0, sizeof(pkt_params));
643  got_params = FALSE;
644 
645  if (_pktdevlevel >= 5 && _pktdevlevel < 255) /* high-performance driver */
646  {
647  if (!pkt_get_params(&pkt_params))
648  TCP_CONSOLE_MSG (1, ("Failed to get PKTDRVR params; %s\n",
650  }
651 
652 #if defined(USE_STATISTICS)
653  if (_pktdevlevel >= 2 && _pktdevlevel < 255) /* extended driver */
654  get_init_stats();
655 #endif
656 
657  if (_pktserial)
658  return (0); /* success */
659 
660  /* Set Rx-mode forced via config.
661  */
662  if (_pkt_forced_rxmode != -1 &&
663  (_pkt_forced_rxmode < -1 ||
665  {
666  TCP_CONSOLE_MSG (0, ("Illegal Rx-mode (%d) specified\n",
668  _pkt_forced_rxmode = -1;
669  }
670 
671  if (pkt_get_rcv_mode())
672  _pkt_rxmode0 = _pkt_rxmode; /* remember startup mode */
673 
674  if (_pkt_forced_rxmode != -1 &&
677 
678  /* else hope _pkt_rxmode0 is >= RXMODE_BROADCAST */
679 
680  return (0); /* success */
681 }
682 
683 /*
684  * The following functions (ending at '_pkt_end()') are called
685  * at interrupt time (or asynchronously). 'pkt_release()' may be
686  * called from SIGSEGV handler. Therefore don't assume anything
687  * about the state of our stack (except hope it's large enough).
688  * And don't use large local variables here. Hope we will not be
689  * reentered since not all functions below are reentrant.
690  */
691 
692 /* Disable stack-checking here
693  */
694 #if defined(__HIGHC__)
695  #pragma off(Call_trace)
696  #pragma off(Prolog_trace)
697  #pragma off(Epilog_trace)
698 #endif
699 
700 #if defined(WATCOM386)
701  /* #pragma option -zu */ /* assume SS != DS (doesn't work) */
702  /* #pragma aux pkt_release __modify[ss] */ /* !! fix-me (doesn't work) */
703 #endif
704 
705 #include "nochkstk.h"
706 
707 
711 int pkt_release_handle (WORD handle)
712 {
713  static IREGS regs; /* `static' because the stack could be too small */
714 
715  memset (&regs, 0, sizeof(regs));
716  regs.r_ax = PD_RELEASE;
717  regs.r_bx = handle;
718 
719  if (!PKT_API(&regs) && !_watt_fatal_error)
720  PKT_ERR ("Error releasing handle: ", _pkt_errno);
721  return (1);
722 }
723 
727 int pkt_reset_handle (WORD handle)
728 {
729  static IREGS regs; /* `static' because the stack could be too small */
730 
731  memset (&regs, 0, sizeof(regs));
732  regs.r_ax = PD_RESET;
733  regs.r_bx = handle;
734 
735  if (!PKT_API(&regs))
736  PKT_ERR ("Error resetting handle: ", _pkt_errno);
737  return (1);
738 }
739 
740 #if (DOSX) && !defined(USE_FAST_PKT)
741 static void release_callback (void)
742 {
743 #if (DOSX & (PHARLAP|X32VM))
744  if (rm_base)
745  _dx_free_rmode_wrapper (rm_base);
746  rm_base = 0;
747 
748 #elif (DOSX & POWERPAK)
749  if (rm_cb.pm_func)
750  dpmi_free_callback_retf (&rm_cb);
751  rm_cb.pm_func = 0;
752 
753 #elif (DOSX & DJGPP)
754  if (rm_cb.pm_offset)
755  _pkt_dpmi_free_real_mode_callback (&rm_cb);
756  rm_cb.pm_offset = 0;
757 #endif
758 }
759 #endif /* DOSX && !USE_FAST_PKT */
760 
761 
765 #if (DOSX) && defined(USE_FAST_PKT)
766 static void release_real_mem (void)
767 {
768 #if (DOSX & PHARLAP)
769  if (_pkt_inf && _pkt_inf->rm_seg)
770  _dx_real_free (_pkt_inf->rm_seg);
771  rm_base = 0;
772 
773 #elif (DOSX & X32VM)
774  if (rm_base)
775  _x32_real_free (rm_base);
776  rm_base = 0;
777 
778 #elif (DOSX & POWERPAK)
779  if (_pkt_inf && _pkt_inf->rm_sel)
780  dpmi_real_free (_pkt_inf->rm_sel);
781 
782 #elif (DOSX & DJGPP)
783  if (_pkt_inf && _pkt_inf->rm_sel)
784  {
785  __dpmi_error = 0;
786  __dpmi_free_dos_memory (_pkt_inf->rm_sel); /* DPMI fn 101h */
787  if (__dpmi_error)
788  {
789  (*_printf) ("%s (%u): DPMI/DOS error %04Xh\n",
790  __FILE__, __LINE__, __dpmi_error);
791  TCP_TRACE_MSG (("release_real_mem: dpmi_error %u\n", __dpmi_error));
792  }
793  }
794  rm_base = (DWORD)-1; /* crash if used after freed */
795 
796 #elif (DOSX & DOS4GW)
797  if (!_watt_fatal_error && _pkt_inf)
798  {
799  if (_pkt_inf->rm_sel)
800  dpmi_real_free (_pkt_inf->rm_sel);
801 
802 #if !defined(USE_FAST_PKT)
803  if (pkt_inf_sel)
804  dpmi_real_free (pkt_inf_sel);
805  pkt_inf_sel = 0;
806 #endif
807  }
808 #endif
809 
810  if (_pkt_inf)
811  _pkt_inf->rm_sel = _pkt_inf->rm_seg = 0;
812 
813 #if !defined(USE_FAST_PKT)
814  _pkt_inf = NULL; /* don't free this ptr below */
815 #endif
816 }
817 #endif /* DOSX && USE_FAST_PKT */
818 
819 
828 #ifdef __WATCOMC__
829 #pragma aux pkt_release loadds;
830 #endif
831 
832 #if defined(__GNUC__)
833 #define DTOR __attribute__((destructor))
834 #else
835 #define DTOR
836 #endif
837 
838 int DTOR pkt_release (void)
839 {
840  DISABLE();
841 
842  if (_pkt_inf)
843  {
844  /* Don't do this by default. It may cause some (RealTek)
845  * packet-drivers to fail all further upcalls.
846  */
847  if (pkt_do_reset)
848  pkt_reset_handle (_pkt_inf->handle);
849  pkt_release_handle (_pkt_inf->handle);
850  }
851 
852 /* !! pkt_interrupt = 0; */
853 
861 #if (DOSX)
862  #if defined(USE_FAST_PKT)
864  #else
865  unlock_code_and_data(); /* unlock before freeing */
866  release_callback();
867  #endif
868 #endif
869 
870  if (_pkt_inf && !_watt_fatal_error)
871  free (_pkt_inf);
872 
873  _pkt_inf = NULL; /* drop anything still in the queue */
874 
875  ENABLE();
876  return (1);
877 }
878 
879 #if defined(__BORLANDC__)
880  #pragma exit pkt_release 100
881 #elif defined(__CCDL__)
882  #pragma rundown pkt_release 110
883 #endif
884 
885 
886 #if !defined(USE_FAST_PKT) && !(DOSX & DOS4GW)
887 
915 #if (DOSX)
916 static void pkt_enqueue (unsigned rxBuf, WORD rxLen)
917 #else
918 static void __cdecl _far pkt_enqueue (BYTE _far *rxBuf, WORD rxLen)
919 #endif
920 {
921  struct pkt_ringbuf *q = &_pkt_inf->pkt_queue;
922  int index;
923 
924  /* don't use pktq_in_index() and pktq_in_buf() because they
925  * are not in locked code area.
926  */
927  index = q->in_index + 1;
928  if (index >= q->num_buf)
929  index = 0;
930 
931  if (index != q->out_index)
932  {
933  char *head = (char*)q->buf_start + (q->buf_size * q->in_index);
934  int padLen = q->buf_size - 4 - rxLen;
935 
936  if (rxLen > q->buf_size - 4) /* don't overwrite marker */
937  {
938  rxLen = q->buf_size - 4;
939  padLen = 0;
940  }
941 
942 #if (DOSX & (PHARLAP|X32VM|POWERPAK))
943  ReadRealMem (head, rm_base + rxBuf, rxLen);
944 
945 #elif (DOSX & DJGPP)
946  if (_pkt_inf->use_near_ptr)
947  memcpy (head, (void*)(rm_base+rxBuf+__djgpp_conventional_base), rxLen);
948  else DOSMEMGETL (rm_base + rxBuf, (rxLen+3)/4, head);
949 
950 #else /* real-mode targets */
951  _fmemcpy (head, rxBuf, rxLen);
952 #endif
953 
954  /* Zero-fill remaining old data in this buffer.
955  */
956  head += rxLen;
957  while (padLen--)
958  *head++ = '\0';
959  q->in_index = index; /* update buffer tail-index */
960  }
961  else
962  q->num_drop++; /* no room, increment drop count */
963 }
964 
965 
966 /*
967  * We have allocated a real-mode callback (RMCB) to gain control
968  * here when the packet-driver makes an upcall.
969  *
970  * Entry AL = 0; driver requests a buffer. We return ES:DI of real-mode buffer
971  * BX = handle (IP, ARP or RARP)
972  * CX = length of packet
973  *
974  * Entry AL = 1; driver has put the data in buffer, we then enqueues the buffer
975  * BX = handle (IP, ARP or RARP)
976  * CX = length of packet (same as CX above)
977  * DS:SI = *must* be same as ES:DI returned above.
978  * ES:DI = should be same as ES:DI returned above (but don't count on it).
979  *
980  * Interrupts are disabled on entry.
981  * Note: This function MUST be declared cdecl (not register called).
982  */
983 #if (DOSX & (PHARLAP|X32VM))
984  static void cdecl pkt_receiver_pm (SWI_REGS *r)
985  {
986  PUSHF_CLI();
987 
988  if ((BYTE)r->r_ax == 0) /* AL == 0; rx-buffer request */
989  {
990  if (!_pkt_inf || (WORD)r->r_cx > ETH_MAX)
991  {
992  r->r_es = 0;
993  r->r_di = 0;
994  }
995  else
996  {
997  r->r_es = RP_SEGM();
998  r->r_di = RX_BUF();
999  }
1000  }
1001  else if ((WORD)r->r_si && _pkt_inf) /* AL != 0; rx-buffer filled */
1002  {
1003  pkt_enqueue (RX_BUF(), (WORD)r->r_cx);
1004  }
1005  POPF();
1006  }
1007 
1008 #elif (DOSX & DJGPP)
1009  static void cdecl pkt_receiver_pm (__dpmi_regs *r)
1010  {
1011  WORD fs, gs;
1012 
1013  PUSHF_CLI(); /* "cld" already done in RMCB wrapper */
1014 
1015  fs = get_fs_reg();
1016  gs = get_gs_reg();
1017 
1018  if (r->h.al == 0)
1019  {
1020  if (!_pkt_inf || r->x.cx > ETH_MAX)
1021  {
1022  r->x.es = 0;
1023  r->x.di = 0;
1024  }
1025  else
1026  {
1027  r->x.es = RP_SEGM();
1028  r->x.di = RX_BUF();
1029  }
1030  }
1031  else if (r->x.si && _pkt_inf)
1032  {
1033  pkt_enqueue (RX_BUF(), r->x.cx);
1034  }
1035 
1036  set_fs_reg (fs);
1037  set_gs_reg (gs);
1038 
1039  POPF();
1040  }
1041 
1042 #elif (DOSX & POWERPAK)
1043  static void cdecl pkt_receiver_pm (void)
1044  {
1045  REAL_regs *r;
1046 
1047  PUSHF_CLI();
1048  r = &rm_cb.rm_regs;
1049 
1050  if ((BYTE)r->r_ax == 0)
1051  {
1052  if (!_pkt_inf || (WORD)r->r_cx > ETH_MAX)
1053  {
1054  r->r_es = 0;
1055  r->r_di = 0;
1056  }
1057  else
1058  {
1059  r->r_es = RP_SEGM();
1060  r->r_di = RX_BUF();
1061  }
1062  }
1063  else if (r->r_si && _pkt_inf)
1064  {
1065  pkt_enqueue (RX_BUF(), (WORD)r->r_cx);
1066  }
1067  POPF();
1068  }
1069 #endif
1070 
1071 void _pkt_end (void) {}
1072 
1073 #if defined(__WATCOMC__)
1074 #pragma alloc_text (pkt_lock_TEXT, pkt_enqueue, pkt_receiver_pm, _pkt_end);
1075 #endif
1076 
1077 #endif /* !(DOSX & DOS4GW) && !USE_FAST_PKT */
1078 
1079 
1090 int pkt_send (const void *tx, int length)
1091 {
1092  IREGS regs;
1093  WORD tx_seg, tx_ofs;
1094  BOOL fail = FALSE;
1095  int tx_cnt;
1096 
1097  if (!_pkt_inf)
1098  return (0);
1099 
1100  PROFILE_START ("pkt_send");
1101 
1102  memset (&regs, 0, sizeof(regs));
1103 
1104 #if (DOSX & (PHARLAP|POWERPAK))
1105  tx_seg = RP_SEGM();
1106  tx_ofs = TX_BUF();
1107  WriteRealMem (rm_base + tx_ofs, (void*)tx, length);
1108 
1109 #elif (DOSX & (DOS4GW|X32VM))
1110  tx_seg = RP_SEGM();
1111  tx_ofs = TX_BUF();
1112  WATT_ASSERT (tx == pkt_tx_buf()); /* no need to copy anything */
1113 
1114 #elif (DOSX & DJGPP)
1115  tx_seg = RP_SEGM();
1116  tx_ofs = TX_BUF();
1117  if (_pkt_inf->use_near_ptr)
1118  WATT_ASSERT (tx == pkt_tx_buf());
1119  else DOSMEMPUTL (tx, (length+3)/4, rm_base + tx_ofs);
1120 
1121 #else
1122  tx_seg = FP_SEG (tx);
1123  tx_ofs = FP_OFF (tx);
1124 #endif
1125 
1126  for (tx_cnt = 0; tx_cnt <= pkt_txretries; tx_cnt++)
1127  {
1128  regs.r_cx = length;
1129  regs.r_ax = PD_SEND;
1130  regs.r_ds = tx_seg;
1131  regs.r_si = tx_ofs;
1132 
1133  fail = FALSE;
1134 
1135  if (PKT_API(&regs)) /* success */
1136  break;
1137 
1138  fail = TRUE;
1139  if (pkt_txwait > 0)
1140  Wait (pkt_txwait);
1141  }
1142 
1143  if (tx_cnt > 0)
1144  STAT (macstats.num_tx_retry += tx_cnt-1);
1145 
1146  if (fail)
1147  length = 0;
1148 
1149  if (length == 0)
1150  STAT (macstats.num_tx_err++);
1151 
1152  PROFILE_STOP();
1153  return (length);
1154 }
1155 
1159 int pkt_get_addr (mac_address *mac)
1160 {
1161  IREGS regs;
1162  WORD seg, ofs;
1163  int rc;
1164 
1165  ASSERT_PKT_INF (0);
1166 
1167  PROFILE_START ("pkt_get_addr");
1168 
1169  regs.r_ax = PD_GET_ADDRESS;
1170  regs.r_bx = _pkt_inf->handle;
1171  regs.r_cx = sizeof (*mac);
1172 
1173 #if (DOSX)
1174  regs.r_es = seg = RP_SEGM();
1175  regs.r_di = ofs = PKT_TMP();
1176 #else
1177  regs.r_es = seg = FP_SEG (mac);
1178  regs.r_di = ofs = FP_OFF (mac);
1179 #endif
1180 
1181  if (!PKT_API(&regs))
1182  {
1183  PKT_ERR ("Cannot read own MAC address: ", _pkt_errno);
1184  rc = 0;
1185  }
1186  else
1187  {
1188  get_rmode_data (mac, sizeof(*mac), seg, ofs);
1189  rc = 1;
1190  }
1191  PROFILE_STOP();
1192  return (rc);
1193 }
1194 
1198 int pkt_set_addr (const void *addr)
1199 {
1200  IREGS regs;
1201 
1202  ASSERT_PKT_INF (0);
1203 
1204  regs.r_ax = PD_SET_ADDR;
1205  regs.r_cx = sizeof (mac_address);
1206 
1207 #if (DOSX & DJGPP)
1208  DOSMEMPUT (addr, sizeof(mac_address), rm_base + PKT_TMP());
1209  regs.r_es = RP_SEGM();
1210  regs.r_di = PKT_TMP();
1211 
1212 #elif (DOSX & DOS4GW)
1213  memcpy ((void*)(rm_base + PKT_TMP()), addr, sizeof(mac_address));
1214  regs.r_es = RP_SEGM();
1215  regs.r_di = PKT_TMP();
1216 
1217 #elif (DOSX & (PHARLAP|X32VM|POWERPAK))
1218  WriteRealMem (rm_base + PKT_TMP(), (void*)addr, sizeof(mac_address));
1219  regs.r_es = RP_SEGM();
1220  regs.r_di = PKT_TMP();
1221 
1222 #else
1223  {
1224  mac_address tmp;
1225  memcpy (&tmp, addr, sizeof(tmp)); /* prevent driver modifying '*addr' */
1226  regs.r_es = FP_SEG (&tmp);
1227  regs.r_di = FP_OFF (&tmp);
1228  }
1229 #endif
1230 
1231  if (!PKT_API(&regs))
1232  return (0);
1233  return (1);
1234 }
1235 
1236 #if defined(USE_STATISTICS)
1237 
1243 int pkt_get_stats (struct PktStats *stats, struct PktStats *total)
1244 {
1245  IREGS regs;
1246  int rc = 0;
1247 
1248  PROFILE_START ("pkt_get_stats");
1249  DISABLE();
1250 
1251  /* Handle in BX is optional for 1.11 drivers
1252  */
1253  regs.r_bx = _pkt_inf ? _pkt_inf->handle : 0;
1254  regs.r_ax = PD_GET_STATS;
1255 
1256  if (!PKT_API(&regs))
1257  goto fail;
1258 
1259  rc = 1;
1260  get_rmode_data (stats, sizeof(*stats), regs.r_ds, regs.r_si);
1261 
1262  if (total)
1263  *total = *stats;
1264 
1265  stats->in_packets -= init_stats.in_packets;
1266  stats->out_packets -= init_stats.out_packets;
1267  stats->in_bytes -= init_stats.in_bytes;
1268  stats->out_bytes -= init_stats.out_bytes;
1269  stats->in_errors -= init_stats.in_errors;
1270  stats->out_errors -= init_stats.out_errors;
1271  stats->lost -= init_stats.lost;
1272 fail:
1273  ENABLE();
1274  PROFILE_STOP();
1275  return (rc);
1276 }
1277 
1278 static void get_init_stats (void)
1279 {
1280  IREGS regs;
1281 
1282  regs.r_ax = PD_GET_STATS;
1283  regs.r_bx = _pkt_inf->handle;
1284  memset (&init_stats, 0, sizeof(init_stats));
1285 
1286  DISABLE();
1287  if (PKT_API(&regs))
1288  get_rmode_data (&init_stats, sizeof(init_stats), regs.r_ds, regs.r_si);
1289  ENABLE();
1290 }
1291 
1292 
1297 static WORD cstate_dseg = 0;
1298 
1299 int pkt_get_vjstats (struct slcompress *vjstats)
1300 {
1301  IREGS regs;
1302  int rc = 0;
1303 
1304  regs.r_ax = PD_GET_VJSTATS;
1305  regs.r_bx = sizeof (*vjstats);
1306 
1307  DISABLE();
1308  if (PKT_API(&regs))
1309  {
1310  get_rmode_data (vjstats, sizeof(*vjstats), regs.r_ds, regs.r_si);
1311  cstate_dseg = regs.r_ds;
1312  rc = 1;
1313  }
1314  ENABLE();
1315  return (rc);
1316 }
1317 
1318 int pkt_get_cstate (struct cstate *cs, WORD cstate_ofs)
1319 {
1320  if (cstate_dseg == 0 || cstate_ofs == 0)
1321  return (0);
1322 
1323  DISABLE();
1324  get_rmode_data (cs, sizeof(*cs), cstate_dseg, cstate_ofs);
1325  ENABLE();
1326  return (1);
1327 }
1328 #endif /* USE_STATISTICS */
1329 
1330 
1334 int pkt_buf_wipe (void)
1335 {
1336 #if defined(USE_FAST_PKT)
1337  pktq_clear (NULL);
1338 #else
1339  ASSERT_PKT_INF (0);
1340  pktq_clear (&_pkt_inf->pkt_queue);
1341 #endif
1342  return (1);
1343 }
1344 
1349 void pkt_free_pkt (const void *pkt)
1350 {
1351 #if !defined(USE_FAST_PKT) /* packet already copied in pcsed.c */
1352  struct pkt_ringbuf *q;
1353 
1354  if (!_pkt_inf || !pkt)
1355  return;
1356 
1357  q = &_pkt_inf->pkt_queue;
1358  pkt_drop_cnt = q->num_drop;
1359 
1360  if (pkt != (const void*) (pktq_out_buf(q) + _pkt_ip_ofs))
1361  {
1362  TCP_CONSOLE_MSG (0, ("%s: freeing illegal packet 0x%p.\n", __FILE__, pkt));
1363  pktq_clear (q);
1364  }
1365  else
1366  pktq_inc_out (q);
1367 #else
1368  if (rm_base && rm_base < (DWORD)-1)
1369  pkt_drop_cnt = FAR_PEEK_DWORD (struct pkt_info, pkt_queue.num_drop);
1370  ARGSUSED (pkt);
1371 #endif
1372 }
1373 
1374 
1378 int pkt_waiting (void)
1379 {
1380 #if defined(USE_FAST_PKT)
1381  if (rm_base && rm_base < (DWORD)-1)
1382  return pkt_buffers_used();
1383  return (-1);
1384 #else
1385  if (_pkt_inf)
1386  return pktq_queued (&_pkt_inf->pkt_queue);
1387  return (-1);
1388 #endif
1389 }
1390 
1394 DWORD pkt_dropped (void)
1395 {
1396 #if defined(USE_FAST_PKT)
1397  if (rm_base && rm_base < (DWORD)-1)
1398  return pkt_rx_dropped();
1399 #else
1400  if (_pkt_inf)
1401  return (_pkt_inf->pkt_queue.num_drop);
1402 #endif
1403  return (pkt_drop_cnt); /* return last known value */
1404 }
1405 
1410 static int parse_config_pass_1 (void)
1411 {
1412  static int vect = 0;
1413  static const struct config_table pkt_init_cfg[] = {
1414  { "PKT.VECTOR", ARG_ATOX_B, (void*)&vect },
1415  { "PKT.TXRETRIES", ARG_ATOB, (void*)&pkt_txretries },
1416  { "PKT.TXWAIT", ARG_ATOI, (void*)&pkt_txwait },
1417  { "PKT.RXMODE", ARG_ATOI, (void*)&_pkt_forced_rxmode },
1418  { "PKT.RXBUFS", ARG_ATOI, (void*)&pkt_num_rx_bufs },
1419  { "PKT.NEAR_PTR", ARG_ATOI, (void*)&pkt_use_near },
1420  { "PKT.RESET", ARG_ATOI, (void*)&pkt_do_reset },
1421  { NULL, 0, NULL }
1422  };
1423  const struct config_table *cfg_save = watt_init_cfg;
1424  void (W32_CALL *init_save) (const char*, const char*) = usr_init;
1425  int rc;
1426 
1427  watt_init_cfg = pkt_init_cfg;
1428  usr_init = NULL; /* only pkt_init_cfg[] gets parsed */
1429  rc = tcp_config (NULL);
1430  usr_init = init_save;
1431  watt_init_cfg = cfg_save;
1432  if (!rc)
1433  return (0);
1434  return (vect);
1435 }
1436 
1449 int pkt_eth_init (mac_address *addr)
1450 {
1451  int vector, rc = -1;
1452 
1453  if (_watt_no_config && !_watt_user_config_fn)
1454  vector = 0;
1455  else vector = parse_config_pass_1();
1456 
1457  if (vector)
1458  {
1459  pkt_interrupt = vector;
1460  if (pkt_interrupt < PKT_FIRST_VEC_11 || /* 0x20-0xFF range for 1.11 drvr */
1461  pkt_interrupt > PKT_LAST_VEC_11)
1462  pkt_interrupt = 0; /* discard illegal value */
1463  }
1464  else
1465  pkt_interrupt = 0;
1466 
1467  {
1468 #if (DOSX)
1469  int pm_driver = pkt32_drvr_probe (pm_driver_list);
1470 
1471  if (pm_driver > -1)
1472  {
1473  rc = pkt32_drvr_init (pm_driver, addr);
1474  if (rc == 0)
1475  TCP_CONSOLE_MSG (2, ("Using Pmode `%s' driver at %08lX\n",
1476  pkt32_drvr_name(pm_driver), (DWORD)_pkt32_drvr));
1477  }
1478  if (rc) /* pmode driver failed, try real-mode driver */
1479 #endif
1480  rc = pkt16_drvr_init (addr);
1481 
1482  if (rc)
1483  return (rc); /* no suitable driver found */
1484  }
1485 
1486 #if defined(USE_FAST_PKT)
1487  FAR_POKE_WORD (struct pkt_info, handle, _pkt_inf->handle);
1488  FAR_POKE_WORD (struct pkt_info, is_serial, _pkt_inf->is_serial);
1489  FAR_POKE_WORD (struct pkt_info, pkt_ip_ofs, _pkt_inf->pkt_ip_ofs);
1490  FAR_POKE_WORD (struct pkt_info, pkt_type_ofs, _pkt_inf->pkt_type_ofs);
1491 
1492 #if (DOSX & X32VM) && 0
1493  if (!pkt_test_upcall())
1494  {
1495  pkt_release();
1496  return (-1);
1497  }
1498 #endif
1499 #endif
1500 
1501  return (0);
1502 }
1503 
1508 #if (DOSX & (PHARLAP|X32VM))
1509  static BOOL check_intr_num (WORD intr_num)
1510  {
1511  REALPTR rp;
1512  char temp[16];
1513 
1514  _dx_rmiv_get (intr_num, &rp);
1515  if (rp)
1516  {
1517  ReadRealMem (&temp, rp, sizeof(temp));
1518  if (!memcmp(temp+3, pkt_sign, strlen(pkt_sign)))
1519  return (TRUE);
1520  }
1521  return (FALSE);
1522  }
1523 
1524 #elif (DOSX & DJGPP)
1525  static BOOL check_intr_num (WORD intr_num)
1526  {
1527  char temp[16];
1528  DWORD rp;
1529  __dpmi_raddr realAdr;
1530 
1531  __dpmi_get_real_mode_interrupt_vector (intr_num, &realAdr);
1532  rp = (realAdr.segment << 4) + realAdr.offset16;
1533  if (rp)
1534  {
1535  dosmemget (rp, sizeof(temp), &temp);
1536  if (!memcmp(temp+3, pkt_sign, strlen(pkt_sign)))
1537  return (TRUE);
1538  }
1539  return (FALSE);
1540  }
1541 
1542 #elif (DOSX & DOS4GW)
1543  static BOOL check_intr_num (WORD intr_num)
1544  {
1545  const BYTE *addr = (const BYTE*) dpmi_get_real_vector (intr_num);
1546 
1547  if (addr && !memcmp(addr+3, pkt_sign, strlen(pkt_sign)))
1548  return (TRUE);
1549  return (FALSE);
1550  }
1551 
1552 #elif (DOSX & POWERPAK)
1553  static BOOL check_intr_num (WORD intr_num)
1554  {
1555  char temp[16];
1556  DWORD addr = (DWORD) dpmi_get_real_vector (intr_num);
1557  REALPTR rp;
1558 
1559  RP_SET (rp, addr & 0xF, addr >> 4);
1560  ReadRealMem (&temp, rp, sizeof(temp));
1561  if (!memcmp(temp+3, pkt_sign, strlen(pkt_sign)))
1562  return (TRUE);
1563  return (FALSE);
1564  }
1565 
1566 #else /* real-mode version */
1567  static BOOL check_intr_num (WORD intr_num)
1568  {
1569  char _far *addr = (char _far*) getvect (intr_num);
1570 
1571 #if !defined(USE_FAST_PKT)
1572  pkt_enque_ptr = pkt_enqueue;
1573  _pkt_enque_ptr = pkt_enqueue;
1574 #endif
1575 
1576  if (addr && !_fmemcmp(addr+3, pkt_sign, strlen(pkt_sign)))
1577  return (TRUE);
1578  return (FALSE);
1579  }
1580 #endif
1581 
1582 /*
1583  * Find the interrupt-number for the PKTDRVR by searching interrupt
1584  * handler entries (at vector+3) for signature string "PKT DRVR".
1585  */
1586 static int find_vector (int first, int num)
1587 {
1588  int inum;
1589 
1590  for (inum = first; inum < first + num; inum++)
1591  {
1592  if (inum != 0x67 && /* can never be at EMS vector */
1593  check_intr_num(inum))
1594  return (inum);
1595  }
1596  return (0);
1597 }
1598 
1599 #if !defined(USE_FAST_PKT)
1600 /*
1601  * DOS-extender functions for allocation a real-mode callback that
1602  * the real-mode PKTDRVR will call when a packet is received.
1603  * Lock down all code and data that is touched in this callback.
1604  */
1605 #if (DOSX & (PHARLAP|X32VM))
1606  static int setup_rmode_callback (void)
1607  {
1608  rm_base = _dx_alloc_rmode_wrapper_retf (pkt_receiver_pm, NULL,
1609  RDATA_SIZE, 1024);
1610  if (!rm_base)
1611  return (-1);
1612  return (0);
1613  }
1614 
1615  static int lock_code_and_data (void) /* Needed for 386|VMM only (?) */
1616  {
1617  UINT size = (UINT)_pkt_end - (UINT)pkt_enqueue;
1618 
1619  _dx_lock_pgsn ((void*)pkt_enqueue, size);
1620  _dx_lock_pgsn ((void*)ReadRealMem, 100);
1621  _dx_lock_pgsn ((void*)_pkt_inf, sizeof(*_pkt_inf));
1622  _dx_lock_pgsn ((void*)&_pkt_inf, sizeof(_pkt_inf));
1623 
1624  #if (DOSX & X32VM)
1625  _dx_lock_pgsn ((void*)memcpy, 200);
1626  #endif
1627  return (0);
1628  }
1629 
1630  static int unlock_code_and_data (void)
1631  {
1632  UINT size = (UINT)_pkt_end - (UINT)pkt_enqueue;
1633 
1634  _dx_ulock_pgsn ((void*)pkt_enqueue, size);
1635  _dx_ulock_pgsn ((void*)ReadRealMem, 100);
1636  _dx_ulock_pgsn ((void*)_pkt_inf, sizeof(*_pkt_inf));
1637  _dx_ulock_pgsn ((void*)&_pkt_inf, sizeof(_pkt_inf));
1638 
1639  #if (DOSX & X32VM)
1640  _dx_ulock_pgsn ((void*)memcpy, 200);
1641  #endif
1642  return (0);
1643  }
1644 
1645 #elif (DOSX & DJGPP)
1646  static int setup_rmode_callback (void)
1647  {
1648  static __dpmi_regs rm_reg;
1649  int seg = __dpmi_allocate_dos_memory ((RDATA_SIZE + 15) / 16,
1650  (int*)&_pkt_inf->rm_sel);
1651  if (seg < 0)
1652  return (-2);
1653 
1654  _pkt_inf->rm_seg = seg;
1655  rm_cb.pm_offset = (DWORD) pkt_receiver_pm;
1656 
1657  memset (&rm_reg, 0, sizeof(rm_reg));
1658  if (_pkt_dpmi_allocate_real_mode_callback_retf (&rm_cb,&rm_reg))
1659  return (-1);
1660 
1661  rm_base = (_pkt_inf->rm_seg << 4);
1662 
1663  DOSMEMCLR (rm_base, RDATA_SIZE);
1664  return (0);
1665  }
1666 
1667  static int lock_code_and_data (void)
1668  {
1669  DWORD size = (DWORD)_pkt_end - (DWORD)pkt_enqueue;
1670 
1671  WATT_ASSERT ((DWORD)_pkt_end > (DWORD)pkt_enqueue);
1672 
1673  if (_go32_dpmi_lock_code((void*)pkt_enqueue, size) ||
1674  _go32_dpmi_lock_code((void*)__movedata, 30) ||
1675  _go32_dpmi_lock_code((void*)_movedatal, 30) ||
1676  _go32_dpmi_lock_code((void*)__dj_movedata, 100) ||
1677  _go32_dpmi_lock_data(&_pkt_inf, sizeof(_pkt_inf)) ||
1678  _go32_dpmi_lock_data(_pkt_inf, sizeof(*_pkt_inf)))
1679  return (-1);
1680  /* rm_reg is already locked */
1681  return (0);
1682  }
1683 
1684  static void _unlock (const void *addr, DWORD size)
1685  {
1686  __dpmi_meminfo mem;
1687  DWORD base = 0;
1688 
1689  __dpmi_get_segment_base_address (_my_ds(), &base);
1690  mem.address = base + (DWORD)addr;
1691  mem.size = size;
1692  __dpmi_unlock_linear_region (&mem);
1693  }
1694 
1695  static int unlock_code_and_data (void)
1696  {
1697  _unlock ((void*)pkt_enqueue, (DWORD)_pkt_end - (DWORD)pkt_enqueue);
1698  _unlock ((void*)__movedata, 30);
1699  _unlock ((void*)_movedatal, 30);
1700  _unlock ((void*)__dj_movedata, 100);
1701  _unlock (_pkt_inf, sizeof(*_pkt_inf));
1702  _unlock (&_pkt_inf, sizeof(_pkt_inf));
1703  return (0);
1704  }
1705 
1706 #elif (DOSX & DOS4GW)
1707  static int setup_rmode_callback (void)
1708  {
1709  int length;
1710 
1711  /* test for asmpkt4.asm/pcpkt.h mismatch
1712  */
1713  if (asmpkt_size_chk != sizeof(*_pkt_inf))
1714  {
1715 #ifdef USE_DEBUG
1716  fprintf (stderr,
1717  "%s (%u): Development error:\n"
1718  " sizeof(pkt_info) = %u pcpkt.h\n"
1719  " sizeof(pkt_info) = %u asmpkt4.asm, (diff %d)\n",
1720  __FILE__, __LINE__,
1721  sizeof(*_pkt_inf), asmpkt_size_chk,
1722  sizeof(*_pkt_inf) - asmpkt_size_chk);
1723 #endif
1724  return (-3);
1725  }
1726 
1727  /* Allocate DOS-memory for pkt_receiver4_rm() and temp/Tx buffers.
1728  */
1729  length = TX_BUF() + RX_SIZE;
1730  _pkt_inf->rm_seg = dpmi_real_malloc (length, &_pkt_inf->rm_sel);
1731  if (!_pkt_inf->rm_seg)
1732  return (-2);
1733 
1734  rm_base = ((DWORD)_pkt_inf->rm_seg) << 4;
1735 
1736  /* Clear DOS area and copy code down into it.
1737  */
1738  memset ((void*)rm_base, 0, length);
1739  length = PKT_TMP() - 1;
1740  memcpy ((void*)rm_base, pkt_receiver4_start, length);
1741  return (0);
1742  }
1743 
1744  /* No need (?) to lock anything.
1745  */
1746  static int lock_code_and_data (void)
1747  {
1748  return (0);
1749  }
1750 
1751  static int unlock_code_and_data (void)
1752  {
1753  return (0);
1754  }
1755 
1756 #elif (DOSX & POWERPAK)
1757  static int setup_rmode_callback (void)
1758  {
1759  /* Allocate DOS-memory for temp/Tx buffers.
1760  */
1761  _pkt_inf->rm_seg = dpmi_real_malloc (RDATA_SIZE, &_pkt_inf->rm_sel);
1762  if (!_pkt_inf->rm_seg)
1763  return (-2);
1764 
1765  rm_base = (REALPTR) ((DWORD)_pkt_inf->rm_seg << 16);
1766 
1767  rm_cb.pm_func = pkt_receiver_pm;
1768  if (!dpmi_alloc_callback_retf(&rm_cb))
1769  return (-1);
1770  return (0);
1771  }
1772 
1773  static int lock_code_and_data (void)
1774  {
1775  unsigned size = (unsigned)_pkt_end - (unsigned)pkt_enqueue;
1776 
1777  if (!dpmi_lock_region ((void*)pkt_enqueue, size) ||
1778  !dpmi_lock_region ((void*)ReadRealMem, 100) ||
1779  !dpmi_lock_region ((void*)_pkt_inf, sizeof(*_pkt_inf)) ||
1780  !dpmi_lock_region ((void*)&_pkt_inf, sizeof(_pkt_inf)))
1781  return (-1);
1782  return (0);
1783  }
1784 
1785  static int unlock_code_and_data (void)
1786  {
1787  unsigned size = (unsigned)_pkt_end - (unsigned)pkt_enqueue;
1788 
1789  if (!dpmi_unlock_region ((void*)pkt_enqueue, size) ||
1790  !dpmi_unlock_region ((void*)ReadRealMem, 100) ||
1791  !dpmi_unlock_region ((void*)_pkt_inf, sizeof(*_pkt_inf)) ||
1792  !dpmi_unlock_region ((void*)&_pkt_inf, sizeof(_pkt_inf)))
1793  return (-1);
1794  return (0);
1795  }
1796 #endif
1797 #endif /* !USE_FAST_PKT */
1798 
1799 
1800 /*
1801  * For DOS4GW targets, allocate the '_pkt_inf' structure
1802  * from DOS memory. All others allocate from heap.
1803  */
1804 static int setup_pkt_inf (void)
1805 {
1810  int size = sizeof (*_pkt_inf);
1811 
1812 #if (DOSX & DOS4GW) && !defined(USE_FAST_PKT)
1813  DWORD seg;
1814 
1815  WATT_ASSERT (size < USHRT_MAX); /* max alloc from DOS is 64k */
1816 
1817  seg = dpmi_real_malloc (size, &pkt_inf_sel);
1818 
1819  asmpkt_inf = (struct pkt_info*) (seg << 16); /* run-time location */
1820  _pkt_inf = (struct pkt_info*) (seg << 4);
1821 
1822 #else
1823  _pkt_inf = malloc (size);
1824 #endif
1825 
1826  if (!_pkt_inf) /* Allocation failed */
1827  return (0);
1828 
1829  memset (_pkt_inf, 0, size); /* Clear area */
1830 
1831 #if defined(USE_FAST_PKT)
1832  rm_base = setup_pkt_inf_fast();
1833  if (!rm_base)
1834  return (0);
1835 
1836 #else
1837  pktq_init (&_pkt_inf->pkt_queue,
1838  sizeof(_pkt_inf->rx_buf[0]), /* RX_SIZE */
1839  DIM(_pkt_inf->rx_buf), /* RX_BUFS */
1840  (char*)&_pkt_inf->rx_buf);
1841 #endif
1842 
1843 #if (DOSX & DOS4GW) && !defined(USE_FAST_PKT)
1844  _pkt_inf->pkt_queue.dos_ofs = offsetof (struct pkt_info, rx_buf[0]);
1845 #elif (DOSX & DJGPP)
1846  _pkt_inf->dos_ds = _dos_ds;
1847 #endif
1848 
1849 #if (DOSX & DJGPP)
1850  if (pkt_use_near)
1851  {
1852  if (!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
1853  TCP_CONSOLE_MSG (1, ("Near-pointers not enabled\n"));
1854  else
1855  {
1856  _pkt_inf->use_near_ptr = TRUE;
1857  TCP_CONSOLE_MSG (1, ("Near-pointers enabled\n"));
1858  }
1859  }
1860  else if (_crt0_startup_flags & _CRT0_FLAG_NEARPTR)
1861  TCP_CONSOLE_MSG (1, ("Near-pointers on, but \"PKT.NEAR_PTR = 0\"\n"));
1862 #endif
1863 
1864  return (1);
1865 }
1866 
1867 
1871 static void get_rmode_data (void *dest, unsigned size, WORD seg, WORD ofs)
1872 {
1873 #if (DOSX & (PHARLAP|X32VM|POWERPAK))
1874  REALPTR rp;
1875  RP_SET (rp, ofs, seg);
1876  ReadRealMem (dest, rp, size);
1877 
1878 #elif (DOSX & DOS4GW)
1879  memcpy (dest, SEG_OFS_TO_LIN(seg,ofs), size);
1880 
1881 #elif (DOSX & DJGPP)
1882  dosmemget (ofs + (seg << 4), size, dest);
1883 
1884 #else
1885  _fmemcpy (dest, MK_FP(seg,ofs), size);
1886 #endif
1887 }
1888 
1889 
1897 static BOOL pkt_api_entry (IREGS *reg, unsigned line)
1898 {
1899  _pkt_errno = 0;
1900  reg->r_flags = 0;
1901 
1902 #if (DOSX)
1903 
1905  if (_pkt32_drvr)
1906  {
1907  if (!(*_pkt32_drvr)(reg)) /* call the pmode interface */
1908  {
1909  /* _pkt_errno should be set above */
1910  reg->r_flags |= CARRY_BIT;
1911  return (FALSE);
1912  }
1913  return (TRUE);
1914  }
1915 #endif
1916 
1917  if (!pkt_interrupt)
1918  {
1919 #if defined(USE_DEBUG)
1920  fprintf (stderr, "%s (%d): API called after deinit.\n", __FILE__, line);
1921 #endif
1922  reg->r_flags |= CARRY_BIT;
1923  ARGSUSED (line);
1924  _pkt_errno = PDERR_BAD_COMMAND;
1925  return (FALSE);
1926  }
1927 
1928  /* Use the 16-bit real-mode PKTDRVR API.
1929  */
1930  GEN_INTERRUPT (pkt_interrupt, reg);
1931 
1932  if (reg->r_flags & CARRY_BIT)
1933  {
1934  _pkt_errno = hiBYTE (reg->r_dx); /* DH has error-code */
1935  return (FALSE);
1936  }
1937  return (TRUE);
1938 }
1939 
1940 
1955 int pkt_set_rcv_mode (int mode)
1956 {
1957  IREGS regs;
1958 
1959  if (!_pkt_inf)
1960  {
1961  _pkt_errno = PDERR_BAD_HANDLE;
1962  return (0);
1963  }
1964 
1965  regs.r_ax = PD_SET_RCV;
1966  regs.r_bx = _pkt_inf->handle;
1967  regs.r_cx = mode;
1968 
1969  /* This needs an Extended driver. SLIP/PPP is point-to-point.
1970  */
1971  if (_pktdevlevel < 2 || _pktserial)
1972  {
1973  _pkt_errno = PDERR_CANT_SET;
1974  return (0);
1975  }
1976 
1977  if (!PKT_API(&regs))
1978  {
1979  PKT_ERR ("Error setting receiver mode: ", _pkt_errno);
1980  return (0);
1981  }
1982  _pkt_rxmode = mode;
1983  return (1);
1984 }
1985 
2000 {
2001  IREGS regs;
2002 
2003  ASSERT_PKT_INF (-1);
2004 
2005  regs.r_ax = PD_GET_RCV;
2006  regs.r_bx = _pkt_inf->handle;
2007 
2008  /* This needs an Extended driver (not SLIP/PPP)
2009  */
2010  if (_pktdevlevel < 2 || _pktserial)
2011  {
2012  _pkt_errno = PDERR_BAD_COMMAND;
2013  return (0);
2014  }
2015 
2016  if (!PKT_API(&regs))
2017  {
2018  PKT_ERR ("Error getting receive mode: ", _pkt_errno);
2019  return (0);
2020  }
2021  _pkt_rxmode = regs.r_ax;
2022  return (regs.r_ax);
2023 }
2024 
2025 
2026 #if defined(USE_MULTICAST)
2027 
2037 int pkt_get_multicast_list (mac_address *listbuf, int *lenp)
2038 {
2039  IREGS regs;
2040  int len = *lenp;
2041 
2042  ASSERT_PKT_INF (0);
2043 
2044  regs.r_ax = PD_GET_MULTI;
2045  _pkt_errno = PDERR_NO_MULTICAST;
2046 
2047  /* Basic drivers don't support multicast
2048  */
2049  if (_pktdevlevel < 2 || _pktserial ||
2050  (got_params && pkt_params.multicast_avail == 0) ||
2051  !PKT_API(&regs))
2052  {
2053  if (debug_on > 0)
2054  PKT_ERR ("Error getting multicast list: ", _pkt_errno);
2055  return (0);
2056  }
2057 
2058  if ((WORD)regs.r_cx == 0) /* no MC addresses, okay */
2059  {
2060  memset (listbuf, 0, len);
2061  *lenp = 0;
2062  return (1);
2063  }
2064 
2065  /* move it into the caller's buffer
2066  */
2067  DISABLE();
2068  len = min (len, (WORD)regs.r_cx);
2069  get_rmode_data (listbuf, len, regs.r_es, regs.r_di);
2070  *lenp = len;
2071  ENABLE();
2072  return (1);
2073 }
2074 
2084 int pkt_set_multicast_list (const void *listbuf, int len)
2085 {
2086  IREGS regs;
2087  WORD seg, ofs;
2088 
2089  ASSERT_PKT_INF (0);
2090 
2091  /* Basic drivers don't support multicast
2092  */
2093  if (_pktdevlevel < 2 || _pktserial ||
2094  (got_params && pkt_params.multicast_avail == 0)) /* no point in trying */
2095  {
2096  _pkt_errno = PDERR_NO_MULTICAST;
2097  return (0);
2098  }
2099 
2100 #if (DOSX)
2101  if (len > PKT_TMP_SIZE)
2102  {
2103  _pkt_errno = PDERR_NO_SPACE;
2104  return (0);
2105  }
2106 #endif
2107 
2108  DISABLE();
2109 
2110 #if (DOSX & (PHARLAP|X32VM|POWERPAK))
2111  seg = RP_SEGM();
2112  ofs = PKT_TMP();
2113  WriteRealMem (rm_base + PKT_TMP(), (void*)listbuf, len);
2114 
2115 #elif (DOSX & DOS4GW)
2116  seg = RP_SEGM();
2117  ofs = PKT_TMP();
2118  memcpy ((void*)(rm_base + PKT_TMP()), listbuf, len);
2119 
2120 #elif (DOSX & DJGPP)
2121  seg = RP_SEGM();
2122  ofs = PKT_TMP();
2123  DOSMEMPUT (listbuf, len, rm_base + PKT_TMP());
2124 
2125 #else
2126  seg = FP_SEG (listbuf);
2127  ofs = FP_OFF (listbuf);
2128 #endif
2129 
2130  ENABLE();
2131 
2132  regs.r_ax = PD_SET_MULTI;
2133  regs.r_cx = len;
2134  regs.r_es = seg;
2135  regs.r_di = ofs;
2136 
2137  if (!PKT_API(&regs))
2138  {
2139  if (debug_on > 0)
2140  PKT_ERR ("Error setting multicast list: ", _pkt_errno);
2141  return (0);
2142  }
2143  return (1);
2144 }
2145 #endif /* USE_MULTICAST */
2146 #endif /* __MSDOS__ */
2147 
Definition: pcpkt.h:135
int pkt_waiting(void)
Return number of packets waiting in queue.
Definition: pcpkt.c:1378
convert to int
Definition: tcp.h:424
static int pkt16_drvr_init(mac_address *mac_addr)
Called from pkt_eth_init() to search for PKTDRVR.
Definition: pcpkt.c:578
int pkt_reset_handle(WORD handle)
Reset the driver-state associated with handle.
Definition: pcpkt.c:727
BOOL _watt_no_config
run with no config file (embedded/diskless)
Definition: sock_ini.c:135
int pkt_get_multicast_list(mac_address *listbuf, int *lenp)
Gets the current list of multicast addresses from the PKTDRVR.
Definition: pcpkt.c:2037
int pkt_release_handle(WORD handle)
Release the allocated protocol handle.
Definition: pcpkt.c:711
int pkt_get_rcv_mode(void)
Gets the receive mode of the interface (can never be mode 0).
Definition: pcpkt.c:1999
int pkt_set_rcv_mode(int mode)
Sets the receive mode of the interface.
Definition: pcpkt.c:1955
static void get_rmode_data(void *dest, unsigned size, WORD seg, WORD ofs)
Return PKTDRVR data at seg:ofs, Copy to 'dest'.
Definition: pcpkt.c:1871
int pkt_buf_wipe(void)
Clear the receive queue.
Definition: pcpkt.c:1334
int pkt_eth_init(mac_address *addr)
Initialise Packet driver interface.
Definition: pcpkt.c:1449
void Wait(unsigned msec)
Not all vendors have delay().
Definition: misc.c:776
void * pkt_tx_buf(void)
Return address of DOS memory Tx-buffer.
Definition: pcpkt.c:302
int pkt_get_drvr_ver(WORD *major, WORD *minor, WORD *unused1, WORD *unused2)
Return version of PKTDRVR.
Definition: pcpkt.c:532
DIRECT + broadcast packets.
Definition: pcpkt.h:111
int pkt_set_multicast_list(const void *listbuf, int len)
Sets the list of multicast addresses for which the PKTDRVR is responsible.
Definition: pcpkt.c:2084
int pkt_set_addr(const void *addr)
Set a new MAC source address.
Definition: pcpkt.c:1198
int pkt_send(const void *tx, int length)
Send a link-layer frame.
Definition: pcpkt.c:1090
Core definitions.
static BOOL pkt_api_entry(IREGS *reg, unsigned called_from_line)
The API entry to the network link-driver.
Definition: pcpkt.c:1897
static int pkt_drvr_info(void)
Fetch the PKTDRVR information.
Definition: pcpkt.c:382
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
DWORD pkt_dropped(void)
Return number of packets dropped.
Definition: pcpkt.c:1394
W32_FUNC int W32_CALL pkt_get_vector(void)
Return PKTDRVR vector.
Definition: pcpkt.c:546
int pkt_get_stats(struct PktStats *stats, struct PktStats *total)
Get PKTDRVR statistics.
Definition: pcpkt.c:1243
convert to 8-bit byte
Definition: tcp.h:425
static BOOL check_intr_num(WORD intr_num)
Check a single interrupt vector for signature string "PKT DRVR" at offset 3 into intr-handler.
Definition: pcpkt.c:1509
static void release_real_mem(void)
Release allocated DOS memory.
Definition: pcpkt.c:766
static int parse_config_pass_1(void)
Search WATTCP.CFG file for "PKT.VECTOR = 0x??" etc.
Definition: pcpkt.c:1410
static WORD cstate_dseg
Get VJ-compression statistics from pkt-driver.
Definition: pcpkt.c:1297
char _pktdrvrname[20]
Name of PKDRVR.
Definition: pcpkt.c:62
Definition: x32vm.h:16
BYTE _pktdevlevel
basic unless otherwise specified
Definition: pcpkt.c:55
int pkt_get_mtu(void)
Return PKTDRVR maximum-transmit-units (MTU).
Definition: pcpkt.c:489
WORD _pktdevclass
Ethernet, Token, FDDI etc.
Definition: pcpkt.c:51
int pkt_get_addr(mac_address *mac)
Return the MAC address.
Definition: pcpkt.c:1159
WORD _pkt_type_ofs
ofs from link-layer head to type
Definition: pcpkt.c:53
BOOL _pktserial
using serial driver, SLIP/PPP
Definition: pcpkt.c:54
const char * pkt_error
Last pkt error string.
Definition: pcpkt.c:59
int pkt_get_mac_len(void)
Return length of MAC address.
Definition: pcpkt.c:504
const char *W32_CALL pkt_strerror(int code)
Return textual error representing error-code.
Definition: pcpkt.c:216
Definition: zinftree.h:24
int _pkt_rxmode0
startup receive mode
Definition: pcpkt.c:57
struct pkt_info * _pkt_inf
module data that will be locked
Definition: pcpkt.c:64
int _pkt_errno
error code set in pcpkt.c API
Definition: pcpkt.c:58
int DTOR pkt_release(void)
Definition: pcpkt.c:838
Definition: tcp.h:778
receive all packets on network
Definition: pcpkt.h:114
BOOL _watt_fatal_error
Definition: misc.c:60
void pkt_free_pkt(const void *pkt)
Release a packet from the receive queue.
Definition: pcpkt.c:1349
int _pkt_rxmode
active receive mode
Definition: pcpkt.c:56
Definition: misc.h:511
static int pkt_set_access(void)
Setup the receiver upcall handler.
Definition: pcpkt.c:332
static void pkt_enqueue(unsigned rxBuf, WORD rxLen) static void __cdecl _far pkt_enqueue(BYTE _far *rxBuf
Enqueue a received packet into '_pkt_inf->pkt_queue'.
int pkt_get_params(struct PktParameters *params)
Get PKTDRVR parameters (MTU, version etc.)
Definition: pcpkt.c:466
int _pkt_forced_rxmode
Forced Rx-mode via WATTCP.CFG.
Definition: pcpkt.c:61
int pkt_get_api_ver(WORD *ver)
Return version of spec.
Definition: pcpkt.c:519
Placeholder for vital data accessed by capture thread.
Definition: pcpkt.h:206
convert to hex-byte
Definition: tcp.h:428
WORD _pkt_ip_ofs
ofs from link-layer head to ip
Definition: pcpkt.c:52
static int setup_pkt_inf(void)
Definition: pcpkt.c:1804