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