1335640Shselasky/* 2335640Shselasky * This file is part of DOS-libpcap 3335640Shselasky * Ported to DOS/DOSX by G. Vanem <gvanem@yahoo.no> 4335640Shselasky * 5335640Shselasky * pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode 6335640Shselasky * network drivers. 7335640Shselasky */ 8335640Shselasky 9335640Shselasky#include <stdio.h> 10335640Shselasky#include <stdlib.h> 11335640Shselasky#include <string.h> 12335640Shselasky#include <signal.h> 13335640Shselasky#include <float.h> 14335640Shselasky#include <fcntl.h> 15335640Shselasky#include <io.h> 16335640Shselasky 17335640Shselasky#if defined(USE_32BIT_DRIVERS) 18335640Shselasky #include "msdos/pm_drvr/pmdrvr.h" 19335640Shselasky #include "msdos/pm_drvr/pci.h" 20335640Shselasky #include "msdos/pm_drvr/bios32.h" 21335640Shselasky #include "msdos/pm_drvr/module.h" 22335640Shselasky #include "msdos/pm_drvr/3c501.h" 23335640Shselasky #include "msdos/pm_drvr/3c503.h" 24335640Shselasky #include "msdos/pm_drvr/3c509.h" 25335640Shselasky #include "msdos/pm_drvr/3c59x.h" 26335640Shselasky #include "msdos/pm_drvr/3c515.h" 27335640Shselasky #include "msdos/pm_drvr/3c90x.h" 28335640Shselasky #include "msdos/pm_drvr/3c575_cb.h" 29335640Shselasky #include "msdos/pm_drvr/ne.h" 30335640Shselasky #include "msdos/pm_drvr/wd.h" 31335640Shselasky #include "msdos/pm_drvr/accton.h" 32335640Shselasky #include "msdos/pm_drvr/cs89x0.h" 33335640Shselasky #include "msdos/pm_drvr/rtl8139.h" 34335640Shselasky #include "msdos/pm_drvr/ne2k-pci.h" 35335640Shselasky#endif 36335640Shselasky 37335640Shselasky#include "pcap.h" 38335640Shselasky#include "pcap-dos.h" 39335640Shselasky#include "pcap-int.h" 40335640Shselasky#include "msdos/pktdrvr.h" 41335640Shselasky 42335640Shselasky#ifdef USE_NDIS2 43335640Shselasky#include "msdos/ndis2.h" 44335640Shselasky#endif 45335640Shselasky 46335640Shselasky#include <arpa/inet.h> 47335640Shselasky#include <net/if.h> 48335640Shselasky#include <net/if_arp.h> 49335640Shselasky#include <net/if_ether.h> 50335640Shselasky#include <net/if_packe.h> 51335640Shselasky#include <tcp.h> 52335640Shselasky 53335640Shselasky#if defined(USE_32BIT_DRIVERS) 54335640Shselasky #define FLUSHK() do { _printk_safe = 1; _printk_flush(); } while (0) 55335640Shselasky #define NDIS_NEXT_DEV &rtl8139_dev 56335640Shselasky 57335640Shselasky static char *rx_pool = NULL; 58335640Shselasky static void init_32bit (void); 59335640Shselasky 60335640Shselasky static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool); 61335640Shselasky static int pktq_check (struct rx_ringbuf *q); 62335640Shselasky static int pktq_inc_out (struct rx_ringbuf *q); 63335640Shselasky static int pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC; 64335640Shselasky static void pktq_clear (struct rx_ringbuf *q) LOCKED_FUNC; 65335640Shselasky 66335640Shselasky static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) LOCKED_FUNC; 67335640Shselasky static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q); 68335640Shselasky 69335640Shselasky#else 70335640Shselasky #define FLUSHK() ((void)0) 71335640Shselasky #define NDIS_NEXT_DEV NULL 72335640Shselasky#endif 73335640Shselasky 74335640Shselasky/* 75335640Shselasky * Internal variables/functions in Watt-32 76335640Shselasky */ 77335640Shselaskyextern WORD _pktdevclass; 78335640Shselaskyextern BOOL _eth_is_init; 79335640Shselaskyextern int _w32_dynamic_host; 80335640Shselaskyextern int _watt_do_exit; 81335640Shselaskyextern int _watt_is_init; 82335640Shselaskyextern int _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req; 83335640Shselaskyextern void (*_w32_usr_post_init) (void); 84335640Shselaskyextern void (*_w32_print_hook)(); 85335640Shselasky 86335640Shselaskyextern void dbug_write (const char *); /* Watt-32 lib, pcdbug.c */ 87335640Shselaskyextern int pkt_get_mtu (void); 88335640Shselasky 89335640Shselaskystatic int ref_count = 0; 90335640Shselasky 91335640Shselaskystatic u_long mac_count = 0; 92335640Shselaskystatic u_long filter_count = 0; 93335640Shselasky 94335640Shselaskystatic volatile BOOL exc_occured = 0; 95335640Shselasky 96335640Shselaskystatic struct device *handle_to_device [20]; 97335640Shselasky 98335640Shselaskystatic int pcap_activate_dos (pcap_t *p); 99335640Shselaskystatic int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, 100335640Shselasky u_char *data); 101335640Shselaskystatic void pcap_cleanup_dos (pcap_t *p); 102335640Shselaskystatic int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps); 103335640Shselaskystatic int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len); 104335640Shselaskystatic int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp); 105335640Shselasky 106335640Shselaskystatic int ndis_probe (struct device *dev); 107335640Shselaskystatic int pkt_probe (struct device *dev); 108335640Shselasky 109335640Shselaskystatic void close_driver (void); 110335640Shselaskystatic int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf); 111335640Shselaskystatic int first_init (const char *name, char *ebuf, int promisc); 112335640Shselasky 113335640Shselaskystatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, 114335640Shselasky const u_char *buf); 115335640Shselasky 116335640Shselasky/* 117335640Shselasky * These are the device we always support 118335640Shselasky */ 119335640Shselaskystatic struct device ndis_dev = { 120335640Shselasky "ndis", 121335640Shselasky "NDIS2 LanManager", 122335640Shselasky 0, 123335640Shselasky 0,0,0,0,0,0, 124335640Shselasky NDIS_NEXT_DEV, /* NULL or a 32-bit device */ 125335640Shselasky ndis_probe 126335640Shselasky }; 127335640Shselasky 128335640Shselaskystatic struct device pkt_dev = { 129335640Shselasky "pkt", 130335640Shselasky "Packet-Driver", 131335640Shselasky 0, 132335640Shselasky 0,0,0,0,0,0, 133335640Shselasky &ndis_dev, 134335640Shselasky pkt_probe 135335640Shselasky }; 136335640Shselasky 137335640Shselaskystatic struct device *get_device (int fd) 138335640Shselasky{ 139335640Shselasky if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0])) 140335640Shselasky return (NULL); 141335640Shselasky return handle_to_device [fd-1]; 142335640Shselasky} 143335640Shselasky 144335640Shselasky/* 145335640Shselasky * Private data for capturing on MS-DOS. 146335640Shselasky */ 147335640Shselaskystruct pcap_dos { 148335640Shselasky void (*wait_proc)(void); /* call proc while waiting */ 149335640Shselasky struct pcap_stat stat; 150335640Shselasky}; 151335640Shselasky 152335640Shselaskypcap_t *pcap_create_interface (const char *device _U_, char *ebuf) 153335640Shselasky{ 154335640Shselasky pcap_t *p; 155335640Shselasky 156335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_dos)); 157335640Shselasky if (p == NULL) 158335640Shselasky return (NULL); 159335640Shselasky 160335640Shselasky p->activate_op = pcap_activate_dos; 161335640Shselasky return (p); 162335640Shselasky} 163335640Shselasky 164335640Shselasky/* 165335640Shselasky * Open MAC-driver with name 'device_name' for live capture of 166335640Shselasky * network packets. 167335640Shselasky */ 168335640Shselaskystatic int pcap_activate_dos (pcap_t *pcap) 169335640Shselasky{ 170335640Shselasky if (pcap->opt.rfmon) { 171335640Shselasky /* 172335640Shselasky * No monitor mode on DOS. 173335640Shselasky */ 174335640Shselasky return (PCAP_ERROR_RFMON_NOTSUP); 175335640Shselasky } 176335640Shselasky 177335640Shselasky /* 178335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 179335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 180335640Shselasky * value, into the maximum allowed value. 181335640Shselasky * 182335640Shselasky * If some application really *needs* a bigger snapshot 183335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 184335640Shselasky */ 185335640Shselasky if (pcap->snapshot <= 0 || pcap->snapshot > MAXIMUM_SNAPLEN) 186335640Shselasky pcap->snapshot = MAXIMUM_SNAPLEN; 187335640Shselasky 188335640Shselasky if (pcap->snapshot < ETH_MIN+8) 189335640Shselasky pcap->snapshot = ETH_MIN+8; 190335640Shselasky 191335640Shselasky if (pcap->snapshot > ETH_MAX) /* silently accept and truncate large MTUs */ 192335640Shselasky pcap->snapshot = ETH_MAX; 193335640Shselasky 194335640Shselasky pcap->linktype = DLT_EN10MB; /* !! */ 195335640Shselasky pcap->cleanup_op = pcap_cleanup_dos; 196335640Shselasky pcap->read_op = pcap_read_dos; 197335640Shselasky pcap->stats_op = pcap_stats_dos; 198335640Shselasky pcap->inject_op = pcap_sendpacket_dos; 199335640Shselasky pcap->setfilter_op = pcap_setfilter_dos; 200335640Shselasky pcap->setdirection_op = NULL; /* Not implemented.*/ 201335640Shselasky pcap->fd = ++ref_count; 202335640Shselasky 203335640Shselasky pcap->bufsize = ETH_MAX+100; /* add some margin */ 204335640Shselasky pcap->buffer = calloc (pcap->bufsize, 1); 205335640Shselasky 206335640Shselasky if (pcap->fd == 1) /* first time we're called */ 207335640Shselasky { 208335640Shselasky if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) || 209335640Shselasky !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc)) 210335640Shselasky { 211335640Shselasky /* XXX - free pcap->buffer? */ 212335640Shselasky return (PCAP_ERROR); 213335640Shselasky } 214335640Shselasky atexit (close_driver); 215335640Shselasky } 216335640Shselasky else if (stricmp(active_dev->name,pcap->opt.device)) 217335640Shselasky { 218335640Shselasky pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE, 219335640Shselasky "Cannot use different devices simultaneously " 220335640Shselasky "(`%s' vs. `%s')", active_dev->name, pcap->opt.device); 221335640Shselasky /* XXX - free pcap->buffer? */ 222335640Shselasky return (PCAP_ERROR); 223335640Shselasky } 224335640Shselasky handle_to_device [pcap->fd-1] = active_dev; 225335640Shselasky return (0); 226335640Shselasky} 227335640Shselasky 228335640Shselasky/* 229335640Shselasky * Poll the receiver queue and call the pcap callback-handler 230335640Shselasky * with the packet. 231335640Shselasky */ 232335640Shselaskystatic int 233335640Shselaskypcap_read_one (pcap_t *p, pcap_handler callback, u_char *data) 234335640Shselasky{ 235335640Shselasky struct pcap_dos *pd = p->priv; 236335640Shselasky struct pcap_pkthdr pcap; 237335640Shselasky struct timeval now, expiry = { 0,0 }; 238335640Shselasky int rx_len = 0; 239335640Shselasky 240335640Shselasky if (p->opt.timeout > 0) 241335640Shselasky { 242335640Shselasky gettimeofday2 (&now, NULL); 243335640Shselasky expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout; 244335640Shselasky expiry.tv_sec = now.tv_sec; 245335640Shselasky while (expiry.tv_usec >= 1000000L) 246335640Shselasky { 247335640Shselasky expiry.tv_usec -= 1000000L; 248335640Shselasky expiry.tv_sec++; 249335640Shselasky } 250335640Shselasky } 251335640Shselasky 252335640Shselasky while (!exc_occured) 253335640Shselasky { 254335640Shselasky volatile struct device *dev; /* might be reset by sig_handler */ 255335640Shselasky 256335640Shselasky dev = get_device (p->fd); 257335640Shselasky if (!dev) 258335640Shselasky break; 259335640Shselasky 260335640Shselasky PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf); 261335640Shselasky FLUSHK(); 262335640Shselasky 263335640Shselasky /* If driver has a zero-copy receive facility, peek at the queue, 264335640Shselasky * filter it, do the callback and release the buffer. 265335640Shselasky */ 266335640Shselasky if (dev->peek_rx_buf) 267335640Shselasky { 268335640Shselasky PCAP_ASSERT (dev->release_rx_buf); 269335640Shselasky rx_len = (*dev->peek_rx_buf) (&p->buffer); 270335640Shselasky } 271335640Shselasky else 272335640Shselasky { 273335640Shselasky rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot); 274335640Shselasky } 275335640Shselasky 276335640Shselasky if (rx_len > 0) /* got a packet */ 277335640Shselasky { 278335640Shselasky mac_count++; 279335640Shselasky 280335640Shselasky FLUSHK(); 281335640Shselasky 282335640Shselasky pcap.caplen = min (rx_len, p->snapshot); 283335640Shselasky pcap.len = rx_len; 284335640Shselasky 285335640Shselasky if (callback && 286335640Shselasky (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen))) 287335640Shselasky { 288335640Shselasky filter_count++; 289335640Shselasky 290335640Shselasky /* Fix-me!! Should be time of arrival. Not time of 291335640Shselasky * capture. 292335640Shselasky */ 293335640Shselasky gettimeofday2 (&pcap.ts, NULL); 294335640Shselasky (*callback) (data, &pcap, p->buffer); 295335640Shselasky } 296335640Shselasky 297335640Shselasky if (dev->release_rx_buf) 298335640Shselasky (*dev->release_rx_buf) (p->buffer); 299335640Shselasky 300335640Shselasky if (pcap_pkt_debug > 0) 301335640Shselasky { 302335640Shselasky if (callback == watt32_recv_hook) 303335640Shselasky dbug_write ("pcap_recv_hook\n"); 304335640Shselasky else dbug_write ("pcap_read_op\n"); 305335640Shselasky } 306335640Shselasky FLUSHK(); 307335640Shselasky return (1); 308335640Shselasky } 309335640Shselasky 310335640Shselasky /* Has "pcap_breakloop()" been called? 311335640Shselasky */ 312335640Shselasky if (p->break_loop) { 313335640Shselasky /* 314335640Shselasky * Yes - clear the flag that indicates that it 315335640Shselasky * has, and return -2 to indicate that we were 316335640Shselasky * told to break out of the loop. 317335640Shselasky */ 318335640Shselasky p->break_loop = 0; 319335640Shselasky return (-2); 320335640Shselasky } 321335640Shselasky 322335640Shselasky /* If not to wait for a packet or pcap_cleanup_dos() called from 323335640Shselasky * e.g. SIGINT handler, exit loop now. 324335640Shselasky */ 325335640Shselasky if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0) 326335640Shselasky break; 327335640Shselasky 328335640Shselasky gettimeofday2 (&now, NULL); 329335640Shselasky 330335640Shselasky if (timercmp(&now, &expiry, >)) 331335640Shselasky break; 332335640Shselasky 333335640Shselasky#ifndef DJGPP 334335640Shselasky kbhit(); /* a real CPU hog */ 335335640Shselasky#endif 336335640Shselasky 337335640Shselasky if (pd->wait_proc) 338335640Shselasky (*pd->wait_proc)(); /* call yield func */ 339335640Shselasky } 340335640Shselasky 341335640Shselasky if (rx_len < 0) /* receive error */ 342335640Shselasky { 343335640Shselasky pd->stat.ps_drop++; 344335640Shselasky#ifdef USE_32BIT_DRIVERS 345335640Shselasky if (pcap_pkt_debug > 1) 346335640Shselasky printk ("pkt-err %s\n", pktInfo.error); 347335640Shselasky#endif 348335640Shselasky return (-1); 349335640Shselasky } 350335640Shselasky return (0); 351335640Shselasky} 352335640Shselasky 353335640Shselaskystatic int 354335640Shselaskypcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data) 355335640Shselasky{ 356335640Shselasky int rc, num = 0; 357335640Shselasky 358335640Shselasky while (num <= cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) 359335640Shselasky { 360335640Shselasky if (p->fd <= 0) 361335640Shselasky return (-1); 362335640Shselasky rc = pcap_read_one (p, callback, data); 363335640Shselasky if (rc > 0) 364335640Shselasky num++; 365335640Shselasky if (rc < 0) 366335640Shselasky break; 367335640Shselasky _w32_os_yield(); /* allow SIGINT generation, yield to Win95/NT */ 368335640Shselasky } 369335640Shselasky return (num); 370335640Shselasky} 371335640Shselasky 372335640Shselasky/* 373335640Shselasky * Return network statistics 374335640Shselasky */ 375335640Shselaskystatic int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps) 376335640Shselasky{ 377335640Shselasky struct net_device_stats *stats; 378335640Shselasky struct pcap_dos *pd; 379335640Shselasky struct device *dev = p ? get_device(p->fd) : NULL; 380335640Shselasky 381335640Shselasky if (!dev) 382335640Shselasky { 383335640Shselasky strcpy (p->errbuf, "illegal pcap handle"); 384335640Shselasky return (-1); 385335640Shselasky } 386335640Shselasky 387335640Shselasky if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL) 388335640Shselasky { 389335640Shselasky strcpy (p->errbuf, "device statistics not available"); 390335640Shselasky return (-1); 391335640Shselasky } 392335640Shselasky 393335640Shselasky FLUSHK(); 394335640Shselasky 395335640Shselasky pd = p->priv; 396335640Shselasky pd->stat.ps_recv = stats->rx_packets; 397335640Shselasky pd->stat.ps_drop += stats->rx_missed_errors; 398335640Shselasky pd->stat.ps_ifdrop = stats->rx_dropped + /* queue full */ 399335640Shselasky stats->rx_errors; /* HW errors */ 400335640Shselasky if (ps) 401335640Shselasky *ps = pd->stat; 402335640Shselasky 403335640Shselasky return (0); 404335640Shselasky} 405335640Shselasky 406335640Shselasky/* 407335640Shselasky * Return detailed network/device statistics. 408335640Shselasky * May be called after 'dev->close' is called. 409335640Shselasky */ 410335640Shselaskyint pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) 411335640Shselasky{ 412335640Shselasky struct device *dev = p ? get_device (p->fd) : NULL; 413335640Shselasky 414335640Shselasky if (!dev || !dev->get_stats) 415335640Shselasky { 416356341Scy pcap_strlcpy (p->errbuf, "detailed device statistics not available", 417335640Shselasky PCAP_ERRBUF_SIZE); 418335640Shselasky return (-1); 419335640Shselasky } 420335640Shselasky 421335640Shselasky if (!strnicmp(dev->name,"pkt",3)) 422335640Shselasky { 423356341Scy pcap_strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", 424335640Shselasky PCAP_ERRBUF_SIZE); 425335640Shselasky return (-1); 426335640Shselasky } 427335640Shselasky memcpy (se, (*dev->get_stats)(dev), sizeof(*se)); 428335640Shselasky return (0); 429335640Shselasky} 430335640Shselasky 431335640Shselasky/* 432335640Shselasky * Simply store the filter-code for the pcap_read_dos() callback 433335640Shselasky * Some day the filter-code could be handed down to the active 434335640Shselasky * device (pkt_rx1.s or 32-bit device interrupt handler). 435335640Shselasky */ 436335640Shselaskystatic int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp) 437335640Shselasky{ 438335640Shselasky if (!p) 439335640Shselasky return (-1); 440335640Shselasky p->fcode = *fp; 441335640Shselasky return (0); 442335640Shselasky} 443335640Shselasky 444335640Shselasky/* 445335640Shselasky * Return # of packets received in pcap_read_dos() 446335640Shselasky */ 447335640Shselaskyu_long pcap_mac_packets (void) 448335640Shselasky{ 449335640Shselasky return (mac_count); 450335640Shselasky} 451335640Shselasky 452335640Shselasky/* 453335640Shselasky * Return # of packets passed through filter in pcap_read_dos() 454335640Shselasky */ 455335640Shselaskyu_long pcap_filter_packets (void) 456335640Shselasky{ 457335640Shselasky return (filter_count); 458335640Shselasky} 459335640Shselasky 460335640Shselasky/* 461335640Shselasky * Close pcap device. Not called for offline captures. 462335640Shselasky */ 463335640Shselaskystatic void pcap_cleanup_dos (pcap_t *p) 464335640Shselasky{ 465335640Shselasky struct pcap_dos *pd; 466335640Shselasky 467335640Shselasky if (!exc_occured) 468335640Shselasky { 469335640Shselasky pd = p->priv; 470335640Shselasky if (pcap_stats(p,NULL) < 0) 471335640Shselasky pd->stat.ps_drop = 0; 472335640Shselasky if (!get_device(p->fd)) 473335640Shselasky return; 474335640Shselasky 475335640Shselasky handle_to_device [p->fd-1] = NULL; 476335640Shselasky p->fd = 0; 477335640Shselasky if (ref_count > 0) 478335640Shselasky ref_count--; 479335640Shselasky if (ref_count > 0) 480335640Shselasky return; 481335640Shselasky } 482335640Shselasky close_driver(); 483335640Shselasky /* XXX - call pcap_cleanup_live_common? */ 484335640Shselasky} 485335640Shselasky 486335640Shselasky/* 487335640Shselasky * Return the name of the 1st network interface, 488335640Shselasky * or NULL if none can be found. 489335640Shselasky */ 490335640Shselaskychar *pcap_lookupdev (char *ebuf) 491335640Shselasky{ 492335640Shselasky struct device *dev; 493335640Shselasky 494335640Shselasky#ifdef USE_32BIT_DRIVERS 495335640Shselasky init_32bit(); 496335640Shselasky#endif 497335640Shselasky 498335640Shselasky for (dev = (struct device*)dev_base; dev; dev = dev->next) 499335640Shselasky { 500335640Shselasky PCAP_ASSERT (dev->probe); 501335640Shselasky 502335640Shselasky if ((*dev->probe)(dev)) 503335640Shselasky { 504335640Shselasky FLUSHK(); 505335640Shselasky probed_dev = (struct device*) dev; /* remember last probed device */ 506335640Shselasky return (char*) dev->name; 507335640Shselasky } 508335640Shselasky } 509335640Shselasky 510335640Shselasky if (ebuf) 511335640Shselasky strcpy (ebuf, "No driver found"); 512335640Shselasky return (NULL); 513335640Shselasky} 514335640Shselasky 515335640Shselasky/* 516335640Shselasky * Gets localnet & netmask from Watt-32. 517335640Shselasky */ 518335640Shselaskyint pcap_lookupnet (const char *device, bpf_u_int32 *localnet, 519335640Shselasky bpf_u_int32 *netmask, char *errbuf) 520335640Shselasky{ 521335640Shselasky DWORD mask, net; 522335640Shselasky 523335640Shselasky if (!_watt_is_init) 524335640Shselasky { 525335640Shselasky strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be " 526335640Shselasky "called first"); 527335640Shselasky return (-1); 528335640Shselasky } 529335640Shselasky 530335640Shselasky mask = _w32_sin_mask; 531335640Shselasky net = my_ip_addr & mask; 532335640Shselasky if (net == 0) 533335640Shselasky { 534335640Shselasky if (IN_CLASSA(*netmask)) 535335640Shselasky net = IN_CLASSA_NET; 536335640Shselasky else if (IN_CLASSB(*netmask)) 537335640Shselasky net = IN_CLASSB_NET; 538335640Shselasky else if (IN_CLASSC(*netmask)) 539335640Shselasky net = IN_CLASSC_NET; 540335640Shselasky else 541335640Shselasky { 542335640Shselasky pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask); 543335640Shselasky return (-1); 544335640Shselasky } 545335640Shselasky } 546335640Shselasky *localnet = htonl (net); 547335640Shselasky *netmask = htonl (mask); 548335640Shselasky 549335640Shselasky ARGSUSED (device); 550335640Shselasky return (0); 551335640Shselasky} 552335640Shselasky 553335640Shselasky/* 554335640Shselasky * Get a list of all interfaces that are present and that we probe okay. 555335640Shselasky * Returns -1 on error, 0 otherwise. 556335640Shselasky * The list may be NULL epty if no interfaces were up and could be opened. 557335640Shselasky */ 558335640Shselaskyint pcap_platform_finddevs (pcap_if_list_t *devlistp, char *errbuf) 559335640Shselasky{ 560335640Shselasky struct device *dev; 561335640Shselasky pcap_if_t *curdev; 562335640Shselasky#if 0 /* Pkt drivers should have no addresses */ 563335640Shselasky struct sockaddr_in sa_ll_1, sa_ll_2; 564335640Shselasky struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; 565335640Shselasky#endif 566335640Shselasky int ret = 0; 567335640Shselasky int found = 0; 568335640Shselasky 569335640Shselasky for (dev = (struct device*)dev_base; dev; dev = dev->next) 570335640Shselasky { 571335640Shselasky PCAP_ASSERT (dev->probe); 572335640Shselasky 573335640Shselasky if (!(*dev->probe)(dev)) 574335640Shselasky continue; 575335640Shselasky 576335640Shselasky PCAP_ASSERT (dev->close); /* set by probe routine */ 577335640Shselasky FLUSHK(); 578335640Shselasky (*dev->close) (dev); 579335640Shselasky 580335640Shselasky /* 581335640Shselasky * XXX - find out whether it's up or running? Does that apply here? 582335640Shselasky * Can we find out if anything's plugged into the adapter, if it's 583335640Shselasky * a wired device, and set PCAP_IF_CONNECTION_STATUS_CONNECTED 584335640Shselasky * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED? 585335640Shselasky */ 586335640Shselasky if ((curdev = add_dev(devlistp, dev->name, 0, 587335640Shselasky dev->long_name, errbuf)) == NULL) 588335640Shselasky { 589335640Shselasky ret = -1; 590335640Shselasky break; 591335640Shselasky } 592335640Shselasky found = 1; 593335640Shselasky#if 0 /* Pkt drivers should have no addresses */ 594335640Shselasky memset (&sa_ll_1, 0, sizeof(sa_ll_1)); 595335640Shselasky memset (&sa_ll_2, 0, sizeof(sa_ll_2)); 596335640Shselasky sa_ll_1.sin_family = AF_INET; 597335640Shselasky sa_ll_2.sin_family = AF_INET; 598335640Shselasky 599335640Shselasky addr = (struct sockaddr*) &sa_ll_1; 600335640Shselasky netmask = (struct sockaddr*) &sa_ll_1; 601335640Shselasky dstaddr = (struct sockaddr*) &sa_ll_1; 602335640Shselasky broadaddr = (struct sockaddr*) &sa_ll_2; 603335640Shselasky memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr)); 604335640Shselasky 605335640Shselasky if (add_addr_to_dev(curdev, addr, sizeof(*addr), 606335640Shselasky netmask, sizeof(*netmask), 607335640Shselasky broadaddr, sizeof(*broadaddr), 608335640Shselasky dstaddr, sizeof(*dstaddr), errbuf) < 0) 609335640Shselasky { 610335640Shselasky ret = -1; 611335640Shselasky break; 612335640Shselasky } 613335640Shselasky#endif 614335640Shselasky } 615335640Shselasky 616335640Shselasky if (ret == 0 && !found) 617335640Shselasky strcpy (errbuf, "No drivers found"); 618335640Shselasky 619335640Shselasky return (ret); 620335640Shselasky} 621335640Shselasky 622335640Shselasky/* 623335640Shselasky * pcap_assert() is mainly used for debugging 624335640Shselasky */ 625335640Shselaskyvoid pcap_assert (const char *what, const char *file, unsigned line) 626335640Shselasky{ 627335640Shselasky FLUSHK(); 628335640Shselasky fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n", 629335640Shselasky file, line, what); 630335640Shselasky close_driver(); 631335640Shselasky _exit (-1); 632335640Shselasky} 633335640Shselasky 634335640Shselasky/* 635335640Shselasky * For pcap_offline_read(): wait and yield between printing packets 636335640Shselasky * to simulate the pace packets where actually recorded. 637335640Shselasky */ 638335640Shselaskyvoid pcap_set_wait (pcap_t *p, void (*yield)(void), int wait) 639335640Shselasky{ 640335640Shselasky if (p) 641335640Shselasky { 642335640Shselasky struct pcap_dos *pd = p->priv; 643335640Shselasky 644335640Shselasky pd->wait_proc = yield; 645335640Shselasky p->opt.timeout = wait; 646335640Shselasky } 647335640Shselasky} 648335640Shselasky 649335640Shselasky/* 650335640Shselasky * Initialise a named network device. 651335640Shselasky */ 652335640Shselaskystatic struct device * 653335640Shselaskyopen_driver (const char *dev_name, char *ebuf, int promisc) 654335640Shselasky{ 655335640Shselasky struct device *dev; 656335640Shselasky 657335640Shselasky for (dev = (struct device*)dev_base; dev; dev = dev->next) 658335640Shselasky { 659335640Shselasky PCAP_ASSERT (dev->name); 660335640Shselasky 661335640Shselasky if (strcmp (dev_name,dev->name)) 662335640Shselasky continue; 663335640Shselasky 664335640Shselasky if (!probed_dev) /* user didn't call pcap_lookupdev() first */ 665335640Shselasky { 666335640Shselasky PCAP_ASSERT (dev->probe); 667335640Shselasky 668335640Shselasky if (!(*dev->probe)(dev)) /* call the xx_probe() function */ 669335640Shselasky { 670335640Shselasky pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name); 671335640Shselasky return (NULL); 672335640Shselasky } 673335640Shselasky probed_dev = dev; /* device is probed okay and may be used */ 674335640Shselasky } 675335640Shselasky else if (dev != probed_dev) 676335640Shselasky { 677335640Shselasky goto not_probed; 678335640Shselasky } 679335640Shselasky 680335640Shselasky FLUSHK(); 681335640Shselasky 682335640Shselasky /* Select what traffic to receive 683335640Shselasky */ 684335640Shselasky if (promisc) 685335640Shselasky dev->flags |= (IFF_ALLMULTI | IFF_PROMISC); 686335640Shselasky else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC); 687335640Shselasky 688335640Shselasky PCAP_ASSERT (dev->open); 689335640Shselasky 690335640Shselasky if (!(*dev->open)(dev)) 691335640Shselasky { 692335640Shselasky pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name); 693335640Shselasky if (pktInfo.error && !strncmp(dev->name,"pkt",3)) 694335640Shselasky { 695335640Shselasky strcat (ebuf, ": "); 696335640Shselasky strcat (ebuf, pktInfo.error); 697335640Shselasky } 698335640Shselasky return (NULL); 699335640Shselasky } 700335640Shselasky 701335640Shselasky /* Some devices need this to operate in promiscous mode 702335640Shselasky */ 703335640Shselasky if (promisc && dev->set_multicast_list) 704335640Shselasky (*dev->set_multicast_list) (dev); 705335640Shselasky 706335640Shselasky active_dev = dev; /* remember our active device */ 707335640Shselasky break; 708335640Shselasky } 709335640Shselasky 710335640Shselasky /* 'dev_name' not matched in 'dev_base' list. 711335640Shselasky */ 712335640Shselasky if (!dev) 713335640Shselasky { 714335640Shselasky pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name); 715335640Shselasky return (NULL); 716335640Shselasky } 717335640Shselasky 718335640Shselaskynot_probed: 719335640Shselasky if (!probed_dev) 720335640Shselasky { 721335640Shselasky pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name); 722335640Shselasky return (NULL); 723335640Shselasky } 724335640Shselasky return (dev); 725335640Shselasky} 726335640Shselasky 727335640Shselasky/* 728335640Shselasky * Deinitialise MAC driver. 729335640Shselasky * Set receive mode back to default mode. 730335640Shselasky */ 731335640Shselaskystatic void close_driver (void) 732335640Shselasky{ 733335640Shselasky /* !!todo: loop over all 'handle_to_device[]' ? */ 734335640Shselasky struct device *dev = active_dev; 735335640Shselasky 736335640Shselasky if (dev && dev->close) 737335640Shselasky { 738335640Shselasky (*dev->close) (dev); 739335640Shselasky FLUSHK(); 740335640Shselasky } 741335640Shselasky 742335640Shselasky active_dev = NULL; 743335640Shselasky 744335640Shselasky#ifdef USE_32BIT_DRIVERS 745335640Shselasky if (rx_pool) 746335640Shselasky { 747335640Shselasky k_free (rx_pool); 748335640Shselasky rx_pool = NULL; 749335640Shselasky } 750335640Shselasky if (dev) 751335640Shselasky pcibios_exit(); 752335640Shselasky#endif 753335640Shselasky} 754335640Shselasky 755335640Shselasky 756335640Shselasky#ifdef __DJGPP__ 757335640Shselaskystatic void setup_signals (void (*handler)(int)) 758335640Shselasky{ 759335640Shselasky signal (SIGSEGV,handler); 760335640Shselasky signal (SIGILL, handler); 761335640Shselasky signal (SIGFPE, handler); 762335640Shselasky} 763335640Shselasky 764335640Shselaskystatic void exc_handler (int sig) 765335640Shselasky{ 766335640Shselasky#ifdef USE_32BIT_DRIVERS 767335640Shselasky if (active_dev->irq > 0) /* excludes IRQ 0 */ 768335640Shselasky { 769335640Shselasky disable_irq (active_dev->irq); 770335640Shselasky irq_eoi_cmd (active_dev->irq); 771335640Shselasky _printk_safe = 1; 772335640Shselasky } 773335640Shselasky#endif 774335640Shselasky 775335640Shselasky switch (sig) 776335640Shselasky { 777335640Shselasky case SIGSEGV: 778335640Shselasky fputs ("Catching SIGSEGV.\n", stderr); 779335640Shselasky break; 780335640Shselasky case SIGILL: 781335640Shselasky fputs ("Catching SIGILL.\n", stderr); 782335640Shselasky break; 783335640Shselasky case SIGFPE: 784335640Shselasky _fpreset(); 785335640Shselasky fputs ("Catching SIGFPE.\n", stderr); 786335640Shselasky break; 787335640Shselasky default: 788335640Shselasky fprintf (stderr, "Catching signal %d.\n", sig); 789335640Shselasky } 790335640Shselasky exc_occured = 1; 791335640Shselasky close_driver(); 792335640Shselasky} 793335640Shselasky#endif /* __DJGPP__ */ 794335640Shselasky 795335640Shselasky 796335640Shselasky/* 797335640Shselasky * Open the pcap device for the first client calling pcap_activate() 798335640Shselasky */ 799335640Shselaskystatic int first_init (const char *name, char *ebuf, int promisc) 800335640Shselasky{ 801335640Shselasky struct device *dev; 802335640Shselasky 803335640Shselasky#ifdef USE_32BIT_DRIVERS 804335640Shselasky rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE); 805335640Shselasky if (!rx_pool) 806335640Shselasky { 807335640Shselasky strcpy (ebuf, "Not enough memory (Rx pool)"); 808335640Shselasky return (0); 809335640Shselasky } 810335640Shselasky#endif 811335640Shselasky 812335640Shselasky#ifdef __DJGPP__ 813335640Shselasky setup_signals (exc_handler); 814335640Shselasky#endif 815335640Shselasky 816335640Shselasky#ifdef USE_32BIT_DRIVERS 817335640Shselasky init_32bit(); 818335640Shselasky#endif 819335640Shselasky 820335640Shselasky dev = open_driver (name, ebuf, promisc); 821335640Shselasky if (!dev) 822335640Shselasky { 823335640Shselasky#ifdef USE_32BIT_DRIVERS 824335640Shselasky k_free (rx_pool); 825335640Shselasky rx_pool = NULL; 826335640Shselasky#endif 827335640Shselasky 828335640Shselasky#ifdef __DJGPP__ 829335640Shselasky setup_signals (SIG_DFL); 830335640Shselasky#endif 831335640Shselasky return (0); 832335640Shselasky } 833335640Shselasky 834335640Shselasky#ifdef USE_32BIT_DRIVERS 835335640Shselasky /* 836335640Shselasky * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf' 837335640Shselasky * set in it's probe handler), initialise near-memory ring-buffer for 838335640Shselasky * the 32-bit device. 839335640Shselasky */ 840335640Shselasky if (dev->copy_rx_buf == NULL) 841335640Shselasky { 842335640Shselasky dev->get_rx_buf = get_rxbuf; 843335640Shselasky dev->peek_rx_buf = peek_rxbuf; 844335640Shselasky dev->release_rx_buf = release_rxbuf; 845335640Shselasky pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool); 846335640Shselasky } 847335640Shselasky#endif 848335640Shselasky return (1); 849335640Shselasky} 850335640Shselasky 851335640Shselasky#ifdef USE_32BIT_DRIVERS 852335640Shselaskystatic void init_32bit (void) 853335640Shselasky{ 854335640Shselasky static int init_pci = 0; 855335640Shselasky 856335640Shselasky if (!_printk_file) 857335640Shselasky _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */ 858335640Shselasky 859335640Shselasky if (!init_pci) 860335640Shselasky (void)pci_init(); /* init BIOS32+PCI interface */ 861335640Shselasky init_pci = 1; 862335640Shselasky} 863335640Shselasky#endif 864335640Shselasky 865335640Shselasky 866335640Shselasky/* 867335640Shselasky * Hook functions for using Watt-32 together with pcap 868335640Shselasky */ 869335640Shselaskystatic char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */ 870335640Shselaskystatic WORD etype; 871335640Shselaskystatic pcap_t pcap_save; 872335640Shselasky 873335640Shselaskystatic void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, 874335640Shselasky const u_char *buf) 875335640Shselasky{ 876335640Shselasky /* Fix me: assumes Ethernet II only */ 877335640Shselasky struct ether_header *ep = (struct ether_header*) buf; 878335640Shselasky 879335640Shselasky memcpy (rxbuf, buf, pcap->caplen); 880335640Shselasky etype = ep->ether_type; 881335640Shselasky ARGSUSED (dummy); 882335640Shselasky} 883335640Shselasky 884335640Shselasky#if (WATTCP_VER >= 0x0224) 885335640Shselasky/* 886335640Shselasky * This function is used by Watt-32 to poll for a packet. 887335640Shselasky * i.e. it's set to bypass _eth_arrived() 888335640Shselasky */ 889335640Shselaskystatic void *pcap_recv_hook (WORD *type) 890335640Shselasky{ 891335640Shselasky int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL); 892335640Shselasky 893335640Shselasky if (len < 0) 894335640Shselasky return (NULL); 895335640Shselasky 896335640Shselasky *type = etype; 897335640Shselasky return (void*) &rxbuf; 898335640Shselasky} 899335640Shselasky 900335640Shselasky/* 901335640Shselasky * This function is called by Watt-32 (via _eth_xmit_hook). 902335640Shselasky * If dbug_init() was called, we should trace packets sent. 903335640Shselasky */ 904335640Shselaskystatic int pcap_xmit_hook (const void *buf, unsigned len) 905335640Shselasky{ 906335640Shselasky int rc = 0; 907335640Shselasky 908335640Shselasky if (pcap_pkt_debug > 0) 909335640Shselasky dbug_write ("pcap_xmit_hook: "); 910335640Shselasky 911335640Shselasky if (active_dev && active_dev->xmit) 912335640Shselasky if ((*active_dev->xmit) (active_dev, buf, len) > 0) 913335640Shselasky rc = len; 914335640Shselasky 915335640Shselasky if (pcap_pkt_debug > 0) 916335640Shselasky dbug_write (rc ? "ok\n" : "fail\n"); 917335640Shselasky return (rc); 918335640Shselasky} 919335640Shselasky#endif 920335640Shselasky 921335640Shselaskystatic int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len) 922335640Shselasky{ 923335640Shselasky struct device *dev = p ? get_device(p->fd) : NULL; 924335640Shselasky 925335640Shselasky if (!dev || !dev->xmit) 926335640Shselasky return (-1); 927335640Shselasky return (*dev->xmit) (dev, buf, len); 928335640Shselasky} 929335640Shselasky 930335640Shselasky/* 931335640Shselasky * This function is called by Watt-32 in tcp_post_init(). 932335640Shselasky * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc. 933335640Shselasky */ 934335640Shselaskystatic void (*prev_post_hook) (void); 935335640Shselasky 936335640Shselaskystatic void pcap_init_hook (void) 937335640Shselasky{ 938335640Shselasky _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0; 939335640Shselasky _w32__do_mask_req = 0; 940335640Shselasky _w32_dynamic_host = 0; 941335640Shselasky if (prev_post_hook) 942335640Shselasky (*prev_post_hook)(); 943335640Shselasky} 944335640Shselasky 945335640Shselasky/* 946335640Shselasky * Supress PRINT message from Watt-32's sock_init() 947335640Shselasky */ 948335640Shselaskystatic void null_print (void) {} 949335640Shselasky 950335640Shselasky/* 951335640Shselasky * To use features of Watt-32 (netdb functions and socket etc.) 952335640Shselasky * we must call sock_init(). But we set various hooks to prevent 953335640Shselasky * using normal PKTDRVR functions in pcpkt.c. This should hopefully 954335640Shselasky * make Watt-32 and pcap co-operate. 955335640Shselasky */ 956335640Shselaskystatic int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf) 957335640Shselasky{ 958335640Shselasky char *env; 959335640Shselasky int rc, MTU, has_ip_addr; 960335640Shselasky int using_pktdrv = 1; 961335640Shselasky 962335640Shselasky /* If user called sock_init() first, we need to reinit in 963335640Shselasky * order to open debug/trace-file properly 964335640Shselasky */ 965335640Shselasky if (_watt_is_init) 966335640Shselasky sock_exit(); 967335640Shselasky 968335640Shselasky env = getenv ("PCAP_TRACE"); 969335640Shselasky if (env && atoi(env) > 0 && 970335640Shselasky pcap_pkt_debug < 0) /* if not already set */ 971335640Shselasky { 972335640Shselasky dbug_init(); 973335640Shselasky pcap_pkt_debug = atoi (env); 974335640Shselasky } 975335640Shselasky 976335640Shselasky _watt_do_exit = 0; /* prevent sock_init() calling exit() */ 977335640Shselasky prev_post_hook = _w32_usr_post_init; 978335640Shselasky _w32_usr_post_init = pcap_init_hook; 979335640Shselasky _w32_print_hook = null_print; 980335640Shselasky 981335640Shselasky if (dev_name && strncmp(dev_name,"pkt",3)) 982335640Shselasky using_pktdrv = FALSE; 983335640Shselasky 984335640Shselasky rc = sock_init(); 985335640Shselasky has_ip_addr = (rc != 8); /* IP-address assignment failed */ 986335640Shselasky 987335640Shselasky /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we 988335640Shselasky * just pretend Watt-32 is initialised okay. 989335640Shselasky * 990335640Shselasky * !! fix-me: The Watt-32 config isn't done if no pktdrvr 991335640Shselasky * was found. In that case my_ip_addr + sin_mask 992335640Shselasky * have default values. Should be taken from another 993335640Shselasky * ini-file/environment in any case (ref. tcpdump.ini) 994335640Shselasky */ 995335640Shselasky _watt_is_init = 1; 996335640Shselasky 997335640Shselasky if (!using_pktdrv || !has_ip_addr) /* for now .... */ 998335640Shselasky { 999335640Shselasky static const char myip[] = "192.168.0.1"; 1000335640Shselasky static const char mask[] = "255.255.255.0"; 1001335640Shselasky 1002335640Shselasky printf ("Just guessing, using IP %s and netmask %s\n", myip, mask); 1003335640Shselasky my_ip_addr = aton (myip); 1004335640Shselasky _w32_sin_mask = aton (mask); 1005335640Shselasky } 1006335640Shselasky else if (rc && using_pktdrv) 1007335640Shselasky { 1008335640Shselasky pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc); 1009335640Shselasky return (0); 1010335640Shselasky } 1011335640Shselasky 1012335640Shselasky /* Set recv-hook for peeking in _eth_arrived(). 1013335640Shselasky */ 1014335640Shselasky#if (WATTCP_VER >= 0x0224) 1015335640Shselasky _eth_recv_hook = pcap_recv_hook; 1016335640Shselasky _eth_xmit_hook = pcap_xmit_hook; 1017335640Shselasky#endif 1018335640Shselasky 1019335640Shselasky /* Free the pkt-drvr handle allocated in pkt_init(). 1020335640Shselasky * The above hooks should thus use the handle reopened in open_driver() 1021335640Shselasky */ 1022335640Shselasky if (using_pktdrv) 1023335640Shselasky { 1024335640Shselasky _eth_release(); 1025335640Shselasky/* _eth_is_init = 1; */ /* hack to get Rx/Tx-hooks in Watt-32 working */ 1026335640Shselasky } 1027335640Shselasky 1028335640Shselasky memcpy (&pcap_save, pcap, sizeof(pcap_save)); 1029335640Shselasky MTU = pkt_get_mtu(); 1030335640Shselasky pcap_save.fcode.bf_insns = NULL; 1031335640Shselasky pcap_save.linktype = _eth_get_hwtype (NULL, NULL); 1032335640Shselasky pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */ 1033335640Shselasky 1034335640Shselasky#if 1 1035335640Shselasky /* prevent use of resolve() and resolve_ip() 1036335640Shselasky */ 1037335640Shselasky last_nameserver = 0; 1038335640Shselasky#endif 1039335640Shselasky return (1); 1040335640Shselasky} 1041335640Shselasky 1042335640Shselaskyint EISA_bus = 0; /* Where is natural place for this? */ 1043335640Shselasky 1044335640Shselasky/* 1045335640Shselasky * Application config hooks to set various driver parameters. 1046335640Shselasky */ 1047335640Shselasky 1048335640Shselaskystatic const struct config_table debug_tab[] = { 1049335640Shselasky { "PKT.DEBUG", ARG_ATOI, &pcap_pkt_debug }, 1050335640Shselasky { "PKT.VECTOR", ARG_ATOX_W, NULL }, 1051335640Shselasky { "NDIS.DEBUG", ARG_ATOI, NULL }, 1052335640Shselasky#ifdef USE_32BIT_DRIVERS 1053335640Shselasky { "3C503.DEBUG", ARG_ATOI, &ei_debug }, 1054335640Shselasky { "3C503.IO_BASE", ARG_ATOX_W, &el2_dev.base_addr }, 1055335640Shselasky { "3C503.MEMORY", ARG_ATOX_W, &el2_dev.mem_start }, 1056335640Shselasky { "3C503.IRQ", ARG_ATOI, &el2_dev.irq }, 1057335640Shselasky { "3C505.DEBUG", ARG_ATOI, NULL }, 1058335640Shselasky { "3C505.BASE", ARG_ATOX_W, NULL }, 1059335640Shselasky { "3C507.DEBUG", ARG_ATOI, NULL }, 1060335640Shselasky { "3C509.DEBUG", ARG_ATOI, &el3_debug }, 1061335640Shselasky { "3C509.ILOOP", ARG_ATOI, &el3_max_loop }, 1062335640Shselasky { "3C529.DEBUG", ARG_ATOI, NULL }, 1063335640Shselasky { "3C575.DEBUG", ARG_ATOI, &debug_3c575 }, 1064335640Shselasky { "3C59X.DEBUG", ARG_ATOI, &vortex_debug }, 1065335640Shselasky { "3C59X.IFACE0", ARG_ATOI, &vortex_options[0] }, 1066335640Shselasky { "3C59X.IFACE1", ARG_ATOI, &vortex_options[1] }, 1067335640Shselasky { "3C59X.IFACE2", ARG_ATOI, &vortex_options[2] }, 1068335640Shselasky { "3C59X.IFACE3", ARG_ATOI, &vortex_options[3] }, 1069335640Shselasky { "3C90X.DEBUG", ARG_ATOX_W, &tc90xbc_debug }, 1070335640Shselasky { "ACCT.DEBUG", ARG_ATOI, ðpk_debug }, 1071335640Shselasky { "CS89.DEBUG", ARG_ATOI, &cs89_debug }, 1072335640Shselasky { "RTL8139.DEBUG", ARG_ATOI, &rtl8139_debug }, 1073335640Shselasky /* { "RTL8139.FDUPLEX", ARG_ATOI, &rtl8139_options }, */ 1074335640Shselasky { "SMC.DEBUG", ARG_ATOI, &ei_debug }, 1075335640Shselasky /* { "E100.DEBUG", ARG_ATOI, &e100_debug }, */ 1076335640Shselasky { "PCI.DEBUG", ARG_ATOI, &pci_debug }, 1077335640Shselasky { "BIOS32.DEBUG", ARG_ATOI, &bios32_debug }, 1078335640Shselasky { "IRQ.DEBUG", ARG_ATOI, &irq_debug }, 1079335640Shselasky { "TIMER.IRQ", ARG_ATOI, &timer_irq }, 1080335640Shselasky#endif 1081335640Shselasky { NULL } 1082335640Shselasky }; 1083335640Shselasky 1084335640Shselasky/* 1085335640Shselasky * pcap_config_hook() is an extension to application's config 1086335640Shselasky * handling. Uses Watt-32's config-table function. 1087335640Shselasky */ 1088335640Shselaskyint pcap_config_hook (const char *keyword, const char *value) 1089335640Shselasky{ 1090335640Shselasky return parse_config_table (debug_tab, NULL, keyword, value); 1091335640Shselasky} 1092335640Shselasky 1093335640Shselasky/* 1094335640Shselasky * Linked list of supported devices 1095335640Shselasky */ 1096335640Shselaskystruct device *active_dev = NULL; /* the device we have opened */ 1097335640Shselaskystruct device *probed_dev = NULL; /* the device we have probed */ 1098335640Shselaskyconst struct device *dev_base = &pkt_dev; /* list of network devices */ 1099335640Shselasky 1100335640Shselasky/* 1101335640Shselasky * PKTDRVR device functions 1102335640Shselasky */ 1103335640Shselaskyint pcap_pkt_debug = -1; 1104335640Shselasky 1105335640Shselaskystatic void pkt_close (struct device *dev) 1106335640Shselasky{ 1107335640Shselasky BOOL okay = PktExitDriver(); 1108335640Shselasky 1109335640Shselasky if (pcap_pkt_debug > 1) 1110335640Shselasky fprintf (stderr, "pkt_close(): %d\n", okay); 1111335640Shselasky 1112335640Shselasky if (dev->priv) 1113335640Shselasky free (dev->priv); 1114335640Shselasky dev->priv = NULL; 1115335640Shselasky} 1116335640Shselasky 1117335640Shselaskystatic int pkt_open (struct device *dev) 1118335640Shselasky{ 1119335640Shselasky PKT_RX_MODE mode; 1120335640Shselasky 1121335640Shselasky if (dev->flags & IFF_PROMISC) 1122335640Shselasky mode = PDRX_ALL_PACKETS; 1123335640Shselasky else mode = PDRX_BROADCAST; 1124335640Shselasky 1125335640Shselasky if (!PktInitDriver(mode)) 1126335640Shselasky return (0); 1127335640Shselasky 1128335640Shselasky PktResetStatistics (pktInfo.handle); 1129335640Shselasky PktQueueBusy (FALSE); 1130335640Shselasky return (1); 1131335640Shselasky} 1132335640Shselasky 1133335640Shselaskystatic int pkt_xmit (struct device *dev, const void *buf, int len) 1134335640Shselasky{ 1135335640Shselasky struct net_device_stats *stats = (struct net_device_stats*) dev->priv; 1136335640Shselasky 1137335640Shselasky if (pcap_pkt_debug > 0) 1138335640Shselasky dbug_write ("pcap_xmit\n"); 1139335640Shselasky 1140335640Shselasky if (!PktTransmit(buf,len)) 1141335640Shselasky { 1142335640Shselasky stats->tx_errors++; 1143335640Shselasky return (0); 1144335640Shselasky } 1145335640Shselasky return (len); 1146335640Shselasky} 1147335640Shselasky 1148335640Shselaskystatic void *pkt_stats (struct device *dev) 1149335640Shselasky{ 1150335640Shselasky struct net_device_stats *stats = (struct net_device_stats*) dev->priv; 1151335640Shselasky 1152335640Shselasky if (!stats || !PktSessStatistics(pktInfo.handle)) 1153335640Shselasky return (NULL); 1154335640Shselasky 1155335640Shselasky stats->rx_packets = pktStat.inPackets; 1156335640Shselasky stats->rx_errors = pktStat.lost; 1157335640Shselasky stats->rx_missed_errors = PktRxDropped(); 1158335640Shselasky return (stats); 1159335640Shselasky} 1160335640Shselasky 1161335640Shselaskystatic int pkt_probe (struct device *dev) 1162335640Shselasky{ 1163335640Shselasky if (!PktSearchDriver()) 1164335640Shselasky return (0); 1165335640Shselasky 1166335640Shselasky dev->open = pkt_open; 1167335640Shselasky dev->xmit = pkt_xmit; 1168335640Shselasky dev->close = pkt_close; 1169335640Shselasky dev->get_stats = pkt_stats; 1170335640Shselasky dev->copy_rx_buf = PktReceive; /* farmem peek and copy routine */ 1171335640Shselasky dev->get_rx_buf = NULL; 1172335640Shselasky dev->peek_rx_buf = NULL; 1173335640Shselasky dev->release_rx_buf = NULL; 1174335640Shselasky dev->priv = calloc (sizeof(struct net_device_stats), 1); 1175335640Shselasky if (!dev->priv) 1176335640Shselasky return (0); 1177335640Shselasky return (1); 1178335640Shselasky} 1179335640Shselasky 1180335640Shselasky/* 1181335640Shselasky * NDIS device functions 1182335640Shselasky */ 1183335640Shselaskystatic void ndis_close (struct device *dev) 1184335640Shselasky{ 1185335640Shselasky#ifdef USE_NDIS2 1186335640Shselasky NdisShutdown(); 1187335640Shselasky#endif 1188335640Shselasky ARGSUSED (dev); 1189335640Shselasky} 1190335640Shselasky 1191335640Shselaskystatic int ndis_open (struct device *dev) 1192335640Shselasky{ 1193335640Shselasky int promis = (dev->flags & IFF_PROMISC); 1194335640Shselasky 1195335640Shselasky#ifdef USE_NDIS2 1196335640Shselasky if (!NdisInit(promis)) 1197335640Shselasky return (0); 1198335640Shselasky return (1); 1199335640Shselasky#else 1200335640Shselasky ARGSUSED (promis); 1201335640Shselasky return (0); 1202335640Shselasky#endif 1203335640Shselasky} 1204335640Shselasky 1205335640Shselaskystatic void *ndis_stats (struct device *dev) 1206335640Shselasky{ 1207335640Shselasky static struct net_device_stats stats; 1208335640Shselasky 1209335640Shselasky /* to-do */ 1210335640Shselasky ARGSUSED (dev); 1211335640Shselasky return (&stats); 1212335640Shselasky} 1213335640Shselasky 1214335640Shselaskystatic int ndis_probe (struct device *dev) 1215335640Shselasky{ 1216335640Shselasky#ifdef USE_NDIS2 1217335640Shselasky if (!NdisOpen()) 1218335640Shselasky return (0); 1219335640Shselasky#endif 1220335640Shselasky 1221335640Shselasky dev->open = ndis_open; 1222335640Shselasky dev->xmit = NULL; 1223335640Shselasky dev->close = ndis_close; 1224335640Shselasky dev->get_stats = ndis_stats; 1225335640Shselasky dev->copy_rx_buf = NULL; /* to-do */ 1226335640Shselasky dev->get_rx_buf = NULL; /* upcall is from rmode driver */ 1227335640Shselasky dev->peek_rx_buf = NULL; 1228335640Shselasky dev->release_rx_buf = NULL; 1229335640Shselasky return (0); 1230335640Shselasky} 1231335640Shselasky 1232335640Shselasky/* 1233335640Shselasky * Search & probe for supported 32-bit (pmode) pcap devices 1234335640Shselasky */ 1235335640Shselasky#if defined(USE_32BIT_DRIVERS) 1236335640Shselasky 1237335640Shselaskystruct device el2_dev LOCKED_VAR = { 1238335640Shselasky "3c503", 1239335640Shselasky "EtherLink II", 1240335640Shselasky 0, 1241335640Shselasky 0,0,0,0,0,0, 1242335640Shselasky NULL, 1243335640Shselasky el2_probe 1244335640Shselasky }; 1245335640Shselasky 1246335640Shselaskystruct device el3_dev LOCKED_VAR = { 1247335640Shselasky "3c509", 1248335640Shselasky "EtherLink III", 1249335640Shselasky 0, 1250335640Shselasky 0,0,0,0,0,0, 1251335640Shselasky &el2_dev, 1252335640Shselasky el3_probe 1253335640Shselasky }; 1254335640Shselasky 1255335640Shselaskystruct device tc515_dev LOCKED_VAR = { 1256335640Shselasky "3c515", 1257335640Shselasky "EtherLink PCI", 1258335640Shselasky 0, 1259335640Shselasky 0,0,0,0,0,0, 1260335640Shselasky &el3_dev, 1261335640Shselasky tc515_probe 1262335640Shselasky }; 1263335640Shselasky 1264335640Shselaskystruct device tc59_dev LOCKED_VAR = { 1265335640Shselasky "3c59x", 1266335640Shselasky "EtherLink PCI", 1267335640Shselasky 0, 1268335640Shselasky 0,0,0,0,0,0, 1269335640Shselasky &tc515_dev, 1270335640Shselasky tc59x_probe 1271335640Shselasky }; 1272335640Shselasky 1273335640Shselaskystruct device tc90xbc_dev LOCKED_VAR = { 1274335640Shselasky "3c90x", 1275335640Shselasky "EtherLink 90X", 1276335640Shselasky 0, 1277335640Shselasky 0,0,0,0,0,0, 1278335640Shselasky &tc59_dev, 1279335640Shselasky tc90xbc_probe 1280335640Shselasky }; 1281335640Shselasky 1282335640Shselaskystruct device wd_dev LOCKED_VAR = { 1283335640Shselasky "wd", 1284335640Shselasky "Westen Digital", 1285335640Shselasky 0, 1286335640Shselasky 0,0,0,0,0,0, 1287335640Shselasky &tc90xbc_dev, 1288335640Shselasky wd_probe 1289335640Shselasky }; 1290335640Shselasky 1291335640Shselaskystruct device ne_dev LOCKED_VAR = { 1292335640Shselasky "ne", 1293335640Shselasky "NEx000", 1294335640Shselasky 0, 1295335640Shselasky 0,0,0,0,0,0, 1296335640Shselasky &wd_dev, 1297335640Shselasky ne_probe 1298335640Shselasky }; 1299335640Shselasky 1300335640Shselaskystruct device acct_dev LOCKED_VAR = { 1301335640Shselasky "acct", 1302335640Shselasky "Accton EtherPocket", 1303335640Shselasky 0, 1304335640Shselasky 0,0,0,0,0,0, 1305335640Shselasky &ne_dev, 1306335640Shselasky ethpk_probe 1307335640Shselasky }; 1308335640Shselasky 1309335640Shselaskystruct device cs89_dev LOCKED_VAR = { 1310335640Shselasky "cs89", 1311335640Shselasky "Crystal Semiconductor", 1312335640Shselasky 0, 1313335640Shselasky 0,0,0,0,0,0, 1314335640Shselasky &acct_dev, 1315335640Shselasky cs89x0_probe 1316335640Shselasky }; 1317335640Shselasky 1318335640Shselaskystruct device rtl8139_dev LOCKED_VAR = { 1319335640Shselasky "rtl8139", 1320335640Shselasky "RealTek PCI", 1321335640Shselasky 0, 1322335640Shselasky 0,0,0,0,0,0, 1323335640Shselasky &cs89_dev, 1324335640Shselasky rtl8139_probe /* dev->probe routine */ 1325335640Shselasky }; 1326335640Shselasky 1327335640Shselasky/* 1328335640Shselasky * Dequeue routine is called by polling. 1329335640Shselasky * NOTE: the queue-element is not copied, only a pointer is 1330335640Shselasky * returned at '*buf' 1331335640Shselasky */ 1332335640Shselaskyint peek_rxbuf (BYTE **buf) 1333335640Shselasky{ 1334335640Shselasky struct rx_elem *tail, *head; 1335335640Shselasky 1336335640Shselasky PCAP_ASSERT (pktq_check (&active_dev->queue)); 1337335640Shselasky 1338335640Shselasky DISABLE(); 1339335640Shselasky tail = pktq_out_elem (&active_dev->queue); 1340335640Shselasky head = pktq_in_elem (&active_dev->queue); 1341335640Shselasky ENABLE(); 1342335640Shselasky 1343335640Shselasky if (head != tail) 1344335640Shselasky { 1345335640Shselasky PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2); 1346335640Shselasky 1347335640Shselasky *buf = &tail->data[0]; 1348335640Shselasky return (tail->size); 1349335640Shselasky } 1350335640Shselasky *buf = NULL; 1351335640Shselasky return (0); 1352335640Shselasky} 1353335640Shselasky 1354335640Shselasky/* 1355335640Shselasky * Release buffer we peeked at above. 1356335640Shselasky */ 1357335640Shselaskyint release_rxbuf (BYTE *buf) 1358335640Shselasky{ 1359335640Shselasky#ifndef NDEBUG 1360335640Shselasky struct rx_elem *tail = pktq_out_elem (&active_dev->queue); 1361335640Shselasky 1362335640Shselasky PCAP_ASSERT (&tail->data[0] == buf); 1363335640Shselasky#else 1364335640Shselasky ARGSUSED (buf); 1365335640Shselasky#endif 1366335640Shselasky pktq_inc_out (&active_dev->queue); 1367335640Shselasky return (1); 1368335640Shselasky} 1369335640Shselasky 1370335640Shselasky/* 1371335640Shselasky * get_rxbuf() routine (in locked code) is called from IRQ handler 1372335640Shselasky * to request a buffer. Interrupts are disabled and we have a 32kB stack. 1373335640Shselasky */ 1374335640ShselaskyBYTE *get_rxbuf (int len) 1375335640Shselasky{ 1376335640Shselasky int idx; 1377335640Shselasky 1378335640Shselasky if (len < ETH_MIN || len > ETH_MAX) 1379335640Shselasky return (NULL); 1380335640Shselasky 1381335640Shselasky idx = pktq_in_index (&active_dev->queue); 1382335640Shselasky 1383335640Shselasky#ifdef DEBUG 1384335640Shselasky { 1385335640Shselasky static int fan_idx LOCKED_VAR = 0; 1386335640Shselasky writew ("-\\|/"[fan_idx++] | (15 << 8), /* white on black colour */ 1387335640Shselasky 0xB8000 + 2*79); /* upper-right corner, 80-col colour screen */ 1388335640Shselasky fan_idx &= 3; 1389335640Shselasky } 1390335640Shselasky/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */ 1391335640Shselasky#endif 1392335640Shselasky 1393335640Shselasky if (idx != active_dev->queue.out_index) 1394335640Shselasky { 1395335640Shselasky struct rx_elem *head = pktq_in_elem (&active_dev->queue); 1396335640Shselasky 1397335640Shselasky head->size = len; 1398335640Shselasky active_dev->queue.in_index = idx; 1399335640Shselasky return (&head->data[0]); 1400335640Shselasky } 1401335640Shselasky 1402335640Shselasky /* !!to-do: drop 25% of the oldest element 1403335640Shselasky */ 1404335640Shselasky pktq_clear (&active_dev->queue); 1405335640Shselasky return (NULL); 1406335640Shselasky} 1407335640Shselasky 1408335640Shselasky/* 1409335640Shselasky * Simple ring-buffer queue handler for reception of packets 1410335640Shselasky * from network driver. 1411335640Shselasky */ 1412335640Shselasky#define PKTQ_MARKER 0xDEADBEEF 1413335640Shselasky 1414335640Shselaskystatic int pktq_check (struct rx_ringbuf *q) 1415335640Shselasky{ 1416335640Shselasky#ifndef NDEBUG 1417335640Shselasky int i; 1418335640Shselasky char *buf; 1419335640Shselasky#endif 1420335640Shselasky 1421335640Shselasky if (!q || !q->num_elem || !q->buf_start) 1422335640Shselasky return (0); 1423335640Shselasky 1424335640Shselasky#ifndef NDEBUG 1425335640Shselasky buf = q->buf_start; 1426335640Shselasky 1427335640Shselasky for (i = 0; i < q->num_elem; i++) 1428335640Shselasky { 1429335640Shselasky buf += q->elem_size; 1430335640Shselasky if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER) 1431335640Shselasky return (0); 1432335640Shselasky } 1433335640Shselasky#endif 1434335640Shselasky return (1); 1435335640Shselasky} 1436335640Shselasky 1437335640Shselaskystatic int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool) 1438335640Shselasky{ 1439335640Shselasky int i; 1440335640Shselasky 1441335640Shselasky q->elem_size = size; 1442335640Shselasky q->num_elem = num; 1443335640Shselasky q->buf_start = pool; 1444335640Shselasky q->in_index = 0; 1445335640Shselasky q->out_index = 0; 1446335640Shselasky 1447335640Shselasky PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD)); 1448335640Shselasky PCAP_ASSERT (num); 1449335640Shselasky PCAP_ASSERT (pool); 1450335640Shselasky 1451335640Shselasky for (i = 0; i < num; i++) 1452335640Shselasky { 1453335640Shselasky#if 0 1454335640Shselasky struct rx_elem *elem = (struct rx_elem*) pool; 1455335640Shselasky 1456335640Shselasky /* assert dword aligned elements 1457335640Shselasky */ 1458335640Shselasky PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0); 1459335640Shselasky#endif 1460335640Shselasky pool += size; 1461335640Shselasky *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER; 1462335640Shselasky } 1463335640Shselasky return (1); 1464335640Shselasky} 1465335640Shselasky 1466335640Shselasky/* 1467335640Shselasky * Increment the queue 'out_index' (tail). 1468335640Shselasky * Check for wraps. 1469335640Shselasky */ 1470335640Shselaskystatic int pktq_inc_out (struct rx_ringbuf *q) 1471335640Shselasky{ 1472335640Shselasky q->out_index++; 1473335640Shselasky if (q->out_index >= q->num_elem) 1474335640Shselasky q->out_index = 0; 1475335640Shselasky return (q->out_index); 1476335640Shselasky} 1477335640Shselasky 1478335640Shselasky/* 1479335640Shselasky * Return the queue's next 'in_index' (head). 1480335640Shselasky * Check for wraps. 1481335640Shselasky */ 1482335640Shselaskystatic int pktq_in_index (struct rx_ringbuf *q) 1483335640Shselasky{ 1484335640Shselasky volatile int index = q->in_index + 1; 1485335640Shselasky 1486335640Shselasky if (index >= q->num_elem) 1487335640Shselasky index = 0; 1488335640Shselasky return (index); 1489335640Shselasky} 1490335640Shselasky 1491335640Shselasky/* 1492335640Shselasky * Return the queue's head-buffer. 1493335640Shselasky */ 1494335640Shselaskystatic struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) 1495335640Shselasky{ 1496335640Shselasky return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index)); 1497335640Shselasky} 1498335640Shselasky 1499335640Shselasky/* 1500335640Shselasky * Return the queue's tail-buffer. 1501335640Shselasky */ 1502335640Shselaskystatic struct rx_elem *pktq_out_elem (struct rx_ringbuf *q) 1503335640Shselasky{ 1504335640Shselasky return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index)); 1505335640Shselasky} 1506335640Shselasky 1507335640Shselasky/* 1508335640Shselasky * Clear the queue ring-buffer by setting head=tail. 1509335640Shselasky */ 1510335640Shselaskystatic void pktq_clear (struct rx_ringbuf *q) 1511335640Shselasky{ 1512335640Shselasky q->in_index = q->out_index; 1513335640Shselasky} 1514335640Shselasky 1515335640Shselasky/* 1516335640Shselasky * Symbols that must be linkable for "gcc -O0" 1517335640Shselasky */ 1518335640Shselasky#undef __IOPORT_H 1519335640Shselasky#undef __DMA_H 1520335640Shselasky 1521335640Shselasky#define extern 1522335640Shselasky#define __inline__ 1523335640Shselasky 1524335640Shselasky#include "msdos/pm_drvr/ioport.h" 1525335640Shselasky#include "msdos/pm_drvr/dma.h" 1526335640Shselasky 1527335640Shselasky#endif /* USE_32BIT_DRIVERS */ 1528335640Shselasky 1529335640Shselasky/* 1530335640Shselasky * Libpcap version string. 1531335640Shselasky */ 1532335640Shselaskyconst char * 1533335640Shselaskypcap_lib_version(void) 1534335640Shselasky{ 1535335640Shselasky return ("DOS-" PCAP_VERSION_STRING); 1536335640Shselasky} 1537