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, ðpk_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