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