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