xref: /freebsd/contrib/libpcap/pcap-dos.c (revision ada6f083b93b4adce9c3b3ba00112528244a3b86)
104fb2745SSam Leffler /*
204fb2745SSam Leffler  *  This file is part of DOS-libpcap
3*ada6f083SXin LI  *  Ported to DOS/DOSX by G. Vanem <gvanem@yahoo.no>
404fb2745SSam Leffler  *
504fb2745SSam Leffler  *  pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode
604fb2745SSam Leffler  *              network drivers.
704fb2745SSam Leffler  */
804fb2745SSam Leffler 
904fb2745SSam Leffler #include <stdio.h>
1004fb2745SSam Leffler #include <stdlib.h>
1104fb2745SSam Leffler #include <string.h>
1204fb2745SSam Leffler #include <signal.h>
1304fb2745SSam Leffler #include <float.h>
1404fb2745SSam Leffler #include <fcntl.h>
1504fb2745SSam Leffler #include <io.h>
1604fb2745SSam Leffler 
1704fb2745SSam Leffler #if defined(USE_32BIT_DRIVERS)
1804fb2745SSam Leffler   #include "msdos/pm_drvr/pmdrvr.h"
1904fb2745SSam Leffler   #include "msdos/pm_drvr/pci.h"
2004fb2745SSam Leffler   #include "msdos/pm_drvr/bios32.h"
2104fb2745SSam Leffler   #include "msdos/pm_drvr/module.h"
2204fb2745SSam Leffler   #include "msdos/pm_drvr/3c501.h"
2304fb2745SSam Leffler   #include "msdos/pm_drvr/3c503.h"
2404fb2745SSam Leffler   #include "msdos/pm_drvr/3c509.h"
2504fb2745SSam Leffler   #include "msdos/pm_drvr/3c59x.h"
2604fb2745SSam Leffler   #include "msdos/pm_drvr/3c515.h"
2704fb2745SSam Leffler   #include "msdos/pm_drvr/3c90x.h"
2804fb2745SSam Leffler   #include "msdos/pm_drvr/3c575_cb.h"
2904fb2745SSam Leffler   #include "msdos/pm_drvr/ne.h"
3004fb2745SSam Leffler   #include "msdos/pm_drvr/wd.h"
3104fb2745SSam Leffler   #include "msdos/pm_drvr/accton.h"
3204fb2745SSam Leffler   #include "msdos/pm_drvr/cs89x0.h"
3304fb2745SSam Leffler   #include "msdos/pm_drvr/rtl8139.h"
3404fb2745SSam Leffler   #include "msdos/pm_drvr/ne2k-pci.h"
3504fb2745SSam Leffler #endif
3604fb2745SSam Leffler 
3704fb2745SSam Leffler #include "pcap.h"
3804fb2745SSam Leffler #include "pcap-dos.h"
3904fb2745SSam Leffler #include "pcap-int.h"
4004fb2745SSam Leffler #include "msdos/pktdrvr.h"
4104fb2745SSam Leffler 
4204fb2745SSam Leffler #ifdef USE_NDIS2
4304fb2745SSam Leffler #include "msdos/ndis2.h"
4404fb2745SSam Leffler #endif
4504fb2745SSam Leffler 
4604fb2745SSam Leffler #include <arpa/inet.h>
4704fb2745SSam Leffler #include <net/if.h>
4804fb2745SSam Leffler #include <net/if_arp.h>
4904fb2745SSam Leffler #include <net/if_ether.h>
5004fb2745SSam Leffler #include <net/if_packe.h>
5104fb2745SSam Leffler #include <tcp.h>
5204fb2745SSam Leffler 
5304fb2745SSam Leffler #if defined(USE_32BIT_DRIVERS)
5404fb2745SSam Leffler   #define FLUSHK()       do { _printk_safe = 1; _printk_flush(); } while (0)
5504fb2745SSam Leffler   #define NDIS_NEXT_DEV  &rtl8139_dev
5604fb2745SSam Leffler 
5704fb2745SSam Leffler   static char *rx_pool = NULL;
5804fb2745SSam Leffler   static void init_32bit (void);
5904fb2745SSam Leffler 
6004fb2745SSam Leffler   static int  pktq_init     (struct rx_ringbuf *q, int size, int num, char *pool);
6104fb2745SSam Leffler   static int  pktq_check    (struct rx_ringbuf *q);
6204fb2745SSam Leffler   static int  pktq_inc_out  (struct rx_ringbuf *q);
6304fb2745SSam Leffler   static int  pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC;
6404fb2745SSam Leffler   static void pktq_clear    (struct rx_ringbuf *q) LOCKED_FUNC;
6504fb2745SSam Leffler 
6604fb2745SSam Leffler   static struct rx_elem *pktq_in_elem  (struct rx_ringbuf *q) LOCKED_FUNC;
6704fb2745SSam Leffler   static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q);
6804fb2745SSam Leffler 
6904fb2745SSam Leffler #else
7004fb2745SSam Leffler   #define FLUSHK()      ((void)0)
7104fb2745SSam Leffler   #define NDIS_NEXT_DEV  NULL
7204fb2745SSam Leffler #endif
7304fb2745SSam Leffler 
7404fb2745SSam Leffler /*
7504fb2745SSam Leffler  * Internal variables/functions in Watt-32
7604fb2745SSam Leffler  */
7704fb2745SSam Leffler extern WORD  _pktdevclass;
7804fb2745SSam Leffler extern BOOL  _eth_is_init;
7904fb2745SSam Leffler extern int   _w32_dynamic_host;
8004fb2745SSam Leffler extern int   _watt_do_exit;
8104fb2745SSam Leffler extern int   _watt_is_init;
8204fb2745SSam Leffler extern int   _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req;
8304fb2745SSam Leffler extern void (*_w32_usr_post_init) (void);
8404fb2745SSam Leffler extern void (*_w32_print_hook)();
8504fb2745SSam Leffler 
8604fb2745SSam Leffler extern void dbug_write (const char *);  /* Watt-32 lib, pcdbug.c */
8704fb2745SSam Leffler extern int  pkt_get_mtu (void);
8804fb2745SSam Leffler 
8904fb2745SSam Leffler static int ref_count = 0;
9004fb2745SSam Leffler 
9104fb2745SSam Leffler static u_long mac_count    = 0;
9204fb2745SSam Leffler static u_long filter_count = 0;
9304fb2745SSam Leffler 
9404fb2745SSam Leffler static volatile BOOL exc_occured = 0;
9504fb2745SSam Leffler 
9604fb2745SSam Leffler static struct device *handle_to_device [20];
9704fb2745SSam Leffler 
98a8e07101SRui Paulo static int  pcap_activate_dos (pcap_t *p);
9904fb2745SSam Leffler static int  pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback,
10004fb2745SSam Leffler                            u_char *data);
101a8e07101SRui Paulo static void pcap_cleanup_dos (pcap_t *p);
10204fb2745SSam Leffler static int  pcap_stats_dos (pcap_t *p, struct pcap_stat *ps);
10304fb2745SSam Leffler static int  pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len);
10404fb2745SSam Leffler static int  pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp);
10504fb2745SSam Leffler 
10604fb2745SSam Leffler static int  ndis_probe (struct device *dev);
10704fb2745SSam Leffler static int  pkt_probe  (struct device *dev);
10804fb2745SSam Leffler 
10904fb2745SSam Leffler static void close_driver (void);
11004fb2745SSam Leffler static int  init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf);
11104fb2745SSam Leffler static int  first_init (const char *name, char *ebuf, int promisc);
11204fb2745SSam Leffler 
11304fb2745SSam Leffler static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
11404fb2745SSam Leffler                               const u_char *buf);
11504fb2745SSam Leffler 
11604fb2745SSam Leffler /*
11704fb2745SSam Leffler  * These are the device we always support
11804fb2745SSam Leffler  */
11904fb2745SSam Leffler static struct device ndis_dev = {
12004fb2745SSam Leffler               "ndis",
12104fb2745SSam Leffler               "NDIS2 LanManager",
12204fb2745SSam Leffler               0,
12304fb2745SSam Leffler               0,0,0,0,0,0,
12404fb2745SSam Leffler               NDIS_NEXT_DEV,  /* NULL or a 32-bit device */
12504fb2745SSam Leffler               ndis_probe
12604fb2745SSam Leffler             };
12704fb2745SSam Leffler 
12804fb2745SSam Leffler static struct device pkt_dev = {
12904fb2745SSam Leffler               "pkt",
13004fb2745SSam Leffler               "Packet-Driver",
13104fb2745SSam Leffler               0,
13204fb2745SSam Leffler               0,0,0,0,0,0,
13304fb2745SSam Leffler               &ndis_dev,
13404fb2745SSam Leffler               pkt_probe
13504fb2745SSam Leffler             };
13604fb2745SSam Leffler 
13704fb2745SSam Leffler static struct device *get_device (int fd)
13804fb2745SSam Leffler {
13904fb2745SSam Leffler   if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0]))
14004fb2745SSam Leffler      return (NULL);
14104fb2745SSam Leffler   return handle_to_device [fd-1];
14204fb2745SSam Leffler }
14304fb2745SSam Leffler 
144681ed54cSXin LI /*
145681ed54cSXin LI  * Private data for capturing on MS-DOS.
146681ed54cSXin LI  */
147681ed54cSXin LI struct pcap_dos {
148681ed54cSXin LI 	void (*wait_proc)(void); /* call proc while waiting */
149681ed54cSXin LI 	struct pcap_stat stat;
150681ed54cSXin LI };
151681ed54cSXin LI 
152*ada6f083SXin LI pcap_t *pcap_create_interface (const char *device _U_, char *ebuf)
153a8e07101SRui Paulo {
154a8e07101SRui Paulo 	pcap_t *p;
155a8e07101SRui Paulo 
156*ada6f083SXin LI 	p = pcap_create_common(ebuf, sizeof (struct pcap_dos));
157a8e07101SRui Paulo 	if (p == NULL)
158a8e07101SRui Paulo 		return (NULL);
159a8e07101SRui Paulo 
160a8e07101SRui Paulo 	p->activate_op = pcap_activate_dos;
161a8e07101SRui Paulo 	return (p);
162a8e07101SRui Paulo }
163a8e07101SRui Paulo 
16404fb2745SSam Leffler /*
16504fb2745SSam Leffler  * Open MAC-driver with name 'device_name' for live capture of
16604fb2745SSam Leffler  * network packets.
16704fb2745SSam Leffler  */
168a8e07101SRui Paulo static int pcap_activate_dos (pcap_t *pcap)
16904fb2745SSam Leffler {
170a8e07101SRui Paulo   if (pcap->opt.rfmon) {
171a8e07101SRui Paulo     /*
172a8e07101SRui Paulo      * No monitor mode on DOS.
173a8e07101SRui Paulo      */
174a8e07101SRui Paulo     return (PCAP_ERROR_RFMON_NOTSUP);
17504fb2745SSam Leffler   }
17604fb2745SSam Leffler 
177a8e07101SRui Paulo   if (pcap->snapshot < ETH_MIN+8)
178a8e07101SRui Paulo       pcap->snapshot = ETH_MIN+8;
179a8e07101SRui Paulo 
180a8e07101SRui Paulo   if (pcap->snapshot > ETH_MAX)   /* silently accept and truncate large MTUs */
181a8e07101SRui Paulo       pcap->snapshot = ETH_MAX;
182a8e07101SRui Paulo 
18304fb2745SSam Leffler   pcap->linktype          = DLT_EN10MB;  /* !! */
184a8e07101SRui Paulo   pcap->cleanup_op        = pcap_cleanup_dos;
18504fb2745SSam Leffler   pcap->read_op           = pcap_read_dos;
18604fb2745SSam Leffler   pcap->stats_op          = pcap_stats_dos;
18704fb2745SSam Leffler   pcap->inject_op         = pcap_sendpacket_dos;
18804fb2745SSam Leffler   pcap->setfilter_op      = pcap_setfilter_dos;
189ee2dd488SSam Leffler   pcap->setdirection_op   = NULL;  /* Not implemented.*/
19004fb2745SSam Leffler   pcap->fd                = ++ref_count;
19104fb2745SSam Leffler 
192*ada6f083SXin LI   pcap->bufsize = ETH_MAX+100;     /* add some margin */
193*ada6f083SXin LI   pcap->buffer = calloc (pcap->bufsize, 1);
194*ada6f083SXin LI 
19504fb2745SSam Leffler   if (pcap->fd == 1)  /* first time we're called */
19604fb2745SSam Leffler   {
197*ada6f083SXin LI     if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) ||
198*ada6f083SXin LI         !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc))
19904fb2745SSam Leffler     {
200a8e07101SRui Paulo       return (PCAP_ERROR);
20104fb2745SSam Leffler     }
20204fb2745SSam Leffler     atexit (close_driver);
20304fb2745SSam Leffler   }
204*ada6f083SXin LI   else if (stricmp(active_dev->name,pcap->opt.device))
20504fb2745SSam Leffler   {
206*ada6f083SXin LI     pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
20704fb2745SSam Leffler                    "Cannot use different devices simultaneously "
208*ada6f083SXin LI                    "(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
209a8e07101SRui Paulo     return (PCAP_ERROR);
21004fb2745SSam Leffler   }
21104fb2745SSam Leffler   handle_to_device [pcap->fd-1] = active_dev;
212a8e07101SRui Paulo   return (0);
21304fb2745SSam Leffler }
21404fb2745SSam Leffler 
21504fb2745SSam Leffler /*
21604fb2745SSam Leffler  * Poll the receiver queue and call the pcap callback-handler
21704fb2745SSam Leffler  * with the packet.
21804fb2745SSam Leffler  */
21904fb2745SSam Leffler static int
22004fb2745SSam Leffler pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
22104fb2745SSam Leffler {
222681ed54cSXin LI   struct pcap_dos *pd = p->priv;
22304fb2745SSam Leffler   struct pcap_pkthdr pcap;
224681ed54cSXin LI   struct timeval     now, expiry = { 0,0 };
22504fb2745SSam Leffler   int    rx_len = 0;
22604fb2745SSam Leffler 
227681ed54cSXin LI   if (p->opt.timeout > 0)
22804fb2745SSam Leffler   {
22904fb2745SSam Leffler     gettimeofday2 (&now, NULL);
230681ed54cSXin LI     expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout;
23104fb2745SSam Leffler     expiry.tv_sec  = now.tv_sec;
23204fb2745SSam Leffler     while (expiry.tv_usec >= 1000000L)
23304fb2745SSam Leffler     {
23404fb2745SSam Leffler       expiry.tv_usec -= 1000000L;
23504fb2745SSam Leffler       expiry.tv_sec++;
23604fb2745SSam Leffler     }
23704fb2745SSam Leffler   }
23804fb2745SSam Leffler 
23904fb2745SSam Leffler   while (!exc_occured)
24004fb2745SSam Leffler   {
24104fb2745SSam Leffler     volatile struct device *dev; /* might be reset by sig_handler */
24204fb2745SSam Leffler 
24304fb2745SSam Leffler     dev = get_device (p->fd);
24404fb2745SSam Leffler     if (!dev)
24504fb2745SSam Leffler        break;
24604fb2745SSam Leffler 
24704fb2745SSam Leffler     PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf);
24804fb2745SSam Leffler     FLUSHK();
24904fb2745SSam Leffler 
25004fb2745SSam Leffler     /* If driver has a zero-copy receive facility, peek at the queue,
25104fb2745SSam Leffler      * filter it, do the callback and release the buffer.
25204fb2745SSam Leffler      */
25304fb2745SSam Leffler     if (dev->peek_rx_buf)
25404fb2745SSam Leffler     {
25504fb2745SSam Leffler       PCAP_ASSERT (dev->release_rx_buf);
256*ada6f083SXin LI       rx_len = (*dev->peek_rx_buf) (&p->buffer);
25704fb2745SSam Leffler     }
25804fb2745SSam Leffler     else
25904fb2745SSam Leffler     {
260*ada6f083SXin LI       rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot);
26104fb2745SSam Leffler     }
26204fb2745SSam Leffler 
26304fb2745SSam Leffler     if (rx_len > 0)  /* got a packet */
26404fb2745SSam Leffler     {
26504fb2745SSam Leffler       mac_count++;
26604fb2745SSam Leffler 
26704fb2745SSam Leffler       FLUSHK();
26804fb2745SSam Leffler 
26904fb2745SSam Leffler       pcap.caplen = min (rx_len, p->snapshot);
27004fb2745SSam Leffler       pcap.len    = rx_len;
27104fb2745SSam Leffler 
27204fb2745SSam Leffler       if (callback &&
273*ada6f083SXin LI           (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
27404fb2745SSam Leffler       {
27504fb2745SSam Leffler         filter_count++;
27604fb2745SSam Leffler 
27704fb2745SSam Leffler         /* Fix-me!! Should be time of arrival. Not time of
27804fb2745SSam Leffler          * capture.
27904fb2745SSam Leffler          */
28004fb2745SSam Leffler         gettimeofday2 (&pcap.ts, NULL);
281*ada6f083SXin LI         (*callback) (data, &pcap, p->buffer);
28204fb2745SSam Leffler       }
28304fb2745SSam Leffler 
28404fb2745SSam Leffler       if (dev->release_rx_buf)
285*ada6f083SXin LI         (*dev->release_rx_buf) (p->buffer);
28604fb2745SSam Leffler 
28704fb2745SSam Leffler       if (pcap_pkt_debug > 0)
28804fb2745SSam Leffler       {
28904fb2745SSam Leffler         if (callback == watt32_recv_hook)
29004fb2745SSam Leffler              dbug_write ("pcap_recv_hook\n");
29104fb2745SSam Leffler         else dbug_write ("pcap_read_op\n");
29204fb2745SSam Leffler       }
29304fb2745SSam Leffler       FLUSHK();
29404fb2745SSam Leffler       return (1);
29504fb2745SSam Leffler     }
29604fb2745SSam Leffler 
297*ada6f083SXin LI     /* Has "pcap_breakloop()" been called?
298*ada6f083SXin LI      */
299*ada6f083SXin LI     if (p->break_loop) {
300*ada6f083SXin LI       /*
301*ada6f083SXin LI        * Yes - clear the flag that indicates that it
302*ada6f083SXin LI        * has, and return -2 to indicate that we were
303*ada6f083SXin LI        * told to break out of the loop.
304*ada6f083SXin LI        */
305*ada6f083SXin LI       p->break_loop = 0;
306*ada6f083SXin LI       return (-2);
307*ada6f083SXin LI     }
308*ada6f083SXin LI 
309681ed54cSXin LI     /* If not to wait for a packet or pcap_cleanup_dos() called from
31004fb2745SSam Leffler      * e.g. SIGINT handler, exit loop now.
31104fb2745SSam Leffler      */
312681ed54cSXin LI     if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0)
31304fb2745SSam Leffler        break;
31404fb2745SSam Leffler 
31504fb2745SSam Leffler     gettimeofday2 (&now, NULL);
31604fb2745SSam Leffler 
31704fb2745SSam Leffler     if (timercmp(&now, &expiry, >))
31804fb2745SSam Leffler        break;
31904fb2745SSam Leffler 
32004fb2745SSam Leffler #ifndef DJGPP
32104fb2745SSam Leffler     kbhit();    /* a real CPU hog */
32204fb2745SSam Leffler #endif
32304fb2745SSam Leffler 
324*ada6f083SXin LI     if (pd->wait_proc)
325*ada6f083SXin LI       (*pd->wait_proc)();     /* call yield func */
32604fb2745SSam Leffler   }
32704fb2745SSam Leffler 
32804fb2745SSam Leffler   if (rx_len < 0)            /* receive error */
32904fb2745SSam Leffler   {
330681ed54cSXin LI     pd->stat.ps_drop++;
33104fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
33204fb2745SSam Leffler     if (pcap_pkt_debug > 1)
33304fb2745SSam Leffler        printk ("pkt-err %s\n", pktInfo.error);
33404fb2745SSam Leffler #endif
33504fb2745SSam Leffler     return (-1);
33604fb2745SSam Leffler   }
33704fb2745SSam Leffler   return (0);
33804fb2745SSam Leffler }
33904fb2745SSam Leffler 
34004fb2745SSam Leffler static int
34104fb2745SSam Leffler pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data)
34204fb2745SSam Leffler {
34304fb2745SSam Leffler   int rc, num = 0;
34404fb2745SSam Leffler 
345681ed54cSXin LI   while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt))
34604fb2745SSam Leffler   {
34704fb2745SSam Leffler     if (p->fd <= 0)
34804fb2745SSam Leffler        return (-1);
34904fb2745SSam Leffler     rc = pcap_read_one (p, callback, data);
35004fb2745SSam Leffler     if (rc > 0)
35104fb2745SSam Leffler        num++;
35204fb2745SSam Leffler     if (rc < 0)
35304fb2745SSam Leffler        break;
35404fb2745SSam Leffler     _w32_os_yield();  /* allow SIGINT generation, yield to Win95/NT */
35504fb2745SSam Leffler   }
35604fb2745SSam Leffler   return (num);
35704fb2745SSam Leffler }
35804fb2745SSam Leffler 
35904fb2745SSam Leffler /*
36004fb2745SSam Leffler  * Return network statistics
36104fb2745SSam Leffler  */
36204fb2745SSam Leffler static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps)
36304fb2745SSam Leffler {
36404fb2745SSam Leffler   struct net_device_stats *stats;
365681ed54cSXin LI   struct pcap_dos         *pd;
36604fb2745SSam Leffler   struct device           *dev = p ? get_device(p->fd) : NULL;
36704fb2745SSam Leffler 
36804fb2745SSam Leffler   if (!dev)
36904fb2745SSam Leffler   {
37004fb2745SSam Leffler     strcpy (p->errbuf, "illegal pcap handle");
37104fb2745SSam Leffler     return (-1);
37204fb2745SSam Leffler   }
37304fb2745SSam Leffler 
37404fb2745SSam Leffler   if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL)
37504fb2745SSam Leffler   {
37604fb2745SSam Leffler     strcpy (p->errbuf, "device statistics not available");
37704fb2745SSam Leffler     return (-1);
37804fb2745SSam Leffler   }
37904fb2745SSam Leffler 
38004fb2745SSam Leffler   FLUSHK();
38104fb2745SSam Leffler 
382681ed54cSXin LI   pd = p->priv;
383681ed54cSXin LI   pd->stat.ps_recv   = stats->rx_packets;
384681ed54cSXin LI   pd->stat.ps_drop  += stats->rx_missed_errors;
385681ed54cSXin LI   pd->stat.ps_ifdrop = stats->rx_dropped +  /* queue full */
38604fb2745SSam Leffler                          stats->rx_errors;    /* HW errors */
38704fb2745SSam Leffler   if (ps)
388681ed54cSXin LI      *ps = pd->stat;
38904fb2745SSam Leffler 
39004fb2745SSam Leffler   return (0);
39104fb2745SSam Leffler }
39204fb2745SSam Leffler 
39304fb2745SSam Leffler /*
39404fb2745SSam Leffler  * Return detailed network/device statistics.
39504fb2745SSam Leffler  * May be called after 'dev->close' is called.
39604fb2745SSam Leffler  */
39704fb2745SSam Leffler int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se)
39804fb2745SSam Leffler {
39904fb2745SSam Leffler   struct device *dev = p ? get_device (p->fd) : NULL;
40004fb2745SSam Leffler 
40104fb2745SSam Leffler   if (!dev || !dev->get_stats)
40204fb2745SSam Leffler   {
40304fb2745SSam Leffler     strlcpy (p->errbuf, "detailed device statistics not available",
40404fb2745SSam Leffler              PCAP_ERRBUF_SIZE);
40504fb2745SSam Leffler     return (-1);
40604fb2745SSam Leffler   }
40704fb2745SSam Leffler 
40804fb2745SSam Leffler   if (!strnicmp(dev->name,"pkt",3))
40904fb2745SSam Leffler   {
41004fb2745SSam Leffler     strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics",
41104fb2745SSam Leffler              PCAP_ERRBUF_SIZE);
41204fb2745SSam Leffler     return (-1);
41304fb2745SSam Leffler   }
41404fb2745SSam Leffler   memcpy (se, (*dev->get_stats)(dev), sizeof(*se));
41504fb2745SSam Leffler   return (0);
41604fb2745SSam Leffler }
41704fb2745SSam Leffler 
41804fb2745SSam Leffler /*
41904fb2745SSam Leffler  * Simply store the filter-code for the pcap_read_dos() callback
42004fb2745SSam Leffler  * Some day the filter-code could be handed down to the active
42104fb2745SSam Leffler  * device (pkt_rx1.s or 32-bit device interrupt handler).
42204fb2745SSam Leffler  */
42304fb2745SSam Leffler static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp)
42404fb2745SSam Leffler {
42504fb2745SSam Leffler   if (!p)
42604fb2745SSam Leffler      return (-1);
42704fb2745SSam Leffler   p->fcode = *fp;
42804fb2745SSam Leffler   return (0);
42904fb2745SSam Leffler }
43004fb2745SSam Leffler 
43104fb2745SSam Leffler /*
43204fb2745SSam Leffler  * Return # of packets received in pcap_read_dos()
43304fb2745SSam Leffler  */
43404fb2745SSam Leffler u_long pcap_mac_packets (void)
43504fb2745SSam Leffler {
43604fb2745SSam Leffler   return (mac_count);
43704fb2745SSam Leffler }
43804fb2745SSam Leffler 
43904fb2745SSam Leffler /*
44004fb2745SSam Leffler  * Return # of packets passed through filter in pcap_read_dos()
44104fb2745SSam Leffler  */
44204fb2745SSam Leffler u_long pcap_filter_packets (void)
44304fb2745SSam Leffler {
44404fb2745SSam Leffler   return (filter_count);
44504fb2745SSam Leffler }
44604fb2745SSam Leffler 
44704fb2745SSam Leffler /*
44804fb2745SSam Leffler  * Close pcap device. Not called for offline captures.
44904fb2745SSam Leffler  */
450a8e07101SRui Paulo static void pcap_cleanup_dos (pcap_t *p)
45104fb2745SSam Leffler {
452681ed54cSXin LI   struct pcap_dos *pd;
453681ed54cSXin LI 
454*ada6f083SXin LI   if (!exc_occured)
45504fb2745SSam Leffler   {
456681ed54cSXin LI     pd = p->priv;
45704fb2745SSam Leffler     if (pcap_stats(p,NULL) < 0)
458681ed54cSXin LI        pd->stat.ps_drop = 0;
45904fb2745SSam Leffler     if (!get_device(p->fd))
46004fb2745SSam Leffler        return;
46104fb2745SSam Leffler 
46204fb2745SSam Leffler     handle_to_device [p->fd-1] = NULL;
46304fb2745SSam Leffler     p->fd = 0;
46404fb2745SSam Leffler     if (ref_count > 0)
46504fb2745SSam Leffler         ref_count--;
46604fb2745SSam Leffler     if (ref_count > 0)
46704fb2745SSam Leffler        return;
46804fb2745SSam Leffler   }
46904fb2745SSam Leffler   close_driver();
47004fb2745SSam Leffler }
47104fb2745SSam Leffler 
47204fb2745SSam Leffler /*
47304fb2745SSam Leffler  * Return the name of the 1st network interface,
47404fb2745SSam Leffler  * or NULL if none can be found.
47504fb2745SSam Leffler  */
47604fb2745SSam Leffler char *pcap_lookupdev (char *ebuf)
47704fb2745SSam Leffler {
47804fb2745SSam Leffler   struct device *dev;
47904fb2745SSam Leffler 
48004fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
48104fb2745SSam Leffler   init_32bit();
48204fb2745SSam Leffler #endif
48304fb2745SSam Leffler 
48404fb2745SSam Leffler   for (dev = (struct device*)dev_base; dev; dev = dev->next)
48504fb2745SSam Leffler   {
48604fb2745SSam Leffler     PCAP_ASSERT (dev->probe);
48704fb2745SSam Leffler 
48804fb2745SSam Leffler     if ((*dev->probe)(dev))
48904fb2745SSam Leffler     {
49004fb2745SSam Leffler       FLUSHK();
49104fb2745SSam Leffler       probed_dev = (struct device*) dev; /* remember last probed device */
49204fb2745SSam Leffler       return (char*) dev->name;
49304fb2745SSam Leffler     }
49404fb2745SSam Leffler   }
49504fb2745SSam Leffler 
49604fb2745SSam Leffler   if (ebuf)
49704fb2745SSam Leffler      strcpy (ebuf, "No driver found");
49804fb2745SSam Leffler   return (NULL);
49904fb2745SSam Leffler }
50004fb2745SSam Leffler 
50104fb2745SSam Leffler /*
50204fb2745SSam Leffler  * Gets localnet & netmask from Watt-32.
50304fb2745SSam Leffler  */
50404fb2745SSam Leffler int pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
50504fb2745SSam Leffler                     bpf_u_int32 *netmask, char *errbuf)
50604fb2745SSam Leffler {
507*ada6f083SXin LI   DWORD mask, net;
508*ada6f083SXin LI 
50904fb2745SSam Leffler   if (!_watt_is_init)
51004fb2745SSam Leffler   {
511a8e07101SRui Paulo     strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be "
51204fb2745SSam Leffler                     "called first");
51304fb2745SSam Leffler     return (-1);
51404fb2745SSam Leffler   }
51504fb2745SSam Leffler 
516*ada6f083SXin LI   mask  = _w32_sin_mask;
517*ada6f083SXin LI   net = my_ip_addr & mask;
518*ada6f083SXin LI   if (net == 0)
51904fb2745SSam Leffler   {
52004fb2745SSam Leffler     if (IN_CLASSA(*netmask))
521*ada6f083SXin LI        net = IN_CLASSA_NET;
52204fb2745SSam Leffler     else if (IN_CLASSB(*netmask))
523*ada6f083SXin LI        net = IN_CLASSB_NET;
52404fb2745SSam Leffler     else if (IN_CLASSC(*netmask))
525*ada6f083SXin LI        net = IN_CLASSC_NET;
52604fb2745SSam Leffler     else
52704fb2745SSam Leffler     {
528*ada6f083SXin LI       pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
52904fb2745SSam Leffler       return (-1);
53004fb2745SSam Leffler     }
53104fb2745SSam Leffler   }
532*ada6f083SXin LI   *localnet = htonl (net);
533*ada6f083SXin LI   *netmask = htonl (mask);
534*ada6f083SXin LI 
53504fb2745SSam Leffler   ARGSUSED (device);
53604fb2745SSam Leffler   return (0);
53704fb2745SSam Leffler }
53804fb2745SSam Leffler 
53904fb2745SSam Leffler /*
54004fb2745SSam Leffler  * Get a list of all interfaces that are present and that we probe okay.
54104fb2745SSam Leffler  * Returns -1 on error, 0 otherwise.
542*ada6f083SXin LI  * The list, as returned through "alldevsp", may be NULL if no interfaces
54304fb2745SSam Leffler  * were up and could be opened.
54404fb2745SSam Leffler  */
545*ada6f083SXin LI int pcap_platform_finddevs  (pcap_if_t **alldevsp, char *errbuf)
54604fb2745SSam Leffler {
54704fb2745SSam Leffler   struct device     *dev;
548*ada6f083SXin LI   struct sockaddr_in sa_ll_1, sa_ll_2;
54904fb2745SSam Leffler   struct sockaddr   *addr, *netmask, *broadaddr, *dstaddr;
55004fb2745SSam Leffler   pcap_if_t *devlist = NULL;
55104fb2745SSam Leffler   int       ret = 0;
552*ada6f083SXin LI   size_t    addr_size = sizeof(*addr);
55304fb2745SSam Leffler 
55404fb2745SSam Leffler   for (dev = (struct device*)dev_base; dev; dev = dev->next)
55504fb2745SSam Leffler   {
55604fb2745SSam Leffler     PCAP_ASSERT (dev->probe);
55704fb2745SSam Leffler 
55804fb2745SSam Leffler     if (!(*dev->probe)(dev))
55904fb2745SSam Leffler        continue;
56004fb2745SSam Leffler 
56104fb2745SSam Leffler     PCAP_ASSERT (dev->close);  /* set by probe routine */
56204fb2745SSam Leffler     FLUSHK();
56304fb2745SSam Leffler     (*dev->close) (dev);
56404fb2745SSam Leffler 
56504fb2745SSam Leffler     memset (&sa_ll_1, 0, sizeof(sa_ll_1));
56604fb2745SSam Leffler     memset (&sa_ll_2, 0, sizeof(sa_ll_2));
567*ada6f083SXin LI     sa_ll_1.sin_family = AF_INET;
568*ada6f083SXin LI     sa_ll_2.sin_family = AF_INET;
56904fb2745SSam Leffler 
57004fb2745SSam Leffler     addr      = (struct sockaddr*) &sa_ll_1;
57104fb2745SSam Leffler     netmask   = (struct sockaddr*) &sa_ll_1;
57204fb2745SSam Leffler     dstaddr   = (struct sockaddr*) &sa_ll_1;
57304fb2745SSam Leffler     broadaddr = (struct sockaddr*) &sa_ll_2;
574*ada6f083SXin LI     memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr));
57504fb2745SSam Leffler 
57604fb2745SSam Leffler     if (pcap_add_if(&devlist, dev->name, dev->flags,
57704fb2745SSam Leffler                     dev->long_name, errbuf) < 0)
57804fb2745SSam Leffler     {
57904fb2745SSam Leffler       ret = -1;
58004fb2745SSam Leffler       break;
58104fb2745SSam Leffler     }
582*ada6f083SXin LI #if 0   /* Pkt drivers should have no addresses */
58304fb2745SSam Leffler     if (add_addr_to_iflist(&devlist, dev->name, dev->flags, addr, addr_size,
58404fb2745SSam Leffler                            netmask, addr_size, broadaddr, addr_size,
58504fb2745SSam Leffler                            dstaddr, addr_size, errbuf) < 0)
58604fb2745SSam Leffler     {
58704fb2745SSam Leffler       ret = -1;
58804fb2745SSam Leffler       break;
58904fb2745SSam Leffler     }
590*ada6f083SXin LI #endif
59104fb2745SSam Leffler   }
59204fb2745SSam Leffler 
59304fb2745SSam Leffler   if (devlist && ret < 0)
59404fb2745SSam Leffler   {
59504fb2745SSam Leffler     pcap_freealldevs (devlist);
59604fb2745SSam Leffler     devlist = NULL;
59704fb2745SSam Leffler   }
59804fb2745SSam Leffler   else
59904fb2745SSam Leffler   if (!devlist)
60004fb2745SSam Leffler      strcpy (errbuf, "No drivers found");
60104fb2745SSam Leffler 
60204fb2745SSam Leffler   *alldevsp = devlist;
60304fb2745SSam Leffler   return (ret);
60404fb2745SSam Leffler }
60504fb2745SSam Leffler 
60604fb2745SSam Leffler /*
60704fb2745SSam Leffler  * pcap_assert() is mainly used for debugging
60804fb2745SSam Leffler  */
60904fb2745SSam Leffler void pcap_assert (const char *what, const char *file, unsigned line)
61004fb2745SSam Leffler {
61104fb2745SSam Leffler   FLUSHK();
61204fb2745SSam Leffler   fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n",
61304fb2745SSam Leffler            file, line, what);
61404fb2745SSam Leffler   close_driver();
61504fb2745SSam Leffler   _exit (-1);
61604fb2745SSam Leffler }
61704fb2745SSam Leffler 
61804fb2745SSam Leffler /*
61904fb2745SSam Leffler  * For pcap_offline_read(): wait and yield between printing packets
62004fb2745SSam Leffler  * to simulate the pace packets where actually recorded.
62104fb2745SSam Leffler  */
62204fb2745SSam Leffler void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait)
62304fb2745SSam Leffler {
62404fb2745SSam Leffler   if (p)
62504fb2745SSam Leffler   {
626*ada6f083SXin LI     struct pcap_dos *pd = p->priv;
627*ada6f083SXin LI 
628681ed54cSXin LI     pd->wait_proc  = yield;
629681ed54cSXin LI     p->opt.timeout = wait;
63004fb2745SSam Leffler   }
63104fb2745SSam Leffler }
63204fb2745SSam Leffler 
63304fb2745SSam Leffler /*
63404fb2745SSam Leffler  * Initialise a named network device.
63504fb2745SSam Leffler  */
63604fb2745SSam Leffler static struct device *
63704fb2745SSam Leffler open_driver (const char *dev_name, char *ebuf, int promisc)
63804fb2745SSam Leffler {
63904fb2745SSam Leffler   struct device *dev;
64004fb2745SSam Leffler 
64104fb2745SSam Leffler   for (dev = (struct device*)dev_base; dev; dev = dev->next)
64204fb2745SSam Leffler   {
64304fb2745SSam Leffler     PCAP_ASSERT (dev->name);
64404fb2745SSam Leffler 
64504fb2745SSam Leffler     if (strcmp (dev_name,dev->name))
64604fb2745SSam Leffler        continue;
64704fb2745SSam Leffler 
64804fb2745SSam Leffler     if (!probed_dev)   /* user didn't call pcap_lookupdev() first */
64904fb2745SSam Leffler     {
65004fb2745SSam Leffler       PCAP_ASSERT (dev->probe);
65104fb2745SSam Leffler 
65204fb2745SSam Leffler       if (!(*dev->probe)(dev))    /* call the xx_probe() function */
65304fb2745SSam Leffler       {
654*ada6f083SXin LI         pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
65504fb2745SSam Leffler         return (NULL);
65604fb2745SSam Leffler       }
65704fb2745SSam Leffler       probed_dev = dev;  /* device is probed okay and may be used */
65804fb2745SSam Leffler     }
65904fb2745SSam Leffler     else if (dev != probed_dev)
66004fb2745SSam Leffler     {
66104fb2745SSam Leffler       goto not_probed;
66204fb2745SSam Leffler     }
66304fb2745SSam Leffler 
66404fb2745SSam Leffler     FLUSHK();
66504fb2745SSam Leffler 
66604fb2745SSam Leffler     /* Select what traffic to receive
66704fb2745SSam Leffler      */
66804fb2745SSam Leffler     if (promisc)
66904fb2745SSam Leffler          dev->flags |=  (IFF_ALLMULTI | IFF_PROMISC);
67004fb2745SSam Leffler     else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC);
67104fb2745SSam Leffler 
67204fb2745SSam Leffler     PCAP_ASSERT (dev->open);
67304fb2745SSam Leffler 
67404fb2745SSam Leffler     if (!(*dev->open)(dev))
67504fb2745SSam Leffler     {
676*ada6f083SXin LI       pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
67704fb2745SSam Leffler       if (pktInfo.error && !strncmp(dev->name,"pkt",3))
67804fb2745SSam Leffler       {
67904fb2745SSam Leffler         strcat (ebuf, ": ");
68004fb2745SSam Leffler         strcat (ebuf, pktInfo.error);
68104fb2745SSam Leffler       }
68204fb2745SSam Leffler       return (NULL);
68304fb2745SSam Leffler     }
68404fb2745SSam Leffler 
68504fb2745SSam Leffler     /* Some devices need this to operate in promiscous mode
68604fb2745SSam Leffler      */
68704fb2745SSam Leffler     if (promisc && dev->set_multicast_list)
68804fb2745SSam Leffler        (*dev->set_multicast_list) (dev);
68904fb2745SSam Leffler 
69004fb2745SSam Leffler     active_dev = dev;   /* remember our active device */
69104fb2745SSam Leffler     break;
69204fb2745SSam Leffler   }
69304fb2745SSam Leffler 
69404fb2745SSam Leffler   /* 'dev_name' not matched in 'dev_base' list.
69504fb2745SSam Leffler    */
69604fb2745SSam Leffler   if (!dev)
69704fb2745SSam Leffler   {
698*ada6f083SXin LI     pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
69904fb2745SSam Leffler     return (NULL);
70004fb2745SSam Leffler   }
70104fb2745SSam Leffler 
70204fb2745SSam Leffler not_probed:
70304fb2745SSam Leffler   if (!probed_dev)
70404fb2745SSam Leffler   {
705*ada6f083SXin LI     pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
70604fb2745SSam Leffler     return (NULL);
70704fb2745SSam Leffler   }
70804fb2745SSam Leffler   return (dev);
70904fb2745SSam Leffler }
71004fb2745SSam Leffler 
71104fb2745SSam Leffler /*
71204fb2745SSam Leffler  * Deinitialise MAC driver.
71304fb2745SSam Leffler  * Set receive mode back to default mode.
71404fb2745SSam Leffler  */
71504fb2745SSam Leffler static void close_driver (void)
71604fb2745SSam Leffler {
71704fb2745SSam Leffler   /* !!todo: loop over all 'handle_to_device[]' ? */
71804fb2745SSam Leffler   struct device *dev = active_dev;
71904fb2745SSam Leffler 
72004fb2745SSam Leffler   if (dev && dev->close)
72104fb2745SSam Leffler   {
72204fb2745SSam Leffler     (*dev->close) (dev);
72304fb2745SSam Leffler     FLUSHK();
72404fb2745SSam Leffler   }
72504fb2745SSam Leffler 
72604fb2745SSam Leffler   active_dev = NULL;
72704fb2745SSam Leffler 
72804fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
72904fb2745SSam Leffler   if (rx_pool)
73004fb2745SSam Leffler   {
73104fb2745SSam Leffler     k_free (rx_pool);
73204fb2745SSam Leffler     rx_pool = NULL;
73304fb2745SSam Leffler   }
73404fb2745SSam Leffler   if (dev)
73504fb2745SSam Leffler      pcibios_exit();
73604fb2745SSam Leffler #endif
73704fb2745SSam Leffler }
73804fb2745SSam Leffler 
73904fb2745SSam Leffler 
74004fb2745SSam Leffler #ifdef __DJGPP__
74104fb2745SSam Leffler static void setup_signals (void (*handler)(int))
74204fb2745SSam Leffler {
74304fb2745SSam Leffler   signal (SIGSEGV,handler);
74404fb2745SSam Leffler   signal (SIGILL, handler);
74504fb2745SSam Leffler   signal (SIGFPE, handler);
74604fb2745SSam Leffler }
74704fb2745SSam Leffler 
74804fb2745SSam Leffler static void exc_handler (int sig)
74904fb2745SSam Leffler {
75004fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
75104fb2745SSam Leffler   if (active_dev->irq > 0)    /* excludes IRQ 0 */
75204fb2745SSam Leffler   {
75304fb2745SSam Leffler     disable_irq (active_dev->irq);
75404fb2745SSam Leffler     irq_eoi_cmd (active_dev->irq);
75504fb2745SSam Leffler     _printk_safe = 1;
75604fb2745SSam Leffler   }
75704fb2745SSam Leffler #endif
75804fb2745SSam Leffler 
75904fb2745SSam Leffler   switch (sig)
76004fb2745SSam Leffler   {
76104fb2745SSam Leffler     case SIGSEGV:
76204fb2745SSam Leffler          fputs ("Catching SIGSEGV.\n", stderr);
76304fb2745SSam Leffler          break;
76404fb2745SSam Leffler     case SIGILL:
76504fb2745SSam Leffler          fputs ("Catching SIGILL.\n", stderr);
76604fb2745SSam Leffler          break;
76704fb2745SSam Leffler     case SIGFPE:
76804fb2745SSam Leffler          _fpreset();
76904fb2745SSam Leffler          fputs ("Catching SIGFPE.\n", stderr);
77004fb2745SSam Leffler          break;
77104fb2745SSam Leffler     default:
77204fb2745SSam Leffler          fprintf (stderr, "Catching signal %d.\n", sig);
77304fb2745SSam Leffler   }
77404fb2745SSam Leffler   exc_occured = 1;
775*ada6f083SXin LI   close_driver();
77604fb2745SSam Leffler }
77704fb2745SSam Leffler #endif  /* __DJGPP__ */
77804fb2745SSam Leffler 
77904fb2745SSam Leffler 
78004fb2745SSam Leffler /*
781a8e07101SRui Paulo  * Open the pcap device for the first client calling pcap_activate()
78204fb2745SSam Leffler  */
78304fb2745SSam Leffler static int first_init (const char *name, char *ebuf, int promisc)
78404fb2745SSam Leffler {
78504fb2745SSam Leffler   struct device *dev;
78604fb2745SSam Leffler 
78704fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
78804fb2745SSam Leffler   rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE);
78904fb2745SSam Leffler   if (!rx_pool)
79004fb2745SSam Leffler   {
79104fb2745SSam Leffler     strcpy (ebuf, "Not enough memory (Rx pool)");
79204fb2745SSam Leffler     return (0);
79304fb2745SSam Leffler   }
79404fb2745SSam Leffler #endif
79504fb2745SSam Leffler 
79604fb2745SSam Leffler #ifdef __DJGPP__
79704fb2745SSam Leffler   setup_signals (exc_handler);
79804fb2745SSam Leffler #endif
79904fb2745SSam Leffler 
80004fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
80104fb2745SSam Leffler   init_32bit();
80204fb2745SSam Leffler #endif
80304fb2745SSam Leffler 
80404fb2745SSam Leffler   dev = open_driver (name, ebuf, promisc);
80504fb2745SSam Leffler   if (!dev)
80604fb2745SSam Leffler   {
80704fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
80804fb2745SSam Leffler     k_free (rx_pool);
80904fb2745SSam Leffler     rx_pool = NULL;
81004fb2745SSam Leffler #endif
81104fb2745SSam Leffler 
81204fb2745SSam Leffler #ifdef __DJGPP__
81304fb2745SSam Leffler     setup_signals (SIG_DFL);
81404fb2745SSam Leffler #endif
81504fb2745SSam Leffler     return (0);
81604fb2745SSam Leffler   }
81704fb2745SSam Leffler 
81804fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
81904fb2745SSam Leffler   /*
82004fb2745SSam Leffler    * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf'
82104fb2745SSam Leffler    * set in it's probe handler), initialise near-memory ring-buffer for
82204fb2745SSam Leffler    * the 32-bit device.
82304fb2745SSam Leffler    */
82404fb2745SSam Leffler   if (dev->copy_rx_buf == NULL)
82504fb2745SSam Leffler   {
82604fb2745SSam Leffler     dev->get_rx_buf     = get_rxbuf;
82704fb2745SSam Leffler     dev->peek_rx_buf    = peek_rxbuf;
82804fb2745SSam Leffler     dev->release_rx_buf = release_rxbuf;
82904fb2745SSam Leffler     pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool);
83004fb2745SSam Leffler   }
83104fb2745SSam Leffler #endif
83204fb2745SSam Leffler   return (1);
83304fb2745SSam Leffler }
83404fb2745SSam Leffler 
83504fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
83604fb2745SSam Leffler static void init_32bit (void)
83704fb2745SSam Leffler {
83804fb2745SSam Leffler   static int init_pci = 0;
83904fb2745SSam Leffler 
84004fb2745SSam Leffler   if (!_printk_file)
84104fb2745SSam Leffler      _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */
84204fb2745SSam Leffler 
84304fb2745SSam Leffler   if (!init_pci)
84404fb2745SSam Leffler      (void)pci_init();             /* init BIOS32+PCI interface */
84504fb2745SSam Leffler   init_pci = 1;
84604fb2745SSam Leffler }
84704fb2745SSam Leffler #endif
84804fb2745SSam Leffler 
84904fb2745SSam Leffler 
85004fb2745SSam Leffler /*
85104fb2745SSam Leffler  * Hook functions for using Watt-32 together with pcap
85204fb2745SSam Leffler  */
85304fb2745SSam Leffler static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */
85404fb2745SSam Leffler static WORD etype;
85504fb2745SSam Leffler static pcap_t pcap_save;
85604fb2745SSam Leffler 
85704fb2745SSam Leffler static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap,
85804fb2745SSam Leffler                               const u_char *buf)
85904fb2745SSam Leffler {
86004fb2745SSam Leffler   /* Fix me: assumes Ethernet II only */
86104fb2745SSam Leffler   struct ether_header *ep = (struct ether_header*) buf;
86204fb2745SSam Leffler 
86304fb2745SSam Leffler   memcpy (rxbuf, buf, pcap->caplen);
86404fb2745SSam Leffler   etype = ep->ether_type;
86504fb2745SSam Leffler   ARGSUSED (dummy);
86604fb2745SSam Leffler }
86704fb2745SSam Leffler 
86804fb2745SSam Leffler #if (WATTCP_VER >= 0x0224)
86904fb2745SSam Leffler /*
87004fb2745SSam Leffler  * This function is used by Watt-32 to poll for a packet.
87104fb2745SSam Leffler  * i.e. it's set to bypass _eth_arrived()
87204fb2745SSam Leffler  */
87304fb2745SSam Leffler static void *pcap_recv_hook (WORD *type)
87404fb2745SSam Leffler {
87504fb2745SSam Leffler   int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL);
87604fb2745SSam Leffler 
87704fb2745SSam Leffler   if (len < 0)
87804fb2745SSam Leffler      return (NULL);
87904fb2745SSam Leffler 
88004fb2745SSam Leffler   *type = etype;
88104fb2745SSam Leffler   return (void*) &rxbuf;
88204fb2745SSam Leffler }
88304fb2745SSam Leffler 
88404fb2745SSam Leffler /*
88504fb2745SSam Leffler  * This function is called by Watt-32 (via _eth_xmit_hook).
88604fb2745SSam Leffler  * If dbug_init() was called, we should trace packets sent.
88704fb2745SSam Leffler  */
88804fb2745SSam Leffler static int pcap_xmit_hook (const void *buf, unsigned len)
88904fb2745SSam Leffler {
89004fb2745SSam Leffler   int rc = 0;
89104fb2745SSam Leffler 
89204fb2745SSam Leffler   if (pcap_pkt_debug > 0)
89304fb2745SSam Leffler      dbug_write ("pcap_xmit_hook: ");
89404fb2745SSam Leffler 
89504fb2745SSam Leffler   if (active_dev && active_dev->xmit)
89604fb2745SSam Leffler      if ((*active_dev->xmit) (active_dev, buf, len) > 0)
89704fb2745SSam Leffler         rc = len;
89804fb2745SSam Leffler 
89904fb2745SSam Leffler   if (pcap_pkt_debug > 0)
90004fb2745SSam Leffler      dbug_write (rc ? "ok\n" : "fail\n");
90104fb2745SSam Leffler   return (rc);
90204fb2745SSam Leffler }
90304fb2745SSam Leffler #endif
90404fb2745SSam Leffler 
90504fb2745SSam Leffler static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len)
90604fb2745SSam Leffler {
90704fb2745SSam Leffler   struct device *dev = p ? get_device(p->fd) : NULL;
90804fb2745SSam Leffler 
90904fb2745SSam Leffler   if (!dev || !dev->xmit)
91004fb2745SSam Leffler      return (-1);
91104fb2745SSam Leffler   return (*dev->xmit) (dev, buf, len);
91204fb2745SSam Leffler }
91304fb2745SSam Leffler 
91404fb2745SSam Leffler /*
91504fb2745SSam Leffler  * This function is called by Watt-32 in tcp_post_init().
91604fb2745SSam Leffler  * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc.
91704fb2745SSam Leffler  */
91804fb2745SSam Leffler static void (*prev_post_hook) (void);
91904fb2745SSam Leffler 
92004fb2745SSam Leffler static void pcap_init_hook (void)
92104fb2745SSam Leffler {
92204fb2745SSam Leffler   _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0;
92304fb2745SSam Leffler   _w32__do_mask_req = 0;
92404fb2745SSam Leffler   _w32_dynamic_host = 0;
92504fb2745SSam Leffler   if (prev_post_hook)
92604fb2745SSam Leffler     (*prev_post_hook)();
92704fb2745SSam Leffler }
92804fb2745SSam Leffler 
92904fb2745SSam Leffler /*
93004fb2745SSam Leffler  * Supress PRINT message from Watt-32's sock_init()
93104fb2745SSam Leffler  */
93204fb2745SSam Leffler static void null_print (void) {}
93304fb2745SSam Leffler 
93404fb2745SSam Leffler /*
93504fb2745SSam Leffler  * To use features of Watt-32 (netdb functions and socket etc.)
93604fb2745SSam Leffler  * we must call sock_init(). But we set various hooks to prevent
93704fb2745SSam Leffler  * using normal PKTDRVR functions in pcpkt.c. This should hopefully
93804fb2745SSam Leffler  * make Watt-32 and pcap co-operate.
93904fb2745SSam Leffler  */
94004fb2745SSam Leffler static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
94104fb2745SSam Leffler {
94204fb2745SSam Leffler   char *env;
94304fb2745SSam Leffler   int   rc, MTU, has_ip_addr;
94404fb2745SSam Leffler   int   using_pktdrv = 1;
94504fb2745SSam Leffler 
94604fb2745SSam Leffler   /* If user called sock_init() first, we need to reinit in
94704fb2745SSam Leffler    * order to open debug/trace-file properly
94804fb2745SSam Leffler    */
94904fb2745SSam Leffler   if (_watt_is_init)
95004fb2745SSam Leffler      sock_exit();
95104fb2745SSam Leffler 
952*ada6f083SXin LI   env = getenv ("PCAP_TRACE");
95304fb2745SSam Leffler   if (env && atoi(env) > 0 &&
95404fb2745SSam Leffler       pcap_pkt_debug < 0)   /* if not already set */
95504fb2745SSam Leffler   {
95604fb2745SSam Leffler     dbug_init();
95704fb2745SSam Leffler     pcap_pkt_debug = atoi (env);
95804fb2745SSam Leffler   }
95904fb2745SSam Leffler 
96004fb2745SSam Leffler   _watt_do_exit      = 0;    /* prevent sock_init() calling exit() */
96104fb2745SSam Leffler   prev_post_hook     = _w32_usr_post_init;
96204fb2745SSam Leffler   _w32_usr_post_init = pcap_init_hook;
96304fb2745SSam Leffler   _w32_print_hook    = null_print;
96404fb2745SSam Leffler 
96504fb2745SSam Leffler   if (dev_name && strncmp(dev_name,"pkt",3))
96604fb2745SSam Leffler      using_pktdrv = FALSE;
96704fb2745SSam Leffler 
96804fb2745SSam Leffler   rc = sock_init();
96904fb2745SSam Leffler   has_ip_addr = (rc != 8);  /* IP-address assignment failed */
97004fb2745SSam Leffler 
97104fb2745SSam Leffler   /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we
97204fb2745SSam Leffler    * just pretend Watt-32 is initialised okay.
97304fb2745SSam Leffler    *
97404fb2745SSam Leffler    * !! fix-me: The Watt-32 config isn't done if no pktdrvr
97504fb2745SSam Leffler    *            was found. In that case my_ip_addr + sin_mask
97604fb2745SSam Leffler    *            have default values. Should be taken from another
97704fb2745SSam Leffler    *            ini-file/environment in any case (ref. tcpdump.ini)
97804fb2745SSam Leffler    */
97904fb2745SSam Leffler   _watt_is_init = 1;
98004fb2745SSam Leffler 
98104fb2745SSam Leffler   if (!using_pktdrv || !has_ip_addr)  /* for now .... */
98204fb2745SSam Leffler   {
98304fb2745SSam Leffler     static const char myip[] = "192.168.0.1";
98404fb2745SSam Leffler     static const char mask[] = "255.255.255.0";
98504fb2745SSam Leffler 
98604fb2745SSam Leffler     printf ("Just guessing, using IP %s and netmask %s\n", myip, mask);
98704fb2745SSam Leffler     my_ip_addr    = aton (myip);
98804fb2745SSam Leffler     _w32_sin_mask = aton (mask);
98904fb2745SSam Leffler   }
99004fb2745SSam Leffler   else if (rc && using_pktdrv)
99104fb2745SSam Leffler   {
992*ada6f083SXin LI     pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
99304fb2745SSam Leffler     return (0);
99404fb2745SSam Leffler   }
99504fb2745SSam Leffler 
99604fb2745SSam Leffler   /* Set recv-hook for peeking in _eth_arrived().
99704fb2745SSam Leffler    */
99804fb2745SSam Leffler #if (WATTCP_VER >= 0x0224)
99904fb2745SSam Leffler   _eth_recv_hook = pcap_recv_hook;
100004fb2745SSam Leffler   _eth_xmit_hook = pcap_xmit_hook;
100104fb2745SSam Leffler #endif
100204fb2745SSam Leffler 
100304fb2745SSam Leffler   /* Free the pkt-drvr handle allocated in pkt_init().
100404fb2745SSam Leffler    * The above hooks should thus use the handle reopened in open_driver()
100504fb2745SSam Leffler    */
100604fb2745SSam Leffler   if (using_pktdrv)
100704fb2745SSam Leffler   {
100804fb2745SSam Leffler     _eth_release();
100904fb2745SSam Leffler /*  _eth_is_init = 1; */  /* hack to get Rx/Tx-hooks in Watt-32 working */
101004fb2745SSam Leffler   }
101104fb2745SSam Leffler 
101204fb2745SSam Leffler   memcpy (&pcap_save, pcap, sizeof(pcap_save));
101304fb2745SSam Leffler   MTU = pkt_get_mtu();
101404fb2745SSam Leffler   pcap_save.fcode.bf_insns = NULL;
101504fb2745SSam Leffler   pcap_save.linktype       = _eth_get_hwtype (NULL, NULL);
101604fb2745SSam Leffler   pcap_save.snapshot       = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
101704fb2745SSam Leffler 
101804fb2745SSam Leffler #if 1
101904fb2745SSam Leffler   /* prevent use of resolve() and resolve_ip()
102004fb2745SSam Leffler    */
102104fb2745SSam Leffler   last_nameserver = 0;
102204fb2745SSam Leffler #endif
102304fb2745SSam Leffler   return (1);
102404fb2745SSam Leffler }
102504fb2745SSam Leffler 
102604fb2745SSam Leffler int EISA_bus = 0;  /* Where is natural place for this? */
102704fb2745SSam Leffler 
102804fb2745SSam Leffler /*
102904fb2745SSam Leffler  * Application config hooks to set various driver parameters.
103004fb2745SSam Leffler  */
103104fb2745SSam Leffler 
1032a8e07101SRui Paulo static const struct config_table debug_tab[] = {
103304fb2745SSam Leffler             { "PKT.DEBUG",       ARG_ATOI,   &pcap_pkt_debug    },
103404fb2745SSam Leffler             { "PKT.VECTOR",      ARG_ATOX_W, NULL               },
103504fb2745SSam Leffler             { "NDIS.DEBUG",      ARG_ATOI,   NULL               },
103604fb2745SSam Leffler #ifdef USE_32BIT_DRIVERS
103704fb2745SSam Leffler             { "3C503.DEBUG",     ARG_ATOI,   &ei_debug          },
103804fb2745SSam Leffler             { "3C503.IO_BASE",   ARG_ATOX_W, &el2_dev.base_addr },
103904fb2745SSam Leffler             { "3C503.MEMORY",    ARG_ATOX_W, &el2_dev.mem_start },
104004fb2745SSam Leffler             { "3C503.IRQ",       ARG_ATOI,   &el2_dev.irq       },
104104fb2745SSam Leffler             { "3C505.DEBUG",     ARG_ATOI,   NULL               },
104204fb2745SSam Leffler             { "3C505.BASE",      ARG_ATOX_W, NULL               },
104304fb2745SSam Leffler             { "3C507.DEBUG",     ARG_ATOI,   NULL               },
104404fb2745SSam Leffler             { "3C509.DEBUG",     ARG_ATOI,   &el3_debug         },
104504fb2745SSam Leffler             { "3C509.ILOOP",     ARG_ATOI,   &el3_max_loop      },
104604fb2745SSam Leffler             { "3C529.DEBUG",     ARG_ATOI,   NULL               },
104704fb2745SSam Leffler             { "3C575.DEBUG",     ARG_ATOI,   &debug_3c575       },
104804fb2745SSam Leffler             { "3C59X.DEBUG",     ARG_ATOI,   &vortex_debug      },
104904fb2745SSam Leffler             { "3C59X.IFACE0",    ARG_ATOI,   &vortex_options[0] },
105004fb2745SSam Leffler             { "3C59X.IFACE1",    ARG_ATOI,   &vortex_options[1] },
105104fb2745SSam Leffler             { "3C59X.IFACE2",    ARG_ATOI,   &vortex_options[2] },
105204fb2745SSam Leffler             { "3C59X.IFACE3",    ARG_ATOI,   &vortex_options[3] },
105304fb2745SSam Leffler             { "3C90X.DEBUG",     ARG_ATOX_W, &tc90xbc_debug     },
105404fb2745SSam Leffler             { "ACCT.DEBUG",      ARG_ATOI,   &ethpk_debug       },
105504fb2745SSam Leffler             { "CS89.DEBUG",      ARG_ATOI,   &cs89_debug        },
105604fb2745SSam Leffler             { "RTL8139.DEBUG",   ARG_ATOI,   &rtl8139_debug     },
105704fb2745SSam Leffler         /*  { "RTL8139.FDUPLEX", ARG_ATOI,   &rtl8139_options   }, */
105804fb2745SSam Leffler             { "SMC.DEBUG",       ARG_ATOI,   &ei_debug          },
105904fb2745SSam Leffler         /*  { "E100.DEBUG",      ARG_ATOI,   &e100_debug        }, */
106004fb2745SSam Leffler             { "PCI.DEBUG",       ARG_ATOI,   &pci_debug         },
106104fb2745SSam Leffler             { "BIOS32.DEBUG",    ARG_ATOI,   &bios32_debug      },
106204fb2745SSam Leffler             { "IRQ.DEBUG",       ARG_ATOI,   &irq_debug         },
106304fb2745SSam Leffler             { "TIMER.IRQ",       ARG_ATOI,   &timer_irq         },
106404fb2745SSam Leffler #endif
106504fb2745SSam Leffler             { NULL }
106604fb2745SSam Leffler           };
106704fb2745SSam Leffler 
106804fb2745SSam Leffler /*
106904fb2745SSam Leffler  * pcap_config_hook() is an extension to application's config
107004fb2745SSam Leffler  * handling. Uses Watt-32's config-table function.
107104fb2745SSam Leffler  */
1072*ada6f083SXin LI int pcap_config_hook (const char *keyword, const char *value)
107304fb2745SSam Leffler {
1074*ada6f083SXin LI   return parse_config_table (debug_tab, NULL, keyword, value);
107504fb2745SSam Leffler }
107604fb2745SSam Leffler 
107704fb2745SSam Leffler /*
107804fb2745SSam Leffler  * Linked list of supported devices
107904fb2745SSam Leffler  */
108004fb2745SSam Leffler struct device       *active_dev = NULL;      /* the device we have opened */
108104fb2745SSam Leffler struct device       *probed_dev = NULL;      /* the device we have probed */
108204fb2745SSam Leffler const struct device *dev_base   = &pkt_dev;  /* list of network devices */
108304fb2745SSam Leffler 
108404fb2745SSam Leffler /*
108504fb2745SSam Leffler  * PKTDRVR device functions
108604fb2745SSam Leffler  */
108704fb2745SSam Leffler int pcap_pkt_debug = -1;
108804fb2745SSam Leffler 
108904fb2745SSam Leffler static void pkt_close (struct device *dev)
109004fb2745SSam Leffler {
109104fb2745SSam Leffler   BOOL okay = PktExitDriver();
109204fb2745SSam Leffler 
109304fb2745SSam Leffler   if (pcap_pkt_debug > 1)
109404fb2745SSam Leffler      fprintf (stderr, "pkt_close(): %d\n", okay);
109504fb2745SSam Leffler 
109604fb2745SSam Leffler   if (dev->priv)
109704fb2745SSam Leffler      free (dev->priv);
109804fb2745SSam Leffler   dev->priv = NULL;
109904fb2745SSam Leffler }
110004fb2745SSam Leffler 
110104fb2745SSam Leffler static int pkt_open (struct device *dev)
110204fb2745SSam Leffler {
110304fb2745SSam Leffler   PKT_RX_MODE mode;
110404fb2745SSam Leffler 
110504fb2745SSam Leffler   if (dev->flags & IFF_PROMISC)
110604fb2745SSam Leffler        mode = PDRX_ALL_PACKETS;
110704fb2745SSam Leffler   else mode = PDRX_BROADCAST;
110804fb2745SSam Leffler 
110904fb2745SSam Leffler   if (!PktInitDriver(mode))
111004fb2745SSam Leffler      return (0);
111104fb2745SSam Leffler 
111204fb2745SSam Leffler   PktResetStatistics (pktInfo.handle);
111304fb2745SSam Leffler   PktQueueBusy (FALSE);
111404fb2745SSam Leffler   return (1);
111504fb2745SSam Leffler }
111604fb2745SSam Leffler 
111704fb2745SSam Leffler static int pkt_xmit (struct device *dev, const void *buf, int len)
111804fb2745SSam Leffler {
111904fb2745SSam Leffler   struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
112004fb2745SSam Leffler 
112104fb2745SSam Leffler   if (pcap_pkt_debug > 0)
112204fb2745SSam Leffler      dbug_write ("pcap_xmit\n");
112304fb2745SSam Leffler 
112404fb2745SSam Leffler   if (!PktTransmit(buf,len))
112504fb2745SSam Leffler   {
112604fb2745SSam Leffler     stats->tx_errors++;
112704fb2745SSam Leffler     return (0);
112804fb2745SSam Leffler   }
112904fb2745SSam Leffler   return (len);
113004fb2745SSam Leffler }
113104fb2745SSam Leffler 
113204fb2745SSam Leffler static void *pkt_stats (struct device *dev)
113304fb2745SSam Leffler {
113404fb2745SSam Leffler   struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
113504fb2745SSam Leffler 
113604fb2745SSam Leffler   if (!stats || !PktSessStatistics(pktInfo.handle))
113704fb2745SSam Leffler      return (NULL);
113804fb2745SSam Leffler 
113904fb2745SSam Leffler   stats->rx_packets       = pktStat.inPackets;
114004fb2745SSam Leffler   stats->rx_errors        = pktStat.lost;
114104fb2745SSam Leffler   stats->rx_missed_errors = PktRxDropped();
114204fb2745SSam Leffler   return (stats);
114304fb2745SSam Leffler }
114404fb2745SSam Leffler 
114504fb2745SSam Leffler static int pkt_probe (struct device *dev)
114604fb2745SSam Leffler {
114704fb2745SSam Leffler   if (!PktSearchDriver())
114804fb2745SSam Leffler      return (0);
114904fb2745SSam Leffler 
115004fb2745SSam Leffler   dev->open           = pkt_open;
115104fb2745SSam Leffler   dev->xmit           = pkt_xmit;
115204fb2745SSam Leffler   dev->close          = pkt_close;
115304fb2745SSam Leffler   dev->get_stats      = pkt_stats;
115404fb2745SSam Leffler   dev->copy_rx_buf    = PktReceive;  /* farmem peek and copy routine */
115504fb2745SSam Leffler   dev->get_rx_buf     = NULL;
115604fb2745SSam Leffler   dev->peek_rx_buf    = NULL;
115704fb2745SSam Leffler   dev->release_rx_buf = NULL;
115804fb2745SSam Leffler   dev->priv           = calloc (sizeof(struct net_device_stats), 1);
115904fb2745SSam Leffler   if (!dev->priv)
116004fb2745SSam Leffler      return (0);
116104fb2745SSam Leffler   return (1);
116204fb2745SSam Leffler }
116304fb2745SSam Leffler 
116404fb2745SSam Leffler /*
116504fb2745SSam Leffler  * NDIS device functions
116604fb2745SSam Leffler  */
116704fb2745SSam Leffler static void ndis_close (struct device *dev)
116804fb2745SSam Leffler {
116904fb2745SSam Leffler #ifdef USE_NDIS2
117004fb2745SSam Leffler   NdisShutdown();
117104fb2745SSam Leffler #endif
117204fb2745SSam Leffler   ARGSUSED (dev);
117304fb2745SSam Leffler }
117404fb2745SSam Leffler 
117504fb2745SSam Leffler static int ndis_open (struct device *dev)
117604fb2745SSam Leffler {
117704fb2745SSam Leffler   int promis = (dev->flags & IFF_PROMISC);
117804fb2745SSam Leffler 
117904fb2745SSam Leffler #ifdef USE_NDIS2
118004fb2745SSam Leffler   if (!NdisInit(promis))
118104fb2745SSam Leffler      return (0);
118204fb2745SSam Leffler   return (1);
118304fb2745SSam Leffler #else
118404fb2745SSam Leffler   ARGSUSED (promis);
118504fb2745SSam Leffler   return (0);
118604fb2745SSam Leffler #endif
118704fb2745SSam Leffler }
118804fb2745SSam Leffler 
118904fb2745SSam Leffler static void *ndis_stats (struct device *dev)
119004fb2745SSam Leffler {
119104fb2745SSam Leffler   static struct net_device_stats stats;
119204fb2745SSam Leffler 
119304fb2745SSam Leffler   /* to-do */
119404fb2745SSam Leffler   ARGSUSED (dev);
119504fb2745SSam Leffler   return (&stats);
119604fb2745SSam Leffler }
119704fb2745SSam Leffler 
119804fb2745SSam Leffler static int ndis_probe (struct device *dev)
119904fb2745SSam Leffler {
120004fb2745SSam Leffler #ifdef USE_NDIS2
120104fb2745SSam Leffler   if (!NdisOpen())
120204fb2745SSam Leffler      return (0);
120304fb2745SSam Leffler #endif
120404fb2745SSam Leffler 
120504fb2745SSam Leffler   dev->open           = ndis_open;
120604fb2745SSam Leffler   dev->xmit           = NULL;
120704fb2745SSam Leffler   dev->close          = ndis_close;
120804fb2745SSam Leffler   dev->get_stats      = ndis_stats;
120904fb2745SSam Leffler   dev->copy_rx_buf    = NULL;       /* to-do */
121004fb2745SSam Leffler   dev->get_rx_buf     = NULL;       /* upcall is from rmode driver */
121104fb2745SSam Leffler   dev->peek_rx_buf    = NULL;
121204fb2745SSam Leffler   dev->release_rx_buf = NULL;
121304fb2745SSam Leffler   return (0);
121404fb2745SSam Leffler }
121504fb2745SSam Leffler 
121604fb2745SSam Leffler /*
121704fb2745SSam Leffler  * Search & probe for supported 32-bit (pmode) pcap devices
121804fb2745SSam Leffler  */
121904fb2745SSam Leffler #if defined(USE_32BIT_DRIVERS)
122004fb2745SSam Leffler 
122104fb2745SSam Leffler struct device el2_dev LOCKED_VAR = {
122204fb2745SSam Leffler               "3c503",
122304fb2745SSam Leffler               "EtherLink II",
122404fb2745SSam Leffler               0,
122504fb2745SSam Leffler               0,0,0,0,0,0,
122604fb2745SSam Leffler               NULL,
122704fb2745SSam Leffler               el2_probe
122804fb2745SSam Leffler             };
122904fb2745SSam Leffler 
123004fb2745SSam Leffler struct device el3_dev LOCKED_VAR = {
123104fb2745SSam Leffler               "3c509",
123204fb2745SSam Leffler               "EtherLink III",
123304fb2745SSam Leffler               0,
123404fb2745SSam Leffler               0,0,0,0,0,0,
123504fb2745SSam Leffler               &el2_dev,
123604fb2745SSam Leffler               el3_probe
123704fb2745SSam Leffler             };
123804fb2745SSam Leffler 
123904fb2745SSam Leffler struct device tc515_dev LOCKED_VAR = {
124004fb2745SSam Leffler               "3c515",
124104fb2745SSam Leffler               "EtherLink PCI",
124204fb2745SSam Leffler               0,
124304fb2745SSam Leffler               0,0,0,0,0,0,
124404fb2745SSam Leffler               &el3_dev,
124504fb2745SSam Leffler               tc515_probe
124604fb2745SSam Leffler             };
124704fb2745SSam Leffler 
124804fb2745SSam Leffler struct device tc59_dev LOCKED_VAR = {
124904fb2745SSam Leffler               "3c59x",
125004fb2745SSam Leffler               "EtherLink PCI",
125104fb2745SSam Leffler               0,
125204fb2745SSam Leffler               0,0,0,0,0,0,
125304fb2745SSam Leffler               &tc515_dev,
125404fb2745SSam Leffler               tc59x_probe
125504fb2745SSam Leffler             };
125604fb2745SSam Leffler 
125704fb2745SSam Leffler struct device tc90xbc_dev LOCKED_VAR = {
125804fb2745SSam Leffler               "3c90x",
125904fb2745SSam Leffler               "EtherLink 90X",
126004fb2745SSam Leffler               0,
126104fb2745SSam Leffler               0,0,0,0,0,0,
126204fb2745SSam Leffler               &tc59_dev,
126304fb2745SSam Leffler               tc90xbc_probe
126404fb2745SSam Leffler             };
126504fb2745SSam Leffler 
126604fb2745SSam Leffler struct device wd_dev LOCKED_VAR = {
126704fb2745SSam Leffler               "wd",
126804fb2745SSam Leffler               "Westen Digital",
126904fb2745SSam Leffler               0,
127004fb2745SSam Leffler               0,0,0,0,0,0,
127104fb2745SSam Leffler               &tc90xbc_dev,
127204fb2745SSam Leffler               wd_probe
127304fb2745SSam Leffler             };
127404fb2745SSam Leffler 
127504fb2745SSam Leffler struct device ne_dev LOCKED_VAR = {
127604fb2745SSam Leffler               "ne",
127704fb2745SSam Leffler               "NEx000",
127804fb2745SSam Leffler               0,
127904fb2745SSam Leffler               0,0,0,0,0,0,
128004fb2745SSam Leffler               &wd_dev,
128104fb2745SSam Leffler               ne_probe
128204fb2745SSam Leffler             };
128304fb2745SSam Leffler 
128404fb2745SSam Leffler struct device acct_dev LOCKED_VAR = {
128504fb2745SSam Leffler               "acct",
128604fb2745SSam Leffler               "Accton EtherPocket",
128704fb2745SSam Leffler               0,
128804fb2745SSam Leffler               0,0,0,0,0,0,
128904fb2745SSam Leffler               &ne_dev,
129004fb2745SSam Leffler               ethpk_probe
129104fb2745SSam Leffler             };
129204fb2745SSam Leffler 
129304fb2745SSam Leffler struct device cs89_dev LOCKED_VAR = {
129404fb2745SSam Leffler               "cs89",
129504fb2745SSam Leffler               "Crystal Semiconductor",
129604fb2745SSam Leffler               0,
129704fb2745SSam Leffler               0,0,0,0,0,0,
129804fb2745SSam Leffler               &acct_dev,
129904fb2745SSam Leffler               cs89x0_probe
130004fb2745SSam Leffler             };
130104fb2745SSam Leffler 
130204fb2745SSam Leffler struct device rtl8139_dev LOCKED_VAR = {
130304fb2745SSam Leffler               "rtl8139",
130404fb2745SSam Leffler               "RealTek PCI",
130504fb2745SSam Leffler               0,
130604fb2745SSam Leffler               0,0,0,0,0,0,
130704fb2745SSam Leffler               &cs89_dev,
130804fb2745SSam Leffler               rtl8139_probe     /* dev->probe routine */
130904fb2745SSam Leffler             };
131004fb2745SSam Leffler 
131104fb2745SSam Leffler /*
131204fb2745SSam Leffler  * Dequeue routine is called by polling.
131304fb2745SSam Leffler  * NOTE: the queue-element is not copied, only a pointer is
131404fb2745SSam Leffler  * returned at '*buf'
131504fb2745SSam Leffler  */
131604fb2745SSam Leffler int peek_rxbuf (BYTE **buf)
131704fb2745SSam Leffler {
131804fb2745SSam Leffler   struct rx_elem *tail, *head;
131904fb2745SSam Leffler 
132004fb2745SSam Leffler   PCAP_ASSERT (pktq_check (&active_dev->queue));
132104fb2745SSam Leffler 
132204fb2745SSam Leffler   DISABLE();
132304fb2745SSam Leffler   tail = pktq_out_elem (&active_dev->queue);
132404fb2745SSam Leffler   head = pktq_in_elem (&active_dev->queue);
132504fb2745SSam Leffler   ENABLE();
132604fb2745SSam Leffler 
132704fb2745SSam Leffler   if (head != tail)
132804fb2745SSam Leffler   {
132904fb2745SSam Leffler     PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2);
133004fb2745SSam Leffler 
133104fb2745SSam Leffler     *buf = &tail->data[0];
133204fb2745SSam Leffler     return (tail->size);
133304fb2745SSam Leffler   }
133404fb2745SSam Leffler   *buf = NULL;
133504fb2745SSam Leffler   return (0);
133604fb2745SSam Leffler }
133704fb2745SSam Leffler 
133804fb2745SSam Leffler /*
133904fb2745SSam Leffler  * Release buffer we peeked at above.
134004fb2745SSam Leffler  */
134104fb2745SSam Leffler int release_rxbuf (BYTE *buf)
134204fb2745SSam Leffler {
134304fb2745SSam Leffler #ifndef NDEBUG
134404fb2745SSam Leffler   struct rx_elem *tail = pktq_out_elem (&active_dev->queue);
134504fb2745SSam Leffler 
134604fb2745SSam Leffler   PCAP_ASSERT (&tail->data[0] == buf);
134704fb2745SSam Leffler #else
134804fb2745SSam Leffler   ARGSUSED (buf);
134904fb2745SSam Leffler #endif
135004fb2745SSam Leffler   pktq_inc_out (&active_dev->queue);
135104fb2745SSam Leffler   return (1);
135204fb2745SSam Leffler }
135304fb2745SSam Leffler 
135404fb2745SSam Leffler /*
135504fb2745SSam Leffler  * get_rxbuf() routine (in locked code) is called from IRQ handler
135604fb2745SSam Leffler  * to request a buffer. Interrupts are disabled and we have a 32kB stack.
135704fb2745SSam Leffler  */
135804fb2745SSam Leffler BYTE *get_rxbuf (int len)
135904fb2745SSam Leffler {
136004fb2745SSam Leffler   int idx;
136104fb2745SSam Leffler 
136204fb2745SSam Leffler   if (len < ETH_MIN || len > ETH_MAX)
136304fb2745SSam Leffler      return (NULL);
136404fb2745SSam Leffler 
136504fb2745SSam Leffler   idx = pktq_in_index (&active_dev->queue);
136604fb2745SSam Leffler 
136704fb2745SSam Leffler #ifdef DEBUG
136804fb2745SSam Leffler   {
136904fb2745SSam Leffler     static int fan_idx LOCKED_VAR = 0;
137004fb2745SSam Leffler     writew ("-\\|/"[fan_idx++] | (15 << 8),      /* white on black colour */
137104fb2745SSam Leffler             0xB8000 + 2*79);  /* upper-right corner, 80-col colour screen */
137204fb2745SSam Leffler     fan_idx &= 3;
137304fb2745SSam Leffler   }
137404fb2745SSam Leffler /* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */
137504fb2745SSam Leffler #endif
137604fb2745SSam Leffler 
137704fb2745SSam Leffler   if (idx != active_dev->queue.out_index)
137804fb2745SSam Leffler   {
137904fb2745SSam Leffler     struct rx_elem *head = pktq_in_elem (&active_dev->queue);
138004fb2745SSam Leffler 
138104fb2745SSam Leffler     head->size = len;
138204fb2745SSam Leffler     active_dev->queue.in_index = idx;
138304fb2745SSam Leffler     return (&head->data[0]);
138404fb2745SSam Leffler   }
138504fb2745SSam Leffler 
138604fb2745SSam Leffler   /* !!to-do: drop 25% of the oldest element
138704fb2745SSam Leffler    */
138804fb2745SSam Leffler   pktq_clear (&active_dev->queue);
138904fb2745SSam Leffler   return (NULL);
139004fb2745SSam Leffler }
139104fb2745SSam Leffler 
139204fb2745SSam Leffler /*
139304fb2745SSam Leffler  *  Simple ring-buffer queue handler for reception of packets
139404fb2745SSam Leffler  *  from network driver.
139504fb2745SSam Leffler  */
139604fb2745SSam Leffler #define PKTQ_MARKER  0xDEADBEEF
139704fb2745SSam Leffler 
139804fb2745SSam Leffler static int pktq_check (struct rx_ringbuf *q)
139904fb2745SSam Leffler {
140004fb2745SSam Leffler #ifndef NDEBUG
140104fb2745SSam Leffler   int   i;
140204fb2745SSam Leffler   char *buf;
140304fb2745SSam Leffler #endif
140404fb2745SSam Leffler 
140504fb2745SSam Leffler   if (!q || !q->num_elem || !q->buf_start)
140604fb2745SSam Leffler      return (0);
140704fb2745SSam Leffler 
140804fb2745SSam Leffler #ifndef NDEBUG
140904fb2745SSam Leffler   buf = q->buf_start;
141004fb2745SSam Leffler 
141104fb2745SSam Leffler   for (i = 0; i < q->num_elem; i++)
141204fb2745SSam Leffler   {
141304fb2745SSam Leffler     buf += q->elem_size;
141404fb2745SSam Leffler     if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER)
141504fb2745SSam Leffler        return (0);
141604fb2745SSam Leffler   }
141704fb2745SSam Leffler #endif
141804fb2745SSam Leffler   return (1);
141904fb2745SSam Leffler }
142004fb2745SSam Leffler 
142104fb2745SSam Leffler static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool)
142204fb2745SSam Leffler {
142304fb2745SSam Leffler   int i;
142404fb2745SSam Leffler 
142504fb2745SSam Leffler   q->elem_size = size;
142604fb2745SSam Leffler   q->num_elem  = num;
142704fb2745SSam Leffler   q->buf_start = pool;
142804fb2745SSam Leffler   q->in_index  = 0;
142904fb2745SSam Leffler   q->out_index = 0;
143004fb2745SSam Leffler 
143104fb2745SSam Leffler   PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD));
143204fb2745SSam Leffler   PCAP_ASSERT (num);
143304fb2745SSam Leffler   PCAP_ASSERT (pool);
143404fb2745SSam Leffler 
143504fb2745SSam Leffler   for (i = 0; i < num; i++)
143604fb2745SSam Leffler   {
143704fb2745SSam Leffler #if 0
143804fb2745SSam Leffler     struct rx_elem *elem = (struct rx_elem*) pool;
143904fb2745SSam Leffler 
144004fb2745SSam Leffler     /* assert dword aligned elements
144104fb2745SSam Leffler      */
144204fb2745SSam Leffler     PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0);
144304fb2745SSam Leffler #endif
144404fb2745SSam Leffler     pool += size;
144504fb2745SSam Leffler     *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER;
144604fb2745SSam Leffler   }
144704fb2745SSam Leffler   return (1);
144804fb2745SSam Leffler }
144904fb2745SSam Leffler 
145004fb2745SSam Leffler /*
145104fb2745SSam Leffler  * Increment the queue 'out_index' (tail).
145204fb2745SSam Leffler  * Check for wraps.
145304fb2745SSam Leffler  */
145404fb2745SSam Leffler static int pktq_inc_out (struct rx_ringbuf *q)
145504fb2745SSam Leffler {
145604fb2745SSam Leffler   q->out_index++;
145704fb2745SSam Leffler   if (q->out_index >= q->num_elem)
145804fb2745SSam Leffler       q->out_index = 0;
145904fb2745SSam Leffler   return (q->out_index);
146004fb2745SSam Leffler }
146104fb2745SSam Leffler 
146204fb2745SSam Leffler /*
146304fb2745SSam Leffler  * Return the queue's next 'in_index' (head).
146404fb2745SSam Leffler  * Check for wraps.
146504fb2745SSam Leffler  */
146604fb2745SSam Leffler static int pktq_in_index (struct rx_ringbuf *q)
146704fb2745SSam Leffler {
146804fb2745SSam Leffler   volatile int index = q->in_index + 1;
146904fb2745SSam Leffler 
147004fb2745SSam Leffler   if (index >= q->num_elem)
147104fb2745SSam Leffler       index = 0;
147204fb2745SSam Leffler   return (index);
147304fb2745SSam Leffler }
147404fb2745SSam Leffler 
147504fb2745SSam Leffler /*
147604fb2745SSam Leffler  * Return the queue's head-buffer.
147704fb2745SSam Leffler  */
147804fb2745SSam Leffler static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q)
147904fb2745SSam Leffler {
148004fb2745SSam Leffler   return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index));
148104fb2745SSam Leffler }
148204fb2745SSam Leffler 
148304fb2745SSam Leffler /*
148404fb2745SSam Leffler  * Return the queue's tail-buffer.
148504fb2745SSam Leffler  */
148604fb2745SSam Leffler static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q)
148704fb2745SSam Leffler {
148804fb2745SSam Leffler   return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index));
148904fb2745SSam Leffler }
149004fb2745SSam Leffler 
149104fb2745SSam Leffler /*
149204fb2745SSam Leffler  * Clear the queue ring-buffer by setting head=tail.
149304fb2745SSam Leffler  */
149404fb2745SSam Leffler static void pktq_clear (struct rx_ringbuf *q)
149504fb2745SSam Leffler {
149604fb2745SSam Leffler   q->in_index = q->out_index;
149704fb2745SSam Leffler }
149804fb2745SSam Leffler 
149904fb2745SSam Leffler /*
150004fb2745SSam Leffler  * Symbols that must be linkable for "gcc -O0"
150104fb2745SSam Leffler  */
150204fb2745SSam Leffler #undef __IOPORT_H
150304fb2745SSam Leffler #undef __DMA_H
150404fb2745SSam Leffler 
150504fb2745SSam Leffler #define extern
150604fb2745SSam Leffler #define __inline__
150704fb2745SSam Leffler 
150804fb2745SSam Leffler #include "msdos/pm_drvr/ioport.h"
150904fb2745SSam Leffler #include "msdos/pm_drvr/dma.h"
151004fb2745SSam Leffler 
151104fb2745SSam Leffler #endif /* USE_32BIT_DRIVERS */
151204fb2745SSam Leffler 
1513