xref: /freebsd/contrib/libpcap/pcap-dos.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
1 /*
2  *  This file is part of DOS-libpcap
3  *  Ported to DOS/DOSX by G. Vanem <gvanem@yahoo.no>
4  *
5  *  pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode
6  *              network drivers.
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <float.h>
14 #include <fcntl.h>
15 #include <limits.h> /* for INT_MAX */
16 #include <io.h>
17 
18 #if defined(USE_32BIT_DRIVERS)
19   #include "msdos/pm_drvr/pmdrvr.h"
20   #include "msdos/pm_drvr/pci.h"
21   #include "msdos/pm_drvr/bios32.h"
22   #include "msdos/pm_drvr/module.h"
23   #include "msdos/pm_drvr/3c501.h"
24   #include "msdos/pm_drvr/3c503.h"
25   #include "msdos/pm_drvr/3c509.h"
26   #include "msdos/pm_drvr/3c59x.h"
27   #include "msdos/pm_drvr/3c515.h"
28   #include "msdos/pm_drvr/3c90x.h"
29   #include "msdos/pm_drvr/3c575_cb.h"
30   #include "msdos/pm_drvr/ne.h"
31   #include "msdos/pm_drvr/wd.h"
32   #include "msdos/pm_drvr/accton.h"
33   #include "msdos/pm_drvr/cs89x0.h"
34   #include "msdos/pm_drvr/rtl8139.h"
35   #include "msdos/pm_drvr/ne2k-pci.h"
36 #endif
37 
38 #include "pcap.h"
39 #include "pcap-dos.h"
40 #include "pcap-int.h"
41 #include "msdos/pktdrvr.h"
42 
43 #ifdef USE_NDIS2
44 #include "msdos/ndis2.h"
45 #endif
46 
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <net/if_arp.h>
50 #include <net/if_ether.h>
51 #include <net/if_packe.h>
52 #include <tcp.h>
53 
54 #if defined(USE_32BIT_DRIVERS)
55   #define FLUSHK()       do { _printk_safe = 1; _printk_flush(); } while (0)
56   #define NDIS_NEXT_DEV  &rtl8139_dev
57 
58   static char *rx_pool = NULL;
59   static void init_32bit (void);
60 
61   static int  pktq_init     (struct rx_ringbuf *q, int size, int num, char *pool);
62   static int  pktq_check    (struct rx_ringbuf *q);
63   static int  pktq_inc_out  (struct rx_ringbuf *q);
64   static int  pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC;
65   static void pktq_clear    (struct rx_ringbuf *q) LOCKED_FUNC;
66 
67   static struct rx_elem *pktq_in_elem  (struct rx_ringbuf *q) LOCKED_FUNC;
68   static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q);
69 
70 #else
71   #define FLUSHK()      ((void)0)
72   #define NDIS_NEXT_DEV  NULL
73 #endif
74 
75 /*
76  * Internal variables/functions in Watt-32
77  */
78 extern WORD  _pktdevclass;
79 extern BOOL  _eth_is_init;
80 extern int   _w32_dynamic_host;
81 extern int   _watt_do_exit;
82 extern int   _watt_is_init;
83 extern int   _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req;
84 extern void (*_w32_usr_post_init) (void);
85 extern void (*_w32_print_hook)();
86 
87 extern void dbug_write (const char *);  /* Watt-32 lib, pcdbug.c */
88 extern int  pkt_get_mtu (void);
89 
90 static int ref_count = 0;
91 
92 static u_long mac_count    = 0;
93 static u_long filter_count = 0;
94 
95 static volatile BOOL exc_occured = 0;
96 
97 static struct device *handle_to_device [20];
98 
99 static int  pcap_activate_dos (pcap_t *p);
100 static int  pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback,
101                            u_char *data);
102 static void pcap_cleanup_dos (pcap_t *p);
103 static int  pcap_stats_dos (pcap_t *p, struct pcap_stat *ps);
104 static int  pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len);
105 static int  pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp);
106 
107 static int  ndis_probe (struct device *dev);
108 static int  pkt_probe  (struct device *dev);
109 
110 static void close_driver (void);
111 static int  init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf);
112 static int  first_init (const char *name, char *ebuf, int promisc);
113 
114 static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
115                               const u_char *buf);
116 
117 /*
118  * These are the device we always support
119  */
120 static struct device ndis_dev = {
121               "ndis",
122               "NDIS2 LanManager",
123               0,
124               0,0,0,0,0,0,
125               NDIS_NEXT_DEV,  /* NULL or a 32-bit device */
126               ndis_probe
127             };
128 
129 static struct device pkt_dev = {
130               "pkt",
131               "Packet-Driver",
132               0,
133               0,0,0,0,0,0,
134               &ndis_dev,
135               pkt_probe
136             };
137 
138 static struct device *get_device (int fd)
139 {
140   if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0]))
141      return (NULL);
142   return handle_to_device [fd-1];
143 }
144 
145 /*
146  * Private data for capturing on MS-DOS.
147  */
148 struct pcap_dos {
149 	void (*wait_proc)(void); /* call proc while waiting */
150 	struct pcap_stat stat;
151 };
152 
153 pcap_t *pcap_create_interface (const char *device _U_, char *ebuf)
154 {
155 	pcap_t *p;
156 
157 	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dos);
158 	if (p == NULL)
159 		return (NULL);
160 
161 	p->activate_op = pcap_activate_dos;
162 	return (p);
163 }
164 
165 /*
166  * Open MAC-driver with name 'device_name' for live capture of
167  * network packets.
168  */
169 static int pcap_activate_dos (pcap_t *pcap)
170 {
171   if (pcap->opt.rfmon) {
172     /*
173      * No monitor mode on DOS.
174      */
175     return (PCAP_ERROR_RFMON_NOTSUP);
176   }
177 
178   /*
179    * Turn a negative snapshot value (invalid), a snapshot value of
180    * 0 (unspecified), or a value bigger than the normal maximum
181    * value, into the maximum allowed value.
182    *
183    * If some application really *needs* a bigger snapshot
184    * length, we should just increase MAXIMUM_SNAPLEN.
185    */
186   if (pcap->snapshot <= 0 || pcap->snapshot > MAXIMUM_SNAPLEN)
187     pcap->snapshot = MAXIMUM_SNAPLEN;
188 
189   if (pcap->snapshot < ETH_MIN+8)
190       pcap->snapshot = ETH_MIN+8;
191 
192   if (pcap->snapshot > ETH_MAX)   /* silently accept and truncate large MTUs */
193       pcap->snapshot = ETH_MAX;
194 
195   pcap->linktype          = DLT_EN10MB;  /* !! */
196   pcap->cleanup_op        = pcap_cleanup_dos;
197   pcap->read_op           = pcap_read_dos;
198   pcap->stats_op          = pcap_stats_dos;
199   pcap->inject_op         = pcap_sendpacket_dos;
200   pcap->setfilter_op      = pcap_setfilter_dos;
201   pcap->setdirection_op   = NULL;  /* Not implemented.*/
202   pcap->fd                = ++ref_count;
203 
204   pcap->bufsize = ETH_MAX+100;     /* add some margin */
205   pcap->buffer = calloc (pcap->bufsize, 1);
206 
207   if (pcap->fd == 1)  /* first time we're called */
208   {
209     if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) ||
210         !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc))
211     {
212       /* XXX - free pcap->buffer? */
213       return (PCAP_ERROR);
214     }
215     atexit (close_driver);
216   }
217   else if (stricmp(active_dev->name,pcap->opt.device))
218   {
219     snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
220                    "Cannot use different devices simultaneously "
221                    "(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
222     /* XXX - free pcap->buffer? */
223     return (PCAP_ERROR);
224   }
225   handle_to_device [pcap->fd-1] = active_dev;
226   return (0);
227 }
228 
229 /*
230  * Poll the receiver queue and call the pcap callback-handler
231  * with the packet.
232  */
233 static int
234 pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
235 {
236   struct pcap_dos *pd = p->priv;
237   struct pcap_pkthdr pcap;
238   struct timeval     now, expiry = { 0,0 };
239   int    rx_len = 0;
240 
241   if (p->opt.timeout > 0)
242   {
243     gettimeofday2 (&now, NULL);
244     expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout;
245     expiry.tv_sec  = now.tv_sec;
246     while (expiry.tv_usec >= 1000000L)
247     {
248       expiry.tv_usec -= 1000000L;
249       expiry.tv_sec++;
250     }
251   }
252 
253   while (!exc_occured)
254   {
255     volatile struct device *dev; /* might be reset by sig_handler */
256 
257     dev = get_device (p->fd);
258     if (!dev)
259        break;
260 
261     PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf);
262     FLUSHK();
263 
264     /* If driver has a zero-copy receive facility, peek at the queue,
265      * filter it, do the callback and release the buffer.
266      */
267     if (dev->peek_rx_buf)
268     {
269       PCAP_ASSERT (dev->release_rx_buf);
270       rx_len = (*dev->peek_rx_buf) (&p->buffer);
271     }
272     else
273     {
274       rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot);
275     }
276 
277     if (rx_len > 0)  /* got a packet */
278     {
279       mac_count++;
280 
281       FLUSHK();
282 
283       pcap.caplen = min (rx_len, p->snapshot);
284       pcap.len    = rx_len;
285 
286       if (callback &&
287           (!p->fcode.bf_insns || pcap_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
288       {
289         filter_count++;
290 
291         /* Fix-me!! Should be time of arrival. Not time of
292          * capture.
293          */
294         gettimeofday2 (&pcap.ts, NULL);
295         (*callback) (data, &pcap, p->buffer);
296       }
297 
298       if (dev->release_rx_buf)
299         (*dev->release_rx_buf) (p->buffer);
300 
301       if (pcap_pkt_debug > 0)
302       {
303         if (callback == watt32_recv_hook)
304              dbug_write ("pcap_recv_hook\n");
305         else dbug_write ("pcap_read_op\n");
306       }
307       FLUSHK();
308       return (1);
309     }
310 
311     /* Has "pcap_breakloop()" been called?
312      */
313     if (p->break_loop) {
314       /*
315        * Yes - clear the flag that indicates that it
316        * has, and return -2 to indicate that we were
317        * told to break out of the loop.
318        */
319       p->break_loop = 0;
320       return (-2);
321     }
322 
323     /* If not to wait for a packet or pcap_cleanup_dos() called from
324      * e.g. SIGINT handler, exit loop now.
325      */
326     if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0)
327        break;
328 
329     gettimeofday2 (&now, NULL);
330 
331     if (timercmp(&now, &expiry, >))
332        break;
333 
334 #ifndef DJGPP
335     kbhit();    /* a real CPU hog */
336 #endif
337 
338     if (pd->wait_proc)
339       (*pd->wait_proc)();     /* call yield func */
340   }
341 
342   if (rx_len < 0)            /* receive error */
343   {
344     pd->stat.ps_drop++;
345 #ifdef USE_32BIT_DRIVERS
346     if (pcap_pkt_debug > 1)
347        printk ("pkt-err %s\n", pktInfo.error);
348 #endif
349     return (-1);
350   }
351   return (0);
352 }
353 
354 static int
355 pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data)
356 {
357   int rc, num = 0;
358 
359   /*
360    * This can conceivably process more than INT_MAX packets,
361    * which would overflow the packet count, causing it either
362    * to look like a negative number, and thus cause us to
363    * return a value that looks like an error, or overflow
364    * back into positive territory, and thus cause us to
365    * return a too-low count.
366    *
367    * Therefore, if the packet count is unlimited, we clip
368    * it at INT_MAX; this routine is not expected to
369    * process packets indefinitely, so that's not an issue.
370    */
371   if (PACKET_COUNT_IS_UNLIMITED(cnt))
372     cnt = INT_MAX;
373 
374   while (num <= cnt)
375   {
376     if (p->fd <= 0)
377        return (-1);
378     rc = pcap_read_one (p, callback, data);
379     if (rc > 0)
380        num++;
381     if (rc < 0)
382        break;
383     _w32_os_yield();  /* allow SIGINT generation, yield to Win95/NT */
384   }
385   return (num);
386 }
387 
388 /*
389  * Return network statistics
390  */
391 static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps)
392 {
393   struct net_device_stats *stats;
394   struct pcap_dos         *pd;
395   struct device           *dev = p ? get_device(p->fd) : NULL;
396 
397   if (!dev)
398   {
399     strcpy (p->errbuf, "illegal pcap handle");
400     return (-1);
401   }
402 
403   if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL)
404   {
405     strcpy (p->errbuf, "device statistics not available");
406     return (-1);
407   }
408 
409   FLUSHK();
410 
411   pd = p->priv;
412   pd->stat.ps_recv   = stats->rx_packets;
413   pd->stat.ps_drop  += stats->rx_missed_errors;
414   pd->stat.ps_ifdrop = stats->rx_dropped +  /* queue full */
415                          stats->rx_errors;    /* HW errors */
416   if (ps)
417      *ps = pd->stat;
418 
419   return (0);
420 }
421 
422 /*
423  * Return detailed network/device statistics.
424  * May be called after 'dev->close' is called.
425  */
426 int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se)
427 {
428   struct device *dev = p ? get_device (p->fd) : NULL;
429 
430   if (!dev || !dev->get_stats)
431   {
432     pcap_strlcpy (p->errbuf, "detailed device statistics not available",
433              PCAP_ERRBUF_SIZE);
434     return (-1);
435   }
436 
437   if (!strnicmp(dev->name,"pkt",3))
438   {
439     pcap_strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics",
440              PCAP_ERRBUF_SIZE);
441     return (-1);
442   }
443   memcpy (se, (*dev->get_stats)(dev), sizeof(*se));
444   return (0);
445 }
446 
447 /*
448  * Simply store the filter-code for the pcap_read_dos() callback
449  * Some day the filter-code could be handed down to the active
450  * device (pkt_rx1.s or 32-bit device interrupt handler).
451  */
452 static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp)
453 {
454   if (!p)
455      return (-1);
456   p->fcode = *fp;
457   return (0);
458 }
459 
460 /*
461  * Return # of packets received in pcap_read_dos()
462  */
463 u_long pcap_mac_packets (void)
464 {
465   return (mac_count);
466 }
467 
468 /*
469  * Return # of packets passed through filter in pcap_read_dos()
470  */
471 u_long pcap_filter_packets (void)
472 {
473   return (filter_count);
474 }
475 
476 /*
477  * Close pcap device. Not called for offline captures.
478  */
479 static void pcap_cleanup_dos (pcap_t *p)
480 {
481   struct pcap_dos *pd;
482 
483   if (!exc_occured)
484   {
485     pd = p->priv;
486     if (pcap_stats(p,NULL) < 0)
487        pd->stat.ps_drop = 0;
488     if (!get_device(p->fd))
489        return;
490 
491     handle_to_device [p->fd-1] = NULL;
492     p->fd = 0;
493     if (ref_count > 0)
494         ref_count--;
495     if (ref_count > 0)
496        return;
497   }
498   close_driver();
499   /* XXX - call pcap_cleanup_live_common? */
500 }
501 
502 /*
503  * Return the name of the 1st network interface,
504  * or NULL if none can be found.
505  */
506 char *pcap_lookupdev (char *ebuf)
507 {
508   struct device *dev;
509 
510 #ifdef USE_32BIT_DRIVERS
511   init_32bit();
512 #endif
513 
514   for (dev = (struct device*)dev_base; dev; dev = dev->next)
515   {
516     PCAP_ASSERT (dev->probe);
517 
518     if ((*dev->probe)(dev))
519     {
520       FLUSHK();
521       probed_dev = (struct device*) dev; /* remember last probed device */
522       return (char*) dev->name;
523     }
524   }
525 
526   if (ebuf)
527      strcpy (ebuf, "No driver found");
528   return (NULL);
529 }
530 
531 /*
532  * Gets localnet & netmask from Watt-32.
533  */
534 int pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
535                     bpf_u_int32 *netmask, char *errbuf)
536 {
537   DWORD mask, net;
538 
539   if (!_watt_is_init)
540   {
541     strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be "
542                     "called first");
543     return (-1);
544   }
545 
546   mask  = _w32_sin_mask;
547   net = my_ip_addr & mask;
548   if (net == 0)
549   {
550     if (IN_CLASSA(*netmask))
551        net = IN_CLASSA_NET;
552     else if (IN_CLASSB(*netmask))
553        net = IN_CLASSB_NET;
554     else if (IN_CLASSC(*netmask))
555        net = IN_CLASSC_NET;
556     else
557     {
558       snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
559       return (-1);
560     }
561   }
562   *localnet = htonl (net);
563   *netmask = htonl (mask);
564 
565   ARGSUSED (device);
566   return (0);
567 }
568 
569 /*
570  * Get a list of all interfaces that are present and that we probe okay.
571  * Returns -1 on error, 0 otherwise.
572  * The list may be NULL empty if no interfaces were up and could be opened.
573  */
574 int pcap_platform_finddevs  (pcap_if_list_t *devlistp, char *errbuf)
575 {
576   struct device     *dev;
577   pcap_if_t *curdev;
578 #if 0   /* Pkt drivers should have no addresses */
579   struct sockaddr_in sa_ll_1, sa_ll_2;
580   struct sockaddr   *addr, *netmask, *broadaddr, *dstaddr;
581 #endif
582   int       ret = 0;
583   int       found = 0;
584 
585   for (dev = (struct device*)dev_base; dev; dev = dev->next)
586   {
587     PCAP_ASSERT (dev->probe);
588 
589     if (!(*dev->probe)(dev))
590        continue;
591 
592     PCAP_ASSERT (dev->close);  /* set by probe routine */
593     FLUSHK();
594     (*dev->close) (dev);
595 
596     /*
597      * XXX - find out whether it's up or running?  Does that apply here?
598      * Can we find out if anything's plugged into the adapter, if it's
599      * a wired device, and set PCAP_IF_CONNECTION_STATUS_CONNECTED
600      * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
601      */
602     if ((curdev = add_dev(devlistp, dev->name, 0,
603                 dev->long_name, errbuf)) == NULL)
604     {
605       ret = -1;
606       break;
607     }
608     found = 1;
609 #if 0   /* Pkt drivers should have no addresses */
610     memset (&sa_ll_1, 0, sizeof(sa_ll_1));
611     memset (&sa_ll_2, 0, sizeof(sa_ll_2));
612     sa_ll_1.sin_family = AF_INET;
613     sa_ll_2.sin_family = AF_INET;
614 
615     addr      = (struct sockaddr*) &sa_ll_1;
616     netmask   = (struct sockaddr*) &sa_ll_1;
617     dstaddr   = (struct sockaddr*) &sa_ll_1;
618     broadaddr = (struct sockaddr*) &sa_ll_2;
619     memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr));
620 
621     if (add_addr_to_dev(curdev, addr, sizeof(*addr),
622                         netmask, sizeof(*netmask),
623                         broadaddr, sizeof(*broadaddr),
624                         dstaddr, sizeof(*dstaddr), errbuf) < 0)
625     {
626       ret = -1;
627       break;
628     }
629 #endif
630   }
631 
632   if (ret == 0 && !found)
633      strcpy (errbuf, "No drivers found");
634 
635   return (ret);
636 }
637 
638 /*
639  * pcap_assert() is mainly used for debugging
640  */
641 void pcap_assert (const char *what, const char *file, unsigned line)
642 {
643   FLUSHK();
644   fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n",
645            file, line, what);
646   close_driver();
647   _exit (-1);
648 }
649 
650 /*
651  * For pcap_offline_read(): wait and yield between printing packets
652  * to simulate the pace packets where actually recorded.
653  */
654 void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait)
655 {
656   if (p)
657   {
658     struct pcap_dos *pd = p->priv;
659 
660     pd->wait_proc  = yield;
661     p->opt.timeout = wait;
662   }
663 }
664 
665 /*
666  * Initialise a named network device.
667  */
668 static struct device *
669 open_driver (const char *dev_name, char *ebuf, int promisc)
670 {
671   struct device *dev;
672 
673   for (dev = (struct device*)dev_base; dev; dev = dev->next)
674   {
675     PCAP_ASSERT (dev->name);
676 
677     if (strcmp (dev_name,dev->name))
678        continue;
679 
680     if (!probed_dev)   /* user didn't call pcap_lookupdev() first */
681     {
682       PCAP_ASSERT (dev->probe);
683 
684       if (!(*dev->probe)(dev))    /* call the xx_probe() function */
685       {
686         snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
687         return (NULL);
688       }
689       probed_dev = dev;  /* device is probed okay and may be used */
690     }
691     else if (dev != probed_dev)
692     {
693       goto not_probed;
694     }
695 
696     FLUSHK();
697 
698     /* Select what traffic to receive
699      */
700     if (promisc)
701          dev->flags |=  (IFF_ALLMULTI | IFF_PROMISC);
702     else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC);
703 
704     PCAP_ASSERT (dev->open);
705 
706     if (!(*dev->open)(dev))
707     {
708       snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
709       if (pktInfo.error && !strncmp(dev->name,"pkt",3))
710       {
711         strcat (ebuf, ": ");
712         strcat (ebuf, pktInfo.error);
713       }
714       return (NULL);
715     }
716 
717     /* Some devices need this to operate in promiscuous mode
718      */
719     if (promisc && dev->set_multicast_list)
720        (*dev->set_multicast_list) (dev);
721 
722     active_dev = dev;   /* remember our active device */
723     break;
724   }
725 
726   /* 'dev_name' not matched in 'dev_base' list.
727    */
728   if (!dev)
729   {
730     snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
731     return (NULL);
732   }
733 
734 not_probed:
735   if (!probed_dev)
736   {
737     snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
738     return (NULL);
739   }
740   return (dev);
741 }
742 
743 /*
744  * Deinitialise MAC driver.
745  * Set receive mode back to default mode.
746  */
747 static void close_driver (void)
748 {
749   /* !!todo: loop over all 'handle_to_device[]' ? */
750   struct device *dev = active_dev;
751 
752   if (dev && dev->close)
753   {
754     (*dev->close) (dev);
755     FLUSHK();
756   }
757 
758   active_dev = NULL;
759 
760 #ifdef USE_32BIT_DRIVERS
761   if (rx_pool)
762   {
763     k_free (rx_pool);
764     rx_pool = NULL;
765   }
766   if (dev)
767      pcibios_exit();
768 #endif
769 }
770 
771 
772 #ifdef __DJGPP__
773 static void setup_signals (void (*handler)(int))
774 {
775   signal (SIGSEGV,handler);
776   signal (SIGILL, handler);
777   signal (SIGFPE, handler);
778 }
779 
780 static void exc_handler (int sig)
781 {
782 #ifdef USE_32BIT_DRIVERS
783   if (active_dev->irq > 0)    /* excludes IRQ 0 */
784   {
785     disable_irq (active_dev->irq);
786     irq_eoi_cmd (active_dev->irq);
787     _printk_safe = 1;
788   }
789 #endif
790 
791   switch (sig)
792   {
793     case SIGSEGV:
794          fputs ("Catching SIGSEGV.\n", stderr);
795          break;
796     case SIGILL:
797          fputs ("Catching SIGILL.\n", stderr);
798          break;
799     case SIGFPE:
800          _fpreset();
801          fputs ("Catching SIGFPE.\n", stderr);
802          break;
803     default:
804          fprintf (stderr, "Catching signal %d.\n", sig);
805   }
806   exc_occured = 1;
807   close_driver();
808 }
809 #endif  /* __DJGPP__ */
810 
811 
812 /*
813  * Open the pcap device for the first client calling pcap_activate()
814  */
815 static int first_init (const char *name, char *ebuf, int promisc)
816 {
817   struct device *dev;
818 
819 #ifdef USE_32BIT_DRIVERS
820   rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE);
821   if (!rx_pool)
822   {
823     strcpy (ebuf, "Not enough memory (Rx pool)");
824     return (0);
825   }
826 #endif
827 
828 #ifdef __DJGPP__
829   setup_signals (exc_handler);
830 #endif
831 
832 #ifdef USE_32BIT_DRIVERS
833   init_32bit();
834 #endif
835 
836   dev = open_driver (name, ebuf, promisc);
837   if (!dev)
838   {
839 #ifdef USE_32BIT_DRIVERS
840     k_free (rx_pool);
841     rx_pool = NULL;
842 #endif
843 
844 #ifdef __DJGPP__
845     setup_signals (SIG_DFL);
846 #endif
847     return (0);
848   }
849 
850 #ifdef USE_32BIT_DRIVERS
851   /*
852    * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf'
853    * set in it's probe handler), initialise near-memory ring-buffer for
854    * the 32-bit device.
855    */
856   if (dev->copy_rx_buf == NULL)
857   {
858     dev->get_rx_buf     = get_rxbuf;
859     dev->peek_rx_buf    = peek_rxbuf;
860     dev->release_rx_buf = release_rxbuf;
861     pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool);
862   }
863 #endif
864   return (1);
865 }
866 
867 #ifdef USE_32BIT_DRIVERS
868 static void init_32bit (void)
869 {
870   static int init_pci = 0;
871 
872   if (!_printk_file)
873      _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */
874 
875   if (!init_pci)
876      (void)pci_init();             /* init BIOS32+PCI interface */
877   init_pci = 1;
878 }
879 #endif
880 
881 
882 /*
883  * Hook functions for using Watt-32 together with pcap
884  */
885 static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */
886 static WORD etype;
887 static pcap_t pcap_save;
888 
889 static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
890                               const u_char *buf)
891 {
892   /* Fix me: assumes Ethernet II only */
893   struct ether_header *ep = (struct ether_header*) buf;
894 
895   memcpy (rxbuf, buf, pcap->caplen);
896   etype = ep->ether_type;
897   ARGSUSED (dummy);
898 }
899 
900 #if (WATTCP_VER >= 0x0224)
901 /*
902  * This function is used by Watt-32 to poll for a packet.
903  * i.e. it's set to bypass _eth_arrived()
904  */
905 static void *pcap_recv_hook (WORD *type)
906 {
907   int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL);
908 
909   if (len < 0)
910      return (NULL);
911 
912   *type = etype;
913   return (void*) &rxbuf;
914 }
915 
916 /*
917  * This function is called by Watt-32 (via _eth_xmit_hook).
918  * If dbug_init() was called, we should trace packets sent.
919  */
920 static int pcap_xmit_hook (const void *buf, unsigned len)
921 {
922   int rc = 0;
923 
924   if (pcap_pkt_debug > 0)
925      dbug_write ("pcap_xmit_hook: ");
926 
927   if (active_dev && active_dev->xmit)
928      if ((*active_dev->xmit) (active_dev, buf, len) > 0)
929         rc = len;
930 
931   if (pcap_pkt_debug > 0)
932      dbug_write (rc ? "ok\n" : "fail\n");
933   return (rc);
934 }
935 #endif
936 
937 static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len)
938 {
939   struct device *dev = p ? get_device(p->fd) : NULL;
940 
941   if (!dev || !dev->xmit)
942      return (-1);
943   return (*dev->xmit) (dev, buf, len);
944 }
945 
946 /*
947  * This function is called by Watt-32 in tcp_post_init().
948  * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc.
949  */
950 static void (*prev_post_hook) (void);
951 
952 static void pcap_init_hook (void)
953 {
954   _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0;
955   _w32__do_mask_req = 0;
956   _w32_dynamic_host = 0;
957   if (prev_post_hook)
958     (*prev_post_hook)();
959 }
960 
961 /*
962  * Suppress PRINT message from Watt-32's sock_init()
963  */
964 static void null_print (void) {}
965 
966 /*
967  * To use features of Watt-32 (netdb functions and socket etc.)
968  * we must call sock_init(). But we set various hooks to prevent
969  * using normal PKTDRVR functions in pcpkt.c. This should hopefully
970  * make Watt-32 and pcap co-operate.
971  */
972 static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
973 {
974   char *env;
975   int   rc, MTU, has_ip_addr;
976   int   using_pktdrv = 1;
977 
978   /* If user called sock_init() first, we need to reinit in
979    * order to open debug/trace-file properly
980    */
981   if (_watt_is_init)
982      sock_exit();
983 
984   env = getenv ("PCAP_TRACE");
985   if (env && atoi(env) > 0 &&
986       pcap_pkt_debug < 0)   /* if not already set */
987   {
988     dbug_init();
989     pcap_pkt_debug = atoi (env);
990   }
991 
992   _watt_do_exit      = 0;    /* prevent sock_init() calling exit() */
993   prev_post_hook     = _w32_usr_post_init;
994   _w32_usr_post_init = pcap_init_hook;
995   _w32_print_hook    = null_print;
996 
997   if (dev_name && strncmp(dev_name,"pkt",3))
998      using_pktdrv = FALSE;
999 
1000   rc = sock_init();
1001   has_ip_addr = (rc != 8);  /* IP-address assignment failed */
1002 
1003   /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we
1004    * just pretend Watt-32 is initialised okay.
1005    *
1006    * !! fix-me: The Watt-32 config isn't done if no pktdrvr
1007    *            was found. In that case my_ip_addr + sin_mask
1008    *            have default values. Should be taken from another
1009    *            ini-file/environment in any case (ref. tcpdump.ini)
1010    */
1011   _watt_is_init = 1;
1012 
1013   if (!using_pktdrv || !has_ip_addr)  /* for now .... */
1014   {
1015     static const char myip[] = "192.168.0.1";
1016     static const char mask[] = "255.255.255.0";
1017 
1018     printf ("Just guessing, using IP %s and netmask %s\n", myip, mask);
1019     my_ip_addr    = aton (myip);
1020     _w32_sin_mask = aton (mask);
1021   }
1022   else if (rc && using_pktdrv)
1023   {
1024     snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
1025     return (0);
1026   }
1027 
1028   /* Set recv-hook for peeking in _eth_arrived().
1029    */
1030 #if (WATTCP_VER >= 0x0224)
1031   _eth_recv_hook = pcap_recv_hook;
1032   _eth_xmit_hook = pcap_xmit_hook;
1033 #endif
1034 
1035   /* Free the pkt-drvr handle allocated in pkt_init().
1036    * The above hooks should thus use the handle reopened in open_driver()
1037    */
1038   if (using_pktdrv)
1039   {
1040     _eth_release();
1041 /*  _eth_is_init = 1; */  /* hack to get Rx/Tx-hooks in Watt-32 working */
1042   }
1043 
1044   memcpy (&pcap_save, pcap, sizeof(pcap_save));
1045   MTU = pkt_get_mtu();
1046   pcap_save.fcode.bf_insns = NULL;
1047   pcap_save.linktype       = _eth_get_hwtype (NULL, NULL);
1048   pcap_save.snapshot       = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
1049 
1050   /* prevent use of resolve() and resolve_ip()
1051    */
1052   last_nameserver = 0;
1053   return (1);
1054 }
1055 
1056 int EISA_bus = 0;  /* Where is natural place for this? */
1057 
1058 /*
1059  * Application config hooks to set various driver parameters.
1060  */
1061 
1062 static const struct config_table debug_tab[] = {
1063             { "PKT.DEBUG",       ARG_ATOI,   &pcap_pkt_debug    },
1064             { "PKT.VECTOR",      ARG_ATOX_W, NULL               },
1065             { "NDIS.DEBUG",      ARG_ATOI,   NULL               },
1066 #ifdef USE_32BIT_DRIVERS
1067             { "3C503.DEBUG",     ARG_ATOI,   &ei_debug          },
1068             { "3C503.IO_BASE",   ARG_ATOX_W, &el2_dev.base_addr },
1069             { "3C503.MEMORY",    ARG_ATOX_W, &el2_dev.mem_start },
1070             { "3C503.IRQ",       ARG_ATOI,   &el2_dev.irq       },
1071             { "3C505.DEBUG",     ARG_ATOI,   NULL               },
1072             { "3C505.BASE",      ARG_ATOX_W, NULL               },
1073             { "3C507.DEBUG",     ARG_ATOI,   NULL               },
1074             { "3C509.DEBUG",     ARG_ATOI,   &el3_debug         },
1075             { "3C509.ILOOP",     ARG_ATOI,   &el3_max_loop      },
1076             { "3C529.DEBUG",     ARG_ATOI,   NULL               },
1077             { "3C575.DEBUG",     ARG_ATOI,   &debug_3c575       },
1078             { "3C59X.DEBUG",     ARG_ATOI,   &vortex_debug      },
1079             { "3C59X.IFACE0",    ARG_ATOI,   &vortex_options[0] },
1080             { "3C59X.IFACE1",    ARG_ATOI,   &vortex_options[1] },
1081             { "3C59X.IFACE2",    ARG_ATOI,   &vortex_options[2] },
1082             { "3C59X.IFACE3",    ARG_ATOI,   &vortex_options[3] },
1083             { "3C90X.DEBUG",     ARG_ATOX_W, &tc90xbc_debug     },
1084             { "ACCT.DEBUG",      ARG_ATOI,   &ethpk_debug       },
1085             { "CS89.DEBUG",      ARG_ATOI,   &cs89_debug        },
1086             { "RTL8139.DEBUG",   ARG_ATOI,   &rtl8139_debug     },
1087         /*  { "RTL8139.FDUPLEX", ARG_ATOI,   &rtl8139_options   }, */
1088             { "SMC.DEBUG",       ARG_ATOI,   &ei_debug          },
1089         /*  { "E100.DEBUG",      ARG_ATOI,   &e100_debug        }, */
1090             { "PCI.DEBUG",       ARG_ATOI,   &pci_debug         },
1091             { "BIOS32.DEBUG",    ARG_ATOI,   &bios32_debug      },
1092             { "IRQ.DEBUG",       ARG_ATOI,   &irq_debug         },
1093             { "TIMER.IRQ",       ARG_ATOI,   &timer_irq         },
1094 #endif
1095             { NULL }
1096           };
1097 
1098 /*
1099  * pcap_config_hook() is an extension to application's config
1100  * handling. Uses Watt-32's config-table function.
1101  */
1102 int pcap_config_hook (const char *keyword, const char *value)
1103 {
1104   return parse_config_table (debug_tab, NULL, keyword, value);
1105 }
1106 
1107 /*
1108  * Linked list of supported devices
1109  */
1110 struct device       *active_dev = NULL;      /* the device we have opened */
1111 struct device       *probed_dev = NULL;      /* the device we have probed */
1112 const struct device *dev_base   = &pkt_dev;  /* list of network devices */
1113 
1114 /*
1115  * PKTDRVR device functions
1116  */
1117 int pcap_pkt_debug = -1;
1118 
1119 static void pkt_close (struct device *dev)
1120 {
1121   BOOL okay = PktExitDriver();
1122 
1123   if (pcap_pkt_debug > 1)
1124      fprintf (stderr, "pkt_close(): %d\n", okay);
1125 
1126   if (dev->priv)
1127      free (dev->priv);
1128   dev->priv = NULL;
1129 }
1130 
1131 static int pkt_open (struct device *dev)
1132 {
1133   PKT_RX_MODE mode;
1134 
1135   if (dev->flags & IFF_PROMISC)
1136        mode = PDRX_ALL_PACKETS;
1137   else mode = PDRX_BROADCAST;
1138 
1139   if (!PktInitDriver(mode))
1140      return (0);
1141 
1142   PktResetStatistics (pktInfo.handle);
1143   PktQueueBusy (FALSE);
1144   return (1);
1145 }
1146 
1147 static int pkt_xmit (struct device *dev, const void *buf, int len)
1148 {
1149   struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1150 
1151   if (pcap_pkt_debug > 0)
1152      dbug_write ("pcap_xmit\n");
1153 
1154   if (!PktTransmit(buf,len))
1155   {
1156     stats->tx_errors++;
1157     return (0);
1158   }
1159   return (len);
1160 }
1161 
1162 static void *pkt_stats (struct device *dev)
1163 {
1164   struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1165 
1166   if (!stats || !PktSessStatistics(pktInfo.handle))
1167      return (NULL);
1168 
1169   stats->rx_packets       = pktStat.inPackets;
1170   stats->rx_errors        = pktStat.lost;
1171   stats->rx_missed_errors = PktRxDropped();
1172   return (stats);
1173 }
1174 
1175 static int pkt_probe (struct device *dev)
1176 {
1177   if (!PktSearchDriver())
1178      return (0);
1179 
1180   dev->open           = pkt_open;
1181   dev->xmit           = pkt_xmit;
1182   dev->close          = pkt_close;
1183   dev->get_stats      = pkt_stats;
1184   dev->copy_rx_buf    = PktReceive;  /* farmem peek and copy routine */
1185   dev->get_rx_buf     = NULL;
1186   dev->peek_rx_buf    = NULL;
1187   dev->release_rx_buf = NULL;
1188   dev->priv           = calloc (sizeof(struct net_device_stats), 1);
1189   if (!dev->priv)
1190      return (0);
1191   return (1);
1192 }
1193 
1194 /*
1195  * NDIS device functions
1196  */
1197 static void ndis_close (struct device *dev)
1198 {
1199 #ifdef USE_NDIS2
1200   NdisShutdown();
1201 #endif
1202   ARGSUSED (dev);
1203 }
1204 
1205 static int ndis_open (struct device *dev)
1206 {
1207   int promisc = (dev->flags & IFF_PROMISC);
1208 
1209 #ifdef USE_NDIS2
1210   if (!NdisInit(promisc))
1211      return (0);
1212   return (1);
1213 #else
1214   ARGSUSED (promisc);
1215   return (0);
1216 #endif
1217 }
1218 
1219 static void *ndis_stats (struct device *dev)
1220 {
1221   static struct net_device_stats stats;
1222 
1223   /* to-do */
1224   ARGSUSED (dev);
1225   return (&stats);
1226 }
1227 
1228 static int ndis_probe (struct device *dev)
1229 {
1230 #ifdef USE_NDIS2
1231   if (!NdisOpen())
1232      return (0);
1233 #endif
1234 
1235   dev->open           = ndis_open;
1236   dev->xmit           = NULL;
1237   dev->close          = ndis_close;
1238   dev->get_stats      = ndis_stats;
1239   dev->copy_rx_buf    = NULL;       /* to-do */
1240   dev->get_rx_buf     = NULL;       /* upcall is from rmode driver */
1241   dev->peek_rx_buf    = NULL;
1242   dev->release_rx_buf = NULL;
1243   return (0);
1244 }
1245 
1246 /*
1247  * Search & probe for supported 32-bit (pmode) pcap devices
1248  */
1249 #if defined(USE_32BIT_DRIVERS)
1250 
1251 struct device el2_dev LOCKED_VAR = {
1252               "3c503",
1253               "EtherLink II",
1254               0,
1255               0,0,0,0,0,0,
1256               NULL,
1257               el2_probe
1258             };
1259 
1260 struct device el3_dev LOCKED_VAR = {
1261               "3c509",
1262               "EtherLink III",
1263               0,
1264               0,0,0,0,0,0,
1265               &el2_dev,
1266               el3_probe
1267             };
1268 
1269 struct device tc515_dev LOCKED_VAR = {
1270               "3c515",
1271               "EtherLink PCI",
1272               0,
1273               0,0,0,0,0,0,
1274               &el3_dev,
1275               tc515_probe
1276             };
1277 
1278 struct device tc59_dev LOCKED_VAR = {
1279               "3c59x",
1280               "EtherLink PCI",
1281               0,
1282               0,0,0,0,0,0,
1283               &tc515_dev,
1284               tc59x_probe
1285             };
1286 
1287 struct device tc90xbc_dev LOCKED_VAR = {
1288               "3c90x",
1289               "EtherLink 90X",
1290               0,
1291               0,0,0,0,0,0,
1292               &tc59_dev,
1293               tc90xbc_probe
1294             };
1295 
1296 struct device wd_dev LOCKED_VAR = {
1297               "wd",
1298               "Westen Digital",
1299               0,
1300               0,0,0,0,0,0,
1301               &tc90xbc_dev,
1302               wd_probe
1303             };
1304 
1305 struct device ne_dev LOCKED_VAR = {
1306               "ne",
1307               "NEx000",
1308               0,
1309               0,0,0,0,0,0,
1310               &wd_dev,
1311               ne_probe
1312             };
1313 
1314 struct device acct_dev LOCKED_VAR = {
1315               "acct",
1316               "Accton EtherPocket",
1317               0,
1318               0,0,0,0,0,0,
1319               &ne_dev,
1320               ethpk_probe
1321             };
1322 
1323 struct device cs89_dev LOCKED_VAR = {
1324               "cs89",
1325               "Crystal Semiconductor",
1326               0,
1327               0,0,0,0,0,0,
1328               &acct_dev,
1329               cs89x0_probe
1330             };
1331 
1332 struct device rtl8139_dev LOCKED_VAR = {
1333               "rtl8139",
1334               "RealTek PCI",
1335               0,
1336               0,0,0,0,0,0,
1337               &cs89_dev,
1338               rtl8139_probe     /* dev->probe routine */
1339             };
1340 
1341 /*
1342  * Dequeue routine is called by polling.
1343  * NOTE: the queue-element is not copied, only a pointer is
1344  * returned at '*buf'
1345  */
1346 int peek_rxbuf (BYTE **buf)
1347 {
1348   struct rx_elem *tail, *head;
1349 
1350   PCAP_ASSERT (pktq_check (&active_dev->queue));
1351 
1352   DISABLE();
1353   tail = pktq_out_elem (&active_dev->queue);
1354   head = pktq_in_elem (&active_dev->queue);
1355   ENABLE();
1356 
1357   if (head != tail)
1358   {
1359     PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2);
1360 
1361     *buf = &tail->data[0];
1362     return (tail->size);
1363   }
1364   *buf = NULL;
1365   return (0);
1366 }
1367 
1368 /*
1369  * Release buffer we peeked at above.
1370  */
1371 int release_rxbuf (BYTE *buf)
1372 {
1373 #ifndef NDEBUG
1374   struct rx_elem *tail = pktq_out_elem (&active_dev->queue);
1375 
1376   PCAP_ASSERT (&tail->data[0] == buf);
1377 #else
1378   ARGSUSED (buf);
1379 #endif
1380   pktq_inc_out (&active_dev->queue);
1381   return (1);
1382 }
1383 
1384 /*
1385  * get_rxbuf() routine (in locked code) is called from IRQ handler
1386  * to request a buffer. Interrupts are disabled and we have a 32kB stack.
1387  */
1388 BYTE *get_rxbuf (int len)
1389 {
1390   int idx;
1391 
1392   if (len < ETH_MIN || len > ETH_MAX)
1393      return (NULL);
1394 
1395   idx = pktq_in_index (&active_dev->queue);
1396 
1397 #ifdef DEBUG
1398   {
1399     static int fan_idx LOCKED_VAR = 0;
1400     writew ("-\\|/"[fan_idx++] | (15 << 8),      /* white on black colour */
1401             0xB8000 + 2*79);  /* upper-right corner, 80-col colour screen */
1402     fan_idx &= 3;
1403   }
1404 /* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */
1405 #endif
1406 
1407   if (idx != active_dev->queue.out_index)
1408   {
1409     struct rx_elem *head = pktq_in_elem (&active_dev->queue);
1410 
1411     head->size = len;
1412     active_dev->queue.in_index = idx;
1413     return (&head->data[0]);
1414   }
1415 
1416   /* !!to-do: drop 25% of the oldest element
1417    */
1418   pktq_clear (&active_dev->queue);
1419   return (NULL);
1420 }
1421 
1422 /*
1423  *  Simple ring-buffer queue handler for reception of packets
1424  *  from network driver.
1425  */
1426 #define PKTQ_MARKER  0xDEADBEEF
1427 
1428 static int pktq_check (struct rx_ringbuf *q)
1429 {
1430 #ifndef NDEBUG
1431   int   i;
1432   char *buf;
1433 #endif
1434 
1435   if (!q || !q->num_elem || !q->buf_start)
1436      return (0);
1437 
1438 #ifndef NDEBUG
1439   buf = q->buf_start;
1440 
1441   for (i = 0; i < q->num_elem; i++)
1442   {
1443     buf += q->elem_size;
1444     if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER)
1445        return (0);
1446   }
1447 #endif
1448   return (1);
1449 }
1450 
1451 static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool)
1452 {
1453   int i;
1454 
1455   q->elem_size = size;
1456   q->num_elem  = num;
1457   q->buf_start = pool;
1458   q->in_index  = 0;
1459   q->out_index = 0;
1460 
1461   PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD));
1462   PCAP_ASSERT (num);
1463   PCAP_ASSERT (pool);
1464 
1465   for (i = 0; i < num; i++)
1466   {
1467 #if 0
1468     struct rx_elem *elem = (struct rx_elem*) pool;
1469 
1470     /* assert dword aligned elements
1471      */
1472     PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0);
1473 #endif
1474     pool += size;
1475     *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER;
1476   }
1477   return (1);
1478 }
1479 
1480 /*
1481  * Increment the queue 'out_index' (tail).
1482  * Check for wraps.
1483  */
1484 static int pktq_inc_out (struct rx_ringbuf *q)
1485 {
1486   q->out_index++;
1487   if (q->out_index >= q->num_elem)
1488       q->out_index = 0;
1489   return (q->out_index);
1490 }
1491 
1492 /*
1493  * Return the queue's next 'in_index' (head).
1494  * Check for wraps.
1495  */
1496 static int pktq_in_index (struct rx_ringbuf *q)
1497 {
1498   volatile int index = q->in_index + 1;
1499 
1500   if (index >= q->num_elem)
1501       index = 0;
1502   return (index);
1503 }
1504 
1505 /*
1506  * Return the queue's head-buffer.
1507  */
1508 static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q)
1509 {
1510   return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index));
1511 }
1512 
1513 /*
1514  * Return the queue's tail-buffer.
1515  */
1516 static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q)
1517 {
1518   return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index));
1519 }
1520 
1521 /*
1522  * Clear the queue ring-buffer by setting head=tail.
1523  */
1524 static void pktq_clear (struct rx_ringbuf *q)
1525 {
1526   q->in_index = q->out_index;
1527 }
1528 
1529 /*
1530  * Symbols that must be linkable for "gcc -O0"
1531  */
1532 #undef __IOPORT_H
1533 #undef __DMA_H
1534 
1535 #define extern
1536 #define __inline__
1537 
1538 #include "msdos/pm_drvr/ioport.h"
1539 #include "msdos/pm_drvr/dma.h"
1540 
1541 #endif /* USE_32BIT_DRIVERS */
1542 
1543 /*
1544  * Libpcap version string.
1545  */
1546 const char *
1547 pcap_lib_version(void)
1548 {
1549   return ("DOS-" PCAP_VERSION_STRING);
1550 }
1551