1335640Shselasky/*
2335640Shselasky *  This file is part of DOS-libpcap
3335640Shselasky *  Ported to DOS/DOSX by G. Vanem <gvanem@yahoo.no>
4335640Shselasky *
5335640Shselasky *  pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode
6335640Shselasky *              network drivers.
7335640Shselasky */
8335640Shselasky
9335640Shselasky#include <stdio.h>
10335640Shselasky#include <stdlib.h>
11335640Shselasky#include <string.h>
12335640Shselasky#include <signal.h>
13335640Shselasky#include <float.h>
14335640Shselasky#include <fcntl.h>
15335640Shselasky#include <io.h>
16335640Shselasky
17335640Shselasky#if defined(USE_32BIT_DRIVERS)
18335640Shselasky  #include "msdos/pm_drvr/pmdrvr.h"
19335640Shselasky  #include "msdos/pm_drvr/pci.h"
20335640Shselasky  #include "msdos/pm_drvr/bios32.h"
21335640Shselasky  #include "msdos/pm_drvr/module.h"
22335640Shselasky  #include "msdos/pm_drvr/3c501.h"
23335640Shselasky  #include "msdos/pm_drvr/3c503.h"
24335640Shselasky  #include "msdos/pm_drvr/3c509.h"
25335640Shselasky  #include "msdos/pm_drvr/3c59x.h"
26335640Shselasky  #include "msdos/pm_drvr/3c515.h"
27335640Shselasky  #include "msdos/pm_drvr/3c90x.h"
28335640Shselasky  #include "msdos/pm_drvr/3c575_cb.h"
29335640Shselasky  #include "msdos/pm_drvr/ne.h"
30335640Shselasky  #include "msdos/pm_drvr/wd.h"
31335640Shselasky  #include "msdos/pm_drvr/accton.h"
32335640Shselasky  #include "msdos/pm_drvr/cs89x0.h"
33335640Shselasky  #include "msdos/pm_drvr/rtl8139.h"
34335640Shselasky  #include "msdos/pm_drvr/ne2k-pci.h"
35335640Shselasky#endif
36335640Shselasky
37335640Shselasky#include "pcap.h"
38335640Shselasky#include "pcap-dos.h"
39335640Shselasky#include "pcap-int.h"
40335640Shselasky#include "msdos/pktdrvr.h"
41335640Shselasky
42335640Shselasky#ifdef USE_NDIS2
43335640Shselasky#include "msdos/ndis2.h"
44335640Shselasky#endif
45335640Shselasky
46335640Shselasky#include <arpa/inet.h>
47335640Shselasky#include <net/if.h>
48335640Shselasky#include <net/if_arp.h>
49335640Shselasky#include <net/if_ether.h>
50335640Shselasky#include <net/if_packe.h>
51335640Shselasky#include <tcp.h>
52335640Shselasky
53335640Shselasky#if defined(USE_32BIT_DRIVERS)
54335640Shselasky  #define FLUSHK()       do { _printk_safe = 1; _printk_flush(); } while (0)
55335640Shselasky  #define NDIS_NEXT_DEV  &rtl8139_dev
56335640Shselasky
57335640Shselasky  static char *rx_pool = NULL;
58335640Shselasky  static void init_32bit (void);
59335640Shselasky
60335640Shselasky  static int  pktq_init     (struct rx_ringbuf *q, int size, int num, char *pool);
61335640Shselasky  static int  pktq_check    (struct rx_ringbuf *q);
62335640Shselasky  static int  pktq_inc_out  (struct rx_ringbuf *q);
63335640Shselasky  static int  pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC;
64335640Shselasky  static void pktq_clear    (struct rx_ringbuf *q) LOCKED_FUNC;
65335640Shselasky
66335640Shselasky  static struct rx_elem *pktq_in_elem  (struct rx_ringbuf *q) LOCKED_FUNC;
67335640Shselasky  static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q);
68335640Shselasky
69335640Shselasky#else
70335640Shselasky  #define FLUSHK()      ((void)0)
71335640Shselasky  #define NDIS_NEXT_DEV  NULL
72335640Shselasky#endif
73335640Shselasky
74335640Shselasky/*
75335640Shselasky * Internal variables/functions in Watt-32
76335640Shselasky */
77335640Shselaskyextern WORD  _pktdevclass;
78335640Shselaskyextern BOOL  _eth_is_init;
79335640Shselaskyextern int   _w32_dynamic_host;
80335640Shselaskyextern int   _watt_do_exit;
81335640Shselaskyextern int   _watt_is_init;
82335640Shselaskyextern int   _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req;
83335640Shselaskyextern void (*_w32_usr_post_init) (void);
84335640Shselaskyextern void (*_w32_print_hook)();
85335640Shselasky
86335640Shselaskyextern void dbug_write (const char *);  /* Watt-32 lib, pcdbug.c */
87335640Shselaskyextern int  pkt_get_mtu (void);
88335640Shselasky
89335640Shselaskystatic int ref_count = 0;
90335640Shselasky
91335640Shselaskystatic u_long mac_count    = 0;
92335640Shselaskystatic u_long filter_count = 0;
93335640Shselasky
94335640Shselaskystatic volatile BOOL exc_occured = 0;
95335640Shselasky
96335640Shselaskystatic struct device *handle_to_device [20];
97335640Shselasky
98335640Shselaskystatic int  pcap_activate_dos (pcap_t *p);
99335640Shselaskystatic int  pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback,
100335640Shselasky                           u_char *data);
101335640Shselaskystatic void pcap_cleanup_dos (pcap_t *p);
102335640Shselaskystatic int  pcap_stats_dos (pcap_t *p, struct pcap_stat *ps);
103335640Shselaskystatic int  pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len);
104335640Shselaskystatic int  pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp);
105335640Shselasky
106335640Shselaskystatic int  ndis_probe (struct device *dev);
107335640Shselaskystatic int  pkt_probe  (struct device *dev);
108335640Shselasky
109335640Shselaskystatic void close_driver (void);
110335640Shselaskystatic int  init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf);
111335640Shselaskystatic int  first_init (const char *name, char *ebuf, int promisc);
112335640Shselasky
113335640Shselaskystatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
114335640Shselasky                              const u_char *buf);
115335640Shselasky
116335640Shselasky/*
117335640Shselasky * These are the device we always support
118335640Shselasky */
119335640Shselaskystatic struct device ndis_dev = {
120335640Shselasky              "ndis",
121335640Shselasky              "NDIS2 LanManager",
122335640Shselasky              0,
123335640Shselasky              0,0,0,0,0,0,
124335640Shselasky              NDIS_NEXT_DEV,  /* NULL or a 32-bit device */
125335640Shselasky              ndis_probe
126335640Shselasky            };
127335640Shselasky
128335640Shselaskystatic struct device pkt_dev = {
129335640Shselasky              "pkt",
130335640Shselasky              "Packet-Driver",
131335640Shselasky              0,
132335640Shselasky              0,0,0,0,0,0,
133335640Shselasky              &ndis_dev,
134335640Shselasky              pkt_probe
135335640Shselasky            };
136335640Shselasky
137335640Shselaskystatic struct device *get_device (int fd)
138335640Shselasky{
139335640Shselasky  if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0]))
140335640Shselasky     return (NULL);
141335640Shselasky  return handle_to_device [fd-1];
142335640Shselasky}
143335640Shselasky
144335640Shselasky/*
145335640Shselasky * Private data for capturing on MS-DOS.
146335640Shselasky */
147335640Shselaskystruct pcap_dos {
148335640Shselasky	void (*wait_proc)(void); /* call proc while waiting */
149335640Shselasky	struct pcap_stat stat;
150335640Shselasky};
151335640Shselasky
152335640Shselaskypcap_t *pcap_create_interface (const char *device _U_, char *ebuf)
153335640Shselasky{
154335640Shselasky	pcap_t *p;
155335640Shselasky
156335640Shselasky	p = pcap_create_common(ebuf, sizeof (struct pcap_dos));
157335640Shselasky	if (p == NULL)
158335640Shselasky		return (NULL);
159335640Shselasky
160335640Shselasky	p->activate_op = pcap_activate_dos;
161335640Shselasky	return (p);
162335640Shselasky}
163335640Shselasky
164335640Shselasky/*
165335640Shselasky * Open MAC-driver with name 'device_name' for live capture of
166335640Shselasky * network packets.
167335640Shselasky */
168335640Shselaskystatic int pcap_activate_dos (pcap_t *pcap)
169335640Shselasky{
170335640Shselasky  if (pcap->opt.rfmon) {
171335640Shselasky    /*
172335640Shselasky     * No monitor mode on DOS.
173335640Shselasky     */
174335640Shselasky    return (PCAP_ERROR_RFMON_NOTSUP);
175335640Shselasky  }
176335640Shselasky
177335640Shselasky  /*
178335640Shselasky   * Turn a negative snapshot value (invalid), a snapshot value of
179335640Shselasky   * 0 (unspecified), or a value bigger than the normal maximum
180335640Shselasky   * value, into the maximum allowed value.
181335640Shselasky   *
182335640Shselasky   * If some application really *needs* a bigger snapshot
183335640Shselasky   * length, we should just increase MAXIMUM_SNAPLEN.
184335640Shselasky   */
185335640Shselasky  if (pcap->snapshot <= 0 || pcap->snapshot > MAXIMUM_SNAPLEN)
186335640Shselasky    pcap->snapshot = MAXIMUM_SNAPLEN;
187335640Shselasky
188335640Shselasky  if (pcap->snapshot < ETH_MIN+8)
189335640Shselasky      pcap->snapshot = ETH_MIN+8;
190335640Shselasky
191335640Shselasky  if (pcap->snapshot > ETH_MAX)   /* silently accept and truncate large MTUs */
192335640Shselasky      pcap->snapshot = ETH_MAX;
193335640Shselasky
194335640Shselasky  pcap->linktype          = DLT_EN10MB;  /* !! */
195335640Shselasky  pcap->cleanup_op        = pcap_cleanup_dos;
196335640Shselasky  pcap->read_op           = pcap_read_dos;
197335640Shselasky  pcap->stats_op          = pcap_stats_dos;
198335640Shselasky  pcap->inject_op         = pcap_sendpacket_dos;
199335640Shselasky  pcap->setfilter_op      = pcap_setfilter_dos;
200335640Shselasky  pcap->setdirection_op   = NULL;  /* Not implemented.*/
201335640Shselasky  pcap->fd                = ++ref_count;
202335640Shselasky
203335640Shselasky  pcap->bufsize = ETH_MAX+100;     /* add some margin */
204335640Shselasky  pcap->buffer = calloc (pcap->bufsize, 1);
205335640Shselasky
206335640Shselasky  if (pcap->fd == 1)  /* first time we're called */
207335640Shselasky  {
208335640Shselasky    if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) ||
209335640Shselasky        !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc))
210335640Shselasky    {
211335640Shselasky      /* XXX - free pcap->buffer? */
212335640Shselasky      return (PCAP_ERROR);
213335640Shselasky    }
214335640Shselasky    atexit (close_driver);
215335640Shselasky  }
216335640Shselasky  else if (stricmp(active_dev->name,pcap->opt.device))
217335640Shselasky  {
218335640Shselasky    pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
219335640Shselasky                   "Cannot use different devices simultaneously "
220335640Shselasky                   "(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
221335640Shselasky    /* XXX - free pcap->buffer? */
222335640Shselasky    return (PCAP_ERROR);
223335640Shselasky  }
224335640Shselasky  handle_to_device [pcap->fd-1] = active_dev;
225335640Shselasky  return (0);
226335640Shselasky}
227335640Shselasky
228335640Shselasky/*
229335640Shselasky * Poll the receiver queue and call the pcap callback-handler
230335640Shselasky * with the packet.
231335640Shselasky */
232335640Shselaskystatic int
233335640Shselaskypcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
234335640Shselasky{
235335640Shselasky  struct pcap_dos *pd = p->priv;
236335640Shselasky  struct pcap_pkthdr pcap;
237335640Shselasky  struct timeval     now, expiry = { 0,0 };
238335640Shselasky  int    rx_len = 0;
239335640Shselasky
240335640Shselasky  if (p->opt.timeout > 0)
241335640Shselasky  {
242335640Shselasky    gettimeofday2 (&now, NULL);
243335640Shselasky    expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout;
244335640Shselasky    expiry.tv_sec  = now.tv_sec;
245335640Shselasky    while (expiry.tv_usec >= 1000000L)
246335640Shselasky    {
247335640Shselasky      expiry.tv_usec -= 1000000L;
248335640Shselasky      expiry.tv_sec++;
249335640Shselasky    }
250335640Shselasky  }
251335640Shselasky
252335640Shselasky  while (!exc_occured)
253335640Shselasky  {
254335640Shselasky    volatile struct device *dev; /* might be reset by sig_handler */
255335640Shselasky
256335640Shselasky    dev = get_device (p->fd);
257335640Shselasky    if (!dev)
258335640Shselasky       break;
259335640Shselasky
260335640Shselasky    PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf);
261335640Shselasky    FLUSHK();
262335640Shselasky
263335640Shselasky    /* If driver has a zero-copy receive facility, peek at the queue,
264335640Shselasky     * filter it, do the callback and release the buffer.
265335640Shselasky     */
266335640Shselasky    if (dev->peek_rx_buf)
267335640Shselasky    {
268335640Shselasky      PCAP_ASSERT (dev->release_rx_buf);
269335640Shselasky      rx_len = (*dev->peek_rx_buf) (&p->buffer);
270335640Shselasky    }
271335640Shselasky    else
272335640Shselasky    {
273335640Shselasky      rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot);
274335640Shselasky    }
275335640Shselasky
276335640Shselasky    if (rx_len > 0)  /* got a packet */
277335640Shselasky    {
278335640Shselasky      mac_count++;
279335640Shselasky
280335640Shselasky      FLUSHK();
281335640Shselasky
282335640Shselasky      pcap.caplen = min (rx_len, p->snapshot);
283335640Shselasky      pcap.len    = rx_len;
284335640Shselasky
285335640Shselasky      if (callback &&
286335640Shselasky          (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
287335640Shselasky      {
288335640Shselasky        filter_count++;
289335640Shselasky
290335640Shselasky        /* Fix-me!! Should be time of arrival. Not time of
291335640Shselasky         * capture.
292335640Shselasky         */
293335640Shselasky        gettimeofday2 (&pcap.ts, NULL);
294335640Shselasky        (*callback) (data, &pcap, p->buffer);
295335640Shselasky      }
296335640Shselasky
297335640Shselasky      if (dev->release_rx_buf)
298335640Shselasky        (*dev->release_rx_buf) (p->buffer);
299335640Shselasky
300335640Shselasky      if (pcap_pkt_debug > 0)
301335640Shselasky      {
302335640Shselasky        if (callback == watt32_recv_hook)
303335640Shselasky             dbug_write ("pcap_recv_hook\n");
304335640Shselasky        else dbug_write ("pcap_read_op\n");
305335640Shselasky      }
306335640Shselasky      FLUSHK();
307335640Shselasky      return (1);
308335640Shselasky    }
309335640Shselasky
310335640Shselasky    /* Has "pcap_breakloop()" been called?
311335640Shselasky     */
312335640Shselasky    if (p->break_loop) {
313335640Shselasky      /*
314335640Shselasky       * Yes - clear the flag that indicates that it
315335640Shselasky       * has, and return -2 to indicate that we were
316335640Shselasky       * told to break out of the loop.
317335640Shselasky       */
318335640Shselasky      p->break_loop = 0;
319335640Shselasky      return (-2);
320335640Shselasky    }
321335640Shselasky
322335640Shselasky    /* If not to wait for a packet or pcap_cleanup_dos() called from
323335640Shselasky     * e.g. SIGINT handler, exit loop now.
324335640Shselasky     */
325335640Shselasky    if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0)
326335640Shselasky       break;
327335640Shselasky
328335640Shselasky    gettimeofday2 (&now, NULL);
329335640Shselasky
330335640Shselasky    if (timercmp(&now, &expiry, >))
331335640Shselasky       break;
332335640Shselasky
333335640Shselasky#ifndef DJGPP
334335640Shselasky    kbhit();    /* a real CPU hog */
335335640Shselasky#endif
336335640Shselasky
337335640Shselasky    if (pd->wait_proc)
338335640Shselasky      (*pd->wait_proc)();     /* call yield func */
339335640Shselasky  }
340335640Shselasky
341335640Shselasky  if (rx_len < 0)            /* receive error */
342335640Shselasky  {
343335640Shselasky    pd->stat.ps_drop++;
344335640Shselasky#ifdef USE_32BIT_DRIVERS
345335640Shselasky    if (pcap_pkt_debug > 1)
346335640Shselasky       printk ("pkt-err %s\n", pktInfo.error);
347335640Shselasky#endif
348335640Shselasky    return (-1);
349335640Shselasky  }
350335640Shselasky  return (0);
351335640Shselasky}
352335640Shselasky
353335640Shselaskystatic int
354335640Shselaskypcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data)
355335640Shselasky{
356335640Shselasky  int rc, num = 0;
357335640Shselasky
358335640Shselasky  while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt))
359335640Shselasky  {
360335640Shselasky    if (p->fd <= 0)
361335640Shselasky       return (-1);
362335640Shselasky    rc = pcap_read_one (p, callback, data);
363335640Shselasky    if (rc > 0)
364335640Shselasky       num++;
365335640Shselasky    if (rc < 0)
366335640Shselasky       break;
367335640Shselasky    _w32_os_yield();  /* allow SIGINT generation, yield to Win95/NT */
368335640Shselasky  }
369335640Shselasky  return (num);
370335640Shselasky}
371335640Shselasky
372335640Shselasky/*
373335640Shselasky * Return network statistics
374335640Shselasky */
375335640Shselaskystatic int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps)
376335640Shselasky{
377335640Shselasky  struct net_device_stats *stats;
378335640Shselasky  struct pcap_dos         *pd;
379335640Shselasky  struct device           *dev = p ? get_device(p->fd) : NULL;
380335640Shselasky
381335640Shselasky  if (!dev)
382335640Shselasky  {
383335640Shselasky    strcpy (p->errbuf, "illegal pcap handle");
384335640Shselasky    return (-1);
385335640Shselasky  }
386335640Shselasky
387335640Shselasky  if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL)
388335640Shselasky  {
389335640Shselasky    strcpy (p->errbuf, "device statistics not available");
390335640Shselasky    return (-1);
391335640Shselasky  }
392335640Shselasky
393335640Shselasky  FLUSHK();
394335640Shselasky
395335640Shselasky  pd = p->priv;
396335640Shselasky  pd->stat.ps_recv   = stats->rx_packets;
397335640Shselasky  pd->stat.ps_drop  += stats->rx_missed_errors;
398335640Shselasky  pd->stat.ps_ifdrop = stats->rx_dropped +  /* queue full */
399335640Shselasky                         stats->rx_errors;    /* HW errors */
400335640Shselasky  if (ps)
401335640Shselasky     *ps = pd->stat;
402335640Shselasky
403335640Shselasky  return (0);
404335640Shselasky}
405335640Shselasky
406335640Shselasky/*
407335640Shselasky * Return detailed network/device statistics.
408335640Shselasky * May be called after 'dev->close' is called.
409335640Shselasky */
410335640Shselaskyint pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se)
411335640Shselasky{
412335640Shselasky  struct device *dev = p ? get_device (p->fd) : NULL;
413335640Shselasky
414335640Shselasky  if (!dev || !dev->get_stats)
415335640Shselasky  {
416356341Scy    pcap_strlcpy (p->errbuf, "detailed device statistics not available",
417335640Shselasky             PCAP_ERRBUF_SIZE);
418335640Shselasky    return (-1);
419335640Shselasky  }
420335640Shselasky
421335640Shselasky  if (!strnicmp(dev->name,"pkt",3))
422335640Shselasky  {
423356341Scy    pcap_strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics",
424335640Shselasky             PCAP_ERRBUF_SIZE);
425335640Shselasky    return (-1);
426335640Shselasky  }
427335640Shselasky  memcpy (se, (*dev->get_stats)(dev), sizeof(*se));
428335640Shselasky  return (0);
429335640Shselasky}
430335640Shselasky
431335640Shselasky/*
432335640Shselasky * Simply store the filter-code for the pcap_read_dos() callback
433335640Shselasky * Some day the filter-code could be handed down to the active
434335640Shselasky * device (pkt_rx1.s or 32-bit device interrupt handler).
435335640Shselasky */
436335640Shselaskystatic int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp)
437335640Shselasky{
438335640Shselasky  if (!p)
439335640Shselasky     return (-1);
440335640Shselasky  p->fcode = *fp;
441335640Shselasky  return (0);
442335640Shselasky}
443335640Shselasky
444335640Shselasky/*
445335640Shselasky * Return # of packets received in pcap_read_dos()
446335640Shselasky */
447335640Shselaskyu_long pcap_mac_packets (void)
448335640Shselasky{
449335640Shselasky  return (mac_count);
450335640Shselasky}
451335640Shselasky
452335640Shselasky/*
453335640Shselasky * Return # of packets passed through filter in pcap_read_dos()
454335640Shselasky */
455335640Shselaskyu_long pcap_filter_packets (void)
456335640Shselasky{
457335640Shselasky  return (filter_count);
458335640Shselasky}
459335640Shselasky
460335640Shselasky/*
461335640Shselasky * Close pcap device. Not called for offline captures.
462335640Shselasky */
463335640Shselaskystatic void pcap_cleanup_dos (pcap_t *p)
464335640Shselasky{
465335640Shselasky  struct pcap_dos *pd;
466335640Shselasky
467335640Shselasky  if (!exc_occured)
468335640Shselasky  {
469335640Shselasky    pd = p->priv;
470335640Shselasky    if (pcap_stats(p,NULL) < 0)
471335640Shselasky       pd->stat.ps_drop = 0;
472335640Shselasky    if (!get_device(p->fd))
473335640Shselasky       return;
474335640Shselasky
475335640Shselasky    handle_to_device [p->fd-1] = NULL;
476335640Shselasky    p->fd = 0;
477335640Shselasky    if (ref_count > 0)
478335640Shselasky        ref_count--;
479335640Shselasky    if (ref_count > 0)
480335640Shselasky       return;
481335640Shselasky  }
482335640Shselasky  close_driver();
483335640Shselasky  /* XXX - call pcap_cleanup_live_common? */
484335640Shselasky}
485335640Shselasky
486335640Shselasky/*
487335640Shselasky * Return the name of the 1st network interface,
488335640Shselasky * or NULL if none can be found.
489335640Shselasky */
490335640Shselaskychar *pcap_lookupdev (char *ebuf)
491335640Shselasky{
492335640Shselasky  struct device *dev;
493335640Shselasky
494335640Shselasky#ifdef USE_32BIT_DRIVERS
495335640Shselasky  init_32bit();
496335640Shselasky#endif
497335640Shselasky
498335640Shselasky  for (dev = (struct device*)dev_base; dev; dev = dev->next)
499335640Shselasky  {
500335640Shselasky    PCAP_ASSERT (dev->probe);
501335640Shselasky
502335640Shselasky    if ((*dev->probe)(dev))
503335640Shselasky    {
504335640Shselasky      FLUSHK();
505335640Shselasky      probed_dev = (struct device*) dev; /* remember last probed device */
506335640Shselasky      return (char*) dev->name;
507335640Shselasky    }
508335640Shselasky  }
509335640Shselasky
510335640Shselasky  if (ebuf)
511335640Shselasky     strcpy (ebuf, "No driver found");
512335640Shselasky  return (NULL);
513335640Shselasky}
514335640Shselasky
515335640Shselasky/*
516335640Shselasky * Gets localnet & netmask from Watt-32.
517335640Shselasky */
518335640Shselaskyint pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
519335640Shselasky                    bpf_u_int32 *netmask, char *errbuf)
520335640Shselasky{
521335640Shselasky  DWORD mask, net;
522335640Shselasky
523335640Shselasky  if (!_watt_is_init)
524335640Shselasky  {
525335640Shselasky    strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be "
526335640Shselasky                    "called first");
527335640Shselasky    return (-1);
528335640Shselasky  }
529335640Shselasky
530335640Shselasky  mask  = _w32_sin_mask;
531335640Shselasky  net = my_ip_addr & mask;
532335640Shselasky  if (net == 0)
533335640Shselasky  {
534335640Shselasky    if (IN_CLASSA(*netmask))
535335640Shselasky       net = IN_CLASSA_NET;
536335640Shselasky    else if (IN_CLASSB(*netmask))
537335640Shselasky       net = IN_CLASSB_NET;
538335640Shselasky    else if (IN_CLASSC(*netmask))
539335640Shselasky       net = IN_CLASSC_NET;
540335640Shselasky    else
541335640Shselasky    {
542335640Shselasky      pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
543335640Shselasky      return (-1);
544335640Shselasky    }
545335640Shselasky  }
546335640Shselasky  *localnet = htonl (net);
547335640Shselasky  *netmask = htonl (mask);
548335640Shselasky
549335640Shselasky  ARGSUSED (device);
550335640Shselasky  return (0);
551335640Shselasky}
552335640Shselasky
553335640Shselasky/*
554335640Shselasky * Get a list of all interfaces that are present and that we probe okay.
555335640Shselasky * Returns -1 on error, 0 otherwise.
556335640Shselasky * The list may be NULL epty if no interfaces were up and could be opened.
557335640Shselasky */
558335640Shselaskyint pcap_platform_finddevs  (pcap_if_list_t *devlistp, char *errbuf)
559335640Shselasky{
560335640Shselasky  struct device     *dev;
561335640Shselasky  pcap_if_t *curdev;
562335640Shselasky#if 0   /* Pkt drivers should have no addresses */
563335640Shselasky  struct sockaddr_in sa_ll_1, sa_ll_2;
564335640Shselasky  struct sockaddr   *addr, *netmask, *broadaddr, *dstaddr;
565335640Shselasky#endif
566335640Shselasky  int       ret = 0;
567335640Shselasky  int       found = 0;
568335640Shselasky
569335640Shselasky  for (dev = (struct device*)dev_base; dev; dev = dev->next)
570335640Shselasky  {
571335640Shselasky    PCAP_ASSERT (dev->probe);
572335640Shselasky
573335640Shselasky    if (!(*dev->probe)(dev))
574335640Shselasky       continue;
575335640Shselasky
576335640Shselasky    PCAP_ASSERT (dev->close);  /* set by probe routine */
577335640Shselasky    FLUSHK();
578335640Shselasky    (*dev->close) (dev);
579335640Shselasky
580335640Shselasky    /*
581335640Shselasky     * XXX - find out whether it's up or running?  Does that apply here?
582335640Shselasky     * Can we find out if anything's plugged into the adapter, if it's
583335640Shselasky     * a wired device, and set PCAP_IF_CONNECTION_STATUS_CONNECTED
584335640Shselasky     * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
585335640Shselasky     */
586335640Shselasky    if ((curdev = add_dev(devlistp, dev->name, 0,
587335640Shselasky                dev->long_name, errbuf)) == NULL)
588335640Shselasky    {
589335640Shselasky      ret = -1;
590335640Shselasky      break;
591335640Shselasky    }
592335640Shselasky    found = 1;
593335640Shselasky#if 0   /* Pkt drivers should have no addresses */
594335640Shselasky    memset (&sa_ll_1, 0, sizeof(sa_ll_1));
595335640Shselasky    memset (&sa_ll_2, 0, sizeof(sa_ll_2));
596335640Shselasky    sa_ll_1.sin_family = AF_INET;
597335640Shselasky    sa_ll_2.sin_family = AF_INET;
598335640Shselasky
599335640Shselasky    addr      = (struct sockaddr*) &sa_ll_1;
600335640Shselasky    netmask   = (struct sockaddr*) &sa_ll_1;
601335640Shselasky    dstaddr   = (struct sockaddr*) &sa_ll_1;
602335640Shselasky    broadaddr = (struct sockaddr*) &sa_ll_2;
603335640Shselasky    memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr));
604335640Shselasky
605335640Shselasky    if (add_addr_to_dev(curdev, addr, sizeof(*addr),
606335640Shselasky                        netmask, sizeof(*netmask),
607335640Shselasky                        broadaddr, sizeof(*broadaddr),
608335640Shselasky                        dstaddr, sizeof(*dstaddr), errbuf) < 0)
609335640Shselasky    {
610335640Shselasky      ret = -1;
611335640Shselasky      break;
612335640Shselasky    }
613335640Shselasky#endif
614335640Shselasky  }
615335640Shselasky
616335640Shselasky  if (ret == 0 && !found)
617335640Shselasky     strcpy (errbuf, "No drivers found");
618335640Shselasky
619335640Shselasky  return (ret);
620335640Shselasky}
621335640Shselasky
622335640Shselasky/*
623335640Shselasky * pcap_assert() is mainly used for debugging
624335640Shselasky */
625335640Shselaskyvoid pcap_assert (const char *what, const char *file, unsigned line)
626335640Shselasky{
627335640Shselasky  FLUSHK();
628335640Shselasky  fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n",
629335640Shselasky           file, line, what);
630335640Shselasky  close_driver();
631335640Shselasky  _exit (-1);
632335640Shselasky}
633335640Shselasky
634335640Shselasky/*
635335640Shselasky * For pcap_offline_read(): wait and yield between printing packets
636335640Shselasky * to simulate the pace packets where actually recorded.
637335640Shselasky */
638335640Shselaskyvoid pcap_set_wait (pcap_t *p, void (*yield)(void), int wait)
639335640Shselasky{
640335640Shselasky  if (p)
641335640Shselasky  {
642335640Shselasky    struct pcap_dos *pd = p->priv;
643335640Shselasky
644335640Shselasky    pd->wait_proc  = yield;
645335640Shselasky    p->opt.timeout = wait;
646335640Shselasky  }
647335640Shselasky}
648335640Shselasky
649335640Shselasky/*
650335640Shselasky * Initialise a named network device.
651335640Shselasky */
652335640Shselaskystatic struct device *
653335640Shselaskyopen_driver (const char *dev_name, char *ebuf, int promisc)
654335640Shselasky{
655335640Shselasky  struct device *dev;
656335640Shselasky
657335640Shselasky  for (dev = (struct device*)dev_base; dev; dev = dev->next)
658335640Shselasky  {
659335640Shselasky    PCAP_ASSERT (dev->name);
660335640Shselasky
661335640Shselasky    if (strcmp (dev_name,dev->name))
662335640Shselasky       continue;
663335640Shselasky
664335640Shselasky    if (!probed_dev)   /* user didn't call pcap_lookupdev() first */
665335640Shselasky    {
666335640Shselasky      PCAP_ASSERT (dev->probe);
667335640Shselasky
668335640Shselasky      if (!(*dev->probe)(dev))    /* call the xx_probe() function */
669335640Shselasky      {
670335640Shselasky        pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
671335640Shselasky        return (NULL);
672335640Shselasky      }
673335640Shselasky      probed_dev = dev;  /* device is probed okay and may be used */
674335640Shselasky    }
675335640Shselasky    else if (dev != probed_dev)
676335640Shselasky    {
677335640Shselasky      goto not_probed;
678335640Shselasky    }
679335640Shselasky
680335640Shselasky    FLUSHK();
681335640Shselasky
682335640Shselasky    /* Select what traffic to receive
683335640Shselasky     */
684335640Shselasky    if (promisc)
685335640Shselasky         dev->flags |=  (IFF_ALLMULTI | IFF_PROMISC);
686335640Shselasky    else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC);
687335640Shselasky
688335640Shselasky    PCAP_ASSERT (dev->open);
689335640Shselasky
690335640Shselasky    if (!(*dev->open)(dev))
691335640Shselasky    {
692335640Shselasky      pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
693335640Shselasky      if (pktInfo.error && !strncmp(dev->name,"pkt",3))
694335640Shselasky      {
695335640Shselasky        strcat (ebuf, ": ");
696335640Shselasky        strcat (ebuf, pktInfo.error);
697335640Shselasky      }
698335640Shselasky      return (NULL);
699335640Shselasky    }
700335640Shselasky
701335640Shselasky    /* Some devices need this to operate in promiscous mode
702335640Shselasky     */
703335640Shselasky    if (promisc && dev->set_multicast_list)
704335640Shselasky       (*dev->set_multicast_list) (dev);
705335640Shselasky
706335640Shselasky    active_dev = dev;   /* remember our active device */
707335640Shselasky    break;
708335640Shselasky  }
709335640Shselasky
710335640Shselasky  /* 'dev_name' not matched in 'dev_base' list.
711335640Shselasky   */
712335640Shselasky  if (!dev)
713335640Shselasky  {
714335640Shselasky    pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
715335640Shselasky    return (NULL);
716335640Shselasky  }
717335640Shselasky
718335640Shselaskynot_probed:
719335640Shselasky  if (!probed_dev)
720335640Shselasky  {
721335640Shselasky    pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
722335640Shselasky    return (NULL);
723335640Shselasky  }
724335640Shselasky  return (dev);
725335640Shselasky}
726335640Shselasky
727335640Shselasky/*
728335640Shselasky * Deinitialise MAC driver.
729335640Shselasky * Set receive mode back to default mode.
730335640Shselasky */
731335640Shselaskystatic void close_driver (void)
732335640Shselasky{
733335640Shselasky  /* !!todo: loop over all 'handle_to_device[]' ? */
734335640Shselasky  struct device *dev = active_dev;
735335640Shselasky
736335640Shselasky  if (dev && dev->close)
737335640Shselasky  {
738335640Shselasky    (*dev->close) (dev);
739335640Shselasky    FLUSHK();
740335640Shselasky  }
741335640Shselasky
742335640Shselasky  active_dev = NULL;
743335640Shselasky
744335640Shselasky#ifdef USE_32BIT_DRIVERS
745335640Shselasky  if (rx_pool)
746335640Shselasky  {
747335640Shselasky    k_free (rx_pool);
748335640Shselasky    rx_pool = NULL;
749335640Shselasky  }
750335640Shselasky  if (dev)
751335640Shselasky     pcibios_exit();
752335640Shselasky#endif
753335640Shselasky}
754335640Shselasky
755335640Shselasky
756335640Shselasky#ifdef __DJGPP__
757335640Shselaskystatic void setup_signals (void (*handler)(int))
758335640Shselasky{
759335640Shselasky  signal (SIGSEGV,handler);
760335640Shselasky  signal (SIGILL, handler);
761335640Shselasky  signal (SIGFPE, handler);
762335640Shselasky}
763335640Shselasky
764335640Shselaskystatic void exc_handler (int sig)
765335640Shselasky{
766335640Shselasky#ifdef USE_32BIT_DRIVERS
767335640Shselasky  if (active_dev->irq > 0)    /* excludes IRQ 0 */
768335640Shselasky  {
769335640Shselasky    disable_irq (active_dev->irq);
770335640Shselasky    irq_eoi_cmd (active_dev->irq);
771335640Shselasky    _printk_safe = 1;
772335640Shselasky  }
773335640Shselasky#endif
774335640Shselasky
775335640Shselasky  switch (sig)
776335640Shselasky  {
777335640Shselasky    case SIGSEGV:
778335640Shselasky         fputs ("Catching SIGSEGV.\n", stderr);
779335640Shselasky         break;
780335640Shselasky    case SIGILL:
781335640Shselasky         fputs ("Catching SIGILL.\n", stderr);
782335640Shselasky         break;
783335640Shselasky    case SIGFPE:
784335640Shselasky         _fpreset();
785335640Shselasky         fputs ("Catching SIGFPE.\n", stderr);
786335640Shselasky         break;
787335640Shselasky    default:
788335640Shselasky         fprintf (stderr, "Catching signal %d.\n", sig);
789335640Shselasky  }
790335640Shselasky  exc_occured = 1;
791335640Shselasky  close_driver();
792335640Shselasky}
793335640Shselasky#endif  /* __DJGPP__ */
794335640Shselasky
795335640Shselasky
796335640Shselasky/*
797335640Shselasky * Open the pcap device for the first client calling pcap_activate()
798335640Shselasky */
799335640Shselaskystatic int first_init (const char *name, char *ebuf, int promisc)
800335640Shselasky{
801335640Shselasky  struct device *dev;
802335640Shselasky
803335640Shselasky#ifdef USE_32BIT_DRIVERS
804335640Shselasky  rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE);
805335640Shselasky  if (!rx_pool)
806335640Shselasky  {
807335640Shselasky    strcpy (ebuf, "Not enough memory (Rx pool)");
808335640Shselasky    return (0);
809335640Shselasky  }
810335640Shselasky#endif
811335640Shselasky
812335640Shselasky#ifdef __DJGPP__
813335640Shselasky  setup_signals (exc_handler);
814335640Shselasky#endif
815335640Shselasky
816335640Shselasky#ifdef USE_32BIT_DRIVERS
817335640Shselasky  init_32bit();
818335640Shselasky#endif
819335640Shselasky
820335640Shselasky  dev = open_driver (name, ebuf, promisc);
821335640Shselasky  if (!dev)
822335640Shselasky  {
823335640Shselasky#ifdef USE_32BIT_DRIVERS
824335640Shselasky    k_free (rx_pool);
825335640Shselasky    rx_pool = NULL;
826335640Shselasky#endif
827335640Shselasky
828335640Shselasky#ifdef __DJGPP__
829335640Shselasky    setup_signals (SIG_DFL);
830335640Shselasky#endif
831335640Shselasky    return (0);
832335640Shselasky  }
833335640Shselasky
834335640Shselasky#ifdef USE_32BIT_DRIVERS
835335640Shselasky  /*
836335640Shselasky   * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf'
837335640Shselasky   * set in it's probe handler), initialise near-memory ring-buffer for
838335640Shselasky   * the 32-bit device.
839335640Shselasky   */
840335640Shselasky  if (dev->copy_rx_buf == NULL)
841335640Shselasky  {
842335640Shselasky    dev->get_rx_buf     = get_rxbuf;
843335640Shselasky    dev->peek_rx_buf    = peek_rxbuf;
844335640Shselasky    dev->release_rx_buf = release_rxbuf;
845335640Shselasky    pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool);
846335640Shselasky  }
847335640Shselasky#endif
848335640Shselasky  return (1);
849335640Shselasky}
850335640Shselasky
851335640Shselasky#ifdef USE_32BIT_DRIVERS
852335640Shselaskystatic void init_32bit (void)
853335640Shselasky{
854335640Shselasky  static int init_pci = 0;
855335640Shselasky
856335640Shselasky  if (!_printk_file)
857335640Shselasky     _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */
858335640Shselasky
859335640Shselasky  if (!init_pci)
860335640Shselasky     (void)pci_init();             /* init BIOS32+PCI interface */
861335640Shselasky  init_pci = 1;
862335640Shselasky}
863335640Shselasky#endif
864335640Shselasky
865335640Shselasky
866335640Shselasky/*
867335640Shselasky * Hook functions for using Watt-32 together with pcap
868335640Shselasky */
869335640Shselaskystatic char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */
870335640Shselaskystatic WORD etype;
871335640Shselaskystatic pcap_t pcap_save;
872335640Shselasky
873335640Shselaskystatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
874335640Shselasky                              const u_char *buf)
875335640Shselasky{
876335640Shselasky  /* Fix me: assumes Ethernet II only */
877335640Shselasky  struct ether_header *ep = (struct ether_header*) buf;
878335640Shselasky
879335640Shselasky  memcpy (rxbuf, buf, pcap->caplen);
880335640Shselasky  etype = ep->ether_type;
881335640Shselasky  ARGSUSED (dummy);
882335640Shselasky}
883335640Shselasky
884335640Shselasky#if (WATTCP_VER >= 0x0224)
885335640Shselasky/*
886335640Shselasky * This function is used by Watt-32 to poll for a packet.
887335640Shselasky * i.e. it's set to bypass _eth_arrived()
888335640Shselasky */
889335640Shselaskystatic void *pcap_recv_hook (WORD *type)
890335640Shselasky{
891335640Shselasky  int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL);
892335640Shselasky
893335640Shselasky  if (len < 0)
894335640Shselasky     return (NULL);
895335640Shselasky
896335640Shselasky  *type = etype;
897335640Shselasky  return (void*) &rxbuf;
898335640Shselasky}
899335640Shselasky
900335640Shselasky/*
901335640Shselasky * This function is called by Watt-32 (via _eth_xmit_hook).
902335640Shselasky * If dbug_init() was called, we should trace packets sent.
903335640Shselasky */
904335640Shselaskystatic int pcap_xmit_hook (const void *buf, unsigned len)
905335640Shselasky{
906335640Shselasky  int rc = 0;
907335640Shselasky
908335640Shselasky  if (pcap_pkt_debug > 0)
909335640Shselasky     dbug_write ("pcap_xmit_hook: ");
910335640Shselasky
911335640Shselasky  if (active_dev && active_dev->xmit)
912335640Shselasky     if ((*active_dev->xmit) (active_dev, buf, len) > 0)
913335640Shselasky        rc = len;
914335640Shselasky
915335640Shselasky  if (pcap_pkt_debug > 0)
916335640Shselasky     dbug_write (rc ? "ok\n" : "fail\n");
917335640Shselasky  return (rc);
918335640Shselasky}
919335640Shselasky#endif
920335640Shselasky
921335640Shselaskystatic int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len)
922335640Shselasky{
923335640Shselasky  struct device *dev = p ? get_device(p->fd) : NULL;
924335640Shselasky
925335640Shselasky  if (!dev || !dev->xmit)
926335640Shselasky     return (-1);
927335640Shselasky  return (*dev->xmit) (dev, buf, len);
928335640Shselasky}
929335640Shselasky
930335640Shselasky/*
931335640Shselasky * This function is called by Watt-32 in tcp_post_init().
932335640Shselasky * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc.
933335640Shselasky */
934335640Shselaskystatic void (*prev_post_hook) (void);
935335640Shselasky
936335640Shselaskystatic void pcap_init_hook (void)
937335640Shselasky{
938335640Shselasky  _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0;
939335640Shselasky  _w32__do_mask_req = 0;
940335640Shselasky  _w32_dynamic_host = 0;
941335640Shselasky  if (prev_post_hook)
942335640Shselasky    (*prev_post_hook)();
943335640Shselasky}
944335640Shselasky
945335640Shselasky/*
946335640Shselasky * Supress PRINT message from Watt-32's sock_init()
947335640Shselasky */
948335640Shselaskystatic void null_print (void) {}
949335640Shselasky
950335640Shselasky/*
951335640Shselasky * To use features of Watt-32 (netdb functions and socket etc.)
952335640Shselasky * we must call sock_init(). But we set various hooks to prevent
953335640Shselasky * using normal PKTDRVR functions in pcpkt.c. This should hopefully
954335640Shselasky * make Watt-32 and pcap co-operate.
955335640Shselasky */
956335640Shselaskystatic int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
957335640Shselasky{
958335640Shselasky  char *env;
959335640Shselasky  int   rc, MTU, has_ip_addr;
960335640Shselasky  int   using_pktdrv = 1;
961335640Shselasky
962335640Shselasky  /* If user called sock_init() first, we need to reinit in
963335640Shselasky   * order to open debug/trace-file properly
964335640Shselasky   */
965335640Shselasky  if (_watt_is_init)
966335640Shselasky     sock_exit();
967335640Shselasky
968335640Shselasky  env = getenv ("PCAP_TRACE");
969335640Shselasky  if (env && atoi(env) > 0 &&
970335640Shselasky      pcap_pkt_debug < 0)   /* if not already set */
971335640Shselasky  {
972335640Shselasky    dbug_init();
973335640Shselasky    pcap_pkt_debug = atoi (env);
974335640Shselasky  }
975335640Shselasky
976335640Shselasky  _watt_do_exit      = 0;    /* prevent sock_init() calling exit() */
977335640Shselasky  prev_post_hook     = _w32_usr_post_init;
978335640Shselasky  _w32_usr_post_init = pcap_init_hook;
979335640Shselasky  _w32_print_hook    = null_print;
980335640Shselasky
981335640Shselasky  if (dev_name && strncmp(dev_name,"pkt",3))
982335640Shselasky     using_pktdrv = FALSE;
983335640Shselasky
984335640Shselasky  rc = sock_init();
985335640Shselasky  has_ip_addr = (rc != 8);  /* IP-address assignment failed */
986335640Shselasky
987335640Shselasky  /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we
988335640Shselasky   * just pretend Watt-32 is initialised okay.
989335640Shselasky   *
990335640Shselasky   * !! fix-me: The Watt-32 config isn't done if no pktdrvr
991335640Shselasky   *            was found. In that case my_ip_addr + sin_mask
992335640Shselasky   *            have default values. Should be taken from another
993335640Shselasky   *            ini-file/environment in any case (ref. tcpdump.ini)
994335640Shselasky   */
995335640Shselasky  _watt_is_init = 1;
996335640Shselasky
997335640Shselasky  if (!using_pktdrv || !has_ip_addr)  /* for now .... */
998335640Shselasky  {
999335640Shselasky    static const char myip[] = "192.168.0.1";
1000335640Shselasky    static const char mask[] = "255.255.255.0";
1001335640Shselasky
1002335640Shselasky    printf ("Just guessing, using IP %s and netmask %s\n", myip, mask);
1003335640Shselasky    my_ip_addr    = aton (myip);
1004335640Shselasky    _w32_sin_mask = aton (mask);
1005335640Shselasky  }
1006335640Shselasky  else if (rc && using_pktdrv)
1007335640Shselasky  {
1008335640Shselasky    pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
1009335640Shselasky    return (0);
1010335640Shselasky  }
1011335640Shselasky
1012335640Shselasky  /* Set recv-hook for peeking in _eth_arrived().
1013335640Shselasky   */
1014335640Shselasky#if (WATTCP_VER >= 0x0224)
1015335640Shselasky  _eth_recv_hook = pcap_recv_hook;
1016335640Shselasky  _eth_xmit_hook = pcap_xmit_hook;
1017335640Shselasky#endif
1018335640Shselasky
1019335640Shselasky  /* Free the pkt-drvr handle allocated in pkt_init().
1020335640Shselasky   * The above hooks should thus use the handle reopened in open_driver()
1021335640Shselasky   */
1022335640Shselasky  if (using_pktdrv)
1023335640Shselasky  {
1024335640Shselasky    _eth_release();
1025335640Shselasky/*  _eth_is_init = 1; */  /* hack to get Rx/Tx-hooks in Watt-32 working */
1026335640Shselasky  }
1027335640Shselasky
1028335640Shselasky  memcpy (&pcap_save, pcap, sizeof(pcap_save));
1029335640Shselasky  MTU = pkt_get_mtu();
1030335640Shselasky  pcap_save.fcode.bf_insns = NULL;
1031335640Shselasky  pcap_save.linktype       = _eth_get_hwtype (NULL, NULL);
1032335640Shselasky  pcap_save.snapshot       = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
1033335640Shselasky
1034335640Shselasky#if 1
1035335640Shselasky  /* prevent use of resolve() and resolve_ip()
1036335640Shselasky   */
1037335640Shselasky  last_nameserver = 0;
1038335640Shselasky#endif
1039335640Shselasky  return (1);
1040335640Shselasky}
1041335640Shselasky
1042335640Shselaskyint EISA_bus = 0;  /* Where is natural place for this? */
1043335640Shselasky
1044335640Shselasky/*
1045335640Shselasky * Application config hooks to set various driver parameters.
1046335640Shselasky */
1047335640Shselasky
1048335640Shselaskystatic const struct config_table debug_tab[] = {
1049335640Shselasky            { "PKT.DEBUG",       ARG_ATOI,   &pcap_pkt_debug    },
1050335640Shselasky            { "PKT.VECTOR",      ARG_ATOX_W, NULL               },
1051335640Shselasky            { "NDIS.DEBUG",      ARG_ATOI,   NULL               },
1052335640Shselasky#ifdef USE_32BIT_DRIVERS
1053335640Shselasky            { "3C503.DEBUG",     ARG_ATOI,   &ei_debug          },
1054335640Shselasky            { "3C503.IO_BASE",   ARG_ATOX_W, &el2_dev.base_addr },
1055335640Shselasky            { "3C503.MEMORY",    ARG_ATOX_W, &el2_dev.mem_start },
1056335640Shselasky            { "3C503.IRQ",       ARG_ATOI,   &el2_dev.irq       },
1057335640Shselasky            { "3C505.DEBUG",     ARG_ATOI,   NULL               },
1058335640Shselasky            { "3C505.BASE",      ARG_ATOX_W, NULL               },
1059335640Shselasky            { "3C507.DEBUG",     ARG_ATOI,   NULL               },
1060335640Shselasky            { "3C509.DEBUG",     ARG_ATOI,   &el3_debug         },
1061335640Shselasky            { "3C509.ILOOP",     ARG_ATOI,   &el3_max_loop      },
1062335640Shselasky            { "3C529.DEBUG",     ARG_ATOI,   NULL               },
1063335640Shselasky            { "3C575.DEBUG",     ARG_ATOI,   &debug_3c575       },
1064335640Shselasky            { "3C59X.DEBUG",     ARG_ATOI,   &vortex_debug      },
1065335640Shselasky            { "3C59X.IFACE0",    ARG_ATOI,   &vortex_options[0] },
1066335640Shselasky            { "3C59X.IFACE1",    ARG_ATOI,   &vortex_options[1] },
1067335640Shselasky            { "3C59X.IFACE2",    ARG_ATOI,   &vortex_options[2] },
1068335640Shselasky            { "3C59X.IFACE3",    ARG_ATOI,   &vortex_options[3] },
1069335640Shselasky            { "3C90X.DEBUG",     ARG_ATOX_W, &tc90xbc_debug     },
1070335640Shselasky            { "ACCT.DEBUG",      ARG_ATOI,   &ethpk_debug       },
1071335640Shselasky            { "CS89.DEBUG",      ARG_ATOI,   &cs89_debug        },
1072335640Shselasky            { "RTL8139.DEBUG",   ARG_ATOI,   &rtl8139_debug     },
1073335640Shselasky        /*  { "RTL8139.FDUPLEX", ARG_ATOI,   &rtl8139_options   }, */
1074335640Shselasky            { "SMC.DEBUG",       ARG_ATOI,   &ei_debug          },
1075335640Shselasky        /*  { "E100.DEBUG",      ARG_ATOI,   &e100_debug        }, */
1076335640Shselasky            { "PCI.DEBUG",       ARG_ATOI,   &pci_debug         },
1077335640Shselasky            { "BIOS32.DEBUG",    ARG_ATOI,   &bios32_debug      },
1078335640Shselasky            { "IRQ.DEBUG",       ARG_ATOI,   &irq_debug         },
1079335640Shselasky            { "TIMER.IRQ",       ARG_ATOI,   &timer_irq         },
1080335640Shselasky#endif
1081335640Shselasky            { NULL }
1082335640Shselasky          };
1083335640Shselasky
1084335640Shselasky/*
1085335640Shselasky * pcap_config_hook() is an extension to application's config
1086335640Shselasky * handling. Uses Watt-32's config-table function.
1087335640Shselasky */
1088335640Shselaskyint pcap_config_hook (const char *keyword, const char *value)
1089335640Shselasky{
1090335640Shselasky  return parse_config_table (debug_tab, NULL, keyword, value);
1091335640Shselasky}
1092335640Shselasky
1093335640Shselasky/*
1094335640Shselasky * Linked list of supported devices
1095335640Shselasky */
1096335640Shselaskystruct device       *active_dev = NULL;      /* the device we have opened */
1097335640Shselaskystruct device       *probed_dev = NULL;      /* the device we have probed */
1098335640Shselaskyconst struct device *dev_base   = &pkt_dev;  /* list of network devices */
1099335640Shselasky
1100335640Shselasky/*
1101335640Shselasky * PKTDRVR device functions
1102335640Shselasky */
1103335640Shselaskyint pcap_pkt_debug = -1;
1104335640Shselasky
1105335640Shselaskystatic void pkt_close (struct device *dev)
1106335640Shselasky{
1107335640Shselasky  BOOL okay = PktExitDriver();
1108335640Shselasky
1109335640Shselasky  if (pcap_pkt_debug > 1)
1110335640Shselasky     fprintf (stderr, "pkt_close(): %d\n", okay);
1111335640Shselasky
1112335640Shselasky  if (dev->priv)
1113335640Shselasky     free (dev->priv);
1114335640Shselasky  dev->priv = NULL;
1115335640Shselasky}
1116335640Shselasky
1117335640Shselaskystatic int pkt_open (struct device *dev)
1118335640Shselasky{
1119335640Shselasky  PKT_RX_MODE mode;
1120335640Shselasky
1121335640Shselasky  if (dev->flags & IFF_PROMISC)
1122335640Shselasky       mode = PDRX_ALL_PACKETS;
1123335640Shselasky  else mode = PDRX_BROADCAST;
1124335640Shselasky
1125335640Shselasky  if (!PktInitDriver(mode))
1126335640Shselasky     return (0);
1127335640Shselasky
1128335640Shselasky  PktResetStatistics (pktInfo.handle);
1129335640Shselasky  PktQueueBusy (FALSE);
1130335640Shselasky  return (1);
1131335640Shselasky}
1132335640Shselasky
1133335640Shselaskystatic int pkt_xmit (struct device *dev, const void *buf, int len)
1134335640Shselasky{
1135335640Shselasky  struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1136335640Shselasky
1137335640Shselasky  if (pcap_pkt_debug > 0)
1138335640Shselasky     dbug_write ("pcap_xmit\n");
1139335640Shselasky
1140335640Shselasky  if (!PktTransmit(buf,len))
1141335640Shselasky  {
1142335640Shselasky    stats->tx_errors++;
1143335640Shselasky    return (0);
1144335640Shselasky  }
1145335640Shselasky  return (len);
1146335640Shselasky}
1147335640Shselasky
1148335640Shselaskystatic void *pkt_stats (struct device *dev)
1149335640Shselasky{
1150335640Shselasky  struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1151335640Shselasky
1152335640Shselasky  if (!stats || !PktSessStatistics(pktInfo.handle))
1153335640Shselasky     return (NULL);
1154335640Shselasky
1155335640Shselasky  stats->rx_packets       = pktStat.inPackets;
1156335640Shselasky  stats->rx_errors        = pktStat.lost;
1157335640Shselasky  stats->rx_missed_errors = PktRxDropped();
1158335640Shselasky  return (stats);
1159335640Shselasky}
1160335640Shselasky
1161335640Shselaskystatic int pkt_probe (struct device *dev)
1162335640Shselasky{
1163335640Shselasky  if (!PktSearchDriver())
1164335640Shselasky     return (0);
1165335640Shselasky
1166335640Shselasky  dev->open           = pkt_open;
1167335640Shselasky  dev->xmit           = pkt_xmit;
1168335640Shselasky  dev->close          = pkt_close;
1169335640Shselasky  dev->get_stats      = pkt_stats;
1170335640Shselasky  dev->copy_rx_buf    = PktReceive;  /* farmem peek and copy routine */
1171335640Shselasky  dev->get_rx_buf     = NULL;
1172335640Shselasky  dev->peek_rx_buf    = NULL;
1173335640Shselasky  dev->release_rx_buf = NULL;
1174335640Shselasky  dev->priv           = calloc (sizeof(struct net_device_stats), 1);
1175335640Shselasky  if (!dev->priv)
1176335640Shselasky     return (0);
1177335640Shselasky  return (1);
1178335640Shselasky}
1179335640Shselasky
1180335640Shselasky/*
1181335640Shselasky * NDIS device functions
1182335640Shselasky */
1183335640Shselaskystatic void ndis_close (struct device *dev)
1184335640Shselasky{
1185335640Shselasky#ifdef USE_NDIS2
1186335640Shselasky  NdisShutdown();
1187335640Shselasky#endif
1188335640Shselasky  ARGSUSED (dev);
1189335640Shselasky}
1190335640Shselasky
1191335640Shselaskystatic int ndis_open (struct device *dev)
1192335640Shselasky{
1193335640Shselasky  int promis = (dev->flags & IFF_PROMISC);
1194335640Shselasky
1195335640Shselasky#ifdef USE_NDIS2
1196335640Shselasky  if (!NdisInit(promis))
1197335640Shselasky     return (0);
1198335640Shselasky  return (1);
1199335640Shselasky#else
1200335640Shselasky  ARGSUSED (promis);
1201335640Shselasky  return (0);
1202335640Shselasky#endif
1203335640Shselasky}
1204335640Shselasky
1205335640Shselaskystatic void *ndis_stats (struct device *dev)
1206335640Shselasky{
1207335640Shselasky  static struct net_device_stats stats;
1208335640Shselasky
1209335640Shselasky  /* to-do */
1210335640Shselasky  ARGSUSED (dev);
1211335640Shselasky  return (&stats);
1212335640Shselasky}
1213335640Shselasky
1214335640Shselaskystatic int ndis_probe (struct device *dev)
1215335640Shselasky{
1216335640Shselasky#ifdef USE_NDIS2
1217335640Shselasky  if (!NdisOpen())
1218335640Shselasky     return (0);
1219335640Shselasky#endif
1220335640Shselasky
1221335640Shselasky  dev->open           = ndis_open;
1222335640Shselasky  dev->xmit           = NULL;
1223335640Shselasky  dev->close          = ndis_close;
1224335640Shselasky  dev->get_stats      = ndis_stats;
1225335640Shselasky  dev->copy_rx_buf    = NULL;       /* to-do */
1226335640Shselasky  dev->get_rx_buf     = NULL;       /* upcall is from rmode driver */
1227335640Shselasky  dev->peek_rx_buf    = NULL;
1228335640Shselasky  dev->release_rx_buf = NULL;
1229335640Shselasky  return (0);
1230335640Shselasky}
1231335640Shselasky
1232335640Shselasky/*
1233335640Shselasky * Search & probe for supported 32-bit (pmode) pcap devices
1234335640Shselasky */
1235335640Shselasky#if defined(USE_32BIT_DRIVERS)
1236335640Shselasky
1237335640Shselaskystruct device el2_dev LOCKED_VAR = {
1238335640Shselasky              "3c503",
1239335640Shselasky              "EtherLink II",
1240335640Shselasky              0,
1241335640Shselasky              0,0,0,0,0,0,
1242335640Shselasky              NULL,
1243335640Shselasky              el2_probe
1244335640Shselasky            };
1245335640Shselasky
1246335640Shselaskystruct device el3_dev LOCKED_VAR = {
1247335640Shselasky              "3c509",
1248335640Shselasky              "EtherLink III",
1249335640Shselasky              0,
1250335640Shselasky              0,0,0,0,0,0,
1251335640Shselasky              &el2_dev,
1252335640Shselasky              el3_probe
1253335640Shselasky            };
1254335640Shselasky
1255335640Shselaskystruct device tc515_dev LOCKED_VAR = {
1256335640Shselasky              "3c515",
1257335640Shselasky              "EtherLink PCI",
1258335640Shselasky              0,
1259335640Shselasky              0,0,0,0,0,0,
1260335640Shselasky              &el3_dev,
1261335640Shselasky              tc515_probe
1262335640Shselasky            };
1263335640Shselasky
1264335640Shselaskystruct device tc59_dev LOCKED_VAR = {
1265335640Shselasky              "3c59x",
1266335640Shselasky              "EtherLink PCI",
1267335640Shselasky              0,
1268335640Shselasky              0,0,0,0,0,0,
1269335640Shselasky              &tc515_dev,
1270335640Shselasky              tc59x_probe
1271335640Shselasky            };
1272335640Shselasky
1273335640Shselaskystruct device tc90xbc_dev LOCKED_VAR = {
1274335640Shselasky              "3c90x",
1275335640Shselasky              "EtherLink 90X",
1276335640Shselasky              0,
1277335640Shselasky              0,0,0,0,0,0,
1278335640Shselasky              &tc59_dev,
1279335640Shselasky              tc90xbc_probe
1280335640Shselasky            };
1281335640Shselasky
1282335640Shselaskystruct device wd_dev LOCKED_VAR = {
1283335640Shselasky              "wd",
1284335640Shselasky              "Westen Digital",
1285335640Shselasky              0,
1286335640Shselasky              0,0,0,0,0,0,
1287335640Shselasky              &tc90xbc_dev,
1288335640Shselasky              wd_probe
1289335640Shselasky            };
1290335640Shselasky
1291335640Shselaskystruct device ne_dev LOCKED_VAR = {
1292335640Shselasky              "ne",
1293335640Shselasky              "NEx000",
1294335640Shselasky              0,
1295335640Shselasky              0,0,0,0,0,0,
1296335640Shselasky              &wd_dev,
1297335640Shselasky              ne_probe
1298335640Shselasky            };
1299335640Shselasky
1300335640Shselaskystruct device acct_dev LOCKED_VAR = {
1301335640Shselasky              "acct",
1302335640Shselasky              "Accton EtherPocket",
1303335640Shselasky              0,
1304335640Shselasky              0,0,0,0,0,0,
1305335640Shselasky              &ne_dev,
1306335640Shselasky              ethpk_probe
1307335640Shselasky            };
1308335640Shselasky
1309335640Shselaskystruct device cs89_dev LOCKED_VAR = {
1310335640Shselasky              "cs89",
1311335640Shselasky              "Crystal Semiconductor",
1312335640Shselasky              0,
1313335640Shselasky              0,0,0,0,0,0,
1314335640Shselasky              &acct_dev,
1315335640Shselasky              cs89x0_probe
1316335640Shselasky            };
1317335640Shselasky
1318335640Shselaskystruct device rtl8139_dev LOCKED_VAR = {
1319335640Shselasky              "rtl8139",
1320335640Shselasky              "RealTek PCI",
1321335640Shselasky              0,
1322335640Shselasky              0,0,0,0,0,0,
1323335640Shselasky              &cs89_dev,
1324335640Shselasky              rtl8139_probe     /* dev->probe routine */
1325335640Shselasky            };
1326335640Shselasky
1327335640Shselasky/*
1328335640Shselasky * Dequeue routine is called by polling.
1329335640Shselasky * NOTE: the queue-element is not copied, only a pointer is
1330335640Shselasky * returned at '*buf'
1331335640Shselasky */
1332335640Shselaskyint peek_rxbuf (BYTE **buf)
1333335640Shselasky{
1334335640Shselasky  struct rx_elem *tail, *head;
1335335640Shselasky
1336335640Shselasky  PCAP_ASSERT (pktq_check (&active_dev->queue));
1337335640Shselasky
1338335640Shselasky  DISABLE();
1339335640Shselasky  tail = pktq_out_elem (&active_dev->queue);
1340335640Shselasky  head = pktq_in_elem (&active_dev->queue);
1341335640Shselasky  ENABLE();
1342335640Shselasky
1343335640Shselasky  if (head != tail)
1344335640Shselasky  {
1345335640Shselasky    PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2);
1346335640Shselasky
1347335640Shselasky    *buf = &tail->data[0];
1348335640Shselasky    return (tail->size);
1349335640Shselasky  }
1350335640Shselasky  *buf = NULL;
1351335640Shselasky  return (0);
1352335640Shselasky}
1353335640Shselasky
1354335640Shselasky/*
1355335640Shselasky * Release buffer we peeked at above.
1356335640Shselasky */
1357335640Shselaskyint release_rxbuf (BYTE *buf)
1358335640Shselasky{
1359335640Shselasky#ifndef NDEBUG
1360335640Shselasky  struct rx_elem *tail = pktq_out_elem (&active_dev->queue);
1361335640Shselasky
1362335640Shselasky  PCAP_ASSERT (&tail->data[0] == buf);
1363335640Shselasky#else
1364335640Shselasky  ARGSUSED (buf);
1365335640Shselasky#endif
1366335640Shselasky  pktq_inc_out (&active_dev->queue);
1367335640Shselasky  return (1);
1368335640Shselasky}
1369335640Shselasky
1370335640Shselasky/*
1371335640Shselasky * get_rxbuf() routine (in locked code) is called from IRQ handler
1372335640Shselasky * to request a buffer. Interrupts are disabled and we have a 32kB stack.
1373335640Shselasky */
1374335640ShselaskyBYTE *get_rxbuf (int len)
1375335640Shselasky{
1376335640Shselasky  int idx;
1377335640Shselasky
1378335640Shselasky  if (len < ETH_MIN || len > ETH_MAX)
1379335640Shselasky     return (NULL);
1380335640Shselasky
1381335640Shselasky  idx = pktq_in_index (&active_dev->queue);
1382335640Shselasky
1383335640Shselasky#ifdef DEBUG
1384335640Shselasky  {
1385335640Shselasky    static int fan_idx LOCKED_VAR = 0;
1386335640Shselasky    writew ("-\\|/"[fan_idx++] | (15 << 8),      /* white on black colour */
1387335640Shselasky            0xB8000 + 2*79);  /* upper-right corner, 80-col colour screen */
1388335640Shselasky    fan_idx &= 3;
1389335640Shselasky  }
1390335640Shselasky/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */
1391335640Shselasky#endif
1392335640Shselasky
1393335640Shselasky  if (idx != active_dev->queue.out_index)
1394335640Shselasky  {
1395335640Shselasky    struct rx_elem *head = pktq_in_elem (&active_dev->queue);
1396335640Shselasky
1397335640Shselasky    head->size = len;
1398335640Shselasky    active_dev->queue.in_index = idx;
1399335640Shselasky    return (&head->data[0]);
1400335640Shselasky  }
1401335640Shselasky
1402335640Shselasky  /* !!to-do: drop 25% of the oldest element
1403335640Shselasky   */
1404335640Shselasky  pktq_clear (&active_dev->queue);
1405335640Shselasky  return (NULL);
1406335640Shselasky}
1407335640Shselasky
1408335640Shselasky/*
1409335640Shselasky *  Simple ring-buffer queue handler for reception of packets
1410335640Shselasky *  from network driver.
1411335640Shselasky */
1412335640Shselasky#define PKTQ_MARKER  0xDEADBEEF
1413335640Shselasky
1414335640Shselaskystatic int pktq_check (struct rx_ringbuf *q)
1415335640Shselasky{
1416335640Shselasky#ifndef NDEBUG
1417335640Shselasky  int   i;
1418335640Shselasky  char *buf;
1419335640Shselasky#endif
1420335640Shselasky
1421335640Shselasky  if (!q || !q->num_elem || !q->buf_start)
1422335640Shselasky     return (0);
1423335640Shselasky
1424335640Shselasky#ifndef NDEBUG
1425335640Shselasky  buf = q->buf_start;
1426335640Shselasky
1427335640Shselasky  for (i = 0; i < q->num_elem; i++)
1428335640Shselasky  {
1429335640Shselasky    buf += q->elem_size;
1430335640Shselasky    if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER)
1431335640Shselasky       return (0);
1432335640Shselasky  }
1433335640Shselasky#endif
1434335640Shselasky  return (1);
1435335640Shselasky}
1436335640Shselasky
1437335640Shselaskystatic int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool)
1438335640Shselasky{
1439335640Shselasky  int i;
1440335640Shselasky
1441335640Shselasky  q->elem_size = size;
1442335640Shselasky  q->num_elem  = num;
1443335640Shselasky  q->buf_start = pool;
1444335640Shselasky  q->in_index  = 0;
1445335640Shselasky  q->out_index = 0;
1446335640Shselasky
1447335640Shselasky  PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD));
1448335640Shselasky  PCAP_ASSERT (num);
1449335640Shselasky  PCAP_ASSERT (pool);
1450335640Shselasky
1451335640Shselasky  for (i = 0; i < num; i++)
1452335640Shselasky  {
1453335640Shselasky#if 0
1454335640Shselasky    struct rx_elem *elem = (struct rx_elem*) pool;
1455335640Shselasky
1456335640Shselasky    /* assert dword aligned elements
1457335640Shselasky     */
1458335640Shselasky    PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0);
1459335640Shselasky#endif
1460335640Shselasky    pool += size;
1461335640Shselasky    *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER;
1462335640Shselasky  }
1463335640Shselasky  return (1);
1464335640Shselasky}
1465335640Shselasky
1466335640Shselasky/*
1467335640Shselasky * Increment the queue 'out_index' (tail).
1468335640Shselasky * Check for wraps.
1469335640Shselasky */
1470335640Shselaskystatic int pktq_inc_out (struct rx_ringbuf *q)
1471335640Shselasky{
1472335640Shselasky  q->out_index++;
1473335640Shselasky  if (q->out_index >= q->num_elem)
1474335640Shselasky      q->out_index = 0;
1475335640Shselasky  return (q->out_index);
1476335640Shselasky}
1477335640Shselasky
1478335640Shselasky/*
1479335640Shselasky * Return the queue's next 'in_index' (head).
1480335640Shselasky * Check for wraps.
1481335640Shselasky */
1482335640Shselaskystatic int pktq_in_index (struct rx_ringbuf *q)
1483335640Shselasky{
1484335640Shselasky  volatile int index = q->in_index + 1;
1485335640Shselasky
1486335640Shselasky  if (index >= q->num_elem)
1487335640Shselasky      index = 0;
1488335640Shselasky  return (index);
1489335640Shselasky}
1490335640Shselasky
1491335640Shselasky/*
1492335640Shselasky * Return the queue's head-buffer.
1493335640Shselasky */
1494335640Shselaskystatic struct rx_elem *pktq_in_elem (struct rx_ringbuf *q)
1495335640Shselasky{
1496335640Shselasky  return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index));
1497335640Shselasky}
1498335640Shselasky
1499335640Shselasky/*
1500335640Shselasky * Return the queue's tail-buffer.
1501335640Shselasky */
1502335640Shselaskystatic struct rx_elem *pktq_out_elem (struct rx_ringbuf *q)
1503335640Shselasky{
1504335640Shselasky  return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index));
1505335640Shselasky}
1506335640Shselasky
1507335640Shselasky/*
1508335640Shselasky * Clear the queue ring-buffer by setting head=tail.
1509335640Shselasky */
1510335640Shselaskystatic void pktq_clear (struct rx_ringbuf *q)
1511335640Shselasky{
1512335640Shselasky  q->in_index = q->out_index;
1513335640Shselasky}
1514335640Shselasky
1515335640Shselasky/*
1516335640Shselasky * Symbols that must be linkable for "gcc -O0"
1517335640Shselasky */
1518335640Shselasky#undef __IOPORT_H
1519335640Shselasky#undef __DMA_H
1520335640Shselasky
1521335640Shselasky#define extern
1522335640Shselasky#define __inline__
1523335640Shselasky
1524335640Shselasky#include "msdos/pm_drvr/ioport.h"
1525335640Shselasky#include "msdos/pm_drvr/dma.h"
1526335640Shselasky
1527335640Shselasky#endif /* USE_32BIT_DRIVERS */
1528335640Shselasky
1529335640Shselasky/*
1530335640Shselasky * Libpcap version string.
1531335640Shselasky */
1532335640Shselaskyconst char *
1533335640Shselaskypcap_lib_version(void)
1534335640Shselasky{
1535335640Shselasky  return ("DOS-" PCAP_VERSION_STRING);
1536335640Shselasky}
1537