1146768Ssam/*
2146768Ssam *  This file is part of DOS-libpcap
3190225Srpaulo *  Ported to DOS/DOSX by G. Vanem <gvanem@broadpark.no>
4146768Ssam *
5146768Ssam *  pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode
6146768Ssam *              network drivers.
7146768Ssam */
8146768Ssam
9146768Ssam#include <stdio.h>
10146768Ssam#include <stdlib.h>
11146768Ssam#include <string.h>
12146768Ssam#include <signal.h>
13146768Ssam#include <float.h>
14146768Ssam#include <fcntl.h>
15146768Ssam#include <io.h>
16146768Ssam
17146768Ssam#if defined(USE_32BIT_DRIVERS)
18146768Ssam  #include "msdos/pm_drvr/pmdrvr.h"
19146768Ssam  #include "msdos/pm_drvr/pci.h"
20146768Ssam  #include "msdos/pm_drvr/bios32.h"
21146768Ssam  #include "msdos/pm_drvr/module.h"
22146768Ssam  #include "msdos/pm_drvr/3c501.h"
23146768Ssam  #include "msdos/pm_drvr/3c503.h"
24146768Ssam  #include "msdos/pm_drvr/3c509.h"
25146768Ssam  #include "msdos/pm_drvr/3c59x.h"
26146768Ssam  #include "msdos/pm_drvr/3c515.h"
27146768Ssam  #include "msdos/pm_drvr/3c90x.h"
28146768Ssam  #include "msdos/pm_drvr/3c575_cb.h"
29146768Ssam  #include "msdos/pm_drvr/ne.h"
30146768Ssam  #include "msdos/pm_drvr/wd.h"
31146768Ssam  #include "msdos/pm_drvr/accton.h"
32146768Ssam  #include "msdos/pm_drvr/cs89x0.h"
33146768Ssam  #include "msdos/pm_drvr/rtl8139.h"
34146768Ssam  #include "msdos/pm_drvr/ne2k-pci.h"
35146768Ssam#endif
36146768Ssam
37146768Ssam#include "pcap.h"
38146768Ssam#include "pcap-dos.h"
39146768Ssam#include "pcap-int.h"
40146768Ssam#include "msdos/pktdrvr.h"
41146768Ssam
42146768Ssam#ifdef USE_NDIS2
43146768Ssam#include "msdos/ndis2.h"
44146768Ssam#endif
45146768Ssam
46146768Ssam#include <arpa/inet.h>
47146768Ssam#include <net/if.h>
48146768Ssam#include <net/if_arp.h>
49146768Ssam#include <net/if_ether.h>
50146768Ssam#include <net/if_packe.h>
51146768Ssam#include <tcp.h>
52146768Ssam
53146768Ssam#if defined(USE_32BIT_DRIVERS)
54146768Ssam  #define FLUSHK()       do { _printk_safe = 1; _printk_flush(); } while (0)
55146768Ssam  #define NDIS_NEXT_DEV  &rtl8139_dev
56146768Ssam
57146768Ssam  static char *rx_pool = NULL;
58146768Ssam  static void init_32bit (void);
59146768Ssam
60146768Ssam  static int  pktq_init     (struct rx_ringbuf *q, int size, int num, char *pool);
61146768Ssam  static int  pktq_check    (struct rx_ringbuf *q);
62146768Ssam  static int  pktq_inc_out  (struct rx_ringbuf *q);
63146768Ssam  static int  pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC;
64146768Ssam  static void pktq_clear    (struct rx_ringbuf *q) LOCKED_FUNC;
65146768Ssam
66146768Ssam  static struct rx_elem *pktq_in_elem  (struct rx_ringbuf *q) LOCKED_FUNC;
67146768Ssam  static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q);
68146768Ssam
69146768Ssam#else
70146768Ssam  #define FLUSHK()      ((void)0)
71146768Ssam  #define NDIS_NEXT_DEV  NULL
72146768Ssam#endif
73146768Ssam
74146768Ssam/*
75146768Ssam * Internal variables/functions in Watt-32
76146768Ssam */
77146768Ssamextern WORD  _pktdevclass;
78146768Ssamextern BOOL  _eth_is_init;
79146768Ssamextern int   _w32_dynamic_host;
80146768Ssamextern int   _watt_do_exit;
81146768Ssamextern int   _watt_is_init;
82146768Ssamextern int   _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req;
83146768Ssamextern void (*_w32_usr_post_init) (void);
84146768Ssamextern void (*_w32_print_hook)();
85146768Ssam
86146768Ssamextern void dbug_write (const char *);  /* Watt-32 lib, pcdbug.c */
87146768Ssamextern int  pkt_get_mtu (void);
88146768Ssam
89146768Ssamstatic int ref_count = 0;
90146768Ssam
91146768Ssamstatic u_long mac_count    = 0;
92146768Ssamstatic u_long filter_count = 0;
93146768Ssam
94146768Ssamstatic volatile BOOL exc_occured = 0;
95146768Ssam
96146768Ssamstatic struct device *handle_to_device [20];
97146768Ssam
98190225Srpaulostatic int  pcap_activate_dos (pcap_t *p);
99146768Ssamstatic int  pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback,
100146768Ssam                           u_char *data);
101190225Srpaulostatic void pcap_cleanup_dos (pcap_t *p);
102146768Ssamstatic int  pcap_stats_dos (pcap_t *p, struct pcap_stat *ps);
103146768Ssamstatic int  pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len);
104146768Ssamstatic int  pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp);
105146768Ssam
106146768Ssamstatic int  ndis_probe (struct device *dev);
107146768Ssamstatic int  pkt_probe  (struct device *dev);
108146768Ssam
109146768Ssamstatic void close_driver (void);
110146768Ssamstatic int  init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf);
111146768Ssamstatic int  first_init (const char *name, char *ebuf, int promisc);
112146768Ssam
113146768Ssamstatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
114146768Ssam                              const u_char *buf);
115146768Ssam
116146768Ssam/*
117146768Ssam * These are the device we always support
118146768Ssam */
119146768Ssamstatic struct device ndis_dev = {
120146768Ssam              "ndis",
121146768Ssam              "NDIS2 LanManager",
122146768Ssam              0,
123146768Ssam              0,0,0,0,0,0,
124146768Ssam              NDIS_NEXT_DEV,  /* NULL or a 32-bit device */
125146768Ssam              ndis_probe
126146768Ssam            };
127146768Ssam
128146768Ssamstatic struct device pkt_dev = {
129146768Ssam              "pkt",
130146768Ssam              "Packet-Driver",
131146768Ssam              0,
132146768Ssam              0,0,0,0,0,0,
133146768Ssam              &ndis_dev,
134146768Ssam              pkt_probe
135146768Ssam            };
136146768Ssam
137146768Ssamstatic struct device *get_device (int fd)
138146768Ssam{
139146768Ssam  if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0]))
140146768Ssam     return (NULL);
141146768Ssam  return handle_to_device [fd-1];
142146768Ssam}
143146768Ssam
144276768Sdelphij/*
145276768Sdelphij * Private data for capturing on MS-DOS.
146276768Sdelphij */
147276768Sdelphijstruct pcap_dos {
148276768Sdelphij	void (*wait_proc)(void); /*          call proc while waiting */
149276768Sdelphij	struct pcap_stat stat;
150276768Sdelphij};
151276768Sdelphij
152276768Sdelphijpcap_t *pcap_create_interface (const char *device, char *ebuf)
153190225Srpaulo{
154190225Srpaulo	pcap_t *p;
155190225Srpaulo
156276768Sdelphij	p = pcap_create_common(device, ebuf, sizeof (struct pcap_dos));
157190225Srpaulo	if (p == NULL)
158190225Srpaulo		return (NULL);
159190225Srpaulo
160190225Srpaulo	p->activate_op = pcap_activate_dos;
161190225Srpaulo	return (p);
162190225Srpaulo}
163190225Srpaulo
164146768Ssam/*
165146768Ssam * Open MAC-driver with name 'device_name' for live capture of
166146768Ssam * network packets.
167146768Ssam */
168190225Srpaulostatic int pcap_activate_dos (pcap_t *pcap)
169146768Ssam{
170276768Sdelphij  struct pcap_dos *pcapd = pcap->priv;
171276768Sdelphij
172190225Srpaulo  if (pcap->opt.rfmon) {
173190225Srpaulo    /*
174190225Srpaulo     * No monitor mode on DOS.
175190225Srpaulo     */
176190225Srpaulo    return (PCAP_ERROR_RFMON_NOTSUP);
177190225Srpaulo  }
178146768Ssam
179190225Srpaulo  if (pcap->snapshot < ETH_MIN+8)
180190225Srpaulo      pcap->snapshot = ETH_MIN+8;
181146768Ssam
182190225Srpaulo  if (pcap->snapshot > ETH_MAX)   /* silently accept and truncate large MTUs */
183190225Srpaulo      pcap->snapshot = ETH_MAX;
184146768Ssam
185146768Ssam  pcap->linktype          = DLT_EN10MB;  /* !! */
186190225Srpaulo  pcap->cleanup_op        = pcap_cleanup_dos;
187146768Ssam  pcap->read_op           = pcap_read_dos;
188146768Ssam  pcap->stats_op          = pcap_stats_dos;
189146768Ssam  pcap->inject_op         = pcap_sendpacket_dos;
190146768Ssam  pcap->setfilter_op      = pcap_setfilter_dos;
191190225Srpaulo  pcap->setdirection_op   = NULL; /* Not implemented.*/
192146768Ssam  pcap->fd                = ++ref_count;
193146768Ssam
194146768Ssam  if (pcap->fd == 1)  /* first time we're called */
195146768Ssam  {
196190225Srpaulo    if (!init_watt32(pcap, pcap->opt.source, pcap->errbuf) ||
197190225Srpaulo        !first_init(pcap->opt.source, pcap->errbuf, pcap->opt.promisc))
198146768Ssam    {
199190225Srpaulo      return (PCAP_ERROR);
200146768Ssam    }
201146768Ssam    atexit (close_driver);
202146768Ssam  }
203190225Srpaulo  else if (stricmp(active_dev->name,pcap->opt.source))
204146768Ssam  {
205190225Srpaulo    snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
206146768Ssam              "Cannot use different devices simultaneously "
207190225Srpaulo              "(`%s' vs. `%s')", active_dev->name, pcap->opt.source);
208190225Srpaulo    return (PCAP_ERROR);
209146768Ssam  }
210146768Ssam  handle_to_device [pcap->fd-1] = active_dev;
211190225Srpaulo  return (0);
212146768Ssam}
213146768Ssam
214146768Ssam/*
215146768Ssam * Poll the receiver queue and call the pcap callback-handler
216146768Ssam * with the packet.
217146768Ssam */
218146768Ssamstatic int
219146768Ssampcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
220146768Ssam{
221276768Sdelphij  struct pcap_dos *pd = p->priv;
222146768Ssam  struct pcap_pkthdr pcap;
223276768Sdelphij  struct timeval     now, expiry = { 0,0 };
224146768Ssam  BYTE  *rx_buf;
225146768Ssam  int    rx_len = 0;
226146768Ssam
227276768Sdelphij  if (p->opt.timeout > 0)
228146768Ssam  {
229146768Ssam    gettimeofday2 (&now, NULL);
230276768Sdelphij    expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout;
231146768Ssam    expiry.tv_sec  = now.tv_sec;
232146768Ssam    while (expiry.tv_usec >= 1000000L)
233146768Ssam    {
234146768Ssam      expiry.tv_usec -= 1000000L;
235146768Ssam      expiry.tv_sec++;
236146768Ssam    }
237146768Ssam  }
238146768Ssam
239146768Ssam  while (!exc_occured)
240146768Ssam  {
241146768Ssam    volatile struct device *dev; /* might be reset by sig_handler */
242146768Ssam
243146768Ssam    dev = get_device (p->fd);
244146768Ssam    if (!dev)
245146768Ssam       break;
246146768Ssam
247146768Ssam    PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf);
248146768Ssam    FLUSHK();
249146768Ssam
250146768Ssam    /* If driver has a zero-copy receive facility, peek at the queue,
251146768Ssam     * filter it, do the callback and release the buffer.
252146768Ssam     */
253146768Ssam    if (dev->peek_rx_buf)
254146768Ssam    {
255146768Ssam      PCAP_ASSERT (dev->release_rx_buf);
256146768Ssam      rx_len = (*dev->peek_rx_buf) (&rx_buf);
257146768Ssam    }
258146768Ssam    else
259146768Ssam    {
260146768Ssam      BYTE buf [ETH_MAX+100]; /* add some margin */
261146768Ssam      rx_len = (*dev->copy_rx_buf) (buf, p->snapshot);
262146768Ssam      rx_buf = buf;
263146768Ssam    }
264146768Ssam
265146768Ssam    if (rx_len > 0)  /* got a packet */
266146768Ssam    {
267146768Ssam      mac_count++;
268146768Ssam
269146768Ssam      FLUSHK();
270146768Ssam
271146768Ssam      pcap.caplen = min (rx_len, p->snapshot);
272146768Ssam      pcap.len    = rx_len;
273146768Ssam
274146768Ssam      if (callback &&
275190225Srpaulo          (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, rx_buf, pcap.len, pcap.caplen)))
276146768Ssam      {
277146768Ssam        filter_count++;
278146768Ssam
279146768Ssam        /* Fix-me!! Should be time of arrival. Not time of
280146768Ssam         * capture.
281146768Ssam         */
282146768Ssam        gettimeofday2 (&pcap.ts, NULL);
283146768Ssam        (*callback) (data, &pcap, rx_buf);
284146768Ssam      }
285146768Ssam
286146768Ssam      if (dev->release_rx_buf)
287146768Ssam        (*dev->release_rx_buf) (rx_buf);
288146768Ssam
289146768Ssam      if (pcap_pkt_debug > 0)
290146768Ssam      {
291146768Ssam        if (callback == watt32_recv_hook)
292146768Ssam             dbug_write ("pcap_recv_hook\n");
293146768Ssam        else dbug_write ("pcap_read_op\n");
294146768Ssam      }
295146768Ssam      FLUSHK();
296146768Ssam      return (1);
297146768Ssam    }
298146768Ssam
299276768Sdelphij    /* If not to wait for a packet or pcap_cleanup_dos() called from
300146768Ssam     * e.g. SIGINT handler, exit loop now.
301146768Ssam     */
302276768Sdelphij    if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0)
303146768Ssam       break;
304146768Ssam
305146768Ssam    gettimeofday2 (&now, NULL);
306146768Ssam
307146768Ssam    if (timercmp(&now, &expiry, >))
308146768Ssam       break;
309146768Ssam
310146768Ssam#ifndef DJGPP
311146768Ssam    kbhit();    /* a real CPU hog */
312146768Ssam#endif
313146768Ssam
314146768Ssam    if (p->wait_proc)
315146768Ssam      (*p->wait_proc)();     /* call yield func */
316146768Ssam  }
317146768Ssam
318146768Ssam  if (rx_len < 0)            /* receive error */
319146768Ssam  {
320276768Sdelphij    pd->stat.ps_drop++;
321146768Ssam#ifdef USE_32BIT_DRIVERS
322146768Ssam    if (pcap_pkt_debug > 1)
323146768Ssam       printk ("pkt-err %s\n", pktInfo.error);
324146768Ssam#endif
325146768Ssam    return (-1);
326146768Ssam  }
327146768Ssam  return (0);
328146768Ssam}
329146768Ssam
330146768Ssamstatic int
331146768Ssampcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data)
332146768Ssam{
333276768Sdelphij  struct pcap_dos *pd = p->priv;
334146768Ssam  int rc, num = 0;
335146768Ssam
336276768Sdelphij  while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt))
337146768Ssam  {
338146768Ssam    if (p->fd <= 0)
339146768Ssam       return (-1);
340146768Ssam    rc = pcap_read_one (p, callback, data);
341146768Ssam    if (rc > 0)
342146768Ssam       num++;
343146768Ssam    if (rc < 0)
344146768Ssam       break;
345146768Ssam    _w32_os_yield();  /* allow SIGINT generation, yield to Win95/NT */
346146768Ssam  }
347146768Ssam  return (num);
348146768Ssam}
349146768Ssam
350146768Ssam/*
351146768Ssam * Return network statistics
352146768Ssam */
353146768Ssamstatic int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps)
354146768Ssam{
355146768Ssam  struct net_device_stats *stats;
356276768Sdelphij  struct pcap_dos         *pd;
357146768Ssam  struct device           *dev = p ? get_device(p->fd) : NULL;
358146768Ssam
359146768Ssam  if (!dev)
360146768Ssam  {
361146768Ssam    strcpy (p->errbuf, "illegal pcap handle");
362146768Ssam    return (-1);
363146768Ssam  }
364146768Ssam
365146768Ssam  if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL)
366146768Ssam  {
367146768Ssam    strcpy (p->errbuf, "device statistics not available");
368146768Ssam    return (-1);
369146768Ssam  }
370146768Ssam
371146768Ssam  FLUSHK();
372146768Ssam
373276768Sdelphij  pd = p->priv;
374276768Sdelphij  pd->stat.ps_recv   = stats->rx_packets;
375276768Sdelphij  pd->stat.ps_drop  += stats->rx_missed_errors;
376276768Sdelphij  pd->stat.ps_ifdrop = stats->rx_dropped +  /* queue full */
377146768Ssam                         stats->rx_errors;    /* HW errors */
378146768Ssam  if (ps)
379276768Sdelphij     *ps = pd->stat;
380146768Ssam
381146768Ssam  return (0);
382146768Ssam}
383146768Ssam
384146768Ssam/*
385146768Ssam * Return detailed network/device statistics.
386146768Ssam * May be called after 'dev->close' is called.
387146768Ssam */
388146768Ssamint pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se)
389146768Ssam{
390146768Ssam  struct device *dev = p ? get_device (p->fd) : NULL;
391146768Ssam
392146768Ssam  if (!dev || !dev->get_stats)
393146768Ssam  {
394146768Ssam    strlcpy (p->errbuf, "detailed device statistics not available",
395146768Ssam             PCAP_ERRBUF_SIZE);
396146768Ssam    return (-1);
397146768Ssam  }
398146768Ssam
399146768Ssam  if (!strnicmp(dev->name,"pkt",3))
400146768Ssam  {
401146768Ssam    strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics",
402146768Ssam             PCAP_ERRBUF_SIZE);
403146768Ssam    return (-1);
404146768Ssam  }
405146768Ssam  memcpy (se, (*dev->get_stats)(dev), sizeof(*se));
406146768Ssam  return (0);
407146768Ssam}
408146768Ssam
409146768Ssam/*
410146768Ssam * Simply store the filter-code for the pcap_read_dos() callback
411146768Ssam * Some day the filter-code could be handed down to the active
412146768Ssam * device (pkt_rx1.s or 32-bit device interrupt handler).
413146768Ssam */
414146768Ssamstatic int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp)
415146768Ssam{
416146768Ssam  if (!p)
417146768Ssam     return (-1);
418146768Ssam  p->fcode = *fp;
419146768Ssam  return (0);
420146768Ssam}
421146768Ssam
422146768Ssam/*
423146768Ssam * Return # of packets received in pcap_read_dos()
424146768Ssam */
425146768Ssamu_long pcap_mac_packets (void)
426146768Ssam{
427146768Ssam  return (mac_count);
428146768Ssam}
429146768Ssam
430146768Ssam/*
431146768Ssam * Return # of packets passed through filter in pcap_read_dos()
432146768Ssam */
433146768Ssamu_long pcap_filter_packets (void)
434146768Ssam{
435146768Ssam  return (filter_count);
436146768Ssam}
437146768Ssam
438146768Ssam/*
439146768Ssam * Close pcap device. Not called for offline captures.
440146768Ssam */
441190225Srpaulostatic void pcap_cleanup_dos (pcap_t *p)
442146768Ssam{
443276768Sdelphij  struct pcap_dos *pd;
444276768Sdelphij
445146768Ssam  if (p && !exc_occured)
446146768Ssam  {
447276768Sdelphij    pd = p->priv;
448146768Ssam    if (pcap_stats(p,NULL) < 0)
449276768Sdelphij       pd->stat.ps_drop = 0;
450146768Ssam    if (!get_device(p->fd))
451146768Ssam       return;
452146768Ssam
453146768Ssam    handle_to_device [p->fd-1] = NULL;
454146768Ssam    p->fd = 0;
455146768Ssam    if (ref_count > 0)
456146768Ssam        ref_count--;
457146768Ssam    if (ref_count > 0)
458146768Ssam       return;
459146768Ssam  }
460146768Ssam  close_driver();
461146768Ssam}
462146768Ssam
463146768Ssam/*
464146768Ssam * Return the name of the 1st network interface,
465146768Ssam * or NULL if none can be found.
466146768Ssam */
467146768Ssamchar *pcap_lookupdev (char *ebuf)
468146768Ssam{
469146768Ssam  struct device *dev;
470146768Ssam
471146768Ssam#ifdef USE_32BIT_DRIVERS
472146768Ssam  init_32bit();
473146768Ssam#endif
474146768Ssam
475146768Ssam  for (dev = (struct device*)dev_base; dev; dev = dev->next)
476146768Ssam  {
477146768Ssam    PCAP_ASSERT (dev->probe);
478146768Ssam
479146768Ssam    if ((*dev->probe)(dev))
480146768Ssam    {
481146768Ssam      FLUSHK();
482146768Ssam      probed_dev = (struct device*) dev; /* remember last probed device */
483146768Ssam      return (char*) dev->name;
484146768Ssam    }
485146768Ssam  }
486146768Ssam
487146768Ssam  if (ebuf)
488146768Ssam     strcpy (ebuf, "No driver found");
489146768Ssam  return (NULL);
490146768Ssam}
491146768Ssam
492146768Ssam/*
493146768Ssam * Gets localnet & netmask from Watt-32.
494146768Ssam */
495146768Ssamint pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
496146768Ssam                    bpf_u_int32 *netmask, char *errbuf)
497146768Ssam{
498146768Ssam  if (!_watt_is_init)
499146768Ssam  {
500190225Srpaulo    strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be "
501146768Ssam                    "called first");
502146768Ssam    return (-1);
503146768Ssam  }
504146768Ssam
505146768Ssam  *netmask  = _w32_sin_mask;
506146768Ssam  *localnet = my_ip_addr & *netmask;
507146768Ssam  if (*localnet == 0)
508146768Ssam  {
509146768Ssam    if (IN_CLASSA(*netmask))
510146768Ssam       *localnet = IN_CLASSA_NET;
511146768Ssam    else if (IN_CLASSB(*netmask))
512146768Ssam       *localnet = IN_CLASSB_NET;
513146768Ssam    else if (IN_CLASSC(*netmask))
514146768Ssam       *localnet = IN_CLASSC_NET;
515146768Ssam    else
516146768Ssam    {
517146768Ssam      sprintf (errbuf, "inet class for 0x%lx unknown", *netmask);
518146768Ssam      return (-1);
519146768Ssam    }
520146768Ssam  }
521146768Ssam  ARGSUSED (device);
522146768Ssam  return (0);
523146768Ssam}
524146768Ssam
525146768Ssam/*
526146768Ssam * Get a list of all interfaces that are present and that we probe okay.
527146768Ssam * Returns -1 on error, 0 otherwise.
528146768Ssam * The list, as returned through "alldevsp", may be null if no interfaces
529146768Ssam * were up and could be opened.
530146768Ssam */
531146768Ssamint pcap_findalldevs (pcap_if_t **alldevsp, char *errbuf)
532146768Ssam{
533146768Ssam  struct device     *dev;
534146768Ssam  struct sockaddr_ll sa_ll_1, sa_ll_2;
535146768Ssam  struct sockaddr   *addr, *netmask, *broadaddr, *dstaddr;
536146768Ssam  pcap_if_t *devlist = NULL;
537146768Ssam  int       ret = 0;
538146768Ssam  size_t    addr_size = sizeof(struct sockaddr_ll);
539146768Ssam
540146768Ssam  for (dev = (struct device*)dev_base; dev; dev = dev->next)
541146768Ssam  {
542146768Ssam    PCAP_ASSERT (dev->probe);
543146768Ssam
544146768Ssam    if (!(*dev->probe)(dev))
545146768Ssam       continue;
546146768Ssam
547146768Ssam    PCAP_ASSERT (dev->close);  /* set by probe routine */
548146768Ssam    FLUSHK();
549146768Ssam    (*dev->close) (dev);
550146768Ssam
551146768Ssam    memset (&sa_ll_1, 0, sizeof(sa_ll_1));
552146768Ssam    memset (&sa_ll_2, 0, sizeof(sa_ll_2));
553146768Ssam    sa_ll_1.sll_family = AF_PACKET;
554146768Ssam    sa_ll_2.sll_family = AF_PACKET;
555146768Ssam
556146768Ssam    addr      = (struct sockaddr*) &sa_ll_1;
557146768Ssam    netmask   = (struct sockaddr*) &sa_ll_1;
558146768Ssam    dstaddr   = (struct sockaddr*) &sa_ll_1;
559146768Ssam    broadaddr = (struct sockaddr*) &sa_ll_2;
560146768Ssam    memset (&sa_ll_2.sll_addr, 0xFF, sizeof(sa_ll_2.sll_addr));
561146768Ssam
562146768Ssam    if (pcap_add_if(&devlist, dev->name, dev->flags,
563146768Ssam                    dev->long_name, errbuf) < 0)
564146768Ssam    {
565146768Ssam      ret = -1;
566146768Ssam      break;
567146768Ssam    }
568146768Ssam    if (add_addr_to_iflist(&devlist,dev->name, dev->flags, addr, addr_size,
569146768Ssam                           netmask, addr_size, broadaddr, addr_size,
570146768Ssam                           dstaddr, addr_size, errbuf) < 0)
571146768Ssam    {
572146768Ssam      ret = -1;
573146768Ssam      break;
574146768Ssam    }
575146768Ssam  }
576146768Ssam
577146768Ssam  if (devlist && ret < 0)
578146768Ssam  {
579146768Ssam    pcap_freealldevs (devlist);
580146768Ssam    devlist = NULL;
581146768Ssam  }
582146768Ssam  else
583146768Ssam  if (!devlist)
584146768Ssam     strcpy (errbuf, "No drivers found");
585146768Ssam
586146768Ssam  *alldevsp = devlist;
587146768Ssam  return (ret);
588146768Ssam}
589146768Ssam
590146768Ssam/*
591146768Ssam * pcap_assert() is mainly used for debugging
592146768Ssam */
593146768Ssamvoid pcap_assert (const char *what, const char *file, unsigned line)
594146768Ssam{
595146768Ssam  FLUSHK();
596146768Ssam  fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n",
597146768Ssam           file, line, what);
598146768Ssam  close_driver();
599146768Ssam  _exit (-1);
600146768Ssam}
601146768Ssam
602146768Ssam/*
603146768Ssam * For pcap_offline_read(): wait and yield between printing packets
604146768Ssam * to simulate the pace packets where actually recorded.
605146768Ssam */
606146768Ssamvoid pcap_set_wait (pcap_t *p, void (*yield)(void), int wait)
607146768Ssam{
608276768Sdelphij  struct pcap_dos *pd;
609146768Ssam  if (p)
610146768Ssam  {
611276768Sdelphij    pd                   = p->priv;
612276768Sdelphij    pd->wait_proc        = yield;
613276768Sdelphij    p->opt.timeout        = wait;
614146768Ssam  }
615146768Ssam}
616146768Ssam
617146768Ssam/*
618146768Ssam * Initialise a named network device.
619146768Ssam */
620146768Ssamstatic struct device *
621146768Ssamopen_driver (const char *dev_name, char *ebuf, int promisc)
622146768Ssam{
623146768Ssam  struct device *dev;
624146768Ssam
625146768Ssam  for (dev = (struct device*)dev_base; dev; dev = dev->next)
626146768Ssam  {
627146768Ssam    PCAP_ASSERT (dev->name);
628146768Ssam
629146768Ssam    if (strcmp (dev_name,dev->name))
630146768Ssam       continue;
631146768Ssam
632146768Ssam    if (!probed_dev)   /* user didn't call pcap_lookupdev() first */
633146768Ssam    {
634146768Ssam      PCAP_ASSERT (dev->probe);
635146768Ssam
636146768Ssam      if (!(*dev->probe)(dev))    /* call the xx_probe() function */
637146768Ssam      {
638146768Ssam        sprintf (ebuf, "failed to detect device `%s'", dev_name);
639146768Ssam        return (NULL);
640146768Ssam      }
641146768Ssam      probed_dev = dev;  /* device is probed okay and may be used */
642146768Ssam    }
643146768Ssam    else if (dev != probed_dev)
644146768Ssam    {
645146768Ssam      goto not_probed;
646146768Ssam    }
647146768Ssam
648146768Ssam    FLUSHK();
649146768Ssam
650146768Ssam    /* Select what traffic to receive
651146768Ssam     */
652146768Ssam    if (promisc)
653146768Ssam         dev->flags |=  (IFF_ALLMULTI | IFF_PROMISC);
654146768Ssam    else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC);
655146768Ssam
656146768Ssam    PCAP_ASSERT (dev->open);
657146768Ssam
658146768Ssam    if (!(*dev->open)(dev))
659146768Ssam    {
660146768Ssam      sprintf (ebuf, "failed to activate device `%s'", dev_name);
661146768Ssam      if (pktInfo.error && !strncmp(dev->name,"pkt",3))
662146768Ssam      {
663146768Ssam        strcat (ebuf, ": ");
664146768Ssam        strcat (ebuf, pktInfo.error);
665146768Ssam      }
666146768Ssam      return (NULL);
667146768Ssam    }
668146768Ssam
669146768Ssam    /* Some devices need this to operate in promiscous mode
670146768Ssam     */
671146768Ssam    if (promisc && dev->set_multicast_list)
672146768Ssam       (*dev->set_multicast_list) (dev);
673146768Ssam
674146768Ssam    active_dev = dev;   /* remember our active device */
675146768Ssam    break;
676146768Ssam  }
677146768Ssam
678146768Ssam  /* 'dev_name' not matched in 'dev_base' list.
679146768Ssam   */
680146768Ssam  if (!dev)
681146768Ssam  {
682146768Ssam    sprintf (ebuf, "device `%s' not supported", dev_name);
683146768Ssam    return (NULL);
684146768Ssam  }
685146768Ssam
686146768Ssamnot_probed:
687146768Ssam  if (!probed_dev)
688146768Ssam  {
689146768Ssam    sprintf (ebuf, "device `%s' not probed", dev_name);
690146768Ssam    return (NULL);
691146768Ssam  }
692146768Ssam  return (dev);
693146768Ssam}
694146768Ssam
695146768Ssam/*
696146768Ssam * Deinitialise MAC driver.
697146768Ssam * Set receive mode back to default mode.
698146768Ssam */
699146768Ssamstatic void close_driver (void)
700146768Ssam{
701146768Ssam  /* !!todo: loop over all 'handle_to_device[]' ? */
702146768Ssam  struct device *dev = active_dev;
703146768Ssam
704146768Ssam  if (dev && dev->close)
705146768Ssam  {
706146768Ssam    (*dev->close) (dev);
707146768Ssam    FLUSHK();
708146768Ssam  }
709146768Ssam
710146768Ssam  active_dev = NULL;
711146768Ssam
712146768Ssam#ifdef USE_32BIT_DRIVERS
713146768Ssam  if (rx_pool)
714146768Ssam  {
715146768Ssam    k_free (rx_pool);
716146768Ssam    rx_pool = NULL;
717146768Ssam  }
718146768Ssam  if (dev)
719146768Ssam     pcibios_exit();
720146768Ssam#endif
721146768Ssam}
722146768Ssam
723146768Ssam
724146768Ssam#ifdef __DJGPP__
725146768Ssamstatic void setup_signals (void (*handler)(int))
726146768Ssam{
727146768Ssam  signal (SIGSEGV,handler);
728146768Ssam  signal (SIGILL, handler);
729146768Ssam  signal (SIGFPE, handler);
730146768Ssam}
731146768Ssam
732146768Ssamstatic void exc_handler (int sig)
733146768Ssam{
734146768Ssam#ifdef USE_32BIT_DRIVERS
735146768Ssam  if (active_dev->irq > 0)    /* excludes IRQ 0 */
736146768Ssam  {
737146768Ssam    disable_irq (active_dev->irq);
738146768Ssam    irq_eoi_cmd (active_dev->irq);
739146768Ssam    _printk_safe = 1;
740146768Ssam  }
741146768Ssam#endif
742146768Ssam
743146768Ssam  switch (sig)
744146768Ssam  {
745146768Ssam    case SIGSEGV:
746146768Ssam         fputs ("Catching SIGSEGV.\n", stderr);
747146768Ssam         break;
748146768Ssam    case SIGILL:
749146768Ssam         fputs ("Catching SIGILL.\n", stderr);
750146768Ssam         break;
751146768Ssam    case SIGFPE:
752146768Ssam         _fpreset();
753146768Ssam         fputs ("Catching SIGFPE.\n", stderr);
754146768Ssam         break;
755146768Ssam    default:
756146768Ssam         fprintf (stderr, "Catching signal %d.\n", sig);
757146768Ssam  }
758146768Ssam  exc_occured = 1;
759190225Srpaulo  pcap_cleanup_dos (NULL);
760146768Ssam}
761146768Ssam#endif  /* __DJGPP__ */
762146768Ssam
763146768Ssam
764146768Ssam/*
765190225Srpaulo * Open the pcap device for the first client calling pcap_activate()
766146768Ssam */
767146768Ssamstatic int first_init (const char *name, char *ebuf, int promisc)
768146768Ssam{
769146768Ssam  struct device *dev;
770146768Ssam
771146768Ssam#ifdef USE_32BIT_DRIVERS
772146768Ssam  rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE);
773146768Ssam  if (!rx_pool)
774146768Ssam  {
775146768Ssam    strcpy (ebuf, "Not enough memory (Rx pool)");
776146768Ssam    return (0);
777146768Ssam  }
778146768Ssam#endif
779146768Ssam
780146768Ssam#ifdef __DJGPP__
781146768Ssam  setup_signals (exc_handler);
782146768Ssam#endif
783146768Ssam
784146768Ssam#ifdef USE_32BIT_DRIVERS
785146768Ssam  init_32bit();
786146768Ssam#endif
787146768Ssam
788146768Ssam  dev = open_driver (name, ebuf, promisc);
789146768Ssam  if (!dev)
790146768Ssam  {
791146768Ssam#ifdef USE_32BIT_DRIVERS
792146768Ssam    k_free (rx_pool);
793146768Ssam    rx_pool = NULL;
794146768Ssam#endif
795146768Ssam
796146768Ssam#ifdef __DJGPP__
797146768Ssam    setup_signals (SIG_DFL);
798146768Ssam#endif
799146768Ssam    return (0);
800146768Ssam  }
801146768Ssam
802146768Ssam#ifdef USE_32BIT_DRIVERS
803146768Ssam  /*
804146768Ssam   * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf'
805146768Ssam   * set in it's probe handler), initialise near-memory ring-buffer for
806146768Ssam   * the 32-bit device.
807146768Ssam   */
808146768Ssam  if (dev->copy_rx_buf == NULL)
809146768Ssam  {
810146768Ssam    dev->get_rx_buf     = get_rxbuf;
811146768Ssam    dev->peek_rx_buf    = peek_rxbuf;
812146768Ssam    dev->release_rx_buf = release_rxbuf;
813146768Ssam    pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool);
814146768Ssam  }
815146768Ssam#endif
816146768Ssam  return (1);
817146768Ssam}
818146768Ssam
819146768Ssam#ifdef USE_32BIT_DRIVERS
820146768Ssamstatic void init_32bit (void)
821146768Ssam{
822146768Ssam  static int init_pci = 0;
823146768Ssam
824146768Ssam  if (!_printk_file)
825146768Ssam     _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */
826146768Ssam
827146768Ssam  if (!init_pci)
828146768Ssam     (void)pci_init();             /* init BIOS32+PCI interface */
829146768Ssam  init_pci = 1;
830146768Ssam}
831146768Ssam#endif
832146768Ssam
833146768Ssam
834146768Ssam/*
835146768Ssam * Hook functions for using Watt-32 together with pcap
836146768Ssam */
837146768Ssamstatic char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */
838146768Ssamstatic WORD etype;
839146768Ssamstatic pcap_t pcap_save;
840146768Ssam
841146768Ssamstatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
842146768Ssam                              const u_char *buf)
843146768Ssam{
844146768Ssam  /* Fix me: assumes Ethernet II only */
845146768Ssam  struct ether_header *ep = (struct ether_header*) buf;
846146768Ssam
847146768Ssam  memcpy (rxbuf, buf, pcap->caplen);
848146768Ssam  etype = ep->ether_type;
849146768Ssam  ARGSUSED (dummy);
850146768Ssam}
851146768Ssam
852146768Ssam#if (WATTCP_VER >= 0x0224)
853146768Ssam/*
854146768Ssam * This function is used by Watt-32 to poll for a packet.
855146768Ssam * i.e. it's set to bypass _eth_arrived()
856146768Ssam */
857146768Ssamstatic void *pcap_recv_hook (WORD *type)
858146768Ssam{
859146768Ssam  int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL);
860146768Ssam
861146768Ssam  if (len < 0)
862146768Ssam     return (NULL);
863146768Ssam
864146768Ssam  *type = etype;
865146768Ssam  return (void*) &rxbuf;
866146768Ssam}
867146768Ssam
868146768Ssam/*
869146768Ssam * This function is called by Watt-32 (via _eth_xmit_hook).
870146768Ssam * If dbug_init() was called, we should trace packets sent.
871146768Ssam */
872146768Ssamstatic int pcap_xmit_hook (const void *buf, unsigned len)
873146768Ssam{
874146768Ssam  int rc = 0;
875146768Ssam
876146768Ssam  if (pcap_pkt_debug > 0)
877146768Ssam     dbug_write ("pcap_xmit_hook: ");
878146768Ssam
879146768Ssam  if (active_dev && active_dev->xmit)
880146768Ssam     if ((*active_dev->xmit) (active_dev, buf, len) > 0)
881146768Ssam        rc = len;
882146768Ssam
883146768Ssam  if (pcap_pkt_debug > 0)
884146768Ssam     dbug_write (rc ? "ok\n" : "fail\n");
885146768Ssam  return (rc);
886146768Ssam}
887146768Ssam#endif
888146768Ssam
889146768Ssamstatic int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len)
890146768Ssam{
891146768Ssam  struct device *dev = p ? get_device(p->fd) : NULL;
892146768Ssam
893146768Ssam  if (!dev || !dev->xmit)
894146768Ssam     return (-1);
895146768Ssam  return (*dev->xmit) (dev, buf, len);
896146768Ssam}
897146768Ssam
898146768Ssam/*
899146768Ssam * This function is called by Watt-32 in tcp_post_init().
900146768Ssam * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc.
901146768Ssam */
902146768Ssamstatic void (*prev_post_hook) (void);
903146768Ssam
904146768Ssamstatic void pcap_init_hook (void)
905146768Ssam{
906146768Ssam  _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0;
907146768Ssam  _w32__do_mask_req = 0;
908146768Ssam  _w32_dynamic_host = 0;
909146768Ssam  if (prev_post_hook)
910146768Ssam    (*prev_post_hook)();
911146768Ssam}
912146768Ssam
913146768Ssam/*
914146768Ssam * Supress PRINT message from Watt-32's sock_init()
915146768Ssam */
916146768Ssamstatic void null_print (void) {}
917146768Ssam
918146768Ssam/*
919146768Ssam * To use features of Watt-32 (netdb functions and socket etc.)
920146768Ssam * we must call sock_init(). But we set various hooks to prevent
921146768Ssam * using normal PKTDRVR functions in pcpkt.c. This should hopefully
922146768Ssam * make Watt-32 and pcap co-operate.
923146768Ssam */
924146768Ssamstatic int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
925146768Ssam{
926146768Ssam  char *env;
927146768Ssam  int   rc, MTU, has_ip_addr;
928146768Ssam  int   using_pktdrv = 1;
929146768Ssam
930146768Ssam  /* If user called sock_init() first, we need to reinit in
931146768Ssam   * order to open debug/trace-file properly
932146768Ssam   */
933146768Ssam  if (_watt_is_init)
934146768Ssam     sock_exit();
935146768Ssam
936146768Ssam  env = getenv ("PCAP_DEBUG");
937146768Ssam  if (env && atoi(env) > 0 &&
938146768Ssam      pcap_pkt_debug < 0)   /* if not already set */
939146768Ssam  {
940146768Ssam    dbug_init();
941146768Ssam    pcap_pkt_debug = atoi (env);
942146768Ssam  }
943146768Ssam
944146768Ssam  _watt_do_exit      = 0;    /* prevent sock_init() calling exit() */
945146768Ssam  prev_post_hook     = _w32_usr_post_init;
946146768Ssam  _w32_usr_post_init = pcap_init_hook;
947146768Ssam  _w32_print_hook    = null_print;
948146768Ssam
949146768Ssam  if (dev_name && strncmp(dev_name,"pkt",3))
950146768Ssam     using_pktdrv = FALSE;
951146768Ssam
952146768Ssam  rc = sock_init();
953146768Ssam  has_ip_addr = (rc != 8);  /* IP-address assignment failed */
954146768Ssam
955146768Ssam  /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we
956146768Ssam   * just pretend Watt-32 is initialised okay.
957146768Ssam   *
958146768Ssam   * !! fix-me: The Watt-32 config isn't done if no pktdrvr
959146768Ssam   *            was found. In that case my_ip_addr + sin_mask
960146768Ssam   *            have default values. Should be taken from another
961146768Ssam   *            ini-file/environment in any case (ref. tcpdump.ini)
962146768Ssam   */
963146768Ssam  _watt_is_init = 1;
964146768Ssam
965146768Ssam  if (!using_pktdrv || !has_ip_addr)  /* for now .... */
966146768Ssam  {
967146768Ssam    static const char myip[] = "192.168.0.1";
968146768Ssam    static const char mask[] = "255.255.255.0";
969146768Ssam
970146768Ssam    printf ("Just guessing, using IP %s and netmask %s\n", myip, mask);
971146768Ssam    my_ip_addr    = aton (myip);
972146768Ssam    _w32_sin_mask = aton (mask);
973146768Ssam  }
974146768Ssam  else if (rc && using_pktdrv)
975146768Ssam  {
976146768Ssam    sprintf (err_buf, "sock_init() failed, code %d", rc);
977146768Ssam    return (0);
978146768Ssam  }
979146768Ssam
980146768Ssam  /* Set recv-hook for peeking in _eth_arrived().
981146768Ssam   */
982146768Ssam#if (WATTCP_VER >= 0x0224)
983146768Ssam  _eth_recv_hook = pcap_recv_hook;
984146768Ssam  _eth_xmit_hook = pcap_xmit_hook;
985146768Ssam#endif
986146768Ssam
987146768Ssam  /* Free the pkt-drvr handle allocated in pkt_init().
988146768Ssam   * The above hooks should thus use the handle reopened in open_driver()
989146768Ssam   */
990146768Ssam  if (using_pktdrv)
991146768Ssam  {
992146768Ssam    _eth_release();
993146768Ssam/*  _eth_is_init = 1; */  /* hack to get Rx/Tx-hooks in Watt-32 working */
994146768Ssam  }
995146768Ssam
996146768Ssam  memcpy (&pcap_save, pcap, sizeof(pcap_save));
997146768Ssam  MTU = pkt_get_mtu();
998146768Ssam  pcap_save.fcode.bf_insns = NULL;
999146768Ssam  pcap_save.linktype       = _eth_get_hwtype (NULL, NULL);
1000146768Ssam  pcap_save.snapshot       = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
1001146768Ssam
1002146768Ssam#if 1
1003146768Ssam  /* prevent use of resolve() and resolve_ip()
1004146768Ssam   */
1005146768Ssam  last_nameserver = 0;
1006146768Ssam#endif
1007146768Ssam  return (1);
1008146768Ssam}
1009146768Ssam
1010146768Ssamint EISA_bus = 0;  /* Where is natural place for this? */
1011146768Ssam
1012146768Ssam/*
1013146768Ssam * Application config hooks to set various driver parameters.
1014146768Ssam */
1015146768Ssam
1016190225Srpaulostatic const struct config_table debug_tab[] = {
1017146768Ssam            { "PKT.DEBUG",       ARG_ATOI,   &pcap_pkt_debug    },
1018146768Ssam            { "PKT.VECTOR",      ARG_ATOX_W, NULL               },
1019146768Ssam            { "NDIS.DEBUG",      ARG_ATOI,   NULL               },
1020146768Ssam#ifdef USE_32BIT_DRIVERS
1021146768Ssam            { "3C503.DEBUG",     ARG_ATOI,   &ei_debug          },
1022146768Ssam            { "3C503.IO_BASE",   ARG_ATOX_W, &el2_dev.base_addr },
1023146768Ssam            { "3C503.MEMORY",    ARG_ATOX_W, &el2_dev.mem_start },
1024146768Ssam            { "3C503.IRQ",       ARG_ATOI,   &el2_dev.irq       },
1025146768Ssam            { "3C505.DEBUG",     ARG_ATOI,   NULL               },
1026146768Ssam            { "3C505.BASE",      ARG_ATOX_W, NULL               },
1027146768Ssam            { "3C507.DEBUG",     ARG_ATOI,   NULL               },
1028146768Ssam            { "3C509.DEBUG",     ARG_ATOI,   &el3_debug         },
1029146768Ssam            { "3C509.ILOOP",     ARG_ATOI,   &el3_max_loop      },
1030146768Ssam            { "3C529.DEBUG",     ARG_ATOI,   NULL               },
1031146768Ssam            { "3C575.DEBUG",     ARG_ATOI,   &debug_3c575       },
1032146768Ssam            { "3C59X.DEBUG",     ARG_ATOI,   &vortex_debug      },
1033146768Ssam            { "3C59X.IFACE0",    ARG_ATOI,   &vortex_options[0] },
1034146768Ssam            { "3C59X.IFACE1",    ARG_ATOI,   &vortex_options[1] },
1035146768Ssam            { "3C59X.IFACE2",    ARG_ATOI,   &vortex_options[2] },
1036146768Ssam            { "3C59X.IFACE3",    ARG_ATOI,   &vortex_options[3] },
1037146768Ssam            { "3C90X.DEBUG",     ARG_ATOX_W, &tc90xbc_debug     },
1038146768Ssam            { "ACCT.DEBUG",      ARG_ATOI,   &ethpk_debug       },
1039146768Ssam            { "CS89.DEBUG",      ARG_ATOI,   &cs89_debug        },
1040146768Ssam            { "RTL8139.DEBUG",   ARG_ATOI,   &rtl8139_debug     },
1041146768Ssam        /*  { "RTL8139.FDUPLEX", ARG_ATOI,   &rtl8139_options   }, */
1042146768Ssam            { "SMC.DEBUG",       ARG_ATOI,   &ei_debug          },
1043146768Ssam        /*  { "E100.DEBUG",      ARG_ATOI,   &e100_debug        }, */
1044146768Ssam            { "PCI.DEBUG",       ARG_ATOI,   &pci_debug         },
1045146768Ssam            { "BIOS32.DEBUG",    ARG_ATOI,   &bios32_debug      },
1046146768Ssam            { "IRQ.DEBUG",       ARG_ATOI,   &irq_debug         },
1047146768Ssam            { "TIMER.IRQ",       ARG_ATOI,   &timer_irq         },
1048146768Ssam#endif
1049146768Ssam            { NULL }
1050146768Ssam          };
1051146768Ssam
1052146768Ssam/*
1053146768Ssam * pcap_config_hook() is an extension to application's config
1054146768Ssam * handling. Uses Watt-32's config-table function.
1055146768Ssam */
1056146768Ssamint pcap_config_hook (const char *name, const char *value)
1057146768Ssam{
1058146768Ssam  return parse_config_table (debug_tab, NULL, name, value);
1059146768Ssam}
1060146768Ssam
1061146768Ssam/*
1062146768Ssam * Linked list of supported devices
1063146768Ssam */
1064146768Ssamstruct device       *active_dev = NULL;      /* the device we have opened */
1065146768Ssamstruct device       *probed_dev = NULL;      /* the device we have probed */
1066146768Ssamconst struct device *dev_base   = &pkt_dev;  /* list of network devices */
1067146768Ssam
1068146768Ssam/*
1069146768Ssam * PKTDRVR device functions
1070146768Ssam */
1071146768Ssamint pcap_pkt_debug = -1;
1072146768Ssam
1073146768Ssamstatic void pkt_close (struct device *dev)
1074146768Ssam{
1075146768Ssam  BOOL okay = PktExitDriver();
1076146768Ssam
1077146768Ssam  if (pcap_pkt_debug > 1)
1078146768Ssam     fprintf (stderr, "pkt_close(): %d\n", okay);
1079146768Ssam
1080146768Ssam  if (dev->priv)
1081146768Ssam     free (dev->priv);
1082146768Ssam  dev->priv = NULL;
1083146768Ssam}
1084146768Ssam
1085146768Ssamstatic int pkt_open (struct device *dev)
1086146768Ssam{
1087146768Ssam  PKT_RX_MODE mode;
1088146768Ssam
1089146768Ssam  if (dev->flags & IFF_PROMISC)
1090146768Ssam       mode = PDRX_ALL_PACKETS;
1091146768Ssam  else mode = PDRX_BROADCAST;
1092146768Ssam
1093146768Ssam  if (!PktInitDriver(mode))
1094146768Ssam     return (0);
1095146768Ssam
1096146768Ssam  PktResetStatistics (pktInfo.handle);
1097146768Ssam  PktQueueBusy (FALSE);
1098146768Ssam  return (1);
1099146768Ssam}
1100146768Ssam
1101146768Ssamstatic int pkt_xmit (struct device *dev, const void *buf, int len)
1102146768Ssam{
1103146768Ssam  struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1104146768Ssam
1105146768Ssam  if (pcap_pkt_debug > 0)
1106146768Ssam     dbug_write ("pcap_xmit\n");
1107146768Ssam
1108146768Ssam  if (!PktTransmit(buf,len))
1109146768Ssam  {
1110146768Ssam    stats->tx_errors++;
1111146768Ssam    return (0);
1112146768Ssam  }
1113146768Ssam  return (len);
1114146768Ssam}
1115146768Ssam
1116146768Ssamstatic void *pkt_stats (struct device *dev)
1117146768Ssam{
1118146768Ssam  struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
1119146768Ssam
1120146768Ssam  if (!stats || !PktSessStatistics(pktInfo.handle))
1121146768Ssam     return (NULL);
1122146768Ssam
1123146768Ssam  stats->rx_packets       = pktStat.inPackets;
1124146768Ssam  stats->rx_errors        = pktStat.lost;
1125146768Ssam  stats->rx_missed_errors = PktRxDropped();
1126146768Ssam  return (stats);
1127146768Ssam}
1128146768Ssam
1129146768Ssamstatic int pkt_probe (struct device *dev)
1130146768Ssam{
1131146768Ssam  if (!PktSearchDriver())
1132146768Ssam     return (0);
1133146768Ssam
1134146768Ssam  dev->open           = pkt_open;
1135146768Ssam  dev->xmit           = pkt_xmit;
1136146768Ssam  dev->close          = pkt_close;
1137146768Ssam  dev->get_stats      = pkt_stats;
1138146768Ssam  dev->copy_rx_buf    = PktReceive;  /* farmem peek and copy routine */
1139146768Ssam  dev->get_rx_buf     = NULL;
1140146768Ssam  dev->peek_rx_buf    = NULL;
1141146768Ssam  dev->release_rx_buf = NULL;
1142146768Ssam  dev->priv           = calloc (sizeof(struct net_device_stats), 1);
1143146768Ssam  if (!dev->priv)
1144146768Ssam     return (0);
1145146768Ssam  return (1);
1146146768Ssam}
1147146768Ssam
1148146768Ssam/*
1149146768Ssam * NDIS device functions
1150146768Ssam */
1151146768Ssamstatic void ndis_close (struct device *dev)
1152146768Ssam{
1153146768Ssam#ifdef USE_NDIS2
1154146768Ssam  NdisShutdown();
1155146768Ssam#endif
1156146768Ssam  ARGSUSED (dev);
1157146768Ssam}
1158146768Ssam
1159146768Ssamstatic int ndis_open (struct device *dev)
1160146768Ssam{
1161146768Ssam  int promis = (dev->flags & IFF_PROMISC);
1162146768Ssam
1163146768Ssam#ifdef USE_NDIS2
1164146768Ssam  if (!NdisInit(promis))
1165146768Ssam     return (0);
1166146768Ssam  return (1);
1167146768Ssam#else
1168146768Ssam  ARGSUSED (promis);
1169146768Ssam  return (0);
1170146768Ssam#endif
1171146768Ssam}
1172146768Ssam
1173146768Ssamstatic void *ndis_stats (struct device *dev)
1174146768Ssam{
1175146768Ssam  static struct net_device_stats stats;
1176146768Ssam
1177146768Ssam  /* to-do */
1178146768Ssam  ARGSUSED (dev);
1179146768Ssam  return (&stats);
1180146768Ssam}
1181146768Ssam
1182146768Ssamstatic int ndis_probe (struct device *dev)
1183146768Ssam{
1184146768Ssam#ifdef USE_NDIS2
1185146768Ssam  if (!NdisOpen())
1186146768Ssam     return (0);
1187146768Ssam#endif
1188146768Ssam
1189146768Ssam  dev->open           = ndis_open;
1190146768Ssam  dev->xmit           = NULL;
1191146768Ssam  dev->close          = ndis_close;
1192146768Ssam  dev->get_stats      = ndis_stats;
1193146768Ssam  dev->copy_rx_buf    = NULL;       /* to-do */
1194146768Ssam  dev->get_rx_buf     = NULL;       /* upcall is from rmode driver */
1195146768Ssam  dev->peek_rx_buf    = NULL;
1196146768Ssam  dev->release_rx_buf = NULL;
1197146768Ssam  return (0);
1198146768Ssam}
1199146768Ssam
1200146768Ssam/*
1201146768Ssam * Search & probe for supported 32-bit (pmode) pcap devices
1202146768Ssam */
1203146768Ssam#if defined(USE_32BIT_DRIVERS)
1204146768Ssam
1205146768Ssamstruct device el2_dev LOCKED_VAR = {
1206146768Ssam              "3c503",
1207146768Ssam              "EtherLink II",
1208146768Ssam              0,
1209146768Ssam              0,0,0,0,0,0,
1210146768Ssam              NULL,
1211146768Ssam              el2_probe
1212146768Ssam            };
1213146768Ssam
1214146768Ssamstruct device el3_dev LOCKED_VAR = {
1215146768Ssam              "3c509",
1216146768Ssam              "EtherLink III",
1217146768Ssam              0,
1218146768Ssam              0,0,0,0,0,0,
1219146768Ssam              &el2_dev,
1220146768Ssam              el3_probe
1221146768Ssam            };
1222146768Ssam
1223146768Ssamstruct device tc515_dev LOCKED_VAR = {
1224146768Ssam              "3c515",
1225146768Ssam              "EtherLink PCI",
1226146768Ssam              0,
1227146768Ssam              0,0,0,0,0,0,
1228146768Ssam              &el3_dev,
1229146768Ssam              tc515_probe
1230146768Ssam            };
1231146768Ssam
1232146768Ssamstruct device tc59_dev LOCKED_VAR = {
1233146768Ssam              "3c59x",
1234146768Ssam              "EtherLink PCI",
1235146768Ssam              0,
1236146768Ssam              0,0,0,0,0,0,
1237146768Ssam              &tc515_dev,
1238146768Ssam              tc59x_probe
1239146768Ssam            };
1240146768Ssam
1241146768Ssamstruct device tc90xbc_dev LOCKED_VAR = {
1242146768Ssam              "3c90x",
1243146768Ssam              "EtherLink 90X",
1244146768Ssam              0,
1245146768Ssam              0,0,0,0,0,0,
1246146768Ssam              &tc59_dev,
1247146768Ssam              tc90xbc_probe
1248146768Ssam            };
1249146768Ssam
1250146768Ssamstruct device wd_dev LOCKED_VAR = {
1251146768Ssam              "wd",
1252146768Ssam              "Westen Digital",
1253146768Ssam              0,
1254146768Ssam              0,0,0,0,0,0,
1255146768Ssam              &tc90xbc_dev,
1256146768Ssam              wd_probe
1257146768Ssam            };
1258146768Ssam
1259146768Ssamstruct device ne_dev LOCKED_VAR = {
1260146768Ssam              "ne",
1261146768Ssam              "NEx000",
1262146768Ssam              0,
1263146768Ssam              0,0,0,0,0,0,
1264146768Ssam              &wd_dev,
1265146768Ssam              ne_probe
1266146768Ssam            };
1267146768Ssam
1268146768Ssamstruct device acct_dev LOCKED_VAR = {
1269146768Ssam              "acct",
1270146768Ssam              "Accton EtherPocket",
1271146768Ssam              0,
1272146768Ssam              0,0,0,0,0,0,
1273146768Ssam              &ne_dev,
1274146768Ssam              ethpk_probe
1275146768Ssam            };
1276146768Ssam
1277146768Ssamstruct device cs89_dev LOCKED_VAR = {
1278146768Ssam              "cs89",
1279146768Ssam              "Crystal Semiconductor",
1280146768Ssam              0,
1281146768Ssam              0,0,0,0,0,0,
1282146768Ssam              &acct_dev,
1283146768Ssam              cs89x0_probe
1284146768Ssam            };
1285146768Ssam
1286146768Ssamstruct device rtl8139_dev LOCKED_VAR = {
1287146768Ssam              "rtl8139",
1288146768Ssam              "RealTek PCI",
1289146768Ssam              0,
1290146768Ssam              0,0,0,0,0,0,
1291146768Ssam              &cs89_dev,
1292146768Ssam              rtl8139_probe     /* dev->probe routine */
1293146768Ssam            };
1294146768Ssam
1295146768Ssam/*
1296146768Ssam * Dequeue routine is called by polling.
1297146768Ssam * NOTE: the queue-element is not copied, only a pointer is
1298146768Ssam * returned at '*buf'
1299146768Ssam */
1300146768Ssamint peek_rxbuf (BYTE **buf)
1301146768Ssam{
1302146768Ssam  struct rx_elem *tail, *head;
1303146768Ssam
1304146768Ssam  PCAP_ASSERT (pktq_check (&active_dev->queue));
1305146768Ssam
1306146768Ssam  DISABLE();
1307146768Ssam  tail = pktq_out_elem (&active_dev->queue);
1308146768Ssam  head = pktq_in_elem (&active_dev->queue);
1309146768Ssam  ENABLE();
1310146768Ssam
1311146768Ssam  if (head != tail)
1312146768Ssam  {
1313146768Ssam    PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2);
1314146768Ssam
1315146768Ssam    *buf = &tail->data[0];
1316146768Ssam    return (tail->size);
1317146768Ssam  }
1318146768Ssam  *buf = NULL;
1319146768Ssam  return (0);
1320146768Ssam}
1321146768Ssam
1322146768Ssam/*
1323146768Ssam * Release buffer we peeked at above.
1324146768Ssam */
1325146768Ssamint release_rxbuf (BYTE *buf)
1326146768Ssam{
1327146768Ssam#ifndef NDEBUG
1328146768Ssam  struct rx_elem *tail = pktq_out_elem (&active_dev->queue);
1329146768Ssam
1330146768Ssam  PCAP_ASSERT (&tail->data[0] == buf);
1331146768Ssam#else
1332146768Ssam  ARGSUSED (buf);
1333146768Ssam#endif
1334146768Ssam  pktq_inc_out (&active_dev->queue);
1335146768Ssam  return (1);
1336146768Ssam}
1337146768Ssam
1338146768Ssam/*
1339146768Ssam * get_rxbuf() routine (in locked code) is called from IRQ handler
1340146768Ssam * to request a buffer. Interrupts are disabled and we have a 32kB stack.
1341146768Ssam */
1342146768SsamBYTE *get_rxbuf (int len)
1343146768Ssam{
1344146768Ssam  int idx;
1345146768Ssam
1346146768Ssam  if (len < ETH_MIN || len > ETH_MAX)
1347146768Ssam     return (NULL);
1348146768Ssam
1349146768Ssam  idx = pktq_in_index (&active_dev->queue);
1350146768Ssam
1351146768Ssam#ifdef DEBUG
1352146768Ssam  {
1353146768Ssam    static int fan_idx LOCKED_VAR = 0;
1354146768Ssam    writew ("-\\|/"[fan_idx++] | (15 << 8),      /* white on black colour */
1355146768Ssam            0xB8000 + 2*79);  /* upper-right corner, 80-col colour screen */
1356146768Ssam    fan_idx &= 3;
1357146768Ssam  }
1358146768Ssam/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */
1359146768Ssam#endif
1360146768Ssam
1361146768Ssam  if (idx != active_dev->queue.out_index)
1362146768Ssam  {
1363146768Ssam    struct rx_elem *head = pktq_in_elem (&active_dev->queue);
1364146768Ssam
1365146768Ssam    head->size = len;
1366146768Ssam    active_dev->queue.in_index = idx;
1367146768Ssam    return (&head->data[0]);
1368146768Ssam  }
1369146768Ssam
1370146768Ssam  /* !!to-do: drop 25% of the oldest element
1371146768Ssam   */
1372146768Ssam  pktq_clear (&active_dev->queue);
1373146768Ssam  return (NULL);
1374146768Ssam}
1375146768Ssam
1376146768Ssam/*
1377146768Ssam *  Simple ring-buffer queue handler for reception of packets
1378146768Ssam *  from network driver.
1379146768Ssam */
1380146768Ssam#define PKTQ_MARKER  0xDEADBEEF
1381146768Ssam
1382146768Ssamstatic int pktq_check (struct rx_ringbuf *q)
1383146768Ssam{
1384146768Ssam#ifndef NDEBUG
1385146768Ssam  int   i;
1386146768Ssam  char *buf;
1387146768Ssam#endif
1388146768Ssam
1389146768Ssam  if (!q || !q->num_elem || !q->buf_start)
1390146768Ssam     return (0);
1391146768Ssam
1392146768Ssam#ifndef NDEBUG
1393146768Ssam  buf = q->buf_start;
1394146768Ssam
1395146768Ssam  for (i = 0; i < q->num_elem; i++)
1396146768Ssam  {
1397146768Ssam    buf += q->elem_size;
1398146768Ssam    if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER)
1399146768Ssam       return (0);
1400146768Ssam  }
1401146768Ssam#endif
1402146768Ssam  return (1);
1403146768Ssam}
1404146768Ssam
1405146768Ssamstatic int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool)
1406146768Ssam{
1407146768Ssam  int i;
1408146768Ssam
1409146768Ssam  q->elem_size = size;
1410146768Ssam  q->num_elem  = num;
1411146768Ssam  q->buf_start = pool;
1412146768Ssam  q->in_index  = 0;
1413146768Ssam  q->out_index = 0;
1414146768Ssam
1415146768Ssam  PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD));
1416146768Ssam  PCAP_ASSERT (num);
1417146768Ssam  PCAP_ASSERT (pool);
1418146768Ssam
1419146768Ssam  for (i = 0; i < num; i++)
1420146768Ssam  {
1421146768Ssam#if 0
1422146768Ssam    struct rx_elem *elem = (struct rx_elem*) pool;
1423146768Ssam
1424146768Ssam    /* assert dword aligned elements
1425146768Ssam     */
1426146768Ssam    PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0);
1427146768Ssam#endif
1428146768Ssam    pool += size;
1429146768Ssam    *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER;
1430146768Ssam  }
1431146768Ssam  return (1);
1432146768Ssam}
1433146768Ssam
1434146768Ssam/*
1435146768Ssam * Increment the queue 'out_index' (tail).
1436146768Ssam * Check for wraps.
1437146768Ssam */
1438146768Ssamstatic int pktq_inc_out (struct rx_ringbuf *q)
1439146768Ssam{
1440146768Ssam  q->out_index++;
1441146768Ssam  if (q->out_index >= q->num_elem)
1442146768Ssam      q->out_index = 0;
1443146768Ssam  return (q->out_index);
1444146768Ssam}
1445146768Ssam
1446146768Ssam/*
1447146768Ssam * Return the queue's next 'in_index' (head).
1448146768Ssam * Check for wraps.
1449146768Ssam */
1450146768Ssamstatic int pktq_in_index (struct rx_ringbuf *q)
1451146768Ssam{
1452146768Ssam  volatile int index = q->in_index + 1;
1453146768Ssam
1454146768Ssam  if (index >= q->num_elem)
1455146768Ssam      index = 0;
1456146768Ssam  return (index);
1457146768Ssam}
1458146768Ssam
1459146768Ssam/*
1460146768Ssam * Return the queue's head-buffer.
1461146768Ssam */
1462146768Ssamstatic struct rx_elem *pktq_in_elem (struct rx_ringbuf *q)
1463146768Ssam{
1464146768Ssam  return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index));
1465146768Ssam}
1466146768Ssam
1467146768Ssam/*
1468146768Ssam * Return the queue's tail-buffer.
1469146768Ssam */
1470146768Ssamstatic struct rx_elem *pktq_out_elem (struct rx_ringbuf *q)
1471146768Ssam{
1472146768Ssam  return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index));
1473146768Ssam}
1474146768Ssam
1475146768Ssam/*
1476146768Ssam * Clear the queue ring-buffer by setting head=tail.
1477146768Ssam */
1478146768Ssamstatic void pktq_clear (struct rx_ringbuf *q)
1479146768Ssam{
1480146768Ssam  q->in_index = q->out_index;
1481146768Ssam}
1482146768Ssam
1483146768Ssam/*
1484146768Ssam * Symbols that must be linkable for "gcc -O0"
1485146768Ssam */
1486146768Ssam#undef __IOPORT_H
1487146768Ssam#undef __DMA_H
1488146768Ssam
1489146768Ssam#define extern
1490146768Ssam#define __inline__
1491146768Ssam
1492146768Ssam#include "msdos/pm_drvr/ioport.h"
1493146768Ssam#include "msdos/pm_drvr/dma.h"
1494146768Ssam
1495146768Ssam#endif /* USE_32BIT_DRIVERS */
1496146768Ssam
1497