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