diff --git a/CHANGES b/CHANGES index d174cd5e1a9c..c574a278064f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,1416 +1,1430 @@ +Friday, April 7, 2023 / The Tcpdump Group + Summary for 1.10.4 libpcap release + Source code: + Fix spaces before tabs in indentation. + rpcap: + Fix name of launchd service. + Documentation: + Document use of rpcapd with systemd, launchd, inetd, and xinetd. + Building and testing: + Require at least pkg-config 0.17.0, as we use --static. + Get rid of the remains of gnuc.h. + Require at least autoconf 2.69. + Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21. + Thursday, January 12, 2023 / The Tcpdump Group Summary for 1.10.3 libpcap release Source code: Sort the PUBHDR variable in Makefile.in in "ls" order. Fix typo in comment in pflog.h. Remove two no-longer-present files from .gitignore. Update code and comments for handling failure to set promiscuous mode based on new information. Building and testing: install: Fixed not to install the non-public pcap-util.h header. pcap-config: add a --version flag. Makefile.in: Add some missing files in the distclean target. Saturday, December 31, 2022 / The Tcpdump Group Summary for 1.10.2 libpcap release Source code: Use __builtin_unreachable() in PCAP_UNREACHABLE. Use AS_HELP_STRING macro instead of AC_HELP_STRING in the configure scripts, to avoid deprecation warnings. Change availability tags in pcap.h to make it easier to arrange for it to be used in Darwin releases. Use AS_HELP_STRING for --enable-remote. Fix some formatting string issues found by cppcheck. Various small code and comment cleanups. Use PCAP_ERROR (defined as -1) rather than explicit -1 for functions the documentation says return PCAP_ERROR. Remove unused code from the filter compiler. Use _declspec(deprecated(msg)) rather than __pragma(deprecated) for Windows deprecation warnings, so the message that was specified shows up. diag-control.h: define PCAP_DO_PRAGMA() iff we're going to use it. Use "%d" to print some signed ints. Use the Wayback Machine for a removed document in a comment. Add some const qualifiers. RDMA: Use PRIu64 to print a uint64_t. "Dead" pcap_ts from pcap_open_dead() and ..._with_tstamp_precision(): Don't crash if pcap_breakloop() is called. Savefiles: Fix pcap_dispatch() to return number of packets processed, rather than 0, even at EOF. If we get an error writing the packet header, don't write the packet data. Put PFLOG UID and PID values in the header into host byte order when reading a LINKTYPE_PFLOG file. Put CAN ID field in CAN pseudo-headers for LINUX_SLL2, as we do for LINUX_SLL. Fix inorrectly-computed "real" length for isochronous USB transfers when reading savefiles. Don't crash if pcap_can_set_rfmon() is called. Fix pcap_offline_read() loop. Capture: Never process more than INT_MAX packets in a pcap_dispatch() call, to avoid integer overflow (issue #1087). Improve error messages for "no such device" and "permission denied" errors. SITA: Fix a typo in a variable name. Packet filtering: Get PFLOG header length from the length value in the header. Support all the direction, reason, and action types supported by all systems that support PFLOG. Don't require PFLOG support on the target machine in order to support PFLOG filtering (also fixes issue #1076). Expand abbreviations into "proto X" properly. gencode.c: Update a comment about the VLAN TPID test. Add the minimum and maximum matching DLTs to an error message. Linux: Fix memory leak in capture device open (pull request #1038). Fix detection of CAN/CAN FD packets in direction check (issue #1051). Fix double-free crashes on errors such as running on a kernel with CONFIG_PACKET_MMAP not configured (issue #1054). Use DLT_CAN_SOCKETCAN for CANbus interfaces (issue #1052; includes changes from pull request #1035). Make sure the CANFD_FDF can be relied on to indicate whether a CANbus packet is a CAN frame or a CAN FD frame Improve error message for "out of memory" errors for kernel filters (see issue #1089). Fix pcap_findalldevs() to find usbmon devices. Fix handling of VLAN tagged packets if the link-layer type is changed from DLT_LINUX_SLL to DLT_LINUX_SLL2 (see issue #1105). Always turn on PACKET_AUXDATA (see issue #1105). We require 2.6.27 or later, so PACKET_RESERVE is available. Make sure there's reserved space for a DLT_LINUX_SLL2 header when capturing. Correctly compute the "real" length for isochronous USB transfers. Don't have an eventfd descriptor open in non-blocking mode, so as not to waste descriptors. netfilter: Squelch a narrowing warning (To be look at before 2038). BPF capture (*BSD, macOS, AIX, Solaris 11): Fix case where a device open might fail, rather than falling back to a smaller buffer size, when the initial buffer size is too big. Use an unsigned device number to iterate over BPF devices, to squelch a compiler warning. NetBSD: Fix handling of LINKTYPE_HDLC/DLT_HDLC. rpcap: Fix unaligned accesses in rpcapd (pull request #1037). Fix code to process port number. Clean up findalldevs code in rpcapd. Clean up bufferizing code. Fix a file descriptor/handle leak in pcap_findalldevs_ex() (Coverity CID 1507240). Improve error messages for host and port resolution errors. Fix connect code not to fail if both IPv4 and IPv6 addresses are tried. Improve connect failure error message. Provide an error message for a bad authentication reply size. For link-layer types with host-endian fields in the header, fix those fields if capturing from a server with a different byte order. Suppress temporarily the warnings with "enable remote packet capture". Windows: Add support for NdisMediumIP (pull request #1027). Don't require applications using pcap to be built with VS 2015 or later. Use the correct string for the DLL VersionInfo. Remove unnecessary DllMain() function. Correctly handle ERROR_INVALID_FUNCTION from PacketGetTimestampModes() (indicate that WinPcap or an older version of Npcap is probably installed). Fix use-after-free in some cases when a pcap_t is closed. Make sure an error is returned by pcap_create_interface() if PacketOpenAdapter() fails. Return an error if the driver reports 0 timestamp modes supported. Close the ADAPTER handle for some errors in pcap_create_interface(). Get rid of old umaintained VS project files. Fix deprecation warning for pcap_handle(). Npcap is now at npcap.com, not npcap.org. Make sure "no such device" and "no permission to open device" errors show up in pcap_activate(), not pcap_create() (fixes, among other things, tcpdump -i ). npcap: squelch deprecation warnings for kernel dump mode. Haiku: Implement pcap_lib_version(), as now required. Handle negative or too-large snaplen values. Fix various build issues and warnings. Building and testing: Update configure-time universal build checks for macOS. Update config.guess and config.sub. If we look for an SSL library with pkg-config in configure script, try pkg-config first. If we have pkg-config and Homebrew, try to set pkg-config up to find Homebrew packages. Handle some Autoconf/make errors better. Use "git archive" for the "make releasetar" process. Remove the release candidate rcX targets. Fix compiling on Solaris 9/SPARC and 11/AMD64. Address assorted compiler warnings. Fix cross-building on Linux for Windows with mingw32 for Win64 (pull request #1031). Properly set installation directory on Windows when not compiling with MSVC. Fix configure script checks for compiler flags. Give more details if check for usable (F)Lex fails. Fix compiling with GCC 4.6.4. Don't use add_compile_options() with CMake, as we currently don't require 2.8.12, where it first appeared. Don't provide -L/usr/lib for pkg-config --libs in pkg-config. Fix error message for inadequate Bison/Berkeley YACC. configure: correctly do some DPDK checks. Only use pkg-config when checking for DPDK. Allow the path in which DPDK is installed to be specified. Use pkg-config first when checking for libibverbs. CMake: fix check for libibverbs with Sun's C compiler. Have CMake warn if no capture mechanism can be found. Don't do stuff requiring 3.19 or later on earlier CMakes. Squelch some CMake warnings. Fix diag-control.h to handle compiling with clang-cl (issues #1101 and #1115). Cleanup various leftover cruft in the configure script. Fix building without protochain support. (GH #852) Check for a usable YACC (or Bison) and {F}lex in CMake, as we do in autotools. Only check for a C++ compiler on Haiku, as that's the only platform with C++ code, and make sure they generate code for the same instruction set bit-width (both 32-bit or both 64-bit) (issue #1112). On Solaris, check the target bit-width and set PKG_CONFIG_PATH appropriately, to handle the mess that is the D-Bus library package (issue #1112). Fix generation of pcap-config and libpcap.pc files (issue #1062). pcap-config: don't assume the system library directory is /usr/lib. pcap-config: add a --static-pcap-only flag. Cirrus CI: Use the same configuration as for the main branch. Add four libpcap test files. Update Npcap SDK to 1.13. Makefile.in: Use TEST_DIST, like for tcpdump. Remove awk code from mkdep. Cirrus CI: Add the libssl-dev package in the Linux task. Cirrus CI: Add the openssl@3 brew package in the macOS task. Get "make shellcheck" to pass again. CMake: Build valgrindtest only if Autoconf would. CMake: use ${CMAKE_INSTALL_SBINDIR} rather than just sbin. CMake: use NUL: as the null device on Windows. autoconf: fix typo in test of macOS version. Makefile.in: Add two missing files in EXTRA_DIST. autotools, cmake: provide an rpath option if necessary. configure: get rid of the attempt to auto-run PKG_PROG_PKG_CONFIG. configure: use PKG_CHECK_MODULES to run pkg-config. Documentation: Add README.solaris.md. Add SCTP to pcap-filter(7). Note that = and == are the same operator in filters (issue #1044). Update INSTALL.md, README.md, and README.solaris.md. Update and clean up CONTRIBUTING.md. Trim documentation of support for now-dead UN*Xe and older versions of other UN*Xes. Move the "how to allocate a LINKTYPE_/DLT_ value" documentation to the web site. Clean up man pages. Move README.capture-module to the web site. Improve some protocol details in pcap-filter(7). Refine "relop" notes in pcap-filter(7). In pcap-filter(7) "domain" is an id. Discuss backward compatibility in pcap-filter(7). Other improvements to pcap-filter(7). Document pcap_breakloop(3PCAP) interaction with threads better. Document PCAP_ERROR_NOT_ACTIVATED for more routines. Wednesday, June 9, 2021: Summary for 1.10.1 libpcap release: Packet filtering: Fix "type XXX subtype YYY" giving a parse error Source code: Add PCAP_AVAILABLE_1_11. Building and testing: Rename struct bpf_aux_data to avoid NetBSD compile errors Squelch some compiler warnings Squelch some Bison warnings Fix cross-builds with older kernels lacking BPF_MOD and BPF_XOR Fix Bison detection for minor version 0. Fix parallel build with FreeBSD make. Get DLT_MATCHING_MAX right in gencode.c on NetBSD. Define timeradd() and timersub() if necessary. Fix Cygwin/MSYS target directories. Fix symlinking with DESTDIR. Fix generation of libpcap.pc with CMake when not building a shared library. Check for Arm64 as well as x86-64 when looking for packet.lib on Windows. Documentation: Refine Markdown in README.md. Improve the description of portrange in filters. README.linux.md isn't Markdown, rename it just README.linux. pcapng: Support reading version 1.2, which some writers produce, and which is the same as 1.0 (some new block types were added, but that's not sufficient reason to bump the minor version number, as code that understands those new block types can handle them in a 1.0 file) Linux: Drop support for text-mode USB captures, as we require a 2.6.27 or later kernel (credit to Chaoyuan Peng for noting the sscanf vulnerabilities in the text-mode code that got me to realize that we didn't need this code any more) Bluetooth: fix non-blocking mode. Don't assume that all compilers used to build for Linux support the __atomic builtins Windows: Add more information in "interface disappeared" error messages, in the hopes of trying to figure out the cause. Treat ERROR_DEVICE_REMOVED as "device was removed". Indicate in the error message which "device was removed" error occurred. Report the Windows error status if PacketSendPacket() fails. Use %lu for ULONGs in error message formats. Don't treat the inability to find airpcap.dll as an error. Ignore spurious error reports by Microsoft Surface mobile telephony modem driver rpcap: Clean up error checking and error messages for server address lookup. Tuesday, December 29, 2020 Summary for 1.10.0 libpcap release Add support for capturing on DPDK devices Label most APIs by the first release in which they're available Fix some memory leaks, including in pcap_compile() Add pcap_datalink_val_to_description_or_dlt() Handle the pcap private data in a fashion that makes fewer assumptions about memory layouts (might fix GitHub issue #940 on ARM) Fix some thread safety issues pcap_findalldevs(): don't sort interfaces by unit number Always return a list of supported time-stamp types, even if only host time stamps are supported Increase the maximum snaplen for LINKTYPE_USBPCAP/DLT_USBPCAP Report the DLT description in error messages Add pcap_init() for first-time initialization and global option setting; it's not required, but may be used Remove (unused) SITA support Capture file reading: Correctly handle pcapng captures with more than one IDB with a snspshot length greater than the supported maximum Capture file writing: Create the file in pcap_dump_open_append() if it doesn't exist Packet filtering: Fix "unknown ether proto 'aarp'" Add a new filter "ifindex" for DLT_LINUX_SLL2 files on all platforms and live Linux captures Add a hack to the optimizer to try to catch certain optimizer loops (should prevent GitHub issue #112) Show special Linux BPF offsets symbolically in bpf_image() and bpf_dump() Added support for ICMPv6 types 1-4 as tokens with names Remove undocumented and rather old "ether proto" protocols Catch invalid IPv4 addresses in filters Don't assume ARM supports unaligned accesses Security and other issues found by analysis: Fix various security issues reported by Charles Smith at Tangible Security Fix various security issues reported by Include Security Fix some issues found by cppcheck. Add some overflow checks in the optimizer rpcap: Support rpcap-over-TLS Redo protocol version negotiation to avoid problems with old servers (it still works with servers using the old negotiation, as well as servers not supporting negotiation) Error handling cleanups Add some new authentication libpcap error codes for specific errors Fix some inetd issues in rpcapd Fix rpcapd core dumps with invalid configuration file On UN*X, don't have rpcapd tell the client why authentication failed, so a brute-force attacker can't distinguish between "unknown user name" and "known user name, wrong password" Allow rpcapd to rebind more rapidly (GitHub issue #765) Documentation: Improve man pages, including adding backward compatibility notes Building and testing: Require, and assume, some level of C99 support in the C compiler Require Visual Studio 2015 or later if using Visual Studio Fix configure script issues, including with libnl on Linux Fix CMake issues Squelch complaints from Bison about "%define api.pure" being deprecated Fix compilation of pcap-tc.c Linux: Require PF_PACKET support, and kernel 2.6.27 or later Handle systems without AF_INET or AF_UNIX socket support Get rid of Wireless Extensions for turning monitor mode on Proper memory sync for PACKET_MMAP (may prevent GitHub issue #898) Drop support for libnl 1 and 2. Return error on interface going away, but not if it just went down but is still present Set socket protocol only after packet ring configured, reducing bogus packet drop reports Get ifdrop stats from sysfs. When adjusting BPF programs, do not subtract the SLL[2]_HDR_LEN if the location is negative (special metadata offset), to preserve references to metadata; see https://github.com/the-tcpdump-group/tcpdump/issues/480#issuecomment-486827278 Report a warning for unknown ARPHRD types Have pcap_breakloop() forcibly break out of a sleeping capture loop Add support for DSA data link types For raw USB bus capture, use the snapshot length to set the buffer size, and set the len field to reflect the length in the URB (GitHub issue #808) With a timeout of zero, wait indefinitely Clean up support for some non-GNU libc C libraries Add DLT_LINUX_SLL2 for cooked-mode captures Probe CONFIGURATION descriptor of connected USB devices Treat EPERM on ethtool ioctls as meaning "not supported", as permissions checks are done before checking whether the ioctl is supported at all macOS: Cope with getting EPWROFF from SIOCGIFMEDIA Treat EPERM on SIOCGIFMEDIA as meaning "not supported", as permissions checks are done before checking whether the ioctl is supported at all Treat ENXIO when reading packets as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture FreeBSD: Treat ENXIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture NetBSD: Treat ENXIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture OpenBSD: Treat EIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture DragonFly BSD: Treat ENXIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture Solaris: Treat ENXIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture AIX: Fix loading of BPF kernel extension Treat ENXIO as meaning "the interface was removed" Report "the interface disappeared", not "the interface went down", if the interface was removed during a capture Windows: Make the snapshot length work even if pcap_setfilter() isn't called Fix compilation on Cygwin/MSYS Add pcap_handle(), and deprecate pcap_fileno() Report PCAP_ERROR_NO_SUCH_DEVICE for a non-existent device Return an appropriate error message for device removed or device unusable due to a suspend/resume Report a warning for unknown NdisMedium types Have pcap_breakloop() forcibly break out of a sleeping capture loop Clean up building DLL Handle CRT mismatch for pcap_dump_fopen() Map NdisMediumWirelessWan to DLT_RAW Add AirPcap support in a module, rather than using WinPcap/Npcap's support for it Report the system error for PacketSetHwFilter() failures Add support for getting and setting packet time stamp types with Npcap Have pcap_init() allow selecting whether the API should use local code page strings or UTF-8 strings (including error messages) Haiku: Add capture support Sunday, July 22, 2018 Summary for 1.9.1 libpcap release Mention pcap_get_required_select_timeout() in the main pcap man page Fix pcap-usb-linux.c build on systems with musl Fix assorted man page and other documentation issues Plug assorted memory leaks Documentation changes to use https: Changes to how time stamp calculations are done Lots of tweaks to make newer compilers happier and warning-free and to fix instances of C undefined behavior Warn if AC_PROG_CC_C99 can't enable C99 support Rename pcap_set_protocol() to pcap_set_protocol_linux(). Align pcap_t private data on an 8-byte boundary. Fix various error messages Use 64-bit clean API in dag_findalldevs() Fix cleaning up after some errors Work around some ethtool ioctl bugs in newer Linux kernels (GitHub issue #689) Add backwards compatibility sections to some man pages (GitHub issue #745) Fix autotool configuration on AIX and macOS Don't export bpf_filter_with_aux_data() or struct bpf_aux_data; they're internal-only and subject to change Fix pcapng block size checking On macOS, don't build rpcapd or test programs any fatter than they need to be Fix reading of capture statistics for Linux USB Fix packet size values for Linux USB packets (GitHub issue #808) Check only VID in VLAN test in filters (GitHub issue #461) Fix pcap_list_datalinks on 802.11 devices on macOS Fix overflows with very large snapshot length in pcap file Improve parsing of rpcapd configuration file (GitHub issue #767) Handle systems without strlcpy() or strlcat() better Fix crashes and other errors with invalid filter expressions Fix use of uninitialized file descriptor in remote capture Fix some CMake issues Fix some divide-by-zero issues with the filter compiler Work around a GNU libc bug in pcap_nametonetaddr() Add support for DLT_LINUX_SLL2 Fix handling of the packet-count argument for Myricom SNF devices Fix --disable-rdma in configure script (GitHub issue #782) Fix compilation of TurboCap support (GitHub issue #764) Constify first argument to pcap_findalldevs_ex() Fix a number of issues when running rpcapd as an inetd-style daemon Fix CMake issues with D-Bus libraries In rpcapd, clean up termination of a capture session Redo remote capture protocol negotiation In rpcapd, report the same error for "invalid user name" and "invalid password", to make brute-forcing harder For remote captures, add an error code for "the server requires TLS" Fix pcap_dump_fopen() on Windows to avoid clashes between {Win,N}Pcap and application C runtimes Fix exporting of functions from Windows DLLs (GitHub issue #810) Fix building as part of Npcap Allow rpcapd to rebind more rapidly Fix building shared libpcap library on midipix (midipix.org) Fix hack to detect UTF-16LE adapter names on Windows not to go past the end of the string Fix handling of "wireless WAN" (mobile phone network modems) on Windows with WinPcap/Npcap (GitHub issue #824) Have pcap_dump_open_append() create the dump file if it doesn't exists (GitHub issue #247) Fix the maxmum snapshot length for DLT_USBPCAP Use -fPIC when building for 64-bit SPARC on Linux (GitHub issue #837) Fix CMake 64-bit library installation directory on some Linux distributions Boost the TPACKET_V3 timeout to the maximum if a timeout of 0 was specified Five CVE-2019-15161, CVE-2019-15162, CVE-2019-15163, CVE-2019-15164, CVE-2019-15165 PCAPNG reader applies some sanity checks before doing malloc(). Sunday, June 24, 2018, by mcr@sandelman.ca Summary for 1.9.0 libpcap release Added testing system to libpcap, independent of tcpdump Changes to how pcap_t is activated Adding support for Large stream buffers on Endace DAG cards Changes to BSD 3-clause license to 2-clause license Additions to TCP header parsing, per RFC3168 Add CMake build process (extensive number of changes) Assign a value for OpenBSD DLT_OPENFLOW. Support setting non-blocking mode before activating. Extensive build support for Windows VS2010 and MINGW (many many changes, over many months) Added RPCAPD support when --enable-remote (default no) Add the rpcap daemon source and build instructions. Put back the greasy "save the capture filter string so we can tweak it" hack, that keeps libpcap from capturing rpcap traffic. Fixes for captures on MacOS, utun0 fixes so that non-AF_INET addresses, are not ==AF_INET6 addresses. Add a linktype for IBM SDLC frames containing SNA PDUs. pcap_compile() in 1.8.0 and later is newly thread-safe. bound snaplen for linux tpacket_v2 to ~64k Make VLAN filter handle both metadata and inline tags D-Bus captures can now be up to 128MB in size Added LORATAP DLT value Added DLT_VSOCK for https://qemu-project.org/Features/VirtioVsock probe_devices() fixes not to overrun buffer for name of device Add linux-specific pcap_set_protocol_linux() to allow specifying a specific capture protocol. RDMA sniffing support for pcap Add Nordic Semiconductor Bluetooth LE sniffer link-layer header type. fixes for reading /etc/ethers Make it possible to build on Windows without packet.dll. Add tests for large file support on UN*X. Solaris fixes to work with 2.8.6 configuration test now looks for header files, not capture devices present Fix to work with Berkeley YACC. fixes for DragonBSD compilation of pcap-netmap.c Clean up the ether_hostton() stuff. Add an option to disable Linux memory-mapped capture support. Add DAG API support checks. Add Septel, Myricom SNF, and Riverbed TurboCap checks. Add checks for Linux USB, Linux Bluetooth, D-Bus, and RDMA sniffing support. Add a check for hardware time stamping on Linux. Don't bother supporting pre-2005 Visual Studio. Increased minimum autoconf version requirement to 2.64 Add DLT value 273 for XRA-31 sniffer Clean up handing of signal interrupts in pcap_read_nocb_remote(). Use the XPG 4.2 versions of the networking APIs in Solaris. Fix, and better explain, the "IPv6 means IPv6, not IPv4" option setting. Explicitly warn that negative packet buffer timeouts should not be used. rpcapd: Add support inetd-likes, including xinetd.conf, and systemd units Rename DLT_IEEE802_15_4 to DLT_IEEE802_15_4_WITHFCS. Add DISPLAYPORT AUX link type Remove the sunos4 kernel modules and all references to them. Add more interface flags to pcap_findalldevs(). Summary for 1.9.0 libpcap release (to 2017-01-25 by guy@alum.mit.edu) Man page improvements Fix Linux cooked mode userspace filtering (GitHub pull request #429) Fix compilation if IPv6 support not enabled Fix some Linux memory-mapped capture buffer size issues Don't fail if kernel filter can't be set on Linux (GitHub issue #549) Improve sorting of interfaces for pcap_findalldevs() Don't list Linux usbmon devices if usbmon module isn't loaded Report PCAP_ERROR_PERM_DENIED if no permission to open Linux usbmon devices Fix DLT_ type for Solaris IPNET devices Always return an error message for errors finding DAG or Myricom devices If possible, don't require that a device be openable when enumerating them for pcap_findalldevs() Don't put incompletely-initialized addresses in the address list for When finding Myricom devices, update description for regular interfaces that are Myricom devices and handle SNF_FLAGS=0x2(port aggregation enabled) Fix compilation error in DAG support Fix issues with CMake configuration Add support for stream buffers larger than 2GB on newer DAG cards Remove support for building against DAG versions without STREAMS support (before dag-3.0.0 2007) Tuesday, Oct. 25, 2016 mcr@sandelman.ca Summary for 1.8.1 libpcap release Add a target in Makefile.in for Exuberant Ctags use: 'extags'. Rename configure.in to configure.ac: autoconf 2.59 Clean up the name-to-DLT mapping table. Add some newer DLT_ values: IPMI_HPM_2,ZWAVE_R1_R2,ZWAVE_R3,WATTSTOPPER_DLM,ISO_14443,RDS Clarify what the return values are for both success and failure. Many changes to build on windows Check for the "break the loop" condition in the inner loop for TPACKET_V3. Fix handling of packet count in the TPACKET_V3 inner loop: GitHub issue #493. Filter out duplicate looped back CAN frames. Fix the handling of loopback filters for IPv6 packets. Add a link-layer header type for RDS (IEC 62106) groups. Use different intermediate folders for x86 and x64 builds on Windows. On Linux, handle all CAN captures with pcap-linux.c, in cooked mode. Removes the need for the "host-endian" link-layer header type. Compile with '-Wused-but-marked-unused' in devel mode if supported Have separate DLTs for big-endian and host-endian SocketCAN headers. Reflect version.h being renamed to pcap_version.h. Require that version.h be generated: all build procedures we support generate version.h (autoconf, CMake, MSVC)! Properly check for sock_recv() errors. Re-impose some of Winsock's limitations on sock_recv(). Replace sprintf() with pcap_snprintf(). Fix signature of pcap_stats_ex_remote(). Initial cmake support for remote packet capture. Have rpcap_remoteact_getsock() return a SOCKET and supply an "is active" flag. Clean up {DAG, Septel, Myricom SNF}-only builds. Do UTF-16-to-ASCII conversion into the right place. pcap_create_interface() needs the interface name on Linux. Clean up hardware time stamp support: the "any" device does not support any time stamp types. Add support for capturing on FreeBSD usbusN interfaces. Add a LINKTYPE/DLT_ value for FreeBSD USB. Go back to using PCAP_API on Windows. CMake support Add TurboCap support from WinPcap. Recognize 802.1ad nested VLAN tag in vlan filter. Thursday Sep. 3, 2015 guy@alum.mit.edu Summary for 1.7.5 libpcap release Man page cleanups. Add some allocation failure checks. Fix a number of Linux/ucLinux configure/build issues. Fix some memory leaks. Recognize 802.1ad nested VLAN tag in vlan filter. Fix building Bluetooth Linux Monitor support with BlueZ 5.1+ Saturday Jun. 27, 2015 mcr@sandelman.ca Summary for 1.7.4 libpcap release Include fix for GitHub issue #424 -- out of tree builds. Friday Apr. 10, 2015 guy@alum.mit.edu Summary for 1.7.3 libpcap release Work around a Linux bonding driver bug. Thursday Feb. 12, 2015 guy@alum.mit.edu/mcr@sandelman.ca Summary for 1.7.2 libpcap release Support for filtering Geneve encapsulated packets. Generalize encapsulation handling, fixing some bugs. Don't add null addresses to address lists. Add pcap_dump_open_append() to open for appending. Fix the swapping of isochronous descriptors in Linux USB. Attempt to handle TPACKET_V1 with 32-bit userland and 64-bit kernel. Wednesday Nov. 12, 2014 guy@alum.mit.edu/mcr@sandelman.ca Summary for 1.7.0 libpcap release Fix handling of zones for BPF on Solaris new DLT for ZWAVE clarifications for read timeouts. Use BPF extensions in compiled filters, fixing VLAN filters some fixes to compilation without stdint.h EBUSY can now be returned by SNFv3 code. Fix the range checks in BPF loads Various DAG fixes. Various Linux fixes. Monday Aug. 12, 2014 guy@alum.mit.edu Summary for 1.6.2 libpcap release Don't crash on filters testing a non-existent link-layer type field. Fix sending in non-blocking mode on Linux with memory-mapped capture. Fix timestamps when reading pcap-ng files on big-endian machines. Saturday Jul. 19, 2014 mcr@sandelman.ca Summary for 1.6.1 libpcap release some fixes for the any device changes for how --enable-XXX (--enable-sniffing, --enable-can) works Wednesday Jul. 2, 2014 mcr@sandelman.ca Summary for 1.6.0 libpcap release Don't support D-Bus sniffing on OS X fixes for byte order issues with NFLOG captures Handle using cooked mode for DLT_NETLINK in activate_new(). on platforms where you can not capture on down interfaces, do not list them but: do list interfaces which are down, if you can capture on them! Wednesday December 18, 2013 guy@alum.mit.edu Summary for 1.5.3 libpcap release Don't let packets that don't match the current filter get to the application when TPACKET_V3 is used. (GitHub issue #331) Fix handling of pcap_loop()/pcap_dispatch() with a packet count of 0 on some platforms (including Linux with TPACKET_V3). (GitHub issue #333) Work around TPACKET_V3 deficiency that causes packets to be lost when a timeout of 0 is specified. (GitHub issue #335) Man page formatting fixes. Wednesday December 4, 2013 guy@alum.mit.edu Summary for 1.5.2 libpcap release Fix libpcap to work when compiled with TPACKET_V3 support and running on a kernel without TPACKET_V3 support. (GitHub issue #329) Wednesday November 20, 2013 guy@alum.mit.edu Summary for 1.5.1 libpcap release Report an error, rather than crashing, if an IPv6 address is used for link-layer filtering. (Wireshark bug 9376) Wednesday October 30, 2013 guy@alum.mit.edu Summary for 1.5.0 libpcap release TPACKET_V3 support added for Linux Point users to the the-tcpdump-group repository on GitHub rather than the mcr repository Checks added for malloc()/realloc()/etc. failures Fixed build on Solaris 11 Support filtering E1 SS7 traffic on MTP2 layer Annex A Use "ln -s" to link man pages by default Add support for getting nanosecond-resolution time stamps when capturing and reading capture files Many changes to autoconf to deal better with non-GCC compilers added many new DLT types Saturday April 6, 2013 guy@alum.mit.edu Summary for 1.4.0 libpcap release Add netfilter/nfqueue interface. If we don't have support for IPv6 address resolution, support, in filter expressions, what IPv6 stuff we can. Fix pcap-config to include -lpthread if canusb support is present Try to fix "pcap_parse not defined" problems when --without-flex and --without-bison are used when you have Flex and Bison Fix some issues with the pcap_loop man page. Fix pcap_getnonblock() and pcap_setnonblock() to fill in the supplied error message buffer Fix typo that, it appeared, would cause pcap-libdlpi.c not to compile (perhaps systems with libdlpi also have BPF and use that instead) Catch attempts to call pcap_compile() on a non-activated pcap_t Fix crash on Linux with CAN-USB support without usbfs Fix addition of VLAN tags for Linux cooked captures Check for both EOPNOTSUPP and EINVAL after SIOCETHTOOL ioctl, so that the driver can report either one if it doesn't support SIOCETHTOOL Add DLT_INFINIBAND and DLT_SCTP Describe "proto XXX" and "protochain XXX" in the pcap-filter man page Handle either directories, or symlinks to directories, that correspond to interfaces in /sys/class/net Fix handling of VLAN tag insertion to check, on Linux 3.x kernels, for VLAN tag valid flag Clean up some man pages Support libnl3 as well as libnl1 and libnl2 on Linux Fix handling of Bluetooth devices on 3.x Linux kernels Friday March 30, 2012. mcr@sandelman.ca Summary for 1.3.0 libpcap release Handle DLT_PFSYNC in {FreeBSD, other *BSD+Mac OS X, other}. Linux: Don't fail if netfilter isn't enabled in the kernel. Add new link-layer type for NFC Forum LLCP. Put the CANUSB stuff into EXTRA_DIST, so it shows up in the release tarball. Add LINKTYPE_NG40/DLT_NG40. Add DLT_MPEG_2_TS/LINKTYPE_MPEG_2_TS for MPEG-2 transport streams. [PATCH] Fix AIX-3.5 crash with read failure during stress AIX fixes. Introduce --disable-shared configure option. Added initial support for canusb devices. Include the pcap(3PCAP) additions as 1.2.1 changes. many updates to documentation: pcap.3pcap.in Improve 'inbound'/'outbound' capture filters under Linux. Note the cleanup of handling of new DLT_/LINKTYPE_ values. On Lion, don't build for PPC. For mac80211 devices we need to clean up monitor mode on exit. Friday December 9, 2011. guy@alum.mit.edu. Summary for 1.2.1 libpcap release Update README file. Fix typos in README.linux file. Clean up some compiler warnings. Fix Linux compile problems and tests for ethtool.h. Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU toolchains. Support 802.1 QinQ as a form of VLAN in filters. Treat "carp" as equivalent to "vrrp" in filters. Fix code generated for "ip6 protochain". Add some new link-layer header types. Support capturing NetFilter log messages on Linux. Clean up some error messages. Turn off monitor mode on exit for mac80211 interfaces on Linux. Fix problems turning monitor mode on for non-mac80211 interfaces on Linux. Properly fail if /sys/class/net or /proc/net/dev exist but can't be opened. Fail if pcap_activate() is called on an already-activated pcap_t, and add a test program for that. Fix filtering in pcap-ng files. Don't build for PowerPC on Mac OS X Lion. Simplify handling of new DLT_/LINKTYPE_ values. Expand pcap(3PCAP) man page. Sunday July 24, 2011. mcr@sandelman.ca. Summary for 1.2 libpcap release All of the changes listed below for 1.1.1 and 1.1.2. Changes to error handling for pcap_findalldevs(). Fix the calculation of the frame size in memory-mapped captures. Add a link-layer header type for STANAG 5066 D_PDUs. Add a link-layer type for a variant of 3GPP TS 27.010. Noted real nature of LINKTYPE_ARCNET. Add a link-layer type for DVB-CI. Fix configure-script discovery of VLAN acceleration support. see https://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes. Protect against including AIX 5.x's having been included. Add DLT_DBUS, for raw D-Bus messages. Treat either EPERM or EACCES as "no soup for you". Changes to permissions on DLPI systems. Add DLT_IEEE802_15_4_NOFCS for 802.15.4 interfaces. Fri. August 6, 2010. guy@alum.mit.edu. Summary for 1.1.2 libpcap release Return DLT_ values, not raw LINKTYPE_ values from pcap_datalink() when reading pcap-ng files Add support for "wlan ra" and "wlan ta", to check the RA and TA of WLAN frames that have them Don't crash if "wlan addr{1,2,3,4}" are used without 802.11 headers Do filtering on USB and Bluetooth capturing On FreeBSD/SPARC64, use -fPIC - it's apparently necessary Check for valid port numbers (fit in a 16-bit unsigned field) in "port" filters Reject attempts to put savefiles into non-blocking mode Check for "no such device" for the "get the media types" ioctl in *BSD Improve error messages from bpf_open(), and let it do the error handling Return more specific errors from pcap_can_set_rfmon(); fix documentation Update description fetching code for FreeBSD, fix code for OpenBSD Ignore /sys/net/dev files if we get ENODEV for them, not just ENXIO; fixes handling of bonding devices on Linux Fix check for a constant 0 argument to BPF_DIV Use the right version of ar when cross-building Free any filter set on a savefile when the savefile is closed Include the CFLAGS setting when configure was run in the compiler flags Add support for 802.15.4 interfaces on Linux Thu. April 1, 2010. guy@alum.mit.edu. Summary for 1.1.1 libpcap release Update CHANGES to reflect more of the changes in 1.1.0. Fix build on RHEL5. Fix shared library build on AIX. Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. Summary for 1.1.0 libpcap release Add SocketCAN capture support Add Myricom SNF API support Update Endace DAG and ERF support Add support for shared libraries on Solaris, HP-UX, and AIX Build, install, and un-install shared libraries by default; don't build/install shared libraries on platforms we don't support Fix building from a directory other than the source directory Fix compiler warnings and builds on some platforms Update config.guess and config.sub Support monitor mode on mac80211 devices on Linux Fix USB memory-mapped capturing on Linux; it requires a new DLT_ value On Linux, scan /sys/class/net for devices if we have it; scan it, or /proc/net/dev if we don't have /sys/class/net, even if we have getifaddrs(), as it'll find interfaces with no addresses Add limited support for reading pcap-ng files Fix BPF driver-loading error handling on AIX Support getting the full-length interface description on FreeBSD In the lexical analyzer, free up any addrinfo structure we got back from getaddrinfo(). Add support for BPF and libdlpi in OpenSolaris (and SXCE) Hyphenate "link-layer" everywhere Add /sys/kernel/debug/usb/usbmon to the list of usbmon locations In pcap_read_linux_mmap(), if there are no frames available, call poll() even if we're in non-blocking mode, so we pick up errors, and check for the errors in question. Note that poll() works on BPF devices is Snow Leopard If an ENXIO or ENETDOWN is received, it may mean the device has gone away. Deal with it. For BPF, raise the default capture buffer size to from 32k to 512k Support ps_ifdrop on Linux Added a bunch of #ifdef directives to make wpcap.dll (WinPcap) compile under cygwin. Changes to Linux mmapped captures. Fix bug where create_ring would fail for particular snaplen and buffer size combinations Update pcap-config so that it handles libpcap requiring additional libraries Add workaround for threadsafeness on Windows Add missing mapping for DLT_ENC <-> LINKTYPE_ENC DLT: Add DLT_CAN_SOCKETCAN DLT: Add Solaris ipnet Don't check for DLT_IPNET if it's not defined Add link-layer types for Fibre Channel FC-2 Add link-layer types for Wireless HART Add link-layer types for AOS Add link-layer types for DECT Autoconf fixes (AIX, HP-UX, OSF/1, Tru64 cleanups) Install headers unconditionally, and include vlan.h/bluetooth.h if enabled Autoconf fixes+cleanup Support enabling/disabling bluetooth (--{en,dis}able-bluetooth) Support disabling SITA support (--without-sita) Return -1 on failure to create packet ring (if supported but creation failed) Fix handling of 'any' device, so that it can be opened, and no longer attempt to open it in Monitor mode Add support for snapshot length for USB Memory-Mapped Interface Fix configure and build on recent Linux kernels Fix memory-mapped Linux capture to support pcap_next() and pcap_next_ex() Fixes for Linux USB capture DLT: Add DLT_LINUX_EVDEV DLT: Add DLT_GSMTAP_UM DLT: Add DLT_GSMTAP_ABIS Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap release Compile with IPv6 support by default Compile with large file support on by default Add pcap-config script, which deals with -I/-L flags for compiling DLT: Add IPMB DLT: Add LAPD DLT: Add AX25 (AX.25 w/KISS header) DLT: Add JUNIPER_ST 802.15.4 support Variable length 802.11 header support X2E data type support SITA ACN Interface support - see README.sita Support for memory-mapped capture on Linux Support for zerocopy BPF on platforms that support it Support for setting buffer size when opening devices Support for setting monitor mode when opening 802.11 devices Better support for dealing with VLAN tagging/stripping on Linux Fix dynamic library support on OSX Return PCAP_ERROR_IFACE_NOT_UP if the interface isn't 'UP', so applications can print better diagnostic information Return PCAP_ERROR_PERM_DENIED if we don't have permission to open a device, so applications can tell the user they need to go play with permissions On Linux, ignore ENETDOWN so we can continue to capture packets if the interface goes down and comes back up again. On Linux, support new tpacket frame headers (2.6.27+) On Mac OS X, add scripts for changing permissions on /dev/bpf* and launchd plist On Solaris, support 'passive mode' on systems that support it Fixes to autoconf and general build environment Man page reorganization + cleanup Autogenerate VERSION numbers better Mon. September 10, 2007. ken@xelerance.com. Summary for 0.9.8 libpcap release Change build process to put public libpcap headers into pcap subir DLT: Add value for IPMI IPMB packets DLT: Add value for u10 Networks boards Require for pf definitions - allows reading of pflog formatted libpcap files on an OS other than where the file was generated Wed. April 25, 2007. ken@xelerance.com. Summary for 0.9.6 libpcap release Put the public libpcap headers into a pcap subdirectory in both the source directory and the target include directory, and have include files at the top-level directory to include those headers, for backwards compatibility. Add Bluetooth support Add USB capturing support on Linux Add support for the binary USB sniffing interface in Linux Add support for new FreeBSD BIOCSDIRECTION ioctl Add additional filter operations for 802.11 frame types Add support for filtering on MTP2 frame types Propagate some changes from the main branch, so the x.9 branch has all the DLT_ and LINKTYPE_ values that the main branch does Reserved a DLT_ and SAVEFILE_ value for PPI (Per Packet Info) encapsulated packets Add LINKTYPE_ for IEEE 802.15.4, with address fields padded as done by Linux drivers Add LINKTYPE_ value corresponding to DLT_IEEE802_16_MAC_CPS. Add DLT for IEEE 802.16 (WiMAX) MAC Common Part Sublayer Add DLT for Bluetooth HCI UART transport layer When building a shared library, build with "-fPIC" on Linux to support x86_64 Link with "$(CC) -shared" rather than "ld -shared" when building a ".so" shared library Add support for autoconf 2.60 Fixes to discard unread packets when changing filters Changes to handle name changes in the DAG library resulting from switching to libtool. Add support for new DAG ERF types. Add an explicit "-ldag" when building the shared library, so the DAG library dependency is explicit. Mac OSX fixes for dealing with "wlt" devices Fixes in add_or_find_if() & pcap_findalldevs() to optimize generating device lists Fixed a bug in pcap_open_live(). The return value of PacketSetHwFilter was not checked. Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release Support for LAPD frames with vISDN Support for ERF on channelized T1/E1 cards via DAG API Fix capitalization that caused issues crossc compiling on Linux Better failure detection on PacketGetAdapterNames() Fixes for MPLS packet generation (link layer) OP_PACKET now matches the beginning of the packet, instead of beginning+link-layer Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay Fix allocation of buffer for list of link-layer types Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communication Messages Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_ Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN). Added definition for DLT_A429 and LINKTYPE_A429 as #184. Added a new DLT and LINKTYPE value for CAN v2.0B frames. Add support for DLT_JUNIPER_VP. Don't double-count received packets on Linux systems that support the PACKET_STATISTICS getsockopt() argument on PF_PACKET sockets. Add support for DLT_IEEE802_11 and DLT_IEEE802_11_RADIO link layers in Windows Add support to build libpcap.lib and wpcap.dll under Cygnus and MingW32. -Mon. September 5, 2005. ken@xelerance.com. Summary for 0.9.4 libpcap release +Mon. September 5, 2005. ken@xelerance.com. Summary for 0.9.4 libpcap release Support for radiotap on Linux (Mike Kershaw) Fixes for HP-UX Support for additional Juniper link-layer types Fixes for filters on MPLS-encapsulated packets "vlan" filter fixed "pppoed" and "pppoes" filters added; the latter modifies later parts of the filter expression to look at the PPP headers and headers in the PPP payload -Tue. July 5, 2005. ken@xelerance.com. Summary for 0.9.3 libpcap release +Tue. July 5, 2005. ken@xelerance.com. Summary for 0.9.3 libpcap release Fixes for compiling on nearly every platform, including improved 64bit support MSDOS Support Add support for sending packets OpenBSD pf format support IrDA capture (Linux only) Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release Fixed minor problem in gencode.c that would appear on 64-bit platforms. Version number is now sane. Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release updates for autoconf 2.5 fixes for ppp interfaces for freebsd 4.1 pcap gencode can generate code for 802.11, IEEE1394, and pflog. Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 0.8 release added pcap_findalldevs() Win32 patches from NetGroup, Politecnico di Torino (Italy) OpenBSD pf, DLT_PFLOG added Many changes to ATM support. lookup pcap_lookupnet() Added DLT_ARCNET_LINUX, DLT_ENC, DLT_IEEE802_11_RADIO, DLT_SUNATM, DLT_IP_OVER_FC, DLT_FRELAY, others. Sigh. More AIX wonderfulness. Document updates. Changes to API: pcap_next_ex(), pcap_breakloop(), pcap_dump_flush(), pcap_list_datalinks(), pcap_set_datalink(), pcap_lib_version(), pcap_datalink_val_to_name(), pcap_datalink_name_to_val(), new error returns. Tuesday, February 25, 2003. fenner@research.att.com. 0.7.2 release - Support link types that use 802.2 always, never, and sometimes. - Don't decrease the size of the BPF buffer from the default. - Support frame relay. - Handle 32-bit timestamps in DLPI, and pass the right buffer size. - Handle Linux systems with modern kernel but without - SOL_PACKET in the userland headers. - Linux support for ARPHRD_RAWHDLC. - Handle 32-bit timestamps in snoop. - Support eg (Octane/O2xxx/O3xxx Gigabit) devices. - Add new reserved DLT types. + Support link types that use 802.2 always, never, and sometimes. + Don't decrease the size of the BPF buffer from the default. + Support frame relay. + Handle 32-bit timestamps in DLPI, and pass the right buffer size. + Handle Linux systems with modern kernel but without + SOL_PACKET in the userland headers. + Linux support for ARPHRD_RAWHDLC. + Handle 32-bit timestamps in snoop. + Support eg (Octane/O2xxx/O3xxx Gigabit) devices. + Add new reserved DLT types. Monday October 23, 2001. mcr@sandelman.ottawa.on.ca. Summary for 0.7 release Added pcap_findalldevs() call to get list of interfaces in a MI way. pcap_stats() has been documented as to what its counters mean on each platform. Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release New Linux libpcap implementation, which, in 2.2 and later kernels, uses PF_PACKET sockets and supports kernel packet filtering (if compiled into the kernel), and supports the "any" device for capturing on all interfaces. Cleans up promiscuous mode better on pre-2.2 kernels, and has various other fixes (handles 2.4 ARPHRD_IEEE802_TR, handles ISDN devices better, doesn't show duplicate packets on loopback interface, etc.). Fixed HP-UX libpcap implementation to correctly get the PPA for an interface, to allow interfaces to be opened by interface name. libpcap savefiles have system-independent link-layer type values in the header, rather than sometimes platform-dependent DLT_ values, to make it easier to exchange capture files between different OSes. Non-standard capture files produced by some Linux tcpdumps, e.g. the one from Red Hat Linux 6.2 and later, can now be read. Updated autoconf stock files. Filter expressions can filter on VLAN IDs and various OSI protocols, and work on Token Ring (with non-source-routed packets). "pcap_open_dead()" added to allow compiling filter expressions to pcap code without opening a capture device or capture file. Header files fixed to allow use in C++ programs. Removed dependency on native headers for packet layout. Removed Linux specific headers that were shipped. Security fixes: Strcpy replaced with strlcpy, sprintf replaced with snprintf. Fixed bug that could cause subsequent "pcap_compile()"s to fail erroneously after one compile failed. Assorted other bug fixes. README.aix and README.linux files added to describe platform-specific issues. "getifaddrs()" rather than SIOCGIFCONF used, if available. v0.5 Sat Jun 10 11:09:15 PDT 2000 itojun@iijlab.net - Brought in KAME IPv6/IPsec bpf compiler. - Fixes for NetBSD. - Support added for OpenBSD DLT_LOOP and BSD/OS DLT_C_HDLC (Cisco HDLC), and changes to work around different BSDs having different DLT_ types with the same numeric value. Assar Westerlund - Building outside the source code tree fixed. - Changed to write out time stamps with 32-bit seconds and microseconds fields, regardless of whether those fields are 32 bits or 64 bits in the OS's native "struct timeval". - Changed "pcap_lookupdev()" to dynamically grow the buffer into which the list of interfaces is read as necessary in order to hold the entire list. Greg Troxel - Added a new "pcap_compile_nopcap()", which lets you compile a filter expression into a BPF program without having an open live capture or capture file. v0.4 Sat Jul 25 12:40:09 PDT 1998 - Fix endian problem with DLT_NULL devices. From FreeBSD via Bill Fenner (fenner@parc.xerox.com) - Fix alignment problem with FDDI under DLPI. This was causing core dumps under Solaris. - Added configure options to disable flex and bison. Resulted from a bug report by barnett@grymoire.crd.ge.com (Bruce Barnett). Also added options to disable gcc and to force a particular packet capture type. - Added support for Fore ATM interfaces (qaa and fa) under IRIX. Thanks to John Hawkinson (jhawk@mit.edu) - Change Linux PPP and SLIP to use DLT_RAW since the kernel does not supply any "link layer" data. - Change Linux to use SIOCGIFHWADDR ioctl to determine link layer type. Thanks to Thomas Sailer (sailer@ife.ee.ethz.ch) - Change IRIX PPP to use DLT_RAW since the kernel does not supply any "link layer" data. - Modified to support the new BSD/OS 2.1 PPP and SLIP link layer header formats. - Added some new SGI snoop interface types. Thanks to Steve Alexander (sca@refugee.engr.sgi.com) - Fixes for HP-UX 10.20 (which is similar to HP-UX 9). Thanks to Richard Allen (ra@hp.is) and Steinar Haug (sthaug@nethelp.no) - Fddi supports broadcast as reported by Jeff Macdonald (jeff@iacnet.com). Also correct ieee802 and arcnet. - Determine Linux pcap buffer size at run time or else it might not be big enough for some interface types (e.g. FDDI). Thanks to Jes Sorensen (Jes.Sorensen@cern.ch) - Fix some linux alignment problems. - Document promisc argument to pcap_open_live(). Reported by Ian Marsh (ianm@sics.se) - Support Metricom radio packets under Linux. Thanks to Kevin Lai (laik@gunpowder.stanford.edu) - Bind to interface name under Linux to avoid packets from multiple interfaces on multi-homed hosts. Thanks to Kevin Lai (laik@gunpowder.stanford.edu) - Change L_SET to SEEK_SET for HP-UX. Thanks to Roland Roberts (rroberts@muller.com) - Fixed an uninitialized memory reference found by Kent Vander Velden (graphix@iastate.edu) - Fixed lex pattern for IDs to allow leading digits. As reported by Theo de Raadt (deraadt@cvs.openbsd.org) - Fixed Linux include file problems when using GNU libc. - Ifdef ARPHRD_FDDI since not all versions of the Linux kernel have it. Reported reported by Eric Jacksch (jacksch@tenebris.ca) - Fixed bug in pcap_dispatch() that kept it from returning on packet timeouts. - Changed ISLOOPBACK() macro when IFF_LOOPBACK isn't available to check for "lo" followed by an eos or digit (newer versions of Linux apparently call the loopback "lo" instead of "lo0"). - Fixed Linux networking include files to use ints instead of longs to avoid problems with 64 bit longs on the alpha. Thanks to Cristian Gafton (gafton@redhat.com) v0.3 Sat Nov 30 20:56:27 PST 1996 - Added Linux support. - Fixed savefile bugs. - Solaris x86 fix from Tim Rylance (t.rylance@elsevier.nl) - Add support for bpf kernel port filters. - Remove duplicate atalk protocol table entry. Thanks to Christian Hopps (chopps@water.emich.edu) - Fixed pcap_lookupdev() to ignore nonexistent devices. This was reported to happen under BSD/OS by David Vincenzetti (vince@cryptonet.it) - Avoid solaris compiler warnings. Thanks to Bruce Barnett (barnett@grymoire.crd.ge.com) v0.2.1 Sun Jul 14 03:02:26 PDT 1996 - Fixes for HP-UX 10. Thanks in part to Thomas Wolfram (wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com) - Added support for SINIX. Thanks to Andrej Borsenkow (borsenkow.msk@sni.de) - Fixes for AIX (although this system is not yet supported). Thanks to John Hawkinson (jhawk@mit.edu) - Use autoconf's idea of the top level directory in install targets. Thanks to John Hawkinson. - Add missing autoconf packet capture result message. Thanks to Bill Fenner (fenner@parc.xerox.com) - Fixed padding problems in the pf module. - Fixed some more alignment problems on the alpha. - Added explicit netmask support. Thanks to Steve Nuchia (steve@research.oknet.com) - Fixed to handle raw ip addresses such as 0.0.0.1 without "left justifing" - Add "sca" keyword (for DEC cluster services) as suggested by Terry Kennedy (terry@spcvxa.spc.edu) - Add "atalk" keyword as suggested by John Hawkinson. - Add "igrp" keyword. - Fixed HID definition in grammar.y to be a string, not a value. - Use $CC when checking gcc version. Thanks to Carl Lindberg (carl_lindberg@blacksmith.com) - Removed obsolete reference to pcap_immediate() from the man page. Michael Stolarchuk (mts@terminator.rs.itd.umich.edu) - DLT_NULL has a 4 byte family header. Thanks to Jeffrey Honig (jch@bsdi.com) v0.2 Sun Jun 23 02:28:42 PDT 1996 - Add support for HP-UX. Resulted from code contributed by Tom Murray (tmurray@hpindck.cup.hp.com) and Philippe-Andri Prindeville (philipp@res.enst.fr) - Update INSTALL with a reminder to install include files. Thanks to Mark Andrews (mandrews@aw.sgi.com) - Fix bpf compiler alignment bug on the alpha. - Use autoconf to detect architectures that can't handle misaligned accesses. - Added loopback support for snoop. Resulted from report Steve Alexander (sca@engr.sgi.com) v0.1 Fri Apr 28 18:11:03 PDT 1995 - Fixed compiler and optimizer bugs. The BPF filter engine uses unsigned comparison operators, while the code generator and optimizer assumed signed semantics in several places. Thanks to Charlie Slater (cslater@imatek.com) for pointing this out. - Removed FDDI ifdef's, they aren't really needed. Resulted from report by Gary Veum (veum@boa.gsfc.nasa.gov). - Add pcap-null.c which allows offline use of libpcap on systems that don't support live package capture. This feature resulting from a request from Jan van Oorschot (j.p.m.voorschot@et.tudelft.nl). - Make bpf_compile() reentrant. Fix thanks to Pascal Hennequin (Pascal.Hennequin@hugo.int-evry.fr). - Port to GNU autoconf. - Fix pcap-dlpi.c to work with isdn. Resulted from report by Flemming Johansen (fsj@csd.cri.dk). - Handle multi-digit interface unit numbers (aka ppa's) under dlpi. Resulted from report by Daniel Ehrlich (ehrlich@cse.psu.edu). - Fix pcap-dlpi.c to work in non-promiscuous mode. Resulted from report by Jeff Murphy (jcmurphy@acsu.buffalo.edu). - Add support for "long jumps". Thanks to Jeffrey Mogul (mogul@pa.dec.com). - Fix minor problems when compiling with BDEBUG as noticed by Scott Bertilson (scott@unet.umn.edu). - Declare sys_errlist "const char *const" to avoid problems under FreeBSD. Resulted from report by jher@eden.com. v0.0.6 Fri Apr 28 04:07:13 PDT 1995 - Add missing variable declaration missing from 0.0.6 v0.0.5 Fri Apr 28 00:22:21 PDT 1995 - Workaround for problems when pcap_read() returns 0 due to the timeout expiring. v0.0.4 Thu Apr 20 20:41:48 PDT 1995 - Change configuration to not use gcc v2 flags with gcc v1. - Fixed a bug in pcap_next(); if pcap_dispatch() returns 0, pcap_next() should also return 0. Thanks to Richard Stevens (rstevens@noao.edu). - Fixed configure to test for snoop before dlpi to avoid problems under IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). - Hack around deficiency in Ultrix's make. - Fix two bugs related to the Solaris pre-5.3.2 bufmod bug; handle savefiles that have more than snapshot bytes of data in them (so we can read old savefiles) and avoid writing such files. - Added checkioctl which is used with gcc to check that the "fixincludes" script has been run. v0.0.3 Tue Oct 18 18:13:46 PDT 1994 - Fixed configure to test for snoop before dlpi to avoid problems under IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). v0.0.2 Wed Oct 12 20:56:37 PDT 1994 - Implement timeout in the dlpi pcap_open_live(). Thanks to Richard Stevens. - Determine pcap link type from dlpi media type. Resulted from report by Mahesh Jethanandani (mahesh@npix.com). v0.0.1 Fri Jun 24 14:50:57 PDT 1994 - Fixed bug in nit_setflags() in pcap-snit.c. The streams ioctl timeout wasn't being initialized sometimes resulting in an "NIOCSFLAGS: Invalid argument" error under OSF/1. Reported by Matt Day (mday@artisoft.com) and Danny Mitzel (dmitzel@whitney.hitc.com). - Turn on FDDI support by default. v0.0 Mon Jun 20 19:20:16 PDT 1994 - Initial release. - Fixed bug with greater/less keywords, reported by Mark Andrews (mandrews@alias.com). - Fix bug where '|' was defined as BPF_AND instead of BPF_OR, reported by Elan Amir (elan@leeb.cs.berkeley.edu). - Machines with little-endian byte ordering are supported thanks to Jeff Mogul. - Add hack for version 2.3 savefiles which don't have caplen and len swapped thanks to Vern Paxson. - Added "&&" and "||" aliases for "and" and "or" thanks to Vern Paxson. - Added length, inbound and outbound keywords. diff --git a/Makefile.in b/Makefile.in index 54246586828d..3468e204c756 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,843 +1,843 @@ # Copyright (c) 1993, 1994, 1995, 1996 -# The Regents of the University of California. All rights reserved. +# The Regents of the University of California. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that: (1) source code distributions # retain the above copyright notice and this paragraph in its entirety, (2) # distributions including binary code include the above copyright notice and # this paragraph in its entirety in the documentation or other materials # provided with the distribution, and (3) all advertising materials mentioning # features or use of this software display the following acknowledgement: # ``This product includes software developed by the University of California, # Lawrence Berkeley Laboratory and its contributors.'' Neither the name of # the University nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior # written permission. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # Various configurable paths (remember to edit Makefile.in, not Makefile) # # Top level hierarchy prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ # Pathname of directory to install the configure program bindir = @bindir@ # Pathname of directory to install the rpcapd daemon sbindir = @sbindir@ # Pathname of directory to install the include files includedir = @includedir@ # Pathname of directory to install the library libdir = @libdir@ # Pathname of directory to install the man pages mandir = @mandir@ # VPATH srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ # # You shouldn't need to edit anything below. # LD = /usr/bin/ld CC = @CC@ AR = @AR@ LN_S = @LN_S@ MKDEP = @MKDEP@ CCOPT = @V_CCOPT@ SHLIB_CCOPT = @V_SHLIB_CCOPT@ INCLS = -I. @V_INCLS@ DEFS = -DBUILDING_PCAP -Dpcap_EXPORTS @DEFS@ @V_DEFS@ ADDLOBJS = @ADDLOBJS@ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ LIBS = @LIBS@ CROSSFLAGS= CFLAGS = @CFLAGS@ ${CROSSFLAGS} LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} DYEXT = @DYEXT@ RPATH = @RPATH@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ PROG=libpcap PTHREAD_LIBS=@PTHREAD_LIBS@ BUILD_RPCAPD=@BUILD_RPCAPD@ INSTALL_RPCAPD=@INSTALL_RPCAPD@ # Standard CFLAGS for building members of a shared library FULL_CFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS) CXXFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS) INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ LEX = @LEX@ BISON_BYACC = @BISON_BYACC@ # Explicitly define compilation rule since SunOS 4's make doesn't like gcc. # Also, gcc does not remove the .o before forking 'as', which can be a # problem if you don't own the file but can write to the directory. .c.o: @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c PLATFORM_C_SRC = @PLATFORM_C_SRC@ PLATFORM_CXX_SRC = @PLATFORM_CXX_SRC@ MODULE_C_SRC = @MODULE_C_SRC@ REMOTE_C_SRC = @REMOTE_C_SRC@ COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \ fmtutils.c pcap-util.c \ savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \ pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c GENERATED_C_SRC = scanner.c grammar.c LIBOBJS = @LIBOBJS@ SRC = $(PLATFORM_C_SRC) $(PLATFORM_CXX_SRC) \ $(MODULE_C_SRC) $(REMOTE_C_SRC) $(COMMON_C_SRC) \ $(GENERATED_C_SRC) # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot # hack the extra indirection, and we have to handle PLATFORM_CXX_SRC # differently from the defines for C source OBJ = $(PLATFORM_C_SRC:.c=.o) $(PLATFORM_CXX_SRC:.cpp=.o) \ $(MODULE_C_SRC:.c=.o) $(REMOTE_C_SRC:.c=.o) $(COMMON_C_SRC:.c=.o) \ $(GENERATED_C_SRC:.c=.o) \ $(LIBOBJS) PUBHDR = \ pcap.h \ pcap-bpf.h \ pcap-namedb.h \ pcap/bluetooth.h \ pcap/bpf.h \ pcap/can_socketcan.h \ pcap/compiler-tests.h \ pcap/dlt.h \ pcap/funcattrs.h \ pcap/ipnet.h \ pcap/namedb.h \ pcap/nflog.h \ pcap/pcap-inttypes.h \ pcap/pcap.h \ pcap/sll.h \ pcap/socket.h \ pcap/usb.h \ pcap/vlan.h HDR = $(PUBHDR) \ arcnet.h \ atmuni31.h \ diag-control.h \ ethertype.h \ extract.h \ fmtutils.h \ ftmacros.h \ gencode.h \ ieee80211.h \ llc.h \ nametoaddr.h \ nlpid.h \ optimize.h \ pcap-common.h \ pcap-int.h \ pcap-rpcap.h \ pcap-types.h \ pcap-usb-linux-common.h \ pcap-util.h \ pflog.h \ portability.h \ ppp.h \ rpcap-protocol.h \ sf-pcap.h \ sf-pcapng.h \ sunatmpos.h \ varattrs.h GENHDR = \ scanner.h grammar.h TAGFILES = \ $(SRC) $(HDR) CLEANFILES = $(OBJ) libpcap.a libpcap.so.`cat $(srcdir)/VERSION` \ $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENERATED_C_SRC) $(GENHDR) \ lex.yy.c pcap-config libpcap.pc MAN1 = pcap-config.1 MAN3PCAP_EXPAND = \ pcap.3pcap.in \ pcap_compile.3pcap.in \ pcap_datalink.3pcap.in \ pcap_dump_open.3pcap.in \ pcap_get_tstamp_precision.3pcap.in \ pcap_list_datalinks.3pcap.in \ pcap_list_tstamp_types.3pcap.in \ pcap_open_dead.3pcap.in \ pcap_open_offline.3pcap.in \ pcap_set_immediate_mode.3pcap.in \ pcap_set_tstamp_precision.3pcap.in \ pcap_set_tstamp_type.3pcap.in MAN3PCAP_NOEXPAND = \ pcap_activate.3pcap \ pcap_breakloop.3pcap \ pcap_can_set_rfmon.3pcap \ pcap_close.3pcap \ pcap_create.3pcap \ pcap_datalink_name_to_val.3pcap \ pcap_datalink_val_to_name.3pcap \ pcap_dump.3pcap \ pcap_dump_close.3pcap \ pcap_dump_file.3pcap \ pcap_dump_flush.3pcap \ pcap_dump_ftell.3pcap \ pcap_file.3pcap \ pcap_fileno.3pcap \ pcap_findalldevs.3pcap \ pcap_freecode.3pcap \ pcap_get_required_select_timeout.3pcap \ pcap_get_selectable_fd.3pcap \ pcap_geterr.3pcap \ pcap_init.3pcap \ pcap_inject.3pcap \ pcap_is_swapped.3pcap \ pcap_lib_version.3pcap \ pcap_lookupdev.3pcap \ pcap_lookupnet.3pcap \ pcap_loop.3pcap \ pcap_major_version.3pcap \ pcap_next_ex.3pcap \ pcap_offline_filter.3pcap \ pcap_open_live.3pcap \ pcap_set_buffer_size.3pcap \ pcap_set_datalink.3pcap \ pcap_set_promisc.3pcap \ pcap_set_protocol_linux.3pcap \ pcap_set_rfmon.3pcap \ pcap_set_snaplen.3pcap \ pcap_set_timeout.3pcap \ pcap_setdirection.3pcap \ pcap_setfilter.3pcap \ pcap_setnonblock.3pcap \ pcap_snapshot.3pcap \ pcap_stats.3pcap \ pcap_statustostr.3pcap \ pcap_strerror.3pcap \ pcap_tstamp_type_name_to_val.3pcap \ pcap_tstamp_type_val_to_name.3pcap MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=) MANFILE = \ pcap-savefile.manfile.in MANMISC = \ pcap-filter.manmisc.in \ pcap-linktype.manmisc.in \ pcap-tstamp.manmisc.in EXTRA_DIST = \ CHANGES \ ChmodBPF/ChmodBPF \ ChmodBPF/StartupParameters.plist \ CREDITS \ CMakeLists.txt \ INSTALL.md \ LICENSE \ Makefile.in \ Makefile-devel-adds \ README.md \ doc/README.Win32.md \ doc/README.aix \ doc/README.dag \ doc/README.hpux \ doc/README.linux \ doc/README.macos \ doc/README.septel \ doc/README.sita \ doc/README.solaris.md \ CONTRIBUTING.md \ TODO \ VERSION \ aclocal.m4 \ charconv.c \ charconv.h \ chmod_bpf \ cmake_uninstall.cmake.in \ cmakeconfig.h.in \ cmake/Modules/FindAirPcap.cmake \ cmake/Modules/FindDAG.cmake \ cmake/Modules/Finddpdk.cmake \ cmake/Modules/FindFseeko.cmake \ cmake/Modules/FindLFS.cmake \ cmake/Modules/FindPacket.cmake \ cmake/Modules/FindSNF.cmake \ cmake/Modules/FindTC.cmake \ cmake/have_siocglifconf.c \ config.guess \ config.h.in \ config.sub \ configure \ configure.ac \ dlpisubs.c \ dlpisubs.h \ fad-getad.c \ fad-gifc.c \ fad-glifc.c \ grammar.y.in \ install-sh \ lbl/os-aix4.h \ lbl/os-aix7.h \ lbl/os-hpux11.h \ lbl/os-osf4.h \ lbl/os-osf5.h \ lbl/os-solaris2.h \ lbl/os-sunos4.h \ lbl/os-ultrix4.h \ libpcap.pc.in \ missing/asprintf.c \ missing/getopt.c \ missing/getopt.h \ missing/strlcat.c \ missing/strlcpy.c \ missing/strtok_r.c \ missing/win_asprintf.c \ mkdep \ msdos/bin2c.c \ msdos/makefile \ msdos/makefile.dj \ msdos/makefile.wc \ msdos/pkt_rx0.asm \ msdos/pkt_rx1.s \ msdos/pktdrvr.c \ msdos/pktdrvr.h \ msdos/readme.dos \ nomkdep \ org.tcpdump.chmod_bpf.plist \ pcap-airpcap.c \ pcap-airpcap.h \ pcap-bpf.c \ pcap-bt-linux.c \ pcap-bt-linux.h \ pcap-bt-monitor-linux.c \ pcap-bt-monitor-linux.h \ pcap-config.in \ pcap-dag.c \ pcap-dag.h \ pcap-dbus.c \ pcap-dbus.h \ pcap-dll.rc \ pcap-dlpi.c \ pcap-dos.c \ pcap-dos.h \ pcap-dpdk.c \ pcap-dpdk.h \ pcap-enet.c \ pcap-haiku.cpp \ pcap-int.h \ pcap-libdlpi.c \ pcap-linux.c \ pcap-namedb.h \ pcap-new.c \ pcap-netfilter-linux.c \ pcap-netfilter-linux.h \ pcap-netmap.c \ pcap-netmap.h \ pcap-nit.c \ pcap-npf.c \ pcap-null.c \ pcap-pf.c \ pcap-rdmasniff.c \ pcap-rdmasniff.h \ pcap-rpcap.c \ pcap-rpcap-int.h \ pcap-septel.c \ pcap-septel.h \ pcap-sita.h \ pcap-sita.c \ pcap-sita.html \ pcap-snf.c \ pcap-snf.h \ pcap-snit.c \ pcap-snoop.c \ pcap-tc.c \ pcap-tc.h \ pcap-usb-linux.c \ pcap-usb-linux.h \ rpcap-protocol.c \ rpcapd/CMakeLists.txt \ rpcapd/Makefile.in \ rpcapd/config_params.h \ rpcapd/daemon.h \ rpcapd/daemon.c \ rpcapd/fileconf.c \ rpcapd/fileconf.h \ rpcapd/log.h \ rpcapd/log.c \ rpcapd/org.tcpdump.rpcapd.plist \ rpcapd/rpcapd.c \ rpcapd/rpcapd.h \ rpcapd/rpcapd.inetd.conf \ rpcapd/rpcapd.manadmin.in \ rpcapd/rpcapd-config.manfile.in \ rpcapd/rpcapd.rc \ rpcapd/rpcapd.socket \ rpcapd/rpcapd.xinetd.conf \ rpcapd/rpcapd@.service \ rpcapd/win32-svc.c \ rpcapd/win32-svc.h \ sockutils.c \ sockutils.h \ sslutils.c \ sslutils.h \ scanner.l \ testprogs/CMakeLists.txt \ testprogs/Makefile.in \ testprogs/can_set_rfmon_test.c \ testprogs/capturetest.c \ testprogs/filtertest.c \ testprogs/findalldevstest.c \ testprogs/findalldevstest-perf.c \ testprogs/fuzz/CMakeLists.txt \ testprogs/fuzz/fuzz_both.c \ testprogs/fuzz/fuzz_both.options \ testprogs/fuzz/fuzz_filter.c \ testprogs/fuzz/fuzz_filter.options \ testprogs/fuzz/fuzz_pcap.c \ testprogs/fuzz/fuzz_pcap.options \ testprogs/fuzz/onefile.c \ testprogs/nonblocktest.c \ testprogs/opentest.c \ testprogs/reactivatetest.c \ testprogs/selpolltest.c \ testprogs/threadsignaltest.c \ testprogs/unix.h \ testprogs/valgrindtest.c \ testprogs/visopts.py \ testprogs/writecaptest.c TEST_DIST = `git ls-files tests | grep -v 'tests/\..*'` RELEASE_FILES = $(COMMON_C_SRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) \ $(TEST_DIST) all: libpcap.a shared $(BUILD_RPCAPD) libpcap.pc pcap-config libpcap.a: $(OBJ) @rm -f $@ $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) $(RANLIB) $@ shared: libpcap.$(DYEXT) libpcap.so: $(OBJ) @rm -f $@ VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ @V_SHLIB_CMD@ $(LDFLAGS) @V_SHLIB_OPT@ @V_SONAME_OPT@$@.$$MAJOR_VER \ -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) # # The following rule succeeds, but the result is untested. # # In macOS, the libpcap dylib has the name "libpcap.A.dylib", with its # full path as the install_name, and with the compatibility and current # version both set to 1. The compatibility version is set to 1 so that # programs built with a newer version of the library will run against # older versions if they don't use APIs available in the newer version # but not in the older version. # # We also use "A" as the major version, and 1 as the compatibility version, # but set the current version to the value in VERSION, with any non-numeric # stuff stripped off (the compatibility and current version must be of the # form X[.Y[.Z]], with Y and Z possibly absent, and with all components # numeric). # libpcap.dylib: $(OBJ) rm -f libpcap*.dylib VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ COMPAT_VER=1; \ CURRENT_VER=`sed 's/[^0-9.].*$$//' $(srcdir)/VERSION`; \ $(CC) -dynamiclib -undefined error $(LDFLAGS) @V_LIB_LDFLAGS_FAT@ \ -o libpcap.$$VER.dylib $(OBJ) $(ADDLOBJS) $(LIBS) \ -install_name $(libdir)/libpcap.$$MAJOR_VER.dylib \ -compatibility_version $$COMPAT_VER \ -current_version $$CURRENT_VER # # The HP-UX linker manual says that the convention for a versioned library # is libXXX.{number}, not libXXX.sl.{number}. That appears to be the case # on at least one HP-UX 11.00 system; libXXX.sl is a symlink to # libXXX.{number}. # # The manual also says "library-level versioning" (think "sonames") was # added in HP-UX 10.0. # # XXX - this assumes we're using the HP linker, rather than the GNU # linker, even with GCC. # libpcap.sl: $(OBJ) @MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f libpcap.$$MAJOR_VER MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ ld -b $(LDFLAGS) -o libpcap.$$MAJOR_VER +h libpcap.$$MAJOR_VER \ $(OBJ) $(ADDLOBJS) $(LIBS) # # AIX is different from everybody else. A shared library is an archive # library with one or more shared-object components. We still build a # normal static archive library on AIX, for the benefit of the traditional # scheme of building libpcap and tcpdump in subdirectories of the # same directory, with tcpdump statically linked with the libpcap # in question, but we also build a shared library as "libpcap.shareda" # and install *it*, rather than the static library, as "libpcap.a". # libpcap.shareda: $(OBJ) @rm -f $@ shr.o $(CC) $(LDFLAGS) @V_SHLIB_OPT@ -o shr.o $(OBJ) $(ADDLOBJS) $(LIBS) $(AR) rc $@ shr.o # # For platforms that don't support shared libraries (or on which we # don't support shared libraries). # libpcap.none: scanner.c: $(srcdir)/scanner.l $(LEX) -P pcap_ --header-file=scanner.h --nounput -o scanner.c $< scanner.h: scanner.c ## Recover from the removal of $@ @if test -f $@; then :; else \ rm -f scanner.c; \ $(MAKE) $(MAKEFLAGS) scanner.c; \ fi scanner.o: scanner.c grammar.h $(CC) $(FULL_CFLAGS) -c scanner.c # # Generate the grammar.y file. # # Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; # for example, the Solaris 9 make man page says # # Because make assigns $< and $* as it would for implicit rules # (according to the suffixes list and the directory contents), # they may be unreliable when used within explicit target entries. # # and this is an explicit target entry. # # Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in. # grammar.y: $(srcdir)/grammar.y.in ./config.status @rm -f $@ $@.tmp ./config.status --file=$@.tmp:$(srcdir)/grammar.y.in mv $@.tmp $@ grammar.c: grammar.y $(BISON_BYACC) -p pcap_ -o grammar.c -d $< grammar.h: grammar.c ## Recover from the removal of $@ @if test -f $@; then :; else \ rm -f grammar.c; \ $(MAKE) $(MAKEFLAGS) grammar.c; \ fi grammar.o: grammar.c scanner.h $(CC) $(FULL_CFLAGS) -c grammar.c gencode.o: $(srcdir)/gencode.c grammar.h scanner.h $(CC) $(FULL_CFLAGS) -c $(srcdir)/gencode.c asprintf.o: $(srcdir)/missing/asprintf.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/asprintf.c snprintf.o: $(srcdir)/missing/snprintf.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c strlcat.o: $(srcdir)/missing/strlcat.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcat.c strlcpy.o: $(srcdir)/missing/strlcpy.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcpy.c strtok_r.o: $(srcdir)/missing/strtok_r.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strtok_r.c # # Generate the libpcap.pc file. # # Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; # for example, the Solaris 9 make man page says # # Because make assigns $< and $* as it would for implicit rules # (according to the suffixes list and the directory contents), # they may be unreliable when used within explicit target entries. # # and this is an explicit target entry. # # Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in. # libpcap.pc: $(srcdir)/libpcap.pc.in ./config.status @rm -f $@ $@.tmp ./config.status --file=$@.tmp:$(srcdir)/libpcap.pc.in mv $@.tmp $@ # # Generate the pcap-config script. See above. # pcap-config: $(srcdir)/pcap-config.in ./config.status @rm -f $@ $@.tmp ./config.status --file=$@.tmp:$(srcdir)/pcap-config.in mv $@.tmp $@ chmod a+x $@ # # Remote pcap daemon. # build-rpcapd: libpcap.a (cd rpcapd; $(MAKE)) # # Test programs - not built by default, and not installed. # testprogs: FORCE (cd testprogs; $(MAKE)) FORCE: install: install-shared install-archive libpcap.pc pcap-config @INSTALL_RPCAPD@ [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) [ -d $(DESTDIR)$(includedir) ] || \ (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir)) [ -d $(DESTDIR)$(includedir)/pcap ] || \ (mkdir -p $(DESTDIR)$(includedir)/pcap; chmod 755 $(DESTDIR)$(includedir)/pcap) [ -d $(DESTDIR)$(mandir)/man1 ] || \ (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1) [ -d $(DESTDIR)$(mandir)/man3 ] || \ (mkdir -p $(DESTDIR)$(mandir)/man3; chmod 755 $(DESTDIR)$(mandir)/man3) [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) [ -d $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@) for i in $(PUBHDR); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(includedir)/$$i; done [ -d $(DESTDIR)$(bindir) ] || \ (mkdir -p $(DESTDIR)$(bindir); chmod 755 $(DESTDIR)$(bindir)) $(INSTALL_PROGRAM) pcap-config $(DESTDIR)$(bindir)/pcap-config [ -d $(DESTDIR)$(libdir)/pkgconfig ] || \ (mkdir -p $(DESTDIR)$(libdir)/pkgconfig; chmod 755 $(DESTDIR)$(libdir)/pkgconfig) $(INSTALL_DATA) libpcap.pc $(DESTDIR)$(libdir)/pkgconfig/libpcap.pc for i in $(MAN1); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(mandir)/man1/$$i; done for i in $(MAN3PCAP_NOEXPAND); do \ $(INSTALL_DATA) $(srcdir)/$$i \ $(DESTDIR)$(mandir)/man3/$$i; done for i in $(MAN3PCAP_EXPAND:.in=); do \ $(INSTALL_DATA) $$i \ $(DESTDIR)$(mandir)/man3/$$i; done (cd $(DESTDIR)$(mandir)/man3 && \ rm -f pcap_datalink_val_to_description.3pcap && \ $(LN_S) pcap_datalink_val_to_name.3pcap \ pcap_datalink_val_to_description.3pcap && \ rm -f pcap_datalink_val_to_description_or_dlt.3pcap && \ $(LN_S) pcap_datalink_val_to_name.3pcap \ pcap_datalink_val_to_description_or_dlt.3pcap && \ rm -f pcap_dump_fopen.3pcap && \ $(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \ rm -f pcap_freealldevs.3pcap && \ $(LN_S) pcap_findalldevs.3pcap pcap_freealldevs.3pcap && \ rm -f pcap_perror.3pcap && \ $(LN_S) pcap_geterr.3pcap pcap_perror.3pcap && \ rm -f pcap_sendpacket.3pcap && \ $(LN_S) pcap_inject.3pcap pcap_sendpacket.3pcap && \ rm -f pcap_free_datalinks.3pcap && \ $(LN_S) pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap && \ rm -f pcap_free_tstamp_types.3pcap && \ $(LN_S) pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap && \ rm -f pcap_dispatch.3pcap && \ $(LN_S) pcap_loop.3pcap pcap_dispatch.3pcap && \ rm -f pcap_minor_version.3pcap && \ $(LN_S) pcap_major_version.3pcap pcap_minor_version.3pcap && \ rm -f pcap_next.3pcap && \ $(LN_S) pcap_next_ex.3pcap pcap_next.3pcap && \ rm -f pcap_open_dead_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_dead.3pcap \ pcap_open_dead_with_tstamp_precision.3pcap && \ rm -f pcap_open_offline_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap && \ rm -f pcap_fopen_offline.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline.3pcap && \ rm -f pcap_fopen_offline_with_tstamp_precision.3pcap && \ $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap && \ rm -f pcap_tstamp_type_val_to_description.3pcap && \ $(LN_S) pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap && \ rm -f pcap_getnonblock.3pcap && \ $(LN_S) pcap_setnonblock.3pcap pcap_getnonblock.3pcap) for i in $(MANFILE); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done for i in $(MANMISC); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manmisc.in/.manmisc/'` \ $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done install-shared: install-shared-$(DYEXT) install-shared-so: libpcap.so [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ $(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so install-shared-dylib: libpcap.dylib [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ $(INSTALL_PROGRAM) libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ ln -sf libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ ln -sf libpcap.$$MAJOR_VER.dylib $(DESTDIR)$(libdir)/libpcap.dylib install-shared-sl: libpcap.sl [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ $(INSTALL_PROGRAM) libpcap.$$MAJOR_VER $(DESTDIR)$(libdir) ln -sf libpcap.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.sl install-shared-shareda: libpcap.shareda # # AIX shared libraries are weird. They're archive libraries # with one or more shared object components. # [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) $(INSTALL_PROGRAM) libpcap.shareda $(DESTDIR)$(libdir)/libpcap.a install-shared-none: install-archive: install-archive-$(DYEXT) install-archive-so install-archive-dylib install-archive-sl install-archive-none: libpcap.a # # Most platforms have separate suffixes for shared and # archive libraries, so we install both. # [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) $(INSTALL_DATA) libpcap.a $(DESTDIR)$(libdir)/libpcap.a $(RANLIB) $(DESTDIR)$(libdir)/libpcap.a install-archive-shareda: # # AIX, however, doesn't, so we don't install the archive # library on AIX. # install-rpcapd: (cd rpcapd; $(MAKE) DESTDIR=$(DESTDIR) install) uninstall: uninstall-shared uninstall-rpcapd rm -f $(DESTDIR)$(libdir)/libpcap.a for i in $(PUBHDR); do \ rm -f $(DESTDIR)$(includedir)/$$i; done -rmdir $(DESTDIR)$(includedir)/pcap rm -f $(DESTDIR)/$(libdir)/pkgconfig/libpcap.pc rm -f $(DESTDIR)/$(bindir)/pcap-config for i in $(MAN1); do \ rm -f $(DESTDIR)$(mandir)/man1/$$i; done for i in $(MAN3PCAP); do \ rm -f $(DESTDIR)$(mandir)/man3/$$i; done rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description_or_dlt.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_sendpacket.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_minor_version.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_next.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_open_dead_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_open_offline_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline_with_tstamp_precision.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_getnonblock.3pcap rm -f $(DESTDIR)$(mandir)/man3/pcap_tstamp_type_val_to_description.3pcap for i in $(MANFILE); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done for i in $(MANMISC); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done uninstall-shared: uninstall-shared-$(DYEXT) uninstall-shared-so: VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.so uninstall-shared-dylib: VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=A; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ rm -f $(DESTDIR)$(libdir)/libpcap.dylib uninstall-shared-sl: MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER; \ rm -f $(DESTDIR)$(libdir)/libpcap.sl uninstall-shared-shareda: rm -f $(DESTDIR)$(libdir)/libpcap.a uninstall-shared-none: uninstall-rpcapd: (cd rpcapd; $(MAKE) DESTDIR=$(DESTDIR) uninstall) clean: rm -f $(CLEANFILES) (cd rpcapd; $(MAKE) clean) (cd testprogs; $(MAKE) clean) distclean: clean rm -f Makefile grammar.y config.cache config.log config.status \ config.h config.h.in~ configure~ configure.ac~ \ - gnuc.h net os-proto.h libpcap.pc pcap-config stamp-h stamp-h.in + net os-proto.h libpcap.pc pcap-config stamp-h stamp-h.in rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=) rm -rf autom4te.cache (cd rpcapd; $(MAKE) distclean) (cd testprogs; $(MAKE) distclean) extags: $(TAGFILES) ctags $(TAGFILES) tags: $(TAGFILES) ctags -wtd $(TAGFILES) releasetar: @TAG=$(PROG)-`cat VERSION` && \ if git show-ref --tags --quiet --verify -- "refs/tags/$$TAG"; then \ git archive --prefix="$$TAG"/ -o "$$TAG".tar.gz "$$TAG" \ $(RELEASE_FILES) && \ echo "Archive build from tag $$TAG."; \ else \ git archive --prefix="$$TAG"/ -o "$$TAG".tar.gz HEAD \ $(RELEASE_FILES) && \ echo "No $$TAG tag. Archive build from HEAD."; \ fi depend: $(GENERATED_C_SRC) $(GENHDR) $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) (cd rpcapd; $(MAKE) depend) (cd testprogs; $(MAKE) depend) shellcheck: shellcheck -f gcc -e SC2006 build.sh build_matrix.sh build_common.sh diff --git a/README.md b/README.md index 46c33c24125e..e38b9a15d6b3 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,76 @@ # LIBPCAP 1.x.y by [The Tcpdump Group](https://www.tcpdump.org) **To report a security issue please send an e-mail to security@tcpdump.org.** To report bugs and other problems, contribute patches, request a feature, provide generic feedback etc please see the [guidelines for contributing](CONTRIBUTING.md). The [documentation directory](doc/) has README files about specific operating systems and options. Anonymous Git is available via: https://github.com/the-tcpdump-group/libpcap.git This directory contains source code for libpcap, a system-independent interface for user-level packet capture. libpcap provides a portable framework for low-level network monitoring. Applications include network statistics collection, security monitoring, network debugging, etc. Since almost every system vendor provides a different interface for packet capture, and since we've developed several tools that require this functionality, we've created this system-independent API to ease in porting and to alleviate the need for several system-dependent packet capture modules in each application. ```text -formerly from Lawrence Berkeley National Laboratory +formerly from Lawrence Berkeley National Laboratory Network Research Group ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z ``` ### Support for particular platforms and BPF For some platforms there are `README.{system}` files that discuss issues with the OS's interface for packet capture on those platforms, such as how to enable support for that interface in the OS, if it's not built in by default. The libpcap interface supports a filtering mechanism based on the architecture in the BSD packet filter. BPF is described in the 1993 Winter Usenix paper ``The BSD Packet Filter: A New Architecture for User-level Packet Capture'' ([compressed PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.Z), [gzipped PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.gz), [PDF](https://www.tcpdump.org/papers/bpf-usenix93.pdf)). Although most packet capture interfaces support in-kernel filtering, libpcap utilizes in-kernel filtering only for the BPF interface. On systems that don't have BPF, all packets are read into user-space and the BPF filters are evaluated in the libpcap library, incurring added overhead (especially, for selective filters). Ideally, libpcap would translate BPF filters into a filter program that is compatible with the underlying kernel subsystem, but this is not yet implemented. BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, macOS, and Solaris 11; an older, modified and undocumented version is standard in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the packetfilter interface but has been extended to accept BPF filters (which libpcap utilizes). Linux has a number of BPF based systems, and libpcap does not support any of the eBPF mechanisms as yet, although it supports many of the memory mapped receive mechanisms. See the [Linux-specific README](doc/README.linux) for more information. ### Note to Linux distributions and *BSD systems that include libpcap: There's now a rule to make a shared library, which should work on Linux and *BSD, among other platforms. It sets the soname of the library to `libpcap.so.1`; this is what it should be, **NOT** `libpcap.so.1.x` or `libpcap.so.1.x.y` or something such as that. We've been maintaining binary compatibility between libpcap releases for quite a while; there's no reason to tie a binary linked with libpcap to a particular release of libpcap. diff --git a/VERSION b/VERSION index 587c5f0c7309..18b311420650 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.3 +1.10.4 diff --git a/aclocal.m4 b/aclocal.m4 index 502a3711f677..9ec93c28d5e5 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,1328 +1,1327 @@ dnl Copyright (c) 1995, 1996, 1997, 1998 dnl The Regents of the University of California. All rights reserved. dnl dnl Redistribution and use in source and binary forms, with or without dnl modification, are permitted provided that: (1) source code distributions dnl retain the above copyright notice and this paragraph in its entirety, (2) dnl distributions including binary code include the above copyright notice and dnl this paragraph in its entirety in the documentation or other materials dnl provided with the distribution, and (3) all advertising materials mentioning dnl features or use of this software display the following acknowledgement: dnl ``This product includes software developed by the University of California, dnl Lawrence Berkeley Laboratory and its contributors.'' Neither the name of dnl the University nor the names of its contributors may be used to endorse dnl or promote products derived from this software without specific prior dnl written permission. dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED dnl WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. dnl dnl LBL autoconf macros dnl dnl dnl Do whatever AC_LBL_C_INIT work is necessary before using AC_PROG_CC. dnl dnl It appears that newer versions of autoconf (2.64 and later) will, dnl if you use AC_TRY_COMPILE in a macro, stick AC_PROG_CC at the dnl beginning of the macro, even if the macro itself calls AC_PROG_CC. dnl See the "Prerequisite Macros" and "Expanded Before Required" sections dnl in the Autoconf documentation. dnl dnl This causes a steaming heap of fail in our case, as we were, in dnl AC_LBL_C_INIT, doing the tests we now do in AC_LBL_C_INIT_BEFORE_CC, dnl calling AC_PROG_CC, and then doing the tests we now do in dnl AC_LBL_C_INIT. Now, we run AC_LBL_C_INIT_BEFORE_CC, AC_PROG_CC, dnl and AC_LBL_C_INIT at the top level. dnl AC_DEFUN(AC_LBL_C_INIT_BEFORE_CC, [ AC_BEFORE([$0], [AC_LBL_C_INIT]) AC_BEFORE([$0], [AC_PROG_CC]) AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) AC_BEFORE([$0], [AC_LBL_DEVEL]) AC_ARG_WITH(gcc, [ --without-gcc don't use gcc]) $1="" if test "${srcdir}" != "." ; then $1="-I\$(srcdir)" fi if test "${CFLAGS+set}" = set; then LBL_CFLAGS="$CFLAGS" fi if test -z "$CC" ; then case "$host_os" in bsdi*) AC_CHECK_PROG(SHLICC2, shlicc2, yes, no) if test $SHLICC2 = yes ; then CC=shlicc2 export CC fi ;; esac fi if test -z "$CC" -a "$with_gcc" = no ; then CC=cc export CC fi ]) dnl dnl Determine which compiler we're using (cc or gcc) dnl If using gcc, determine the version number dnl If using cc: dnl require that it support ansi prototypes dnl use -O (AC_PROG_CC will use -g -O2 on gcc, so we don't need to dnl do that ourselves for gcc) dnl add -g flags, as appropriate dnl explicitly specify /usr/local/include dnl dnl NOTE WELL: with newer versions of autoconf, "gcc" means any compiler dnl that defines __GNUC__, which means clang, for example, counts as "gcc". dnl dnl usage: dnl dnl AC_LBL_C_INIT(copt, incls) dnl dnl results: dnl dnl $1 (copt set) dnl $2 (incls set) dnl CC dnl LDFLAGS dnl LBL_CFLAGS dnl AC_DEFUN(AC_LBL_C_INIT, [ AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) AC_BEFORE([$0], [AC_LBL_DEVEL]) AC_BEFORE([$0], [AC_LBL_SHLIBS_INIT]) if test "$GCC" = yes ; then # # -Werror forces warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) else $2="$$2 -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" case "$host_os" in darwin*) # # This is assumed either to be GCC or clang, both # of which use -Werror to force warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) ;; hpux*) # # HP C, which is what we presume we're using, doesn't # exit with a non-zero exit status if we hand it an # invalid -W flag, can't be forced to do so even with # +We, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes ;; irix*) # # MIPS C, which is what we presume we're using, doesn't # necessarily exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # It also, apparently, defaults to "char" being # unsigned, unlike most other C implementations; # I suppose we could say "signed char" whenever # we want to guarantee a signed "char", but let's # just force signed chars. # # -xansi is normally the default, but the # configure script was setting it; perhaps -cckr # was the default in the Old Days. (Then again, # that would probably be for backwards compatibility # in the days when ANSI C was Shiny and New, i.e. # 1989 and the early '90's, so maybe we can just # drop support for those compilers.) # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # $1="$$1 -xansi -signed -g3" ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # # The DEC C compiler, which is what we presume we're # using, doesn't exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # $1="$$1 -g3" ;; solaris*) # # Assumed to be Sun C, which requires -errwarn to force # warnings to be treated as errors. # ac_lbl_cc_force_warning_errors=-errwarn # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # AC_LBL_CHECK_COMPILER_OPT($1, -xldscope=hidden) ;; ultrix*) AC_MSG_CHECKING(that Ultrix $CC hacks const in prototypes) AC_CACHE_VAL(ac_cv_lbl_cc_const_proto, AC_TRY_COMPILE( [#include ], [struct a { int b; }; void c(const struct a *)], ac_cv_lbl_cc_const_proto=yes, ac_cv_lbl_cc_const_proto=no)) AC_MSG_RESULT($ac_cv_lbl_cc_const_proto) if test $ac_cv_lbl_cc_const_proto = no ; then AC_DEFINE(const,[], [to handle Ultrix compilers that don't support const in prototypes]) fi ;; esac $1="$$1 -O" fi ]) dnl dnl Save the values of various variables that affect compilation and dnl linking, and that we don't ourselves modify persistently; done dnl before a test involving compiling or linking is done, so that we dnl can restore those variables after the test is done. dnl AC_DEFUN(AC_LBL_SAVE_CHECK_STATE, [ save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" ]) dnl dnl Restore the values of variables saved by AC_LBL_SAVE_CHECK_STATE. dnl AC_DEFUN(AC_LBL_RESTORE_CHECK_STATE, [ CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" ]) dnl dnl Check whether the compiler option specified as the second argument dnl is supported by the compiler and, if so, add it to the macro dnl specified as the first argument dnl dnl If a third argument is supplied, treat it as C code to be compiled dnl with the flag in question, and the "treat warnings as errors" flag dnl set, and don't add the flag to the first argument if the compile dnl fails; this is for warning options cause problems that can't be dnl worked around. If a third argument is supplied, a fourth argument dnl should also be supplied; it's a message describing what the test dnl program is checking. dnl AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, [ AC_MSG_CHECKING([whether the compiler supports the $2 option]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $2" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # AC_COMPILE_IFELSE( [AC_LANG_SOURCE([[int main(void) { return 0; }]])], [ AC_MSG_RESULT([yes]) can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x$4" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" AC_MSG_CHECKING(whether $2 $4) AC_COMPILE_IFELSE( [AC_LANG_SOURCE($3)], [ # # Not a problem. # AC_MSG_RESULT(no) ], [ # # A problem. # AC_MSG_RESULT(yes) can_add_to_cflags=no ]) fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then $1="$$1 $2" fi ], [ AC_MSG_RESULT([no]) CFLAGS="$save_CFLAGS" ]) ac_c_werror_flag="$save_ac_c_werror_flag" ]) dnl dnl Check whether the compiler supports an option to generate dnl Makefile-style dependency lines dnl dnl GCC uses -M for this. Non-GCC compilers that support this dnl use a variety of flags, including but not limited to -M. dnl dnl We test whether the flag in question is supported, as older dnl versions of compilers might not support it. dnl dnl We don't try all the possible flags, just in case some flag means dnl "generate dependencies" on one compiler but means something else dnl on another compiler. dnl dnl Most compilers that support this send the output to the standard dnl output by default. IBM's XLC, however, supports -M but sends dnl the output to {sourcefile-basename}.u, and AIX has no /dev/stdout dnl to work around that, so we don't bother with XLC. dnl AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT, [ AC_MSG_CHECKING([whether the compiler supports generating dependencies]) if test "$GCC" = yes ; then # # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even # though it's not); we assume that, in this case, the flag # would be -M. # ac_lbl_dependency_flag="-M" else # # Not GCC or a compiler deemed to be GCC; what platform is # this? (We're assuming that if the compiler isn't GCC # it's the compiler from the vendor of the OS; that won't # necessarily be true for x86 platforms, where it might be # the Intel C compiler.) # case "$host_os" in irix*|osf*|darwin*) # # MIPS C for IRIX, DEC C, and clang all use -M. # ac_lbl_dependency_flag="-M" ;; solaris*) # # Sun C uses -xM. # ac_lbl_dependency_flag="-xM" ;; hpux*) # # HP's older C compilers don't support this. # HP's newer C compilers support this with # either +M or +Make; the older compilers # interpret +M as something completely # different, so we use +Make so we don't # think it works with the older compilers. # ac_lbl_dependency_flag="+Make" ;; *) # # Not one of the above; assume no support for # generating dependencies. # ac_lbl_dependency_flag="" ;; esac fi # # Is ac_lbl_dependency_flag defined and, if so, does the compiler # complain about it? # # Note: clang doesn't seem to exit with an error status when handed # an unknown non-warning error, even if you pass it # -Werror=unknown-warning-option. However, it always supports # -M, so the fact that this test always succeeds with clang # isn't an issue. # if test ! -z "$ac_lbl_dependency_flag"; then AC_LANG_CONFTEST( [AC_LANG_SOURCE([[int main(void) { return 0; }]])]) if AC_RUN_LOG([eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1"]); then AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag]) DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" MKDEP='${top_srcdir}/mkdep' else AC_MSG_RESULT([no]) # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP='${top_srcdir}/nomkdep' fi rm -rf conftest* else AC_MSG_RESULT([no]) # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP='${top_srcdir}/nomkdep' fi AC_SUBST(DEPENDENCY_CFLAG) AC_SUBST(MKDEP) ]) dnl dnl Determine what options are needed to build a shared library dnl dnl usage: dnl dnl AC_LBL_SHLIBS_INIT dnl dnl results: dnl dnl V_SHLIB_CCOPT (modified to build position-independent code) dnl V_SHLIB_CMD dnl V_SHLIB_OPT dnl V_SONAME_OPT dnl AC_DEFUN(AC_LBL_SHLIBS_INIT, [AC_PREREQ(2.50) if test "$GCC" = yes ; then # # On platforms where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in AIX and Darwin/macOS); # # define option to set the soname of the shared library, # if the OS supports that; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" case "$host_os" in aix*) ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*) # # Platforms where the C compiler is GCC or accepts # compatible command-line arguments, and the linker # is the GNU linker or accepts compatible command-line # arguments. # # Some instruction sets require -fPIC on some # operating systems. Check for them. If you # have a combination that requires it, add it # here. # PIC_OPT=-fpic case "$host_cpu" in sparc64*) case "$host_os" in freebsd*|openbsd*|linux*) PIC_OPT=-fPIC ;; esac ;; esac V_SHLIB_CCOPT="$V_SHLIB_CCOPT $PIC_OPT" V_SONAME_OPT="-Wl,-soname," ;; hpux*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" # # XXX - this assumes GCC is using the HP linker, # rather than the GNU linker, and that the "+h" # option is used on all HP-UX platforms, both .sl # and .so. # V_SONAME_OPT="-Wl,+h," # # By default, directories specified with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; solaris*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" # # Sun/Oracle's C compiler, GCC, and GCC-compatible # compilers support -Wl,{comma-separated list of options}, # and we use the C compiler, not ld, for all linking, # including linking to produce a shared library. # V_SONAME_OPT="-Wl,-h," ;; esac else # # Set the appropriate compiler flags and, on platforms # where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in Darwin/macOS); # # if we generate ".so" shared libraries, define the # appropriate options for building the shared library; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # # Note: spaces after V_SONAME_OPT are significant; on # some platforms the soname is passed with a GCC-like # "-Wl,-soname,{soname}" option, with the soname part # of the option, while on other platforms the C compiler # driver takes it as a regular option with the soname # following the option. # case "$host_os" in aix*) V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G -bnoentry -bexpall" ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*) # # Platforms where the C compiler is GCC or accepts # compatible command-line arguments, and the linker # is the GNU linker or accepts compatible command-line # arguments. # # XXX - does 64-bit SPARC require -fPIC? # V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-Wl,-soname," ;; hpux*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT +z" V_SHLIB_CMD="\$(LD)" V_SHLIB_OPT="-b" V_SONAME_OPT="+h " # # By default, directories specified with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-soname " ;; solaris*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -Kpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G" # # Sun/Oracle's C compiler, GCC, and GCC-compatible # compilers support -Wl,{comma-separated list of options}, # and we use the C compiler, not ld, for all linking, # including linking to produce a shared library. # V_SONAME_OPT="-Wl,-h," ;; esac fi ]) # # Try compiling a sample of the type of code that appears in # gencode.c with "inline", "__inline__", and "__inline". # # Autoconf's AC_C_INLINE, at least in autoconf 2.13, isn't good enough, # as it just tests whether a function returning "int" can be inlined; # at least some versions of HP's C compiler can inline that, but can't # inline a function that returns a struct pointer. # # Make sure we use the V_CCOPT flags, because some of those might # disable inlining. # AC_DEFUN(AC_LBL_C_INLINE, [AC_MSG_CHECKING(for inline) save_CFLAGS="$CFLAGS" CFLAGS="$V_CCOPT" AC_CACHE_VAL(ac_cv_lbl_inline, [ ac_cv_lbl_inline="" ac_lbl_cc_inline=no for ac_lbl_inline in inline __inline__ __inline do AC_TRY_COMPILE( [#define inline $ac_lbl_inline static inline struct iltest *foo(void); struct iltest { int iltest1; int iltest2; }; static inline struct iltest * foo() { static struct iltest xxx; return &xxx; }],,ac_lbl_cc_inline=yes,) if test "$ac_lbl_cc_inline" = yes ; then break; fi done if test "$ac_lbl_cc_inline" = yes ; then ac_cv_lbl_inline=$ac_lbl_inline fi]) CFLAGS="$save_CFLAGS" if test ! -z "$ac_cv_lbl_inline" ; then AC_MSG_RESULT($ac_cv_lbl_inline) else AC_MSG_RESULT(no) fi AC_DEFINE_UNQUOTED(inline, $ac_cv_lbl_inline, [Define as token for inline if inlining supported])]) # # Test whether we have __atomic_load_n() and __atomic_store_n(). # # We use AC_TRY_LINK because AC_TRY_COMPILE will succeed, as the # compiler will just think that those functions are undefined, # and perhaps warn about that, but not fail to compile. # AC_DEFUN(AC_PCAP_C___ATOMICS, [ AC_MSG_CHECKING(for __atomic_load_n) AC_CACHE_VAL(ac_cv_have___atomic_load_n, AC_TRY_LINK([], [ int i = 17; int j; j = __atomic_load_n(&i, __ATOMIC_RELAXED); ], ac_have___atomic_load_n=yes, ac_have___atomic_load_n=no)) AC_MSG_RESULT($ac_have___atomic_load_n) if test $ac_have___atomic_load_n = yes ; then AC_DEFINE(HAVE___ATOMIC_LOAD_N, 1, [define if __atomic_load_n is supported by the compiler]) fi AC_MSG_CHECKING(for __atomic_store_n) AC_CACHE_VAL(ac_cv_have___atomic_store_n, AC_TRY_LINK([], [ int i; __atomic_store_n(&i, 17, __ATOMIC_RELAXED); ], ac_have___atomic_store_n=yes, ac_have___atomic_store_n=no)) AC_MSG_RESULT($ac_have___atomic_store_n) if test $ac_have___atomic_store_n = yes ; then AC_DEFINE(HAVE___ATOMIC_STORE_N, 1, [define if __atomic_store_n is supported by the compiler]) fi]) dnl dnl If using gcc, make sure we have ANSI ioctl definitions dnl dnl usage: dnl dnl AC_LBL_FIXINCLUDES dnl AC_DEFUN(AC_LBL_FIXINCLUDES, [if test "$GCC" = yes ; then AC_MSG_CHECKING(for ANSI ioctl definitions) AC_CACHE_VAL(ac_cv_lbl_gcc_fixincludes, AC_TRY_COMPILE( [/* * This generates a "duplicate case value" when fixincludes * has not be run. */ # include # include # include # ifdef HAVE_SYS_IOCCOM_H # include # endif], [switch (0) { case _IO('A', 1):; case _IO('B', 1):; }], ac_cv_lbl_gcc_fixincludes=yes, ac_cv_lbl_gcc_fixincludes=no)) AC_MSG_RESULT($ac_cv_lbl_gcc_fixincludes) if test $ac_cv_lbl_gcc_fixincludes = no ; then # Don't cache failure unset ac_cv_lbl_gcc_fixincludes AC_MSG_ERROR(see the INSTALL for more info) fi fi]) dnl dnl Checks to see if union wait is used with WEXITSTATUS() dnl dnl usage: dnl dnl AC_LBL_UNION_WAIT dnl dnl results: dnl dnl DECLWAITSTATUS (defined) dnl AC_DEFUN(AC_LBL_UNION_WAIT, [AC_MSG_CHECKING(if union wait is used) AC_CACHE_VAL(ac_cv_lbl_union_wait, AC_TRY_COMPILE([ # include # include ], [int status; u_int i = WEXITSTATUS(status); u_int j = waitpid(0, &status, 0);], ac_cv_lbl_union_wait=no, ac_cv_lbl_union_wait=yes)) AC_MSG_RESULT($ac_cv_lbl_union_wait) if test $ac_cv_lbl_union_wait = yes ; then AC_DEFINE(DECLWAITSTATUS,union wait,[type for wait]) else AC_DEFINE(DECLWAITSTATUS,int,[type for wait]) fi]) dnl dnl Checks to see if -R is used dnl dnl usage: dnl dnl AC_LBL_HAVE_RUN_PATH dnl dnl results: dnl dnl ac_cv_lbl_have_run_path (yes or no) dnl AC_DEFUN(AC_LBL_HAVE_RUN_PATH, [AC_MSG_CHECKING(for ${CC-cc} -R) AC_CACHE_VAL(ac_cv_lbl_have_run_path, [echo 'main(){}' > conftest.c ${CC-cc} -o conftest conftest.c -R/a1/b2/c3 >conftest.out 2>&1 if test ! -s conftest.out ; then ac_cv_lbl_have_run_path=yes else ac_cv_lbl_have_run_path=no fi rm -f -r conftest*]) AC_MSG_RESULT($ac_cv_lbl_have_run_path) ]) dnl dnl If the file .devel exists: dnl Add some warning flags if the compiler supports them dnl If an os prototype include exists, symlink os-proto.h to it dnl dnl usage: dnl dnl AC_LBL_DEVEL(copt) dnl dnl results: dnl dnl $1 (copt appended) dnl HAVE_OS_PROTO_H (defined) dnl os-proto.h (symlinked) dnl AC_DEFUN(AC_LBL_DEVEL, [rm -f os-proto.h if test "${LBL_CFLAGS+set}" = set; then $1="$$1 ${LBL_CFLAGS}" fi if test -f .devel ; then # # Skip all the warning option stuff on some compilers. # if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then AC_LBL_CHECK_COMPILER_OPT($1, -W) AC_LBL_CHECK_COMPILER_OPT($1, -Wall) AC_LBL_CHECK_COMPILER_OPT($1, -Wcomma) AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation) AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral) AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-noreturn) AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations) AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-arith) AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-sign) AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow) AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare) AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-parameter) AC_LBL_CHECK_COMPILER_OPT($1, -Wused-but-marked-unused) # Warns about safeguards added in case the enums are # extended # AC_LBL_CHECK_COMPILER_OPT($1, -Wcovered-switch-default) # # This can cause problems with ntohs(), ntohl(), # htons(), and htonl() on some platforms, such # as OpenBSD 6.3 with Clang 5.0.1. I guess the # problem is that the macro that ultimately does # the byte-swapping involves a conditional # expression that tests whether the value being # swapped is a compile-time constant or not, # using __builtin_constant_p(), and, depending # on whether it is, does a compile-time swap or # a run-time swap; perhaps the compiler always # considers one of the two results of the # conditional expressin is never evaluated, # because the conditional check is done at # compile time, and thus always says "that # expression is never executed". # # (Perhaps there should be a way of flagging # an expression that you *want* evaluated at # compile time, so that the compiler 1) warns # if it *can't* be evaluated at compile time # and 2) *doesn't* warn that the true or false # branch will never be reached.) # AC_LBL_CHECK_COMPILER_OPT($1, -Wunreachable-code, [ #include unsigned short testme(unsigned short a) { return ntohs(a); } ], [generates warnings from ntohs()]) AC_LBL_CHECK_COMPILER_OPT($1, -Wshorten-64-to-32) fi AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT() # # We used to set -n32 for IRIX 6 when not using GCC (presumed # to mean that we're using MIPS C or MIPSpro C); it specified # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm # not sure why that would be something to do *only* with a # .devel file; why should the ABI for which we produce code # depend on .devel? # os=`echo $host_os | sed -e 's/\([[0-9]][[0-9]]*\)[[^0-9]].*$/\1/'` name="lbl/os-$os.h" if test -f $name ; then ln -s $name os-proto.h AC_DEFINE(HAVE_OS_PROTO_H, 1, [if there's an os_proto.h for this platform, to use additional prototypes]) else AC_MSG_WARN(can't find $name) fi fi]) dnl dnl Improved version of AC_CHECK_LIB dnl dnl Thanks to John Hawkinson (jhawk@mit.edu) dnl dnl usage: dnl dnl AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) dnl dnl results: dnl dnl LIBS dnl dnl XXX - "AC_LBL_LIBRARY_NET" was redone to use "AC_SEARCH_LIBS" dnl rather than "AC_LBL_CHECK_LIB", so this isn't used any more. dnl We keep it around for reference purposes in case it's ever dnl useful in the future. dnl define(AC_LBL_CHECK_LIB, [AC_MSG_CHECKING([for $2 in -l$1]) dnl Use a cache variable name containing the library, function dnl name, and extra libraries to link with, because the test really is dnl for library $1 defining function $2, when linked with potinal dnl library $5, not just for library $1. Separate tests with the same dnl $1 and different $2's or $5's may have different results. ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'` AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var, [ac_save_LIBS="$LIBS" LIBS="-l$1 $5 $LIBS" AC_TRY_LINK(dnl ifelse([$2], [main], , dnl Avoid conflicting decl of main. [/* Override any gcc2 internal prototype to avoid an error. */ ]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus extern "C" #endif ])dnl [/* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $2(); ]), [$2()], eval "ac_cv_lbl_lib_$ac_lib_var=yes", eval "ac_cv_lbl_lib_$ac_lib_var=no") LIBS="$ac_save_LIBS" ])dnl if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then AC_MSG_RESULT(yes) ifelse([$3], , [changequote(, )dnl ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` changequote([, ])dnl AC_DEFINE_UNQUOTED($ac_tr_lib) LIBS="-l$1 $LIBS" ], [$3]) else AC_MSG_RESULT(no) ifelse([$4], , , [$4 ])dnl fi ]) dnl dnl AC_LBL_LIBRARY_NET dnl dnl This test is for network applications that need socket functions and dnl getaddrinfo()/getnameinfo()-ish functions. We now require dnl getaddrinfo() and getnameinfo(). We also prefer versions of dnl recvmsg() that conform to the Single UNIX Specification, so that we dnl can check whether a datagram received with recvmsg() was truncated dnl when received due to the buffer being too small. dnl dnl On most operating systems, they're available in the system library. dnl dnl Under Solaris, we need to link with libsocket and libnsl to get dnl getaddrinfo() and getnameinfo() and, if we have libxnet, we need to dnl link with libxnet before libsocket to get a version of recvmsg() dnl that conforms to the Single UNIX Specification. dnl dnl We use getaddrinfo() because we want a portable thread-safe way dnl of getting information for a host name or port; there exist _r dnl versions of gethostbyname() and getservbyname() on some platforms, dnl but not on all platforms. dnl AC_DEFUN(AC_LBL_LIBRARY_NET, [ # # Most operating systems have getaddrinfo() in the default searched # libraries (i.e. libc). Check there first. # AC_CHECK_FUNC(getaddrinfo,, [ # # Not found in the standard system libraries. # Try libsocket, which requires libnsl. # AC_CHECK_LIB(socket, getaddrinfo, [ # # OK, we found it in libsocket. # LIBS="-lsocket -lnsl $LIBS" ], [ # # Not found in libsocket; test for it in libnetwork, which # is where it is in Haiku. # AC_CHECK_LIB(network, getaddrinfo, [ # # OK, we found it in libnetwork. # LIBS="-lnetwork $LIBS" ], [ # # We didn't find it. # AC_MSG_ERROR([getaddrinfo is required, but wasn't found]) ]) ], -lnsl) # # OK, do we have recvmsg() in libxnet? # We also link with libsocket and libnsl. # AC_CHECK_LIB(xnet, recvmsg, [ # # Yes - link with it as well. # LIBS="-lxnet $LIBS" ], , -lsocket -lnsl) ]) # DLPI needs putmsg under HPUX so test for -lstr while we're at it AC_SEARCH_LIBS(putmsg, str) ]) m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl serial 11 (pkg-config-0.29) dnl dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found -dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is -dnl used since that's the first version where most current features of -dnl pkg-config existed. +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.17.0 is +dnl used since that's the first version where --static was supported. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) + _pkg_min_version=m4_default([$1], [0.17.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. AC_DEFUN([PKG_CHECK_EXISTS], [ if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [FLAGS], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG $2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 AC_DEFUN([PKG_CHECK_MODULES], [ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $2, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $2, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS_STATIC], [static-link linker flags for $2, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2 with pkg-config]) PKG_CHECK_EXISTS($2, [ # # The package was found, so try to get its C flags and # libraries. # _PKG_CONFIG([$1][_CFLAGS], [--cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [--libs], [$2]) _PKG_CONFIG([$1][_LIBS_STATIC], [--libs --static], [$2]) m4_define([_PKG_TEXT], [ Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then # # That failed - report an error. # - AC_MSG_RESULT([error]) - _PKG_SHORT_ERRORS_SUPPORTED + AC_MSG_RESULT([error]) + _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - AC_MSG_RESULT([not found (pkg-config not found)]) + AC_MSG_RESULT([not found (pkg-config not found)]) else # # We found the package. # $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS $1[]_LIBS_STATIC=$pkg_cv_[]$1[]_LIBS_STATIC AC_MSG_RESULT([found]) $3 fi[]dnl ], [ # # The package isn't present. # AC_MSG_RESULT([not found]) ]) ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [ _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [ AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [--variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR diff --git a/config.guess b/config.guess index a419d8643b62..69188da73d74 100755 --- a/config.guess +++ b/config.guess @@ -1,1768 +1,1774 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-08-01' +timestamp='2023-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: diff --git a/config.sub b/config.sub index fbaa37f2352d..de4259e40479 100755 --- a/config.sub +++ b/config.sub @@ -1,1890 +1,1907 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-08-01' +timestamp='2023-01-21' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) + | storm-chaos* | os2-emx* | rtmk-nova* | managarm-*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ - | linux-musl* | linux-relibc* | linux-uclibc* ) + | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* ) ;; uclinux-uclibc* ) ;; - -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + managarm-mlibc* | managarm-kernel* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; + -kernel* ) + echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + *-kernel* ) + echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2 + exit 1 + ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: diff --git a/configure b/configure index 91fd1806e8a4..4f8fd5ac4a96 100755 --- a/configure +++ b/configure @@ -1,15246 +1,15246 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for pcap 1.10.3. +# Generated by GNU Autoconf 2.69 for pcap 1.10.4. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pcap' PACKAGE_TARNAME='pcap' -PACKAGE_VERSION='1.10.3' -PACKAGE_STRING='pcap 1.10.3' +PACKAGE_VERSION='1.10.4' +PACKAGE_STRING='pcap 1.10.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="pcap.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS RPCAPD_LIBS INSTALL_RPCAPD BUILD_RPCAPD PTHREAD_LIBS REMOTE_C_SRC MODULE_C_SRC PLATFORM_CXX_SRC PLATFORM_C_SRC ADDLARCHIVEOBJS ADDLOBJS RPATH V_SONAME_OPT V_SHLIB_OPT V_SHLIB_CMD V_SHLIB_CCOPT INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM PCAP_SUPPORT_RDMASNIFF LIBIBVERBS_LIBS_STATIC LIBIBVERBS_LIBS LIBIBVERBS_CFLAGS PCAP_SUPPORT_DBUS DBUS_LIBS_STATIC DBUS_LIBS DBUS_CFLAGS PCAP_SUPPORT_BT PCAP_SUPPORT_DPDK DPDK_LIBS_STATIC DPDK_LIBS DPDK_CFLAGS PCAP_SUPPORT_NETMAP PCAP_SUPPORT_NETFILTER PCAP_SUPPORT_LINUX_USBMON MKDEP DEPENDENCY_CFLAG LN_S AR RANLIB MAN_ADMIN_COMMANDS MAN_MISC_INFO MAN_FILE_FORMATS MAN_DEVICES DYEXT V_PROG_LDFLAGS_FAT V_PROG_CCOPT_FAT V_LIB_LDFLAGS_FAT V_LIB_CCOPT_FAT REENTRANT_PARSER BISON_BYACC LEXLIB LEX_OUTPUT_ROOT LEX OPENSSL_LIBS_STATIC OPENSSL_LIBS OPENSSL_CFLAGS LIBNL_LIBS_STATIC LIBNL_LIBS LIBNL_CFLAGS BREW PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG VALGRINDTEST_SRC LIBOBJS ac_ct_CXX CXXFLAGS CXX EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC SHLICC2 target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBS_PRIVATE REQUIRES_PRIVATE LIBS_STATIC V_INCLS V_DEFS V_CCOPT target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_gcc enable_largefile enable_protochain with_pcap with_libnl enable_ipv6 with_dag with_dag_includes with_dag_libraries with_septel with_snf with_snf_includes with_snf_libraries with_turbocap enable_remote enable_optimizer_dbg enable_yydebug enable_universal enable_shared enable_usb enable_netmap with_dpdk enable_bluetooth enable_dbus enable_rdma ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBNL_CFLAGS LIBNL_LIBS LIBNL_LIBS_STATIC OPENSSL_CFLAGS OPENSSL_LIBS OPENSSL_LIBS_STATIC DPDK_CFLAGS DPDK_LIBS DPDK_LIBS_STATIC DBUS_CFLAGS DBUS_LIBS DBUS_LIBS_STATIC LIBIBVERBS_CFLAGS LIBIBVERBS_LIBS LIBIBVERBS_LIBS_STATIC' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pcap 1.10.3 to adapt to many kinds of systems. +\`configure' configures pcap 1.10.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/pcap] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pcap 1.10.3:";; + short | recursive ) echo "Configuration of pcap 1.10.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-largefile omit support for large files --disable-protochain disable \"protochain\" insn --enable-ipv6 build IPv6-capable version [default=yes] --enable-remote enable remote packet capture [default=no] --enable-optimizer-dbg build optimizer debugging code --enable-yydebug build parser debugging code --disable-universal don't build universal on macOS --enable-shared build shared libraries [default=yes, if support available] --enable-usb enable Linux usbmon USB capture support [default=yes, if support available] --enable-netmap enable netmap support [default=yes, if support available] --enable-bluetooth enable Bluetooth support [default=yes, if support available] --enable-dbus enable D-Bus capture support [default=yes, if support available] --enable-rdma enable RDMA capture support [default=yes, if support available] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-gcc don't use gcc --with-pcap=TYPE use packet capture TYPE --without-libnl disable libnl support [default=yes, on Linux, if present] --with-dag[=DIR] include Endace DAG support (located in directory DIR, if supplied). [default=yes, if present] --with-dag-includes=IDIR Endace DAG include directory, if not DIR/include --with-dag-libraries=LDIR Endace DAG library directory, if not DIR/lib --with-septel[=DIR] include Septel support (located in directory DIR, if supplied). [default=yes, if present] --with-snf[=DIR] include Myricom SNF support (located in directory DIR, if supplied). [default=yes, if present] --with-snf-includes=IDIR Myricom SNF include directory, if not DIR/include --with-snf-libraries=LDIR Myricom SNF library directory, if not DIR/lib --with-turbocap[=DIR] include Riverbed TurboCap support (located in directory DIR, if supplied). [default=yes, if present] --with-dpdk[=DIR] include DPDK support (located in directory DIR, if supplied). [default=yes, if present] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBNL_CFLAGS C compiler flags for libnl-genl-3.0, overriding pkg-config LIBNL_LIBS linker flags for libnl-genl-3.0, overriding pkg-config LIBNL_LIBS_STATIC static-link linker flags for libnl-genl-3.0, overriding pkg-config OPENSSL_CFLAGS C compiler flags for openssl, overriding pkg-config OPENSSL_LIBS linker flags for openssl, overriding pkg-config OPENSSL_LIBS_STATIC static-link linker flags for openssl, overriding pkg-config DPDK_CFLAGS C compiler flags for libdpdk, overriding pkg-config DPDK_LIBS linker flags for libdpdk, overriding pkg-config DPDK_LIBS_STATIC static-link linker flags for libdpdk, overriding pkg-config DBUS_CFLAGS C compiler flags for dbus-1, overriding pkg-config DBUS_LIBS linker flags for dbus-1, overriding pkg-config DBUS_LIBS_STATIC static-link linker flags for dbus-1, overriding pkg-config LIBIBVERBS_CFLAGS C compiler flags for libibverbs, overriding pkg-config LIBIBVERBS_LIBS linker flags for libibverbs, overriding pkg-config LIBIBVERBS_LIBS_STATIC static-link linker flags for libibverbs, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pcap configure 1.10.3 +pcap configure 1.10.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_cxx_compute_int LINENO EXPR VAR INCLUDES # ---------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_cxx_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pcap $as_me 1.10.3, which was +It was created by pcap $as_me 1.10.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # # These are the variables that are used in Makefile, pcap-config, and # libpcap.pc. # # CFLAGS: inherited from the environment, not modified by us (except # temporarily during tests that involve compilation). Used only when # compiling C source. # # CXXFLAGS: inherited from the environment, not modified by us. Used only # when compiling C++ source. # # LDFLAGS: inherited from the environment, not modified by us. # # LIBS: inherited from the environment; we add libraries required by # libpcap. Librares that the core libpcap code requires are added # first; libraries required by additional pcap modules are first # added to ADDITIONAL_LIBS, and only added to LIBS at the end, after # we're finished doing configuration tests for the modules. # # LIBS_STATIC: libraries with which a program using the libpcap *static* # library needs to be linked. This is a superset of LIBS, used in # pcap-config, so that "pcap-config --libs --static" will report them. # Initialized to LIBS. # # REQUIRES_PRIVATE: pkg-config package names for additional libraries # with which a program using the libpcap *static* library needs to be # linked and for which a .pc file exists. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them, and so that # those libraries will be determined using the library's .pc file, not # from our .pc file. Initialized to an empty string. # # V_CCOPT: additional compiler flags other than -I and -D flags # needed when compiling libpcap. Used in Makefile for both C and # C++ source. # # V_DEFS: additional -D compiler flags needed when compiling # libpcap. Used in Makefile for both C and C++ source. # # V_INCLS: additional -I compiler flags needed when compiling # libpcap. Used in Makefile for both C and C++ source. # # ADDITIONAL_LIBS: additional libraries with which the libpcap dynamic # library needs to be linked. Used in Makwfile; not used in pcap-config # or libpcap.pc, as, in all platforms on which we run, if a dynamic # library is linked with other dynamic libraries, a program using # that dynamic library doesn't have to link with those libraries - # they will be automatically loaded at run time. Initialized to an # empty string. # # ADDITIONAL_LIBS_STATIC: additional libraries with which a program # using the libpcap *static* library needs to be linked. This is used # in pcap-config, so that "pcap-config --libs --static" will report # them. Initialized to an empty string. # # REQUIRES_PRIVATE: pkg-config package names for additional libraries # with which a program using the libpcap *static* library needs to be # linked and for which a .pc file exists. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them, and so that # those libraries will be determined using the library's .pc file, not # from our .pc file. Initialized to an empty string. # # LIBS_PRIVATE: pkg-config package names for additional libraries with # which a program using the libpcap *static* library needs to be linked # and for which a .pc file does not exist. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them (those libraries # cannot be determined using the library's .pc file, as there is no such # file, so it has to come from our .pc file. Initialized to an empty # string. # LIBS_STATIC="" REQUIRES_PRIVATE="" LIBS_PRIVATE="" ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- # Check whether --with-gcc was given. if test "${with_gcc+set}" = set; then : withval=$with_gcc; fi V_CCOPT="" if test "${srcdir}" != "." ; then V_CCOPT="-I\$(srcdir)" fi if test "${CFLAGS+set}" = set; then LBL_CFLAGS="$CFLAGS" fi if test -z "$CC" ; then case "$host_os" in bsdi*) # Extract the first word of "shlicc2", so it can be a program name with args. set dummy shlicc2; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_SHLICC2+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SHLICC2"; then ac_cv_prog_SHLICC2="$SHLICC2" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_SHLICC2="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_SHLICC2" && ac_cv_prog_SHLICC2="no" fi fi SHLICC2=$ac_cv_prog_SHLICC2 if test -n "$SHLICC2"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHLICC2" >&5 $as_echo "$SHLICC2" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $SHLICC2 = yes ; then CC=shlicc2 export CC fi ;; esac fi if test -z "$CC" -a "$with_gcc" = no ; then CC=cc export CC fi # # We require C99 or later. # Try to get it, which may involve adding compiler flags; # if that fails, give up. # ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : fi if test "$ac_cv_prog_cc_c99" = "no"; then as_fn_error $? "The C compiler does not support C99" "$LINENO" 5 fi # # Get the size of a void *, to determine whether this is a 32-bit # or 64-bit build. # ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : else if test "$ac_cv_type_void_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 $as_echo "$ac_cv_sizeof_void_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_VOID_P $ac_cv_sizeof_void_p _ACEOF ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" # # We only need a C++ compiler for Haiku; all code except for its # pcap module is in C. # case "$host_os" in haiku*) ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # # Make sure C and C++ have the same pointer sizes with the flags # they're given; if they don't, it means that the compilers for the # languages will, with those flags, not produce code that can be # linked together. # # We have to use different data types, because the results of # a test are cached, so if we test for the size of a given type # in C, the subsequent test in C++ will use the cached variable. # We trick autoconf by testing the size of a "void *" in C and a # "const void *" in C++. # ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of const void *" >&5 $as_echo_n "checking size of const void *... " >&6; } if ${ac_cv_sizeof_const_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (const void *))" "ac_cv_sizeof_const_void_p" "$ac_includes_default"; then : else if test "$ac_cv_type_const_void_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (const void *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_const_void_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_const_void_p" >&5 $as_echo "$ac_cv_sizeof_const_void_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_CONST_VOID_P $ac_cv_sizeof_const_void_p _ACEOF ac_lbl_cxx_sizeof_void_p="$ac_cv_sizeof_const_void_p" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$ac_lbl_cxx_sizeof_void_p" -eq 0; then as_fn_error $? "No C++ compiler was found" "$LINENO" 5 fi if test "$ac_lbl_c_sizeof_void_p" -ne "$ac_lbl_cxx_sizeof_void_p"; then as_fn_error $? "C compiler $CC produces code with $ac_lbl_c_sizeof_void_p-byte pointers while C++ compiler $CXX produces code with $ac_lbl_cxx_sizeof_void_p-byte pointers. This prevents code in those languages from being combined." "$LINENO" 5 fi ;; esac if test "$GCC" = yes ; then # # -Werror forces warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -fvisibility=hidden option" >&5 $as_echo_n "checking whether the compiler supports the -fvisibility=hidden option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 $as_echo_n "checking whether -fvisibility=hidden ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -fvisibility=hidden" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" else V_INCLS="$V_INCLS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" case "$host_os" in darwin*) # # This is assumed either to be GCC or clang, both # of which use -Werror to force warnings to be errors. # ac_lbl_cc_force_warning_errors=-Werror # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -fvisibility=hidden option" >&5 $as_echo_n "checking whether the compiler supports the -fvisibility=hidden option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 $as_echo_n "checking whether -fvisibility=hidden ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -fvisibility=hidden" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" ;; hpux*) # # HP C, which is what we presume we're using, doesn't # exit with a non-zero exit status if we hand it an # invalid -W flag, can't be forced to do so even with # +We, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes ;; irix*) # # MIPS C, which is what we presume we're using, doesn't # necessarily exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # It also, apparently, defaults to "char" being # unsigned, unlike most other C implementations; # I suppose we could say "signed char" whenever # we want to guarantee a signed "char", but let's # just force signed chars. # # -xansi is normally the default, but the # configure script was setting it; perhaps -cckr # was the default in the Old Days. (Then again, # that would probably be for backwards compatibility # in the days when ANSI C was Shiny and New, i.e. # 1989 and the early '90's, so maybe we can just # drop support for those compilers.) # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # V_CCOPT="$V_CCOPT -xansi -signed -g3" ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # # The DEC C compiler, which is what we presume we're # using, doesn't exit with a non-zero exit status if we # hand it an invalid -W flag, can't be forced to do # so, and doesn't handle GCC-style -W flags, so we # don't want to try using GCC-style -W flags. # ac_lbl_cc_dont_try_gcc_dashW=yes # # -g is equivalent to -g2, which turns off # optimization; we choose -g3, which generates # debugging information but doesn't turn off # optimization (even if the optimization would # cause inaccuracies in debugging). # V_CCOPT="$V_CCOPT -g3" ;; solaris*) # # Assumed to be Sun C, which requires -errwarn to force # warnings to be treated as errors. # ac_lbl_cc_force_warning_errors=-errwarn # # Try to have the compiler default to hiding symbols, # so that only symbols explicitly exported with # PCAP_API will be visible outside (shared) libraries. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -xldscope=hidden option" >&5 $as_echo_n "checking whether the compiler supports the -xldscope=hidden option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -xldscope=hidden" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -xldscope=hidden " >&5 $as_echo_n "checking whether -xldscope=hidden ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -xldscope=hidden" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" ;; ultrix*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking that Ultrix $CC hacks const in prototypes" >&5 $as_echo_n "checking that Ultrix $CC hacks const in prototypes... " >&6; } if ${ac_cv_lbl_cc_const_proto+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct a { int b; }; void c(const struct a *) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_lbl_cc_const_proto=yes else ac_cv_lbl_cc_const_proto=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_cc_const_proto" >&5 $as_echo "$ac_cv_lbl_cc_const_proto" >&6; } if test $ac_cv_lbl_cc_const_proto = no ; then $as_echo "#define const /**/" >>confdefs.h fi ;; esac V_CCOPT="$V_CCOPT -O" fi if test "$GCC" = yes ; then # # On platforms where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in AIX and Darwin/macOS); # # define option to set the soname of the shared library, # if the OS supports that; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" case "$host_os" in aix*) ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*) # # Platforms where the C compiler is GCC or accepts # compatible command-line arguments, and the linker # is the GNU linker or accepts compatible command-line # arguments. # # Some instruction sets require -fPIC on some # operating systems. Check for them. If you # have a combination that requires it, add it # here. # PIC_OPT=-fpic case "$host_cpu" in sparc64*) case "$host_os" in freebsd*|openbsd*|linux*) PIC_OPT=-fPIC ;; esac ;; esac V_SHLIB_CCOPT="$V_SHLIB_CCOPT $PIC_OPT" V_SONAME_OPT="-Wl,-soname," ;; hpux*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" # # XXX - this assumes GCC is using the HP linker, # rather than the GNU linker, and that the "+h" # option is used on all HP-UX platforms, both .sl # and .so. # V_SONAME_OPT="-Wl,+h," # # By default, directories specified with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; solaris*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" # # Sun/Oracle's C compiler, GCC, and GCC-compatible # compilers support -Wl,{comma-separated list of options}, # and we use the C compiler, not ld, for all linking, # including linking to produce a shared library. # V_SONAME_OPT="-Wl,-h," ;; esac else # # Set the appropriate compiler flags and, on platforms # where we build a shared library: # # add options to generate position-independent code, # if necessary (it's the default in Darwin/macOS); # # if we generate ".so" shared libraries, define the # appropriate options for building the shared library; # # add options to specify, at link time, a directory to # add to the run-time search path, if that's necessary. # # Note: spaces after V_SONAME_OPT are significant; on # some platforms the soname is passed with a GCC-like # "-Wl,-soname,{soname}" option, with the soname part # of the option, while on other platforms the C compiler # driver takes it as a regular option with the soname # following the option. # case "$host_os" in aix*) V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G -bnoentry -bexpall" ;; freebsd*|netbsd*|openbsd*|dragonfly*|linux*) # # Platforms where the C compiler is GCC or accepts # compatible command-line arguments, and the linker # is the GNU linker or accepts compatible command-line # arguments. # # XXX - does 64-bit SPARC require -fPIC? # V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-Wl,-soname," ;; hpux*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT +z" V_SHLIB_CMD="\$(LD)" V_SHLIB_OPT="-b" V_SONAME_OPT="+h " # # By default, directories specified with -L # are added to the run-time search path, so # we don't add them in pcap-config. # ;; osf*) # # Presumed to be DEC OSF/1, Digital UNIX, or # Tru64 UNIX. # V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-shared" V_SONAME_OPT="-soname " ;; solaris*) V_SHLIB_CCOPT="$V_SHLIB_CCOPT -Kpic" V_SHLIB_CMD="\$(CC)" V_SHLIB_OPT="-G" # # Sun/Oracle's C compiler, GCC, and GCC-compatible # compilers support -Wl,{comma-separated list of options}, # and we use the C compiler, not ld, for all linking, # including linking to produce a shared library. # V_SONAME_OPT="-Wl,-h," ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$V_CCOPT" if ${ac_cv_lbl_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_lbl_inline="" ac_lbl_cc_inline=no for ac_lbl_inline in inline __inline__ __inline do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define inline $ac_lbl_inline static inline struct iltest *foo(void); struct iltest { int iltest1; int iltest2; }; static inline struct iltest * foo() { static struct iltest xxx; return &xxx; } int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lbl_cc_inline=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$ac_lbl_cc_inline" = yes ; then break; fi done if test "$ac_lbl_cc_inline" = yes ; then ac_cv_lbl_inline=$ac_lbl_inline fi fi CFLAGS="$save_CFLAGS" if test ! -z "$ac_cv_lbl_inline" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_inline" >&5 $as_echo "$ac_cv_lbl_inline" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi cat >>confdefs.h <<_ACEOF #define inline $ac_cv_lbl_inline _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_load_n" >&5 $as_echo_n "checking for __atomic_load_n... " >&6; } if ${ac_cv_have___atomic_load_n+:} false; then : $as_echo_n "(cached) " >&6 else # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i = 17; int j; j = __atomic_load_n(&i, __ATOMIC_RELAXED); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_have___atomic_load_n=yes else ac_have___atomic_load_n=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_have___atomic_load_n" >&5 $as_echo "$ac_have___atomic_load_n" >&6; } if test $ac_have___atomic_load_n = yes ; then $as_echo "#define HAVE___ATOMIC_LOAD_N 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_store_n" >&5 $as_echo_n "checking for __atomic_store_n... " >&6; } if ${ac_cv_have___atomic_store_n+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; __atomic_store_n(&i, 17, __ATOMIC_RELAXED); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_have___atomic_store_n=yes else ac_have___atomic_store_n=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_have___atomic_store_n" >&5 $as_echo "$ac_have___atomic_store_n" >&6; } if test $ac_have___atomic_store_n = yes ; then $as_echo "#define HAVE___ATOMIC_STORE_N 1" >>confdefs.h fi # # Try to arrange for large file support. # # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 $as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if ${ac_cv_sys_largefile_source+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 $as_echo "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source _ACEOF ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi for ac_header in sys/ioccom.h sys/sockio.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in netpacket/packet.h do : ac_fn_c_check_header_mongrel "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" if test "x$ac_cv_header_netpacket_packet_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETPACKET_PACKET_H 1 _ACEOF fi done save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" case "$host_os" in haiku*) # # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. # CFLAGS="$CFLAGS -D_BSD_SOURCE" # # Haiku has getpass in libbsd. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpass in -lbsd" >&5 $as_echo_n "checking for getpass in -lbsd... " >&6; } if ${ac_cv_lib_bsd_getpass+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getpass (); int main () { return getpass (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_getpass=yes else ac_cv_lib_bsd_getpass=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_getpass" >&5 $as_echo "$ac_cv_lib_bsd_getpass" >&6; } if test "x$ac_cv_lib_bsd_getpass" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBSD 1 _ACEOF LIBS="-lbsd $LIBS" fi ;; esac if test "$GCC" = yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI ioctl definitions" >&5 $as_echo_n "checking for ANSI ioctl definitions... " >&6; } if ${ac_cv_lbl_gcc_fixincludes+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* * This generates a "duplicate case value" when fixincludes * has not be run. */ # include # include # include # ifdef HAVE_SYS_IOCCOM_H # include # endif int main () { switch (0) { case _IO('A', 1):; case _IO('B', 1):; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_lbl_gcc_fixincludes=yes else ac_cv_lbl_gcc_fixincludes=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_gcc_fixincludes" >&5 $as_echo "$ac_cv_lbl_gcc_fixincludes" >&6; } if test $ac_cv_lbl_gcc_fixincludes = no ; then # Don't cache failure unset ac_cv_lbl_gcc_fixincludes as_fn_error $? "see the INSTALL for more info" "$LINENO" 5 fi fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" for ac_func in strerror do : ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRERROR 1 _ACEOF fi done ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" if test "x$ac_cv_func_strerror_r" = xyes; then : # # We have strerror_r; if we define _GNU_SOURCE, is it a # POSIX-compliant strerror_r() or a GNU strerror_r()? # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r is GNU-style" >&5 $as_echo_n "checking whether strerror_r is GNU-style... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include /* Define it GNU-style; that will cause an error if it's not GNU-style */ extern char *strerror_r(int, char *, size_t); int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - # GNU-style + # GNU-style { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GNU_STRERROR_R /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define HAVE_POSIX_STRERROR_R /**/" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else # # We don't have strerror_r; do we have _wcserror_s? # for ac_func in _wcserror_s do : ac_fn_c_check_func "$LINENO" "_wcserror_s" "ac_cv_func__wcserror_s" if test "x$ac_cv_func__wcserror_s" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__WCSERROR_S 1 _ACEOF fi done fi # # Thanks, IBM, for not providing vsyslog() in AIX! # for ac_func in vsyslog do : ac_fn_c_check_func "$LINENO" "vsyslog" "ac_cv_func_vsyslog" if test "x$ac_cv_func_vsyslog" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VSYSLOG 1 _ACEOF fi done # # Make sure we have vsnprintf() and snprintf(); we require them. # ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = xyes; then : else as_fn_error $? "vsnprintf() is required but wasn't found" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes; then : else as_fn_error $? "snprintf() is required but wasn't found" "$LINENO" 5 fi needasprintf=no for ac_func in vasprintf asprintf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else needasprintf=yes fi done if test $needasprintf = yes; then case " $LIBOBJS " in *" asprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;; esac fi needstrlcat=no for ac_func in strlcat do : ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRLCAT 1 _ACEOF else needstrlcat=yes fi done if test $needstrlcat = yes; then case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac fi needstrlcpy=no for ac_func in strlcpy do : ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRLCPY 1 _ACEOF else needstrlcpy=yes fi done if test $needstrlcpy = yes; then case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac fi needstrtok_r=no for ac_func in strtok_r do : ac_fn_c_check_func "$LINENO" "strtok_r" "ac_cv_func_strtok_r" if test "x$ac_cv_func_strtok_r" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRTOK_R 1 _ACEOF else needstrtok_r=yes fi done if test $needstrtok_r = yes; then case " $LIBOBJS " in *" strtok_r.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strtok_r.$ac_objext" ;; esac fi # # Do we have ffs(), and is it declared in ? # for ac_func in ffs do : ac_fn_c_check_func "$LINENO" "ffs" "ac_cv_func_ffs" if test "x$ac_cv_func_ffs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FFS 1 _ACEOF fi done if test "$ac_cv_func_ffs" = yes; then # # We have ffs(); is it declared in ? # # This test fails if we don't have or if we do # but it doesn't declare ffs(). # ac_fn_c_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" " #include " if test "x$ac_cv_have_decl_ffs" = xyes; then : $as_echo "#define STRINGS_H_DECLARES_FFS /**/" >>confdefs.h fi fi # # Do this before checking for ether_hostton(), as it's a # "getaddrinfo()-ish function". # # # Most operating systems have getaddrinfo() in the default searched # libraries (i.e. libc). Check there first. # ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" if test "x$ac_cv_func_getaddrinfo" = xyes; then : else # # Not found in the standard system libraries. # Try libsocket, which requires libnsl. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lsocket" >&5 $as_echo_n "checking for getaddrinfo in -lsocket... " >&6; } if ${ac_cv_lib_socket_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket -lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo (); int main () { return getaddrinfo (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_getaddrinfo=yes else ac_cv_lib_socket_getaddrinfo=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_getaddrinfo" >&5 $as_echo "$ac_cv_lib_socket_getaddrinfo" >&6; } if test "x$ac_cv_lib_socket_getaddrinfo" = xyes; then : # # OK, we found it in libsocket. # LIBS="-lsocket -lnsl $LIBS" else # # Not found in libsocket; test for it in libnetwork, which # is where it is in Haiku. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lnetwork" >&5 $as_echo_n "checking for getaddrinfo in -lnetwork... " >&6; } if ${ac_cv_lib_network_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo (); int main () { return getaddrinfo (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_network_getaddrinfo=yes else ac_cv_lib_network_getaddrinfo=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_getaddrinfo" >&5 $as_echo "$ac_cv_lib_network_getaddrinfo" >&6; } if test "x$ac_cv_lib_network_getaddrinfo" = xyes; then : # # OK, we found it in libnetwork. # LIBS="-lnetwork $LIBS" else # # We didn't find it. # as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5 fi fi # # OK, do we have recvmsg() in libxnet? # We also link with libsocket and libnsl. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for recvmsg in -lxnet" >&5 $as_echo_n "checking for recvmsg in -lxnet... " >&6; } if ${ac_cv_lib_xnet_recvmsg+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lxnet -lsocket -lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char recvmsg (); int main () { return recvmsg (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_xnet_recvmsg=yes else ac_cv_lib_xnet_recvmsg=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_recvmsg" >&5 $as_echo "$ac_cv_lib_xnet_recvmsg" >&6; } if test "x$ac_cv_lib_xnet_recvmsg" = xyes; then : # # Yes - link with it as well. # LIBS="-lxnet $LIBS" fi fi # DLPI needs putmsg under HPUX so test for -lstr while we're at it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing putmsg" >&5 $as_echo_n "checking for library containing putmsg... " >&6; } if ${ac_cv_search_putmsg+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char putmsg (); int main () { return putmsg (); ; return 0; } _ACEOF for ac_lib in '' str; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_putmsg=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_putmsg+:} false; then : break fi done if ${ac_cv_search_putmsg+:} false; then : else ac_cv_search_putmsg=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_putmsg" >&5 $as_echo "$ac_cv_search_putmsg" >&6; } ac_res=$ac_cv_search_putmsg if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # # Check for reentrant versions of getnetbyname_r(), as provided by # Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). # If we don't find one, we just use getnetbyname(), which uses # thread-specific data on many platforms, but doesn't use it on # NetBSD or OpenBSD, and may not use it on older versions of other # platforms. # # Only do the check if we have a declaration of getnetbyname_r(); # without it, we can't check which API it has. (We assume that # if there's a declaration, it has a prototype, so that the API # can be checked.) # ac_fn_c_check_decl "$LINENO" "getnetbyname_r" "ac_cv_have_decl_getnetbyname_r" "#include " if test "x$ac_cv_have_decl_getnetbyname_r" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Linux getnetbyname_r()" >&5 $as_echo_n "checking for the Linux getnetbyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct netent netent_buf; char buf[1024]; struct netent *resultp; int h_errnoval; return getnetbyname_r((const char *)0, &netent_buf, buf, sizeof buf, &resultp, &h_errnoval); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LINUX_GETNETBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris/IRIX getnetbyname_r()" >&5 $as_echo_n "checking for Solaris/IRIX getnetbyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct netent netent_buf; char buf[1024]; return getnetbyname_r((const char *)0, &netent_buf, buf, (int)sizeof buf) != NULL; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SOLARIS_IRIX_GETNETBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AIX getnetbyname_r()" >&5 $as_echo_n "checking for AIX getnetbyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct netent netent_buf; struct netent_data net_data; return getnetbyname_r((const char *)0, &netent_buf, &net_data); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_AIX_GETNETBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # # Check for reentrant versions of getprotobyname_r(), as provided by # Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). # If we don't find one, we just use getprotobyname(), which uses # thread-specific data on many platforms, but doesn't use it on # NetBSD or OpenBSD, and may not use it on older versions of other # platforms. # # Only do the check if we have a declaration of getprotobyname_r(); # without it, we can't check which API it has. (We assume that # if there's a declaration, it has a prototype, so that the API # can be checked.) # ac_fn_c_check_decl "$LINENO" "getprotobyname_r" "ac_cv_have_decl_getprotobyname_r" "#include " if test "x$ac_cv_have_decl_getprotobyname_r" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Linux getprotobyname_r()" >&5 $as_echo_n "checking for the Linux getprotobyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct protoent protoent_buf; char buf[1024]; struct protoent *resultp; return getprotobyname_r((const char *)0, &protoent_buf, buf, sizeof buf, &resultp); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LINUX_GETPROTOBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris/IRIX getprotobyname_r()" >&5 $as_echo_n "checking for Solaris/IRIX getprotobyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct protoent protoent_buf; char buf[1024]; return getprotobyname_r((const char *)0, &protoent_buf, buf, (int)sizeof buf) != NULL; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AIX getprotobyname_r()" >&5 $as_echo_n "checking for AIX getprotobyname_r()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct protoent protoent_buf; struct protoent_data proto_data; return getprotobyname_r((const char *)0, &protoent_buf, &proto_data); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_AIX_GETPROTOBYNAME_R 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # # You are in a twisty little maze of UN*Xes, all different. # Some might not have ether_hostton(). # Some might have it and declare it in . # Some might have it and declare it in # Some might have it and declare it in . # Some might have it and declare it in . # Some might have it and declare it in . # Some might have it and not declare it in any header file. # # Before you is a C compiler. # for ac_func in ether_hostton do : ac_fn_c_check_func "$LINENO" "ether_hostton" "ac_cv_func_ether_hostton" if test "x$ac_cv_func_ether_hostton" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ETHER_HOSTTON 1 _ACEOF fi done if test "$ac_cv_func_ether_hostton" = yes; then # # OK, we have ether_hostton(). Is it declared in ? # # This test fails if we don't have or if we do # but it doesn't declare ether_hostton(). # ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " #include " if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : $as_echo "#define NET_ETHERNET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as on Linux? # # This test fails if we don't have # or if we do but it doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " #include " if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : $as_echo "#define NETINET_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h fi fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as on Solaris 10 # and later? # # This test fails if we don't have # or if we do but it doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " #include " if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : $as_echo "#define SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h fi fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as in AIX? # # This test fails if we don't have # (if we have ether_hostton(), we should have # networking, and if we have networking, we should # have ) or if we do but it doesn't # declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " #include " if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : $as_echo "#define ARPA_INET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h fi fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about ? # On some platforms, it requires and # , and we always include it with # both of them, so test it with both of them. # # This test fails if we don't have # and the headers we include before it, or if we do but # doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton ac_fn_c_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " #include #include #include #include #include " if test "x$ac_cv_have_decl_ether_hostton" = xyes; then : $as_echo "#define NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h fi fi # # After all that, is ether_hostton() declared? # if test "$ac_cv_have_decl_ether_hostton" = yes; then # # Yes. # $as_echo "#define HAVE_DECL_ETHER_HOSTTON 1" >>confdefs.h else # # No, we'll have to declare it ourselves. # Do we have "struct ether_addr" if we include # ? # ac_fn_c_check_type "$LINENO" "struct ether_addr" "ac_cv_type_struct_ether_addr" " #include #include #include #include #include " if test "x$ac_cv_type_struct_ether_addr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ETHER_ADDR 1 _ACEOF fi fi fi # # For various things that might use pthreads. # ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : # # OK, we have pthread.h. Do we have pthread_create in the # system libraries? # ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" if test "x$ac_cv_func_pthread_create" = xyes; then : # # Yes. # ac_lbl_have_pthreads="found" else # # No - do we have it in -lpthreads? # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } if ${ac_cv_lib_pthreads_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthreads_pthread_create=yes else ac_cv_lib_pthreads_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : # # Yes - add -lpthreads. # ac_lbl_have_pthreads="found" PTHREAD_LIBS="$PTHREAD_LIBS -lpthreads" else # # No - do we have it in -lpthread? # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : # # Yes - add -lpthread. # ac_lbl_have_pthreads="found" PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" else # # No. # ac_lbl_have_pthreads="not found" fi fi fi else # # We didn't find pthread.h. # ac_lbl_have_pthreads="not found" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if --disable-protochain option is specified" >&5 $as_echo_n "checking if --disable-protochain option is specified... " >&6; } # Check whether --enable-protochain was given. if test "${enable_protochain+set}" = set; then : enableval=$enable_protochain; fi case "x$enable_protochain" in xyes) enable_protochain=enabled ;; xno) enable_protochain=disabled ;; x) enable_protochain=enabled ;; esac if test "$enable_protochain" = "disabled"; then $as_echo "#define NO_PROTOCHAIN 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_protochain}" >&5 $as_echo "${enable_protochain}" >&6; } # # valgrindtest directly uses the native capture mechanism, but # only tests with BPF and PF_PACKET sockets; only enable it if # we have BPF or PF_PACKET sockets. # VALGRINDTEST_SRC= # Check whether --with-pcap was given. if test "${with_pcap+set}" = set; then : withval=$with_pcap; fi if test ! -z "$with_pcap" ; then V_PCAP="$withval" else # # Check for a bunch of headers for various packet # capture mechanisms. # for ac_header in net/bpf.h do : ac_fn_c_check_header_mongrel "$LINENO" "net/bpf.h" "ac_cv_header_net_bpf_h" "$ac_includes_default" if test "x$ac_cv_header_net_bpf_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_BPF_H 1 _ACEOF fi done if test "$ac_cv_header_net_bpf_h" = yes; then # # Does it define BIOCSETIF? # I.e., is it a header for an LBL/BSD-style capture # mechanism, or is it just a header for a BPF filter # engine? Some versions of Arch Linux, for example, # have a net/bpf.h that doesn't define BIOCSETIF; # as it's a Linux, it should use packet sockets, # instead. # # We need: # # sys/types.h, because FreeBSD 10's net/bpf.h # requires that various BSD-style integer types # be defined; # # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h # doesn't include it but does use struct timeval # in ioctl definitions; # # sys/ioctl.h and, if we have it, sys/ioccom.h, # because net/bpf.h defines ioctls; # # net/if.h, because it defines some structures # used in ioctls defined by net/bpf.h; # # sys/socket.h, because OpenBSD 5.9's net/bpf.h # defines some structure fields as being # struct sockaddrs; # # and net/bpf.h doesn't necessarily include all # of those headers itself. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if net/bpf.h defines BIOCSETIF" >&5 $as_echo_n "checking if net/bpf.h defines BIOCSETIF... " >&6; } if ${ac_cv_lbl_bpf_h_defines_biocsetif+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include #include int main () { u_int i = BIOCSETIF; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_lbl_bpf_h_defines_biocsetif=yes else ac_cv_lbl_bpf_h_defines_biocsetif=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_bpf_h_defines_biocsetif" >&5 $as_echo "$ac_cv_lbl_bpf_h_defines_biocsetif" >&6; } fi for ac_header in net/pfilt.h net/enet.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in net/nit.h sys/net/nit.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in linux/socket.h net/raw.h sys/dlpi.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in config/HaikuConfig.h do : ac_fn_c_check_header_mongrel "$LINENO" "config/HaikuConfig.h" "ac_cv_header_config_HaikuConfig_h" "$ac_includes_default" if test "x$ac_cv_header_config_HaikuConfig_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CONFIG_HAIKUCONFIG_H 1 _ACEOF fi done if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then # # BPF. # Check this before DLPI, so that we pick BPF on # Solaris 11 and later. # V_PCAP=bpf # # We have BPF, so build valgrindtest with "make test" # on macOS and FreeBSD (add your OS once there's a # valgrind for it). # case "$host_os" in freebsd*|darwin*|linux*) VALGRINDTEST_SRC=valgrindtest.c ;; esac elif test "$ac_cv_header_linux_socket_h" = yes; then # # No prizes for guessing this one. # V_PCAP=linux VALGRINDTEST_SRC=valgrindtest.c elif test "$ac_cv_header_net_pfilt_h" = yes; then - # - # DEC OSF/1, Digital UNIX, Tru64 UNIX - # + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # V_PCAP=pf elif test "$ac_cv_header_net_enet_h" = yes; then # # Stanford Enetfilter. # V_PCAP=enet elif test "$ac_cv_header_net_nit_h" = yes; then # # SunOS 4.x STREAMS NIT. # V_PCAP=snit elif test "$ac_cv_header_sys_net_nit_h" = yes; then # # Pre-SunOS 4.x non-STREAMS NIT. # V_PCAP=nit elif test "$ac_cv_header_net_raw_h" = yes; then # # IRIX snoop. # V_PCAP=snoop elif test "$ac_cv_header_sys_dlpi_h" = yes; then # # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. # V_PCAP=dlpi elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then # # Haiku. # V_PCAP=haiku else # # Nothing we support. # V_PCAP=null { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine packet capture interface" >&5 $as_echo "$as_me: WARNING: cannot determine packet capture interface" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: (see the INSTALL.md file for more info)" >&5 $as_echo "$as_me: WARNING: (see the INSTALL.md file for more info)" >&2;} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking packet capture type" >&5 $as_echo_n "checking packet capture type... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $V_PCAP" >&5 $as_echo "$V_PCAP" >&6; } # # Do we have pkg-config? # if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then - _pkg_min_version=0.9.0 + _pkg_min_version=0.17.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi # # Do we have the brew command from Homebrew? # # Extract the first word of "brew", so it can be a program name with args. set dummy brew; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_BREW+:} false; then : $as_echo_n "(cached) " >&6 else case $BREW in [\\/]* | ?:[\\/]*) ac_cv_path_BREW="$BREW" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_BREW="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi BREW=$ac_cv_path_BREW if test -n "$BREW"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BREW" >&5 $as_echo "$BREW" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # # Solaris pkg-config is annoying. For at least one package (D-Bus, I'm # looking at *you*!), there are separate include files for 32-bit and # 64-bit builds (I guess using "unsigned long long" as a 64-bit integer # type on a 64-bit build is like crossing the beams or soething), and # there are two separate .pc files, so if we're doing a 32-bit build we # should make sure we look in /usr/lib/pkgconfig for .pc files and if # we're doing a 64-bit build we should make sure we look in # /usr/lib/amd64/pkgconfig for .pc files. # case "$host_os" in solaris*) if test "$ac_cv_sizeof_void_p" -eq 8; then # # 64-bit build. If the path is empty, set it to # /usr/lib/amd64/pkgconfig; otherwise, if # /usr/lib/pkgconfig appears in the path, prepend # /usr/lib/amd64/pkgconfig to it; otherwise, put # /usr/lib/amd64/pkgconfig at the end. # if test -z "$PKG_CONFIG_PATH"; then # # Not set, or empty. Set it to # /usr/lib/amd64/pkgconfig. # PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then # # It contains /usr/lib/pkgconfig. Prepend # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. # PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` else # # Not empty, but doesn't contain /usr/lib/pkgconfig. # Append /usr/lib/amd64/pkgconfig to it. # PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" fi export PKG_CONFIG_PATH elif test "$ac_cv_sizeof_void_p" -eq 4; then # # 32-bit build. If /usr/amd64/lib/pkgconfig appears # in the path, prepend /usr/lib/pkgconfig to it. # if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then # # It contains /usr/lib/amd64/pkgconfig. Prepend # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. # PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` export PKG_CONFIG_PATH fi fi esac # # Handle each capture type. # case "$V_PCAP" in dlpi) # # Checks for some header files. # for ac_header in sys/bufmod.h sys/dlpi_ext.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # # Checks to see if Solaris has the public libdlpi(3LIB) library. # Note: The existence of /usr/include/libdlpi.h does not mean it is the # public libdlpi(3LIB) version. Before libdlpi was made public, a # private version also existed, which did not have the same APIs. # Due to a gcc bug, the default search path for 32-bit libraries does # not include /lib, we add it explicitly here. # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. # Also, due to the bug above applications that link to libpcap with # libdlpi will have to add "-L/lib" option to "configure". # save_LDFLAGS="$LDFLAGS" LDFLAGS="$LIBS -L/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_walk in -ldlpi" >&5 $as_echo_n "checking for dlpi_walk in -ldlpi... " >&6; } if ${ac_cv_lib_dlpi_dlpi_walk+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldlpi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlpi_walk (); int main () { return dlpi_walk (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dlpi_dlpi_walk=yes else ac_cv_lib_dlpi_dlpi_walk=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_walk" >&5 $as_echo "$ac_cv_lib_dlpi_dlpi_walk" >&6; } if test "x$ac_cv_lib_dlpi_dlpi_walk" = xyes; then : LIBS="-ldlpi $LIBS" LIBS_STATIC="-ldlpi $LIBS_STATIC" LIBS_PRIVATE="-ldlpi $LIBS_PRIVATE" V_PCAP=libdlpi # # Capture module plus common code needed for # common functions used by pcap-[dlpi,libdlpi].c # PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c" $as_echo "#define HAVE_LIBDLPI 1" >>confdefs.h else V_PCAP=dlpi # # Capture module plus common code needed for # common functions used by pcap-[dlpi,libdlpi].c # PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c" fi LDFLAGS="$save_LDFLAGS" # # Checks whether is usable, to catch weird SCO # versions of DLPI. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether is usable" >&5 $as_echo_n "checking whether is usable... " >&6; } if ${ac_cv_sys_dlpi_usable+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { int i = DL_PROMISC_PHYS; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_dlpi_usable=yes else ac_cv_sys_dlpi_usable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_dlpi_usable" >&5 $as_echo "$ac_cv_sys_dlpi_usable" >&6; } if test $ac_cv_sys_dlpi_usable = no ; then as_fn_error $? " is not usable on this system; it probably has a non-standard DLPI" "$LINENO" 5 fi # # Check to see if Solaris has the dl_passive_req_t struct defined # in . # This check is for DLPI support for passive modes. # See dlpi(7P) for more details. # ac_fn_c_check_type "$LINENO" "dl_passive_req_t" "ac_cv_type_dl_passive_req_t" " #include #include " if test "x$ac_cv_type_dl_passive_req_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DL_PASSIVE_REQ_T 1 _ACEOF fi ;; enet) # # Capture module # - PLATFORM_C_SRC="pcap-enet.c" + PLATFORM_C_SRC="pcap-enet.c" ;; haiku) # # Capture module # - PLATFORM_CXX_SRC="pcap-haiku.cpp" + PLATFORM_CXX_SRC="pcap-haiku.cpp" # # Just for the sake of it. # for ac_header in net/if.h net/if_dl.h net/if_types.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ;; linux) # # Capture module # - PLATFORM_C_SRC="pcap-linux.c" + PLATFORM_C_SRC="pcap-linux.c" # # Do we have the wireless extensions? # for ac_header in linux/wireless.h do : ac_fn_c_check_header_compile "$LINENO" "linux/wireless.h" "ac_cv_header_linux_wireless_h" " #include #include #include " if test "x$ac_cv_header_linux_wireless_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_WIRELESS_H 1 _ACEOF fi done # # Do we have libnl? # We only want version 3. Version 2 was, apparently, # short-lived, and version 1 is source and binary # incompatible with version 3, and it appears that, # these days, everybody's using version 3. We're # not supporting older versions of the Linux kernel; # let's drop support for older versions of libnl, too. # # Check whether --with-libnl was given. if test "${with_libnl+set}" = set; then : withval=$with_libnl; with_libnl=$withval else with_libnl=if_available fi if test x$with_libnl != xno ; then # # Check for libnl-genl-3.0 with pkg-config. # pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl-genl-3.0 with pkg-config" >&5 $as_echo_n "checking for libnl-genl-3.0 with pkg-config... " >&6; } if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # # The package was found, so try to get its C flags and # libraries. # if test -n "$LIBNL_CFLAGS"; then pkg_cv_LIBNL_CFLAGS="$LIBNL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNL_CFLAGS=`$PKG_CONFIG --cflags "libnl-genl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBNL_LIBS"; then pkg_cv_LIBNL_LIBS="$LIBNL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNL_LIBS=`$PKG_CONFIG --libs "libnl-genl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBNL_LIBS_STATIC"; then pkg_cv_LIBNL_LIBS_STATIC="$LIBNL_LIBS_STATIC" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNL_LIBS_STATIC=`$PKG_CONFIG --libs --static "libnl-genl-3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then # # That failed - report an error. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 $as_echo "error" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBNL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnl-genl-3.0" 2>&1` else LIBNL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnl-genl-3.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBNL_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libnl-genl-3.0) were not met: $LIBNL_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables LIBNL_CFLAGS and LIBNL_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 $as_echo "not found (pkg-config not found)" >&6; } else # # We found the package. # LIBNL_CFLAGS=$pkg_cv_LIBNL_CFLAGS LIBNL_LIBS=$pkg_cv_LIBNL_LIBS LIBNL_LIBS_STATIC=$pkg_cv_LIBNL_LIBS_STATIC { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } pkg_config_found_libnl=yes V_INCLS="$V_INCLS $LIBNL_CFLAGS" ADDITIONAL_LIBS="$LIBNL_LIBS $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="$LIBNL_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" REQUIRES_PRIVATE="libnl-genl-3.0 $REQUIRES_PRIVATE" $as_echo "#define HAVE_LIBNL 1" >>confdefs.h fi else # # The package isn't present. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi if test x$pkg_config_found_libnl != xyes; then # # OK, either we don't have pkg-config or there # wasn't a .pc file for it; Check for it directly. # case "$with_libnl" in yes|if_available) incdir=-I/usr/include/libnl3 libnldir= ;; *) if test -d $withval; then libnldir=-L${withval}/lib incdir=-I${withval}/include fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5 $as_echo_n "checking for nl_socket_alloc in -lnl-3... " >&6; } if ${ac_cv_lib_nl_3_nl_socket_alloc+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnl-3 ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nl_socket_alloc (); int main () { return nl_socket_alloc (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nl_3_nl_socket_alloc=yes else ac_cv_lib_nl_3_nl_socket_alloc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_3_nl_socket_alloc" >&5 $as_echo "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; } if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes; then : # # Yes, we have libnl 3.x. # ADDITIONAL_LIBS="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS_STATIC" LIBS_PRIVATE="${libnldir} -lnl-genl-3 -lnl-3 $LIBS_PRIVATE" $as_echo "#define HAVE_LIBNL 1" >>confdefs.h V_INCLS="$V_INCLS ${incdir}" else # # No, we don't have libnl at all. # Fail if the user explicitly requested # it. # if test x$with_libnl = xyes ; then as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5 fi fi fi fi # # Check to see if the tpacket_auxdata struct has a tp_vlan_tci member. # # NOTE: any failure means we conclude that it doesn't have that # member, so if we don't have tpacket_auxdata, we conclude it # doesn't have that member (which is OK, as either we won't be # using code that would use that member, or we wouldn't compile # in any case). ac_fn_c_check_member "$LINENO" "struct tpacket_auxdata" "tp_vlan_tci" "ac_cv_member_struct_tpacket_auxdata_tp_vlan_tci" " #include #include " if test "x$ac_cv_member_struct_tpacket_auxdata_tp_vlan_tci" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI 1 _ACEOF fi ;; bpf) # # Capture module # - PLATFORM_C_SRC="pcap-bpf.c" + PLATFORM_C_SRC="pcap-bpf.c" # # Check whether we have the *BSD-style ioctls. # for ac_header in net/if_media.h do : ac_fn_c_check_header_mongrel "$LINENO" "net/if_media.h" "ac_cv_header_net_if_media_h" "$ac_includes_default" if test "x$ac_cv_header_net_if_media_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_MEDIA_H 1 _ACEOF fi done # # Check whether we have struct BPF_TIMEVAL. # ac_fn_c_check_type "$LINENO" "struct BPF_TIMEVAL" "ac_cv_type_struct_BPF_TIMEVAL" " #include #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include " if test "x$ac_cv_type_struct_BPF_TIMEVAL" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_BPF_TIMEVAL 1 _ACEOF fi ;; pf) # # Capture module # - PLATFORM_C_SRC="pcap-pf.c" + PLATFORM_C_SRC="pcap-pf.c" ;; snit) # # Capture module # - PLATFORM_C_SRC="pcap-snit.c" + PLATFORM_C_SRC="pcap-snit.c" ;; snoop) # # Capture module # - PLATFORM_C_SRC="pcap-snoop.c" + PLATFORM_C_SRC="pcap-snoop.c" ;; dag) # # --with-pcap=dag is the only way to get here, and it means # "DAG support but nothing else" # V_DEFS="$V_DEFS -DDAG_ONLY" PLATFORM_C_SRC="pcap-dag.c" xxx_only=yes ;; dpdk) # # --with-pcap=dpdk is the only way to get here, and it means # "DPDK support but nothing else" # V_DEFS="$V_DEFS -DDPDK_ONLY" PLATFORM_C_SRC="pcap-dpdk.c" xxx_only=yes ;; septel) # # --with-pcap=septel is the only way to get here, and it means # "Septel support but nothing else" # V_DEFS="$V_DEFS -DSEPTEL_ONLY" PLATFORM_C_SRC="pcap-septel.c" xxx_only=yes ;; snf) # # --with-pcap=snf is the only way to get here, and it means # "SNF support but nothing else" # V_DEFS="$V_DEFS -DSNF_ONLY" PLATFORM_C_SRC="pcap-snf.c" xxx_only=yes ;; null) # # Capture module # - PLATFORM_C_SRC="pcap-null.c" + PLATFORM_C_SRC="pcap-null.c" ;; *) as_fn_error $? "$V_PCAP is not a valid pcap type" "$LINENO" 5 ;; esac if test "$V_PCAP" != null then ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" if test "x$ac_cv_func_getifaddrs" = xyes; then : # # We have "getifaddrs()"; make sure we have # as well, just in case some platform is really weird. # ac_fn_c_check_header_mongrel "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default" if test "x$ac_cv_header_ifaddrs_h" = xyes; then : # # We have the header, so we use "getifaddrs()" to # get the list of interfaces. # PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c" else # # We don't have the header - give up. # XXX - we could also fall back on some other # mechanism, but, for now, this'll catch this # problem so that we can at least try to figure # out something to do on systems with "getifaddrs()" # but without "ifaddrs.h", if there is something # we can do on those systems. # as_fn_error $? "Your system has getifaddrs() but doesn't have a usable ." "$LINENO" 5 fi else # # Well, we don't have "getifaddrs()", at least not with the # libraries with which we've decided we need to link # libpcap with, so we have to use some other mechanism. # # Note that this may happen on Solaris, which has # getifaddrs(), but in -lsocket, not in -lxnet, so we # won't find it if we link with -lxnet, which we want # to do for other reasons. # # For now, we use either the SIOCGIFCONF ioctl or the # SIOCGLIFCONF ioctl, preferring the latter if we have # it; the latter is a Solarisism that first appeared # in Solaris 8. (Solaris's getifaddrs() appears to # be built atop SIOCGLIFCONF; using it directly # avoids a not-all-that-useful middleman.) # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have SIOCGLIFCONF" >&5 $as_echo_n "checking whether we have SIOCGLIFCONF... " >&6; } if ${ac_cv_lbl_have_siocglifconf+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include int main () { ioctl(0, SIOCGLIFCONF, (char *)0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_lbl_have_siocglifconf=yes else ac_cv_lbl_have_siocglifconf=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_have_siocglifconf" >&5 $as_echo "$ac_cv_lbl_have_siocglifconf" >&6; } if test $ac_cv_lbl_have_siocglifconf = yes ; then PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c" else PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c" fi fi fi case "$host_os" in linux*) for ac_header in linux/net_tstamp.h do : ac_fn_c_check_header_mongrel "$LINENO" "linux/net_tstamp.h" "ac_cv_header_linux_net_tstamp_h" "$ac_includes_default" if test "x$ac_cv_header_linux_net_tstamp_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NET_TSTAMP_H 1 _ACEOF fi done ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: no hardware timestamp support implemented for $host_os" >&5 $as_echo "$as_me: no hardware timestamp support implemented for $host_os" >&6;} ;; esac # # Check for socklen_t. # ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " #include #include " if test "x$ac_cv_type_socklen_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SOCKLEN_T 1 _ACEOF fi # Check whether --enable-ipv6 was given. if test "${enable_ipv6+set}" = set; then : enableval=$enable_ipv6; else enable_ipv6=yes fi if test "$enable_ipv6" != "no"; then # # We've already made sure we have getaddrinfo above in # AC_LBL_LIBRARY_NET. # $as_echo "#define INET6 1" >>confdefs.h fi # Check for Endace DAG card support. # Check whether --with-dag was given. if test "${with_dag+set}" = set; then : withval=$with_dag; if test "$withval" = no then # User doesn't want DAG support. want_dag=no elif test "$withval" = yes then # User wants DAG support but hasn't specified a directory. want_dag=yes else # User wants DAG support and has specified a directory, so use the provided value. want_dag=yes dag_root=$withval fi else if test "$V_PCAP" = dag; then # User requested DAG-only libpcap, so we'd better have # the DAG API. want_dag=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want DAG support. want_dag=no else # # Use DAG API if present, otherwise don't # want_dag=ifpresent fi fi # Check whether --with-dag-includes was given. if test "${with_dag_includes+set}" = set; then : withval=$with_dag_includes; # User wants DAG support and has specified a header directory, so use the provided value. want_dag=yes dag_include_dir=$withval fi # Check whether --with-dag-libraries was given. if test "${with_dag_libraries+set}" = set; then : withval=$with_dag_libraries; # User wants DAG support and has specified a library directory, so use the provided value. want_dag=yes dag_lib_dir=$withval fi if test "$want_dag" != no; then # If necessary, set default paths for DAG API headers and libraries. if test -z "$dag_root"; then dag_root=/usr/local fi if test -z "$dag_include_dir"; then dag_include_dir="$dag_root/include" fi if test -z "$dag_lib_dir"; then dag_lib_dir="$dag_root/lib" # # Handle multiarch systems. # if test -d "$dag_lib_dir/$host" then dag_lib_dir="$dag_lib_dir/$host" fi fi save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS -I$dag_include_dir" for ac_header in dagapi.h do : ac_fn_c_check_header_mongrel "$LINENO" "dagapi.h" "ac_cv_header_dagapi_h" "$ac_includes_default" if test "x$ac_cv_header_dagapi_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DAGAPI_H 1 _ACEOF fi done CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" if test "$ac_cv_header_dagapi_h" = yes; then V_INCLS="$V_INCLS -I$dag_include_dir" if test $V_PCAP != dag ; then MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c" fi # Check for various DAG API functions. # Don't need to save and restore LIBS to prevent -ldag being # included if there's a found-action (arg 3). save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" LDFLAGS="-L$dag_lib_dir" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream in -ldag" >&5 $as_echo_n "checking for dag_attach_stream in -ldag... " >&6; } if ${ac_cv_lib_dag_dag_attach_stream+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dag_attach_stream (); int main () { return dag_attach_stream (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dag_dag_attach_stream=yes else ac_cv_lib_dag_dag_attach_stream=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_attach_stream" >&5 $as_echo "$ac_cv_lib_dag_dag_attach_stream" >&6; } if test "x$ac_cv_lib_dag_dag_attach_stream" = xyes; then : # # We assume that if we have libdag we have # libdagconf, as they're installed at the # same time from the same package. # ADDITIONAL_LIBS="-L$dag_lib_dir $ADDITIONAL_LIBS -ldag -ldagconf" ADDITIONAL_LIBS_STATIC="-L$dag_lib_dir $ADDITIONAL_LIBS_STATIC -ldag -ldagconf" LIBS_PRIVATE="-L$dag_lib_dir $LIBS_PRIVATE -ldag -ldagconf" else as_fn_error $? "DAG library lacks streams support" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream64 in -ldag" >&5 $as_echo_n "checking for dag_attach_stream64 in -ldag... " >&6; } if ${ac_cv_lib_dag_dag_attach_stream64+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dag_attach_stream64 (); int main () { return dag_attach_stream64 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dag_dag_attach_stream64=yes else ac_cv_lib_dag_dag_attach_stream64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_attach_stream64" >&5 $as_echo "$ac_cv_lib_dag_dag_attach_stream64" >&6; } if test "x$ac_cv_lib_dag_dag_attach_stream64" = xyes; then : dag_large_streams="1" else dag_large_streams="0" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_get_erf_types in -ldag" >&5 $as_echo_n "checking for dag_get_erf_types in -ldag... " >&6; } if ${ac_cv_lib_dag_dag_get_erf_types+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dag_get_erf_types (); int main () { return dag_get_erf_types (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dag_dag_get_erf_types=yes else ac_cv_lib_dag_dag_get_erf_types=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_erf_types" >&5 $as_echo "$ac_cv_lib_dag_dag_get_erf_types" >&6; } if test "x$ac_cv_lib_dag_dag_get_erf_types" = xyes; then : $as_echo "#define HAVE_DAG_GET_ERF_TYPES 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_get_stream_erf_types in -ldag" >&5 $as_echo_n "checking for dag_get_stream_erf_types in -ldag... " >&6; } if ${ac_cv_lib_dag_dag_get_stream_erf_types+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dag_get_stream_erf_types (); int main () { return dag_get_stream_erf_types (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dag_dag_get_stream_erf_types=yes else ac_cv_lib_dag_dag_get_stream_erf_types=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_stream_erf_types" >&5 $as_echo "$ac_cv_lib_dag_dag_get_stream_erf_types" >&6; } if test "x$ac_cv_lib_dag_dag_get_stream_erf_types" = xyes; then : $as_echo "#define HAVE_DAG_GET_STREAM_ERF_TYPES 1" >>confdefs.h fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" # # We assume that if we have libdag we have libdagconf, # as they're installed at the same time from the same # package. # if test "$dag_large_streams" = 1; then $as_echo "#define HAVE_DAG_LARGE_STREAMS_API 1" >>confdefs.h save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" LIBS="$LIBS -ldag -ldagconf" LDFLAGS="$LDFLAGS -L$dag_lib_dir" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vdag_set_device_info in -lvdag" >&5 $as_echo_n "checking for vdag_set_device_info in -lvdag... " >&6; } if ${ac_cv_lib_vdag_vdag_set_device_info+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lvdag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char vdag_set_device_info (); int main () { return vdag_set_device_info (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_vdag_vdag_set_device_info=yes else ac_cv_lib_vdag_vdag_set_device_info=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vdag_vdag_set_device_info" >&5 $as_echo "$ac_cv_lib_vdag_vdag_set_device_info" >&6; } if test "x$ac_cv_lib_vdag_vdag_set_device_info" = xyes; then : ac_dag_have_vdag="1" else ac_dag_have_vdag="0" fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" if test "$ac_dag_have_vdag" = 1; then $as_echo "#define HAVE_DAG_VDAG 1" >>confdefs.h if test "$ac_lbl_have_pthreads" != "found"; then as_fn_error $? "DAG requires pthreads, but we didn't find them" "$LINENO" 5 fi ADDITIONAL_LIBS="$ADDITIONAL_LIBS $PTHREAD_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $PTHREAD_LIBS" LIBS_PRIVATE="$LIBS_PRIVATE $PTHREAD_LIBS" fi fi $as_echo "#define HAVE_DAG_API 1" >>confdefs.h else if test "$V_PCAP" = dag; then # User requested "dag" capture type but we couldn't # find the DAG API support. as_fn_error $? "DAG support requested with --with-pcap=dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5 fi if test "$want_dag" = yes; then # User wanted DAG support but we couldn't find it. as_fn_error $? "DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5 fi fi CFLAGS="$save_CFLAGS" fi # Check whether --with-septel was given. if test "${with_septel+set}" = set; then : withval=$with_septel; if test "$withval" = no then want_septel=no elif test "$withval" = yes then want_septel=yes septel_root= else want_septel=yes septel_root=$withval fi else if test "$V_PCAP" = septel; then # User requested Septel-only libpcap, so we'd better have # the Septel API. want_septel=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Septel support. want_septel=no else # # Use Septel API if present, otherwise don't # want_septel=ifpresent fi fi ac_cv_lbl_septel_api=no if test "$with_septel" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have Septel API headers" >&5 $as_echo_n "checking whether we have Septel API headers... " >&6; } # If necessary, set default paths for Septel API headers and libraries. if test -z "$septel_root"; then septel_root=$srcdir/../septel fi septel_tools_dir="$septel_root" septel_include_dir="$septel_root/INC" if test -r "$septel_include_dir/msg.h"; then ac_cv_lbl_septel_api=yes fi if test "$ac_cv_lbl_septel_api" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($septel_include_dir)" >&5 $as_echo "yes ($septel_include_dir)" >&6; } V_INCLS="$V_INCLS -I$septel_include_dir" ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" if test "$V_PCAP" != septel ; then MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c" fi $as_echo "#define HAVE_SEPTEL_API 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "$V_PCAP" = septel; then # User requested "septel" capture type but # we couldn't find the Septel API support. as_fn_error $? "Septel support requested with --with-pcap=septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5 fi if test "$want_septel" = yes; then # User wanted Septel support but we couldn't find it. as_fn_error $? "Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5 fi fi fi # Check for Myricom SNF support. # Check whether --with-snf was given. if test "${with_snf+set}" = set; then : withval=$with_snf; if test "$withval" = no then # User explicitly doesn't want SNF want_snf=no elif test "$withval" = yes then # User wants SNF support but hasn't specified a directory. want_snf=yes else # User wants SNF support with a specified directory. want_snf=yes snf_root=$withval fi else if test "$V_PCAP" = snf; then # User requested Sniffer-only libpcap, so we'd better have # the Sniffer API. want_snf=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want SNF support. want_snf=no else # # Use Sniffer API if present, otherwise don't # want_snf=ifpresent fi fi # Check whether --with-snf-includes was given. if test "${with_snf_includes+set}" = set; then : withval=$with_snf_includes; # User wants SNF with specific header directory want_snf=yes snf_include_dir=$withval fi # Check whether --with-snf-libraries was given. if test "${with_snf_libraries+set}" = set; then : withval=$with_snf_libraries; # User wants SNF with specific lib directory want_snf=yes snf_lib_dir=$withval fi ac_cv_lbl_snf_api=no if test "$with_snf" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have Myricom Sniffer API" >&5 $as_echo_n "checking whether we have Myricom Sniffer API... " >&6; } # If necessary, set default paths for Sniffer headers and libraries. if test -z "$snf_root"; then snf_root=/opt/snf fi if test -z "$snf_include_dir"; then snf_include_dir="$snf_root/include" fi if test -z "$snf_lib_dir"; then snf_lib_dir="$snf_root/lib" # # Handle multiarch systems. # if test -d "$snf_lib_dir/$host" then snf_lib_dir="$snf_lib_dir/$host" fi fi if test -f "$snf_include_dir/snf.h"; then # We found a header; make sure we can link with the library save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -L$snf_lib_dir" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snf_init in -lsnf" >&5 $as_echo_n "checking for snf_init in -lsnf... " >&6; } if ${ac_cv_lib_snf_snf_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsnf $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char snf_init (); int main () { return snf_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_snf_snf_init=yes else ac_cv_lib_snf_snf_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_snf_snf_init" >&5 $as_echo "$ac_cv_lib_snf_snf_init" >&6; } if test "x$ac_cv_lib_snf_snf_init" = xyes; then : ac_cv_lbl_snf_api="yes" fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" if test "$ac_cv_lbl_snf_api" = no; then as_fn_error $? "SNF API cannot correctly be linked; check config.log" "$LINENO" 5 fi fi if test "$ac_cv_lbl_snf_api" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($snf_root)" >&5 $as_echo "yes ($snf_root)" >&6; } V_INCLS="$V_INCLS -I$snf_include_dir" ADDITIONAL_LIBS="$ADDITIONAL_LIBS -L$snf_lib_dir -lsnf" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC -L$snf_lib_dir -lsnf" LIBS_PRIVATE="$LIBS_PRIVATE -L$snf_lib_dir -lsnf" if test "$V_PCAP" != snf ; then MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c" fi $as_echo "#define HAVE_SNF_API 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "$want_snf" = yes; then # User requested "snf" capture type but # we couldn't find the Sniffer API support. as_fn_error $? "Myricom Sniffer support requested with --with-pcap=snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support" "$LINENO" 5 fi if test "$want_snf" = yes; then as_fn_error $? "Myricom Sniffer support requested with --with-snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support" "$LINENO" 5 fi fi fi # Check for Riverbed TurboCap support. # Check whether --with-turbocap was given. if test "${with_turbocap+set}" = set; then : withval=$with_turbocap; if test "$withval" = no then # User explicitly doesn't want TurboCap want_turbocap=no elif test "$withval" = yes then # User wants TurboCap support but hasn't specified a directory. want_turbocap=yes else # User wants TurboCap support with a specified directory. want_turbocap=yes turbocap_root=$withval fi else if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want TurboCap support. want_turbocap=no else # # Use TurboCap API if present, otherwise don't # want_turbocap=ifpresent fi fi ac_cv_lbl_turbocap_api=no if test "$want_turbocap" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether TurboCap is supported" >&5 $as_echo_n "checking whether TurboCap is supported... " >&6; } save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" if test ! -z "$turbocap_root"; then TURBOCAP_CFLAGS="-I$turbocap_root/include" TURBOCAP_LDFLAGS="-L$turbocap_root/lib" CFLAGS="$CFLAGS $TURBOCAP_CFLAGS" LDFLAGS="$LDFLAGS $TURBOCAP_LDFLAGS" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { TC_INSTANCE a; TC_PORT b; TC_BOARD c; TC_INSTANCE i; (void)TcInstanceCreateByName("foo", &i); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_lbl_turbocap_api=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" if test $ac_cv_lbl_turbocap_api = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c" V_INCLS="$V_INCLS $TURBOCAP_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" LIBS_PRIVATE="$LIBS_PRIVATE $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" $as_echo "#define HAVE_TC_API 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "$want_turbocap" = yes; then # User wanted Turbo support but we couldn't find it. as_fn_error $? "TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support" "$LINENO" 5 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable remote packet capture" >&5 $as_echo_n "checking whether to enable remote packet capture... " >&6; } # Check whether --enable-remote was given. if test "${enable_remote+set}" = set; then : enableval=$enable_remote; else enableval=no fi case "$enableval" in yes) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Remote packet capture may expose libpcap-based applications" >&5 $as_echo "$as_me: WARNING: Remote packet capture may expose libpcap-based applications" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: to attacks by malicious remote capture servers!" >&5 $as_echo "$as_me: WARNING: to attacks by malicious remote capture servers!" >&2;} # # rpcapd requires pthreads on UN*X. # if test "$ac_lbl_have_pthreads" != "found"; then as_fn_error $? "rpcapd requires pthreads, but we didn't find them" "$LINENO" 5 fi # # It also requires crypt(). # Do we have it in the system libraries? # ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt" if test "x$ac_cv_func_crypt" = xyes; then : else # # No. Do we have it in -lcrypt? # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 $as_echo_n "checking for crypt in -lcrypt... " >&6; } if ${ac_cv_lib_crypt_crypt+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char crypt (); int main () { return crypt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypt_crypt=yes else ac_cv_lib_crypt_crypt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 $as_echo "$ac_cv_lib_crypt_crypt" >&6; } if test "x$ac_cv_lib_crypt_crypt" = xyes; then : # # Yes; add -lcrypt to the libraries for rpcapd. # RPCAPD_LIBS="$RPCAPD_LIBS -lcrypt" else as_fn_error $? "rpcapd requires crypt(), but we didn't find it" "$LINENO" 5 fi fi # # OK, we have crypt(). Do we have getspnam()? # for ac_func in getspnam do : ac_fn_c_check_func "$LINENO" "getspnam" "ac_cv_func_getspnam" if test "x$ac_cv_func_getspnam" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETSPNAM 1 _ACEOF fi done # # Check for various members of struct msghdr. # ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" " #include \"ftmacros.h\" #include " if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_flags" "ac_cv_member_struct_msghdr_msg_flags" " #include \"ftmacros.h\" #include " if test "x$ac_cv_member_struct_msghdr_msg_flags" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_MSGHDR_MSG_FLAGS 1 _ACEOF fi # # Optionally, we may want to support SSL. # Check for OpenSSL/libressl. # # First, try looking for it with pkg-config, if we have it. # # Homebrew's pkg-config does not, by default, look for # pkg-config files for packages it has installed. # Furthermore, at least for OpenSSL, they appear to be # dumped in package-specific directories whose paths are # not only package-specific but package-version-specific. # # So the only way to find openssl is to get the value of # PKG_CONFIG_PATH from "brew --env openssl" and add that # to PKG_CONFIG_PATH. (No, we can't just assume it's under # /usr/local; Homebrew have conveniently chosen to put it # under /opt/homebrew on ARM.) # # That's the nice thing about Homebrew - it makes things easier! # Thanks! # save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if test -n "$BREW"; then openssl_pkgconfig_dir=`$BREW --env --plain openssl | sed -n 's/PKG_CONFIG_PATH: //p'` PKG_CONFIG_PATH="$openssl_pkgconfig_dir:$PKG_CONFIG_PATH" fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl with pkg-config" >&5 $as_echo_n "checking for openssl with pkg-config... " >&6; } if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5 ($PKG_CONFIG --exists --print-errors "openssl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # # The package was found, so try to get its C flags and # libraries. # if test -n "$OPENSSL_CFLAGS"; then pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5 ($PKG_CONFIG --exists --print-errors "openssl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_OPENSSL_CFLAGS=`$PKG_CONFIG --cflags "openssl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$OPENSSL_LIBS"; then pkg_cv_OPENSSL_LIBS="$OPENSSL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5 ($PKG_CONFIG --exists --print-errors "openssl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_OPENSSL_LIBS=`$PKG_CONFIG --libs "openssl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$OPENSSL_LIBS_STATIC"; then pkg_cv_OPENSSL_LIBS_STATIC="$OPENSSL_LIBS_STATIC" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5 ($PKG_CONFIG --exists --print-errors "openssl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_OPENSSL_LIBS_STATIC=`$PKG_CONFIG --libs --static "openssl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then # # That failed - report an error. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 $as_echo "error" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then OPENSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "openssl" 2>&1` else OPENSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "openssl" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$OPENSSL_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (openssl) were not met: $OPENSSL_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables OPENSSL_CFLAGS and OPENSSL_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 $as_echo "not found (pkg-config not found)" >&6; } else # # We found the package. # OPENSSL_CFLAGS=$pkg_cv_OPENSSL_CFLAGS OPENSSL_LIBS=$pkg_cv_OPENSSL_LIBS OPENSSL_LIBS_STATIC=$pkg_cv_OPENSSL_LIBS_STATIC { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } # # We found OpenSSL/libressl. # HAVE_OPENSSL=yes REQUIRES_PRIVATE="$REQUIRES_PRIVATE openssl" fi else # # The package isn't present. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" # # If it wasn't found, and we have Homebrew installed, see # if it's in Homebrew. # if test "x$HAVE_OPENSSL" != "xyes" -a -n "$BREW"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl in Homebrew" >&5 $as_echo_n "checking for openssl in Homebrew... " >&6; } # # The brew man page lies when it speaks of # $BREW --prefix --installed # outputting nothing. In Homebrew 3.3.16, # it produces output regardless of whether # the formula is installed or not, so we # send the standard output and error to # the bit bucket. # if $BREW --prefix --installed openssl >/dev/null 2>&1; then # # Yes. Get the include directory and library # directory. (No, we can't just assume it's # under /usr/local; Homebrew have conveniently # chosen to put it under /opt/homebrew on ARM.) # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_OPENSSL=yes openssl_path=`$BREW --prefix openssl` OPENSSL_CFLAGS="-I$openssl_path/include" OPENSSL_LIBS="-L$openssl_path/lib -lssl -lcrypto" OPENSSL_LIBS_STATIC="-L$openssl_path/lib -lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-L$openssl_path/lib -lssl -lcrypto" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # If it wasn't found, and /usr/local/include and /usr/local/lib # exist, check if it's in /usr/local. (We check whether they # exist because, if they don't exist, the compiler will warn # about that and then ignore the argument, so they test # using just the system header files and libraries.) # # We include the standard include file to 1) make sure that # it's installed (if it's just a shared library for the # benefit of existing programs, that's not useful) and 2) # because SSL_library_init() is a library routine in some # versions and a #defined wrapper around OPENSSL_init_ssl() # in others. # if test "x$HAVE_OPENSSL" != "xyes" -a -d "/usr/local/include" -a -d "/usr/local/lib"; then save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS -I/usr/local/include" LIBS="$LIBS -L/usr/local/lib -lssl -lcrypto" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have OpenSSL/libressl in /usr/local that we can use" >&5 $as_echo_n "checking whether we have OpenSSL/libressl in /usr/local that we can use... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_library_init(); return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_OPENSSL=yes OPENSSL_CFLAGS="-I/usr/local/include" OPENSSL_LIBS="-L/usr/local/lib -lssl -lcrypto" OPENSSL_LIBS_STATIC="-L/usr/local/lib -lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-L/usr/local/lib -lssl -lcrypto" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi # # If it wasn't found, check if it's a system library. # # We include the standard include file to 1) make sure that # it's installed (if it's just a shared library for the # benefit of existing programs, that's not useful) and 2) # because SSL_library_init() is a library routine in some # versions and a #defined wrapper around OPENSSL_init_ssl() # in others. # if test "x$HAVE_OPENSSL" != "xyes"; then save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" LIBS="$LIBS -lssl -lcrypto" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have a system OpenSSL/libressl that we can use" >&5 $as_echo_n "checking whether we have a system OpenSSL/libressl that we can use... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_library_init(); return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_OPENSSL=yes OPENSSL_LIBS="-lssl -lcrypto" OPENSSL_LIBS_STATIC="-lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-lssl -lcrypto" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi # # OK, did we find it? # if test "x$HAVE_OPENSSL" = "xyes"; then $as_echo "#define HAVE_OPENSSL 1" >>confdefs.h V_INCLS="$V_INCLS $OPENSSL_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $OPENSSL_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $OPENSSL_LIBS_STATIC" LIBS_PRIVATE="$LIBS_PRIVATE $OPENSSL_LIBS_PRIVATE" REQUIRES_PRIVATE="$REQUIRES_PRIVATE $OPENSSL_REQUIRES_PRIVATE" else { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL not found" >&5 $as_echo "$as_me: OpenSSL not found" >&6;} fi $as_echo "#define ENABLE_REMOTE /**/" >>confdefs.h REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c" BUILD_RPCAPD=build-rpcapd INSTALL_RPCAPD=install-rpcapd ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build optimizer debugging code" >&5 $as_echo_n "checking whether to build optimizer debugging code... " >&6; } # Check whether --enable-optimizer-dbg was given. if test "${enable_optimizer_dbg+set}" = set; then : enableval=$enable_optimizer_dbg; fi if test "$enable_optimizer_dbg" = "yes"; then $as_echo "#define BDEBUG 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_optimizer_dbg-no}" >&5 $as_echo "${enable_optimizer_dbg-no}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build parser debugging code" >&5 $as_echo_n "checking whether to build parser debugging code... " >&6; } # Check whether --enable-yydebug was given. if test "${enable_yydebug+set}" = set; then : enableval=$enable_yydebug; fi if test "$enable_yydebug" = "yes"; then $as_echo "#define YYDEBUG 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_yydebug-no}" >&5 $as_echo "${enable_yydebug-no}" >&6; } # # Look for {f}lex. # for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi if test "$LEX" = ":"; then as_fn_error $? "Neither flex nor lex was found." "$LINENO" 5 fi # # Make sure {f}lex supports the -P, --header-file, and --nounput flags # and supports processing our scanner.l. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable lex" >&5 $as_echo_n "checking for capable lex... " >&6; } if ${tcpdump_cv_capable_lex+:} false; then : $as_echo_n "(cached) " >&6 else if $LEX -P pcap_ --header-file=/dev/null --nounput -t $srcdir/scanner.l > /dev/null 2>&1; then tcpdump_cv_capable_lex=yes else tcpdump_cv_capable_lex=insufficient fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_lex" >&5 $as_echo "$tcpdump_cv_capable_lex" >&6; } if test $tcpdump_cv_capable_lex = insufficient ; then as_fn_error $? "$LEX is insufficient to compile libpcap. libpcap requires Flex 2.5.31 or later, or a compatible version of lex. If a suitable version of Lex/Flex is available as a non-standard command and/or not in the PATH, you can specify it using the LEX environment variable. That said, on some systems the error can mean that Flex/Lex is actually acceptable, but m4 is not. Likewise, if a suitable version of m4 (such as GNU M4) is available but has not been detected, you can specify it using the M4 environment variable." "$LINENO" 5 fi # # Look for yacc/bison/byacc. # If it's Bison, we do not want -y, as 1) we will be using -o to cause # the output for XXX.y to be written to XXX.c and 2) we don't want # it to issue warnings about stuff not supported by POSIX YACC - we # want to use that stuff, and don't care whether plain YACC supports # it or not, we require either Bison or Berkeley YACC. # BISON_BYACC="" # # Look for Bison. # for ac_prog in bison do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_BISON_BYACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BISON_BYACC"; then ac_cv_prog_BISON_BYACC="$BISON_BYACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_BISON_BYACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi BISON_BYACC=$ac_cv_prog_BISON_BYACC if test -n "$BISON_BYACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON_BYACC" >&5 $as_echo "$BISON_BYACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$BISON_BYACC" && break done if test x"$BISON_BYACC" != x; then # # We found Bison. # # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use # "%pure-parser". # bison_major_version=`$BISON_BYACC -V | sed -n 's/.* \([1-9][0-9]*\)\.[0-9][0-9.]*/\1/p'` bison_minor_version=`$BISON_BYACC -V | sed -n 's/.* [1-9][0-9]*\.\([0-9]+\).*/\1/p'` if test "$bison_major_version" -lt 2 -o \ \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \) then REENTRANT_PARSER="%pure-parser" else REENTRANT_PARSER="%define api.pure" fi else # # We didn't find Bison; check for Berkeley YACC, under the # names byacc and yacc. # for ac_prog in byacc yacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_BISON_BYACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BISON_BYACC"; then ac_cv_prog_BISON_BYACC="$BISON_BYACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_BISON_BYACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi BISON_BYACC=$ac_cv_prog_BISON_BYACC if test -n "$BISON_BYACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON_BYACC" >&5 $as_echo "$BISON_BYACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$BISON_BYACC" && break done if test x"$BISON_BYACC" != x; then # # Make sure this is Berkeley YACC, not AT&T YACC; # the latter doesn't support reentrant parsers. # Run it with "-V"; that succeeds and reports the # version number with Berkeley YACC, but will # (probably) fail with various vendor flavors # of AT&T YACC. # # Hopefully this also eliminates any versions # of Berkeley YACC that don't support reentrant # parsers, if there are any. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable yacc" >&5 $as_echo_n "checking for capable yacc... " >&6; } if ${tcpdump_cv_capable_yacc+:} false; then : $as_echo_n "(cached) " >&6 else if $BISON_BYACC -V >/dev/null 2>&1; then tcpdump_cv_capable_yacc=yes else tcpdump_cv_capable_yacc=insufficient fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_yacc" >&5 $as_echo "$tcpdump_cv_capable_yacc" >&6; } if test $tcpdump_cv_capable_yacc = insufficient ; then as_fn_error $? "$BISON_BYACC is insufficient to compile libpcap. libpcap requires Bison, a newer version of Berkeley YACC with support for reentrant parsers, or another YACC compatible with them." "$LINENO" 5 fi else # # OK, we found neither byacc nor yacc. # as_fn_error $? "Neither bison, byacc, nor yacc was found. libpcap requires Bison, a newer version of Berkeley YACC with support for reentrant parsers, or another YACC compatible with them." "$LINENO" 5 fi # # Berkeley YACC doesn't support "%define api.pure", so use # "%pure-parser". # REENTRANT_PARSER="%pure-parser" fi # # Do various checks for various OSes and versions of those OSes. # # Assume, by default, no support for shared libraries and V7/BSD # convention for man pages (devices in section 4, file formats in # section 5, miscellaneous info in section 7, administrative commands # and daemons in section 8). Individual cases can override this. # DYEXT="none" MAN_DEVICES=4 MAN_FILE_FORMATS=5 MAN_MISC_INFO=7 MAN_ADMIN_COMMANDS=8 case "$host_os" in aix*) $as_echo "#define _SUN 1" >>confdefs.h # # AIX makes it fun to build shared and static libraries, # because they're *both* ".a" archive libraries. We # build the static library for the benefit of the traditional # scheme of building libpcap and tcpdump in subdirectories of # the same directory, with tcpdump statically linked with the # libpcap in question, but we also build a shared library as # "libpcap.shareda" and install *it*, rather than the static # library, as "libpcap.a". # DYEXT="shareda" case "$V_PCAP" in dlpi) # # If we're using DLPI, applications will need to # use /lib/pse.exp if present, as we use the # STREAMS routines. # pseexe="/lib/pse.exp" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $pseexe" >&5 $as_echo_n "checking for $pseexe... " >&6; } if test -f $pseexe ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } LIBS="-I:$pseexe" fi ;; bpf) # # If we're using BPF, we need "-lodm" and "-lcfg", as # we use them to load the BPF module. # LIBS="-lodm -lcfg" ;; esac ;; darwin*) DYEXT="dylib" V_CCOPT="$V_CCOPT -fno-common" # Check whether --enable-universal was given. if test "${enable_universal+set}" = set; then : enableval=$enable_universal; fi if test "$enable_universal" != "no"; then case "$host_os" in darwin[0-7].*) # # Pre-Tiger. Build only for 32-bit PowerPC; no # need for any special compiler or linker flags. # ;; darwin8.[0123]|darwin8.[0123].*) # # Tiger, prior to Intel support. Build # libraries and executables for 32-bit PowerPC # and 64-bit PowerPC, with 32-bit PowerPC first. # (I'm guessing that's what Apple does.) # # (The double brackets are needed because # autotools/m4 use brackets as a quoting # character; the double brackets turn into # single brackets in the generated configure # file.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" ;; darwin8.[456]|darwin8.[456].*) # # Tiger, subsequent to Intel support but prior # to x86-64 support. Build libraries and # executables for 32-bit PowerPC, 64-bit # PowerPC, and 32-bit x86, with 32-bit PowerPC # first. (I'm guessing that's what Apple does.) # # (The double brackets are needed because # autotools/m4 use brackets as a quoting # character; the double brackets turn into # single brackets in the generated configure # file.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" ;; darwin8.*) # # All other Tiger, so subsequent to x86-64 # support. Build libraries and executables for # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, # and x86-64, with 32-bit PowerPC first. (I'm # guessing that's what Apple does.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin9.*) # # Leopard. Build libraries for 32-bit PowerPC, # 64-bit PowerPC, 32-bit x86, and x86-64, with # 32-bit PowerPC first, and build executables # for 32-bit x86 and 32-bit PowerPC, with 32-bit # x86 first. (That's what Apple does.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_CCOPT_FAT="-arch i386 -arch ppc" V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" ;; darwin10.*) # # Snow Leopard. Build libraries for x86-64, # 32-bit x86, and 32-bit PowerPC, with x86-64 # first, and build executables for x86-64 and # 32-bit x86, with x86-64 first. (That's what # Apple does, even though Snow Leopard doesn't # run on PPC, so PPC libpcap runs under Rosetta, # and Rosetta doesn't support BPF ioctls, so PPC # programs can't do live captures.) # V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" ;; darwin1[1-8]*) # # Post-Snow Leopard, pre-Catalina. Build # libraries for x86-64 and 32-bit x86, with # x86-64 first, and build executables only for # x86-64. (That's what Apple does.) This # requires no special flags for programs. # # We check whether we *can* build for i386 and, # if not, suggest that the user install the # /usr/include headers if they want to build # fat. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether building for 32-bit x86 is supported" >&5 $as_echo_n "checking whether building for 32-bit x86 is supported... " >&6; } save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS -arch i386" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" # # OpenSSL installation on macOS seems # to install only the libs for 64-bit # x86 - at least that's what Brew does: # only configure 32-bit builds if we # don't have OpenSSL. # if test "$HAVE_OPENSSL" != yes; then V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386" V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" case "$host_os" in darwin18.*) # # Mojave; you need to install the # /usr/include headers to get # 32-bit x86 builds to work. # { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&5 $as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&2;} ;; *) # # Pre-Mojave; the command-line # tools should be sufficient to # enable 32-bit x86 builds. # { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&5 $as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&2;} ;; esac fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" ;; darwin19*) # # Catalina. Build libraries and executables # only for x86-64. (That's what Apple does; # 32-bit x86 binaries are not supported on # Catalina.) # V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" V_PROG_CCOPT_FAT="-arch x86_64" V_PROG_LDFLAGS_FAT="-arch x86_64" ;; darwin*) # # Post-Catalina. Build libraries and # executables for x86-64 and ARM64. # (That's what Apple does, except they # build for arm64e, which may include # some of the pointer-checking extensions.) # # If we're building with libssl, make sure # we can build fat with it (i.e., that it # was built fat); if we can't, don't set # the target architectures, and just # build for the host we're on. # # Otherwise, just add both of them. # if test "$HAVE_OPENSSL" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether building fat with libssl is supported" >&5 $as_echo_n "checking whether building fat with libssl is supported... " >&6; } save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS -arch x86_64 -arch arm64" LDFLAGS="$LDFLAGS $OPENSSL_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_library_init(); return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" else V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" fi ;; esac fi ;; hpux9*) $as_echo "#define HAVE_HPUX9 1" >>confdefs.h # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.0*) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.1*) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux*) $as_echo "#define HAVE_HPUX10_20_OR_LATER 1" >>confdefs.h if test "`uname -m`" = "ia64"; then DYEXT="so" else DYEXT="sl" fi # # "-b" builds a shared library; "+h" sets the soname. # SHLIB_OPT="-b" SONAME_OPT="+h" # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; irix*) # # Use IRIX conventions for man pages; they're the same as the # System V conventions, except that they use section 8 for # administrative commands and daemons. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*) DYEXT="so" ;; osf*) DYEXT="so" # # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. # Use Tru64 UNIX conventions for man pages; they're the same as # the System V conventions except that they use section 8 for # administrative commands and daemons. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 MAN_DEVICES=7 ;; sinix*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if SINIX compiler defines sinix" >&5 $as_echo_n "checking if SINIX compiler defines sinix... " >&6; } if ${ac_cv_cc_sinix_defined+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i = sinix; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_cc_sinix_defined=yes else ac_cv_cc_sinix_defined=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_sinix_defined" >&5 $as_echo "$ac_cv_cc_sinix_defined" >&6; } if test $ac_cv_cc_sinix_defined = no ; then $as_echo "#define sinix 1" >>confdefs.h fi ;; solaris*) $as_echo "#define HAVE_SOLARIS 1" >>confdefs.h DYEXT="so" # # Make sure errno is thread-safe, in case we're called in # a multithreaded program. We don't guarantee that two # threads can use the *same* pcap_t safely, but the # current version does guarantee that you can use different # pcap_t's in different threads, and even that pcap_compile() # is thread-safe (it wasn't thread-safe in some older versions). # V_CCOPT="$V_CCOPT -D_TS_ERRNO" case "`uname -r`" in 5.12) ;; *) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 MAN_DEVICES=7D esac ;; esac # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; fi test "x$enable_shared" = "xno" && DYEXT="none" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi rm -f os-proto.h if test "${LBL_CFLAGS+set}" = set; then V_CCOPT="$V_CCOPT ${LBL_CFLAGS}" fi if test -f .devel ; then # # Skip all the warning option stuff on some compilers. # if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -W option" >&5 $as_echo_n "checking whether the compiler supports the -W option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -W" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -W " >&5 $as_echo_n "checking whether -W ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -W" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wall option" >&5 $as_echo_n "checking whether the compiler supports the -Wall option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wall " >&5 $as_echo_n "checking whether -Wall ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wall" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wcomma option" >&5 $as_echo_n "checking whether the compiler supports the -Wcomma option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wcomma" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wcomma " >&5 $as_echo_n "checking whether -Wcomma ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wcomma" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5 $as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wdocumentation" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdocumentation " >&5 $as_echo_n "checking whether -Wdocumentation ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wdocumentation" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wformat-nonliteral option" >&5 $as_echo_n "checking whether the compiler supports the -Wformat-nonliteral option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wformat-nonliteral" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wformat-nonliteral " >&5 $as_echo_n "checking whether -Wformat-nonliteral ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wformat-nonliteral" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5 $as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-noreturn" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-noreturn " >&5 $as_echo_n "checking whether -Wmissing-noreturn ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wmissing-noreturn" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5 $as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-prototypes" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-prototypes " >&5 $as_echo_n "checking whether -Wmissing-prototypes ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wmissing-prototypes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5 $as_echo_n "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-variable-declarations" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-variable-declarations " >&5 $as_echo_n "checking whether -Wmissing-variable-declarations ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wmissing-variable-declarations" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-arith option" >&5 $as_echo_n "checking whether the compiler supports the -Wpointer-arith option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wpointer-arith" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-arith " >&5 $as_echo_n "checking whether -Wpointer-arith ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wpointer-arith" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-sign option" >&5 $as_echo_n "checking whether the compiler supports the -Wpointer-sign option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wpointer-sign" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-sign " >&5 $as_echo_n "checking whether -Wpointer-sign ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wpointer-sign" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshadow option" >&5 $as_echo_n "checking whether the compiler supports the -Wshadow option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wshadow" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wshadow " >&5 $as_echo_n "checking whether -Wshadow ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wshadow" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wsign-compare option" >&5 $as_echo_n "checking whether the compiler supports the -Wsign-compare option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wsign-compare" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wsign-compare " >&5 $as_echo_n "checking whether -Wsign-compare ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wsign-compare" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wstrict-prototypes option" >&5 $as_echo_n "checking whether the compiler supports the -Wstrict-prototypes option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wstrict-prototypes" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wstrict-prototypes " >&5 $as_echo_n "checking whether -Wstrict-prototypes ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wstrict-prototypes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-parameter option" >&5 $as_echo_n "checking whether the compiler supports the -Wunused-parameter option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wunused-parameter" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wunused-parameter " >&5 $as_echo_n "checking whether -Wunused-parameter ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wunused-parameter" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wused-but-marked-unused option" >&5 $as_echo_n "checking whether the compiler supports the -Wused-but-marked-unused option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wused-but-marked-unused" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wused-but-marked-unused " >&5 $as_echo_n "checking whether -Wused-but-marked-unused ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wused-but-marked-unused" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" # Warns about safeguards added in case the enums are # extended # AC_LBL_CHECK_COMPILER_OPT(V_CCOPT, -Wcovered-switch-default) # # This can cause problems with ntohs(), ntohl(), # htons(), and htonl() on some platforms, such # as OpenBSD 6.3 with Clang 5.0.1. I guess the # problem is that the macro that ultimately does # the byte-swapping involves a conditional # expression that tests whether the value being # swapped is a compile-time constant or not, # using __builtin_constant_p(), and, depending # on whether it is, does a compile-time swap or # a run-time swap; perhaps the compiler always # considers one of the two results of the # conditional expressin is never evaluated, # because the conditional check is done at # compile time, and thus always says "that # expression is never executed". # # (Perhaps there should be a way of flagging # an expression that you *want* evaluated at # compile time, so that the compiler 1) warns # if it *can't* be evaluated at compile time # and 2) *doesn't* warn that the true or false # branch will never be reached.) # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunreachable-code option" >&5 $as_echo_n "checking whether the compiler supports the -Wunreachable-code option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wunreachable-code" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "xgenerates warnings from ntohs()" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wunreachable-code generates warnings from ntohs()" >&5 $as_echo_n "checking whether -Wunreachable-code generates warnings from ntohs()... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include unsigned short testme(unsigned short a) { return ntohs(a); } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wunreachable-code" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshorten-64-to-32 option" >&5 $as_echo_n "checking whether the compiler supports the -Wshorten-64-to-32 option... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wshorten-64-to-32" # # XXX - yes, this depends on the way AC_LANG_WERROR works, # but no mechanism is provided to turn AC_LANG_WERROR on # *and then turn it back off*, so that we *only* do it when # testing compiler options - 15 years after somebody asked # for it: # # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror # save_ac_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes # # We use AC_LANG_SOURCE() so that we can control the complete # content of the program being compiled. We do not, for example, # want the default "int main()" that AC_LANG_PROGRAM() generates, # as it will generate a warning with -Wold-style-definition, meaning # that we would treat it as not working, as the test will fail if # *any* error output, including a warning due to the flag we're # testing, is generated; see # # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=yes # # The compile supports this; do we have some C code for # which the warning should *not* appear? # We test the fourth argument because the third argument # could contain quotes, breaking the test. # if test "x" != "x" then CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wshorten-64-to-32 " >&5 $as_echo_n "checking whether -Wshorten-64-to-32 ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # # Not a problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else # # A problem. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" if test x"$can_add_to_cflags" = "xyes" then V_CCOPT="$V_CCOPT -Wshorten-64-to-32" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$save_CFLAGS" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag="$save_ac_c_werror_flag" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports generating dependencies" >&5 $as_echo_n "checking whether the compiler supports generating dependencies... " >&6; } if test "$GCC" = yes ; then # # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even # though it's not); we assume that, in this case, the flag # would be -M. # ac_lbl_dependency_flag="-M" else # # Not GCC or a compiler deemed to be GCC; what platform is # this? (We're assuming that if the compiler isn't GCC # it's the compiler from the vendor of the OS; that won't # necessarily be true for x86 platforms, where it might be # the Intel C compiler.) # case "$host_os" in irix*|osf*|darwin*) # # MIPS C for IRIX, DEC C, and clang all use -M. # ac_lbl_dependency_flag="-M" ;; solaris*) # # Sun C uses -xM. # ac_lbl_dependency_flag="-xM" ;; hpux*) # # HP's older C compilers don't support this. # HP's newer C compilers support this with # either +M or +Make; the older compilers # interpret +M as something completely # different, so we use +Make so we don't # think it works with the older compilers. # ac_lbl_dependency_flag="+Make" ;; *) # # Not one of the above; assume no support for # generating dependencies. # ac_lbl_dependency_flag="" ;; esac fi # # Is ac_lbl_dependency_flag defined and, if so, does the compiler # complain about it? # # Note: clang doesn't seem to exit with an error status when handed # an unknown non-warning error, even if you pass it # -Werror=unknown-warning-option. However, it always supports # -M, so the fact that this test always succeeds with clang # isn't an issue. # if test ! -z "$ac_lbl_dependency_flag"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void) { return 0; } _ACEOF if { { $as_echo "$as_me:${as_lineno-$LINENO}: eval \"\$CC \$ac_lbl_dependency_flag conftest.c >/dev/null 2>&1\""; } >&5 (eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, with $ac_lbl_dependency_flag" >&5 $as_echo "yes, with $ac_lbl_dependency_flag" >&6; } DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" MKDEP='${top_srcdir}/mkdep' else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP='${top_srcdir}/nomkdep' fi rm -rf conftest* else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } # # We can't run mkdep, so have "make depend" do # nothing. # MKDEP='${top_srcdir}/nomkdep' fi # # We used to set -n32 for IRIX 6 when not using GCC (presumed # to mean that we're using MIPS C or MIPSpro C); it specified # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm # not sure why that would be something to do *only* with a # .devel file; why should the ABI for which we produce code # depend on .devel? # os=`echo $host_os | sed -e 's/\([0-9][0-9]*\)[^0-9].*$/\1/'` name="lbl/os-$os.h" if test -f $name ; then ln -s $name os-proto.h $as_echo "#define HAVE_OS_PROTO_H 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find $name" >&5 $as_echo "$as_me: WARNING: can't find $name" >&2;} fi fi # # Check to see if the sockaddr struct has the 4.4 BSD sa_len member. # ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #include #include " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_SA_LEN 1 _ACEOF fi # # Check to see if there's a sockaddr_storage structure. # ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" " #include #include " if test "x$ac_cv_type_struct_sockaddr_storage" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_STORAGE 1 _ACEOF fi # # Check to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 # dl_module_id_1 member. # # NOTE: any failure means we conclude that it doesn't have that member, # so if we don't have DLPI, don't have a header, or # have one that doesn't declare a dl_hp_ppa_info_t type, we conclude # it doesn't have that member (which is OK, as either we won't be # using code that would use that member, or we wouldn't compile in # any case). # ac_fn_c_check_member "$LINENO" "dl_hp_ppa_info_t" "dl_module_id_1" "ac_cv_member_dl_hp_ppa_info_t_dl_module_id_1" " #include #include #include " if test "x$ac_cv_member_dl_hp_ppa_info_t_dl_module_id_1" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1 1 _ACEOF fi # # Various Linux-specific mechanisms. # # Check whether --enable-usb was given. if test "${enable_usb+set}" = set; then : enableval=$enable_usb; else enable_usb=yes fi # # If somebody requested an XXX-only pcap, that doesn't include # additional mechanisms. # if test "xxx_only" != yes; then case "$host_os" in linux*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux usbmon USB sniffing support" >&5 $as_echo_n "checking for Linux usbmon USB sniffing support... " >&6; } if test "x$enable_usb" != "xno" ; then $as_echo "#define PCAP_SUPPORT_LINUX_USBMON 1" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # # Note: if the directory for special files is *EVER* somewhere # other than the UN*X standard of /dev (which will break any # software that looks for /dev/null or /dev/tty, for example, # so doing that is *REALLY* not a good idea), please provide # some mechanism to determine that directory at *run time*, # rather than *configure time*, so that it works when doinga # a cross-build, and that works with *multiple* distributions, # with our without udev, and with multiple versions of udev, # with udevinfo or udevadm or any other mechanism to get the # special files directory. # # Do we have a version of available? # If so, we might need it for . # for ac_header in linux/compiler.h do : ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default" if test "x$ac_cv_header_linux_compiler_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_COMPILER_H 1 _ACEOF fi done if test "$ac_cv_header_linux_compiler_h" = yes; then # # Yes - include it when testing for . # for ac_header in linux/usbdevice_fs.h do : ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "#include " if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_USBDEVICE_FS_H 1 _ACEOF fi done else for ac_header in linux/usbdevice_fs.h do : ac_fn_c_check_header_mongrel "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "$ac_includes_default" if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_USBDEVICE_FS_H 1 _ACEOF fi done fi if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then # # OK, does it define bRequestType? Older versions of the kernel # define fields with names like "requesttype, "request", and # "value", rather than "bRequestType", "bRequest", and # "wValue". # ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" " $ac_includes_default #ifdef HAVE_LINUX_COMPILER_H #include #endif #include " if test "x$ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1 _ACEOF fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # # Life's too short to deal with trying to get this to compile # if you don't get the right types defined with # __KERNEL_STRICT_NAMES getting defined by some other include. # # Check whether the includes Just Work. If not, don't turn on # netfilter support. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5 $as_echo_n "checking whether we can compile the netfilter support... " >&6; } if ${ac_cv_netfilter_can_compile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include #include #include #include #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_netfilter_can_compile=yes else ac_cv_netfilter_can_compile=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5 $as_echo "$ac_cv_netfilter_can_compile" >&6; } if test $ac_cv_netfilter_can_compile = yes ; then $as_echo "#define PCAP_SUPPORT_NETFILTER 1" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c" fi ;; esac fi # Check whether --enable-netmap was given. if test "${enable_netmap+set}" = set; then : enableval=$enable_netmap; else enable_netmap=yes fi if test "x$enable_netmap" != "xno" ; then # # Check whether net/netmap_user.h is usable if NETMAP_WITH_LIBS is # defined; it's not usable on DragonFly BSD 4.6 if NETMAP_WITH_LIBS # is defined, for example, as it includes a non-existent malloc.h # header. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netmap support" >&5 $as_echo_n "checking whether we can compile the netmap support... " >&6; } if ${ac_cv_net_netmap_user_can_compile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #define NETMAP_WITH_LIBS #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_net_netmap_user_can_compile=yes else ac_cv_net_netmap_user_can_compile=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_net_netmap_user_can_compile" >&5 $as_echo "$ac_cv_net_netmap_user_can_compile" >&6; } if test $ac_cv_net_netmap_user_can_compile = yes ; then $as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c" fi fi # Check for DPDK support. # Check whether --with-dpdk was given. if test "${with_dpdk+set}" = set; then : withval=$with_dpdk; if test "$withval" = no then # User doesn't want DPDK support. want_dpdk=no elif test "$withval" = yes then # User wants DPDK support but hasn't specified a directory. want_dpdk=yes else # User wants DPDK support and has specified a directory, # so use the provided value. want_dpdk=yes dpdk_dir=$withval fi else if test "$V_PCAP" = dpdk; then # User requested DPDK-only libpcap, so we'd better have # the DPDK API. want_dpdk=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want DPDK support. want_dpdk=no else # # Use DPDK API if present, otherwise don't # want_dpdk=ifpresent fi fi if test "$want_dpdk" != no; then # # The user didn't explicitly say they don't want DPDK, # so see if we have it. # # We only try to find it using pkg-config; DPDK is *SO* # complicated - DPDK 19.02, for example, has about 117(!) # libraries, and the precise set of libraries required has # changed over time - so attempting to guess which libraries # you need, and hardcoding that in an attempt to find the # libraries without DPDK, rather than relying on DPDK to # tell you, with a .pc file, what libraries are needed, # is *EXTREMELY* fragile and has caused some bug reports, # so we're just not going to do it. # # If that causes a problem, the only thing we will do is # accept an alternative way of finding the appropriate # library set for the installed version of DPDK that is # as robust as pkg-config (i.e., it had better work as well # as pkg-config with *ALL* versions of DPDK that provide a # libdpdk.pc file). # # If --with-dpdk={path} was specified, add {path}/pkgconfig # to PKG_CONFIG_PATH, so we look for the .pc file there, # first. # save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if test -n "$dpdk_dir"; then PKG_CONFIG_PATH="$dpdk_dir:$PKG_CONFIG_PATH" fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdpdk with pkg-config" >&5 $as_echo_n "checking for libdpdk with pkg-config... " >&6; } if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # # The package was found, so try to get its C flags and # libraries. # if test -n "$DPDK_CFLAGS"; then pkg_cv_DPDK_CFLAGS="$DPDK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DPDK_CFLAGS=`$PKG_CONFIG --cflags "libdpdk" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DPDK_LIBS"; then pkg_cv_DPDK_LIBS="$DPDK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DPDK_LIBS=`$PKG_CONFIG --libs "libdpdk" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DPDK_LIBS_STATIC"; then pkg_cv_DPDK_LIBS_STATIC="$DPDK_LIBS_STATIC" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DPDK_LIBS_STATIC=`$PKG_CONFIG --libs --static "libdpdk" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then # # That failed - report an error. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 $as_echo "error" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then DPDK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdpdk" 2>&1` else DPDK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdpdk" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$DPDK_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libdpdk) were not met: $DPDK_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables DPDK_CFLAGS and DPDK_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 $as_echo "not found (pkg-config not found)" >&6; } else # # We found the package. # DPDK_CFLAGS=$pkg_cv_DPDK_CFLAGS DPDK_LIBS=$pkg_cv_DPDK_LIBS DPDK_LIBS_STATIC=$pkg_cv_DPDK_LIBS_STATIC { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } found_dpdk=yes fi else # # The package isn't present. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" # # Did we find DPDK? # if test "$found_dpdk" = yes; then # # Found it. # # We call rte_eth_dev_count_avail(), and older versions # of DPDK didn't have it, so check for it. # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS $DPDK_CFLAGS" LIBS="$LIBS $DPDK_LIBS" ac_fn_c_check_func "$LINENO" "rte_eth_dev_count_avail" "ac_cv_func_rte_eth_dev_count_avail" if test "x$ac_cv_func_rte_eth_dev_count_avail" = xyes; then : fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then # # We found a usable DPDK. # # Check whether the rte_ether.h file defines # struct ether_addr or struct rte_ether_addr. # # ("API compatibility? That's for losers!") # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS $DPDK_CFLAGS" LIBS="$LIBS $DPDK_LIBS" ac_fn_c_check_type "$LINENO" "struct rte_ether_addr" "ac_cv_type_struct_rte_ether_addr" " #include " if test "x$ac_cv_type_struct_rte_ether_addr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_RTE_ETHER_ADDR 1 _ACEOF fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" # # We can build with DPDK. # V_INCLS="$V_INCLS $DPDK_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DPDK_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DPDK_LIBS_STATIC" REQUIRES_PRIVATE="$REQUIRES_PRIVATE libdpdk" $as_echo "#define PCAP_SUPPORT_DPDK 1" >>confdefs.h if test $V_PCAP != dpdk ; then MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c" fi else # # We didn't find a usable DPDK. # If we required it (with --with-dpdk or --with-pcap=dpdk), # fail with an appropriate message telling the user what # the problem was, otherwise note the problem with a # warning. # if test "$found_dpdk" != yes; then # # Not found with pkg-config. Note that we # require that DPDK must be findable with # pkg-config. # if test "$V_PCAP" = dpdk; then # # User requested DPDK-only capture support. # as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we couldn't find DPDK with pkg-config. Make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides a .pc file." "$LINENO" 5 fi if test "$want_dpdk" = yes; then # # User requested that libpcap include # DPDK capture support. # as_fn_error $? "DPDK support requested with --with-dpdk, but we couldn't find DPDK with pkg-config. Make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides .pc file." "$LINENO" 5 fi # # User didn't indicate whether they wanted DPDK # or not; just warn why we didn't find it. # { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We couldn't find DPDK with pkg-config. If you want DPDK support, make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides a .pc file." >&5 $as_echo "$as_me: WARNING: We couldn't find DPDK with pkg-config. If you want DPDK support, make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides a .pc file." >&2;} elif test "$ac_cv_func_rte_eth_dev_count_avail" != yes; then # # Found with pkg-config, but we couldn't compile # a program that calls rte_eth_dev_count(); we # probably have the developer package installed, # but don't have a sufficiently recent version # of DPDK. Note that we need a sufficiently # recent version of DPDK. # if test "$V_PCAP" = dpdk; then # # User requested DPDK-only capture support. # as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later is installed." "$LINENO" 5 fi if test "$want_dpdk" = yes; then # # User requested that libpcap include # DPDK capture support. # as_fn_error $? "DPDK support requested with --with-dpdk, but we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later is DPDK is installed." "$LINENO" 5 fi # # User didn't indicate whether they wanted DPDK # or not; just warn why we didn't find it. # { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DPDK was found, but we can't compile libpcap with it. Make sure that DPDK 18.02.2 or later is installed." >&5 $as_echo "$as_me: WARNING: DPDK was found, but we can't compile libpcap with it. Make sure that DPDK 18.02.2 or later is installed." >&2;} fi fi fi # Check whether --enable-bluetooth was given. if test "${enable_bluetooth+set}" = set; then : enableval=$enable_bluetooth; else enable_bluetooth=ifsupportavailable fi if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Bluetooth support. enable_bluetooth=no fi if test "x$enable_bluetooth" != "xno" ; then case "$host_os" in linux*) ac_fn_c_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : # # We have bluetooth.h, so we support Bluetooth # sniffing. # $as_echo "#define PCAP_SUPPORT_BT 1" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c" { $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5 $as_echo "$as_me: Bluetooth sniffing is supported" >&6;} ac_lbl_bluetooth_available=yes # # OK, does struct sockaddr_hci have an hci_channel # member? # ac_fn_c_check_member "$LINENO" "struct sockaddr_hci" "hci_channel" "ac_cv_member_struct_sockaddr_hci_hci_channel" " #include #include " if test "x$ac_cv_member_struct_sockaddr_hci_hci_channel" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 1 _ACEOF # # Yes; is HCI_CHANNEL_MONITOR defined? # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if HCI_CHANNEL_MONITOR is defined" >&5 $as_echo_n "checking if HCI_CHANNEL_MONITOR is defined... " >&6; } if ${ac_cv_lbl_hci_channel_monitor_is_defined+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { u_int i = HCI_CHANNEL_MONITOR; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define PCAP_SUPPORT_BT_MONITOR /**/" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi fi else # # We don't have bluetooth.h, so we don't support # Bluetooth sniffing. # if test "x$enable_bluetooth" = "xyes" ; then as_fn_error $? "Bluetooth sniffing is not supported; install bluez-lib devel to enable it" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&5 $as_echo "$as_me: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&6;} fi fi ;; *) if test "x$enable_bluetooth" = "xyes" ; then as_fn_error $? "no Bluetooth sniffing support implemented for $host_os" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: no Bluetooth sniffing support implemented for $host_os" >&5 $as_echo "$as_me: no Bluetooth sniffing support implemented for $host_os" >&6;} fi ;; esac fi # Check whether --enable-dbus was given. if test "${enable_dbus+set}" = set; then : enableval=$enable_dbus; else enable_dbus=ifavailable fi if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want D-Bus support. enable_dbus=no fi if test "x$enable_dbus" != "xno"; then if test "x$enable_dbus" = "xyes"; then case "$host_os" in darwin*) # # We don't support D-Bus sniffing on macOS; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user requested it, so fail. # as_fn_error $? "Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS" "$LINENO" 5 esac else case "$host_os" in darwin*) # # We don't support D-Bus sniffing on macOS; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user dind't explicitly request it, so just # silently refuse to enable it. # enable_dbus="no" ;; esac fi fi if test "x$enable_dbus" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbus-1 with pkg-config" >&5 $as_echo_n "checking for dbus-1 with pkg-config... " >&6; } if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # # The package was found, so try to get its C flags and # libraries. # if test -n "$DBUS_CFLAGS"; then pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DBUS_LIBS"; then pkg_cv_DBUS_LIBS="$DBUS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DBUS_LIBS_STATIC"; then pkg_cv_DBUS_LIBS_STATIC="$DBUS_LIBS_STATIC" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DBUS_LIBS_STATIC=`$PKG_CONFIG --libs --static "dbus-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then # # That failed - report an error. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 $as_echo "error" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1" 2>&1` else DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$DBUS_PKG_ERRORS" >&5 if test "x$enable_dbus" = "xyes"; then as_fn_error $? "--enable-dbus was given, but the dbus-1 package is not installed" "$LINENO" 5 fi elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 $as_echo "not found (pkg-config not found)" >&6; } else # # We found the package. # DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS DBUS_LIBS=$pkg_cv_DBUS_LIBS DBUS_LIBS_STATIC=$pkg_cv_DBUS_LIBS_STATIC { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS $DBUS_CFLAGS" LIBS="$LIBS $DBUS_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the D-Bus library defines dbus_connection_read_write" >&5 $as_echo_n "checking whether the D-Bus library defines dbus_connection_read_write... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { return dbus_connection_read_write(NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define PCAP_SUPPORT_DBUS 1" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c" V_INCLS="$V_INCLS $DBUS_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DBUS_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DBUS_LIBS_STATIC" REQUIRES_PRIVATE="$REQUIRES_PRIVATE dbus-1" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "x$enable_dbus" = "xyes"; then as_fn_error $? "--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()" "$LINENO" 5 fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi else # # The package isn't present. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi fi # Check whether --enable-rdma was given. if test "${enable_rdma+set}" = set; then : enableval=$enable_rdma; else enable_rdma=ifavailable fi if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want RDMA support. enable_rdma=no fi if test "x$enable_rdma" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libibverbs with pkg-config" >&5 $as_echo_n "checking for libibverbs with pkg-config... " >&6; } if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libibverbs\""; } >&5 ($PKG_CONFIG --exists --print-errors "libibverbs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # # The package was found, so try to get its C flags and # libraries. # if test -n "$LIBIBVERBS_CFLAGS"; then pkg_cv_LIBIBVERBS_CFLAGS="$LIBIBVERBS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libibverbs\""; } >&5 ($PKG_CONFIG --exists --print-errors "libibverbs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBIBVERBS_CFLAGS=`$PKG_CONFIG --cflags "libibverbs" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBIBVERBS_LIBS"; then pkg_cv_LIBIBVERBS_LIBS="$LIBIBVERBS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libibverbs\""; } >&5 ($PKG_CONFIG --exists --print-errors "libibverbs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBIBVERBS_LIBS=`$PKG_CONFIG --libs "libibverbs" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBIBVERBS_LIBS_STATIC"; then pkg_cv_LIBIBVERBS_LIBS_STATIC="$LIBIBVERBS_LIBS_STATIC" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libibverbs\""; } >&5 ($PKG_CONFIG --exists --print-errors "libibverbs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBIBVERBS_LIBS_STATIC=`$PKG_CONFIG --libs --static "libibverbs" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then # # That failed - report an error. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 $as_echo "error" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBIBVERBS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libibverbs" 2>&1` else LIBIBVERBS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libibverbs" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBIBVERBS_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libibverbs) were not met: $LIBIBVERBS_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables LIBIBVERBS_CFLAGS and LIBIBVERBS_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then # # We don't have pkg-config, so it didn't work. # - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found (pkg-config not found)" >&5 $as_echo "not found (pkg-config not found)" >&6; } else # # We found the package. # LIBIBVERBS_CFLAGS=$pkg_cv_LIBIBVERBS_CFLAGS LIBIBVERBS_LIBS=$pkg_cv_LIBIBVERBS_LIBS LIBIBVERBS_LIBS_STATIC=$pkg_cv_LIBIBVERBS_LIBS_STATIC { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } found_libibverbs=yes LIBIBVERBS_REQUIRES_PRIVATE="libibverbs" fi else # # The package isn't present. # { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi if test "x$found_libibverbs" != "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ibv_get_device_list in -libverbs" >&5 $as_echo_n "checking for ibv_get_device_list in -libverbs... " >&6; } if ${ac_cv_lib_ibverbs_ibv_get_device_list+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-libverbs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ibv_get_device_list (); int main () { return ibv_get_device_list (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ibverbs_ibv_get_device_list=yes else ac_cv_lib_ibverbs_ibv_get_device_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ibverbs_ibv_get_device_list" >&5 $as_echo "$ac_cv_lib_ibverbs_ibv_get_device_list" >&6; } if test "x$ac_cv_lib_ibverbs_ibv_get_device_list" = xyes; then : found_libibverbs=yes LIBIBVERBS_CFLAGS="" LIBIBVERBS_LIBS="-libverbs" # XXX - at least on Ubuntu 20.04, there are many more # libraries needed; is there any platform where # libibverbs is available but where pkg-config isn't # available or libibverbs doesn't use it? If not, # we should only use pkg-config for it. LIBIBVERBS_LIBS_STATIC="-libverbs" LIBIBVERBS_LIBS_PRIVATE="-libverbs" fi fi if test "x$found_libibverbs" = "xyes"; then save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS $LIBIBVERBS_CFLAGS" LIBS="$LIBS $LIBIBVERBS_LIBS" ac_fn_c_check_header_mongrel "$LINENO" "infiniband/verbs.h" "ac_cv_header_infiniband_verbs_h" "$ac_includes_default" if test "x$ac_cv_header_infiniband_verbs_h" = xyes; then : # # ibv_create_flow may be defined as a static inline # function in infiniband/verbs.h, so we can't # use AC_CHECK_LIB. # # Too bad autoconf has no AC_SYMBOL_EXISTS() # macro that works like CMake's check_symbol_exists() # function, to check do a compile check like # this (they do a clever trick to avoid having # to know the function's signature). # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libibverbs defines ibv_create_flow" >&5 $as_echo_n "checking whether libibverbs defines ibv_create_flow... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { (void) ibv_create_flow((struct ibv_qp *) NULL, (struct ibv_flow_attr *) NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } found_usable_libibverbs=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi if test "x$found_usable_libibverbs" = "xyes" then $as_echo "#define PCAP_SUPPORT_RDMASNIFF /**/" >>confdefs.h MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c" CFLAGS="$LIBIBVERBS_CFLAGS $CFLAGS" ADDITIONAL_LIBS="$LIBIBVERBS_LIBS $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="$LIBIBVERBS_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" LIBS_PRIVATE="$LIBIBVERBS_LIBS_PRIVATE $LIBS_PRIVATE" REQUIRES_PRIVATE="$REQUIRES_PRIVATE $LIBIBVERBS_REQUIRES_PRIVATE" fi fi # # If this is a platform where we need to have the .pc file and # pcap-config script supply an rpath option to specify the directory # in which the libpcap shared library is installed, and the install # prefix /usr (meaning we're not installing a system library), provide # the rpath option. # # (We must check $prefix, as $libdir isn't necessarily /usr/lib in this # case - for example, Linux distributions for 64-bit platforms that # also provide support for binaries for a 32-bit version of the # platform may put the 64-bit libraries, the 32-bit libraries, or both # in directories other than /usr/lib.) # # In AIX, do we have to do this? # # In Darwin-based OSes, the full paths of the shared libraries with # which the program was linked are stored in the executable, so we don't # need to provide an rpath option. # # With the HP-UX linker, directories specified with -L are, by default, # added to the run-time search path, so we don't need to supply them. # # For Tru64 UNIX, "-rpath" works with DEC's^WCompaq's^WHP's C compiler # for Alpha, but isn't documented as working with GCC, and no GCC- # compatible option is documented as working with the DEC compiler. # If anybody needs this on Tru64/Alpha, they're welcome to figure out a # way to make it work. # # This must *not* depend on the compiler, as, on platforms where there's # a GCC-compatible compiler and a vendor compiler, we need to work with # both. # if test "$prefix" != "/usr"; then case "$host_os" in freebsd*|netbsd*|openbsd*|dragonfly*|linux*|haiku*|midipix*|gnu*) # # Platforms where the "native" C compiler is GCC or # accepts compatible command-line arguments, and the # "native" linker is the GNU linker or accepts # compatible command-line arguments. # RPATH="-Wl,-rpath,\${libdir}" ;; solaris*) # # Sun/Oracle's linker, the GNU linker, and # GNU-compatible linkers all support -R. # RPATH="-Wl,-R,\${libdir}" ;; esac fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_config_headers="$ac_config_headers config.h" # # We're done with configuration operations; add ADDITIONAL_LIBS and # ADDITIONAL_LIBS_STATIC to LIBS and LIBS_STATIC, respectively. # LIBS="$ADDITIONAL_LIBS $LIBS" LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $LIBS_STATIC" ac_config_commands="$ac_config_commands default-1" ac_config_files="$ac_config_files Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pcap $as_me 1.10.3, which was +This file was extended by pcap $as_me 1.10.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -pcap config.status 1.10.3 +pcap config.status 1.10.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "grammar.y") CONFIG_FILES="$CONFIG_FILES grammar.y" ;; "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;; "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;; "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;; "pcap-savefile.manfile") CONFIG_FILES="$CONFIG_FILES pcap-savefile.manfile" ;; "pcap.3pcap") CONFIG_FILES="$CONFIG_FILES pcap.3pcap" ;; "pcap_compile.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_compile.3pcap" ;; "pcap_datalink.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_datalink.3pcap" ;; "pcap_dump_open.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_dump_open.3pcap" ;; "pcap_get_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_get_tstamp_precision.3pcap" ;; "pcap_list_datalinks.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_datalinks.3pcap" ;; "pcap_list_tstamp_types.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_tstamp_types.3pcap" ;; "pcap_open_dead.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_dead.3pcap" ;; "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;; "pcap_set_immediate_mode.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_immediate_mode.3pcap" ;; "pcap_set_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_precision.3pcap" ;; "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;; "rpcapd/Makefile") CONFIG_FILES="$CONFIG_FILES rpcapd/Makefile" ;; "rpcapd/rpcapd.manadmin") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd.manadmin" ;; "rpcapd/rpcapd-config.manfile") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd-config.manfile" ;; "testprogs/Makefile") CONFIG_FILES="$CONFIG_FILES testprogs/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "default-1":C) if test -f .devel; then echo timestamp > stamp-h cat $srcdir/Makefile-devel-adds >> Makefile make depend || exit 1 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi exit 0 diff --git a/configure.ac b/configure.ac index ff7e49066fb7..ec601c8445e9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,3215 +1,3215 @@ dnl dnl Copyright (c) 1994, 1995, 1996, 1997 dnl The Regents of the University of California. All rights reserved. dnl dnl Process this file with autoconf to produce a configure script. dnl # # See # # https://ftp.gnu.org/gnu/config/README # # for the URLs to use to fetch new versions of config.guess and # config.sub. # -AC_PREREQ(2.64) +AC_PREREQ(2.69) AC_INIT(pcap, m4_esyscmd_s([cat VERSION])) AC_CONFIG_SRCDIR(pcap.c) AC_SUBST(PACKAGE_NAME) # # These are the variables that are used in Makefile, pcap-config, and # libpcap.pc. # # CFLAGS: inherited from the environment, not modified by us (except # temporarily during tests that involve compilation). Used only when # compiling C source. # # CXXFLAGS: inherited from the environment, not modified by us. Used only # when compiling C++ source. # # LDFLAGS: inherited from the environment, not modified by us. # # LIBS: inherited from the environment; we add libraries required by # libpcap. Librares that the core libpcap code requires are added # first; libraries required by additional pcap modules are first # added to ADDITIONAL_LIBS, and only added to LIBS at the end, after # we're finished doing configuration tests for the modules. # # LIBS_STATIC: libraries with which a program using the libpcap *static* # library needs to be linked. This is a superset of LIBS, used in # pcap-config, so that "pcap-config --libs --static" will report them. # Initialized to LIBS. # # REQUIRES_PRIVATE: pkg-config package names for additional libraries # with which a program using the libpcap *static* library needs to be # linked and for which a .pc file exists. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them, and so that # those libraries will be determined using the library's .pc file, not # from our .pc file. Initialized to an empty string. # # V_CCOPT: additional compiler flags other than -I and -D flags # needed when compiling libpcap. Used in Makefile for both C and # C++ source. # # V_DEFS: additional -D compiler flags needed when compiling # libpcap. Used in Makefile for both C and C++ source. # # V_INCLS: additional -I compiler flags needed when compiling # libpcap. Used in Makefile for both C and C++ source. # # ADDITIONAL_LIBS: additional libraries with which the libpcap dynamic # library needs to be linked. Used in Makwfile; not used in pcap-config # or libpcap.pc, as, in all platforms on which we run, if a dynamic # library is linked with other dynamic libraries, a program using # that dynamic library doesn't have to link with those libraries - # they will be automatically loaded at run time. Initialized to an # empty string. # # ADDITIONAL_LIBS_STATIC: additional libraries with which a program # using the libpcap *static* library needs to be linked. This is used # in pcap-config, so that "pcap-config --libs --static" will report # them. Initialized to an empty string. # # REQUIRES_PRIVATE: pkg-config package names for additional libraries # with which a program using the libpcap *static* library needs to be # linked and for which a .pc file exists. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them, and so that # those libraries will be determined using the library's .pc file, not # from our .pc file. Initialized to an empty string. # # LIBS_PRIVATE: pkg-config package names for additional libraries with # which a program using the libpcap *static* library needs to be linked # and for which a .pc file does not exist. This is used in libpcap.pc, # so that "pkg-config --libs --static" will report them (those libraries # cannot be determined using the library's .pc file, as there is no such # file, so it has to come from our .pc file. Initialized to an empty # string. # LIBS_STATIC="" REQUIRES_PRIVATE="" LIBS_PRIVATE="" AC_SUBST(V_CCOPT) AC_SUBST(V_DEFS) AC_SUBST(V_INCLS) AC_SUBST(LIBS_STATIC) AC_SUBST(REQUIRES_PRIVATE) AC_SUBST(LIBS_PRIVATE) AC_CANONICAL_SYSTEM AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS) # # We require C99 or later. # Try to get it, which may involve adding compiler flags; # if that fails, give up. # AC_PROG_CC_C99 if test "$ac_cv_prog_cc_c99" = "no"; then AC_MSG_ERROR([The C compiler does not support C99]) fi # # Get the size of a void *, to determine whether this is a 32-bit # or 64-bit build. # AC_CHECK_SIZEOF([void *]) ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" # # We only need a C++ compiler for Haiku; all code except for its # pcap module is in C. # case "$host_os" in haiku*) AC_PROG_CXX # # Make sure C and C++ have the same pointer sizes with the flags # they're given; if they don't, it means that the compilers for the # languages will, with those flags, not produce code that can be # linked together. # # We have to use different data types, because the results of # a test are cached, so if we test for the size of a given type # in C, the subsequent test in C++ will use the cached variable. # We trick autoconf by testing the size of a "void *" in C and a # "const void *" in C++. # AC_LANG_PUSH([C++]) AC_CHECK_SIZEOF([const void *]) ac_lbl_cxx_sizeof_void_p="$ac_cv_sizeof_const_void_p" AC_LANG_POP([C++]) if test "$ac_lbl_cxx_sizeof_void_p" -eq 0; then AC_MSG_ERROR([No C++ compiler was found]) fi if test "$ac_lbl_c_sizeof_void_p" -ne "$ac_lbl_cxx_sizeof_void_p"; then AC_MSG_ERROR([C compiler $CC produces code with $ac_lbl_c_sizeof_void_p-byte pointers while C++ compiler $CXX produces code with $ac_lbl_cxx_sizeof_void_p-byte pointers. This prevents code in those languages from being combined.]) fi ;; esac AC_LBL_C_INIT(V_CCOPT, V_INCLS) AC_LBL_SHLIBS_INIT AC_LBL_C_INLINE AC_PCAP_C___ATOMICS # # Try to arrange for large file support. # AC_SYS_LARGEFILE AC_FUNC_FSEEKO dnl dnl Even if were, on all OSes that support BPF, fixed to dnl include , and we were to drop support for older dnl releases without that fix, so that pcap-bpf.c doesn't need to dnl include , the test program in "AC_LBL_FIXINCLUDES" dnl in "aclocal.m4" uses it, so we would still have to test for it dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris. dnl AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h) AC_CHECK_HEADERS(netpacket/packet.h) AC_LBL_SAVE_CHECK_STATE case "$host_os" in haiku*) # # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. # CFLAGS="$CFLAGS -D_BSD_SOURCE" # # Haiku has getpass in libbsd. # AC_CHECK_LIB(bsd, getpass) ;; esac AC_LBL_FIXINCLUDES AC_LBL_RESTORE_CHECK_STATE AC_CHECK_FUNCS(strerror) AC_CHECK_FUNC(strerror_r, [ # # We have strerror_r; if we define _GNU_SOURCE, is it a # POSIX-compliant strerror_r() or a GNU strerror_r()? # AC_MSG_CHECKING(whether strerror_r is GNU-style) AC_COMPILE_IFELSE( [ AC_LANG_SOURCE( #define _GNU_SOURCE #include /* Define it GNU-style; that will cause an error if it's not GNU-style */ extern char *strerror_r(int, char *, size_t); int main(void) { return 0; } ) ], [ - # GNU-style + # GNU-style AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GNU_STRERROR_R,, [Define to 1 if you have a GNU-style `strerror_r' function.]) ], [ AC_MSG_RESULT(no) AC_DEFINE(HAVE_POSIX_STRERROR_R,, [Define to 1 if you have a POSIX-style `strerror_r' function.]) ]) ], [ # # We don't have strerror_r; do we have _wcserror_s? # AC_CHECK_FUNCS(_wcserror_s) ]) # # Thanks, IBM, for not providing vsyslog() in AIX! # AC_CHECK_FUNCS(vsyslog) # # Make sure we have vsnprintf() and snprintf(); we require them. # AC_CHECK_FUNC(vsnprintf,, AC_MSG_ERROR([vsnprintf() is required but wasn't found])) AC_CHECK_FUNC(snprintf,, AC_MSG_ERROR([snprintf() is required but wasn't found])) needasprintf=no AC_CHECK_FUNCS(vasprintf asprintf,, [needasprintf=yes]) if test $needasprintf = yes; then AC_LIBOBJ([asprintf]) fi needstrlcat=no AC_CHECK_FUNCS(strlcat,, [needstrlcat=yes]) if test $needstrlcat = yes; then AC_LIBOBJ([strlcat]) fi needstrlcpy=no AC_CHECK_FUNCS(strlcpy,, [needstrlcpy=yes]) if test $needstrlcpy = yes; then AC_LIBOBJ([strlcpy]) fi needstrtok_r=no AC_CHECK_FUNCS(strtok_r,, [needstrtok_r=yes]) if test $needstrtok_r = yes; then AC_LIBOBJ([strtok_r]) fi # # Do we have ffs(), and is it declared in ? # AC_CHECK_FUNCS(ffs) if test "$ac_cv_func_ffs" = yes; then # # We have ffs(); is it declared in ? # # This test fails if we don't have or if we do # but it doesn't declare ffs(). # AC_CHECK_DECL(ffs, [ AC_DEFINE(STRINGS_H_DECLARES_FFS,, [Define to 1 if strings.h declares `ffs']) ],, [ #include ]) fi # # Do this before checking for ether_hostton(), as it's a # "getaddrinfo()-ish function". # AC_LBL_LIBRARY_NET # # Check for reentrant versions of getnetbyname_r(), as provided by # Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). # If we don't find one, we just use getnetbyname(), which uses # thread-specific data on many platforms, but doesn't use it on # NetBSD or OpenBSD, and may not use it on older versions of other # platforms. # # Only do the check if we have a declaration of getnetbyname_r(); # without it, we can't check which API it has. (We assume that # if there's a declaration, it has a prototype, so that the API # can be checked.) # AC_CHECK_DECL(getnetbyname_r, [ AC_MSG_CHECKING([for the Linux getnetbyname_r()]) AC_TRY_LINK( [#include ], [ struct netent netent_buf; char buf[1024]; struct netent *resultp; int h_errnoval; return getnetbyname_r((const char *)0, &netent_buf, buf, sizeof buf, &resultp, &h_errnoval); ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_GETNETBYNAME_R, 1, [define if we have the Linux getnetbyname_r()]) ], [ AC_MSG_RESULT(no) AC_MSG_CHECKING([for Solaris/IRIX getnetbyname_r()]) AC_TRY_LINK( [#include ], [ struct netent netent_buf; char buf[1024]; return getnetbyname_r((const char *)0, &netent_buf, buf, (int)sizeof buf) != NULL; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SOLARIS_IRIX_GETNETBYNAME_R, 1, [define if we have the Solaris/IRIX getnetbyname_r()]) ], [ AC_MSG_RESULT(no) AC_MSG_CHECKING([for AIX getnetbyname_r()]) AC_TRY_LINK( [#include ], [ struct netent netent_buf; struct netent_data net_data; return getnetbyname_r((const char *)0, &netent_buf, &net_data); ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_AIX_GETNETBYNAME_R, 1, [define if we have the AIX getnetbyname_r()]) ], [ AC_MSG_RESULT(no) ]) ]) ]) ],,[#include ]) # # Check for reentrant versions of getprotobyname_r(), as provided by # Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). # If we don't find one, we just use getprotobyname(), which uses # thread-specific data on many platforms, but doesn't use it on # NetBSD or OpenBSD, and may not use it on older versions of other # platforms. # # Only do the check if we have a declaration of getprotobyname_r(); # without it, we can't check which API it has. (We assume that # if there's a declaration, it has a prototype, so that the API # can be checked.) # AC_CHECK_DECL(getprotobyname_r, [ AC_MSG_CHECKING([for the Linux getprotobyname_r()]) AC_TRY_LINK( [#include ], [ struct protoent protoent_buf; char buf[1024]; struct protoent *resultp; return getprotobyname_r((const char *)0, &protoent_buf, buf, sizeof buf, &resultp); ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LINUX_GETPROTOBYNAME_R, 1, [define if we have the Linux getprotobyname_r()]) ], [ AC_MSG_RESULT(no) AC_MSG_CHECKING([for Solaris/IRIX getprotobyname_r()]) AC_TRY_LINK( [#include ], [ struct protoent protoent_buf; char buf[1024]; return getprotobyname_r((const char *)0, &protoent_buf, buf, (int)sizeof buf) != NULL; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R, 1, [define if we have the Solaris/IRIX getprotobyname_r()]) ], [ AC_MSG_RESULT(no) AC_MSG_CHECKING([for AIX getprotobyname_r()]) AC_TRY_LINK( [#include ], [ struct protoent protoent_buf; struct protoent_data proto_data; return getprotobyname_r((const char *)0, &protoent_buf, &proto_data); ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_AIX_GETPROTOBYNAME_R, 1, [define if we have the AIX getprotobyname_r()]) ], [ AC_MSG_RESULT(no) ]) ]) ]) ],,[#include ]) # # You are in a twisty little maze of UN*Xes, all different. # Some might not have ether_hostton(). # Some might have it and declare it in . # Some might have it and declare it in # Some might have it and declare it in . # Some might have it and declare it in . # Some might have it and declare it in . # Some might have it and not declare it in any header file. # # Before you is a C compiler. # AC_CHECK_FUNCS(ether_hostton) if test "$ac_cv_func_ether_hostton" = yes; then # # OK, we have ether_hostton(). Is it declared in ? # # This test fails if we don't have or if we do # but it doesn't declare ether_hostton(). # AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if net/ethernet.h declares `ether_hostton']) ],, [ #include ]) # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as on Linux? # # This test fails if we don't have # or if we do but it doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if netinet/ether.h declares `ether_hostton']) ],, [ #include ]) fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as on Solaris 10 # and later? # # This test fails if we don't have # or if we do but it doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if sys/ethernet.h declares `ether_hostton']) ],, [ #include ]) fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about , as in AIX? # # This test fails if we don't have # (if we have ether_hostton(), we should have # networking, and if we have networking, we should # have ) or if we do but it doesn't # declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(ARPA_INET_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if arpa/inet.h declares `ether_hostton']) ],, [ #include ]) fi # # Did that succeed? # if test "$ac_cv_have_decl_ether_hostton" != yes; then # # No, how about ? # On some platforms, it requires and # , and we always include it with # both of them, so test it with both of them. # # This test fails if we don't have # and the headers we include before it, or if we do but # doesn't declare ether_hostton(). # # Unset ac_cv_have_decl_ether_hostton so we don't # treat the previous failure as a cached value and # suppress the next test. # unset ac_cv_have_decl_ether_hostton AC_CHECK_DECL(ether_hostton, [ AC_DEFINE(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON,, [Define to 1 if netinet/if_ether.h declares `ether_hostton']) ],, [ #include #include #include #include #include ]) fi # # After all that, is ether_hostton() declared? # if test "$ac_cv_have_decl_ether_hostton" = yes; then # # Yes. # AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 1, [Define to 1 if you have the declaration of `ether_hostton']) else # # No, we'll have to declare it ourselves. # Do we have "struct ether_addr" if we include # ? # AC_CHECK_TYPES(struct ether_addr,,, [ #include #include #include #include #include ]) fi fi # # For various things that might use pthreads. # AC_CHECK_HEADER(pthread.h, [ # # OK, we have pthread.h. Do we have pthread_create in the # system libraries? # AC_CHECK_FUNC(pthread_create, [ # # Yes. # ac_lbl_have_pthreads="found" ], [ # # No - do we have it in -lpthreads? # AC_CHECK_LIB(pthreads, pthread_create, [ # # Yes - add -lpthreads. # ac_lbl_have_pthreads="found" PTHREAD_LIBS="$PTHREAD_LIBS -lpthreads" ], [ # # No - do we have it in -lpthread? # AC_CHECK_LIB(pthread, pthread_create, [ # # Yes - add -lpthread. # ac_lbl_have_pthreads="found" PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" ], [ # # No. # ac_lbl_have_pthreads="not found" ]) ]) ]) ], [ # # We didn't find pthread.h. # ac_lbl_have_pthreads="not found" ] ) dnl to pacify those who hate protochain insn AC_MSG_CHECKING(if --disable-protochain option is specified) AC_ARG_ENABLE(protochain, AS_HELP_STRING([--disable-protochain],[disable \"protochain\" insn])) case "x$enable_protochain" in xyes) enable_protochain=enabled ;; xno) enable_protochain=disabled ;; x) enable_protochain=enabled ;; esac if test "$enable_protochain" = "disabled"; then AC_DEFINE(NO_PROTOCHAIN,1,[do not use protochain]) fi AC_MSG_RESULT(${enable_protochain}) # # valgrindtest directly uses the native capture mechanism, but # only tests with BPF and PF_PACKET sockets; only enable it if # we have BPF or PF_PACKET sockets. # VALGRINDTEST_SRC= AC_ARG_WITH(pcap, AS_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE])) if test ! -z "$with_pcap" ; then V_PCAP="$withval" else # # Check for a bunch of headers for various packet # capture mechanisms. # AC_CHECK_HEADERS(net/bpf.h) if test "$ac_cv_header_net_bpf_h" = yes; then # # Does it define BIOCSETIF? # I.e., is it a header for an LBL/BSD-style capture # mechanism, or is it just a header for a BPF filter # engine? Some versions of Arch Linux, for example, # have a net/bpf.h that doesn't define BIOCSETIF; # as it's a Linux, it should use packet sockets, # instead. # # We need: # # sys/types.h, because FreeBSD 10's net/bpf.h # requires that various BSD-style integer types # be defined; # # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h # doesn't include it but does use struct timeval # in ioctl definitions; # # sys/ioctl.h and, if we have it, sys/ioccom.h, # because net/bpf.h defines ioctls; # # net/if.h, because it defines some structures # used in ioctls defined by net/bpf.h; # # sys/socket.h, because OpenBSD 5.9's net/bpf.h # defines some structure fields as being # struct sockaddrs; # # and net/bpf.h doesn't necessarily include all # of those headers itself. # AC_MSG_CHECKING(if net/bpf.h defines BIOCSETIF) AC_CACHE_VAL(ac_cv_lbl_bpf_h_defines_biocsetif, AC_TRY_COMPILE( [ #include #include #include #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include #include ], [u_int i = BIOCSETIF;], ac_cv_lbl_bpf_h_defines_biocsetif=yes, ac_cv_lbl_bpf_h_defines_biocsetif=no)) AC_MSG_RESULT($ac_cv_lbl_bpf_h_defines_biocsetif) fi AC_CHECK_HEADERS(net/pfilt.h net/enet.h) AC_CHECK_HEADERS(net/nit.h sys/net/nit.h) AC_CHECK_HEADERS(linux/socket.h net/raw.h sys/dlpi.h) AC_CHECK_HEADERS(config/HaikuConfig.h) if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then # # BPF. # Check this before DLPI, so that we pick BPF on # Solaris 11 and later. # V_PCAP=bpf # # We have BPF, so build valgrindtest with "make test" # on macOS and FreeBSD (add your OS once there's a # valgrind for it). # case "$host_os" in freebsd*|darwin*|linux*) VALGRINDTEST_SRC=valgrindtest.c ;; esac elif test "$ac_cv_header_linux_socket_h" = yes; then # # No prizes for guessing this one. # V_PCAP=linux VALGRINDTEST_SRC=valgrindtest.c elif test "$ac_cv_header_net_pfilt_h" = yes; then - # - # DEC OSF/1, Digital UNIX, Tru64 UNIX - # + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # V_PCAP=pf elif test "$ac_cv_header_net_enet_h" = yes; then # # Stanford Enetfilter. # V_PCAP=enet elif test "$ac_cv_header_net_nit_h" = yes; then # # SunOS 4.x STREAMS NIT. # V_PCAP=snit elif test "$ac_cv_header_sys_net_nit_h" = yes; then # # Pre-SunOS 4.x non-STREAMS NIT. # V_PCAP=nit elif test "$ac_cv_header_net_raw_h" = yes; then # # IRIX snoop. # V_PCAP=snoop elif test "$ac_cv_header_sys_dlpi_h" = yes; then # # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. # V_PCAP=dlpi elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then # # Haiku. # V_PCAP=haiku else # # Nothing we support. # V_PCAP=null AC_MSG_WARN(cannot determine packet capture interface) AC_MSG_WARN((see the INSTALL.md file for more info)) fi fi AC_MSG_CHECKING(packet capture type) AC_MSG_RESULT($V_PCAP) AC_SUBST(VALGRINDTEST_SRC) # # Do we have pkg-config? # PKG_PROG_PKG_CONFIG # # Do we have the brew command from Homebrew? # AC_PATH_PROG([BREW], [brew]) # # Solaris pkg-config is annoying. For at least one package (D-Bus, I'm # looking at *you*!), there are separate include files for 32-bit and # 64-bit builds (I guess using "unsigned long long" as a 64-bit integer # type on a 64-bit build is like crossing the beams or soething), and # there are two separate .pc files, so if we're doing a 32-bit build we # should make sure we look in /usr/lib/pkgconfig for .pc files and if # we're doing a 64-bit build we should make sure we look in # /usr/lib/amd64/pkgconfig for .pc files. # case "$host_os" in solaris*) if test "$ac_cv_sizeof_void_p" -eq 8; then # # 64-bit build. If the path is empty, set it to # /usr/lib/amd64/pkgconfig; otherwise, if # /usr/lib/pkgconfig appears in the path, prepend # /usr/lib/amd64/pkgconfig to it; otherwise, put # /usr/lib/amd64/pkgconfig at the end. # if test -z "$PKG_CONFIG_PATH"; then # # Not set, or empty. Set it to # /usr/lib/amd64/pkgconfig. # PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then # # It contains /usr/lib/pkgconfig. Prepend # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. # PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` else # # Not empty, but doesn't contain /usr/lib/pkgconfig. # Append /usr/lib/amd64/pkgconfig to it. # PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" fi export PKG_CONFIG_PATH elif test "$ac_cv_sizeof_void_p" -eq 4; then # # 32-bit build. If /usr/amd64/lib/pkgconfig appears # in the path, prepend /usr/lib/pkgconfig to it. # if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then # # It contains /usr/lib/amd64/pkgconfig. Prepend # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. # PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` export PKG_CONFIG_PATH fi fi esac # # Handle each capture type. # case "$V_PCAP" in dlpi) # # Checks for some header files. # AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) # # Checks to see if Solaris has the public libdlpi(3LIB) library. # Note: The existence of /usr/include/libdlpi.h does not mean it is the # public libdlpi(3LIB) version. Before libdlpi was made public, a # private version also existed, which did not have the same APIs. # Due to a gcc bug, the default search path for 32-bit libraries does # not include /lib, we add it explicitly here. # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. # Also, due to the bug above applications that link to libpcap with # libdlpi will have to add "-L/lib" option to "configure". # save_LDFLAGS="$LDFLAGS" LDFLAGS="$LIBS -L/lib" AC_CHECK_LIB(dlpi, dlpi_walk, [ LIBS="-ldlpi $LIBS" LIBS_STATIC="-ldlpi $LIBS_STATIC" LIBS_PRIVATE="-ldlpi $LIBS_PRIVATE" V_PCAP=libdlpi # # Capture module plus common code needed for # common functions used by pcap-[dlpi,libdlpi].c # PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c" AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists]) ], [ V_PCAP=dlpi # # Capture module plus common code needed for # common functions used by pcap-[dlpi,libdlpi].c # PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c" ]) LDFLAGS="$save_LDFLAGS" # # Checks whether is usable, to catch weird SCO # versions of DLPI. # AC_MSG_CHECKING(whether is usable) AC_CACHE_VAL(ac_cv_sys_dlpi_usable, AC_TRY_COMPILE( [ #include #include #include ], [int i = DL_PROMISC_PHYS;], ac_cv_sys_dlpi_usable=yes, ac_cv_sys_dlpi_usable=no)) AC_MSG_RESULT($ac_cv_sys_dlpi_usable) if test $ac_cv_sys_dlpi_usable = no ; then AC_MSG_ERROR( is not usable on this system; it probably has a non-standard DLPI) fi # # Check to see if Solaris has the dl_passive_req_t struct defined # in . # This check is for DLPI support for passive modes. # See dlpi(7P) for more details. # AC_CHECK_TYPES(dl_passive_req_t,,, [ #include #include ]) ;; enet) # # Capture module # - PLATFORM_C_SRC="pcap-enet.c" + PLATFORM_C_SRC="pcap-enet.c" ;; haiku) # # Capture module # - PLATFORM_CXX_SRC="pcap-haiku.cpp" + PLATFORM_CXX_SRC="pcap-haiku.cpp" # # Just for the sake of it. # AC_CHECK_HEADERS(net/if.h net/if_dl.h net/if_types.h) ;; linux) # # Capture module # - PLATFORM_C_SRC="pcap-linux.c" + PLATFORM_C_SRC="pcap-linux.c" # # Do we have the wireless extensions? # AC_CHECK_HEADERS(linux/wireless.h, [], [], [ #include #include #include ]) # # Do we have libnl? # We only want version 3. Version 2 was, apparently, # short-lived, and version 1 is source and binary # incompatible with version 3, and it appears that, # these days, everybody's using version 3. We're # not supporting older versions of the Linux kernel; # let's drop support for older versions of libnl, too. # AC_ARG_WITH(libnl, AS_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]), with_libnl=$withval,with_libnl=if_available) if test x$with_libnl != xno ; then # # Check for libnl-genl-3.0 with pkg-config. # PKG_CHECK_MODULES(LIBNL, libnl-genl-3.0, [ pkg_config_found_libnl=yes V_INCLS="$V_INCLS $LIBNL_CFLAGS" ADDITIONAL_LIBS="$LIBNL_LIBS $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="$LIBNL_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" REQUIRES_PRIVATE="libnl-genl-3.0 $REQUIRES_PRIVATE" AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) ]) if test x$pkg_config_found_libnl != xyes; then # # OK, either we don't have pkg-config or there # wasn't a .pc file for it; Check for it directly. # case "$with_libnl" in yes|if_available) incdir=-I/usr/include/libnl3 libnldir= ;; *) if test -d $withval; then libnldir=-L${withval}/lib incdir=-I${withval}/include fi ;; esac AC_CHECK_LIB(nl-3, nl_socket_alloc, [ # # Yes, we have libnl 3.x. # ADDITIONAL_LIBS="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS_STATIC" LIBS_PRIVATE="${libnldir} -lnl-genl-3 -lnl-3 $LIBS_PRIVATE" AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) V_INCLS="$V_INCLS ${incdir}" ],[ # # No, we don't have libnl at all. # Fail if the user explicitly requested # it. # if test x$with_libnl = xyes ; then AC_MSG_ERROR([libnl support requested but libnl not found]) fi ], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 ) fi fi # # Check to see if the tpacket_auxdata struct has a tp_vlan_tci member. # # NOTE: any failure means we conclude that it doesn't have that # member, so if we don't have tpacket_auxdata, we conclude it # doesn't have that member (which is OK, as either we won't be # using code that would use that member, or we wouldn't compile # in any case). AC_CHECK_MEMBERS([struct tpacket_auxdata.tp_vlan_tci],,, [ #include #include ]) ;; bpf) # # Capture module # - PLATFORM_C_SRC="pcap-bpf.c" + PLATFORM_C_SRC="pcap-bpf.c" # # Check whether we have the *BSD-style ioctls. # AC_CHECK_HEADERS(net/if_media.h) # # Check whether we have struct BPF_TIMEVAL. # AC_CHECK_TYPES(struct BPF_TIMEVAL,,, [ #include #include #ifdef HAVE_SYS_IOCCOM_H #include #endif #include ]) ;; pf) # # Capture module # - PLATFORM_C_SRC="pcap-pf.c" + PLATFORM_C_SRC="pcap-pf.c" ;; snit) # # Capture module # - PLATFORM_C_SRC="pcap-snit.c" + PLATFORM_C_SRC="pcap-snit.c" ;; snoop) # # Capture module # - PLATFORM_C_SRC="pcap-snoop.c" + PLATFORM_C_SRC="pcap-snoop.c" ;; dag) # # --with-pcap=dag is the only way to get here, and it means # "DAG support but nothing else" # V_DEFS="$V_DEFS -DDAG_ONLY" PLATFORM_C_SRC="pcap-dag.c" xxx_only=yes ;; dpdk) # # --with-pcap=dpdk is the only way to get here, and it means # "DPDK support but nothing else" # V_DEFS="$V_DEFS -DDPDK_ONLY" PLATFORM_C_SRC="pcap-dpdk.c" xxx_only=yes ;; septel) # # --with-pcap=septel is the only way to get here, and it means # "Septel support but nothing else" # V_DEFS="$V_DEFS -DSEPTEL_ONLY" PLATFORM_C_SRC="pcap-septel.c" xxx_only=yes ;; snf) # # --with-pcap=snf is the only way to get here, and it means # "SNF support but nothing else" # V_DEFS="$V_DEFS -DSNF_ONLY" PLATFORM_C_SRC="pcap-snf.c" xxx_only=yes ;; null) # # Capture module # - PLATFORM_C_SRC="pcap-null.c" + PLATFORM_C_SRC="pcap-null.c" ;; *) AC_MSG_ERROR($V_PCAP is not a valid pcap type) ;; esac dnl dnl Now figure out how we get a list of interfaces and addresses, dnl if we support capturing. Don't bother if we don't support dnl capturing. dnl if test "$V_PCAP" != null then AC_CHECK_FUNC(getifaddrs,[ # # We have "getifaddrs()"; make sure we have # as well, just in case some platform is really weird. # AC_CHECK_HEADER(ifaddrs.h,[ # # We have the header, so we use "getifaddrs()" to # get the list of interfaces. # PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c" ],[ # # We don't have the header - give up. # XXX - we could also fall back on some other # mechanism, but, for now, this'll catch this # problem so that we can at least try to figure # out something to do on systems with "getifaddrs()" # but without "ifaddrs.h", if there is something # we can do on those systems. # AC_MSG_ERROR([Your system has getifaddrs() but doesn't have a usable .]) ]) ],[ # # Well, we don't have "getifaddrs()", at least not with the # libraries with which we've decided we need to link # libpcap with, so we have to use some other mechanism. # # Note that this may happen on Solaris, which has # getifaddrs(), but in -lsocket, not in -lxnet, so we # won't find it if we link with -lxnet, which we want # to do for other reasons. # # For now, we use either the SIOCGIFCONF ioctl or the # SIOCGLIFCONF ioctl, preferring the latter if we have # it; the latter is a Solarisism that first appeared # in Solaris 8. (Solaris's getifaddrs() appears to # be built atop SIOCGLIFCONF; using it directly # avoids a not-all-that-useful middleman.) # AC_MSG_CHECKING(whether we have SIOCGLIFCONF) AC_CACHE_VAL(ac_cv_lbl_have_siocglifconf, AC_TRY_COMPILE( [#include #include #include #include #include ], [ioctl(0, SIOCGLIFCONF, (char *)0);], ac_cv_lbl_have_siocglifconf=yes, ac_cv_lbl_have_siocglifconf=no)) AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf) if test $ac_cv_lbl_have_siocglifconf = yes ; then PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c" else PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c" fi ]) fi dnl check for hardware timestamp support case "$host_os" in linux*) AC_CHECK_HEADERS([linux/net_tstamp.h]) ;; *) AC_MSG_NOTICE(no hardware timestamp support implemented for $host_os) ;; esac # # Check for socklen_t. # AC_CHECK_TYPES(socklen_t,,, [ #include #include ]) AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--enable-ipv6],[build IPv6-capable version @<:@default=yes@:>@]), [], [enable_ipv6=yes]) if test "$enable_ipv6" != "no"; then # # We've already made sure we have getaddrinfo above in # AC_LBL_LIBRARY_NET. # AC_DEFINE(INET6,1,[IPv6]) fi # Check for Endace DAG card support. AC_ARG_WITH([dag], AS_HELP_STRING([--with-dag@<:@=DIR@:>@],[include Endace DAG support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User doesn't want DAG support. want_dag=no elif test "$withval" = yes then # User wants DAG support but hasn't specified a directory. want_dag=yes else # User wants DAG support and has specified a directory, so use the provided value. want_dag=yes dag_root=$withval fi ],[ if test "$V_PCAP" = dag; then # User requested DAG-only libpcap, so we'd better have # the DAG API. want_dag=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want DAG support. want_dag=no else # # Use DAG API if present, otherwise don't # want_dag=ifpresent fi ]) AC_ARG_WITH([dag-includes], AS_HELP_STRING([--with-dag-includes=IDIR],[Endace DAG include directory, if not DIR/include]), [ # User wants DAG support and has specified a header directory, so use the provided value. want_dag=yes dag_include_dir=$withval ],[]) AC_ARG_WITH([dag-libraries], AS_HELP_STRING([--with-dag-libraries=LDIR],[Endace DAG library directory, if not DIR/lib]), [ # User wants DAG support and has specified a library directory, so use the provided value. want_dag=yes dag_lib_dir=$withval ],[]) if test "$want_dag" != no; then # If necessary, set default paths for DAG API headers and libraries. if test -z "$dag_root"; then dag_root=/usr/local fi if test -z "$dag_include_dir"; then dag_include_dir="$dag_root/include" fi if test -z "$dag_lib_dir"; then dag_lib_dir="$dag_root/lib" # # Handle multiarch systems. # if test -d "$dag_lib_dir/$host" then dag_lib_dir="$dag_lib_dir/$host" fi fi AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS -I$dag_include_dir" AC_CHECK_HEADERS([dagapi.h]) AC_LBL_RESTORE_CHECK_STATE if test "$ac_cv_header_dagapi_h" = yes; then V_INCLS="$V_INCLS -I$dag_include_dir" if test $V_PCAP != dag ; then MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c" fi # Check for various DAG API functions. # Don't need to save and restore LIBS to prevent -ldag being # included if there's a found-action (arg 3). AC_LBL_SAVE_CHECK_STATE LDFLAGS="-L$dag_lib_dir" AC_CHECK_LIB([dag], [dag_attach_stream], [ # # We assume that if we have libdag we have # libdagconf, as they're installed at the # same time from the same package. # ADDITIONAL_LIBS="-L$dag_lib_dir $ADDITIONAL_LIBS -ldag -ldagconf" ADDITIONAL_LIBS_STATIC="-L$dag_lib_dir $ADDITIONAL_LIBS_STATIC -ldag -ldagconf" LIBS_PRIVATE="-L$dag_lib_dir $LIBS_PRIVATE -ldag -ldagconf" ], [AC_MSG_ERROR(DAG library lacks streams support)]) AC_CHECK_LIB([dag], [dag_attach_stream64], [dag_large_streams="1"], [dag_large_streams="0"]) AC_CHECK_LIB([dag],[dag_get_erf_types], [ AC_DEFINE(HAVE_DAG_GET_ERF_TYPES, 1, [define if you have dag_get_erf_types()])]) AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [ AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])]) AC_LBL_RESTORE_CHECK_STATE # # We assume that if we have libdag we have libdagconf, # as they're installed at the same time from the same # package. # if test "$dag_large_streams" = 1; then AC_DEFINE(HAVE_DAG_LARGE_STREAMS_API, 1, [define if you have large streams capable DAG API]) AC_LBL_SAVE_CHECK_STATE LIBS="$LIBS -ldag -ldagconf" LDFLAGS="$LDFLAGS -L$dag_lib_dir" AC_CHECK_LIB([vdag],[vdag_set_device_info], [ac_dag_have_vdag="1"], [ac_dag_have_vdag="0"]) AC_LBL_RESTORE_CHECK_STATE if test "$ac_dag_have_vdag" = 1; then AC_DEFINE(HAVE_DAG_VDAG, 1, [define if you have vdag_set_device_info()]) if test "$ac_lbl_have_pthreads" != "found"; then AC_MSG_ERROR([DAG requires pthreads, but we didn't find them]) fi ADDITIONAL_LIBS="$ADDITIONAL_LIBS $PTHREAD_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $PTHREAD_LIBS" LIBS_PRIVATE="$LIBS_PRIVATE $PTHREAD_LIBS" fi fi AC_DEFINE(HAVE_DAG_API, 1, [define if you have the DAG API]) else if test "$V_PCAP" = dag; then # User requested "dag" capture type but we couldn't # find the DAG API support. AC_MSG_ERROR([DAG support requested with --with-pcap=dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) fi if test "$want_dag" = yes; then # User wanted DAG support but we couldn't find it. AC_MSG_ERROR([DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) fi fi CFLAGS="$save_CFLAGS" fi AC_ARG_WITH(septel, AS_HELP_STRING([--with-septel@<:@=DIR@:>@],[include Septel support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then want_septel=no elif test "$withval" = yes then want_septel=yes septel_root= else want_septel=yes septel_root=$withval fi ],[ if test "$V_PCAP" = septel; then # User requested Septel-only libpcap, so we'd better have # the Septel API. want_septel=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Septel support. want_septel=no else # # Use Septel API if present, otherwise don't # want_septel=ifpresent fi ]) ac_cv_lbl_septel_api=no if test "$with_septel" != no; then AC_MSG_CHECKING([whether we have Septel API headers]) # If necessary, set default paths for Septel API headers and libraries. if test -z "$septel_root"; then septel_root=$srcdir/../septel fi septel_tools_dir="$septel_root" septel_include_dir="$septel_root/INC" if test -r "$septel_include_dir/msg.h"; then ac_cv_lbl_septel_api=yes fi if test "$ac_cv_lbl_septel_api" = yes; then AC_MSG_RESULT([yes ($septel_include_dir)]) V_INCLS="$V_INCLS -I$septel_include_dir" ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" if test "$V_PCAP" != septel ; then MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c" fi AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have the Septel API]) else AC_MSG_RESULT(no) if test "$V_PCAP" = septel; then # User requested "septel" capture type but # we couldn't find the Septel API support. AC_MSG_ERROR([Septel support requested with --with-pcap=septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) fi if test "$want_septel" = yes; then # User wanted Septel support but we couldn't find it. AC_MSG_ERROR([Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) fi fi fi # Check for Myricom SNF support. AC_ARG_WITH([snf], AS_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User explicitly doesn't want SNF want_snf=no elif test "$withval" = yes then # User wants SNF support but hasn't specified a directory. want_snf=yes else # User wants SNF support with a specified directory. want_snf=yes snf_root=$withval fi ],[ if test "$V_PCAP" = snf; then # User requested Sniffer-only libpcap, so we'd better have # the Sniffer API. want_snf=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want SNF support. want_snf=no else # # Use Sniffer API if present, otherwise don't # want_snf=ifpresent fi ]) AC_ARG_WITH([snf-includes], AS_HELP_STRING([--with-snf-includes=IDIR],[Myricom SNF include directory, if not DIR/include]), [ # User wants SNF with specific header directory want_snf=yes snf_include_dir=$withval ],[]) AC_ARG_WITH([snf-libraries], AS_HELP_STRING([--with-snf-libraries=LDIR],[Myricom SNF library directory, if not DIR/lib]), [ # User wants SNF with specific lib directory want_snf=yes snf_lib_dir=$withval ],[]) ac_cv_lbl_snf_api=no if test "$with_snf" != no; then AC_MSG_CHECKING(whether we have Myricom Sniffer API) # If necessary, set default paths for Sniffer headers and libraries. if test -z "$snf_root"; then snf_root=/opt/snf fi if test -z "$snf_include_dir"; then snf_include_dir="$snf_root/include" fi if test -z "$snf_lib_dir"; then snf_lib_dir="$snf_root/lib" # # Handle multiarch systems. # if test -d "$snf_lib_dir/$host" then snf_lib_dir="$snf_lib_dir/$host" fi fi if test -f "$snf_include_dir/snf.h"; then # We found a header; make sure we can link with the library AC_LBL_SAVE_CHECK_STATE LDFLAGS="$LDFLAGS -L$snf_lib_dir" AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"]) AC_LBL_RESTORE_CHECK_STATE if test "$ac_cv_lbl_snf_api" = no; then AC_MSG_ERROR(SNF API cannot correctly be linked; check config.log) fi fi if test "$ac_cv_lbl_snf_api" = yes; then AC_MSG_RESULT([yes ($snf_root)]) V_INCLS="$V_INCLS -I$snf_include_dir" ADDITIONAL_LIBS="$ADDITIONAL_LIBS -L$snf_lib_dir -lsnf" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC -L$snf_lib_dir -lsnf" LIBS_PRIVATE="$LIBS_PRIVATE -L$snf_lib_dir -lsnf" if test "$V_PCAP" != snf ; then MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c" fi AC_DEFINE(HAVE_SNF_API, 1, [define if you have the Myricom SNF API]) else AC_MSG_RESULT(no) if test "$want_snf" = yes; then # User requested "snf" capture type but # we couldn't find the Sniffer API support. AC_MSG_ERROR([Myricom Sniffer support requested with --with-pcap=snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) fi if test "$want_snf" = yes; then AC_MSG_ERROR([Myricom Sniffer support requested with --with-snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) fi fi fi # Check for Riverbed TurboCap support. AC_ARG_WITH([turbocap], AS_HELP_STRING([--with-turbocap@<:@=DIR@:>@],[include Riverbed TurboCap support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User explicitly doesn't want TurboCap want_turbocap=no elif test "$withval" = yes then # User wants TurboCap support but hasn't specified a directory. want_turbocap=yes else # User wants TurboCap support with a specified directory. want_turbocap=yes turbocap_root=$withval fi ],[ if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want TurboCap support. want_turbocap=no else # # Use TurboCap API if present, otherwise don't # want_turbocap=ifpresent fi ]) ac_cv_lbl_turbocap_api=no if test "$want_turbocap" != no; then AC_MSG_CHECKING(whether TurboCap is supported) AC_LBL_SAVE_CHECK_STATE if test ! -z "$turbocap_root"; then TURBOCAP_CFLAGS="-I$turbocap_root/include" TURBOCAP_LDFLAGS="-L$turbocap_root/lib" CFLAGS="$CFLAGS $TURBOCAP_CFLAGS" LDFLAGS="$LDFLAGS $TURBOCAP_LDFLAGS" fi AC_TRY_COMPILE( [ #include ], [ TC_INSTANCE a; TC_PORT b; TC_BOARD c; TC_INSTANCE i; (void)TcInstanceCreateByName("foo", &i); ], ac_cv_lbl_turbocap_api=yes) AC_LBL_RESTORE_CHECK_STATE if test $ac_cv_lbl_turbocap_api = yes; then AC_MSG_RESULT(yes) MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c" V_INCLS="$V_INCLS $TURBOCAP_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" LIBS_PRIVATE="$LIBS_PRIVATE $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" AC_DEFINE(HAVE_TC_API, 1, [define if you have the TurboCap API]) else AC_MSG_RESULT(no) if test "$want_turbocap" = yes; then # User wanted Turbo support but we couldn't find it. AC_MSG_ERROR([TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support]) fi fi fi dnl dnl Allow the user to enable remote capture. dnl It's off by default, as that increases the attack surface of dnl libpcap, exposing it to malicious servers. dnl AC_MSG_CHECKING([whether to enable remote packet capture]) AC_ARG_ENABLE([remote], [AS_HELP_STRING([--enable-remote], [enable remote packet capture @<:@default=no@:>@])], [], [enableval=no]) case "$enableval" in yes) AC_MSG_RESULT(yes) AC_WARN([Remote packet capture may expose libpcap-based applications]) AC_WARN([to attacks by malicious remote capture servers!]) # # rpcapd requires pthreads on UN*X. # if test "$ac_lbl_have_pthreads" != "found"; then AC_MSG_ERROR([rpcapd requires pthreads, but we didn't find them]) fi # # It also requires crypt(). # Do we have it in the system libraries? # AC_CHECK_FUNC(crypt,, [ # # No. Do we have it in -lcrypt? # AC_CHECK_LIB(crypt, crypt, [ # # Yes; add -lcrypt to the libraries for rpcapd. # RPCAPD_LIBS="$RPCAPD_LIBS -lcrypt" ], [ AC_MSG_ERROR([rpcapd requires crypt(), but we didn't find it]) ]) ]) # # OK, we have crypt(). Do we have getspnam()? # AC_CHECK_FUNCS(getspnam) # # Check for various members of struct msghdr. # AC_CHECK_MEMBERS([struct msghdr.msg_control],,, [ #include "ftmacros.h" #include ]) AC_CHECK_MEMBERS([struct msghdr.msg_flags],,, [ #include "ftmacros.h" #include ]) # # Optionally, we may want to support SSL. # Check for OpenSSL/libressl. # # First, try looking for it with pkg-config, if we have it. # # Homebrew's pkg-config does not, by default, look for # pkg-config files for packages it has installed. # Furthermore, at least for OpenSSL, they appear to be # dumped in package-specific directories whose paths are # not only package-specific but package-version-specific. # # So the only way to find openssl is to get the value of # PKG_CONFIG_PATH from "brew --env openssl" and add that # to PKG_CONFIG_PATH. (No, we can't just assume it's under # /usr/local; Homebrew have conveniently chosen to put it # under /opt/homebrew on ARM.) # # That's the nice thing about Homebrew - it makes things easier! # Thanks! # save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if test -n "$BREW"; then openssl_pkgconfig_dir=`$BREW --env --plain openssl | sed -n 's/PKG_CONFIG_PATH: //p'` PKG_CONFIG_PATH="$openssl_pkgconfig_dir:$PKG_CONFIG_PATH" fi PKG_CHECK_MODULES(OPENSSL, openssl, [ # # We found OpenSSL/libressl. # HAVE_OPENSSL=yes REQUIRES_PRIVATE="$REQUIRES_PRIVATE openssl" ]) PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" # # If it wasn't found, and we have Homebrew installed, see # if it's in Homebrew. # if test "x$HAVE_OPENSSL" != "xyes" -a -n "$BREW"; then AC_MSG_CHECKING(for openssl in Homebrew) # # The brew man page lies when it speaks of # $BREW --prefix --installed # outputting nothing. In Homebrew 3.3.16, # it produces output regardless of whether # the formula is installed or not, so we # send the standard output and error to # the bit bucket. # if $BREW --prefix --installed openssl >/dev/null 2>&1; then # # Yes. Get the include directory and library # directory. (No, we can't just assume it's # under /usr/local; Homebrew have conveniently # chosen to put it under /opt/homebrew on ARM.) # AC_MSG_RESULT(yes) HAVE_OPENSSL=yes openssl_path=`$BREW --prefix openssl` OPENSSL_CFLAGS="-I$openssl_path/include" OPENSSL_LIBS="-L$openssl_path/lib -lssl -lcrypto" OPENSSL_LIBS_STATIC="-L$openssl_path/lib -lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-L$openssl_path/lib -lssl -lcrypto" else AC_MSG_RESULT(no) fi fi # # If it wasn't found, and /usr/local/include and /usr/local/lib # exist, check if it's in /usr/local. (We check whether they # exist because, if they don't exist, the compiler will warn # about that and then ignore the argument, so they test # using just the system header files and libraries.) # # We include the standard include file to 1) make sure that # it's installed (if it's just a shared library for the # benefit of existing programs, that's not useful) and 2) # because SSL_library_init() is a library routine in some # versions and a #defined wrapper around OPENSSL_init_ssl() # in others. # if test "x$HAVE_OPENSSL" != "xyes" -a -d "/usr/local/include" -a -d "/usr/local/lib"; then AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS -I/usr/local/include" LIBS="$LIBS -L/usr/local/lib -lssl -lcrypto" AC_MSG_CHECKING(whether we have OpenSSL/libressl in /usr/local that we can use) AC_TRY_LINK( [ #include ], [ SSL_library_init(); return 0; ], [ AC_MSG_RESULT(yes) HAVE_OPENSSL=yes OPENSSL_CFLAGS="-I/usr/local/include" OPENSSL_LIBS="-L/usr/local/lib -lssl -lcrypto" OPENSSL_LIBS_STATIC="-L/usr/local/lib -lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-L/usr/local/lib -lssl -lcrypto" ], AC_MSG_RESULT(no)) AC_LBL_RESTORE_CHECK_STATE fi # # If it wasn't found, check if it's a system library. # # We include the standard include file to 1) make sure that # it's installed (if it's just a shared library for the # benefit of existing programs, that's not useful) and 2) # because SSL_library_init() is a library routine in some # versions and a #defined wrapper around OPENSSL_init_ssl() # in others. # if test "x$HAVE_OPENSSL" != "xyes"; then AC_LBL_SAVE_CHECK_STATE LIBS="$LIBS -lssl -lcrypto" AC_MSG_CHECKING(whether we have a system OpenSSL/libressl that we can use) AC_TRY_LINK( [ #include ], [ SSL_library_init(); return 0; ], [ AC_MSG_RESULT(yes) HAVE_OPENSSL=yes OPENSSL_LIBS="-lssl -lcrypto" OPENSSL_LIBS_STATIC="-lssl -lcrypto" OPENSSL_LIBS_PRIVATE="-lssl -lcrypto" ], AC_MSG_RESULT(no)) AC_LBL_RESTORE_CHECK_STATE fi # # OK, did we find it? # if test "x$HAVE_OPENSSL" = "xyes"; then AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL]) V_INCLS="$V_INCLS $OPENSSL_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $OPENSSL_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $OPENSSL_LIBS_STATIC" LIBS_PRIVATE="$LIBS_PRIVATE $OPENSSL_LIBS_PRIVATE" REQUIRES_PRIVATE="$REQUIRES_PRIVATE $OPENSSL_REQUIRES_PRIVATE" else AC_MSG_NOTICE(OpenSSL not found) fi AC_DEFINE(ENABLE_REMOTE,, [Define to 1 if remote packet capture is to be supported]) REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c" BUILD_RPCAPD=build-rpcapd INSTALL_RPCAPD=install-rpcapd ;; *) AC_MSG_RESULT(no) ;; esac AC_MSG_CHECKING(whether to build optimizer debugging code) AC_ARG_ENABLE(optimizer-dbg, AS_HELP_STRING([--enable-optimizer-dbg],[build optimizer debugging code])) if test "$enable_optimizer_dbg" = "yes"; then AC_DEFINE(BDEBUG,1,[Enable optimizer debugging]) fi AC_MSG_RESULT(${enable_optimizer_dbg-no}) AC_MSG_CHECKING(whether to build parser debugging code) AC_ARG_ENABLE(yydebug, AS_HELP_STRING([--enable-yydebug],[build parser debugging code])) if test "$enable_yydebug" = "yes"; then AC_DEFINE(YYDEBUG,1,[Enable parser debugging]) fi AC_MSG_RESULT(${enable_yydebug-no}) # # Look for {f}lex. # AC_PROG_LEX if test "$LEX" = ":"; then AC_MSG_ERROR([Neither flex nor lex was found.]) fi # # Make sure {f}lex supports the -P, --header-file, and --nounput flags # and supports processing our scanner.l. # AC_CACHE_CHECK([for capable lex], tcpdump_cv_capable_lex, if $LEX -P pcap_ --header-file=/dev/null --nounput -t $srcdir/scanner.l > /dev/null 2>&1; then tcpdump_cv_capable_lex=yes else tcpdump_cv_capable_lex=insufficient fi) if test $tcpdump_cv_capable_lex = insufficient ; then AC_MSG_ERROR([$LEX is insufficient to compile libpcap. libpcap requires Flex 2.5.31 or later, or a compatible version of lex. If a suitable version of Lex/Flex is available as a non-standard command and/or not in the PATH, you can specify it using the LEX environment variable. That said, on some systems the error can mean that Flex/Lex is actually acceptable, but m4 is not. Likewise, if a suitable version of m4 (such as GNU M4) is available but has not been detected, you can specify it using the M4 environment variable.]) fi # # Look for yacc/bison/byacc. # If it's Bison, we do not want -y, as 1) we will be using -o to cause # the output for XXX.y to be written to XXX.c and 2) we don't want # it to issue warnings about stuff not supported by POSIX YACC - we # want to use that stuff, and don't care whether plain YACC supports # it or not, we require either Bison or Berkeley YACC. # BISON_BYACC="" # # Look for Bison. # AC_CHECK_PROGS(BISON_BYACC, bison) if test x"$BISON_BYACC" != x; then # # We found Bison. # # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use # "%pure-parser". # bison_major_version=`$BISON_BYACC -V | sed -n 's/.* \(@<:@1-9@:>@@<:@0-9@:>@*\)\.@<:@0-9@:>@@<:@0-9.@:>@*/\1/p'` bison_minor_version=`$BISON_BYACC -V | sed -n 's/.* @<:@1-9@:>@@<:@0-9@:>@*\.\(@<:@0-9@:>@+\).*/\1/p'` if test "$bison_major_version" -lt 2 -o \ \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \) then REENTRANT_PARSER="%pure-parser" else REENTRANT_PARSER="%define api.pure" fi else # # We didn't find Bison; check for Berkeley YACC, under the # names byacc and yacc. # AC_CHECK_PROGS(BISON_BYACC, byacc yacc) if test x"$BISON_BYACC" != x; then # # Make sure this is Berkeley YACC, not AT&T YACC; # the latter doesn't support reentrant parsers. # Run it with "-V"; that succeeds and reports the # version number with Berkeley YACC, but will # (probably) fail with various vendor flavors # of AT&T YACC. # # Hopefully this also eliminates any versions # of Berkeley YACC that don't support reentrant # parsers, if there are any. # AC_CACHE_CHECK([for capable yacc], tcpdump_cv_capable_yacc, if $BISON_BYACC -V >/dev/null 2>&1; then tcpdump_cv_capable_yacc=yes else tcpdump_cv_capable_yacc=insufficient fi) if test $tcpdump_cv_capable_yacc = insufficient ; then AC_MSG_ERROR([$BISON_BYACC is insufficient to compile libpcap. libpcap requires Bison, a newer version of Berkeley YACC with support for reentrant parsers, or another YACC compatible with them.]) fi else # # OK, we found neither byacc nor yacc. # AC_MSG_ERROR([Neither bison, byacc, nor yacc was found. libpcap requires Bison, a newer version of Berkeley YACC with support for reentrant parsers, or another YACC compatible with them.]) fi # # Berkeley YACC doesn't support "%define api.pure", so use # "%pure-parser". # REENTRANT_PARSER="%pure-parser" fi AC_SUBST(BISON_BYACC) AC_SUBST(REENTRANT_PARSER) # # Do various checks for various OSes and versions of those OSes. # # Assume, by default, no support for shared libraries and V7/BSD # convention for man pages (devices in section 4, file formats in # section 5, miscellaneous info in section 7, administrative commands # and daemons in section 8). Individual cases can override this. # DYEXT="none" MAN_DEVICES=4 MAN_FILE_FORMATS=5 MAN_MISC_INFO=7 MAN_ADMIN_COMMANDS=8 case "$host_os" in aix*) dnl Workaround to enable certain features AC_DEFINE(_SUN,1,[define on AIX to get certain functions]) # # AIX makes it fun to build shared and static libraries, # because they're *both* ".a" archive libraries. We # build the static library for the benefit of the traditional # scheme of building libpcap and tcpdump in subdirectories of # the same directory, with tcpdump statically linked with the # libpcap in question, but we also build a shared library as # "libpcap.shareda" and install *it*, rather than the static # library, as "libpcap.a". # DYEXT="shareda" case "$V_PCAP" in dlpi) # # If we're using DLPI, applications will need to # use /lib/pse.exp if present, as we use the # STREAMS routines. # pseexe="/lib/pse.exp" AC_MSG_CHECKING(for $pseexe) if test -f $pseexe ; then AC_MSG_RESULT(yes) LIBS="-I:$pseexe" fi ;; bpf) # # If we're using BPF, we need "-lodm" and "-lcfg", as # we use them to load the BPF module. # LIBS="-lodm -lcfg" ;; esac ;; darwin*) DYEXT="dylib" V_CCOPT="$V_CCOPT -fno-common" AC_ARG_ENABLE(universal, AS_HELP_STRING([--disable-universal],[don't build universal on macOS])) if test "$enable_universal" != "no"; then case "$host_os" in darwin[[0-7]].*) # # Pre-Tiger. Build only for 32-bit PowerPC; no # need for any special compiler or linker flags. # ;; darwin8.[[0123]]|darwin8.[[0123]].*) # # Tiger, prior to Intel support. Build # libraries and executables for 32-bit PowerPC # and 64-bit PowerPC, with 32-bit PowerPC first. # (I'm guessing that's what Apple does.) # # (The double brackets are needed because # autotools/m4 use brackets as a quoting # character; the double brackets turn into # single brackets in the generated configure # file.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" ;; darwin8.[[456]]|darwin8.[[456]].*) # # Tiger, subsequent to Intel support but prior # to x86-64 support. Build libraries and # executables for 32-bit PowerPC, 64-bit # PowerPC, and 32-bit x86, with 32-bit PowerPC # first. (I'm guessing that's what Apple does.) # # (The double brackets are needed because # autotools/m4 use brackets as a quoting # character; the double brackets turn into # single brackets in the generated configure # file.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" ;; darwin8.*) # # All other Tiger, so subsequent to x86-64 # support. Build libraries and executables for # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, # and x86-64, with 32-bit PowerPC first. (I'm # guessing that's what Apple does.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin9.*) # # Leopard. Build libraries for 32-bit PowerPC, # 64-bit PowerPC, 32-bit x86, and x86-64, with # 32-bit PowerPC first, and build executables # for 32-bit x86 and 32-bit PowerPC, with 32-bit # x86 first. (That's what Apple does.) # V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" V_PROG_CCOPT_FAT="-arch i386 -arch ppc" V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" ;; darwin10.*) # # Snow Leopard. Build libraries for x86-64, # 32-bit x86, and 32-bit PowerPC, with x86-64 # first, and build executables for x86-64 and # 32-bit x86, with x86-64 first. (That's what # Apple does, even though Snow Leopard doesn't # run on PPC, so PPC libpcap runs under Rosetta, # and Rosetta doesn't support BPF ioctls, so PPC # programs can't do live captures.) # V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" ;; darwin1[[1-8]]*) # # Post-Snow Leopard, pre-Catalina. Build # libraries for x86-64 and 32-bit x86, with # x86-64 first, and build executables only for # x86-64. (That's what Apple does.) This # requires no special flags for programs. # # We check whether we *can* build for i386 and, # if not, suggest that the user install the # /usr/include headers if they want to build # fat. # AC_MSG_CHECKING(whether building for 32-bit x86 is supported) AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS -arch i386" AC_TRY_LINK( [], [return 0;], [ AC_MSG_RESULT(yes) V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" # # OpenSSL installation on macOS seems # to install only the libs for 64-bit # x86 - at least that's what Brew does: # only configure 32-bit builds if we # don't have OpenSSL. # if test "$HAVE_OPENSSL" != yes; then V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386" V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386" fi ], [ AC_MSG_RESULT(no) V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" case "$host_os" in darwin18.*) # # Mojave; you need to install the # /usr/include headers to get # 32-bit x86 builds to work. # AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package]) ;; *) # # Pre-Mojave; the command-line # tools should be sufficient to # enable 32-bit x86 builds. # AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools]) ;; esac ]) AC_LBL_RESTORE_CHECK_STATE ;; darwin19*) # # Catalina. Build libraries and executables # only for x86-64. (That's what Apple does; # 32-bit x86 binaries are not supported on # Catalina.) # V_LIB_CCOPT_FAT="-arch x86_64" V_LIB_LDFLAGS_FAT="-arch x86_64" V_PROG_CCOPT_FAT="-arch x86_64" V_PROG_LDFLAGS_FAT="-arch x86_64" ;; darwin*) # # Post-Catalina. Build libraries and # executables for x86-64 and ARM64. # (That's what Apple does, except they # build for arm64e, which may include # some of the pointer-checking extensions.) # # If we're building with libssl, make sure # we can build fat with it (i.e., that it # was built fat); if we can't, don't set # the target architectures, and just # build for the host we're on. # # Otherwise, just add both of them. # if test "$HAVE_OPENSSL" = yes; then AC_MSG_CHECKING(whether building fat with libssl is supported) AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS -arch x86_64 -arch arm64" LDFLAGS="$LDFLAGS $OPENSSL_LIBS" AC_TRY_LINK( [ #include ], [ SSL_library_init(); return 0; ], [ AC_MSG_RESULT(yes) V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" ], [AC_MSG_RESULT(no)] ) AC_LBL_RESTORE_CHECK_STATE else V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" fi ;; esac fi ;; hpux9*) AC_DEFINE(HAVE_HPUX9,1,[on HP-UX 9.x]) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.0*) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux10.1*) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; hpux*) dnl HPUX 10.20 and above is similar to HPUX 9, but dnl not the same.... dnl dnl XXX - DYEXT should be set to "sl" if this is building dnl for 32-bit PA-RISC, but should be left as "so" for dnl 64-bit PA-RISC or, I suspect, IA-64. AC_DEFINE(HAVE_HPUX10_20_OR_LATER,1,[on HP-UX 10.20 or later]) if test "`uname -m`" = "ia64"; then DYEXT="so" else DYEXT="sl" fi # # "-b" builds a shared library; "+h" sets the soname. # SHLIB_OPT="-b" SONAME_OPT="+h" # # Use System V conventions for man pages. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; irix*) # # Use IRIX conventions for man pages; they're the same as the # System V conventions, except that they use section 8 for # administrative commands and daemons. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 ;; linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*) DYEXT="so" ;; osf*) DYEXT="so" # # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. # Use Tru64 UNIX conventions for man pages; they're the same as # the System V conventions except that they use section 8 for # administrative commands and daemons. # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 MAN_DEVICES=7 ;; sinix*) AC_MSG_CHECKING(if SINIX compiler defines sinix) AC_CACHE_VAL(ac_cv_cc_sinix_defined, AC_TRY_COMPILE( [], [int i = sinix;], ac_cv_cc_sinix_defined=yes, ac_cv_cc_sinix_defined=no)) AC_MSG_RESULT($ac_cv_cc_sinix_defined) if test $ac_cv_cc_sinix_defined = no ; then AC_DEFINE(sinix,1,[on sinix]) fi ;; solaris*) AC_DEFINE(HAVE_SOLARIS,1,[On solaris]) DYEXT="so" # # Make sure errno is thread-safe, in case we're called in # a multithreaded program. We don't guarantee that two # threads can use the *same* pcap_t safely, but the # current version does guarantee that you can use different # pcap_t's in different threads, and even that pcap_compile() # is thread-safe (it wasn't thread-safe in some older versions). # V_CCOPT="$V_CCOPT -D_TS_ERRNO" case "`uname -r`" in 5.12) ;; *) # # Use System V conventions for man pages. # MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 MAN_DEVICES=7D esac ;; esac AC_SUBST(V_LIB_CCOPT_FAT) AC_SUBST(V_LIB_LDFLAGS_FAT) AC_SUBST(V_PROG_CCOPT_FAT) AC_SUBST(V_PROG_LDFLAGS_FAT) AC_SUBST(DYEXT) AC_SUBST(MAN_DEVICES) AC_SUBST(MAN_FILE_FORMATS) AC_SUBST(MAN_MISC_INFO) AC_SUBST(MAN_ADMIN_COMMANDS) AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared],[build shared libraries @<:@default=yes, if support available@:>@])) test "x$enable_shared" = "xno" && DYEXT="none" AC_PROG_RANLIB AC_CHECK_TOOL([AR], [ar]) AC_PROG_LN_S AC_SUBST(LN_S) AC_LBL_DEVEL(V_CCOPT) # # Check to see if the sockaddr struct has the 4.4 BSD sa_len member. # AC_CHECK_MEMBERS([struct sockaddr.sa_len],,, [ #include #include ]) # # Check to see if there's a sockaddr_storage structure. # AC_CHECK_TYPES(struct sockaddr_storage,,, [ #include #include ]) # # Check to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 # dl_module_id_1 member. # # NOTE: any failure means we conclude that it doesn't have that member, # so if we don't have DLPI, don't have a header, or # have one that doesn't declare a dl_hp_ppa_info_t type, we conclude # it doesn't have that member (which is OK, as either we won't be # using code that would use that member, or we wouldn't compile in # any case). # AC_CHECK_MEMBERS([dl_hp_ppa_info_t.dl_module_id_1],,, [ #include #include #include ]) # # Various Linux-specific mechanisms. # AC_ARG_ENABLE([usb], [AS_HELP_STRING([--enable-usb],[enable Linux usbmon USB capture support @<:@default=yes, if support available@:>@])], [], [enable_usb=yes]) # # If somebody requested an XXX-only pcap, that doesn't include # additional mechanisms. # if test "xxx_only" != yes; then case "$host_os" in linux*) dnl check for USB sniffing support AC_MSG_CHECKING(for Linux usbmon USB sniffing support) if test "x$enable_usb" != "xno" ; then AC_DEFINE(PCAP_SUPPORT_LINUX_USBMON, 1, [target host supports Linux usbmon for USB sniffing]) MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c" AC_MSG_RESULT(yes) # # Note: if the directory for special files is *EVER* somewhere # other than the UN*X standard of /dev (which will break any # software that looks for /dev/null or /dev/tty, for example, # so doing that is *REALLY* not a good idea), please provide # some mechanism to determine that directory at *run time*, # rather than *configure time*, so that it works when doinga # a cross-build, and that works with *multiple* distributions, # with our without udev, and with multiple versions of udev, # with udevinfo or udevadm or any other mechanism to get the # special files directory. # # Do we have a version of available? # If so, we might need it for . # AC_CHECK_HEADERS(linux/compiler.h) if test "$ac_cv_header_linux_compiler_h" = yes; then # # Yes - include it when testing for . # AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include ]) else AC_CHECK_HEADERS(linux/usbdevice_fs.h) fi if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then # # OK, does it define bRequestType? Older versions of the kernel # define fields with names like "requesttype, "request", and # "value", rather than "bRequestType", "bRequest", and # "wValue". # AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,, [ AC_INCLUDES_DEFAULT #ifdef HAVE_LINUX_COMPILER_H #include #endif #include ]) fi else AC_MSG_RESULT(no) fi # # Life's too short to deal with trying to get this to compile # if you don't get the right types defined with # __KERNEL_STRICT_NAMES getting defined by some other include. # # Check whether the includes Just Work. If not, don't turn on # netfilter support. # AC_MSG_CHECKING(whether we can compile the netfilter support) AC_CACHE_VAL(ac_cv_netfilter_can_compile, AC_TRY_COMPILE([ AC_INCLUDES_DEFAULT #include #include #include #include #include #include #include #include ], [], ac_cv_netfilter_can_compile=yes, ac_cv_netfilter_can_compile=no)) AC_MSG_RESULT($ac_cv_netfilter_can_compile) if test $ac_cv_netfilter_can_compile = yes ; then AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1, [target host supports netfilter sniffing]) MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c" fi ;; esac fi AC_SUBST(PCAP_SUPPORT_LINUX_USBMON) AC_SUBST(PCAP_SUPPORT_NETFILTER) AC_ARG_ENABLE([netmap], [AS_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])], [], [enable_netmap=yes]) if test "x$enable_netmap" != "xno" ; then # # Check whether net/netmap_user.h is usable if NETMAP_WITH_LIBS is # defined; it's not usable on DragonFly BSD 4.6 if NETMAP_WITH_LIBS # is defined, for example, as it includes a non-existent malloc.h # header. # AC_MSG_CHECKING(whether we can compile the netmap support) AC_CACHE_VAL(ac_cv_net_netmap_user_can_compile, AC_TRY_COMPILE([ AC_INCLUDES_DEFAULT #define NETMAP_WITH_LIBS #include ], [], ac_cv_net_netmap_user_can_compile=yes, ac_cv_net_netmap_user_can_compile=no)) AC_MSG_RESULT($ac_cv_net_netmap_user_can_compile) if test $ac_cv_net_netmap_user_can_compile = yes ; then AC_DEFINE(PCAP_SUPPORT_NETMAP, 1, [target host supports netmap]) MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c" fi AC_SUBST(PCAP_SUPPORT_NETMAP) fi # Check for DPDK support. AC_ARG_WITH([dpdk], AS_HELP_STRING([--with-dpdk@<:@=DIR@:>@],[include DPDK support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), [ if test "$withval" = no then # User doesn't want DPDK support. want_dpdk=no elif test "$withval" = yes then # User wants DPDK support but hasn't specified a directory. want_dpdk=yes else # User wants DPDK support and has specified a directory, # so use the provided value. want_dpdk=yes dpdk_dir=$withval fi ],[ if test "$V_PCAP" = dpdk; then # User requested DPDK-only libpcap, so we'd better have # the DPDK API. want_dpdk=yes elif test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want DPDK support. want_dpdk=no else # # Use DPDK API if present, otherwise don't # want_dpdk=ifpresent fi ]) if test "$want_dpdk" != no; then # # The user didn't explicitly say they don't want DPDK, # so see if we have it. # # We only try to find it using pkg-config; DPDK is *SO* # complicated - DPDK 19.02, for example, has about 117(!) # libraries, and the precise set of libraries required has # changed over time - so attempting to guess which libraries # you need, and hardcoding that in an attempt to find the # libraries without DPDK, rather than relying on DPDK to # tell you, with a .pc file, what libraries are needed, # is *EXTREMELY* fragile and has caused some bug reports, # so we're just not going to do it. # # If that causes a problem, the only thing we will do is # accept an alternative way of finding the appropriate # library set for the installed version of DPDK that is # as robust as pkg-config (i.e., it had better work as well # as pkg-config with *ALL* versions of DPDK that provide a # libdpdk.pc file). # # If --with-dpdk={path} was specified, add {path}/pkgconfig # to PKG_CONFIG_PATH, so we look for the .pc file there, # first. # save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if test -n "$dpdk_dir"; then PKG_CONFIG_PATH="$dpdk_dir:$PKG_CONFIG_PATH" fi PKG_CHECK_MODULES(DPDK, libdpdk, [ found_dpdk=yes ]) PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" # # Did we find DPDK? # if test "$found_dpdk" = yes; then # # Found it. # # We call rte_eth_dev_count_avail(), and older versions # of DPDK didn't have it, so check for it. # AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS $DPDK_CFLAGS" LIBS="$LIBS $DPDK_LIBS" AC_CHECK_FUNC(rte_eth_dev_count_avail) AC_LBL_RESTORE_CHECK_STATE fi if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then # # We found a usable DPDK. # # Check whether the rte_ether.h file defines # struct ether_addr or struct rte_ether_addr. # # ("API compatibility? That's for losers!") # AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS $DPDK_CFLAGS" LIBS="$LIBS $DPDK_LIBS" AC_CHECK_TYPES(struct rte_ether_addr,,, [ #include ]) AC_LBL_RESTORE_CHECK_STATE # # We can build with DPDK. # V_INCLS="$V_INCLS $DPDK_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DPDK_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DPDK_LIBS_STATIC" REQUIRES_PRIVATE="$REQUIRES_PRIVATE libdpdk" AC_DEFINE(PCAP_SUPPORT_DPDK, 1, [target host supports DPDK]) if test $V_PCAP != dpdk ; then MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c" fi else # # We didn't find a usable DPDK. # If we required it (with --with-dpdk or --with-pcap=dpdk), # fail with an appropriate message telling the user what # the problem was, otherwise note the problem with a # warning. # if test "$found_dpdk" != yes; then # # Not found with pkg-config. Note that we # require that DPDK must be findable with # pkg-config. # if test "$V_PCAP" = dpdk; then # # User requested DPDK-only capture support. # AC_MSG_ERROR( [DPDK support requested with --with-pcap=dpdk, but we couldn't find DPDK with pkg-config. Make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides a .pc file.]) fi if test "$want_dpdk" = yes; then # # User requested that libpcap include # DPDK capture support. # AC_MSG_ERROR( [DPDK support requested with --with-dpdk, but we couldn't find DPDK with pkg-config. Make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides .pc file.]) fi # # User didn't indicate whether they wanted DPDK # or not; just warn why we didn't find it. # AC_MSG_WARN( [We couldn't find DPDK with pkg-config. If you want DPDK support, make sure that pkg-config is installed, that DPDK 18.02.2 or later is installed, and that DPDK provides a .pc file.]) elif test "$ac_cv_func_rte_eth_dev_count_avail" != yes; then # # Found with pkg-config, but we couldn't compile # a program that calls rte_eth_dev_count(); we # probably have the developer package installed, # but don't have a sufficiently recent version # of DPDK. Note that we need a sufficiently # recent version of DPDK. # if test "$V_PCAP" = dpdk; then # # User requested DPDK-only capture support. # AC_MSG_ERROR( [DPDK support requested with --with-pcap=dpdk, but we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later is installed.]) fi if test "$want_dpdk" = yes; then # # User requested that libpcap include # DPDK capture support. # AC_MSG_ERROR( [DPDK support requested with --with-dpdk, but we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later is DPDK is installed.]) fi # # User didn't indicate whether they wanted DPDK # or not; just warn why we didn't find it. # AC_MSG_WARN( [DPDK was found, but we can't compile libpcap with it. Make sure that DPDK 18.02.2 or later is installed.]) fi fi fi AC_SUBST(PCAP_SUPPORT_DPDK) AC_ARG_ENABLE([bluetooth], [AS_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])], [], [enable_bluetooth=ifsupportavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want Bluetooth support. enable_bluetooth=no fi if test "x$enable_bluetooth" != "xno" ; then dnl check for Bluetooth sniffing support case "$host_os" in linux*) AC_CHECK_HEADER(bluetooth/bluetooth.h, [ # # We have bluetooth.h, so we support Bluetooth # sniffing. # AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing]) MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c" AC_MSG_NOTICE(Bluetooth sniffing is supported) ac_lbl_bluetooth_available=yes # # OK, does struct sockaddr_hci have an hci_channel # member? # AC_CHECK_MEMBERS([struct sockaddr_hci.hci_channel], [ # # Yes; is HCI_CHANNEL_MONITOR defined? # AC_MSG_CHECKING(if HCI_CHANNEL_MONITOR is defined) AC_CACHE_VAL(ac_cv_lbl_hci_channel_monitor_is_defined, AC_TRY_COMPILE( [ #include #include ], [ u_int i = HCI_CHANNEL_MONITOR; ], [ AC_MSG_RESULT(yes) AC_DEFINE(PCAP_SUPPORT_BT_MONITOR,, [target host supports Bluetooth Monitor]) MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c" ], [ AC_MSG_RESULT(no) ])) ],, [ #include #include ]) ], [ # # We don't have bluetooth.h, so we don't support # Bluetooth sniffing. # if test "x$enable_bluetooth" = "xyes" ; then AC_MSG_ERROR(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) else AC_MSG_NOTICE(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) fi ]) ;; *) if test "x$enable_bluetooth" = "xyes" ; then AC_MSG_ERROR(no Bluetooth sniffing support implemented for $host_os) else AC_MSG_NOTICE(no Bluetooth sniffing support implemented for $host_os) fi ;; esac AC_SUBST(PCAP_SUPPORT_BT) fi AC_ARG_ENABLE([dbus], [AS_HELP_STRING([--enable-dbus],[enable D-Bus capture support @<:@default=yes, if support available@:>@])], [], [enable_dbus=ifavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want D-Bus support. enable_dbus=no fi if test "x$enable_dbus" != "xno"; then if test "x$enable_dbus" = "xyes"; then case "$host_os" in darwin*) # # We don't support D-Bus sniffing on macOS; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user requested it, so fail. # AC_MSG_ERROR([Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS]) esac else case "$host_os" in darwin*) # # We don't support D-Bus sniffing on macOS; see # # https://bugs.freedesktop.org/show_bug.cgi?id=74029 # # The user dind't explicitly request it, so just # silently refuse to enable it. # enable_dbus="no" ;; esac fi fi if test "x$enable_dbus" != "xno"; then PKG_CHECK_MODULES(DBUS, dbus-1, [ AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS $DBUS_CFLAGS" LIBS="$LIBS $DBUS_LIBS" AC_MSG_CHECKING(whether the D-Bus library defines dbus_connection_read_write) AC_TRY_LINK( [#include #include #include #include ], [return dbus_connection_read_write(NULL, 0);], [ AC_MSG_RESULT([yes]) AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing]) MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c" V_INCLS="$V_INCLS $DBUS_CFLAGS" ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DBUS_LIBS" ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DBUS_LIBS_STATIC" REQUIRES_PRIVATE="$REQUIRES_PRIVATE dbus-1" ], [ AC_MSG_RESULT([no]) if test "x$enable_dbus" = "xyes"; then AC_MSG_ERROR([--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()]) fi ]) AC_LBL_RESTORE_CHECK_STATE ], [ if test "x$enable_dbus" = "xyes"; then AC_MSG_ERROR([--enable-dbus was given, but the dbus-1 package is not installed]) fi ]) AC_SUBST(PCAP_SUPPORT_DBUS) fi AC_ARG_ENABLE([rdma], [AS_HELP_STRING([--enable-rdma],[enable RDMA capture support @<:@default=yes, if support available@:>@])], [], [enable_rdma=ifavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want RDMA support. enable_rdma=no fi if test "x$enable_rdma" != "xno"; then PKG_CHECK_MODULES(LIBIBVERBS, libibverbs, [ found_libibverbs=yes LIBIBVERBS_REQUIRES_PRIVATE="libibverbs" ]) if test "x$found_libibverbs" != "xyes"; then AC_CHECK_LIB(ibverbs, ibv_get_device_list, [ found_libibverbs=yes LIBIBVERBS_CFLAGS="" LIBIBVERBS_LIBS="-libverbs" # XXX - at least on Ubuntu 20.04, there are many more # libraries needed; is there any platform where # libibverbs is available but where pkg-config isn't # available or libibverbs doesn't use it? If not, # we should only use pkg-config for it. LIBIBVERBS_LIBS_STATIC="-libverbs" LIBIBVERBS_LIBS_PRIVATE="-libverbs" ] ) fi if test "x$found_libibverbs" = "xyes"; then AC_LBL_SAVE_CHECK_STATE CFLAGS="$CFLAGS $LIBIBVERBS_CFLAGS" LIBS="$LIBS $LIBIBVERBS_LIBS" AC_CHECK_HEADER(infiniband/verbs.h, [ # # ibv_create_flow may be defined as a static inline # function in infiniband/verbs.h, so we can't # use AC_CHECK_LIB. # # Too bad autoconf has no AC_SYMBOL_EXISTS() # macro that works like CMake's check_symbol_exists() # function, to check do a compile check like # this (they do a clever trick to avoid having # to know the function's signature). # AC_MSG_CHECKING(whether libibverbs defines ibv_create_flow) AC_TRY_LINK( [ #include ], [ (void) ibv_create_flow((struct ibv_qp *) NULL, (struct ibv_flow_attr *) NULL); ], [ AC_MSG_RESULT([yes]) found_usable_libibverbs=yes ], [ AC_MSG_RESULT([no]) ] ) ]) AC_LBL_RESTORE_CHECK_STATE fi if test "x$found_usable_libibverbs" = "xyes" then AC_DEFINE(PCAP_SUPPORT_RDMASNIFF, , [target host supports RDMA sniffing]) MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c" CFLAGS="$LIBIBVERBS_CFLAGS $CFLAGS" ADDITIONAL_LIBS="$LIBIBVERBS_LIBS $ADDITIONAL_LIBS" ADDITIONAL_LIBS_STATIC="$LIBIBVERBS_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" LIBS_PRIVATE="$LIBIBVERBS_LIBS_PRIVATE $LIBS_PRIVATE" REQUIRES_PRIVATE="$REQUIRES_PRIVATE $LIBIBVERBS_REQUIRES_PRIVATE" fi AC_SUBST(PCAP_SUPPORT_RDMASNIFF) fi # # If this is a platform where we need to have the .pc file and # pcap-config script supply an rpath option to specify the directory # in which the libpcap shared library is installed, and the install # prefix /usr (meaning we're not installing a system library), provide # the rpath option. # # (We must check $prefix, as $libdir isn't necessarily /usr/lib in this # case - for example, Linux distributions for 64-bit platforms that # also provide support for binaries for a 32-bit version of the # platform may put the 64-bit libraries, the 32-bit libraries, or both # in directories other than /usr/lib.) # # In AIX, do we have to do this? # # In Darwin-based OSes, the full paths of the shared libraries with # which the program was linked are stored in the executable, so we don't # need to provide an rpath option. # # With the HP-UX linker, directories specified with -L are, by default, # added to the run-time search path, so we don't need to supply them. # # For Tru64 UNIX, "-rpath" works with DEC's^WCompaq's^WHP's C compiler # for Alpha, but isn't documented as working with GCC, and no GCC- # compatible option is documented as working with the DEC compiler. # If anybody needs this on Tru64/Alpha, they're welcome to figure out a # way to make it work. # # This must *not* depend on the compiler, as, on platforms where there's # a GCC-compatible compiler and a vendor compiler, we need to work with # both. # if test "$prefix" != "/usr"; then case "$host_os" in freebsd*|netbsd*|openbsd*|dragonfly*|linux*|haiku*|midipix*|gnu*) # # Platforms where the "native" C compiler is GCC or # accepts compatible command-line arguments, and the # "native" linker is the GNU linker or accepts # compatible command-line arguments. # RPATH="-Wl,-rpath,\${libdir}" ;; solaris*) # # Sun/Oracle's linker, the GNU linker, and # GNU-compatible linkers all support -R. # RPATH="-Wl,-R,\${libdir}" ;; esac fi AC_PROG_INSTALL AC_CONFIG_HEADER(config.h) AC_SUBST(V_SHLIB_CCOPT) AC_SUBST(V_SHLIB_CMD) AC_SUBST(V_SHLIB_OPT) AC_SUBST(V_SONAME_OPT) AC_SUBST(RPATH) AC_SUBST(ADDLOBJS) AC_SUBST(ADDLARCHIVEOBJS) AC_SUBST(PLATFORM_C_SRC) AC_SUBST(PLATFORM_CXX_SRC) AC_SUBST(MODULE_C_SRC) AC_SUBST(REMOTE_C_SRC) AC_SUBST(PTHREAD_LIBS) AC_SUBST(BUILD_RPCAPD) AC_SUBST(INSTALL_RPCAPD) AC_SUBST(RPCAPD_LIBS) # # We're done with configuration operations; add ADDITIONAL_LIBS and # ADDITIONAL_LIBS_STATIC to LIBS and LIBS_STATIC, respectively. # LIBS="$ADDITIONAL_LIBS $LIBS" LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $LIBS_STATIC" AC_OUTPUT_COMMANDS([if test -f .devel; then echo timestamp > stamp-h cat $srcdir/Makefile-devel-adds >> Makefile make depend || exit 1 fi]) AC_OUTPUT(Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile) exit 0 diff --git a/gencode.c b/gencode.c index 87a6e962b012..496e02f377e6 100644 --- a/gencode.c +++ b/gencode.c @@ -1,9993 +1,9993 @@ /* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef _WIN32 #include #else #include #ifdef __NetBSD__ #include #endif #include #include #endif /* _WIN32 */ #include #include #include #include #include #include #ifdef MSDOS #include "pcap-dos.h" #endif #include "pcap-int.h" #include "extract.h" #include "ethertype.h" #include "nlpid.h" #include "llc.h" #include "gencode.h" #include "ieee80211.h" #include "atmuni31.h" #include "sunatmpos.h" #include "pflog.h" #include "ppp.h" #include "pcap/sll.h" #include "pcap/ipnet.h" #include "arcnet.h" #include "diag-control.h" #include "scanner.h" #if defined(linux) #include #include #include #endif #ifndef offsetof #define offsetof(s, e) ((size_t)&((s *)0)->e) #endif #ifdef _WIN32 #ifdef INET6 #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) /* IPv6 address */ struct in6_addr { union { uint8_t u6_addr8[16]; uint16_t u6_addr16[8]; uint32_t u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 #define s6_addr64 in6_u.u6_addr64 }; typedef unsigned short sa_family_t; #define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family /* Ditto, for IPv6. */ struct sockaddr_in6 { __SOCKADDR_COMMON (sin6_); uint16_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; #ifndef EAI_ADDRFAMILY struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif /* EAI_ADDRFAMILY */ #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */ #endif /* INET6 */ #else /* _WIN32 */ #include /* for "struct addrinfo" */ #endif /* _WIN32 */ #include #include "nametoaddr.h" #define ETHERMTU 1500 #ifndef IPPROTO_HOPOPTS #define IPPROTO_HOPOPTS 0 #endif #ifndef IPPROTO_ROUTING #define IPPROTO_ROUTING 43 #endif #ifndef IPPROTO_FRAGMENT #define IPPROTO_FRAGMENT 44 #endif #ifndef IPPROTO_DSTOPTS #define IPPROTO_DSTOPTS 60 #endif #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #define GENEVE_PORT 6081 #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #define JMP(c) ((c)|BPF_JMP|BPF_K) /* * "Push" the current value of the link-layer header type and link-layer * header offset onto a "stack", and set a new value. (It's not a * full-blown stack; we keep only the top two items.) */ #define PUSH_LINKHDR(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \ { \ (cs)->prevlinktype = (cs)->linktype; \ (cs)->off_prevlinkhdr = (cs)->off_linkhdr; \ (cs)->linktype = (new_linktype); \ (cs)->off_linkhdr.is_variable = (new_is_variable); \ (cs)->off_linkhdr.constant_part = (new_constant_part); \ (cs)->off_linkhdr.reg = (new_reg); \ (cs)->is_geneve = 0; \ } /* * Offset "not set" value. */ #define OFFSET_NOT_SET 0xffffffffU /* * Absolute offsets, which are offsets from the beginning of the raw * packet data, are, in the general case, the sum of a variable value * and a constant value; the variable value may be absent, in which * case the offset is only the constant value, and the constant value * may be zero, in which case the offset is only the variable value. * * bpf_abs_offset is a structure containing all that information: * * is_variable is 1 if there's a variable part. * * constant_part is the constant part of the value, possibly zero; * * if is_variable is 1, reg is the register number for a register * containing the variable value if the register has been assigned, * and -1 otherwise. */ typedef struct { int is_variable; u_int constant_part; int reg; } bpf_abs_offset; /* * Value passed to gen_load_a() to indicate what the offset argument * is relative to the beginning of. */ enum e_offrel { OR_PACKET, /* full packet data */ OR_LINKHDR, /* link-layer header */ OR_PREVLINKHDR, /* previous link-layer header */ OR_LLC, /* 802.2 LLC header */ OR_PREVMPLSHDR, /* previous MPLS header */ OR_LINKTYPE, /* link-layer type */ OR_LINKPL, /* link-layer payload */ OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */ OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */ OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */ }; /* * We divy out chunks of memory rather than call malloc each time so * we don't have to worry about leaking memory. It's probably * not a big deal if all this memory was wasted but if this ever * goes into a library that would probably not be a good idea. * * XXX - this *is* in a library.... */ #define NCHUNKS 16 #define CHUNK0SIZE 1024 struct chunk { size_t n_left; void *m; }; /* Code generator state */ struct _compiler_state { jmp_buf top_ctx; pcap_t *bpf_pcap; int error_set; struct icode ic; int snaplen; int linktype; int prevlinktype; int outermostlinktype; bpf_u_int32 netmask; int no_optimize; /* Hack for handling VLAN and MPLS stacks. */ u_int label_stack_depth; u_int vlan_stack_depth; /* XXX */ u_int pcap_fddipad; /* * As errors are handled by a longjmp, anything allocated must * be freed in the longjmp handler, so it must be reachable * from that handler. * * One thing that's allocated is the result of pcap_nametoaddrinfo(); * it must be freed with freeaddrinfo(). This variable points to * any addrinfo structure that would need to be freed. */ struct addrinfo *ai; /* * Another thing that's allocated is the result of pcap_ether_aton(); * it must be freed with free(). This variable points to any * address that would need to be freed. */ u_char *e; /* * Various code constructs need to know the layout of the packet. * These values give the necessary offsets from the beginning * of the packet data. */ /* * Absolute offset of the beginning of the link-layer header. */ bpf_abs_offset off_linkhdr; /* * If we're checking a link-layer header for a packet encapsulated * in another protocol layer, this is the equivalent information * for the previous layers' link-layer header from the beginning * of the raw packet data. */ bpf_abs_offset off_prevlinkhdr; /* * This is the equivalent information for the outermost layers' * link-layer header. */ bpf_abs_offset off_outermostlinkhdr; /* * Absolute offset of the beginning of the link-layer payload. */ bpf_abs_offset off_linkpl; /* * "off_linktype" is the offset to information in the link-layer * header giving the packet type. This is an absolute offset * from the beginning of the packet. * * For Ethernet, it's the offset of the Ethernet type field; this * means that it must have a value that skips VLAN tags. * * For link-layer types that always use 802.2 headers, it's the * offset of the LLC header; this means that it must have a value * that skips VLAN tags. * * For PPP, it's the offset of the PPP type field. * * For Cisco HDLC, it's the offset of the CHDLC type field. * * For BSD loopback, it's the offset of the AF_ value. * * For Linux cooked sockets, it's the offset of the type field. * * off_linktype.constant_part is set to OFFSET_NOT_SET for no * encapsulation, in which case, IP is assumed. */ bpf_abs_offset off_linktype; /* * TRUE if the link layer includes an ATM pseudo-header. */ int is_atm; /* * TRUE if "geneve" appeared in the filter; it causes us to * generate code that checks for a Geneve header and assume * that later filters apply to the encapsulated payload. */ int is_geneve; /* * TRUE if we need variable length part of VLAN offset */ int is_vlan_vloffset; /* * These are offsets for the ATM pseudo-header. */ u_int off_vpi; u_int off_vci; u_int off_proto; /* * These are offsets for the MTP2 fields. */ u_int off_li; u_int off_li_hsl; /* * These are offsets for the MTP3 fields. */ u_int off_sio; u_int off_opc; u_int off_dpc; u_int off_sls; /* * This is the offset of the first byte after the ATM pseudo_header, * or -1 if there is no ATM pseudo-header. */ u_int off_payload; /* * These are offsets to the beginning of the network-layer header. * They are relative to the beginning of the link-layer payload * (i.e., they don't include off_linkhdr.constant_part or * off_linkpl.constant_part). * * If the link layer never uses 802.2 LLC: * * "off_nl" and "off_nl_nosnap" are the same. * * If the link layer always uses 802.2 LLC: * * "off_nl" is the offset if there's a SNAP header following * the 802.2 header; * * "off_nl_nosnap" is the offset if there's no SNAP header. * * If the link layer is Ethernet: * * "off_nl" is the offset if the packet is an Ethernet II packet * (we assume no 802.3+802.2+SNAP); * * "off_nl_nosnap" is the offset if the packet is an 802.3 packet * with an 802.2 header following it. */ u_int off_nl; u_int off_nl_nosnap; /* * Here we handle simple allocation of the scratch registers. * If too many registers are alloc'd, the allocator punts. */ int regused[BPF_MEMWORDS]; int curreg; /* * Memory chunks. */ struct chunk chunks[NCHUNKS]; int cur_chunk; }; /* * For use by routines outside this file. */ /* VARARGS */ void bpf_set_error(compiler_state_t *cstate, const char *fmt, ...) { va_list ap; /* * If we've already set an error, don't override it. * The lexical analyzer reports some errors by setting * the error and then returning a LEX_ERROR token, which * is not recognized by any grammar rule, and thus forces * the parse to stop. We don't want the error reported * by the lexical analyzer to be overwritten by the syntax * error. */ if (!cstate->error_set) { va_start(ap, fmt); (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); cstate->error_set = 1; } } /* * For use *ONLY* in routines in this file. */ static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...) PCAP_PRINTFLIKE(2, 3); /* VARARGS */ static void PCAP_NORETURN bpf_error(compiler_state_t *cstate, const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); longjmp(cstate->top_ctx, 1); /*NOTREACHED*/ #ifdef _AIX PCAP_UNREACHABLE #endif /* _AIX */ } static int init_linktype(compiler_state_t *, pcap_t *); static void init_regs(compiler_state_t *); static int alloc_reg(compiler_state_t *); static void free_reg(compiler_state_t *, int); static void initchunks(compiler_state_t *cstate); static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t); static void *newchunk(compiler_state_t *cstate, size_t); static void freechunks(compiler_state_t *cstate); static inline struct block *new_block(compiler_state_t *cstate, int); static inline struct slist *new_stmt(compiler_state_t *cstate, int); static struct block *gen_retblk(compiler_state_t *cstate, int); static inline void syntax(compiler_state_t *cstate); static void backpatch(struct block *, struct block *); static void merge(struct block *, struct block *); static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32); static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32); static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32); static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32); static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32); static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32, bpf_u_int32); static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int, u_int, const u_char *); static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int, u_int, bpf_u_int32, int, int, bpf_u_int32); static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *, u_int, u_int); static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int, u_int); static struct slist *gen_loadx_iphdrlen(compiler_state_t *); static struct block *gen_uncond(compiler_state_t *, int); static inline struct block *gen_true(compiler_state_t *); static inline struct block *gen_false(compiler_state_t *); static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32); static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32); static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32); static struct slist *gen_load_pflog_llprefixlen(compiler_state_t *); static struct slist *gen_load_prism_llprefixlen(compiler_state_t *); static struct slist *gen_load_avs_llprefixlen(compiler_state_t *); static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *); static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *); static void insert_compute_vloffsets(compiler_state_t *, struct block *); static struct slist *gen_abs_offset_varpart(compiler_state_t *, bpf_abs_offset *); static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32); static struct block *gen_linktype(compiler_state_t *, bpf_u_int32); static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32); static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32); static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32, int, bpf_u_int32, u_int, u_int); #ifdef INET6 static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *, struct in6_addr *, int, bpf_u_int32, u_int, u_int); #endif static struct block *gen_ahostop(compiler_state_t *, const u_char *, int); static struct block *gen_ehostop(compiler_state_t *, const u_char *, int); static struct block *gen_fhostop(compiler_state_t *, const u_char *, int); static struct block *gen_thostop(compiler_state_t *, const u_char *, int); static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int); static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int); static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int); static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32); static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32, int, int, int); #ifdef INET6 static struct block *gen_host6(compiler_state_t *, struct in6_addr *, struct in6_addr *, int, int, int); #endif #ifndef INET6 static struct block *gen_gateway(compiler_state_t *, const u_char *, struct addrinfo *, int, int); #endif static struct block *gen_ipfrag(compiler_state_t *); static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32); static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32, bpf_u_int32); static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32); static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32, bpf_u_int32); static struct block *gen_portop(compiler_state_t *, u_int, u_int, int); static struct block *gen_port(compiler_state_t *, u_int, int, int); static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int, bpf_u_int32, int); static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int); struct block *gen_portop6(compiler_state_t *, u_int, u_int, int); static struct block *gen_port6(compiler_state_t *, u_int, int, int); static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int, bpf_u_int32, int); static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int); static int lookup_proto(compiler_state_t *, const char *, int); #if !defined(NO_PROTOCHAIN) static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int); #endif /* !defined(NO_PROTOCHAIN) */ static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int); static struct slist *xfer_to_x(compiler_state_t *, struct arth *); static struct slist *xfer_to_a(compiler_state_t *, struct arth *); static struct block *gen_mac_multicast(compiler_state_t *, int); static struct block *gen_len(compiler_state_t *, int, int); static struct block *gen_check_802_11_data_frame(compiler_state_t *); static struct block *gen_geneve_ll_check(compiler_state_t *cstate); static struct block *gen_ppi_dlt_check(compiler_state_t *); static struct block *gen_atmfield_code_internal(compiler_state_t *, int, bpf_u_int32, int, int); static struct block *gen_atmtype_llc(compiler_state_t *); static struct block *gen_msg_abbrev(compiler_state_t *, int type); static void initchunks(compiler_state_t *cstate) { int i; for (i = 0; i < NCHUNKS; i++) { cstate->chunks[i].n_left = 0; cstate->chunks[i].m = NULL; } cstate->cur_chunk = 0; } static void * newchunk_nolongjmp(compiler_state_t *cstate, size_t n) { struct chunk *cp; int k; size_t size; #ifndef __NetBSD__ /* XXX Round up to nearest long. */ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); #else /* XXX Round up to structure boundary. */ n = ALIGN(n); #endif cp = &cstate->chunks[cstate->cur_chunk]; if (n > cp->n_left) { ++cp; k = ++cstate->cur_chunk; if (k >= NCHUNKS) { bpf_set_error(cstate, "out of memory"); return (NULL); } size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); if (cp->m == NULL) { bpf_set_error(cstate, "out of memory"); return (NULL); } memset((char *)cp->m, 0, size); cp->n_left = size; if (n > size) { bpf_set_error(cstate, "out of memory"); return (NULL); } } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left); } static void * newchunk(compiler_state_t *cstate, size_t n) { void *p; p = newchunk_nolongjmp(cstate, n); if (p == NULL) { longjmp(cstate->top_ctx, 1); /*NOTREACHED*/ } return (p); } static void freechunks(compiler_state_t *cstate) { int i; for (i = 0; i < NCHUNKS; ++i) if (cstate->chunks[i].m != NULL) free(cstate->chunks[i].m); } /* * A strdup whose allocations are freed after code generation is over. * This is used by the lexical analyzer, so it can't longjmp; it just * returns NULL on an allocation error, and the callers must check * for it. */ char * sdup(compiler_state_t *cstate, const char *s) { size_t n = strlen(s) + 1; char *cp = newchunk_nolongjmp(cstate, n); if (cp == NULL) return (NULL); pcap_strlcpy(cp, s, n); return (cp); } static inline struct block * new_block(compiler_state_t *cstate, int code) { struct block *p; p = (struct block *)newchunk(cstate, sizeof(*p)); p->s.code = code; p->head = p; return p; } static inline struct slist * new_stmt(compiler_state_t *cstate, int code) { struct slist *p; p = (struct slist *)newchunk(cstate, sizeof(*p)); p->s.code = code; return p; } static struct block * gen_retblk(compiler_state_t *cstate, int v) { struct block *b = new_block(cstate, BPF_RET|BPF_K); b->s.k = v; return b; } static inline PCAP_NORETURN_DEF void syntax(compiler_state_t *cstate) { bpf_error(cstate, "syntax error in filter expression"); } int pcap_compile(pcap_t *p, struct bpf_program *program, const char *buf, int optimize, bpf_u_int32 mask) { #ifdef _WIN32 static int done = 0; #endif compiler_state_t cstate; const char * volatile xbuf = buf; yyscan_t scanner = NULL; volatile YY_BUFFER_STATE in_buffer = NULL; u_int len; int rc; /* * If this pcap_t hasn't been activated, it doesn't have a * link-layer type, so we can't use it. */ if (!p->activated) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "not-yet-activated pcap_t passed to pcap_compile"); return (PCAP_ERROR); } #ifdef _WIN32 if (!done) pcap_wsockinit(); done = 1; #endif #ifdef ENABLE_REMOTE /* * If the device on which we're capturing need to be notified * that a new filter is being compiled, do so. * * This allows them to save a copy of it, in case, for example, * they're implementing a form of remote packet capture, and * want the remote machine to filter out the packets in which * it's sending the packets it's captured. * * XXX - the fact that we happen to be compiling a filter * doesn't necessarily mean we'll be installing it as the * filter for this pcap_t; we might be running it from userland * on captured packets to do packet classification. We really * need a better way of handling this, but this is all that * the WinPcap remote capture code did. */ if (p->save_current_filter_op != NULL) (p->save_current_filter_op)(p, buf); #endif initchunks(&cstate); cstate.no_optimize = 0; #ifdef INET6 cstate.ai = NULL; #endif cstate.e = NULL; cstate.ic.root = NULL; cstate.ic.cur_mark = 0; cstate.bpf_pcap = p; cstate.error_set = 0; init_regs(&cstate); cstate.netmask = mask; cstate.snaplen = pcap_snapshot(p); if (cstate.snaplen == 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snaplen of 0 rejects all packets"); rc = PCAP_ERROR; goto quit; } if (pcap_lex_init(&scanner) != 0) pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "can't initialize scanner"); in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); /* * Associate the compiler state with the lexical analyzer * state. */ pcap_set_extra(&cstate, scanner); if (init_linktype(&cstate, p) == -1) { rc = PCAP_ERROR; goto quit; } if (pcap_parse(scanner, &cstate) != 0) { #ifdef INET6 if (cstate.ai != NULL) freeaddrinfo(cstate.ai); #endif if (cstate.e != NULL) free(cstate.e); rc = PCAP_ERROR; goto quit; } if (cstate.ic.root == NULL) { /* * Catch errors reported by gen_retblk(). */ if (setjmp(cstate.top_ctx)) { rc = PCAP_ERROR; goto quit; } cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); } if (optimize && !cstate.no_optimize) { if (bpf_optimize(&cstate.ic, p->errbuf) == -1) { /* Failure */ rc = PCAP_ERROR; goto quit; } if (cstate.ic.root == NULL || (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "expression rejects all packets"); rc = PCAP_ERROR; goto quit; } } program->bf_insns = icode_to_fcode(&cstate.ic, cstate.ic.root, &len, p->errbuf); if (program->bf_insns == NULL) { /* Failure */ rc = PCAP_ERROR; goto quit; } program->bf_len = len; rc = 0; /* We're all okay */ quit: /* * Clean up everything for the lexical analyzer. */ if (in_buffer != NULL) pcap__delete_buffer(in_buffer, scanner); if (scanner != NULL) pcap_lex_destroy(scanner); /* * Clean up our own allocated memory. */ freechunks(&cstate); return (rc); } /* * entry point for using the compiler with no pcap open * pass in all the stuff that is needed explicitly instead. */ int pcap_compile_nopcap(int snaplen_arg, int linktype_arg, struct bpf_program *program, const char *buf, int optimize, bpf_u_int32 mask) { pcap_t *p; int ret; p = pcap_open_dead(linktype_arg, snaplen_arg); if (p == NULL) return (PCAP_ERROR); ret = pcap_compile(p, program, buf, optimize, mask); pcap_close(p); return (ret); } /* * Clean up a "struct bpf_program" by freeing all the memory allocated * in it. */ void pcap_freecode(struct bpf_program *program) { program->bf_len = 0; if (program->bf_insns != NULL) { free((char *)program->bf_insns); program->bf_insns = NULL; } } /* * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates * which of the jt and jf fields has been resolved and which is a pointer * back to another unresolved block (or nil). At least one of the fields * in each block is already resolved. */ static void backpatch(struct block *list, struct block *target) { struct block *next; while (list) { if (!list->sense) { next = JT(list); JT(list) = target; } else { next = JF(list); JF(list) = target; } list = next; } } /* * Merge the lists in b0 and b1, using the 'sense' field to indicate * which of jt and jf is the link. */ static void merge(struct block *b0, struct block *b1) { register struct block **p = &b0; /* Find end of list. */ while (*p) p = !((*p)->sense) ? &JT(*p) : &JF(*p); /* Concatenate the lists. */ *p = b1; } int finish_parse(compiler_state_t *cstate, struct block *p) { struct block *ppi_dlt_check; /* * Catch errors reported by us and routines below us, and return -1 * on an error. */ if (setjmp(cstate->top_ctx)) return (-1); /* * Insert before the statements of the first (root) block any * statements needed to load the lengths of any variable-length * headers into registers. * * XXX - a fancier strategy would be to insert those before the * statements of all blocks that use those lengths and that * have no predecessors that use them, so that we only compute * the lengths if we need them. There might be even better * approaches than that. * * However, those strategies would be more complicated, and * as we don't generate code to compute a length if the * program has no tests that use the length, and as most * tests will probably use those lengths, we would just * postpone computing the lengths so that it's not done * for tests that fail early, and it's not clear that's * worth the effort. */ insert_compute_vloffsets(cstate, p->head); /* * For DLT_PPI captures, generate a check of the per-packet * DLT value to make sure it's DLT_IEEE802_11. * * XXX - TurboCap cards use DLT_PPI for Ethernet. * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header * with appropriate Ethernet information and use that rather * than using something such as DLT_PPI where you don't know * the link-layer header type until runtime, which, in the * general case, would force us to generate both Ethernet *and* * 802.11 code (*and* anything else for which PPI is used) * and choose between them early in the BPF program? */ ppi_dlt_check = gen_ppi_dlt_check(cstate); if (ppi_dlt_check != NULL) gen_and(ppi_dlt_check, p); backpatch(p, gen_retblk(cstate, cstate->snaplen)); p->sense = !p->sense; backpatch(p, gen_retblk(cstate, 0)); cstate->ic.root = p->head; return (0); } void gen_and(struct block *b0, struct block *b1) { backpatch(b0, b1->head); b0->sense = !b0->sense; b1->sense = !b1->sense; merge(b1, b0); b1->sense = !b1->sense; b1->head = b0->head; } void gen_or(struct block *b0, struct block *b1) { b0->sense = !b0->sense; backpatch(b0, b1->head); b0->sense = !b0->sense; merge(b1, b0); b1->head = b0->head; } void gen_not(struct block *b) { b->sense = !b->sense; } static struct block * gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); } static struct block * gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); } static struct block * gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); } static struct block * gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); } static struct block * gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v) { return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); } static struct block * gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 v, bpf_u_int32 mask) { return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v); } static struct block * gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, const u_char *v) { register struct block *b, *tmp; b = NULL; while (size >= 4) { register const u_char *p = &v[size - 4]; tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, EXTRACT_BE_U_4(p)); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 4; } while (size >= 2) { register const u_char *p = &v[size - 2]; tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, EXTRACT_BE_U_2(p)); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 2; } if (size > 0) { tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]); if (b != NULL) gen_and(b, tmp); b = tmp; } return b; } /* * AND the field of size "size" at offset "offset" relative to the header * specified by "offrel" with "mask", and compare it with the value "v" * with the test specified by "jtype"; if "reverse" is true, the test * should test the opposite of "jtype". */ static struct block * gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size, bpf_u_int32 mask, int jtype, int reverse, bpf_u_int32 v) { struct slist *s, *s2; struct block *b; s = gen_load_a(cstate, offrel, offset, size); if (mask != 0xffffffff) { s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = mask; sappend(s, s2); } b = new_block(cstate, JMP(jtype)); b->stmts = s; b->s.k = v; if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) gen_not(b); return b; } static int init_linktype(compiler_state_t *cstate, pcap_t *p) { cstate->pcap_fddipad = p->fddipad; /* * We start out with only one link-layer header. */ cstate->outermostlinktype = pcap_datalink(p); cstate->off_outermostlinkhdr.constant_part = 0; cstate->off_outermostlinkhdr.is_variable = 0; cstate->off_outermostlinkhdr.reg = -1; cstate->prevlinktype = cstate->outermostlinktype; cstate->off_prevlinkhdr.constant_part = 0; cstate->off_prevlinkhdr.is_variable = 0; cstate->off_prevlinkhdr.reg = -1; cstate->linktype = cstate->outermostlinktype; cstate->off_linkhdr.constant_part = 0; cstate->off_linkhdr.is_variable = 0; cstate->off_linkhdr.reg = -1; /* * XXX */ cstate->off_linkpl.constant_part = 0; cstate->off_linkpl.is_variable = 0; cstate->off_linkpl.reg = -1; cstate->off_linktype.constant_part = 0; cstate->off_linktype.is_variable = 0; cstate->off_linktype.reg = -1; /* * Assume it's not raw ATM with a pseudo-header, for now. */ cstate->is_atm = 0; cstate->off_vpi = OFFSET_NOT_SET; cstate->off_vci = OFFSET_NOT_SET; cstate->off_proto = OFFSET_NOT_SET; cstate->off_payload = OFFSET_NOT_SET; /* * And not Geneve. */ cstate->is_geneve = 0; /* * No variable length VLAN offset by default */ cstate->is_vlan_vloffset = 0; /* * And assume we're not doing SS7. */ cstate->off_li = OFFSET_NOT_SET; cstate->off_li_hsl = OFFSET_NOT_SET; cstate->off_sio = OFFSET_NOT_SET; cstate->off_opc = OFFSET_NOT_SET; cstate->off_dpc = OFFSET_NOT_SET; cstate->off_sls = OFFSET_NOT_SET; cstate->label_stack_depth = 0; cstate->vlan_stack_depth = 0; switch (cstate->linktype) { case DLT_ARCNET: cstate->off_linktype.constant_part = 2; cstate->off_linkpl.constant_part = 6; cstate->off_nl = 0; /* XXX in reality, variable! */ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_ARCNET_LINUX: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 8; cstate->off_nl = 0; /* XXX in reality, variable! */ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_EN10MB: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = 14; /* Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case DLT_SLIP: /* * SLIP doesn't have a link level type. The 16 byte * header is hacked into our SLIP driver. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_SLIP_BSDOS: /* XXX this may be the same as the DLT_PPP_BSDOS case */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* XXX end */ cstate->off_linkpl.constant_part = 24; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_NULL: case DLT_LOOP: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_ENC: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP: case DLT_PPP_PPPD: case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ case DLT_HDLC: /* NetBSD (Cisco) HDLC */ case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */ cstate->off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */ cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP_ETHER: /* * This does no include the Ethernet header, and * only covers session state. */ cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 8; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_PPP_BSDOS: cstate->off_linktype.constant_part = 5; cstate->off_linkpl.constant_part = 24; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_FDDI: /* * FDDI doesn't really have a link-level type field. * We set "off_linktype" to the offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? */ cstate->off_linktype.constant_part = 13; cstate->off_linktype.constant_part += cstate->pcap_fddipad; cstate->off_linkpl.constant_part = 13; /* FDDI MAC header length */ cstate->off_linkpl.constant_part += cstate->pcap_fddipad; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_IEEE802: /* * Token Ring doesn't really have a link-level type field. * We set "off_linktype" to the offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? * * XXX - the header is actually variable-length. * Some various Linux patched versions gave 38 * as "off_linktype" and 40 as "off_nl"; however, * if a token ring packet has *no* routing * information, i.e. is not source-routed, the correct * values are 20 and 22, as they are in the vanilla code. * * A packet is source-routed iff the uppermost bit * of the first byte of the source address, at an * offset of 8, has the uppermost bit set. If the * packet is source-routed, the total number of bytes * of routing information is 2 plus bits 0x1F00 of * the 16-bit value at an offset of 14 (shifted right * 8 - figure out which byte that is). */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 14; /* Token Ring MAC header length */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: cstate->off_linkhdr.is_variable = 1; /* Fall through, 802.11 doesn't have a variable link * prefix but is otherwise the same. */ /* FALLTHROUGH */ case DLT_IEEE802_11: /* * 802.11 doesn't really have a link-level type field. * We set "off_linktype.constant_part" to the offset of * the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? * * We also handle variable-length radio headers here. * The Prism header is in theory variable-length, but in * practice it's always 144 bytes long. However, some * drivers on Linux use ARPHRD_IEEE80211_PRISM, but * sometimes or always supply an AVS header, so we * have to check whether the radio header is a Prism * header or an AVS header, so, in practice, it's * variable-length. */ cstate->off_linktype.constant_part = 24; cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ cstate->off_linkpl.is_variable = 1; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_PPI: /* * At the moment we treat PPI the same way that we treat * normal Radiotap encoded packets. The difference is in * the function that generates the code at the beginning * to compute the header length. Since this code generator * of PPI supports bare 802.11 encapsulation only (i.e. * the encapsulated DLT should be DLT_IEEE802_11) we * generate code to check for this too. */ cstate->off_linktype.constant_part = 24; cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ cstate->off_linkpl.is_variable = 1; cstate->off_linkhdr.is_variable = 1; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_ATM_RFC1483: case DLT_ATM_CLIP: /* Linux ATM defines this */ /* * assume routed, non-ISO PDUs * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) * * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, * or PPP with the PPP NLPID (e.g., PPPoA)? The * latter would presumably be treated the way PPPoE * should be, so you can do "pppoe and udp port 2049" * or "pppoa and tcp port 80" and have it check for * PPPo{A,E} and a PPP protocol of IP and.... */ cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 0; /* packet begins with LLC header */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_SUNATM: /* * Full Frontal ATM; you get AALn PDUs with an ATM * pseudo-header. */ cstate->is_atm = 1; cstate->off_vpi = SUNATM_VPI_POS; cstate->off_vci = SUNATM_VCI_POS; cstate->off_proto = PROTO_POS; cstate->off_payload = SUNATM_PKT_BEGIN_POS; cstate->off_linktype.constant_part = cstate->off_payload; cstate->off_linkpl.constant_part = cstate->off_payload; /* if LLC-encapsulated */ cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_RAW: case DLT_IPV4: case DLT_IPV6: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */ cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 20; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_LTALK: /* * LocalTalk does have a 1-byte type field in the LLAP header, * but really it just indicates whether there is a "short" or * "long" DDP packet following. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_IP_OVER_FC: /* * RFC 2625 IP-over-Fibre-Channel doesn't really have a * link-level type field. We set "off_linktype" to the * offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? RFC * 2625 says SNAP should be used. */ cstate->off_linktype.constant_part = 16; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 8; /* 802.2+SNAP */ cstate->off_nl_nosnap = 3; /* 802.2 */ break; case DLT_FRELAY: /* * XXX - we should set this to handle SNAP-encapsulated * frames (NLPID of 0x80). */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; /* * the only BPF-interesting FRF.16 frames are non-control frames; * Frame Relay has a variable length link-layer * so lets start with offset 4 for now and increments later on (FIXME); */ case DLT_MFR: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 0; cstate->off_nl = 4; cstate->off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ break; case DLT_APPLE_IP_OVER_IEEE1394: cstate->off_linktype.constant_part = 16; cstate->off_linkpl.constant_part = 18; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_SYMANTEC_FIREWALL: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 44; cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ break; case DLT_PFLOG: cstate->off_linktype.constant_part = 0; cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ cstate->off_linkpl.is_variable = 1; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_PPP: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_FRELAY: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_ATM1: cstate->off_linktype.constant_part = 4; /* in reality variable between 4-8 */ cstate->off_linkpl.constant_part = 4; /* in reality variable between 4-8 */ cstate->off_nl = 0; cstate->off_nl_nosnap = 10; break; case DLT_JUNIPER_ATM2: cstate->off_linktype.constant_part = 8; /* in reality variable between 8-12 */ cstate->off_linkpl.constant_part = 8; /* in reality variable between 8-12 */ cstate->off_nl = 0; cstate->off_nl_nosnap = 10; break; /* frames captured on a Juniper PPPoE service PIC * contain raw ethernet frames */ case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_ETHER: cstate->off_linkpl.constant_part = 14; cstate->off_linktype.constant_part = 16; cstate->off_nl = 18; /* Ethernet II */ cstate->off_nl_nosnap = 21; /* 802.3+802.2 */ break; case DLT_JUNIPER_PPPOE_ATM: cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 6; cstate->off_nl = 0; cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_GGSN: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_ES: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ cstate->off_nl = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_MONITOR: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; /* raw IP/IP6 header */ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_BACNET_MS_TP: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_SERVICES: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ cstate->off_nl = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_VP: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_ST: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_ISM: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_MTP2: cstate->off_li = 2; cstate->off_li_hsl = 4; cstate->off_sio = 3; cstate->off_opc = 4; cstate->off_dpc = 4; cstate->off_sls = 7; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_MTP2_WITH_PHDR: cstate->off_li = 6; cstate->off_li_hsl = 8; cstate->off_sio = 7; cstate->off_opc = 8; cstate->off_dpc = 8; cstate->off_sls = 11; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_ERF: cstate->off_li = 22; cstate->off_li_hsl = 24; cstate->off_sio = 23; cstate->off_opc = 24; cstate->off_dpc = 24; cstate->off_sls = 27; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_PFSYNC: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; break; case DLT_AX25_KISS: /* * Currently, only raw "link[N:M]" filtering is supported. */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */ cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; /* variable, min 16, max 71 steps of 7 */ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_IPNET: cstate->off_linktype.constant_part = 1; cstate->off_linkpl.constant_part = 24; /* ipnet header length */ cstate->off_nl = 0; cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_NETANALYZER: cstate->off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case DLT_NETANALYZER_TRANSPARENT: cstate->off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; default: /* * For values in the range in which we've assigned new * DLT_ values, only raw "link[N:M]" filtering is supported. */ if (cstate->linktype >= DLT_MATCHING_MIN && cstate->linktype <= DLT_MATCHING_MAX) { cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; } else { bpf_set_error(cstate, "unknown data link type %d (min %d, max %d)", cstate->linktype, DLT_MATCHING_MIN, DLT_MATCHING_MAX); return (-1); } break; } cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr; return (0); } /* * Load a value relative to the specified absolute offset. */ static struct slist * gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset, u_int offset, u_int size) { struct slist *s, *s2; s = gen_abs_offset_varpart(cstate, abs_offset); /* * If "s" is non-null, it has code to arrange that the X register * contains the variable part of the absolute offset, so we * generate a load relative to that, with an offset of * abs_offset->constant_part + offset. * * Otherwise, we can do an absolute load with an offset of * abs_offset->constant_part + offset. */ if (s != NULL) { /* * "s" points to a list of statements that puts the * variable part of the absolute offset into the X register. * Do an indirect load, to use the X register as an offset. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); s2->s.k = abs_offset->constant_part + offset; sappend(s, s2); } else { /* * There is no variable part of the absolute offset, so * just do an absolute load. */ s = new_stmt(cstate, BPF_LD|BPF_ABS|size); s->s.k = abs_offset->constant_part + offset; } return s; } /* * Load a value relative to the beginning of the specified header. */ static struct slist * gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, u_int size) { struct slist *s, *s2; /* * Squelch warnings from compilers that *don't* assume that * offrel always has a valid enum value and therefore don't * assume that we'll always go through one of the case arms. * * If we have a default case, compilers that *do* assume that * will then complain about the default case code being * unreachable. * * Damned if you do, damned if you don't. */ s = NULL; switch (offrel) { case OR_PACKET: s = new_stmt(cstate, BPF_LD|BPF_ABS|size); s->s.k = offset; break; case OR_LINKHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size); break; case OR_PREVLINKHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size); break; case OR_LLC: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size); break; case OR_PREVMPLSHDR: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl - 4 + offset, size); break; case OR_LINKPL: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + offset, size); break; case OR_LINKPL_NOSNAP: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl_nosnap + offset, size); break; case OR_LINKTYPE: s = gen_load_absoffsetrel(cstate, &cstate->off_linktype, offset, size); break; case OR_TRAN_IPV4: /* * Load the X register with the length of the IPv4 header * (plus the offset of the link-layer header, if it's * preceded by a variable-length header such as a radio * header), in bytes. */ s = gen_loadx_iphdrlen(cstate); /* * Load the item at {offset of the link-layer payload} + * {offset, relative to the start of the link-layer * paylod, of the IPv4 header} + {length of the IPv4 header} + * {specified offset}. * * If the offset of the link-layer payload is variable, * the variable part of that offset is included in the * value in the X register, and we include the constant * part in the offset of the load. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + offset; sappend(s, s2); break; case OR_TRAN_IPV6: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size); break; } return s; } /* * Generate code to load into the X register the sum of the length of * the IPv4 header and the variable part of the offset of the link-layer * payload. */ static struct slist * gen_loadx_iphdrlen(compiler_state_t *cstate) { struct slist *s, *s2; s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); if (s != NULL) { /* * The offset of the link-layer payload has a variable * part. "s" points to a list of statements that put * the variable part of that offset into the X register. * * The 4*([k]&0xf) addressing mode can't be used, as we * don't have a constant offset, so we have to load the * value in question into the A register and add to it * the value from the X register. */ s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xf; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); s2->s.k = 2; sappend(s, s2); /* * The A register now contains the length of the IP header. * We need to add to it the variable part of the offset of * the link-layer payload, which is still in the X * register, and move the result into the X register. */ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else { /* * The offset of the link-layer payload is a constant, * so no code was generated to load the (non-existent) * variable part of that offset. * * This means we can use the 4*([k]&0xf) addressing * mode. Load the length of the IPv4 header, which * is at an offset of cstate->off_nl from the beginning of * the link-layer payload, and thus at an offset of * cstate->off_linkpl.constant_part + cstate->off_nl from the beginning * of the raw packet data, using that addressing mode. */ s = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; } return s; } static struct block * gen_uncond(compiler_state_t *cstate, int rsense) { struct block *b; struct slist *s; s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = !rsense; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; return b; } static inline struct block * gen_true(compiler_state_t *cstate) { return gen_uncond(cstate, 1); } static inline struct block * gen_false(compiler_state_t *cstate) { return gen_uncond(cstate, 0); } /* * Byte-swap a 32-bit number. * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on * big-endian platforms.) */ #define SWAPLONG(y) \ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) /* * Generate code to match a particular packet type. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the type/length field or to check the type/length field for * a value <= ETHERMTU to see whether it's a type field and then do * the appropriate test. */ static struct block * gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { struct block *b0, *b1; switch (ll_proto) { case LLCSAP_ISONS: case LLCSAP_IP: case LLCSAP_NETBEUI: /* * OSI protocols and NetBEUI always use 802.2 encapsulation, * so we check the DSAP and SSAP. * * LLCSAP_IP checks for IP-over-802.2, rather * than IP-over-Ethernet or IP-over-SNAP. * * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto); gen_and(b0, b1); return b1; case LLCSAP_IPX: /* * Check for; * * Ethernet_II frames, which are Ethernet * frames with a frame type of ETHERTYPE_IPX; * * Ethernet_802.3 frames, which are 802.3 * frames (i.e., the type/length field is * a length field, <= ETHERMTU, rather than * a type field) with the first two bytes * after the Ethernet/802.3 header being * 0xFFFF; * * Ethernet_802.2 frames, which are 802.3 * frames with an 802.2 LLC header and * with the IPX LSAP as the DSAP in the LLC * header; * * Ethernet_SNAP frames, which are 802.3 * frames with an LLC header and a SNAP * header and with an OUI of 0x000000 * (encapsulated Ethernet) and a protocol * ID of ETHERTYPE_IPX in the SNAP header. * * XXX - should we generate the same code both * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? */ /* * This generates code to check both for the * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. */ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF); gen_or(b0, b1); /* * Now we add code to check for SNAP frames with * ETHERTYPE_IPX, i.e. Ethernet_SNAP. */ b0 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); gen_or(b0, b1); /* * Now we generate code to check for 802.3 * frames in general. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * Now add the check for 802.3 frames before the * check for Ethernet_802.2 and Ethernet_802.3, * as those checks should only be done on 802.3 * frames, not on Ethernet frames. */ gen_and(b0, b1); /* * Now add the check for Ethernet_II frames, and * do that before checking for the other frame * types. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX); gen_or(b0, b1); return b1; case ETHERTYPE_ATALK: case ETHERTYPE_AARP: /* * EtherTalk (AppleTalk protocols on Ethernet link * layer) may use 802.2 encapsulation. */ /* * Check for 802.2 encapsulation (EtherTalk phase 2?); * we check for an Ethernet type field less than * 1500, which means it's an 802.3 length field. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * 802.2-encapsulated ETHERTYPE_AARP packets are * SNAP packets with an organization code of * 0x000000 (encapsulated Ethernet) and a protocol * type of ETHERTYPE_AARP (Appletalk ARP). */ if (ll_proto == ETHERTYPE_ATALK) b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* ll_proto == ETHERTYPE_AARP */ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* * Check for Ethernet encapsulation (Ethertalk * phase 1?); we just check for the Ethernet * protocol type. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); gen_or(b0, b1); return b1; default: if (ll_proto <= ETHERMTU) { /* * This is an LLC SAP value, so the frames * that match would be 802.2 frames. * Check that the frame is an 802.2 frame * (i.e., that the length/type field is * a length field, <= ETHERMTU) and * then check the DSAP. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto); gen_and(b0, b1); return b1; } else { /* * This is an Ethernet type, so compare * the length/type field with it (if * the frame is an 802.2 frame, the length * field will be <= ETHERMTU, and, as * "ll_proto" is > ETHERMTU, this test * will fail and the frame won't match, * which is what we want). */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); } } } static struct block * gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { /* * For DLT_NULL, the link-layer header is a 32-bit word * containing an AF_ value in *host* byte order, and for * DLT_ENC, the link-layer header begins with a 32-bit * word containing an AF_ value in host byte order. * * In addition, if we're reading a saved capture file, * the host byte order in the capture may not be the * same as the host byte order on this machine. * * For DLT_LOOP, the link-layer header is a 32-bit * word containing an AF_ value in *network* byte order. */ if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) { /* * The AF_ value is in host byte order, but the BPF * interpreter will convert it to network byte order. * * If this is a save file, and it's from a machine * with the opposite byte order to ours, we byte-swap * the AF_ value. * * Then we run it through "htonl()", and generate * code to compare against the result. */ if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped) ll_proto = SWAPLONG(ll_proto); ll_proto = htonl(ll_proto); } return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto)); } /* * "proto" is an Ethernet type value and for IPNET, if it is not IPv4 * or IPv6 then we have an error. */ static struct block * gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { switch (ll_proto) { case ETHERTYPE_IP: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET); /*NOTREACHED*/ case ETHERTYPE_IPV6: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6); /*NOTREACHED*/ default: break; } return gen_false(cstate); } /* * Generate code to match a particular packet type. * * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the type field or to check the type field for the special * LINUX_SLL_P_802_2 value and then do the appropriate test. */ static struct block * gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { struct block *b0, *b1; switch (ll_proto) { case LLCSAP_ISONS: case LLCSAP_IP: case LLCSAP_NETBEUI: /* * OSI protocols and NetBEUI always use 802.2 encapsulation, * so we check the DSAP and SSAP. * * LLCSAP_IP checks for IP-over-802.2, rather * than IP-over-Ethernet or IP-over-SNAP. * * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto); gen_and(b0, b1); return b1; case LLCSAP_IPX: /* * Ethernet_II frames, which are Ethernet * frames with a frame type of ETHERTYPE_IPX; * * Ethernet_802.3 frames, which have a frame * type of LINUX_SLL_P_802_3; * * Ethernet_802.2 frames, which are 802.3 * frames with an 802.2 LLC header (i.e, have * a frame type of LINUX_SLL_P_802_2) and * with the IPX LSAP as the DSAP in the LLC * header; * * Ethernet_SNAP frames, which are 802.3 * frames with an LLC header and a SNAP * header and with an OUI of 0x000000 * (encapsulated Ethernet) and a protocol * ID of ETHERTYPE_IPX in the SNAP header. * * First, do the checks on LINUX_SLL_P_802_2 * frames; generate the check for either * Ethernet_802.2 or Ethernet_SNAP frames, and * then put a check for LINUX_SLL_P_802_2 frames * before it. */ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); gen_or(b0, b1); b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); gen_and(b0, b1); /* * Now check for 802.3 frames and OR that with * the previous test. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3); gen_or(b0, b1); /* * Now add the check for Ethernet_II frames, and * do that before checking for the other frame * types. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX); gen_or(b0, b1); return b1; case ETHERTYPE_ATALK: case ETHERTYPE_AARP: /* * EtherTalk (AppleTalk protocols on Ethernet link * layer) may use 802.2 encapsulation. */ /* * Check for 802.2 encapsulation (EtherTalk phase 2?); * we check for the 802.2 protocol type in the * "Ethernet type" field. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * 802.2-encapsulated ETHERTYPE_AARP packets are * SNAP packets with an organization code of * 0x000000 (encapsulated Ethernet) and a protocol * type of ETHERTYPE_AARP (Appletalk ARP). */ if (ll_proto == ETHERTYPE_ATALK) b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* ll_proto == ETHERTYPE_AARP */ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* * Check for Ethernet encapsulation (Ethertalk * phase 1?); we just check for the Ethernet * protocol type. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); gen_or(b0, b1); return b1; default: if (ll_proto <= ETHERMTU) { /* * This is an LLC SAP value, so the frames * that match would be 802.2 frames. * Check for the 802.2 protocol type * in the "Ethernet type" field, and * then check the DSAP. */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B, ll_proto); gen_and(b0, b1); return b1; } else { /* * This is an Ethernet type, so compare * the length/type field with it (if * the frame is an 802.2 frame, the length * field will be <= ETHERMTU, and, as * "ll_proto" is > ETHERMTU, this test * will fail and the frame won't match, * which is what we want). */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); } } } /* * Load a value relative to the beginning of the link-layer header after the * pflog header. */ static struct slist * gen_load_pflog_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the pflog header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) */ if (cstate->off_linkpl.reg != -1) { /* * The length is in the first byte of the header. */ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 0; /* * Round it up to a multiple of 4. * Add 3, and clear the lower 2 bits. */ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s2->s.k = 3; sappend(s1, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xfffffffc; sappend(s1, s2); /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } static struct slist * gen_load_prism_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; struct slist *sjeq_avs_cookie; struct slist *sjcommon; /* * This code is not compatible with the optimizer, as * we are generating jmp instructions within a normal * slist of instructions */ cstate->no_optimize = 1; /* * Generate code to load the length of the radio header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) * * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes * or always use the AVS header rather than the Prism header. * We load a 4-byte big-endian value at the beginning of the * raw packet data, and see whether, when masked with 0xFFFFF000, * it's equal to 0x80211000. If so, that indicates that it's * an AVS header (the masked-out bits are the version number). * Otherwise, it's a Prism header. * * XXX - the Prism header is also, in theory, variable-length, * but no known software generates headers that aren't 144 * bytes long. */ if (cstate->off_linkhdr.reg != -1) { /* * Load the cookie. */ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s1->s.k = 0; /* * AND it with 0xFFFFF000. */ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xFFFFF000; sappend(s1, s2); /* * Compare with 0x80211000. */ sjeq_avs_cookie = new_stmt(cstate, JMP(BPF_JEQ)); sjeq_avs_cookie->s.k = 0x80211000; sappend(s1, sjeq_avs_cookie); /* * If it's AVS: * * The 4 bytes at an offset of 4 from the beginning of * the AVS header are the length of the AVS header. * That field is big-endian. */ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s2->s.k = 4; sappend(s1, s2); sjeq_avs_cookie->s.jt = s2; /* * Now jump to the code to allocate a register * into which to save the header length and * store the length there. (The "jump always" * instruction needs to have the k field set; * it's added to the PC, so, as we're jumping * over a single instruction, it should be 1.) */ sjcommon = new_stmt(cstate, JMP(BPF_JA)); sjcommon->s.k = 1; sappend(s1, sjcommon); /* * Now for the code that handles the Prism header. * Just load the length of the Prism header (144) * into the A register. Have the test for an AVS * header branch here if we don't have an AVS header. */ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); s2->s.k = 144; sappend(s1, s2); sjeq_avs_cookie->s.jf = s2; /* * Now allocate a register to hold that value and store * it. The code for the AVS header will jump here after * loading the length of the AVS header. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); sjcommon->s.jf = s2; /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } static struct slist * gen_load_avs_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the AVS header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) */ if (cstate->off_linkhdr.reg != -1) { /* * The 4 bytes at an offset of 4 from the beginning of * the AVS header are the length of the AVS header. * That field is big-endian. */ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s1->s.k = 4; /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } static struct slist * gen_load_radiotap_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the radiotap header into * the register assigned to hold that length, if one has been * assigned. (If one hasn't been assigned, no code we've * generated uses that prefix, so we don't need to generate any * code to load it.) */ if (cstate->off_linkhdr.reg != -1) { /* * The 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap * header; unfortunately, it's little-endian, so we have * to load it a byte at a time and construct the value. */ /* * Load the high-order byte, at an offset of 3, shift it * left a byte, and put the result in the X register. */ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); /* * Load the next byte, at an offset of 2, and OR the * value from the X register into it. */ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); sappend(s1, s2); /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } /* * At the moment we treat PPI as normal Radiotap encoded * packets. The difference is in the function that generates * the code at the beginning to compute the header length. * Since this code generator of PPI supports bare 802.11 * encapsulation only (i.e. the encapsulated DLT should be * DLT_IEEE802_11) we generate code to check for this too; * that's done in finish_parse(). */ static struct slist * gen_load_ppi_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; /* * Generate code to load the length of the radiotap header * into the register assigned to hold that length, if one has * been assigned. */ if (cstate->off_linkhdr.reg != -1) { /* * The 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap * header; unfortunately, it's little-endian, so we have * to load it a byte at a time and construct the value. */ /* * Load the high-order byte, at an offset of 3, shift it * left a byte, and put the result in the X register. */ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); /* * Load the next byte, at an offset of 2, and OR the * value from the X register into it. */ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); sappend(s1, s2); /* * Now allocate a register to hold that value and store * it. */ s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkhdr.reg; sappend(s1, s2); /* * Now move it into the X register. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); } else return (NULL); } /* * Load a value relative to the beginning of the link-layer header after the 802.11 * header, i.e. LLC_SNAP. * The link-layer header doesn't necessarily begin at the beginning * of the packet data; there might be a variable-length prefix containing * radio information. */ static struct slist * gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct slist *snext) { struct slist *s2; struct slist *sjset_data_frame_1; struct slist *sjset_data_frame_2; struct slist *sjset_qos; struct slist *sjset_radiotap_flags_present; struct slist *sjset_radiotap_ext_present; struct slist *sjset_radiotap_tsft_present; struct slist *sjset_tsft_datapad, *sjset_notsft_datapad; struct slist *s_roundup; if (cstate->off_linkpl.reg == -1) { /* * No register has been assigned to the offset of * the link-layer payload, which means nobody needs * it; don't bother computing it - just return * what we already have. */ return (s); } /* * This code is not compatible with the optimizer, as * we are generating jmp instructions within a normal * slist of instructions */ cstate->no_optimize = 1; /* * If "s" is non-null, it has code to arrange that the X register * contains the length of the prefix preceding the link-layer * header. * * Otherwise, the length of the prefix preceding the link-layer * header is "off_outermostlinkhdr.constant_part". */ if (s == NULL) { /* * There is no variable-length header preceding the * link-layer header. * * Load the length of the fixed-length prefix preceding * the link-layer header (if any) into the X register, * and store it in the cstate->off_linkpl.reg register. * That length is off_outermostlinkhdr.constant_part. */ s = new_stmt(cstate, BPF_LDX|BPF_IMM); s->s.k = cstate->off_outermostlinkhdr.constant_part; } /* * The X register contains the offset of the beginning of the * link-layer header; add 24, which is the minimum length * of the MAC header for a data frame, to that, and store it * in cstate->off_linkpl.reg, and then load the Frame Control field, * which is at the offset in the X register, with an indexed load. */ s2 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s2->s.k = 24; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s2->s.k = 0; sappend(s, s2); /* * Check the Frame Control field to see if this is a data frame; * a data frame has the 0x08 bit (b3) in that field set and the * 0x04 bit (b2) clear. */ sjset_data_frame_1 = new_stmt(cstate, JMP(BPF_JSET)); sjset_data_frame_1->s.k = 0x08; sappend(s, sjset_data_frame_1); /* * If b3 is set, test b2, otherwise go to the first statement of * the rest of the program. */ sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(cstate, JMP(BPF_JSET)); sjset_data_frame_2->s.k = 0x04; sappend(s, sjset_data_frame_2); sjset_data_frame_1->s.jf = snext; /* * If b2 is not set, this is a data frame; test the QoS bit. * Otherwise, go to the first statement of the rest of the * program. */ sjset_data_frame_2->s.jt = snext; sjset_data_frame_2->s.jf = sjset_qos = new_stmt(cstate, JMP(BPF_JSET)); sjset_qos->s.k = 0x80; /* QoS bit */ sappend(s, sjset_qos); /* * If it's set, add 2 to cstate->off_linkpl.reg, to skip the QoS * field. * Otherwise, go to the first statement of the rest of the * program. */ sjset_qos->s.jt = s2 = new_stmt(cstate, BPF_LD|BPF_MEM); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 2; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); /* * If we have a radiotap header, look at it to see whether * there's Atheros padding between the MAC-layer header * and the payload. * * Note: all of the fields in the radiotap header are * little-endian, so we byte-swap all of the values * we test against, as they will be loaded as big-endian * values. * * XXX - in the general case, we would have to scan through * *all* the presence bits, if there's more than one word of * presence bits. That would require a loop, meaning that * we wouldn't be able to run the filter in the kernel. * * We assume here that the Atheros adapters that insert the * annoying padding don't have multiple antennae and therefore * do not generate radiotap headers with multiple presence words. */ if (cstate->linktype == DLT_IEEE802_11_RADIO) { /* * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set * in the first presence flag word? */ sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W); s2->s.k = 4; sappend(s, s2); sjset_radiotap_flags_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_flags_present->s.k = SWAPLONG(0x00000002); sappend(s, sjset_radiotap_flags_present); /* * If not, skip all of this. */ sjset_radiotap_flags_present->s.jf = snext; /* * Otherwise, is the "extension" bit set in that word? */ sjset_radiotap_ext_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_ext_present->s.k = SWAPLONG(0x80000000); sappend(s, sjset_radiotap_ext_present); sjset_radiotap_flags_present->s.jt = sjset_radiotap_ext_present; /* * If so, skip all of this. */ sjset_radiotap_ext_present->s.jt = snext; /* * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set? */ sjset_radiotap_tsft_present = new_stmt(cstate, JMP(BPF_JSET)); sjset_radiotap_tsft_present->s.k = SWAPLONG(0x00000001); sappend(s, sjset_radiotap_tsft_present); sjset_radiotap_ext_present->s.jf = sjset_radiotap_tsft_present; /* * If IEEE80211_RADIOTAP_TSFT is set, the flags field is * at an offset of 16 from the beginning of the raw packet * data (8 bytes for the radiotap header and 8 bytes for * the TSFT field). * * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s2->s.k = 16; sappend(s, s2); sjset_radiotap_tsft_present->s.jt = s2; sjset_tsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_tsft_datapad->s.k = 0x20; sappend(s, sjset_tsft_datapad); /* * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is * at an offset of 8 from the beginning of the raw packet * data (8 bytes for the radiotap header). * * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s2->s.k = 8; sappend(s, s2); sjset_radiotap_tsft_present->s.jf = s2; sjset_notsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_notsft_datapad->s.k = 0x20; sappend(s, sjset_notsft_datapad); /* * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is * set, round the length of the 802.11 header to * a multiple of 4. Do that by adding 3 and then * dividing by and multiplying by 4, which we do by * ANDing with ~3. */ s_roundup = new_stmt(cstate, BPF_LD|BPF_MEM); s_roundup->s.k = cstate->off_linkpl.reg; sappend(s, s_roundup); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 3; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM); s2->s.k = (bpf_u_int32)~3; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); sjset_tsft_datapad->s.jt = s_roundup; sjset_tsft_datapad->s.jf = snext; sjset_notsft_datapad->s.jt = s_roundup; sjset_notsft_datapad->s.jf = snext; } else sjset_qos->s.jf = snext; return s; } static void insert_compute_vloffsets(compiler_state_t *cstate, struct block *b) { struct slist *s; /* There is an implicit dependency between the link * payload and link header since the payload computation * includes the variable part of the header. Therefore, * if nobody else has allocated a register for the link * header and we need it, do it now. */ if (cstate->off_linkpl.reg != -1 && cstate->off_linkhdr.is_variable && cstate->off_linkhdr.reg == -1) cstate->off_linkhdr.reg = alloc_reg(cstate); /* * For link-layer types that have a variable-length header * preceding the link-layer header, generate code to load * the offset of the link-layer header into the register * assigned to that offset, if any. * * XXX - this, and the next switch statement, won't handle * encapsulation of 802.11 or 802.11+radio information in * some other protocol stack. That's significantly more * complicated. */ switch (cstate->outermostlinktype) { case DLT_PRISM_HEADER: s = gen_load_prism_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO_AVS: s = gen_load_avs_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO: s = gen_load_radiotap_llprefixlen(cstate); break; case DLT_PPI: s = gen_load_ppi_llprefixlen(cstate); break; default: s = NULL; break; } /* * For link-layer types that have a variable-length link-layer * header, generate code to load the offset of the link-layer * payload into the register assigned to that offset, if any. */ switch (cstate->outermostlinktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: s = gen_load_802_11_header_len(cstate, s, b->stmts); break; case DLT_PFLOG: s = gen_load_pflog_llprefixlen(cstate); break; } /* * If there is no initialization yet and we need variable * length offsets for VLAN, initialize them to zero */ if (s == NULL && cstate->is_vlan_vloffset) { struct slist *s2; if (cstate->off_linkpl.reg == -1) cstate->off_linkpl.reg = alloc_reg(cstate); if (cstate->off_linktype.reg == -1) cstate->off_linktype.reg = alloc_reg(cstate); s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); s->s.k = 0; s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = cstate->off_linktype.reg; sappend(s, s2); } /* * If we have any offset-loading code, append all the * existing statements in the block to those statements, * and make the resulting list the list of statements * for the block. */ if (s != NULL) { sappend(s, b->stmts); b->stmts = s; } } static struct block * gen_ppi_dlt_check(compiler_state_t *cstate) { struct slist *s_load_dlt; struct block *b; if (cstate->linktype == DLT_PPI) { /* Create the statements that check for the DLT */ s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s_load_dlt->s.k = 4; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s_load_dlt; b->s.k = SWAPLONG(DLT_IEEE802_11); } else { b = NULL; } return b; } /* * Take an absolute offset, and: * * if it has no variable part, return NULL; * * if it has a variable part, generate code to load the register * containing that variable part into the X register, returning * a pointer to that code - if no register for that offset has * been allocated, allocate it first. * * (The code to set that register will be generated later, but will * be placed earlier in the code sequence.) */ static struct slist * gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off) { struct slist *s; if (off->is_variable) { if (off->reg == -1) { /* * We haven't yet assigned a register for the * variable part of the offset of the link-layer * header; allocate one. */ off->reg = alloc_reg(cstate); } /* * Load the register containing the variable part of the * offset of the link-layer header into the X register. */ s = new_stmt(cstate, BPF_LDX|BPF_MEM); s->s.k = off->reg; return s; } else { /* * That offset isn't variable, there's no variable part, * so we don't need to generate any code. */ return NULL; } } /* * Map an Ethernet type to the equivalent PPP type. */ static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32 ll_proto) { switch (ll_proto) { case ETHERTYPE_IP: ll_proto = PPP_IP; break; case ETHERTYPE_IPV6: ll_proto = PPP_IPV6; break; case ETHERTYPE_DN: ll_proto = PPP_DECNET; break; case ETHERTYPE_ATALK: ll_proto = PPP_APPLE; break; case ETHERTYPE_NS: ll_proto = PPP_NS; break; case LLCSAP_ISONS: ll_proto = PPP_OSI; break; case LLCSAP_8021D: /* * I'm assuming the "Bridging PDU"s that go * over PPP are Spanning Tree Protocol * Bridging PDUs. */ ll_proto = PPP_BRPDU; break; case LLCSAP_IPX: ll_proto = PPP_IPX; break; } return (ll_proto); } /* * Generate any tests that, for encapsulation of a link-layer packet * inside another protocol stack, need to be done to check for those * link-layer packets (and that haven't already been done by a check * for that encapsulation). */ static struct block * gen_prevlinkhdr_check(compiler_state_t *cstate) { struct block *b0; if (cstate->is_geneve) return gen_geneve_ll_check(cstate); switch (cstate->prevlinktype) { case DLT_SUNATM: /* * This is LANE-encapsulated Ethernet; check that the LANE * packet doesn't begin with an LE Control marker, i.e. * that it's data, not a control message. * * (We've already generated a test for LANE.) */ b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); gen_not(b0); return b0; default: /* * No such tests are necessary. */ return NULL; } /*NOTREACHED*/ } /* * The three different values we should check for when checking for an * IPv6 packet with DLT_NULL. */ #define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */ #define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */ #define BSD_AFNUM_INET6_DARWIN 30 /* macOS, iOS, other Darwin-based OSes */ /* * Generate code to match a particular packet type by matching the * link-layer type field or fields in the 802.2 LLC header. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. */ static struct block * gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { struct block *b0, *b1, *b2; const char *description; /* are we checking MPLS-encapsulated packets? */ if (cstate->label_stack_depth > 0) return gen_mpls_linktype(cstate, ll_proto); switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: /* Geneve has an EtherType regardless of whether there is an * L2 header. */ if (!cstate->is_geneve) b0 = gen_prevlinkhdr_check(cstate); else b0 = NULL; b1 = gen_ether_linktype(cstate, ll_proto); if (b0 != NULL) gen_and(b0, b1); return b1; /*NOTREACHED*/ case DLT_C_HDLC: case DLT_HDLC: switch (ll_proto) { case LLCSAP_ISONS: ll_proto = (ll_proto << 8 | LLCSAP_ISONS); /* fall through */ default: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); /*NOTREACHED*/ } case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: /* * Check that we have a data frame. */ b0 = gen_check_802_11_data_frame(cstate); /* * Now check for the specified link-layer type. */ b1 = gen_llc_linktype(cstate, ll_proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ case DLT_FDDI: /* * XXX - check for LLC frames. */ return gen_llc_linktype(cstate, ll_proto); /*NOTREACHED*/ case DLT_IEEE802: /* * XXX - check for LLC PDUs, as per IEEE 802.5. */ return gen_llc_linktype(cstate, ll_proto); /*NOTREACHED*/ case DLT_ATM_RFC1483: case DLT_ATM_CLIP: case DLT_IP_OVER_FC: return gen_llc_linktype(cstate, ll_proto); /*NOTREACHED*/ case DLT_SUNATM: /* * Check for an LLC-encapsulated version of this protocol; * if we were checking for LANE, linktype would no longer * be DLT_SUNATM. * * Check for LLC encapsulation and then check the protocol. */ b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); b1 = gen_llc_linktype(cstate, ll_proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ case DLT_LINUX_SLL: return gen_linux_sll_linktype(cstate, ll_proto); /*NOTREACHED*/ case DLT_SLIP: case DLT_SLIP_BSDOS: case DLT_RAW: /* * These types don't provide any type field; packets * are always IPv4 or IPv6. * * XXX - for IPv4, check for a version number of 4, and, * for IPv6, check for a version number of 6? */ switch (ll_proto) { case ETHERTYPE_IP: /* Check for a version number of 4. */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0); case ETHERTYPE_IPV6: /* Check for a version number of 6. */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0); default: return gen_false(cstate); /* always false */ } /*NOTREACHED*/ case DLT_IPV4: /* * Raw IPv4, so no type field. */ if (ll_proto == ETHERTYPE_IP) return gen_true(cstate); /* always true */ /* Checking for something other than IPv4; always false */ return gen_false(cstate); /*NOTREACHED*/ case DLT_IPV6: /* * Raw IPv6, so no type field. */ if (ll_proto == ETHERTYPE_IPV6) return gen_true(cstate); /* always true */ /* Checking for something other than IPv6; always false */ return gen_false(cstate); /*NOTREACHED*/ case DLT_PPP: case DLT_PPP_PPPD: case DLT_PPP_SERIAL: case DLT_PPP_ETHER: /* * We use Ethernet protocol types inside libpcap; * map them to the corresponding PPP protocol types. */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ethertype_to_ppptype(ll_proto)); /*NOTREACHED*/ case DLT_PPP_BSDOS: /* * We use Ethernet protocol types inside libpcap; * map them to the corresponding PPP protocol types. */ switch (ll_proto) { case ETHERTYPE_IP: /* * Also check for Van Jacobson-compressed IP. * XXX - do this for other forms of PPP? */ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_IP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJC); gen_or(b0, b1); b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC); gen_or(b1, b0); return b0; default: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ethertype_to_ppptype(ll_proto)); } /*NOTREACHED*/ case DLT_NULL: case DLT_LOOP: case DLT_ENC: switch (ll_proto) { case ETHERTYPE_IP: return (gen_loopback_linktype(cstate, AF_INET)); case ETHERTYPE_IPV6: /* * AF_ values may, unfortunately, be platform- * dependent; AF_INET isn't, because everybody * used 4.2BSD's value, but AF_INET6 is, because * 4.2BSD didn't have a value for it (given that * IPv6 didn't exist back in the early 1980's), * and they all picked their own values. * * This means that, if we're reading from a * savefile, we need to check for all the * possible values. * * If we're doing a live capture, we only need * to check for this platform's value; however, * Npcap uses 24, which isn't Windows's AF_INET6 * value. (Given the multiple different values, * programs that read pcap files shouldn't be * checking for their platform's AF_INET6 value * anyway, they should check for all of the * possible values. and they might as well do * that even for live captures.) */ if (cstate->bpf_pcap->rfile != NULL) { /* * Savefile - check for all three * possible IPv6 values. */ b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD); b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD); gen_or(b0, b1); b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN); gen_or(b0, b1); return (b1); } else { /* * Live capture, so we only need to * check for the value used on this * platform. */ #ifdef _WIN32 /* * Npcap doesn't use Windows's AF_INET6, * as that collides with AF_IPX on * some BSDs (both have the value 23). * Instead, it uses 24. */ return (gen_loopback_linktype(cstate, 24)); #else /* _WIN32 */ #ifdef AF_INET6 return (gen_loopback_linktype(cstate, AF_INET6)); #else /* AF_INET6 */ /* * I guess this platform doesn't support * IPv6, so we just reject all packets. */ return gen_false(cstate); #endif /* AF_INET6 */ #endif /* _WIN32 */ } default: /* * Not a type on which we support filtering. * XXX - support those that have AF_ values * #defined on this platform, at least? */ return gen_false(cstate); } case DLT_PFLOG: /* * af field is host byte order in contrast to the rest of * the packet. */ if (ll_proto == ETHERTYPE_IP) return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, AF_INET)); else if (ll_proto == ETHERTYPE_IPV6) return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, AF_INET6)); else return gen_false(cstate); /*NOTREACHED*/ case DLT_ARCNET: case DLT_ARCNET_LINUX: /* * XXX should we check for first fragment if the protocol * uses PHDS? */ switch (ll_proto) { default: return gen_false(cstate); case ETHERTYPE_IPV6: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_INET6)); case ETHERTYPE_IP: b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_IP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_IP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_ARP: b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_ARP); b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_ARP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_REVARP: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_REVARP)); case ETHERTYPE_ATALK: return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, ARCTYPE_ATALK)); } /*NOTREACHED*/ case DLT_LTALK: switch (ll_proto) { case ETHERTYPE_ATALK: return gen_true(cstate); default: return gen_false(cstate); } /*NOTREACHED*/ case DLT_FRELAY: /* * XXX - assumes a 2-byte Frame Relay header with * DLCI and flags. What if the address is longer? */ switch (ll_proto) { case ETHERTYPE_IP: /* * Check for the special NLPID for IP. */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc); case ETHERTYPE_IPV6: /* * Check for the special NLPID for IPv6. */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e); case LLCSAP_ISONS: /* * Check for several OSI protocols. * * Frame Relay packets typically have an OSI * NLPID at the beginning; we check for each * of them. * * What we check for is the NLPID and a frame * control field of UI, i.e. 0x03 followed * by the NLPID. */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP); b1 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS); b2 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS); gen_or(b1, b2); gen_or(b0, b2); return b2; default: return gen_false(cstate); } /*NOTREACHED*/ case DLT_MFR: bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented"); case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: case DLT_JUNIPER_ATM2: case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_PPPOE_ATM: case DLT_JUNIPER_GGSN: case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: case DLT_JUNIPER_ETHER: case DLT_JUNIPER_PPP: case DLT_JUNIPER_FRELAY: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_VP: case DLT_JUNIPER_ST: case DLT_JUNIPER_ISM: case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: /* just lets verify the magic number for now - * on ATM we may have up to 6 different encapsulations on the wire * and need a lot of heuristics to figure out that the payload * might be; * * FIXME encapsulation specific BPF_ filters */ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */ case DLT_BACNET_MS_TP: return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000); case DLT_IPNET: return gen_ipnet_linktype(cstate, ll_proto); case DLT_LINUX_IRDA: bpf_error(cstate, "IrDA link-layer type filtering not implemented"); case DLT_DOCSIS: bpf_error(cstate, "DOCSIS link-layer type filtering not implemented"); case DLT_MTP2: case DLT_MTP2_WITH_PHDR: bpf_error(cstate, "MTP2 link-layer type filtering not implemented"); case DLT_ERF: bpf_error(cstate, "ERF link-layer type filtering not implemented"); case DLT_PFSYNC: bpf_error(cstate, "PFSYNC link-layer type filtering not implemented"); case DLT_LINUX_LAPD: bpf_error(cstate, "LAPD link-layer type filtering not implemented"); case DLT_USB_FREEBSD: case DLT_USB_LINUX: case DLT_USB_LINUX_MMAPPED: case DLT_USBPCAP: bpf_error(cstate, "USB link-layer type filtering not implemented"); case DLT_BLUETOOTH_HCI_H4: case DLT_BLUETOOTH_HCI_H4_WITH_PHDR: bpf_error(cstate, "Bluetooth link-layer type filtering not implemented"); case DLT_CAN20B: case DLT_CAN_SOCKETCAN: bpf_error(cstate, "CAN link-layer type filtering not implemented"); case DLT_IEEE802_15_4: case DLT_IEEE802_15_4_LINUX: case DLT_IEEE802_15_4_NONASK_PHY: case DLT_IEEE802_15_4_NOFCS: case DLT_IEEE802_15_4_TAP: bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented"); case DLT_IEEE802_16_MAC_CPS_RADIO: bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented"); case DLT_SITA: bpf_error(cstate, "SITA link-layer type filtering not implemented"); case DLT_RAIF1: bpf_error(cstate, "RAIF1 link-layer type filtering not implemented"); case DLT_IPMB_KONTRON: case DLT_IPMB_LINUX: bpf_error(cstate, "IPMB link-layer type filtering not implemented"); case DLT_AX25_KISS: bpf_error(cstate, "AX.25 link-layer type filtering not implemented"); case DLT_NFLOG: /* Using the fixed-size NFLOG header it is possible to tell only * the address family of the packet, other meaningful data is * either missing or behind TLVs. */ bpf_error(cstate, "NFLOG link-layer type filtering not implemented"); default: /* * Does this link-layer header type have a field * indicating the type of the next protocol? If * so, off_linktype.constant_part will be the offset of that * field in the packet; if not, it will be OFFSET_NOT_SET. */ if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) { /* * Yes; assume it's an Ethernet type. (If * it's not, it needs to be handled specially * above.) */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); /*NOTREACHED */ } else { /* * No; report an error. */ description = pcap_datalink_val_to_description_or_dlt(cstate->linktype); bpf_error(cstate, "%s link-layer type filtering not implemented", description); /*NOTREACHED */ } } } /* * Check for an LLC SNAP packet with a given organization code and * protocol type; we check the entire contents of the 802.2 LLC and * snap headers, checking for DSAP and SSAP of SNAP and a control * field of 0x03 in the LLC header, and for the specified organization * code and protocol type in the SNAP header. */ static struct block * gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) { u_char snapblock[8]; snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ snapblock[2] = 0x03; /* control = UI */ snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */ snapblock[4] = (u_char)(orgcode >> 8); /* middle 8 bits of organization code */ snapblock[5] = (u_char)(orgcode >> 0); /* lower 8 bits of organization code */ snapblock[6] = (u_char)(ptype >> 8); /* upper 8 bits of protocol type */ snapblock[7] = (u_char)(ptype >> 0); /* lower 8 bits of protocol type */ return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock); } /* * Generate code to match frames with an LLC header. */ static struct block * gen_llc_internal(compiler_state_t *cstate) { struct block *b0, *b1; switch (cstate->linktype) { case DLT_EN10MB: /* * We check for an Ethernet type field less than * 1500, which means it's an 802.3 length field. */ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* * Now check for the purported DSAP and SSAP not being * 0xFF, to rule out NetWare-over-802.3. */ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF); gen_not(b1); gen_and(b0, b1); return b1; case DLT_SUNATM: /* * We check for LLC traffic. */ b0 = gen_atmtype_llc(cstate); return b0; case DLT_IEEE802: /* Token Ring */ /* * XXX - check for LLC frames. */ return gen_true(cstate); case DLT_FDDI: /* * XXX - check for LLC frames. */ return gen_true(cstate); case DLT_ATM_RFC1483: /* * For LLC encapsulation, these are defined to have an * 802.2 LLC header. * * For VC encapsulation, they don't, but there's no * way to check for that; the protocol used on the VC * is negotiated out of band. */ return gen_true(cstate); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11_RADIO_AVS: case DLT_PPI: /* * Check that we have a data frame. */ b0 = gen_check_802_11_data_frame(cstate); return b0; default: bpf_error(cstate, "'llc' not supported for %s", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ } } struct block * gen_llc(compiler_state_t *cstate) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_llc_internal(cstate); } struct block * gen_llc_i(compiler_state_t *cstate) { struct block *b0, *b1; struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Check whether this is an LLC frame. */ b0 = gen_llc_internal(cstate); /* * Load the control byte and test the low-order bit; it must * be clear for I frames. */ s = gen_load_a(cstate, OR_LLC, 2, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; b1->stmts = s; gen_not(b1); gen_and(b0, b1); return b1; } struct block * gen_llc_s(compiler_state_t *cstate) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Check whether this is an LLC frame. */ b0 = gen_llc_internal(cstate); /* * Now compare the low-order 2 bit of the control byte against * the appropriate value for S frames. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03); gen_and(b0, b1); return b1; } struct block * gen_llc_u(compiler_state_t *cstate) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Check whether this is an LLC frame. */ b0 = gen_llc_internal(cstate); /* * Now compare the low-order 2 bit of the control byte against * the appropriate value for U frames. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03); gen_and(b0, b1); return b1; } struct block * gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Check whether this is an LLC frame. */ b0 = gen_llc_internal(cstate); /* * Now check for an S frame with the appropriate type. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK); gen_and(b0, b1); return b1; } struct block * gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Check whether this is an LLC frame. */ b0 = gen_llc_internal(cstate); /* * Now check for a U frame with the appropriate type. */ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK); gen_and(b0, b1); return b1; } /* * Generate code to match a particular packet type, for link-layer types * using 802.2 LLC headers. * * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the DSAP or both DSAP and LSAP or to check the OUI and * protocol ID in a SNAP header. */ static struct block * gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { /* * XXX - handle token-ring variable-length header. */ switch (ll_proto) { case LLCSAP_IP: case LLCSAP_ISONS: case LLCSAP_NETBEUI: /* * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other SAP values? */ return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32) ((ll_proto << 8) | ll_proto)); case LLCSAP_IPX: /* * XXX - are there ever SNAP frames for IPX on * non-Ethernet 802.x networks? */ return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); case ETHERTYPE_ATALK: /* * 802.2-encapsulated ETHERTYPE_ATALK packets are * SNAP packets with an organization code of * 0x080007 (Apple, for Appletalk) and a protocol * type of ETHERTYPE_ATALK (Appletalk). * * XXX - check for an organization code of * encapsulated Ethernet as well? */ return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); default: /* * XXX - we don't have to check for IPX 802.3 * here, but should we check for the IPX Ethertype? */ if (ll_proto <= ETHERMTU) { /* * This is an LLC SAP value, so check * the DSAP. */ return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto); } else { /* * This is an Ethernet type; we assume that it's * unlikely that it'll appear in the right place * at random, and therefore check only the * location that would hold the Ethernet type * in a SNAP frame with an organization code of * 0x000000 (encapsulated Ethernet). * * XXX - if we were to check for the SNAP DSAP and * LSAP, as per XXX, and were also to check for an * organization code of 0x000000 (encapsulated * Ethernet), we'd do * * return gen_snap(cstate, 0x000000, ll_proto); * * here; for now, we don't, as per the above. * I don't know whether it's worth the extra CPU * time to do the right check or not. */ return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto); } } } static struct block * gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND: b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } b0 = gen_linktype(cstate, ll_proto); b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask); gen_and(b0, b1); return b1; } #ifdef INET6 static struct block * gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; uint32_t *a, *m; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } /* this order is important */ a = (uint32_t *)addr; m = (uint32_t *)mask; b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); gen_and(b0, b1); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); gen_and(b0, b1); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); gen_and(b0, b1); b0 = gen_linktype(cstate, ll_proto); gen_and(b0, b1); return b1; } #endif static struct block * gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr); case Q_AND: b0 = gen_ehostop(cstate, eaddr, Q_SRC); b1 = gen_ehostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ehostop(cstate, eaddr, Q_SRC); b1 = gen_ehostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers"); /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } /* * Like gen_ehostop, but for DLT_FDDI */ static struct block * gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_AND: b0 = gen_fhostop(cstate, eaddr, Q_SRC); b1 = gen_fhostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_fhostop(cstate, eaddr, Q_SRC); b1 = gen_fhostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } /* * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) */ static struct block * gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: b0 = gen_thostop(cstate, eaddr, Q_SRC); b1 = gen_thostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_thostop(cstate, eaddr, Q_SRC); b1 = gen_thostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } /* * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and * various 802.11 + radio headers. */ static struct block * gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1, *b2; register struct slist *s; #ifdef ENABLE_WLAN_FILTERING_PATCH /* * TODO GV 20070613 * We need to disable the optimizer because the optimizer is buggy * and wipes out some LD instructions generated by the below * code to validate the Frame Control bits */ cstate->no_optimize = 1; #endif /* ENABLE_WLAN_FILTERING_PATCH */ switch (dir) { case Q_SRC: /* * Oh, yuk. * * For control frames, there is no SA. * * For management frames, SA is at an * offset of 10 from the beginning of * the packet. * * For data frames, SA is at an offset * of 10 from the beginning of the packet * if From DS is clear, at an offset of * 16 from the beginning of the packet * if From DS is set and To DS is clear, * and an offset of 24 from the beginning * of the packet if From DS is set and To DS * is set. */ /* * Generate the tests to be done for data frames * with From DS set. * * First, check for To DS set, i.e. check "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the SA is at 24. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the SA is at 16. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames with * From DS set. */ gen_or(b1, b0); /* * Now check for From DS being set, and AND that with * the ORed-together checks. */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x02; /* From DS */ b1->stmts = s; gen_and(b1, b0); /* * Now check for data frames with From DS not set. */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x02; /* From DS */ b2->stmts = s; gen_not(b2); /* * If From DS isn't set, the SA is at 10. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* * Now OR together the checks for data frames with * From DS not set and for data frames with From DS * set; that gives the checks done for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the SA is at 10. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case Q_DST: /* * Oh, yuk. * * For control frames, there is no DA. * * For management frames, DA is at an * offset of 4 from the beginning of * the packet. * * For data frames, DA is at an offset * of 4 from the beginning of the packet * if To DS is clear and at an offset of * 16 from the beginning of the packet * if To DS is set. */ /* * Generate the tests to be done for data frames. * * First, check for To DS set, i.e. "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the DA is at 16. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the DA is at 4. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the DA is at 4. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case Q_AND: b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); b1 = gen_wlanhostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); b1 = gen_wlanhostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; /* * XXX - add BSSID keyword? */ case Q_ADDR1: return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); case Q_ADDR2: /* * Not present in CTS or ACK control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b2); gen_and(b1, b2); gen_or(b0, b2); b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; case Q_ADDR3: /* * Not present in control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b0, b1); return b1; case Q_ADDR4: /* * Present only if the direction mask has both "From DS" * and "To DS" set. Neither control frames nor management * frames should have both of those set, so we don't * check the frame type. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); gen_and(b0, b1); return b1; case Q_RA: /* * Not present in management frames; addr1 in other * frames. */ /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * Check addr1. */ b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); /* * AND that with the check of addr1. */ gen_and(b1, b0); return (b0); case Q_TA: /* * Not present in management frames; addr2, if present, * in other frames. */ /* * Not present in CTS or ACK control frames. */ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b2); gen_and(b1, b2); gen_or(b0, b2); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the check for frames other than * CTS and ACK frames. */ gen_and(b1, b2); /* * Check addr2. */ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; } abort(); /*NOTREACHED*/ } /* * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel. * (We assume that the addresses are IEEE 48-bit MAC addresses, * as the RFC states.) */ static struct block * gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); b1 = gen_ipfchostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); b1 = gen_ipfchostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } /* * This is quite tricky because there may be pad bytes in front of the * DECNET header, and then there are two possible data packet formats that * carry both src and dst addresses, plus 5 packet types in a format that * carries only the src node, plus 2 types that use a different format and * also carry just the src node. * * Yuck. * * Instead of doing those all right, we just look for data packets with * 0 or 1 bytes of padding. If you want to look at other packets, that * will require a lot more hacking. * * To add support for filtering on DECNET "areas" (network numbers) * one would want to add a "mask" argument to this routine. That would * make the filter even more inefficient, although one could be clever * and not generate masking instructions if the mask is 0xFFFF. */ static struct block * gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir) { struct block *b0, *b1, *b2, *tmp; u_int offset_lh; /* offset if long header is received */ u_int offset_sh; /* offset if short header is received */ switch (dir) { case Q_DST: offset_sh = 1; /* follows flags */ offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ break; case Q_SRC: offset_sh = 3; /* follows flags, dstnode */ offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ break; case Q_AND: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } b0 = gen_linktype(cstate, ETHERTYPE_DN); /* Check for pad = 1, long header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF)); b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, BPF_H, (bpf_u_int32)ntohs((u_short)addr)); gen_and(tmp, b1); /* Check for pad = 0, long header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x06, (bpf_u_int32)0x7); b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_u_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 1, short header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_u_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF)); b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_u_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 0, short header case */ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x02, (bpf_u_int32)0x7); b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_u_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Combine with test for cstate->linktype */ gen_and(b0, b1); return b1; } /* * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets; * test the bottom-of-stack bit, and then check the version number * field in the IP header. */ static struct block * gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) { struct block *b0, *b1; switch (ll_proto) { case ETHERTYPE_IP: /* match the bottom-of-stack bit */ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0); gen_and(b0, b1); return b1; case ETHERTYPE_IPV6: /* match the bottom-of-stack bit */ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0); gen_and(b0, b1); return b1; default: /* FIXME add other L3 proto IDs */ bpf_error(cstate, "unsupported protocol over mpls"); /*NOTREACHED*/ } } static struct block * gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, int proto, int dir, int type) { struct block *b0, *b1; const char *typestr; if (type == Q_NET) typestr = "net"; else typestr = "host"; switch (proto) { case Q_DEFAULT: b0 = gen_host(cstate, addr, mask, Q_IP, dir, type); /* * Only check for non-IPv4 addresses if we're not * checking MPLS-encapsulated packets. */ if (cstate->label_stack_depth == 0) { b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type); gen_or(b0, b1); b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type); gen_or(b1, b0); } return b0; case Q_LINK: bpf_error(cstate, "link-layer modifier applied to %s", typestr); case Q_IP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); case Q_RARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24); case Q_ARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to %s", typestr); case Q_TCP: bpf_error(cstate, "'tcp' modifier applied to %s", typestr); case Q_UDP: bpf_error(cstate, "'udp' modifier applied to %s", typestr); case Q_ICMP: bpf_error(cstate, "'icmp' modifier applied to %s", typestr); case Q_IGMP: bpf_error(cstate, "'igmp' modifier applied to %s", typestr); case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to %s", typestr); case Q_ATALK: bpf_error(cstate, "AppleTalk host filtering not implemented"); case Q_DECNET: return gen_dnhostop(cstate, addr, dir); case Q_LAT: bpf_error(cstate, "LAT host filtering not implemented"); case Q_SCA: bpf_error(cstate, "SCA host filtering not implemented"); case Q_MOPRC: bpf_error(cstate, "MOPRC host filtering not implemented"); case Q_MOPDL: bpf_error(cstate, "MOPDL host filtering not implemented"); case Q_IPV6: bpf_error(cstate, "'ip6' modifier applied to ip host"); case Q_ICMPV6: bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); case Q_AH: bpf_error(cstate, "'ah' modifier applied to %s", typestr); case Q_ESP: bpf_error(cstate, "'esp' modifier applied to %s", typestr); case Q_PIM: bpf_error(cstate, "'pim' modifier applied to %s", typestr); case Q_VRRP: bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); case Q_AARP: bpf_error(cstate, "AARP host filtering not implemented"); case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); case Q_ESIS: bpf_error(cstate, "'esis' modifier applied to %s", typestr); case Q_ISIS: bpf_error(cstate, "'isis' modifier applied to %s", typestr); case Q_CLNP: bpf_error(cstate, "'clnp' modifier applied to %s", typestr); case Q_STP: bpf_error(cstate, "'stp' modifier applied to %s", typestr); case Q_IPX: bpf_error(cstate, "IPX host filtering not implemented"); case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); case Q_ISIS_L1: bpf_error(cstate, "'l1' modifier applied to %s", typestr); case Q_ISIS_L2: bpf_error(cstate, "'l2' modifier applied to %s", typestr); case Q_ISIS_IIH: bpf_error(cstate, "'iih' modifier applied to %s", typestr); case Q_ISIS_SNP: bpf_error(cstate, "'snp' modifier applied to %s", typestr); case Q_ISIS_CSNP: bpf_error(cstate, "'csnp' modifier applied to %s", typestr); case Q_ISIS_PSNP: bpf_error(cstate, "'psnp' modifier applied to %s", typestr); case Q_ISIS_LSP: bpf_error(cstate, "'lsp' modifier applied to %s", typestr); case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to %s", typestr); case Q_CARP: bpf_error(cstate, "'carp' modifier applied to %s", typestr); default: abort(); } /*NOTREACHED*/ } #ifdef INET6 static struct block * gen_host6(compiler_state_t *cstate, struct in6_addr *addr, struct in6_addr *mask, int proto, int dir, int type) { const char *typestr; if (type == Q_NET) typestr = "net"; else typestr = "host"; switch (proto) { case Q_DEFAULT: return gen_host6(cstate, addr, mask, Q_IPV6, dir, type); case Q_LINK: bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr); case Q_IP: bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr); case Q_RARP: bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr); case Q_ARP: bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr); case Q_TCP: bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr); case Q_UDP: bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr); case Q_ICMP: bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr); case Q_IGMP: bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr); case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr); case Q_ATALK: bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr); case Q_DECNET: bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); case Q_LAT: bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr); case Q_SCA: bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr); case Q_MOPRC: bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr); case Q_MOPDL: bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr); case Q_IPV6: return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr); case Q_AH: bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr); case Q_ESP: bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr); case Q_PIM: bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr); case Q_VRRP: bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr); case Q_AARP: bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr); case Q_ISO: bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr); case Q_ESIS: bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr); case Q_ISIS: bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr); case Q_CLNP: bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr); case Q_STP: bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr); case Q_IPX: bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr); case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr); case Q_ISIS_L1: bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr); case Q_ISIS_L2: bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr); case Q_ISIS_IIH: bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr); case Q_ISIS_SNP: bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr); case Q_ISIS_CSNP: bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr); case Q_ISIS_PSNP: bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr); case Q_ISIS_LSP: bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr); case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr); case Q_CARP: bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr); default: abort(); } /*NOTREACHED*/ } #endif #ifndef INET6 static struct block * gen_gateway(compiler_state_t *cstate, const u_char *eaddr, struct addrinfo *alist, int proto, int dir) { struct block *b0, *b1, *tmp; struct addrinfo *ai; struct sockaddr_in *sin; if (dir != 0) bpf_error(cstate, "direction applied to 'gateway'"); switch (proto) { case Q_DEFAULT: case Q_IP: case Q_ARP: case Q_RARP: switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); b0 = gen_ehostop(cstate, eaddr, Q_OR); if (b1 != NULL) gen_and(b1, b0); break; case DLT_FDDI: b0 = gen_fhostop(cstate, eaddr, Q_OR); break; case DLT_IEEE802: b0 = gen_thostop(cstate, eaddr, Q_OR); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: b0 = gen_wlanhostop(cstate, eaddr, Q_OR); break; case DLT_SUNATM: /* * This is LLC-multiplexed traffic; if it were * LANE, cstate->linktype would have been set to * DLT_EN10MB. */ bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); break; case DLT_IP_OVER_FC: b0 = gen_ipfchostop(cstate, eaddr, Q_OR); break; default: bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); } b1 = NULL; for (ai = alist; ai != NULL; ai = ai->ai_next) { /* * Does it have an address? */ if (ai->ai_addr != NULL) { /* * Yes. Is it an IPv4 address? */ if (ai->ai_addr->sa_family == AF_INET) { /* * Generate an entry for it. */ sin = (struct sockaddr_in *)ai->ai_addr; tmp = gen_host(cstate, ntohl(sin->sin_addr.s_addr), 0xffffffff, proto, Q_OR, Q_HOST); /* * Is it the *first* IPv4 address? */ if (b1 == NULL) { /* * Yes, so start with it. */ b1 = tmp; } else { /* * No, so OR it into the * existing set of * addresses. */ gen_or(b1, tmp); b1 = tmp; } } } } if (b1 == NULL) { /* * No IPv4 addresses found. */ return (NULL); } gen_not(b1); gen_and(b0, b1); return b1; } bpf_error(cstate, "illegal modifier of 'gateway'"); /*NOTREACHED*/ } #endif static struct block * gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) { struct block *b0; struct block *b1; switch (proto) { case Q_SCTP: b1 = gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT, Q_DEFAULT); break; case Q_TCP: b1 = gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT, Q_DEFAULT); break; case Q_UDP: b1 = gen_proto(cstate, IPPROTO_UDP, Q_DEFAULT, Q_DEFAULT); break; case Q_ICMP: b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_IGMP #define IPPROTO_IGMP 2 #endif case Q_IGMP: b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_IGRP #define IPPROTO_IGRP 9 #endif case Q_IGRP: b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_PIM #define IPPROTO_PIM 103 #endif case Q_PIM: b1 = gen_proto(cstate, IPPROTO_PIM, Q_DEFAULT, Q_DEFAULT); break; #ifndef IPPROTO_VRRP #define IPPROTO_VRRP 112 #endif case Q_VRRP: b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_CARP #define IPPROTO_CARP 112 #endif case Q_CARP: b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT); break; case Q_IP: b1 = gen_linktype(cstate, ETHERTYPE_IP); break; case Q_ARP: b1 = gen_linktype(cstate, ETHERTYPE_ARP); break; case Q_RARP: b1 = gen_linktype(cstate, ETHERTYPE_REVARP); break; case Q_LINK: bpf_error(cstate, "link layer applied in wrong context"); case Q_ATALK: b1 = gen_linktype(cstate, ETHERTYPE_ATALK); break; case Q_AARP: b1 = gen_linktype(cstate, ETHERTYPE_AARP); break; case Q_DECNET: b1 = gen_linktype(cstate, ETHERTYPE_DN); break; case Q_SCA: b1 = gen_linktype(cstate, ETHERTYPE_SCA); break; case Q_LAT: b1 = gen_linktype(cstate, ETHERTYPE_LAT); break; case Q_MOPDL: b1 = gen_linktype(cstate, ETHERTYPE_MOPDL); break; case Q_MOPRC: b1 = gen_linktype(cstate, ETHERTYPE_MOPRC); break; case Q_IPV6: b1 = gen_linktype(cstate, ETHERTYPE_IPV6); break; #ifndef IPPROTO_ICMPV6 #define IPPROTO_ICMPV6 58 #endif case Q_ICMPV6: b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); break; #ifndef IPPROTO_AH #define IPPROTO_AH 51 #endif case Q_AH: b1 = gen_proto(cstate, IPPROTO_AH, Q_DEFAULT, Q_DEFAULT); break; #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 #endif case Q_ESP: b1 = gen_proto(cstate, IPPROTO_ESP, Q_DEFAULT, Q_DEFAULT); break; case Q_ISO: b1 = gen_linktype(cstate, LLCSAP_ISONS); break; case Q_ESIS: b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS: b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */ b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_LSP: b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_SNP: b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_CSNP: b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_PSNP: b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_CLNP: b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT); break; case Q_STP: b1 = gen_linktype(cstate, LLCSAP_8021D); break; case Q_IPX: b1 = gen_linktype(cstate, LLCSAP_IPX); break; case Q_NETBEUI: b1 = gen_linktype(cstate, LLCSAP_NETBEUI); break; case Q_RADIO: bpf_error(cstate, "'radio' is not a valid protocol type"); default: abort(); } return b1; } struct block * gen_proto_abbrev(compiler_state_t *cstate, int proto) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_proto_abbrev_internal(cstate, proto); } static struct block * gen_ipfrag(compiler_state_t *cstate) { struct slist *s; struct block *b; /* not IPv4 frag other than the first frag */ s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H); b = new_block(cstate, JMP(BPF_JSET)); b->s.k = 0x1fff; b->stmts = s; gen_not(b); return b; } /* * Generate a comparison to a port value in the transport-layer header * at the specified offset from the beginning of that header. * * XXX - this handles a variable-length prefix preceding the link-layer * header, such as the radiotap or AVS radio prefix, but doesn't handle * variable-length link-layer headers (such as Token Ring or 802.11 * headers). */ static struct block * gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v) { return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v); } static struct block * gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v) { return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v); } static struct block * gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto); b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: b1 = gen_portatom(cstate, 0, port); break; case Q_DST: b1 = gen_portatom(cstate, 2, port); break; case Q_AND: tmp = gen_portatom(cstate, 0, port); b1 = gen_portatom(cstate, 2, port); gen_and(tmp, b1); break; case Q_DEFAULT: case Q_OR: tmp = gen_portatom(cstate, 0, port); b1 = gen_portatom(cstate, 2, port); gen_or(tmp, b1); break; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for ports"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for ports"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } gen_and(b0, b1); return b1; } static struct block * gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* * ether proto ip * * For FDDI, RFC 1188 says that SNAP encapsulation is used, * not LLC encapsulation with LLCSAP_IP. * * For IEEE 802 networks - which includes 802.5 token ring * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 * says that SNAP encapsulation is used, not LLC encapsulation * with LLCSAP_IP. * * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and * RFC 2225 say that SNAP encapsulation is used, not LLC * encapsulation with LLCSAP_IP. * * So we always check for ETHERTYPE_IP. */ b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portop(cstate, port, (u_int)ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portop(cstate, port, IPPROTO_TCP, dir); b1 = gen_portop(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } struct block * gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto); switch (dir) { case Q_SRC: b1 = gen_portatom6(cstate, 0, port); break; case Q_DST: b1 = gen_portatom6(cstate, 2, port); break; case Q_AND: tmp = gen_portatom6(cstate, 0, port); b1 = gen_portatom6(cstate, 2, port); gen_and(tmp, b1); break; case Q_DEFAULT: case Q_OR: tmp = gen_portatom6(cstate, 0, port); b1 = gen_portatom6(cstate, 2, port); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir); b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } /* gen_portrange code */ static struct block * gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1, bpf_u_int32 v2) { struct block *b1, *b2; if (v1 > v2) { /* * Reverse the order of the ports, so v1 is the lower one. */ bpf_u_int32 vtemp; vtemp = v1; v1 = v2; v2 = vtemp; } b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1); b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2); gen_and(b1, b2); return b2; } static struct block * gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2, bpf_u_int32 proto, int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto); b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: b1 = gen_portrangeatom(cstate, 0, port1, port2); break; case Q_DST: b1 = gen_portrangeatom(cstate, 2, port1, port2); break; case Q_AND: tmp = gen_portrangeatom(cstate, 0, port1, port2); b1 = gen_portrangeatom(cstate, 2, port1, port2); gen_and(tmp, b1); break; case Q_DEFAULT: case Q_OR: tmp = gen_portrangeatom(cstate, 0, port1, port2); b1 = gen_portrangeatom(cstate, 2, port1, port2); gen_or(tmp, b1); break; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges"); /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges"); /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges"); /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges"); /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for port ranges"); /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for port ranges"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } gen_and(b0, b1); return b1; } static struct block * gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip */ b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir); b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1, bpf_u_int32 v2) { struct block *b1, *b2; if (v1 > v2) { /* * Reverse the order of the ports, so v1 is the lower one. */ bpf_u_int32 vtemp; vtemp = v1; v1 = v2; v2 = vtemp; } b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1); b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2); gen_and(b1, b2); return b2; } static struct block * gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2, bpf_u_int32 proto, int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto); switch (dir) { case Q_SRC: b1 = gen_portrangeatom6(cstate, 0, port1, port2); break; case Q_DST: b1 = gen_portrangeatom6(cstate, 2, port1, port2); break; case Q_AND: tmp = gen_portrangeatom6(cstate, 0, port1, port2); b1 = gen_portrangeatom6(cstate, 2, port1, port2); gen_and(tmp, b1); break; case Q_DEFAULT: case Q_OR: tmp = gen_portrangeatom6(cstate, 0, port1, port2); b1 = gen_portrangeatom6(cstate, 2, port1, port2); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static struct block * gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto, dir); break; case PROTO_UNDEF: tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir); b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir); gen_or(tmp, b1); tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; default: abort(); } gen_and(b0, b1); return b1; } static int lookup_proto(compiler_state_t *cstate, const char *name, int proto) { register int v; switch (proto) { case Q_DEFAULT: case Q_IP: case Q_IPV6: v = pcap_nametoproto(name); if (v == PROTO_UNDEF) bpf_error(cstate, "unknown ip proto '%s'", name); break; case Q_LINK: /* XXX should look up h/w protocol type based on cstate->linktype */ v = pcap_nametoeproto(name); if (v == PROTO_UNDEF) { v = pcap_nametollc(name); if (v == PROTO_UNDEF) bpf_error(cstate, "unknown ether proto '%s'", name); } break; case Q_ISO: if (strcmp(name, "esis") == 0) v = ISO9542_ESIS; else if (strcmp(name, "isis") == 0) v = ISO10589_ISIS; else if (strcmp(name, "clnp") == 0) v = ISO8473_CLNP; else bpf_error(cstate, "unknown osi proto '%s'", name); break; default: v = PROTO_UNDEF; break; } return v; } #if !defined(NO_PROTOCHAIN) static struct block * gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto) { struct block *b0, *b; struct slist *s[100]; int fix2, fix3, fix4, fix5; int ahcheck, again, end; int i, max; int reg2 = alloc_reg(cstate); memset(s, 0, sizeof(s)); fix3 = fix4 = fix5 = 0; switch (proto) { case Q_IP: case Q_IPV6: break; case Q_DEFAULT: b0 = gen_protochain(cstate, v, Q_IP); b = gen_protochain(cstate, v, Q_IPV6); gen_or(b0, b); return b; default: bpf_error(cstate, "bad protocol applied for 'protochain'"); /*NOTREACHED*/ } /* * We don't handle variable-length prefixes before the link-layer * header, or variable-length link-layer headers, here yet. * We might want to add BPF instructions to do the protochain * work, to simplify that and, on platforms that have a BPF * interpreter with the new instructions, let the filtering * be done in the kernel. (We already require a modified BPF * engine to do the protochain stuff, to support backward * branches, and backward branch support is unlikely to appear * in kernel BPF engines.) */ if (cstate->off_linkpl.is_variable) bpf_error(cstate, "'protochain' not supported with variable length headers"); /* * To quote a comment in optimize.c: * * "These data structures are used in a Cocke and Shwarz style * value numbering scheme. Since the flowgraph is acyclic, * exit values can be propagated from a node's predecessors * provided it is uniquely defined." * * "Acyclic" means "no backward branches", which means "no * loops", so we have to turn the optimizer off. */ cstate->no_optimize = 1; /* * s[0] is a dummy entry to protect other BPF insn from damage * by s[fix] = foo with uninitialized variable "fix". It is somewhat * hard to find interdependency made by jump table fixup. */ i = 0; s[i] = new_stmt(cstate, 0); /*dummy*/ i++; switch (proto) { case Q_IP: b0 = gen_linktype(cstate, ETHERTYPE_IP); /* A = ip->ip_p */ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 9; i++; /* X = ip->ip_hl << 2 */ s[i] = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; break; case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); /* A = ip6->ip_nxt */ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 6; i++; /* X = sizeof(struct ip6_hdr) */ s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM); s[i]->s.k = 40; i++; break; default: bpf_error(cstate, "unsupported proto to gen_protochain"); /*NOTREACHED*/ } /* again: if (A == v) goto end; else fall through; */ again = i; s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.k = v; s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ fix5 = i; i++; #ifndef IPPROTO_NONE #define IPPROTO_NONE 59 #endif /* if (A == IPPROTO_NONE) goto end */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_NONE; s[fix5]->s.jf = s[i]; fix2 = i; i++; if (proto == Q_IPV6) { int v6start, v6end, v6advance, j; v6start = i; /* if (A == IPPROTO_HOPOPTS) goto v6advance */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_HOPOPTS; s[fix2]->s.jf = s[i]; i++; /* if (A == IPPROTO_DSTOPTS) goto v6advance */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_DSTOPTS; i++; /* if (A == IPPROTO_ROUTING) goto v6advance */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*update in next stmt*/ s[i]->s.k = IPPROTO_ROUTING; i++; /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*later*/ s[i]->s.k = IPPROTO_FRAGMENT; fix3 = i; v6end = i; i++; /* v6advance: */ v6advance = i; /* * in short, * A = P[X + packet head]; * X = X + (P[X + packet head + 1] + 1) * 8; */ /* A = P[X + packet head] */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = P[X + packet head + 1]; */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 1; i++; /* A += 1 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* A *= 8 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 8; i++; /* A += X */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s[i]->s.k = 0; i++; /* X = A; */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); s[i]->s.k = reg2; i++; /* goto again; (must use BPF_JA for backward jump) */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); s[i]->s.k = again - i - 1; s[i - 1]->s.jf = s[i]; i++; /* fixup */ for (j = v6start; j <= v6end; j++) s[j]->s.jt = s[v6advance]; } else { /* nop */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; s[fix2]->s.jf = s[i]; i++; } /* ahcheck: */ ahcheck = i; /* if (A == IPPROTO_AH) then fall through; else goto end; */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ s[i]->s.jf = NULL; /*later*/ s[i]->s.k = IPPROTO_AH; if (fix3) s[fix3]->s.jf = s[ahcheck]; fix4 = i; i++; /* * in short, * A = P[X]; * X = X + (P[X + 1] + 2) * 4; */ /* A = X */ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A = P[X + packet head]; */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = X */ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A += 1 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* X = A */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = P[X + packet head] */ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; i++; /* A += 2 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 2; i++; /* A *= 4 */ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 4; i++; /* X = A; */ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); s[i]->s.k = reg2; i++; /* goto again; (must use BPF_JA for backward jump) */ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); s[i]->s.k = again - i - 1; i++; /* end: nop */ end = i; s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; s[fix2]->s.jt = s[end]; s[fix4]->s.jf = s[end]; s[fix5]->s.jt = s[end]; i++; /* * make slist chain */ max = i; for (i = 0; i < max - 1; i++) s[i]->next = s[i + 1]; s[max - 1]->next = NULL; /* * emit final check */ b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s[1]; /*remember, s[0] is dummy*/ b->s.k = v; free_reg(cstate, reg2); gen_and(b0, b); return b; } #endif /* !defined(NO_PROTOCHAIN) */ static struct block * gen_check_802_11_data_frame(compiler_state_t *cstate) { struct slist *s; struct block *b0, *b1; /* * A data frame has the 0x08 bit (b3) in the frame control field set * and the 0x04 bit (b2) clear. */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b0 = new_block(cstate, JMP(BPF_JSET)); b0->s.k = 0x08; b0->stmts = s; s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); gen_and(b1, b0); return b0; } /* * Generate code that checks whether the packet is a packet for protocol * and whether the type field in that protocol's header has * the value , e.g. if is Q_IP, it checks whether it's an * IP packet and checks the protocol number in the IP header against . * * If is Q_DEFAULT, i.e. just "proto" was specified, it checks * against Q_IP and Q_IPV6. */ static struct block * gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) { struct block *b0, *b1; struct block *b2; if (dir != Q_DEFAULT) bpf_error(cstate, "direction applied to 'proto'"); switch (proto) { case Q_DEFAULT: b0 = gen_proto(cstate, v, Q_IP, dir); b1 = gen_proto(cstate, v, Q_IPV6, dir); gen_or(b0, b1); return b1; case Q_LINK: return gen_linktype(cstate, v); case Q_IP: /* * For FDDI, RFC 1188 says that SNAP encapsulation is used, * not LLC encapsulation with LLCSAP_IP. * * For IEEE 802 networks - which includes 802.5 token ring * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 * says that SNAP encapsulation is used, not LLC encapsulation * with LLCSAP_IP. * * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and * RFC 2225 say that SNAP encapsulation is used, not LLC * encapsulation with LLCSAP_IP. * * So we always check for ETHERTYPE_IP. */ b0 = gen_linktype(cstate, ETHERTYPE_IP); b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v); gen_and(b0, b1); return b1; case Q_ARP: bpf_error(cstate, "arp does not encapsulate another protocol"); /*NOTREACHED*/ case Q_RARP: bpf_error(cstate, "rarp does not encapsulate another protocol"); /*NOTREACHED*/ case Q_SCTP: bpf_error(cstate, "'sctp proto' is bogus"); /*NOTREACHED*/ case Q_TCP: bpf_error(cstate, "'tcp proto' is bogus"); /*NOTREACHED*/ case Q_UDP: bpf_error(cstate, "'udp proto' is bogus"); /*NOTREACHED*/ case Q_ICMP: bpf_error(cstate, "'icmp proto' is bogus"); /*NOTREACHED*/ case Q_IGMP: bpf_error(cstate, "'igmp proto' is bogus"); /*NOTREACHED*/ case Q_IGRP: bpf_error(cstate, "'igrp proto' is bogus"); /*NOTREACHED*/ case Q_ATALK: bpf_error(cstate, "AppleTalk encapsulation is not specifiable"); /*NOTREACHED*/ case Q_DECNET: bpf_error(cstate, "DECNET encapsulation is not specifiable"); /*NOTREACHED*/ case Q_LAT: bpf_error(cstate, "LAT does not encapsulate another protocol"); /*NOTREACHED*/ case Q_SCA: bpf_error(cstate, "SCA does not encapsulate another protocol"); /*NOTREACHED*/ case Q_MOPRC: bpf_error(cstate, "MOPRC does not encapsulate another protocol"); /*NOTREACHED*/ case Q_MOPDL: bpf_error(cstate, "MOPDL does not encapsulate another protocol"); /*NOTREACHED*/ case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); /* * Also check for a fragment header before the final * header. */ b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v); gen_and(b2, b1); b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v); gen_or(b2, b1); gen_and(b0, b1); return b1; case Q_ICMPV6: bpf_error(cstate, "'icmp6 proto' is bogus"); /*NOTREACHED*/ case Q_AH: bpf_error(cstate, "'ah proto' is bogus"); /*NOTREACHED*/ case Q_ESP: bpf_error(cstate, "'esp proto' is bogus"); /*NOTREACHED*/ case Q_PIM: bpf_error(cstate, "'pim proto' is bogus"); /*NOTREACHED*/ case Q_VRRP: bpf_error(cstate, "'vrrp proto' is bogus"); /*NOTREACHED*/ case Q_AARP: bpf_error(cstate, "'aarp proto' is bogus"); /*NOTREACHED*/ case Q_ISO: switch (cstate->linktype) { case DLT_FRELAY: /* * Frame Relay packets typically have an OSI * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)" * generates code to check for all the OSI * NLPIDs, so calling it and then adding a check * for the particular NLPID for which we're * looking is bogus, as we can just check for * the NLPID. * * What we check for is the NLPID and a frame * control field value of UI, i.e. 0x03 followed * by the NLPID. * * XXX - assumes a 2-byte Frame Relay header with * DLCI and flags. What if the address is longer? * * XXX - what about SNAP-encapsulated frames? */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); /*NOTREACHED*/ case DLT_C_HDLC: case DLT_HDLC: /* * Cisco uses an Ethertype lookalike - for OSI, * it's 0xfefe. */ b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS); /* OSI in C-HDLC is stuffed with a fudge byte */ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v); gen_and(b0, b1); return b1; default: b0 = gen_linktype(cstate, LLCSAP_ISONS); b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v); gen_and(b0, b1); return b1; } case Q_ESIS: bpf_error(cstate, "'esis proto' is bogus"); /*NOTREACHED*/ case Q_ISIS: b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); /* * 4 is the offset of the PDU type relative to the IS-IS * header. */ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v); gen_and(b0, b1); return b1; case Q_CLNP: bpf_error(cstate, "'clnp proto' is not supported"); /*NOTREACHED*/ case Q_STP: bpf_error(cstate, "'stp proto' is bogus"); /*NOTREACHED*/ case Q_IPX: bpf_error(cstate, "'ipx proto' is bogus"); /*NOTREACHED*/ case Q_NETBEUI: bpf_error(cstate, "'netbeui proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_L1: bpf_error(cstate, "'l1 proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_L2: bpf_error(cstate, "'l2 proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_IIH: bpf_error(cstate, "'iih proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_SNP: bpf_error(cstate, "'snp proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_CSNP: bpf_error(cstate, "'csnp proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_PSNP: bpf_error(cstate, "'psnp proto' is bogus"); /*NOTREACHED*/ case Q_ISIS_LSP: bpf_error(cstate, "'lsp proto' is bogus"); /*NOTREACHED*/ case Q_RADIO: bpf_error(cstate, "'radio proto' is bogus"); /*NOTREACHED*/ case Q_CARP: bpf_error(cstate, "'carp proto' is bogus"); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } /*NOTREACHED*/ } struct block * gen_scode(compiler_state_t *cstate, const char *name, struct qual q) { int proto = q.proto; int dir = q.dir; int tproto; u_char *eaddr; bpf_u_int32 mask, addr; struct addrinfo *res, *res0; struct sockaddr_in *sin4; #ifdef INET6 int tproto6; struct sockaddr_in6 *sin6; struct in6_addr mask128; #endif /*INET6*/ struct block *b, *tmp; int port, real_proto; int port1, port2; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (q.addr) { case Q_NET: addr = pcap_nametonetaddr(name); if (addr == 0) bpf_error(cstate, "unknown network '%s'", name); /* Left justify network addr and calculate its network mask */ mask = 0xffffffff; while (addr && (addr & 0xff000000) == 0) { addr <<= 8; mask <<= 8; } return gen_host(cstate, addr, mask, proto, dir, q.addr); case Q_DEFAULT: case Q_HOST: if (proto == Q_LINK) { switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown ether host '%s'", name); tmp = gen_prevlinkhdr_check(cstate); b = gen_ehostop(cstate, eaddr, dir); if (tmp != NULL) gen_and(tmp, b); free(eaddr); return b; case DLT_FDDI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown FDDI host '%s'", name); b = gen_fhostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IEEE802: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown token ring host '%s'", name); b = gen_thostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown 802.11 host '%s'", name); b = gen_wlanhostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IP_OVER_FC: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown Fibre Channel host '%s'", name); b = gen_ipfchostop(cstate, eaddr, dir); free(eaddr); return b; } bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); } else if (proto == Q_DECNET) { unsigned short dn_addr; if (!__pcap_nametodnaddr(name, &dn_addr)) { #ifdef DECNETLIB bpf_error(cstate, "unknown decnet host name '%s'\n", name); #else bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n", name); #endif } /* * I don't think DECNET hosts can be multihomed, so * there is no need to build up a list of addresses */ return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr)); } else { #ifdef INET6 memset(&mask128, 0xff, sizeof(mask128)); #endif res0 = res = pcap_nametoaddrinfo(name); if (res == NULL) bpf_error(cstate, "unknown host '%s'", name); cstate->ai = res; b = tmp = NULL; tproto = proto; #ifdef INET6 tproto6 = proto; #endif if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && tproto == Q_DEFAULT) { tproto = Q_IP; #ifdef INET6 tproto6 = Q_IPV6; #endif } for (res = res0; res; res = res->ai_next) { switch (res->ai_family) { case AF_INET: #ifdef INET6 if (tproto == Q_IPV6) continue; #endif sin4 = (struct sockaddr_in *) res->ai_addr; tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr), 0xffffffff, tproto, dir, q.addr); break; #ifdef INET6 case AF_INET6: if (tproto6 == Q_IP) continue; sin6 = (struct sockaddr_in6 *) res->ai_addr; tmp = gen_host6(cstate, &sin6->sin6_addr, &mask128, tproto6, dir, q.addr); break; #endif default: continue; } if (b) gen_or(b, tmp); b = tmp; } cstate->ai = NULL; freeaddrinfo(res0); if (b == NULL) { bpf_error(cstate, "unknown host '%s'%s", name, (proto == Q_DEFAULT) ? "" : " for specified address family"); } return b; } case Q_PORT: if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) bpf_error(cstate, "illegal qualifier of 'port'"); if (pcap_nametoport(name, &port, &real_proto) == 0) bpf_error(cstate, "unknown port '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_UDP; } if (proto == Q_TCP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_TCP; } if (proto == Q_SCTP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port '%s' is tcp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_SCTP; } if (port < 0) bpf_error(cstate, "illegal port number %d < 0", port); if (port > 65535) bpf_error(cstate, "illegal port number %d > 65535", port); b = gen_port(cstate, port, real_proto, dir); gen_or(gen_port6(cstate, port, real_proto, dir), b); return b; case Q_PORTRANGE: if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) bpf_error(cstate, "illegal qualifier of 'portrange'"); if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0) bpf_error(cstate, "unknown port in range '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port in range '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port in range '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_UDP; } if (proto == Q_TCP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) bpf_error(cstate, "port in range '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_TCP; } if (proto == Q_SCTP) { if (real_proto == IPPROTO_UDP) bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_TCP) bpf_error(cstate, "port in range '%s' is tcp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_SCTP; } if (port1 < 0) bpf_error(cstate, "illegal port number %d < 0", port1); if (port1 > 65535) bpf_error(cstate, "illegal port number %d > 65535", port1); if (port2 < 0) bpf_error(cstate, "illegal port number %d < 0", port2); if (port2 > 65535) bpf_error(cstate, "illegal port number %d > 65535", port2); b = gen_portrange(cstate, port1, port2, real_proto, dir); gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b); return b; case Q_GATEWAY: #ifndef INET6 eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error(cstate, "unknown ether host: %s", name); res = pcap_nametoaddrinfo(name); cstate->ai = res; if (res == NULL) bpf_error(cstate, "unknown host '%s'", name); b = gen_gateway(cstate, eaddr, res, proto, dir); cstate->ai = NULL; freeaddrinfo(res); if (b == NULL) bpf_error(cstate, "unknown host '%s'", name); return b; #else bpf_error(cstate, "'gateway' not supported in this configuration"); #endif /*INET6*/ case Q_PROTO: real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) return gen_proto(cstate, real_proto, proto, dir); else bpf_error(cstate, "unknown protocol: %s", name); #if !defined(NO_PROTOCHAIN) case Q_PROTOCHAIN: real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) return gen_protochain(cstate, real_proto, proto); else bpf_error(cstate, "unknown protocol: %s", name); #endif /* !defined(NO_PROTOCHAIN) */ case Q_UNDEF: syntax(cstate); /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } struct block * gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, bpf_u_int32 masklen, struct qual q) { register int nlen, mlen; bpf_u_int32 n, m; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); nlen = __pcap_atoin(s1, &n); if (nlen < 0) bpf_error(cstate, "invalid IPv4 address '%s'", s1); /* Promote short ipaddr */ n <<= 32 - nlen; if (s2 != NULL) { mlen = __pcap_atoin(s2, &m); if (mlen < 0) bpf_error(cstate, "invalid IPv4 address '%s'", s2); /* Promote short ipaddr */ m <<= 32 - mlen; if ((n & ~m) != 0) bpf_error(cstate, "non-network bits set in \"%s mask %s\"", s1, s2); } else { /* Convert mask len to mask */ if (masklen > 32) bpf_error(cstate, "mask length must be <= 32"); if (masklen == 0) { /* * X << 32 is not guaranteed by C to be 0; it's * undefined. */ m = 0; } else m = 0xffffffff << (32 - masklen); if ((n & ~m) != 0) bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { case Q_NET: return gen_host(cstate, n, m, q.proto, q.dir, q.addr); default: bpf_error(cstate, "Mask syntax for networks only"); /*NOTREACHED*/ } /*NOTREACHED*/ } struct block * gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) { bpf_u_int32 mask; int proto; int dir; register int vlen; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); proto = q.proto; dir = q.dir; if (s == NULL) vlen = 32; else if (q.proto == Q_DECNET) { vlen = __pcap_atodn(s, &v); if (vlen == 0) bpf_error(cstate, "malformed decnet address '%s'", s); } else { vlen = __pcap_atoin(s, &v); if (vlen < 0) bpf_error(cstate, "invalid IPv4 address '%s'", s); } switch (q.addr) { case Q_DEFAULT: case Q_HOST: case Q_NET: if (proto == Q_DECNET) return gen_host(cstate, v, 0, proto, dir, q.addr); else if (proto == Q_LINK) { bpf_error(cstate, "illegal link layer address"); } else { mask = 0xffffffff; if (s == NULL && q.addr == Q_NET) { /* Promote short net number */ while (v && (v & 0xff000000) == 0) { v <<= 8; mask <<= 8; } } else { /* Promote short ipaddr */ v <<= 32 - vlen; mask <<= 32 - vlen ; } return gen_host(cstate, v, mask, proto, dir, q.addr); } case Q_PORT: if (proto == Q_UDP) proto = IPPROTO_UDP; else if (proto == Q_TCP) proto = IPPROTO_TCP; else if (proto == Q_SCTP) proto = IPPROTO_SCTP; else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else bpf_error(cstate, "illegal qualifier of 'port'"); if (v > 65535) bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; b = gen_port(cstate, v, proto, dir); gen_or(gen_port6(cstate, v, proto, dir), b); return b; } case Q_PORTRANGE: if (proto == Q_UDP) proto = IPPROTO_UDP; else if (proto == Q_TCP) proto = IPPROTO_TCP; else if (proto == Q_SCTP) proto = IPPROTO_SCTP; else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else bpf_error(cstate, "illegal qualifier of 'portrange'"); if (v > 65535) bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; b = gen_portrange(cstate, v, v, proto, dir); gen_or(gen_portrange6(cstate, v, v, proto, dir), b); return b; } case Q_GATEWAY: bpf_error(cstate, "'gateway' requires a name"); /*NOTREACHED*/ case Q_PROTO: return gen_proto(cstate, v, proto, dir); #if !defined(NO_PROTOCHAIN) case Q_PROTOCHAIN: return gen_protochain(cstate, v, proto); #endif case Q_UNDEF: syntax(cstate); /*NOTREACHED*/ default: abort(); /*NOTREACHED*/ } /*NOTREACHED*/ } #ifdef INET6 struct block * gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, bpf_u_int32 masklen, struct qual q) { struct addrinfo *res; struct in6_addr *addr; struct in6_addr mask; struct block *b; uint32_t *a, *m; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (s2) bpf_error(cstate, "no mask %s supported", s2); res = pcap_nametoaddrinfo(s1); if (!res) bpf_error(cstate, "invalid ip6 address %s", s1); cstate->ai = res; if (res->ai_next) bpf_error(cstate, "%s resolved to multiple address", s1); addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; if (masklen > sizeof(mask.s6_addr) * 8) bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask.s6_addr) * 8)); memset(&mask, 0, sizeof(mask)); memset(&mask.s6_addr, 0xff, masklen / 8); if (masklen % 8) { mask.s6_addr[masklen / 8] = (0xff << (8 - masklen % 8)) & 0xff; } a = (uint32_t *)addr; m = (uint32_t *)&mask; if ((a[0] & ~m[0]) || (a[1] & ~m[1]) || (a[2] & ~m[2]) || (a[3] & ~m[3])) { bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { case Q_DEFAULT: case Q_HOST: if (masklen != 128) bpf_error(cstate, "Mask syntax for networks only"); /* FALLTHROUGH */ case Q_NET: b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr); cstate->ai = NULL; freeaddrinfo(res); return b; default: bpf_error(cstate, "invalid qualifier against IPv6 address"); /*NOTREACHED*/ } } #endif /*INET6*/ struct block * gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) { struct block *b, *tmp; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { cstate->e = pcap_ether_aton(s); if (cstate->e == NULL) bpf_error(cstate, "malloc"); switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: tmp = gen_prevlinkhdr_check(cstate); b = gen_ehostop(cstate, cstate->e, (int)q.dir); if (tmp != NULL) gen_and(tmp, b); break; case DLT_FDDI: b = gen_fhostop(cstate, cstate->e, (int)q.dir); break; case DLT_IEEE802: b = gen_thostop(cstate, cstate->e, (int)q.dir); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: b = gen_wlanhostop(cstate, cstate->e, (int)q.dir); break; case DLT_IP_OVER_FC: b = gen_ipfchostop(cstate, cstate->e, (int)q.dir); break; default: free(cstate->e); cstate->e = NULL; bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); /*NOTREACHED*/ } free(cstate->e); cstate->e = NULL; return (b); } bpf_error(cstate, "ethernet address used in non-ether expression"); /*NOTREACHED*/ } void sappend(struct slist *s0, struct slist *s1) { /* * This is definitely not the best way to do this, but the * lists will rarely get long. */ while (s0->next) s0 = s0->next; s0->next = s1; } static struct slist * xfer_to_x(compiler_state_t *cstate, struct arth *a) { struct slist *s; s = new_stmt(cstate, BPF_LDX|BPF_MEM); s->s.k = a->regno; return s; } static struct slist * xfer_to_a(compiler_state_t *cstate, struct arth *a) { struct slist *s; s = new_stmt(cstate, BPF_LD|BPF_MEM); s->s.k = a->regno; return s; } /* * Modify "index" to use the value stored into its register as an * offset relative to the beginning of the header for the protocol * "proto", and allocate a register and put an item "size" bytes long * (1, 2, or 4) at that offset into that register, making it the register * for "index". */ static struct arth * gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, bpf_u_int32 size) { int size_code; struct slist *s, *tmp; struct block *b; int regno = alloc_reg(cstate); free_reg(cstate, inst->regno); switch (size) { default: bpf_error(cstate, "data size must be 1, 2, or 4"); /*NOTREACHED*/ case 1: size_code = BPF_B; break; case 2: size_code = BPF_H; break; case 4: size_code = BPF_W; break; } switch (proto) { default: bpf_error(cstate, "unsupported index operation"); case Q_RADIO: /* * The offset is relative to the beginning of the packet * data, if we have a radio header. (If we don't, this * is an error.) */ if (cstate->linktype != DLT_IEEE802_11_RADIO_AVS && cstate->linktype != DLT_IEEE802_11_RADIO && cstate->linktype != DLT_PRISM_HEADER) bpf_error(cstate, "radio information not present in capture"); /* * Load into the X register the offset computed into the * register specified by "index". */ s = xfer_to_x(cstate, inst); /* * Load the item at that offset. */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); sappend(s, tmp); sappend(inst->s, s); break; case Q_LINK: /* * The offset is relative to the beginning of * the link-layer header. * * XXX - what about ATM LANE? Should the index be * relative to the beginning of the AAL5 frame, so * that 0 refers to the beginning of the LE Control * field, or relative to the beginning of the LAN * frame, so that 0 refers, for Ethernet LANE, to * the beginning of the destination address? */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr); /* * If "s" is non-null, it has code to arrange that the * X register contains the length of the prefix preceding * the link-layer header. Add to it the offset computed * into the register specified by "index", and move that * into the X register. Otherwise, just load into the X * register the offset computed into the register specified * by "index". */ if (s != NULL) { sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else s = xfer_to_x(cstate, inst); /* * Load the item at the sum of the offset we've put in the * X register and the offset of the start of the link * layer header (which is 0 if the radio header is * variable-length; that header length is what we put * into the X register and then added to the index). */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); tmp->s.k = cstate->off_linkhdr.constant_part; sappend(s, tmp); sappend(inst->s, s); break; case Q_IP: case Q_ARP: case Q_RARP: case Q_ATALK: case Q_DECNET: case Q_SCA: case Q_LAT: case Q_MOPRC: case Q_MOPDL: case Q_IPV6: /* * The offset is relative to the beginning of * the network-layer header. * XXX - are there any cases where we want * cstate->off_nl_nosnap? */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); /* * If "s" is non-null, it has code to arrange that the * X register contains the variable part of the offset * of the link-layer payload. Add to it the offset * computed into the register specified by "index", * and move that into the X register. Otherwise, just * load into the X register the offset computed into * the register specified by "index". */ if (s != NULL) { sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else s = xfer_to_x(cstate, inst); /* * Load the item at the sum of the offset we've put in the * X register, the offset of the start of the network * layer header from the beginning of the link-layer * payload, and the constant part of the offset of the * start of the link-layer payload. */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(s, tmp); sappend(inst->s, s); /* * Do the computation only if the packet contains * the protocol in question. */ b = gen_proto_abbrev_internal(cstate, proto); if (inst->b) gen_and(inst->b, b); inst->b = b; break; case Q_SCTP: case Q_TCP: case Q_UDP: case Q_ICMP: case Q_IGMP: case Q_IGRP: case Q_PIM: case Q_VRRP: case Q_CARP: /* * The offset is relative to the beginning of * the transport-layer header. * * Load the X register with the length of the IPv4 header * (plus the offset of the link-layer header, if it's * a variable-length header), in bytes. * * XXX - are there any cases where we want * cstate->off_nl_nosnap? * XXX - we should, if we're built with * IPv6 support, generate code to load either * IPv4, IPv6, or both, as appropriate. */ s = gen_loadx_iphdrlen(cstate); /* * The X register now contains the sum of the variable * part of the offset of the link-layer payload and the * length of the network-layer header. * * Load into the A register the offset relative to * the beginning of the transport layer header, * add the X register to that, move that to the * X register, and load with an offset from the * X register equal to the sum of the constant part of * the offset of the link-layer payload and the offset, * relative to the beginning of the link-layer payload, * of the network-layer header. */ sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code)); tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(inst->s, s); /* * Do the computation only if the packet contains * the protocol in question - which is true only * if this is an IP datagram and is the first or * only fragment of that datagram. */ gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate)); if (inst->b) gen_and(inst->b, b); gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b); inst->b = b; break; case Q_ICMPV6: /* * Do the computation only if the packet contains * the protocol in question. */ b = gen_proto_abbrev_internal(cstate, Q_IPV6); if (inst->b) { gen_and(inst->b, b); } inst->b = b; /* * Check if we have an icmp6 next header */ b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58); if (inst->b) { gen_and(inst->b, b); } inst->b = b; s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); /* * If "s" is non-null, it has code to arrange that the * X register contains the variable part of the offset * of the link-layer payload. Add to it the offset * computed into the register specified by "index", * and move that into the X register. Otherwise, just * load into the X register the offset computed into * the register specified by "index". */ if (s != NULL) { sappend(s, xfer_to_a(cstate, inst)); sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else { s = xfer_to_x(cstate, inst); } /* * Load the item at the sum of the offset we've put in the * X register, the offset of the start of the network * layer header from the beginning of the link-layer * payload, and the constant part of the offset of the * start of the link-layer payload. */ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40; sappend(s, tmp); sappend(inst->s, s); break; } inst->regno = regno; s = new_stmt(cstate, BPF_ST); s->s.k = regno; sappend(inst->s, s); return inst; } struct arth * gen_load(compiler_state_t *cstate, int proto, struct arth *inst, bpf_u_int32 size) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_load_internal(cstate, proto, inst, size); } static struct block * gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0, struct arth *a1, int reversed) { struct slist *s0, *s1, *s2; struct block *b, *tmp; s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); if (code == BPF_JEQ) { s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X); b = new_block(cstate, JMP(code)); sappend(s1, s2); } else b = new_block(cstate, BPF_JMP|code|BPF_X); if (reversed) gen_not(b); sappend(s0, s1); sappend(a1->s, s0); sappend(a0->s, a1->s); b->stmts = a0->s; free_reg(cstate, a0->regno); free_reg(cstate, a1->regno); /* 'and' together protocol checks */ if (a0->b) { if (a1->b) { gen_and(a0->b, tmp = a1->b); } else tmp = a0->b; } else tmp = a1->b; if (tmp) gen_and(tmp, b); return b; } struct block * gen_relation(compiler_state_t *cstate, int code, struct arth *a0, struct arth *a1, int reversed) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_relation_internal(cstate, code, a0, a1, reversed); } struct arth * gen_loadlen(compiler_state_t *cstate) { int regno; struct arth *a; struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); regno = alloc_reg(cstate); a = (struct arth *)newchunk(cstate, sizeof(*a)); s = new_stmt(cstate, BPF_LD|BPF_LEN); s->next = new_stmt(cstate, BPF_ST); s->next->s.k = regno; a->s = s; a->regno = regno; return a; } static struct arth * gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val) { struct arth *a; struct slist *s; int reg; a = (struct arth *)newchunk(cstate, sizeof(*a)); reg = alloc_reg(cstate); s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = val; s->next = new_stmt(cstate, BPF_ST); s->next->s.k = reg; a->s = s; a->regno = reg; return a; } struct arth * gen_loadi(compiler_state_t *cstate, bpf_u_int32 val) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_loadi_internal(cstate, val); } /* * The a_arg dance is to avoid annoying whining by compilers that * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*? * It's not *used* after setjmp returns. */ struct arth * gen_neg(compiler_state_t *cstate, struct arth *a_arg) { struct arth *a = a_arg; struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); s = xfer_to_a(cstate, a); sappend(a->s, s); s = new_stmt(cstate, BPF_ALU|BPF_NEG); s->s.k = 0; sappend(a->s, s); s = new_stmt(cstate, BPF_ST); s->s.k = a->regno; sappend(a->s, s); return a; } /* * The a0_arg dance is to avoid annoying whining by compilers that * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*? * It's not *used* after setjmp returns. */ struct arth * gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg, struct arth *a1) { struct arth *a0 = a0_arg; struct slist *s0, *s1, *s2; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Disallow division by, or modulus by, zero; we do this here * so that it gets done even if the optimizer is disabled. * * Also disallow shifts by a value greater than 31; we do this * here, for the same reason. */ if (code == BPF_DIV) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "division by zero"); } else if (code == BPF_MOD) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "modulus by zero"); } else if (code == BPF_LSH || code == BPF_RSH) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31) bpf_error(cstate, "shift by more than 31 bits"); } s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); s2 = new_stmt(cstate, BPF_ALU|BPF_X|code); sappend(s1, s2); sappend(s0, s1); sappend(a1->s, s0); sappend(a0->s, a1->s); free_reg(cstate, a0->regno); free_reg(cstate, a1->regno); s0 = new_stmt(cstate, BPF_ST); a0->regno = s0->s.k = alloc_reg(cstate); sappend(a0->s, s0); return a0; } /* * Initialize the table of used registers and the current register. */ static void init_regs(compiler_state_t *cstate) { cstate->curreg = 0; memset(cstate->regused, 0, sizeof cstate->regused); } /* * Return the next free register. */ static int alloc_reg(compiler_state_t *cstate) { int n = BPF_MEMWORDS; while (--n >= 0) { if (cstate->regused[cstate->curreg]) cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS; else { cstate->regused[cstate->curreg] = 1; return cstate->curreg; } } bpf_error(cstate, "too many registers needed to evaluate expression"); /*NOTREACHED*/ } /* * Return a register to the table so it can * be used later. */ static void free_reg(compiler_state_t *cstate, int n) { cstate->regused[n] = 0; } static struct block * gen_len(compiler_state_t *cstate, int jmp, int n) { struct slist *s; struct block *b; s = new_stmt(cstate, BPF_LD|BPF_LEN); b = new_block(cstate, JMP(jmp)); b->stmts = s; b->s.k = n; return b; } struct block * gen_greater(compiler_state_t *cstate, int n) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_len(cstate, BPF_JGE, n); } /* * Actually, this is less than or equal. */ struct block * gen_less(compiler_state_t *cstate, int n) { struct block *b; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); b = gen_len(cstate, BPF_JGT, n); gen_not(b); return b; } /* * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to * the beginning of the link-layer header. * XXX - that means you can't test values in the radiotap header, but * as that header is difficult if not impossible to parse generally * without a loop, that might not be a severe problem. A new keyword * "radio" could be added for that, although what you'd really want * would be a way of testing particular radio header values, which * would generate code appropriate to the radio header in question. */ struct block * gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val) { struct block *b; struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (op) { default: abort(); case '=': return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); case '<': b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); return b; case '>': b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); return b; case '|': s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K); break; case '&': s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); break; } s->s.k = val; b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; gen_not(b); return b; } static const u_char abroadcast[] = { 0x0 }; struct block * gen_broadcast(compiler_state_t *cstate, int proto) { bpf_u_int32 hostmask; struct block *b0, *b1, *b2; static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (proto) { case Q_DEFAULT: case Q_LINK: switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: return gen_ahostop(cstate, abroadcast, Q_DST); case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); b0 = gen_ehostop(cstate, ebroadcast, Q_DST); if (b1 != NULL) gen_and(b1, b0); return b0; case DLT_FDDI: return gen_fhostop(cstate, ebroadcast, Q_DST); case DLT_IEEE802: return gen_thostop(cstate, ebroadcast, Q_DST); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: return gen_wlanhostop(cstate, ebroadcast, Q_DST); case DLT_IP_OVER_FC: return gen_ipfchostop(cstate, ebroadcast, Q_DST); default: bpf_error(cstate, "not a broadcast link"); } - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_IP: /* * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff) * as an indication that we don't know the netmask, and fail * in that case. */ if (cstate->netmask == PCAP_NETMASK_UNKNOWN) bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported"); b0 = gen_linktype(cstate, ETHERTYPE_IP); hostmask = ~cstate->netmask; b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask); b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, ~0 & hostmask, hostmask); gen_or(b1, b2); gen_and(b0, b2); return b2; } bpf_error(cstate, "only link-layer/IP broadcast filters supported"); /*NOTREACHED*/ } /* * Generate code to test the low-order bit of a MAC address (that's * the bottom bit of the *first* byte). */ static struct block * gen_mac_multicast(compiler_state_t *cstate, int offset) { register struct block *b0; register struct slist *s; /* link[offset] & 1 != 0 */ s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B); b0 = new_block(cstate, JMP(BPF_JSET)); b0->s.k = 1; b0->stmts = s; return b0; } struct block * gen_multicast(compiler_state_t *cstate, int proto) { register struct block *b0, *b1, *b2; register struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (proto) { case Q_DEFAULT: case Q_LINK: switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: /* all ARCnet multicasts use the same address */ return gen_ahostop(cstate, abroadcast, Q_DST); case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b1 = gen_prevlinkhdr_check(cstate); /* ether[0] & 1 != 0 */ b0 = gen_mac_multicast(cstate, 0); if (b1 != NULL) gen_and(b1, b0); return b0; case DLT_FDDI: /* * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX * * XXX - was that referring to bit-order issues? */ /* fddi[1] & 1 != 0 */ return gen_mac_multicast(cstate, 1); case DLT_IEEE802: /* tr[2] & 1 != 0 */ return gen_mac_multicast(cstate, 2); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: /* * Oh, yuk. * * For control frames, there is no DA. * * For management frames, DA is at an * offset of 4 from the beginning of * the packet. * * For data frames, DA is at an offset * of 4 from the beginning of the packet * if To DS is clear and at an offset of * 16 from the beginning of the packet * if To DS is set. */ /* * Generate the tests to be done for data frames. * * First, check for To DS set, i.e. "link[1] & 0x01". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x01; /* To DS */ b1->stmts = s; /* * If To DS is set, the DA is at 16. */ b0 = gen_mac_multicast(cstate, 16); gen_and(b1, b0); /* * Now, check for To DS not set, i.e. check * "!(link[1] & 0x01)". */ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x01; /* To DS */ b2->stmts = s; gen_not(b2); /* * If To DS is not set, the DA is at 4. */ b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* * Now OR together the last two checks. That gives * the complete set of checks for data frames. */ gen_or(b1, b0); /* * Now check for a data frame. * I.e, check "link[0] & 0x08". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; /* * AND that with the checks done for data frames. */ gen_and(b1, b0); /* * If the high-order bit of the type value is 0, this * is a management frame. * I.e, check "!(link[0] & 0x08)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b2 = new_block(cstate, JMP(BPF_JSET)); b2->s.k = 0x08; b2->stmts = s; gen_not(b2); /* * For management frames, the DA is at 4. */ b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* * OR that with the checks done for data frames. * That gives the checks done for management and * data frames. */ gen_or(b1, b0); /* * If the low-order bit of the type value is 1, * this is either a control frame or a frame * with a reserved type, and thus not a * frame with an SA. * * I.e., check "!(link[0] & 0x04)". */ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x04; b1->stmts = s; gen_not(b1); /* * AND that with the checks for data and management * frames. */ gen_and(b1, b0); return b0; case DLT_IP_OVER_FC: b0 = gen_mac_multicast(cstate, 2); return b0; default: break; } /* Link not known to support multicasts */ break; case Q_IP: b0 = gen_linktype(cstate, ETHERTYPE_IP); b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224); gen_and(b0, b1); return b1; case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255); gen_and(b0, b1); return b1; } bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); /*NOTREACHED*/ } struct block * gen_ifindex(compiler_state_t *cstate, int ifindex) { register struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Only some data link types support ifindex qualifiers. */ switch (cstate->linktype) { case DLT_LINUX_SLL2: /* match packets on this interface */ b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex); break; default: #if defined(linux) /* * This is Linux; we require PF_PACKET support. * If this is a *live* capture, we can look at * special meta-data in the filter expression; * if it's a savefile, we can't. */ if (cstate->bpf_pcap->rfile != NULL) { /* We have a FILE *, so this is a savefile */ bpf_error(cstate, "ifindex not supported on %s when reading savefiles", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); b0 = NULL; /*NOTREACHED*/ } /* match ifindex */ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W, ifindex); #else /* defined(linux) */ bpf_error(cstate, "ifindex not supported on %s", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ #endif /* defined(linux) */ } return (b0); } /* * Filter on inbound (dir == 0) or outbound (dir == 1) traffic. * Outbound traffic is sent by this machine, while inbound traffic is * sent by a remote machine (and may include packets destined for a * unicast or multicast link-layer address we are not subscribing to). * These are the same definitions implemented by pcap_setdirection(). * Capturing only unicast traffic destined for this host is probably * better accomplished using a higher-layer filter. */ struct block * gen_inbound(compiler_state_t *cstate, int dir) { register struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Only some data link types support inbound/outbound qualifiers. */ switch (cstate->linktype) { case DLT_SLIP: b0 = gen_relation_internal(cstate, BPF_JEQ, gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1), gen_loadi_internal(cstate, 0), dir); break; case DLT_IPNET: if (dir) { /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND); } else { /* match incoming packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND); } break; case DLT_LINUX_SLL: /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING); if (!dir) { /* to filter on inbound traffic, invert the match */ gen_not(b0); } break; case DLT_LINUX_SLL2: /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING); if (!dir) { /* to filter on inbound traffic, invert the match */ gen_not(b0); } break; case DLT_PFLOG: b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, ((dir == 0) ? PF_IN : PF_OUT)); break; case DLT_PPP_PPPD: if (dir) { /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT); } else { /* match incoming packets */ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN); } break; case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: case DLT_JUNIPER_ATM2: case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_PPPOE_ATM: case DLT_JUNIPER_GGSN: case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: case DLT_JUNIPER_ETHER: case DLT_JUNIPER_PPP: case DLT_JUNIPER_FRELAY: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_VP: case DLT_JUNIPER_ST: case DLT_JUNIPER_ISM: case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: /* juniper flags (including direction) are stored * the byte after the 3-byte magic number */ if (dir) { /* match outgoing packets */ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01); } else { /* match incoming packets */ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01); } break; default: /* * If we have packet meta-data indicating a direction, * and that metadata can be checked by BPF code, check * it. Otherwise, give up, as this link-layer type has * nothing in the packet data. * * Currently, the only platform where a BPF filter can * check that metadata is Linux with the in-kernel * BPF interpreter. If other packet capture mechanisms * and BPF filters also supported this, it would be * nice. It would be even better if they made that * metadata available so that we could provide it * with newer capture APIs, allowing it to be saved * in pcapng files. */ #if defined(linux) /* * This is Linux; we require PF_PACKET support. * If this is a *live* capture, we can look at * special meta-data in the filter expression; * if it's a savefile, we can't. */ if (cstate->bpf_pcap->rfile != NULL) { /* We have a FILE *, so this is a savefile */ bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ } /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, PACKET_OUTGOING); if (!dir) { /* to filter on inbound traffic, invert the match */ gen_not(b0); } #else /* defined(linux) */ bpf_error(cstate, "inbound/outbound not supported on %s", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ #endif /* defined(linux) */ } return (b0); } /* PF firewall log matched interface */ struct block * gen_pf_ifname(compiler_state_t *cstate, const char *ifname) { struct block *b0; u_int len, off; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ifname supported only on PF linktype"); /*NOTREACHED*/ } len = sizeof(((struct pfloghdr *)0)->ifname); off = offsetof(struct pfloghdr, ifname); if (strlen(ifname) >= len) { bpf_error(cstate, "ifname interface names can only be %d characters", len-1); /*NOTREACHED*/ } b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname), (const u_char *)ifname); return (b0); } /* PF firewall log ruleset name */ struct block * gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ruleset supported only on PF linktype"); /*NOTREACHED*/ } if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { bpf_error(cstate, "ruleset names can only be %ld characters", (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); /*NOTREACHED*/ } b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset), (u_int)strlen(ruleset), (const u_char *)ruleset); return (b0); } /* PF firewall log rule number */ struct block * gen_pf_rnr(compiler_state_t *cstate, int rnr) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "rnr supported only on PF linktype"); /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, (bpf_u_int32)rnr); return (b0); } /* PF firewall log sub-rule number */ struct block * gen_pf_srnr(compiler_state_t *cstate, int srnr) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "srnr supported only on PF linktype"); /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, (bpf_u_int32)srnr); return (b0); } /* PF firewall log reason code */ struct block * gen_pf_reason(compiler_state_t *cstate, int reason) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "reason supported only on PF linktype"); /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, (bpf_u_int32)reason); return (b0); } /* PF firewall log action */ struct block * gen_pf_action(compiler_state_t *cstate, int action) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "action supported only on PF linktype"); /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, (bpf_u_int32)action); return (b0); } /* IEEE 802.11 wireless header */ struct block * gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (cstate->linktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask); break; default: bpf_error(cstate, "802.11 link-layer types supported only on 802.11"); /*NOTREACHED*/ } return (b0); } struct block * gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (cstate->linktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: break; default: bpf_error(cstate, "frame direction supported only with 802.11 headers"); /*NOTREACHED*/ } b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir, IEEE80211_FC1_DIR_MASK); return (b0); } struct block * gen_acode(compiler_state_t *cstate, const char *s, struct qual q) { struct block *b; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { cstate->e = pcap_ether_aton(s); if (cstate->e == NULL) bpf_error(cstate, "malloc"); b = gen_ahostop(cstate, cstate->e, (int)q.dir); free(cstate->e); cstate->e = NULL; return (b); } else bpf_error(cstate, "ARCnet address used in non-arc expression"); - /*NOTREACHED*/ + /*NOTREACHED*/ default: bpf_error(cstate, "aid supported only on ARCnet"); /*NOTREACHED*/ } } static struct block * gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1; switch (dir) { /* src comes first, different from Ethernet */ case Q_SRC: return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr); case Q_DST: return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr); case Q_AND: b0 = gen_ahostop(cstate, eaddr, Q_SRC); b1 = gen_ahostop(cstate, eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ahostop(cstate, eaddr, Q_SRC); b1 = gen_ahostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); - /*NOTREACHED*/ + /*NOTREACHED*/ } abort(); /*NOTREACHED*/ } static struct block * gen_vlan_tpid_test(compiler_state_t *cstate) { struct block *b0, *b1; /* check for VLAN, including 802.1ad and QinQ */ b0 = gen_linktype(cstate, ETHERTYPE_8021Q); b1 = gen_linktype(cstate, ETHERTYPE_8021AD); gen_or(b0,b1); b0 = b1; b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ); gen_or(b0,b1); return b1; } static struct block * gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num) { if (vlan_num > 0x0fff) { bpf_error(cstate, "VLAN tag %u greater than maximum %u", vlan_num, 0x0fff); } return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff); } static struct block * gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag) { struct block *b0, *b1; b0 = gen_vlan_tpid_test(cstate); if (has_vlan_tag) { b1 = gen_vlan_vid_test(cstate, vlan_num); gen_and(b0, b1); b0 = b1; } /* * Both payload and link header type follow the VLAN tags so that * both need to be updated. */ cstate->off_linkpl.constant_part += 4; cstate->off_linktype.constant_part += 4; return b0; } #if defined(SKF_AD_VLAN_TAG_PRESENT) /* add v to variable part of off */ static void gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, bpf_u_int32 v, struct slist *s) { struct slist *s2; if (!off->is_variable) off->is_variable = 1; if (off->reg == -1) off->reg = alloc_reg(cstate); s2 = new_stmt(cstate, BPF_LD|BPF_MEM); s2->s.k = off->reg; sappend(s, s2); s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = v; sappend(s, s2); s2 = new_stmt(cstate, BPF_ST); s2->s.k = off->reg; sappend(s, s2); } /* * patch block b_tpid (VLAN TPID test) to update variable parts of link payload * and link type offsets first */ static void gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid) { struct slist s; /* offset determined at run time, shift variable part */ s.next = NULL; cstate->is_vlan_vloffset = 1; gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s); gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s); /* we get a pointer to a chain of or-ed blocks, patch first of them */ sappend(s.next, b_tpid->head->stmts); b_tpid->head->stmts = s.next; } /* * patch block b_vid (VLAN id test) to load VID value either from packet * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true */ static void gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid) { struct slist *s, *s2, *sjeq; unsigned cnt; s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; /* true -> next instructions, false -> beginning of b_vid */ sjeq = new_stmt(cstate, JMP(BPF_JEQ)); sjeq->s.k = 1; sjeq->s.jf = b_vid->stmts; sappend(s, sjeq); s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; sappend(s, s2); sjeq->s.jt = s2; /* Jump to the test in b_vid. We need to jump one instruction before * the end of the b_vid block so that we only skip loading the TCI * from packet data and not the 'and' instruction extractging VID. */ cnt = 0; for (s2 = b_vid->stmts; s2; s2 = s2->next) cnt++; s2 = new_stmt(cstate, JMP(BPF_JA)); s2->s.k = cnt - 1; sappend(s, s2); /* insert our statements at the beginning of b_vid */ sappend(s, b_vid->stmts); b_vid->stmts = s; } /* * Generate check for "vlan" or "vlan " on systems with support for BPF * extensions. Even if kernel supports VLAN BPF extensions, (outermost) VLAN * tag can be either in metadata or in packet data; therefore if the * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link * header for VLAN tag. As the decision is done at run time, we need * update variable part of the offsets */ static struct block * gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag) { struct block *b0, *b_tpid, *b_vid = NULL; struct slist *s; /* generate new filter code based on extracting packet * metadata */ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; b0 = new_block(cstate, JMP(BPF_JEQ)); b0->stmts = s; b0->s.k = 1; /* * This is tricky. We need to insert the statements updating variable * parts of offsets before the traditional TPID and VID tests so * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but * we do not want this update to affect those checks. That's why we * generate both test blocks first and insert the statements updating * variable parts of both offsets after that. This wouldn't work if * there already were variable length link header when entering this * function but gen_vlan_bpf_extensions() isn't called in that case. */ b_tpid = gen_vlan_tpid_test(cstate); if (has_vlan_tag) b_vid = gen_vlan_vid_test(cstate, vlan_num); gen_vlan_patch_tpid_test(cstate, b_tpid); gen_or(b0, b_tpid); b0 = b_tpid; if (has_vlan_tag) { gen_vlan_patch_vid_test(cstate, b_vid); gen_and(b0, b_vid); b0 = b_vid; } return b0; } #endif /* * support IEEE 802.1Q VLAN trunk over ethernet */ struct block * gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag) { struct block *b0; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* can't check for VLAN-encapsulated packets inside MPLS */ if (cstate->label_stack_depth > 0) bpf_error(cstate, "no VLAN match after MPLS"); /* * Check for a VLAN packet, and then change the offsets to point * to the type and data fields within the VLAN packet. Just * increment the offsets, so that we can support a hierarchy, e.g. * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within * VLAN 100. * * XXX - this is a bit of a kludge. If we were to split the * compiler into a parser that parses an expression and * generates an expression tree, and a code generator that * takes an expression tree (which could come from our * parser or from some other parser) and generates BPF code, * we could perhaps make the offsets parameters of routines * and, in the handler for an "AND" node, pass to subnodes * other than the VLAN node the adjusted offsets. * * This would mean that "vlan" would, instead of changing the * behavior of *all* tests after it, change only the behavior * of tests ANDed with it. That would change the documented * semantics of "vlan", which might break some expressions. * However, it would mean that "(vlan and ip) or ip" would check * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than * checking only for VLAN-encapsulated IP, so that could still * be considered worth doing; it wouldn't break expressions * that are of the form "vlan and ..." or "vlan N and ...", * which I suspect are the most common expressions involving * "vlan". "vlan or ..." doesn't necessarily do what the user * would really want, now, as all the "or ..." tests would * be done assuming a VLAN, even though the "or" could be viewed * as meaning "or, if this isn't a VLAN packet...". */ switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: #if defined(SKF_AD_VLAN_TAG_PRESENT) /* Verify that this is the outer part of the packet and * not encapsulated somehow. */ if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable && cstate->off_linkhdr.constant_part == cstate->off_outermostlinkhdr.constant_part) { /* * Do we need special VLAN handling? */ if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING) b0 = gen_vlan_bpf_extensions(cstate, vlan_num, has_vlan_tag); else b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag); } else #endif b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag); break; default: bpf_error(cstate, "no VLAN support for %s", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ } cstate->vlan_stack_depth++; return (b0); } /* * support for MPLS * * The label_num_arg dance is to avoid annoying whining by compilers that * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*? * It's not *used* after setjmp returns. */ struct block * gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg, int has_label_num) { volatile bpf_u_int32 label_num = label_num_arg; struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); if (cstate->label_stack_depth > 0) { /* just match the bottom-of-stack bit clear */ b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); } else { /* * We're not in an MPLS stack yet, so check the link-layer * type against MPLS. */ switch (cstate->linktype) { case DLT_C_HDLC: /* fall through */ case DLT_HDLC: case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: b0 = gen_linktype(cstate, ETHERTYPE_MPLS); break; case DLT_PPP: b0 = gen_linktype(cstate, PPP_MPLS_UCAST); break; /* FIXME add other DLT_s ... * for Frame-Relay/and ATM this may get messy due to SNAP headers * leave it for now */ default: bpf_error(cstate, "no MPLS support for %s", pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ } } /* If a specific MPLS label is requested, check it */ if (has_label_num) { if (label_num > 0xFFFFF) { bpf_error(cstate, "MPLS label %u greater than maximum %u", label_num, 0xFFFFF); } label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num, 0xfffff000); /* only compare the first 20 bits */ gen_and(b0, b1); b0 = b1; } /* * Change the offsets to point to the type and data fields within * the MPLS packet. Just increment the offsets, so that we * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to * capture packets with an outer label of 100000 and an inner * label of 1024. * * Increment the MPLS stack depth as well; this indicates that * we're checking MPLS-encapsulated headers, to make sure higher * level code generators don't try to match against IP-related * protocols such as Q_ARP, Q_RARP etc. * * XXX - this is a bit of a kludge. See comments in gen_vlan(). */ cstate->off_nl_nosnap += 4; cstate->off_nl += 4; cstate->label_stack_depth++; return (b0); } /* * Support PPPOE discovery and session. */ struct block * gen_pppoed(compiler_state_t *cstate) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* check for PPPoE discovery */ return gen_linktype(cstate, ETHERTYPE_PPPOED); } struct block * gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); /* * Test against the PPPoE session link-layer type. */ b0 = gen_linktype(cstate, ETHERTYPE_PPPOES); /* If a specific session is requested, check PPPoE session id */ if (has_sess_num) { if (sess_num > 0x0000ffff) { bpf_error(cstate, "PPPoE session number %u greater than maximum %u", sess_num, 0x0000ffff); } b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff); gen_and(b0, b1); b0 = b1; } /* * Change the offsets to point to the type and data fields within * the PPP packet, and note that this is PPPoE rather than * raw PPP. * * XXX - this is a bit of a kludge. See the comments in * gen_vlan(). * * The "network-layer" protocol is PPPoE, which has a 6-byte * PPPoE header, followed by a PPP packet. * * There is no HDLC encapsulation for the PPP packet (it's * encapsulated in PPPoES instead), so the link-layer type * starts at the first byte of the PPP packet. For PPPoE, * that offset is relative to the beginning of the total * link-layer payload, including any 802.2 LLC header, so * it's 6 bytes past cstate->off_nl. */ PUSH_LINKHDR(cstate, DLT_PPP, cstate->off_linkpl.is_variable, cstate->off_linkpl.constant_part + cstate->off_nl + 6, /* 6 bytes past the PPPoE header */ cstate->off_linkpl.reg); cstate->off_linktype = cstate->off_linkhdr; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 2; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ return b0; } /* Check that this is Geneve and the VNI is correct if * specified. Parameterized to handle both IPv4 and IPv6. */ static struct block * gen_geneve_check(compiler_state_t *cstate, struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int), enum e_offrel offrel, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST); /* Check that we are operating on version 0. Otherwise, we * can't decode the rest of the fields. The version is 2 bits * in the first byte of the Geneve header. */ b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0); gen_and(b0, b1); b0 = b1; if (has_vni) { if (vni > 0xffffff) { bpf_error(cstate, "Geneve VNI %u greater than maximum %u", vni, 0xffffff); } vni <<= 8; /* VNI is in the upper 3 bytes */ b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00); gen_and(b0, b1); b0 = b1; } return b0; } /* The IPv4 and IPv6 Geneve checks need to do two things: * - Verify that this actually is Geneve with the right VNI. * - Place the IP header length (plus variable link prefix if * needed) into register A to be used later to compute * the inner packet offsets. */ static struct block * gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s, *s1; b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni); /* Load the IP header length into A. */ s = gen_loadx_iphdrlen(cstate); s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s1); /* Forcibly append these statements to the true condition * of the protocol check by creating a new block that is * always true and ANDing them. */ b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b1->stmts = s; b1->s.k = 0; gen_and(b0, b1); return b1; } static struct block * gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s, *s1; b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni); /* Load the IP header length. We need to account for a * variable length link prefix if there is one. */ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); if (s) { s1 = new_stmt(cstate, BPF_LD|BPF_IMM); s1->s.k = 40; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s1->s.k = 0; sappend(s, s1); } else { s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = 40; } /* Forcibly append these statements to the true condition * of the protocol check by creating a new block that is * always true and ANDing them. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b1->stmts = s; b1->s.k = 0; gen_and(b0, b1); return b1; } /* We need to store three values based on the Geneve header:: * - The offset of the linktype. * - The offset of the end of the Geneve header. * - The offset of the end of the encapsulated MAC header. */ static struct slist * gen_geneve_offsets(compiler_state_t *cstate) { struct slist *s, *s1, *s_proto; /* First we need to calculate the offset of the Geneve header * itself. This is composed of the IP header previously calculated * (include any variable link prefix) and stored in A plus the * fixed sized headers (fixed link prefix, MAC length, and UDP * header). */ s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8; /* Stash this in X since we'll need it later. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); /* The EtherType in Geneve is 2 bytes in. Calculate this and * store it. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 2; sappend(s, s1); cstate->off_linktype.reg = alloc_reg(cstate); cstate->off_linktype.is_variable = 1; cstate->off_linktype.constant_part = 0; s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linktype.reg; sappend(s, s1); /* Load the Geneve option length and mask and shift to get the * number of bytes. It is stored in the first byte of the Geneve * header. */ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s1->s.k = 0; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s1->s.k = 0x3f; sappend(s, s1); s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s1->s.k = 4; sappend(s, s1); /* Add in the rest of the Geneve base header. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 8; sappend(s, s1); /* Add the Geneve header length to its offset and store. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s1->s.k = 0; sappend(s, s1); /* Set the encapsulated type as Ethernet. Even though we may * not actually have Ethernet inside there are two reasons this * is useful: * - The linktype field is always in EtherType format regardless * of whether it is in Geneve or an inner Ethernet frame. * - The only link layer that we have specific support for is * Ethernet. We will confirm that the packet actually is * Ethernet at runtime before executing these checks. */ PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate)); s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linkhdr.reg; sappend(s, s1); /* Calculate whether we have an Ethernet header or just raw IP/ * MPLS/etc. If we have Ethernet, advance the end of the MAC offset * and linktype by 14 bytes so that the network header can be found * seamlessly. Otherwise, keep what we've calculated already. */ /* We have a bare jmp so we can't use the optimizer. */ cstate->no_optimize = 1; /* Load the EtherType in the Geneve header, 2 bytes in. */ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H); s1->s.k = 2; sappend(s, s1); /* Load X with the end of the Geneve header. */ s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); s1->s.k = cstate->off_linkhdr.reg; sappend(s, s1); /* Check if the EtherType is Transparent Ethernet Bridging. At the * end of this check, we should have the total length in X. In * the non-Ethernet case, it's already there. */ s_proto = new_stmt(cstate, JMP(BPF_JEQ)); s_proto->s.k = ETHERTYPE_TEB; sappend(s, s_proto); s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s1); s_proto->s.jt = s1; /* Since this is Ethernet, use the EtherType of the payload * directly as the linktype. Overwrite what we already have. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 12; sappend(s, s1); s1 = new_stmt(cstate, BPF_ST); s1->s.k = cstate->off_linktype.reg; sappend(s, s1); /* Advance two bytes further to get the end of the Ethernet * header. */ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s1->s.k = 2; sappend(s, s1); /* Move the result to X. */ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s, s1); /* Store the final result of our linkpl calculation. */ cstate->off_linkpl.reg = alloc_reg(cstate); cstate->off_linkpl.is_variable = 1; cstate->off_linkpl.constant_part = 0; s1 = new_stmt(cstate, BPF_STX); s1->s.k = cstate->off_linkpl.reg; sappend(s, s1); s_proto->s.jf = s1; cstate->off_nl = 0; return s; } /* Check to see if this is a Geneve packet. */ struct block * gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); b0 = gen_geneve4(cstate, vni, has_vni); b1 = gen_geneve6(cstate, vni, has_vni); gen_or(b0, b1); b0 = b1; /* Later filters should act on the payload of the Geneve frame, * update all of the header pointers. Attach this code so that * it gets executed in the event that the Geneve filter matches. */ s = gen_geneve_offsets(cstate); b1 = gen_true(cstate); sappend(s, b1->stmts); b1->stmts = s; gen_and(b0, b1); cstate->is_geneve = 1; return b1; } /* Check that the encapsulated frame has a link layer header * for Ethernet filters. */ static struct block * gen_geneve_ll_check(compiler_state_t *cstate) { struct block *b0; struct slist *s, *s1; /* The easiest way to see if there is a link layer present * is to check if the link layer header and payload are not * the same. */ /* Geneve always generates pure variable offsets so we can * compare only the registers. */ s = new_stmt(cstate, BPF_LD|BPF_MEM); s->s.k = cstate->off_linkhdr.reg; s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); s1->s.k = cstate->off_linkpl.reg; sappend(s, s1); b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); b0->stmts = s; b0->s.k = 0; gen_not(b0); return b0; } static struct block * gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield, bpf_u_int32 jvalue, int jtype, int reverse) { struct block *b0; switch (atmfield) { case A_VPI: if (!cstate->is_atm) bpf_error(cstate, "'vpi' supported only on raw ATM"); if (cstate->off_vpi == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffffU, jtype, reverse, jvalue); break; case A_VCI: if (!cstate->is_atm) bpf_error(cstate, "'vci' supported only on raw ATM"); if (cstate->off_vci == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffffU, jtype, reverse, jvalue); break; case A_PROTOTYPE: if (cstate->off_proto == OFFSET_NOT_SET) abort(); /* XXX - this isn't on FreeBSD */ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0fU, jtype, reverse, jvalue); break; case A_MSGTYPE: if (cstate->off_payload == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B, 0xffffffffU, jtype, reverse, jvalue); break; case A_CALLREFTYPE: if (!cstate->is_atm) bpf_error(cstate, "'callref' supported only on raw ATM"); if (cstate->off_proto == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffffU, jtype, reverse, jvalue); break; default: abort(); } return b0; } static struct block * gen_atmtype_metac(compiler_state_t *cstate) { struct block *b0, *b1; b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0); gen_and(b0, b1); return b1; } static struct block * gen_atmtype_sc(compiler_state_t *cstate) { struct block *b0, *b1; b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0); gen_and(b0, b1); return b1; } static struct block * gen_atmtype_llc(compiler_state_t *cstate) { struct block *b0; b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); cstate->linktype = cstate->prevlinktype; return b0; } struct block * gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_u_int32 jvalue, int jtype, int reverse) { /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype, reverse); } struct block * gen_atmtype_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (type) { case A_METAC: /* Get all packets in Meta signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'metac' supported only on raw ATM"); b1 = gen_atmtype_metac(cstate); break; case A_BCC: /* Get all packets in Broadcast Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'bcc' supported only on raw ATM"); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4SC: /* Get all cells in Segment OAM F4 circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4sc' supported only on raw ATM"); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4EC: /* Get all cells in End-to-End OAM F4 Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4ec' supported only on raw ATM"); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); gen_and(b0, b1); break; case A_SC: /* Get all packets in connection Signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'sc' supported only on raw ATM"); b1 = gen_atmtype_sc(cstate); break; case A_ILMIC: /* Get all packets in ILMI Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'ilmic' supported only on raw ATM"); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0); gen_and(b0, b1); break; case A_LANE: /* Get all LANE packets */ if (!cstate->is_atm) bpf_error(cstate, "'lane' supported only on raw ATM"); b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); /* * Arrange that all subsequent tests assume LANE * rather than LLC-encapsulated packets, and set * the offsets appropriately for LANE-encapsulated * Ethernet. * * We assume LANE means Ethernet, not Token Ring. */ PUSH_LINKHDR(cstate, DLT_EN10MB, 0, cstate->off_payload + 2, /* Ethernet header */ -1); cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* Ethernet */ cstate->off_nl = 0; /* Ethernet II */ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ break; case A_LLC: /* Get all LLC-encapsulated packets */ if (!cstate->is_atm) bpf_error(cstate, "'llc' supported only on raw ATM"); b1 = gen_atmtype_llc(cstate); break; default: abort(); } return b1; } /* * Filtering for MTP2 messages based on li value * FISU, length is null * LSSU, length is 1 or 2 * MSU, length is 3 or more * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits */ struct block * gen_mtp2type_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (type) { case M_FISU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'fisu' supported only on MTP2"); /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3fU, BPF_JEQ, 0, 0U); break; case M_LSSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'lssu' supported only on MTP2"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3fU, BPF_JGT, 1, 2U); b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3fU, BPF_JGT, 0, 0U); gen_and(b1, b0); break; case M_MSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'msu' supported only on MTP2"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3fU, BPF_JGT, 0, 2U); break; case MH_FISU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hfisu' supported only on MTP2_HSL"); /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80U, BPF_JEQ, 0, 0U); break; case MH_LSSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hlssu' supported only on MTP2_HSL"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80U, BPF_JGT, 1, 0x0100U); b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80U, BPF_JGT, 0, 0U); gen_and(b1, b0); break; case MH_MSU: if ( (cstate->linktype != DLT_MTP2) && (cstate->linktype != DLT_ERF) && (cstate->linktype != DLT_MTP2_WITH_PHDR) ) bpf_error(cstate, "'hmsu' supported only on MTP2_HSL"); b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80U, BPF_JGT, 0, 0x0100U); break; default: abort(); } return b0; } /* * The jvalue_arg dance is to avoid annoying whining by compilers that * jvalue might be clobbered by longjmp - yeah, it might, but *WHO CARES*? * It's not *used* after setjmp returns. */ struct block * gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue_arg, int jtype, int reverse) { volatile bpf_u_int32 jvalue = jvalue_arg; struct block *b0; bpf_u_int32 val1 , val2 , val3; u_int newoff_sio; u_int newoff_opc; u_int newoff_dpc; u_int newoff_sls; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); newoff_sio = cstate->off_sio; newoff_opc = cstate->off_opc; newoff_dpc = cstate->off_dpc; newoff_sls = cstate->off_sls; switch (mtp3field) { case MH_SIO: newoff_sio += 3; /* offset for MTP2_HSL */ /* FALLTHROUGH */ case M_SIO: if (cstate->off_sio == OFFSET_NOT_SET) bpf_error(cstate, "'sio' supported only on SS7"); /* sio coded on 1 byte so max value 255 */ if(jvalue > 255) bpf_error(cstate, "sio value %u too big; max value = 255", jvalue); b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU, jtype, reverse, jvalue); break; case MH_OPC: newoff_opc += 3; /* FALLTHROUGH */ case M_OPC: if (cstate->off_opc == OFFSET_NOT_SET) bpf_error(cstate, "'opc' supported only on SS7"); /* opc coded on 14 bits so max value 16383 */ if (jvalue > 16383) bpf_error(cstate, "opc value %u too big; max value = 16383", jvalue); /* the following instructions are made to convert jvalue * to the form used to write opc in an ss7 message*/ val1 = jvalue & 0x00003c00; val1 = val1 >>10; val2 = jvalue & 0x000003fc; val2 = val2 <<6; val3 = jvalue & 0x00000003; val3 = val3 <<22; jvalue = val1 + val2 + val3; b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU, jtype, reverse, jvalue); break; case MH_DPC: newoff_dpc += 3; /* FALLTHROUGH */ case M_DPC: if (cstate->off_dpc == OFFSET_NOT_SET) bpf_error(cstate, "'dpc' supported only on SS7"); /* dpc coded on 14 bits so max value 16383 */ if (jvalue > 16383) bpf_error(cstate, "dpc value %u too big; max value = 16383", jvalue); /* the following instructions are made to convert jvalue * to the forme used to write dpc in an ss7 message*/ val1 = jvalue & 0x000000ff; val1 = val1 << 24; val2 = jvalue & 0x00003f00; val2 = val2 << 8; jvalue = val1 + val2; b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U, jtype, reverse, jvalue); break; case MH_SLS: newoff_sls += 3; /* FALLTHROUGH */ case M_SLS: if (cstate->off_sls == OFFSET_NOT_SET) bpf_error(cstate, "'sls' supported only on SS7"); /* sls coded on 4 bits so max value 15 */ if (jvalue > 15) bpf_error(cstate, "sls value %u too big; max value = 15", jvalue); /* the following instruction is made to convert jvalue * to the forme used to write sls in an ss7 message*/ jvalue = jvalue << 4; b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U, jtype, reverse, jvalue); break; default: abort(); } return b0; } static struct block * gen_msg_abbrev(compiler_state_t *cstate, int type) { struct block *b1; /* * Q.2931 signalling protocol messages for handling virtual circuits * establishment and teardown */ switch (type) { case A_SETUP: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); break; case A_CALLPROCEED: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); break; case A_CONNECT: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); break; case A_CONNECTACK: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); break; case A_RELEASE: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); break; case A_RELEASE_DONE: b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); break; default: abort(); } return b1; } struct block * gen_atmmulti_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; /* * Catch errors reported by us and routines below us, and return NULL * on an error. */ if (setjmp(cstate->top_ctx)) return (NULL); switch (type) { case A_OAM: if (!cstate->is_atm) bpf_error(cstate, "'oam' supported only on raw ATM"); /* OAM F4 type */ b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); gen_or(b0, b1); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4: if (!cstate->is_atm) bpf_error(cstate, "'oamf4' supported only on raw ATM"); /* OAM F4 type */ b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); gen_or(b0, b1); b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); gen_and(b0, b1); break; case A_CONNECTMSG: /* * Get Q.2931 signalling messages for switched * virtual connection */ if (!cstate->is_atm) bpf_error(cstate, "'connectmsg' supported only on raw ATM"); b0 = gen_msg_abbrev(cstate, A_SETUP); b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECTACK); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); b0 = gen_atmtype_sc(cstate); gen_and(b0, b1); break; case A_METACONNECT: if (!cstate->is_atm) bpf_error(cstate, "'metaconnect' supported only on raw ATM"); b0 = gen_msg_abbrev(cstate, A_SETUP); b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); b0 = gen_atmtype_metac(cstate); gen_and(b0, b1); break; default: abort(); } return b1; } diff --git a/mkdep b/mkdep index ef120bdb2b3a..f85a447a79c6 100755 --- a/mkdep +++ b/mkdep @@ -1,121 +1,121 @@ #!/bin/sh - # # Copyright (c) 1994, 1996 # The Regents of the University of California. All rights reserved. # # Redistribution and use in source and binary forms are permitted # provided that this notice is preserved and that due credit is given # to the University of California at Berkeley. The name of the University # may not be used to endorse or promote products derived from this # software without specific prior written permission. This software # is provided ``as is'' without express or implied warranty. # # @(#)mkdep.sh 5.11 (Berkeley) 5/5/88 # MAKE=Makefile # default makefile name is "Makefile" CC=cc # default C compiler is "cc" DEPENDENCY_CFLAG=-M # default dependency-generation flag is -M SOURCE_DIRECTORY=. # default source directory is the current directory # No command-line flags seen yet. flags="" while : do case "$1" in # -c allows you to specify the C compiler -c) CC=$2 shift; shift ;; # -f allows you to select a makefile name -f) MAKE=$2 shift; shift ;; # -m allows you to specify the dependency-generation flag -m) DEPENDENCY_CFLAG=$2 shift; shift ;; # the -p flag produces "program: program.c" style dependencies # so .o's don't get produced -p) SED='s;\.o;;' shift ;; # -s allows you to specify the source directory -s) SOURCE_DIRECTORY=$2 shift; shift ;; # -include takes an argument -include) flags="$flags $1 $2" shift; shift ;; # other command-line flag -*) flags="$flags $1" shift ;; *) break ;; esac done if [ $# = 0 ] ; then echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [-s source-directory] [flags] file ...' exit 1 fi if [ ! -w $MAKE ]; then echo "mkdep: no writeable file \"$MAKE\"" exit 1 fi TMP=/tmp/mkdep$$ trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 cp $MAKE ${MAKE}.bak sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP cat << _EOF_ >> $TMP # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. _EOF_ # If your compiler doesn't have -M, add it. If you can't, the next two # lines will try and replace the "cc -M". The real problem is that this # hack can't deal with anything that requires a search path, and doesn't # even try for anything using bracket (<>) syntax. # -# egrep '^#include[ ]*".*"' /dev/null $* | +# grep -E '^#include[[:blank:]]*".*"' /dev/null $* | # sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | # # Construct a list of source files with paths relative to the source directory. # sources="" for srcfile in $* do sources="$sources $SOURCE_DIRECTORY/$srcfile" done # XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait" $CC $DEPENDENCY_CFLAG $flags $sources | sed " s; \./; ;g $SED" >> $TMP cat << _EOF_ >> $TMP # IF YOU PUT ANYTHING HERE IT WILL GO AWAY _EOF_ # copy to preserve permissions cp $TMP $MAKE rm -f ${MAKE}.bak $TMP exit 0 diff --git a/msdos/makefile b/msdos/makefile index 599a619f402e..84819aae3f0c 100644 --- a/msdos/makefile +++ b/msdos/makefile @@ -1,180 +1,180 @@ # # Makefile for dos-libpcap. NB. This makefile requires a Borland # compatible make tool. # # Targets: # Borland C 4.0+ (DOS large model) # Metaware HighC 3.3+ (PharLap 386|DosX) # .AUTODEPEND .SWAP !if "$(WATT_ROOT)" == "" !error Environment variable "WATT_ROOT" not set. !endif WATT_INC = $(WATT_ROOT)\inc DEFS = -DMSDOS -DDEBUG -DNDIS_DEBUG -D_U_= -Dinline= \ -DHAVE_STRERROR -DHAVE_LIMITS_H ASM = tasm.exe -t -l -mx -m2 -DDEBUG SOURCE = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ savefile.c pcap.c msdos\ndis2.c msdos\pktdrvr.c \ missing\snprintf.c BORLAND_OBJ = $(SOURCE:.c=.obj) msdos\pkt_rx0.obj msdos\ndis_0.obj HIGHC_OBJ = $(SOURCE:.c=.o32) msdos\pkt_rx0.o32 all: @echo Usage: make pcap_bc.lib or pcap_hc.lib pcap_bc.lib: bcc.arg $(BORLAND_OBJ) pcap_bc pcap_hc.lib: hc386.arg $(HIGHC_OBJ) 386lib $< @&&| -nowarn -nobackup -twocase -replace $(HIGHC_OBJ) | pcap_bc: $(BORLAND_OBJ) @tlib pcap_bc.lib /C @&&| -+$(**:.obj=-+) | .c.obj: bcc.exe @bcc.arg -o$*.obj $*.c .c.o32: hc386.exe @hc386.arg -o $*.o32 $*.c .asm.obj: $(ASM) $*.asm, $*.obj .asm.o32: $(ASM) -DDOSX=1 $*.asm, $*.o32 scanner.c: scanner.l flex -Ppcap_ -7 -oscanner.c scanner.l grammar.c tokdefs.h: grammar.y bison --name-prefix=pcap_ --yacc --defines grammar.y - @del grammar.c - @del tokdefs.h ren y_tab.c grammar.c ren y_tab.h tokdefs.h bcc.arg: msdos\Makefile @copy &&| $(DEFS) -ml -c -v -3 -O2 -po -RT- -w- -I$(WATT_INC) -I. -I.\msdos\pm_drvr -H=$(TEMP)\bcc.sym | $< hc386.arg: msdos\Makefile @copy &&| # -DUSE_32BIT_DRIVERS $(DEFS) -DDOSX=1 -w3 -c -g -O5 -I$(WATT_INC) -I. -I.\msdos\pm_drvr -Hsuffix=.o32 -Hnocopyr -Hpragma=Offwarn(491,553,572) -Hon=Recognize_library # make memcpy/strlen etc. inline -Hoff=Behaved # turn off some optimiser warnings | $< clean: @del *.obj @del *.o32 @del *.lst @del *.map @del bcc.arg @del hc386.arg @del grammar.c @del tokdefs.h @del scanner.c @echo Cleaned # # dependencies # pkt_rx0.obj: msdos\pkt_rx0.asm -bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h +bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pf.h pcap-namedb.h scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h tokdefs.h gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ arcnet.h pf.h pcap-namedb.h nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h ethertype.h pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ msdos\pktdrvr.h -pktdrvr.obj: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ +pktdrvr.obj: msdos\pktdrvr.c pcap-dos.h pcap-int.h \ pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ msdos\ndis2.h pkt_rx0.o32: msdos\pkt_rx0.asm -bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h gnuc.h +bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h bpf_imag.o32: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h bpf_dump.o32: bpf_dump.c pcap.h pcap-bpf.h etherent.o32: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h optimize.o32: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h savefile.o32: savefile.c pcap-int.h pcap.h pcap-bpf.h pcap.o32: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h grammar.o32: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pf.h pcap-namedb.h scanner.o32: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h tokdefs.h gencode.o32: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ arcnet.h pf.h pcap-namedb.h nametoad.o32: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ pcap-namedb.h ethertype.h pcap-dos.o32: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ msdos\pktdrvr.h -pktdrvr.o32: msdos\pktdrvr.c gnuc.h pcap-dos.h pcap-int.h \ +pktdrvr.o32: msdos\pktdrvr.c pcap-dos.h pcap-int.h \ pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc ndis2.o32: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ msdos\ndis2.h diff --git a/nametoaddr.c b/nametoaddr.c index 55f93897b9f8..7a04a61dbd6c 100644 --- a/nametoaddr.c +++ b/nametoaddr.c @@ -1,825 +1,825 @@ /* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Name to id translation routines used by the scanner. * These functions are not time critical. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef DECNETLIB #include #include #endif #ifdef _WIN32 #include #include #ifdef INET6 /* * To quote the MSDN page for getaddrinfo() at * * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx * * "Support for getaddrinfo on Windows 2000 and older versions * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and * later. To execute an application that uses this function on earlier * versions of Windows, then you need to include the Ws2tcpip.h and * Wspiapi.h files. When the Wspiapi.h include file is added, the * getaddrinfo function is defined to the WspiapiGetAddrInfo inline * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo * function is implemented in such a way that if the Ws2_32.dll or the * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology * Preview for Windows 2000) does not include getaddrinfo, then a * version of getaddrinfo is implemented inline based on code in the * Wspiapi.h header file. This inline code will be used on older Windows * platforms that do not natively support the getaddrinfo function." * * We use getaddrinfo(), so we include Wspiapi.h here. */ #include #endif /* INET6 */ #else /* _WIN32 */ #include #include #include #include #include #ifdef HAVE_ETHER_HOSTTON #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) /* * OK, just include . */ #include #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) /* * OK, just include */ #include #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) /* * OK, just include */ #include #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON) /* * OK, just include */ #include #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) /* * OK, include , after all the other stuff we * need to include or define for its benefit. */ #define NEED_NETINET_IF_ETHER_H #else /* * We'll have to declare it ourselves. * If defines struct ether_addr, include * it. Otherwise, define it ourselves. */ #ifdef HAVE_STRUCT_ETHER_ADDR #define NEED_NETINET_IF_ETHER_H #else /* HAVE_STRUCT_ETHER_ADDR */ struct ether_addr { unsigned char ether_addr_octet[6]; }; #endif /* HAVE_STRUCT_ETHER_ADDR */ #endif /* what declares ether_hostton() */ #ifdef NEED_NETINET_IF_ETHER_H #include /* Needed on some platforms */ #include /* Needed on some platforms */ #include #endif /* NEED_NETINET_IF_ETHER_H */ #ifndef HAVE_DECL_ETHER_HOSTTON /* * No header declares it, so declare it ourselves. */ extern int ether_hostton(const char *, struct ether_addr *); #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */ #endif /* HAVE_ETHER_HOSTTON */ #include #include #endif /* _WIN32 */ #include #include #include #include #include "pcap-int.h" #include "diag-control.h" #include "gencode.h" #include #include "nametoaddr.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifndef NTOHL #define NTOHL(x) (x) = ntohl(x) #define NTOHS(x) (x) = ntohs(x) #endif /* * Convert host name to internet address. * Return 0 upon failure. * XXX - not thread-safe; don't use it inside libpcap. */ bpf_u_int32 ** pcap_nametoaddr(const char *name) { #ifndef h_addr static bpf_u_int32 *hlist[2]; #endif bpf_u_int32 **p; struct hostent *hp; /* * gethostbyname() is deprecated on Windows, perhaps because * it's not thread-safe, or because it doesn't support IPv6, * or both. * * We deprecate pcap_nametoaddr() on all platforms because * it's not thread-safe; we supply it for backwards compatibility, * so suppress the deprecation warning. We could, I guess, * use getaddrinfo() and construct the array ourselves, but * that's probably not worth the effort, as that wouldn't make * this thread-safe - we can't change the API to require that * our caller free the address array, so we still have to reuse * a local array. */ DIAG_OFF_DEPRECATION if ((hp = gethostbyname(name)) != NULL) { DIAG_ON_DEPRECATION #ifndef h_addr hlist[0] = (bpf_u_int32 *)hp->h_addr; NTOHL(hp->h_addr); return hlist; #else for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p) NTOHL(**p); return (bpf_u_int32 **)hp->h_addr_list; #endif } else return 0; } struct addrinfo * pcap_nametoaddrinfo(const char *name) { struct addrinfo hints, *res; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /*not really*/ hints.ai_protocol = IPPROTO_TCP; /*not really*/ error = getaddrinfo(name, NULL, &hints, &res); if (error) return NULL; else return res; } /* * Convert net name to internet address. * Return 0 upon failure. * XXX - not guaranteed to be thread-safe! See below for platforms * on which it is thread-safe and on which it isn't. */ #if defined(_WIN32) || defined(__CYGWIN__) bpf_u_int32 pcap_nametonetaddr(const char *name _U_) { /* * There's no "getnetbyname()" on Windows. * * XXX - I guess we could use the BSD code to read * C:\Windows\System32\drivers\etc/networks, assuming * that's its home on all the versions of Windows * we use, but that file probably just has the loopback * network on 127/24 on 99 44/100% of Windows machines. * * (Heck, these days it probably just has that on 99 44/100% * of *UN*X* machines.) */ return 0; } #else /* _WIN32 */ bpf_u_int32 pcap_nametonetaddr(const char *name) { /* * UN*X. */ struct netent *np; #if defined(HAVE_LINUX_GETNETBYNAME_R) /* * We have Linux's reentrant getnetbyname_r(). */ struct netent result_buf; char buf[1024]; /* arbitrary size */ int h_errnoval; int err; /* * Apparently, the man page at * * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html * * lies when it says * * If the function call successfully obtains a network record, * then *result is set pointing to result_buf; otherwise, *result * is set to NULL. * * and, in fact, at least in some versions of GNU libc, it does * *not* always get set if getnetbyname_r() succeeds. */ np = NULL; - err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, + err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, &h_errnoval); if (err != 0) { /* * XXX - dynamically allocate the buffer, and make it * bigger if we get ERANGE back? */ return 0; } #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) /* * We have Solaris's and IRIX's reentrant getnetbyname_r(). */ struct netent result_buf; char buf[1024]; /* arbitrary size */ np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf); #elif defined(HAVE_AIX_GETNETBYNAME_R) /* * We have AIX's reentrant getnetbyname_r(). */ struct netent result_buf; struct netent_data net_data; if (getnetbyname_r(name, &result_buf, &net_data) == -1) np = NULL; else np = &result_buf; #else - /* - * We don't have any getnetbyname_r(); either we have a - * getnetbyname() that uses thread-specific data, in which - * case we're thread-safe (sufficiently recent FreeBSD, - * sufficiently recent Darwin-based OS, sufficiently recent - * HP-UX, sufficiently recent Tru64 UNIX), or we have the - * traditional getnetbyname() (everything else, including - * current NetBSD and OpenBSD), in which case we're not - * thread-safe. - */ + /* + * We don't have any getnetbyname_r(); either we have a + * getnetbyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX), or we have the + * traditional getnetbyname() (everything else, including + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ np = getnetbyname(name); #endif if (np != NULL) return np->n_net; else return 0; } #endif /* _WIN32 */ /* * Convert a port name to its port and protocol numbers. * We assume only TCP or UDP. * Return 0 upon failure. */ int pcap_nametoport(const char *name, int *port, int *proto) { struct addrinfo hints, *res, *ai; int error; struct sockaddr_in *in4; #ifdef INET6 struct sockaddr_in6 *in6; #endif int tcp_port = -1; int udp_port = -1; /* * We check for both TCP and UDP in case there are * ambiguous entries. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(NULL, name, &hints, &res); if (error != 0) { if (error != EAI_NONAME && error != EAI_SERVICE) { /* * This is a real error, not just "there's * no such service name". * XXX - this doesn't return an error string. */ return 0; } } else { /* * OK, we found it. Did it find anything? */ for (ai = res; ai != NULL; ai = ai->ai_next) { /* * Does it have an address? */ if (ai->ai_addr != NULL) { /* * Yes. Get a port number; we're done. */ if (ai->ai_addr->sa_family == AF_INET) { in4 = (struct sockaddr_in *)ai->ai_addr; tcp_port = ntohs(in4->sin_port); break; } #ifdef INET6 if (ai->ai_addr->sa_family == AF_INET6) { in6 = (struct sockaddr_in6 *)ai->ai_addr; tcp_port = ntohs(in6->sin6_port); break; } #endif } } freeaddrinfo(res); } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; error = getaddrinfo(NULL, name, &hints, &res); if (error != 0) { if (error != EAI_NONAME && error != EAI_SERVICE) { /* * This is a real error, not just "there's * no such service name". * XXX - this doesn't return an error string. */ return 0; } } else { /* * OK, we found it. Did it find anything? */ for (ai = res; ai != NULL; ai = ai->ai_next) { /* * Does it have an address? */ if (ai->ai_addr != NULL) { /* * Yes. Get a port number; we're done. */ if (ai->ai_addr->sa_family == AF_INET) { in4 = (struct sockaddr_in *)ai->ai_addr; udp_port = ntohs(in4->sin_port); break; } #ifdef INET6 if (ai->ai_addr->sa_family == AF_INET6) { in6 = (struct sockaddr_in6 *)ai->ai_addr; udp_port = ntohs(in6->sin6_port); break; } #endif } } freeaddrinfo(res); } /* * We need to check /etc/services for ambiguous entries. * If we find an ambiguous entry, and it has the * same port number, change the proto to PROTO_UNDEF * so both TCP and UDP will be checked. */ if (tcp_port >= 0) { *port = tcp_port; *proto = IPPROTO_TCP; if (udp_port >= 0) { if (udp_port == tcp_port) *proto = PROTO_UNDEF; #ifdef notdef else /* Can't handle ambiguous names that refer to different port numbers. */ warning("ambiguous port %s in /etc/services", name); #endif } return 1; } if (udp_port >= 0) { *port = udp_port; *proto = IPPROTO_UDP; return 1; } #if defined(ultrix) || defined(__osf__) /* Special hack in case NFS isn't in /etc/services */ if (strcmp(name, "nfs") == 0) { *port = 2049; *proto = PROTO_UNDEF; return 1; } #endif return 0; } /* * Convert a string in the form PPP-PPP, where correspond to ports, to * a starting and ending port in a port range. * Return 0 on failure. */ int pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) { u_int p1, p2; char *off, *cpy; int save_proto; if (sscanf(name, "%d-%d", &p1, &p2) != 2) { if ((cpy = strdup(name)) == NULL) return 0; if ((off = strchr(cpy, '-')) == NULL) { free(cpy); return 0; } *off = '\0'; if (pcap_nametoport(cpy, port1, proto) == 0) { free(cpy); return 0; } save_proto = *proto; if (pcap_nametoport(off + 1, port2, proto) == 0) { free(cpy); return 0; } free(cpy); if (*proto != save_proto) *proto = PROTO_UNDEF; } else { *port1 = p1; *port2 = p2; *proto = PROTO_UNDEF; } return 1; } /* * XXX - not guaranteed to be thread-safe! See below for platforms * on which it is thread-safe and on which it isn't. */ int pcap_nametoproto(const char *str) { struct protoent *p; #if defined(HAVE_LINUX_GETNETBYNAME_R) /* * We have Linux's reentrant getprotobyname_r(). */ struct protoent result_buf; char buf[1024]; /* arbitrary size */ int err; err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p); if (err != 0) { /* * XXX - dynamically allocate the buffer, and make it * bigger if we get ERANGE back? */ return 0; } #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) /* * We have Solaris's and IRIX's reentrant getprotobyname_r(). */ struct protoent result_buf; char buf[1024]; /* arbitrary size */ p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf); #elif defined(HAVE_AIX_GETNETBYNAME_R) /* * We have AIX's reentrant getprotobyname_r(). */ struct protoent result_buf; struct protoent_data proto_data; if (getprotobyname_r(str, &result_buf, &proto_data) == -1) p = NULL; else p = &result_buf; #else - /* - * We don't have any getprotobyname_r(); either we have a - * getprotobyname() that uses thread-specific data, in which - * case we're thread-safe (sufficiently recent FreeBSD, - * sufficiently recent Darwin-based OS, sufficiently recent - * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have + /* + * We don't have any getprotobyname_r(); either we have a + * getprotobyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have * the traditional getprotobyname() (everything else, including - * current NetBSD and OpenBSD), in which case we're not - * thread-safe. - */ + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ p = getprotobyname(str); #endif if (p != 0) return p->p_proto; else return PROTO_UNDEF; } #include "ethertype.h" struct eproto { const char *s; u_short p; }; /* * Static data base of ether protocol types. * tcpdump used to import this, and it's declared as an export on * Debian, at least, so make it a public symbol, even though we * don't officially export it by declaring it in a header file. * (Programs *should* do this themselves, as tcpdump now does.) * * We declare it here, right before defining it, to squelch any * warnings we might get from compilers about the lack of a * declaration. */ PCAP_API struct eproto eproto_db[]; PCAP_API_DEF struct eproto eproto_db[] = { { "aarp", ETHERTYPE_AARP }, { "arp", ETHERTYPE_ARP }, { "atalk", ETHERTYPE_ATALK }, { "decnet", ETHERTYPE_DN }, { "ip", ETHERTYPE_IP }, #ifdef INET6 { "ip6", ETHERTYPE_IPV6 }, #endif { "lat", ETHERTYPE_LAT }, { "loopback", ETHERTYPE_LOOPBACK }, { "mopdl", ETHERTYPE_MOPDL }, { "moprc", ETHERTYPE_MOPRC }, { "rarp", ETHERTYPE_REVARP }, { "sca", ETHERTYPE_SCA }, { (char *)0, 0 } }; int pcap_nametoeproto(const char *s) { struct eproto *p = eproto_db; while (p->s != 0) { if (strcmp(p->s, s) == 0) return p->p; p += 1; } return PROTO_UNDEF; } #include "llc.h" /* Static data base of LLC values. */ static struct eproto llc_db[] = { { "iso", LLCSAP_ISONS }, { "stp", LLCSAP_8021D }, { "ipx", LLCSAP_IPX }, { "netbeui", LLCSAP_NETBEUI }, { (char *)0, 0 } }; int pcap_nametollc(const char *s) { struct eproto *p = llc_db; while (p->s != 0) { if (strcmp(p->s, s) == 0) return p->p; p += 1; } return PROTO_UNDEF; } /* Hex digit to 8-bit unsigned integer. */ static inline u_char xdtoi(u_char c) { if (c >= '0' && c <= '9') return (u_char)(c - '0'); else if (c >= 'a' && c <= 'f') return (u_char)(c - 'a' + 10); else return (u_char)(c - 'A' + 10); } int __pcap_atoin(const char *s, bpf_u_int32 *addr) { u_int n; int len; *addr = 0; len = 0; for (;;) { n = 0; while (*s && *s != '.') { if (n > 25) { /* The result will be > 255 */ return -1; } n = n * 10 + *s++ - '0'; } if (n > 255) return -1; *addr <<= 8; *addr |= n & 0xff; len += 8; if (*s == '\0') return len; ++s; } /* NOTREACHED */ } int __pcap_atodn(const char *s, bpf_u_int32 *addr) { #define AREASHIFT 10 #define AREAMASK 0176000 #define NODEMASK 01777 u_int node, area; if (sscanf(s, "%d.%d", &area, &node) != 2) return(0); *addr = (area << AREASHIFT) & AREAMASK; *addr |= (node & NODEMASK); return(32); } /* * Convert 's', which can have the one of the forms: * * "xx:xx:xx:xx:xx:xx" * "xx.xx.xx.xx.xx.xx" * "xx-xx-xx-xx-xx-xx" * "xxxx.xxxx.xxxx" * "xxxxxxxxxxxx" * * (or various mixes of ':', '.', and '-') into a new * ethernet address. Assumes 's' is well formed. */ u_char * pcap_ether_aton(const char *s) { register u_char *ep, *e; register u_char d; e = ep = (u_char *)malloc(6); if (e == NULL) return (NULL); while (*s) { if (*s == ':' || *s == '.' || *s == '-') s += 1; d = xdtoi(*s++); if (PCAP_ISXDIGIT(*s)) { d <<= 4; d |= xdtoi(*s++); } *ep++ = d; } return (e); } #ifndef HAVE_ETHER_HOSTTON /* * Roll our own. * XXX - not thread-safe, because pcap_next_etherent() isn't thread- * safe! Needs a mutex or a thread-safe pcap_next_etherent(). */ u_char * pcap_ether_hostton(const char *name) { register struct pcap_etherent *ep; register u_char *ap; static FILE *fp = NULL; static int init = 0; if (!init) { fp = fopen(PCAP_ETHERS_FILE, "r"); ++init; if (fp == NULL) return (NULL); } else if (fp == NULL) return (NULL); else rewind(fp); while ((ep = pcap_next_etherent(fp)) != NULL) { if (strcmp(ep->name, name) == 0) { ap = (u_char *)malloc(6); if (ap != NULL) { memcpy(ap, ep->addr, 6); return (ap); } break; } } return (NULL); } #else /* * Use the OS-supplied routine. * This *should* be thread-safe; the API doesn't have a static buffer. */ u_char * pcap_ether_hostton(const char *name) { register u_char *ap; u_char a[6]; char namebuf[1024]; /* * In AIX 7.1 and 7.2: int ether_hostton(char *, struct ether_addr *); */ pcap_strlcpy(namebuf, name, sizeof(namebuf)); ap = NULL; if (ether_hostton(namebuf, (struct ether_addr *)a) == 0) { ap = (u_char *)malloc(6); if (ap != NULL) memcpy((char *)ap, (char *)a, 6); } return (ap); } #endif /* * XXX - not guaranteed to be thread-safe! */ int #ifdef DECNETLIB __pcap_nametodnaddr(const char *name, u_short *res) { struct nodeent *getnodebyname(); struct nodeent *nep; nep = getnodebyname(name); if (nep == ((struct nodeent *)0)) return(0); memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); return(1); #else __pcap_nametodnaddr(const char *name _U_, u_short *res _U_) { return(0); #endif } diff --git a/optimize.c b/optimize.c index 0ad0c4163bb0..9af4c15d2ca7 100644 --- a/optimize.c +++ b/optimize.c @@ -1,3099 +1,3099 @@ /* * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Optimization module for BPF code intermediate representation. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include /* for SIZE_MAX */ #include #include "pcap-int.h" #include "gencode.h" #include "optimize.h" #include "diag-control.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifdef BDEBUG /* * The internal "debug printout" flag for the filter expression optimizer. * The code to print that stuff is present only if BDEBUG is defined, so * the flag, and the routine to set it, are defined only if BDEBUG is * defined. */ static int pcap_optimizer_debug; /* * Routine to set that flag. * * This is intended for libpcap developers, not for general use. * If you want to set these in a program, you'll have to declare this * routine yourself, with the appropriate DLL import attribute on Windows; * it's not declared in any header file, and won't be declared in any * header file provided by libpcap. */ PCAP_API void pcap_set_optimizer_debug(int value); PCAP_API_DEF void pcap_set_optimizer_debug(int value) { pcap_optimizer_debug = value; } /* * The internal "print dot graph" flag for the filter expression optimizer. * The code to print that stuff is present only if BDEBUG is defined, so * the flag, and the routine to set it, are defined only if BDEBUG is * defined. */ static int pcap_print_dot_graph; /* * Routine to set that flag. * * This is intended for libpcap developers, not for general use. * If you want to set these in a program, you'll have to declare this * routine yourself, with the appropriate DLL import attribute on Windows; * it's not declared in any header file, and won't be declared in any * header file provided by libpcap. */ PCAP_API void pcap_set_print_dot_graph(int value); PCAP_API_DEF void pcap_set_print_dot_graph(int value) { pcap_print_dot_graph = value; } #endif /* * lowest_set_bit(). * * Takes a 32-bit integer as an argument. * * If handed a non-zero value, returns the index of the lowest set bit, * counting upwards from zero. * * If handed zero, the results are platform- and compiler-dependent. * Keep it out of the light, don't give it any water, don't feed it * after midnight, and don't pass zero to it. * * This is the same as the count of trailing zeroes in the word. */ #if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4) /* * GCC 3.4 and later; we have __builtin_ctz(). */ #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask)) #elif defined(_MSC_VER) /* * Visual Studio; we support only 2005 and later, so use * _BitScanForward(). */ #include #ifndef __clang__ #pragma intrinsic(_BitScanForward) #endif static __forceinline u_int lowest_set_bit(int mask) { unsigned long bit; /* * Don't sign-extend mask if long is longer than int. * (It's currently not, in MSVC, even on 64-bit platforms, but....) */ if (_BitScanForward(&bit, (unsigned int)mask) == 0) abort(); /* mask is zero */ return (u_int)bit; } #elif defined(MSDOS) && defined(__DJGPP__) /* * MS-DOS with DJGPP, which declares ffs() in , which * we've already included. */ #define lowest_set_bit(mask) ((u_int)(ffs((mask)) - 1)) #elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS) /* * MS-DOS with Watcom C, which has and declares ffs() there, * or some other platform (UN*X conforming to a sufficient recent version * of the Single UNIX Specification). */ #include #define lowest_set_bit(mask) (u_int)((ffs((mask)) - 1)) #else /* * None of the above. * Use a perfect-hash-function-based function. */ static u_int lowest_set_bit(int mask) { unsigned int v = (unsigned int)mask; static const u_int MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; /* * We strip off all but the lowermost set bit (v & ~v), * and perform a minimal perfect hash on it to look up the * number of low-order zero bits in a table. * * See: * * http://7ooo.mooo.com/text/ComputingTrailingZerosHOWTO.pdf * * http://supertech.csail.mit.edu/papers/debruijn.pdf */ return (MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27]); } #endif /* * Represents a deleted instruction. */ #define NOP -1 /* * Register numbers for use-def values. * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory * location. A_ATOM is the accumulator and X_ATOM is the index * register. */ #define A_ATOM BPF_MEMWORDS #define X_ATOM (BPF_MEMWORDS+1) /* * This define is used to represent *both* the accumulator and * x register in use-def computations. * Currently, the use-def code assumes only one definition per instruction. */ #define AX_ATOM N_ATOMS /* * These data structures are used in a Cocke and Shwarz style * value numbering scheme. Since the flowgraph is acyclic, * exit values can be propagated from a node's predecessors * provided it is uniquely defined. */ struct valnode { int code; bpf_u_int32 v0, v1; int val; /* the value number */ struct valnode *next; }; /* Integer constants mapped with the load immediate opcode. */ #define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U) struct vmapinfo { int is_const; bpf_u_int32 const_val; }; typedef struct { /* * Place to longjmp to on an error. */ jmp_buf top_ctx; /* * The buffer into which to put error message. */ char *errbuf; /* * A flag to indicate that further optimization is needed. * Iterative passes are continued until a given pass yields no * code simplification or branch movement. */ int done; /* * XXX - detect loops that do nothing but repeated AND/OR pullups * and edge moves. * If 100 passes in a row do nothing but that, treat that as a * sign that we're in a loop that just shuffles in a cycle in * which each pass just shuffles the code and we eventually * get back to the original configuration. * * XXX - we need a non-heuristic way of detecting, or preventing, * such a cycle. */ int non_branch_movement_performed; u_int n_blocks; /* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */ struct block **blocks; u_int n_edges; /* twice n_blocks, so guaranteed to be > 0 */ struct edge **edges; /* * A bit vector set representation of the dominators. * We round up the set size to the next power of two. */ u_int nodewords; /* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */ u_int edgewords; /* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */ struct block **levels; bpf_u_int32 *space; #define BITS_PER_WORD (8*sizeof(bpf_u_int32)) /* * True if a is in uset {p} */ #define SET_MEMBER(p, a) \ ((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))) /* * Add 'a' to uset p. */ #define SET_INSERT(p, a) \ (p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) /* * Delete 'a' from uset p. */ #define SET_DELETE(p, a) \ (p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) /* * a := a intersect b * n must be guaranteed to be > 0 */ #define SET_INTERSECT(a, b, n)\ {\ register bpf_u_int32 *_x = a, *_y = b;\ register u_int _n = n;\ do *_x++ &= *_y++; while (--_n != 0);\ } /* * a := a - b * n must be guaranteed to be > 0 */ #define SET_SUBTRACT(a, b, n)\ {\ register bpf_u_int32 *_x = a, *_y = b;\ register u_int _n = n;\ do *_x++ &=~ *_y++; while (--_n != 0);\ } /* * a := a union b * n must be guaranteed to be > 0 */ #define SET_UNION(a, b, n)\ {\ register bpf_u_int32 *_x = a, *_y = b;\ register u_int _n = n;\ do *_x++ |= *_y++; while (--_n != 0);\ } uset all_dom_sets; uset all_closure_sets; uset all_edge_sets; #define MODULUS 213 struct valnode *hashtbl[MODULUS]; bpf_u_int32 curval; bpf_u_int32 maxval; struct vmapinfo *vmap; struct valnode *vnode_base; struct valnode *next_vnode; } opt_state_t; typedef struct { /* * Place to longjmp to on an error. */ jmp_buf top_ctx; /* * The buffer into which to put error message. */ char *errbuf; /* * Some pointers used to convert the basic block form of the code, * into the array form that BPF requires. 'fstart' will point to * the malloc'd array while 'ftail' is used during the recursive * traversal. */ struct bpf_insn *fstart; struct bpf_insn *ftail; } conv_state_t; static void opt_init(opt_state_t *, struct icode *); static void opt_cleanup(opt_state_t *); static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...) PCAP_PRINTFLIKE(2, 3); static void intern_blocks(opt_state_t *, struct icode *); static void find_inedges(opt_state_t *, struct block *); #ifdef BDEBUG static void opt_dump(opt_state_t *, struct icode *); #endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif static void find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b) { int level; if (isMarked(ic, b)) return; Mark(ic, b); b->link = 0; if (JT(b)) { find_levels_r(opt_state, ic, JT(b)); find_levels_r(opt_state, ic, JF(b)); level = MAX(JT(b)->level, JF(b)->level) + 1; } else level = 0; b->level = level; b->link = opt_state->levels[level]; opt_state->levels[level] = b; } /* * Level graph. The levels go from 0 at the leaves to * N_LEVELS at the root. The opt_state->levels[] array points to the * first node of the level list, whose elements are linked * with the 'link' field of the struct block. */ static void find_levels(opt_state_t *opt_state, struct icode *ic) { memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels)); unMarkAll(ic); find_levels_r(opt_state, ic, ic->root); } /* * Find dominator relationships. * Assumes graph has been leveled. */ static void find_dom(opt_state_t *opt_state, struct block *root) { u_int i; int level; struct block *b; bpf_u_int32 *x; /* * Initialize sets to contain all nodes. */ x = opt_state->all_dom_sets; /* * In opt_init(), we've made sure the product doesn't overflow. */ i = opt_state->n_blocks * opt_state->nodewords; while (i != 0) { --i; *x++ = 0xFFFFFFFFU; } /* Root starts off empty. */ for (i = opt_state->nodewords; i != 0;) { --i; root->dom[i] = 0; } /* root->level is the highest level no found. */ for (level = root->level; level >= 0; --level) { for (b = opt_state->levels[level]; b; b = b->link) { SET_INSERT(b->dom, b->id); if (JT(b) == 0) continue; SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords); SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords); } } } static void propedom(opt_state_t *opt_state, struct edge *ep) { SET_INSERT(ep->edom, ep->id); if (ep->succ) { SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords); SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords); } } /* * Compute edge dominators. * Assumes graph has been leveled and predecessors established. */ static void find_edom(opt_state_t *opt_state, struct block *root) { u_int i; uset x; int level; struct block *b; x = opt_state->all_edge_sets; /* * In opt_init(), we've made sure the product doesn't overflow. */ for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) { --i; x[i] = 0xFFFFFFFFU; } /* root->level is the highest level no found. */ memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); for (level = root->level; level >= 0; --level) { for (b = opt_state->levels[level]; b != 0; b = b->link) { propedom(opt_state, &b->et); propedom(opt_state, &b->ef); } } } /* * Find the backwards transitive closure of the flow graph. These sets * are backwards in the sense that we find the set of nodes that reach * a given node, not the set of nodes that can be reached by a node. * * Assumes graph has been leveled. */ static void find_closure(opt_state_t *opt_state, struct block *root) { int level; struct block *b; /* * Initialize sets to contain no nodes. */ memset((char *)opt_state->all_closure_sets, 0, opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets)); /* root->level is the highest level no found. */ for (level = root->level; level >= 0; --level) { for (b = opt_state->levels[level]; b; b = b->link) { SET_INSERT(b->closure, b->id); if (JT(b) == 0) continue; SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords); SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords); } } } /* * Return the register number that is used by s. * * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X * are used, the scratch memory location's number if a scratch memory * location is used (e.g., 0 for M[0]), or -1 if none of those are used. * * The implementation should probably change to an array access. */ static int atomuse(struct stmt *s) { register int c = s->code; if (c == NOP) return -1; switch (BPF_CLASS(c)) { case BPF_RET: return (BPF_RVAL(c) == BPF_A) ? A_ATOM : (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; case BPF_LD: case BPF_LDX: /* * As there are fewer than 2^31 memory locations, * s->k should be convertible to int without problems. */ return (BPF_MODE(c) == BPF_IND) ? X_ATOM : (BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1; case BPF_ST: return A_ATOM; case BPF_STX: return X_ATOM; case BPF_JMP: case BPF_ALU: if (BPF_SRC(c) == BPF_X) return AX_ATOM; return A_ATOM; case BPF_MISC: return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; } abort(); /* NOTREACHED */ } /* * Return the register number that is defined by 's'. We assume that * a single stmt cannot define more than one register. If no register * is defined, return -1. * * The implementation should probably change to an array access. */ static int atomdef(struct stmt *s) { if (s->code == NOP) return -1; switch (BPF_CLASS(s->code)) { case BPF_LD: case BPF_ALU: return A_ATOM; case BPF_LDX: return X_ATOM; case BPF_ST: case BPF_STX: return s->k; case BPF_MISC: return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; } return -1; } /* * Compute the sets of registers used, defined, and killed by 'b'. * * "Used" means that a statement in 'b' uses the register before any * statement in 'b' defines it, i.e. it uses the value left in * that register by a predecessor block of this block. * "Defined" means that a statement in 'b' defines it. * "Killed" means that a statement in 'b' defines it before any * statement in 'b' uses it, i.e. it kills the value left in that * register by a predecessor block of this block. */ static void compute_local_ud(struct block *b) { struct slist *s; atomset def = 0, use = 0, killed = 0; int atom; for (s = b->stmts; s; s = s->next) { if (s->s.code == NOP) continue; atom = atomuse(&s->s); if (atom >= 0) { if (atom == AX_ATOM) { if (!ATOMELEM(def, X_ATOM)) use |= ATOMMASK(X_ATOM); if (!ATOMELEM(def, A_ATOM)) use |= ATOMMASK(A_ATOM); } else if (atom < N_ATOMS) { if (!ATOMELEM(def, atom)) use |= ATOMMASK(atom); } else abort(); } atom = atomdef(&s->s); if (atom >= 0) { if (!ATOMELEM(use, atom)) killed |= ATOMMASK(atom); def |= ATOMMASK(atom); } } if (BPF_CLASS(b->s.code) == BPF_JMP) { /* * XXX - what about RET? */ atom = atomuse(&b->s); if (atom >= 0) { if (atom == AX_ATOM) { if (!ATOMELEM(def, X_ATOM)) use |= ATOMMASK(X_ATOM); if (!ATOMELEM(def, A_ATOM)) use |= ATOMMASK(A_ATOM); } else if (atom < N_ATOMS) { if (!ATOMELEM(def, atom)) use |= ATOMMASK(atom); } else abort(); } } b->def = def; b->kill = killed; b->in_use = use; } /* * Assume graph is already leveled. */ static void find_ud(opt_state_t *opt_state, struct block *root) { int i, maxlevel; struct block *p; /* * root->level is the highest level no found; * count down from there. */ maxlevel = root->level; for (i = maxlevel; i >= 0; --i) for (p = opt_state->levels[i]; p; p = p->link) { compute_local_ud(p); p->out_use = 0; } for (i = 1; i <= maxlevel; ++i) { for (p = opt_state->levels[i]; p; p = p->link) { p->out_use |= JT(p)->in_use | JF(p)->in_use; p->in_use |= p->out_use &~ p->kill; } } } static void init_val(opt_state_t *opt_state) { opt_state->curval = 0; opt_state->next_vnode = opt_state->vnode_base; memset((char *)opt_state->vmap, 0, opt_state->maxval * sizeof(*opt_state->vmap)); memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl); } /* * Because we really don't have an IR, this stuff is a little messy. * * This routine looks in the table of existing value number for a value * with generated from an operation with the specified opcode and * the specified values. If it finds it, it returns its value number, * otherwise it makes a new entry in the table and returns the * value number of that entry. */ static bpf_u_int32 F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1) { u_int hash; bpf_u_int32 val; struct valnode *p; hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); hash %= MODULUS; for (p = opt_state->hashtbl[hash]; p; p = p->next) if (p->code == code && p->v0 == v0 && p->v1 == v1) return p->val; /* * Not found. Allocate a new value, and assign it a new * value number. * * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we * increment it before using it as the new value number, which * means we never assign VAL_UNKNOWN. * * XXX - unless we overflow, but we probably won't have 2^32-1 * values; we treat 32 bits as effectively infinite. */ val = ++opt_state->curval; if (BPF_MODE(code) == BPF_IMM && (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) { opt_state->vmap[val].const_val = v0; opt_state->vmap[val].is_const = 1; } p = opt_state->next_vnode++; p->val = val; p->code = code; p->v0 = v0; p->v1 = v1; p->next = opt_state->hashtbl[hash]; opt_state->hashtbl[hash] = p; return val; } static inline void vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter) { if (alter && newval != VAL_UNKNOWN && *valp == newval) s->code = NOP; else *valp = newval; } /* * Do constant-folding on binary operators. * (Unary operators are handled elsewhere.) */ static void fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1) { bpf_u_int32 a, b; a = opt_state->vmap[v0].const_val; b = opt_state->vmap[v1].const_val; switch (BPF_OP(s->code)) { case BPF_ADD: a += b; break; case BPF_SUB: a -= b; break; case BPF_MUL: a *= b; break; case BPF_DIV: if (b == 0) opt_error(opt_state, "division by zero"); a /= b; break; case BPF_MOD: if (b == 0) opt_error(opt_state, "modulus by zero"); a %= b; break; case BPF_AND: a &= b; break; case BPF_OR: a |= b; break; case BPF_XOR: a ^= b; break; case BPF_LSH: /* * A left shift of more than the width of the type * is undefined in C; we'll just treat it as shifting * all the bits out. * * XXX - the BPF interpreter doesn't check for this, * so its behavior is dependent on the behavior of * the processor on which it's running. There are * processors on which it shifts all the bits out * and processors on which it does no shift. */ if (b < 32) a <<= b; else a = 0; break; case BPF_RSH: /* * A right shift of more than the width of the type * is undefined in C; we'll just treat it as shifting * all the bits out. * * XXX - the BPF interpreter doesn't check for this, * so its behavior is dependent on the behavior of * the processor on which it's running. There are * processors on which it shifts all the bits out * and processors on which it does no shift. */ if (b < 32) a >>= b; else a = 0; break; default: abort(); } s->k = a; s->code = BPF_LD|BPF_IMM; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } static inline struct slist * this_op(struct slist *s) { while (s != 0 && s->s.code == NOP) s = s->next; return s; } static void opt_not(struct block *b) { struct block *tmp = JT(b); JT(b) = JF(b); JF(b) = tmp; } static void opt_peep(opt_state_t *opt_state, struct block *b) { struct slist *s; struct slist *next, *last; bpf_u_int32 val; s = b->stmts; if (s == 0) return; last = s; for (/*empty*/; /*empty*/; s = next) { /* * Skip over nops. */ s = this_op(s); if (s == 0) break; /* nothing left in the block */ /* * Find the next real instruction after that one * (skipping nops). */ next = this_op(s->next); if (next == 0) break; /* no next instruction */ last = next; /* * st M[k] --> st M[k] * ldx M[k] tax */ if (s->s.code == BPF_ST && next->s.code == (BPF_LDX|BPF_MEM) && s->s.k == next->s.k) { /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; next->s.code = BPF_MISC|BPF_TAX; } /* * ld #k --> ldx #k * tax txa */ if (s->s.code == (BPF_LD|BPF_IMM) && next->s.code == (BPF_MISC|BPF_TAX)) { s->s.code = BPF_LDX|BPF_IMM; next->s.code = BPF_MISC|BPF_TXA; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } /* * This is an ugly special case, but it happens * when you say tcp[k] or udp[k] where k is a constant. */ if (s->s.code == (BPF_LD|BPF_IMM)) { struct slist *add, *tax, *ild; /* * Check that X isn't used on exit from this * block (which the optimizer might cause). * We know the code generator won't generate * any local dependencies. */ if (ATOMELEM(b->out_use, X_ATOM)) continue; /* * Check that the instruction following the ldi * is an addx, or it's an ldxms with an addx * following it (with 0 or more nops between the * ldxms and addx). */ if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B)) add = next; else add = this_op(next->next); if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X)) continue; /* * Check that a tax follows that (with 0 or more * nops between them). */ tax = this_op(add->next); if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX)) continue; /* * Check that an ild follows that (with 0 or more * nops between them). */ ild = this_op(tax->next); if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || BPF_MODE(ild->s.code) != BPF_IND) continue; /* * We want to turn this sequence: * * (004) ldi #0x2 {s} * (005) ldxms [14] {next} -- optional * (006) addx {add} * (007) tax {tax} * (008) ild [x+0] {ild} * * into this sequence: * * (004) nop * (005) ldxms [14] * (006) nop * (007) nop * (008) ild [x+2] * * XXX We need to check that X is not * subsequently used, because we want to change * what'll be in it after this sequence. * * We know we can eliminate the accumulator * modifications earlier in the sequence since * it is defined by the last stmt of this sequence * (i.e., the last statement of the sequence loads * a value into the accumulator, so we can eliminate * earlier operations on the accumulator). */ ild->s.k += s->s.k; s->s.code = NOP; add->s.code = NOP; tax->s.code = NOP; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } } /* * If the comparison at the end of a block is an equality * comparison against a constant, and nobody uses the value * we leave in the A register at the end of a block, and * the operation preceding the comparison is an arithmetic * operation, we can sometime optimize it away. */ if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) && !ATOMELEM(b->out_use, A_ATOM)) { /* * We can optimize away certain subtractions of the * X register. */ if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) { val = b->val[X_ATOM]; if (opt_state->vmap[val].is_const) { /* * If we have a subtract to do a comparison, * and the X register is a known constant, * we can merge this value into the * comparison: * * sub x -> nop * jeq #y jeq #(x+y) */ b->s.k += opt_state->vmap[val].const_val; last->s.code = NOP; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } else if (b->s.k == 0) { /* * If the X register isn't a constant, * and the comparison in the test is * against 0, we can compare with the * X register, instead: * * sub x -> nop * jeq #0 jeq x */ last->s.code = NOP; b->s.code = BPF_JMP|BPF_JEQ|BPF_X; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } } /* * Likewise, a constant subtract can be simplified: * * sub #x -> nop * jeq #y -> jeq #(x+y) */ else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) { last->s.code = NOP; b->s.k += last->s.k; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } /* * And, similarly, a constant AND can be simplified * if we're testing against 0, i.e.: * * and #k nop * jeq #0 -> jset #k */ else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) && b->s.k == 0) { b->s.k = last->s.k; b->s.code = BPF_JMP|BPF_K|BPF_JSET; last->s.code = NOP; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; opt_not(b); } } /* * jset #0 -> never * jset #ffffffff -> always */ if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) { if (b->s.k == 0) JT(b) = JF(b); if (b->s.k == 0xffffffffU) JF(b) = JT(b); } /* * If we're comparing against the index register, and the index * register is a known constant, we can just compare against that * constant. */ val = b->val[X_ATOM]; if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) { bpf_u_int32 v = opt_state->vmap[val].const_val; b->s.code &= ~BPF_X; b->s.k = v; } /* * If the accumulator is a known constant, we can compute the * comparison result. */ val = b->val[A_ATOM]; if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { bpf_u_int32 v = opt_state->vmap[val].const_val; switch (BPF_OP(b->s.code)) { case BPF_JEQ: v = v == b->s.k; break; case BPF_JGT: v = v > b->s.k; break; case BPF_JGE: v = v >= b->s.k; break; case BPF_JSET: v &= b->s.k; break; default: abort(); } if (JF(b) != JT(b)) { /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } if (v) JF(b) = JT(b); else JT(b) = JF(b); } } /* * Compute the symbolic value of expression of 's', and update * anything it defines in the value table 'val'. If 'alter' is true, * do various optimizations. This code would be cleaner if symbolic * evaluation and code transformations weren't folded together. */ static void opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter) { int op; bpf_u_int32 v; switch (s->code) { case BPF_LD|BPF_ABS|BPF_W: case BPF_LD|BPF_ABS|BPF_H: case BPF_LD|BPF_ABS|BPF_B: v = F(opt_state, s->code, s->k, 0L); vstore(s, &val[A_ATOM], v, alter); break; case BPF_LD|BPF_IND|BPF_W: case BPF_LD|BPF_IND|BPF_H: case BPF_LD|BPF_IND|BPF_B: v = val[X_ATOM]; if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code); s->k += opt_state->vmap[v].const_val; v = F(opt_state, s->code, s->k, 0L); /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } else v = F(opt_state, s->code, s->k, v); vstore(s, &val[A_ATOM], v, alter); break; case BPF_LD|BPF_LEN: v = F(opt_state, s->code, 0L, 0L); vstore(s, &val[A_ATOM], v, alter); break; case BPF_LD|BPF_IMM: v = K(s->k); vstore(s, &val[A_ATOM], v, alter); break; case BPF_LDX|BPF_IMM: v = K(s->k); vstore(s, &val[X_ATOM], v, alter); break; case BPF_LDX|BPF_MSH|BPF_B: v = F(opt_state, s->code, s->k, 0L); vstore(s, &val[X_ATOM], v, alter); break; case BPF_ALU|BPF_NEG: if (alter && opt_state->vmap[val[A_ATOM]].is_const) { s->code = BPF_LD|BPF_IMM; /* * Do this negation as unsigned arithmetic; that's * what modern BPF engines do, and it guarantees * that all possible values can be negated. (Yeah, * negating 0x80000000, the minimum signed 32-bit * two's-complement value, results in 0x80000000, * so it's still negative, but we *should* be doing * all unsigned arithmetic here, to match what * modern BPF engines do.) * * Express it as 0U - (unsigned value) so that we * don't get compiler warnings about negating an * unsigned value and don't get UBSan warnings * about the result of negating 0x80000000 being * undefined. */ s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val; val[A_ATOM] = K(s->k); } else val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], 0L); break; case BPF_ALU|BPF_ADD|BPF_K: case BPF_ALU|BPF_SUB|BPF_K: case BPF_ALU|BPF_MUL|BPF_K: case BPF_ALU|BPF_DIV|BPF_K: case BPF_ALU|BPF_MOD|BPF_K: case BPF_ALU|BPF_AND|BPF_K: case BPF_ALU|BPF_OR|BPF_K: case BPF_ALU|BPF_XOR|BPF_K: case BPF_ALU|BPF_LSH|BPF_K: case BPF_ALU|BPF_RSH|BPF_K: op = BPF_OP(s->code); if (alter) { if (s->k == 0) { /* * Optimize operations where the constant * is zero. * * Don't optimize away "sub #0" * as it may be needed later to * fixup the generated math code. * * Fail if we're dividing by zero or taking * a modulus by zero. */ if (op == BPF_ADD || op == BPF_LSH || op == BPF_RSH || op == BPF_OR || op == BPF_XOR) { s->code = NOP; break; } if (op == BPF_MUL || op == BPF_AND) { s->code = BPF_LD|BPF_IMM; val[A_ATOM] = K(s->k); break; } if (op == BPF_DIV) opt_error(opt_state, "division by zero"); if (op == BPF_MOD) opt_error(opt_state, "modulus by zero"); } if (opt_state->vmap[val[A_ATOM]].is_const) { fold_op(opt_state, s, val[A_ATOM], K(s->k)); val[A_ATOM] = K(s->k); break; } } val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k)); break; case BPF_ALU|BPF_ADD|BPF_X: case BPF_ALU|BPF_SUB|BPF_X: case BPF_ALU|BPF_MUL|BPF_X: case BPF_ALU|BPF_DIV|BPF_X: case BPF_ALU|BPF_MOD|BPF_X: case BPF_ALU|BPF_AND|BPF_X: case BPF_ALU|BPF_OR|BPF_X: case BPF_ALU|BPF_XOR|BPF_X: case BPF_ALU|BPF_LSH|BPF_X: case BPF_ALU|BPF_RSH|BPF_X: op = BPF_OP(s->code); if (alter && opt_state->vmap[val[X_ATOM]].is_const) { if (opt_state->vmap[val[A_ATOM]].is_const) { fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]); val[A_ATOM] = K(s->k); } else { s->code = BPF_ALU|BPF_K|op; s->k = opt_state->vmap[val[X_ATOM]].const_val; if ((op == BPF_LSH || op == BPF_RSH) && s->k > 31) opt_error(opt_state, "shift by more than 31 bits"); /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k)); } break; } /* * Check if we're doing something to an accumulator * that is 0, and simplify. This may not seem like * much of a simplification but it could open up further * optimizations. * XXX We could also check for mul by 1, etc. */ if (alter && opt_state->vmap[val[A_ATOM]].is_const && opt_state->vmap[val[A_ATOM]].const_val == 0) { if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) { s->code = BPF_MISC|BPF_TXA; vstore(s, &val[A_ATOM], val[X_ATOM], alter); break; } else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD || op == BPF_AND || op == BPF_LSH || op == BPF_RSH) { s->code = BPF_LD|BPF_IMM; s->k = 0; vstore(s, &val[A_ATOM], K(s->k), alter); break; } else if (op == BPF_NEG) { s->code = NOP; break; } } val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]); break; case BPF_MISC|BPF_TXA: vstore(s, &val[A_ATOM], val[X_ATOM], alter); break; case BPF_LD|BPF_MEM: v = val[s->k]; if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LD|BPF_IMM; s->k = opt_state->vmap[v].const_val; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } vstore(s, &val[A_ATOM], v, alter); break; case BPF_MISC|BPF_TAX: vstore(s, &val[X_ATOM], val[A_ATOM], alter); break; case BPF_LDX|BPF_MEM: v = val[s->k]; if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LDX|BPF_IMM; s->k = opt_state->vmap[v].const_val; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } vstore(s, &val[X_ATOM], v, alter); break; case BPF_ST: vstore(s, &val[s->k], val[A_ATOM], alter); break; case BPF_STX: vstore(s, &val[s->k], val[X_ATOM], alter); break; } } static void deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[]) { register int atom; atom = atomuse(s); if (atom >= 0) { if (atom == AX_ATOM) { last[X_ATOM] = 0; last[A_ATOM] = 0; } else last[atom] = 0; } atom = atomdef(s); if (atom >= 0) { if (last[atom]) { /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; last[atom]->code = NOP; } last[atom] = s; } } static void opt_deadstores(opt_state_t *opt_state, register struct block *b) { register struct slist *s; register int atom; struct stmt *last[N_ATOMS]; memset((char *)last, 0, sizeof last); for (s = b->stmts; s != 0; s = s->next) deadstmt(opt_state, &s->s, last); deadstmt(opt_state, &b->s, last); for (atom = 0; atom < N_ATOMS; ++atom) if (last[atom] && !ATOMELEM(b->out_use, atom)) { last[atom]->code = NOP; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } } static void opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts) { struct slist *s; struct edge *p; int i; bpf_u_int32 aval, xval; #if 0 for (s = b->stmts; s && s->next; s = s->next) if (BPF_CLASS(s->s.code) == BPF_JMP) { do_stmts = 0; break; } #endif /* * Initialize the atom values. */ p = b->in_edges; if (p == 0) { /* * We have no predecessors, so everything is undefined * upon entry to this block. */ memset((char *)b->val, 0, sizeof(b->val)); } else { /* * Inherit values from our predecessors. * * First, get the values from the predecessor along the * first edge leading to this node. */ memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val)); /* * Now look at all the other nodes leading to this node. * If, for the predecessor along that edge, a register * has a different value from the one we have (i.e., * control paths are merging, and the merging paths * assign different values to that register), give the * register the undefined value of 0. */ while ((p = p->next) != NULL) { for (i = 0; i < N_ATOMS; ++i) if (b->val[i] != p->pred->val[i]) b->val[i] = 0; } } aval = b->val[A_ATOM]; xval = b->val[X_ATOM]; for (s = b->stmts; s; s = s->next) opt_stmt(opt_state, &s->s, b->val, do_stmts); /* * This is a special case: if we don't use anything from this * block, and we load the accumulator or index register with a * value that is already there, or if this block is a return, * eliminate all the statements. * * XXX - what if it does a store? Presumably that falls under * the heading of "if we don't use anything from this block", * i.e., if we use any memory location set to a different * value by this block, then we use something from this block. * * XXX - why does it matter whether we use anything from this * block? If the accumulator or index register doesn't change * its value, isn't that OK even if we use that value? * * XXX - if we load the accumulator with a different value, * and the block ends with a conditional branch, we obviously * can't eliminate it, as the branch depends on that value. * For the index register, the conditional branch only depends * on the index register value if the test is against the index * register value rather than a constant; if nothing uses the * value we put into the index register, and we're not testing * against the index register's value, and there aren't any * other problems that would keep us from eliminating this * block, can we eliminate it? */ if (do_stmts && ((b->out_use == 0 && aval != VAL_UNKNOWN && b->val[A_ATOM] == aval && xval != VAL_UNKNOWN && b->val[X_ATOM] == xval) || BPF_CLASS(b->s.code) == BPF_RET)) { if (b->stmts != 0) { b->stmts = 0; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; } } else { opt_peep(opt_state, b); opt_deadstores(opt_state, b); } /* * Set up values for branch optimizer. */ if (BPF_SRC(b->s.code) == BPF_K) b->oval = K(b->s.k); else b->oval = b->val[X_ATOM]; b->et.code = b->s.code; b->ef.code = -b->s.code; } /* * Return true if any register that is used on exit from 'succ', has * an exit value that is different from the corresponding exit value * from 'b'. */ static int use_conflict(struct block *b, struct block *succ) { int atom; atomset use = succ->out_use; if (use == 0) return 0; for (atom = 0; atom < N_ATOMS; ++atom) if (ATOMELEM(use, atom)) if (b->val[atom] != succ->val[atom]) return 1; return 0; } /* * Given a block that is the successor of an edge, and an edge that * dominates that edge, return either a pointer to a child of that * block (a block to which that block jumps) if that block is a * candidate to replace the successor of the latter edge or NULL * if neither of the children of the first block are candidates. */ static struct block * fold_edge(struct block *child, struct edge *ep) { int sense; bpf_u_int32 aval0, aval1, oval0, oval1; int code = ep->code; if (code < 0) { /* * This edge is a "branch if false" edge. */ code = -code; sense = 0; } else { /* * This edge is a "branch if true" edge. */ sense = 1; } /* * If the opcode for the branch at the end of the block we * were handed isn't the same as the opcode for the branch * to which the edge we were handed corresponds, the tests * for those branches aren't testing the same conditions, * so the blocks to which the first block branches aren't * candidates to replace the successor of the edge. */ if (child->s.code != code) return 0; aval0 = child->val[A_ATOM]; oval0 = child->oval; aval1 = ep->pred->val[A_ATOM]; oval1 = ep->pred->oval; /* * If the A register value on exit from the successor block * isn't the same as the A register value on exit from the * predecessor of the edge, the blocks to which the first * block branches aren't candidates to replace the successor * of the edge. */ if (aval0 != aval1) return 0; if (oval0 == oval1) /* * The operands of the branch instructions are * identical, so the branches are testing the * same condition, and the result is true if a true * branch was taken to get here, otherwise false. */ return sense ? JT(child) : JF(child); if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K)) /* * At this point, we only know the comparison if we * came down the true branch, and it was an equality * comparison with a constant. * * I.e., if we came down the true branch, and the branch * was an equality comparison with a constant, we know the * accumulator contains that constant. If we came down * the false branch, or the comparison wasn't with a * constant, we don't know what was in the accumulator. * * We rely on the fact that distinct constants have distinct * value numbers. */ return JF(child); return 0; } /* * If we can make this edge go directly to a child of the edge's current * successor, do so. */ static void opt_j(opt_state_t *opt_state, struct edge *ep) { register u_int i, k; register struct block *target; /* * Does this edge go to a block where, if the test * at the end of it succeeds, it goes to a block * that's a leaf node of the DAG, i.e. a return * statement? * If so, there's nothing to optimize. */ if (JT(ep->succ) == 0) return; /* * Does this edge go to a block that goes, in turn, to * the same block regardless of whether the test at the * end succeeds or fails? */ if (JT(ep->succ) == JF(ep->succ)) { /* * Common branch targets can be eliminated, provided * there is no data dependency. * * Check whether any register used on exit from the * block to which the successor of this edge goes * has a value at that point that's different from * the value it has on exit from the predecessor of * this edge. If not, the predecessor of this edge * can just go to the block to which the successor * of this edge goes, bypassing the successor of this * edge, as the successor of this edge isn't doing * any calculations whose results are different * from what the blocks before it did and isn't * doing any tests the results of which matter. */ if (!use_conflict(ep->pred, JT(ep->succ))) { /* * No, there isn't. * Make this edge go to the block to * which the successor of that edge * goes. * * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 1; opt_state->done = 0; ep->succ = JT(ep->succ); } } /* * For each edge dominator that matches the successor of this * edge, promote the edge successor to the its grandchild. * * XXX We violate the set abstraction here in favor a reasonably * efficient loop. */ top: for (i = 0; i < opt_state->edgewords; ++i) { /* i'th word in the bitset of dominators */ register bpf_u_int32 x = ep->edom[i]; while (x != 0) { /* Find the next dominator in that word and mark it as found */ k = lowest_set_bit(x); x &=~ ((bpf_u_int32)1 << k); k += i * BITS_PER_WORD; target = fold_edge(ep->succ, opt_state->edges[k]); /* * We have a candidate to replace the successor * of ep. * * Check that there is no data dependency between * nodes that will be violated if we move the edge; * i.e., if any register used on exit from the * candidate has a value at that point different * from the value it has when we exit the * predecessor of that edge, there's a data * dependency that will be violated. */ if (target != 0 && !use_conflict(ep->pred, target)) { /* * It's safe to replace the successor of * ep; do so, and note that we've made * at least one change. * * XXX - this is one of the operations that * happens when the optimizer gets into * one of those infinite loops. */ opt_state->done = 0; ep->succ = target; if (JT(target) != 0) /* * Start over unless we hit a leaf. */ goto top; return; } } } } /* * XXX - is this, and and_pullup(), what's described in section 6.1.2 * "Predicate Assertion Propagation" in the BPF+ paper? * * Note that this looks at block dominators, not edge dominators. * Don't think so. * * "A or B" compiles into * * A * t / \ f * / B * / t / \ f * \ / * \ / * X * * */ static void or_pullup(opt_state_t *opt_state, struct block *b) { bpf_u_int32 val; int at_top; struct block *pull; struct block **diffp, **samep; struct edge *ep; ep = b->in_edges; if (ep == 0) return; /* * Make sure each predecessor loads the same value. * XXX why? */ val = ep->pred->val[A_ATOM]; for (ep = ep->next; ep != 0; ep = ep->next) if (val != ep->pred->val[A_ATOM]) return; /* * For the first edge in the list of edges coming into this block, * see whether the predecessor of that edge comes here via a true * branch or a false branch. */ if (JT(b->in_edges->pred) == b) diffp = &JT(b->in_edges->pred); /* jt */ else diffp = &JF(b->in_edges->pred); /* jf */ /* * diffp is a pointer to a pointer to the block. * * Go down the false chain looking as far as you can, * making sure that each jump-compare is doing the * same as the original block. * * If you reach the bottom before you reach a * different jump-compare, just exit. There's nothing * to do here. XXX - no, this version is checking for * the value leaving the block; that's from the BPF+ * pullup routine. */ at_top = 1; for (;;) { /* * Done if that's not going anywhere XXX */ if (*diffp == 0) return; /* * Done if that predecessor blah blah blah isn't * going the same place we're going XXX * * Does the true edge of this block point to the same * location as the true edge of b? */ if (JT(*diffp) != JT(b)) return; /* * Done if this node isn't a dominator of that * node blah blah blah XXX * * Does b dominate diffp? */ if (!SET_MEMBER((*diffp)->dom, b->id)) return; /* * Break out of the loop if that node's value of A * isn't the value of A above XXX */ if ((*diffp)->val[A_ATOM] != val) break; /* * Get the JF for that node XXX * Go down the false path. */ diffp = &JF(*diffp); at_top = 0; } /* * Now that we've found a different jump-compare in a chain * below b, search further down until we find another * jump-compare that looks at the original value. This * jump-compare should get pulled up. XXX again we're * comparing values not jump-compares. */ samep = &JF(*diffp); for (;;) { /* * Done if that's not going anywhere XXX */ if (*samep == 0) return; /* * Done if that predecessor blah blah blah isn't * going the same place we're going XXX */ if (JT(*samep) != JT(b)) return; /* * Done if this node isn't a dominator of that * node blah blah blah XXX * * Does b dominate samep? */ if (!SET_MEMBER((*samep)->dom, b->id)) return; /* * Break out of the loop if that node's value of A * is the value of A above XXX */ if ((*samep)->val[A_ATOM] == val) break; /* XXX Need to check that there are no data dependencies between dp0 and dp1. Currently, the code generator will not produce such dependencies. */ samep = &JF(*samep); } #ifdef notdef /* XXX This doesn't cover everything. */ for (i = 0; i < N_ATOMS; ++i) if ((*samep)->val[i] != pred->val[i]) return; #endif /* Pull up the node. */ pull = *samep; *samep = JF(pull); JF(pull) = *diffp; /* * At the top of the chain, each predecessor needs to point at the * pulled up node. Inside the chain, there is only one predecessor * to worry about. */ if (at_top) { for (ep = b->in_edges; ep != 0; ep = ep->next) { if (JT(ep->pred) == b) JT(ep->pred) = pull; else JF(ep->pred) = pull; } } else *diffp = pull; /* * XXX - this is one of the operations that happens when the * optimizer gets into one of those infinite loops. */ opt_state->done = 0; } static void and_pullup(opt_state_t *opt_state, struct block *b) { bpf_u_int32 val; int at_top; struct block *pull; struct block **diffp, **samep; struct edge *ep; ep = b->in_edges; if (ep == 0) return; /* * Make sure each predecessor loads the same value. */ val = ep->pred->val[A_ATOM]; for (ep = ep->next; ep != 0; ep = ep->next) if (val != ep->pred->val[A_ATOM]) return; if (JT(b->in_edges->pred) == b) diffp = &JT(b->in_edges->pred); else diffp = &JF(b->in_edges->pred); at_top = 1; for (;;) { if (*diffp == 0) return; if (JF(*diffp) != JF(b)) return; if (!SET_MEMBER((*diffp)->dom, b->id)) return; if ((*diffp)->val[A_ATOM] != val) break; diffp = &JT(*diffp); at_top = 0; } samep = &JT(*diffp); for (;;) { if (*samep == 0) return; if (JF(*samep) != JF(b)) return; if (!SET_MEMBER((*samep)->dom, b->id)) return; if ((*samep)->val[A_ATOM] == val) break; /* XXX Need to check that there are no data dependencies between diffp and samep. Currently, the code generator will not produce such dependencies. */ samep = &JT(*samep); } #ifdef notdef /* XXX This doesn't cover everything. */ for (i = 0; i < N_ATOMS; ++i) if ((*samep)->val[i] != pred->val[i]) return; #endif /* Pull up the node. */ pull = *samep; *samep = JT(pull); JT(pull) = *diffp; /* * At the top of the chain, each predecessor needs to point at the * pulled up node. Inside the chain, there is only one predecessor * to worry about. */ if (at_top) { for (ep = b->in_edges; ep != 0; ep = ep->next) { if (JT(ep->pred) == b) JT(ep->pred) = pull; else JF(ep->pred) = pull; } } else *diffp = pull; /* * XXX - this is one of the operations that happens when the * optimizer gets into one of those infinite loops. */ opt_state->done = 0; } static void opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts) { int i, maxlevel; struct block *p; init_val(opt_state); maxlevel = ic->root->level; find_inedges(opt_state, ic->root); for (i = maxlevel; i >= 0; --i) for (p = opt_state->levels[i]; p; p = p->link) opt_blk(opt_state, p, do_stmts); if (do_stmts) /* * No point trying to move branches; it can't possibly * make a difference at this point. * * XXX - this might be after we detect a loop where * we were just looping infinitely moving branches * in such a fashion that we went through two or more * versions of the machine code, eventually returning * to the first version. (We're really not doing a * full loop detection, we're just testing for two * passes in a row where we do nothing but * move branches.) */ return; /* * Is this what the BPF+ paper describes in sections 6.1.1, * 6.1.2, and 6.1.3? */ for (i = 1; i <= maxlevel; ++i) { for (p = opt_state->levels[i]; p; p = p->link) { opt_j(opt_state, &p->et); opt_j(opt_state, &p->ef); } } find_inedges(opt_state, ic->root); for (i = 1; i <= maxlevel; ++i) { for (p = opt_state->levels[i]; p; p = p->link) { or_pullup(opt_state, p); and_pullup(opt_state, p); } } } static inline void link_inedge(struct edge *parent, struct block *child) { parent->next = child->in_edges; child->in_edges = parent; } static void find_inedges(opt_state_t *opt_state, struct block *root) { u_int i; int level; struct block *b; for (i = 0; i < opt_state->n_blocks; ++i) opt_state->blocks[i]->in_edges = 0; /* * Traverse the graph, adding each edge to the predecessor * list of its successors. Skip the leaves (i.e. level 0). */ for (level = root->level; level > 0; --level) { for (b = opt_state->levels[level]; b != 0; b = b->link) { link_inedge(&b->et, JT(b)); link_inedge(&b->ef, JF(b)); } } } static void opt_root(struct block **b) { struct slist *tmp, *s; s = (*b)->stmts; (*b)->stmts = 0; while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b)) *b = JT(*b); tmp = (*b)->stmts; if (tmp != 0) sappend(s, tmp); (*b)->stmts = s; /* * If the root node is a return, then there is no * point executing any statements (since the bpf machine * has no side effects). */ if (BPF_CLASS((*b)->s.code) == BPF_RET) (*b)->stmts = 0; } static void opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts) { #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("opt_loop(root, %d) begin\n", do_stmts); opt_dump(opt_state, ic); } #endif /* * XXX - optimizer loop detection. */ int loop_count = 0; for (;;) { opt_state->done = 1; /* * XXX - optimizer loop detection. */ opt_state->non_branch_movement_performed = 0; find_levels(opt_state, ic); find_dom(opt_state, ic->root); find_closure(opt_state, ic->root); find_ud(opt_state, ic->root); find_edom(opt_state, ic->root); opt_blks(opt_state, ic, do_stmts); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done); opt_dump(opt_state, ic); } #endif /* * Was anything done in this optimizer pass? */ if (opt_state->done) { /* * No, so we've reached a fixed point. * We're done. */ break; } /* * XXX - was anything done other than branch movement * in this pass? */ if (opt_state->non_branch_movement_performed) { /* * Yes. Clear any loop-detection counter; * we're making some form of progress (assuming * we can't get into a cycle doing *other* * optimizations...). */ loop_count = 0; } else { /* * No - increment the counter, and quit if * it's up to 100. */ loop_count++; if (loop_count >= 100) { /* * We've done nothing but branch movement * for 100 passes; we're probably * in a cycle and will never reach a * fixed point. * * XXX - yes, we really need a non- * heuristic way of detecting a cycle. */ opt_state->done = 1; break; } } } } /* * Optimize the filter code in its dag representation. * Return 0 on success, -1 on error. */ int bpf_optimize(struct icode *ic, char *errbuf) { opt_state_t opt_state; memset(&opt_state, 0, sizeof(opt_state)); opt_state.errbuf = errbuf; opt_state.non_branch_movement_performed = 0; if (setjmp(opt_state.top_ctx)) { opt_cleanup(&opt_state); return -1; } opt_init(&opt_state, ic); opt_loop(&opt_state, ic, 0); opt_loop(&opt_state, ic, 1); intern_blocks(&opt_state, ic); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("after intern_blocks()\n"); opt_dump(&opt_state, ic); } #endif opt_root(&ic->root); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("after opt_root()\n"); opt_dump(&opt_state, ic); } #endif opt_cleanup(&opt_state); return 0; } static void make_marks(struct icode *ic, struct block *p) { if (!isMarked(ic, p)) { Mark(ic, p); if (BPF_CLASS(p->s.code) != BPF_RET) { make_marks(ic, JT(p)); make_marks(ic, JF(p)); } } } /* * Mark code array such that isMarked(ic->cur_mark, i) is true * only for nodes that are alive. */ static void mark_code(struct icode *ic) { ic->cur_mark += 1; make_marks(ic, ic->root); } /* * True iff the two stmt lists load the same value from the packet into * the accumulator. */ static int eq_slist(struct slist *x, struct slist *y) { for (;;) { while (x && x->s.code == NOP) x = x->next; while (y && y->s.code == NOP) y = y->next; if (x == 0) return y == 0; if (y == 0) return x == 0; if (x->s.code != y->s.code || x->s.k != y->s.k) return 0; x = x->next; y = y->next; } } static inline int eq_blk(struct block *b0, struct block *b1) { if (b0->s.code == b1->s.code && b0->s.k == b1->s.k && b0->et.succ == b1->et.succ && b0->ef.succ == b1->ef.succ) return eq_slist(b0->stmts, b1->stmts); return 0; } static void intern_blocks(opt_state_t *opt_state, struct icode *ic) { struct block *p; u_int i, j; int done1; /* don't shadow global */ top: done1 = 1; for (i = 0; i < opt_state->n_blocks; ++i) opt_state->blocks[i]->link = 0; mark_code(ic); for (i = opt_state->n_blocks - 1; i != 0; ) { --i; if (!isMarked(ic, opt_state->blocks[i])) continue; for (j = i + 1; j < opt_state->n_blocks; ++j) { if (!isMarked(ic, opt_state->blocks[j])) continue; if (eq_blk(opt_state->blocks[i], opt_state->blocks[j])) { opt_state->blocks[i]->link = opt_state->blocks[j]->link ? opt_state->blocks[j]->link : opt_state->blocks[j]; break; } } } for (i = 0; i < opt_state->n_blocks; ++i) { p = opt_state->blocks[i]; if (JT(p) == 0) continue; if (JT(p)->link) { done1 = 0; JT(p) = JT(p)->link; } if (JF(p)->link) { done1 = 0; JF(p) = JF(p)->link; } } if (!done1) goto top; } static void opt_cleanup(opt_state_t *opt_state) { free((void *)opt_state->vnode_base); free((void *)opt_state->vmap); free((void *)opt_state->edges); free((void *)opt_state->space); free((void *)opt_state->levels); free((void *)opt_state->blocks); } /* * For optimizer errors. */ static void PCAP_NORETURN opt_error(opt_state_t *opt_state, const char *fmt, ...) { va_list ap; if (opt_state->errbuf != NULL) { va_start(ap, fmt); (void)vsnprintf(opt_state->errbuf, PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); } longjmp(opt_state->top_ctx, 1); /* NOTREACHED */ #ifdef _AIX PCAP_UNREACHABLE #endif /* _AIX */ } /* * Return the number of stmts in 's'. */ static u_int slength(struct slist *s) { u_int n = 0; for (; s; s = s->next) if (s->s.code != NOP) ++n; return n; } /* * Return the number of nodes reachable by 'p'. * All nodes should be initially unmarked. */ static int count_blocks(struct icode *ic, struct block *p) { if (p == 0 || isMarked(ic, p)) return 0; Mark(ic, p); return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1; } /* * Do a depth first search on the flow graph, numbering the * the basic blocks, and entering them into the 'blocks' array.` */ static void number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p) { u_int n; if (p == 0 || isMarked(ic, p)) return; Mark(ic, p); n = opt_state->n_blocks++; if (opt_state->n_blocks == 0) { /* * Overflow. */ opt_error(opt_state, "filter is too complex to optimize"); } p->id = n; opt_state->blocks[n] = p; number_blks_r(opt_state, ic, JT(p)); number_blks_r(opt_state, ic, JF(p)); } /* * Return the number of stmts in the flowgraph reachable by 'p'. * The nodes should be unmarked before calling. * * Note that "stmts" means "instructions", and that this includes * * side-effect statements in 'p' (slength(p->stmts)); * * statements in the true branch from 'p' (count_stmts(JT(p))); * * statements in the false branch from 'p' (count_stmts(JF(p))); * * the conditional jump itself (1); * * an extra long jump if the true branch requires it (p->longjt); * * an extra long jump if the false branch requires it (p->longjf). */ static u_int count_stmts(struct icode *ic, struct block *p) { u_int n; if (p == 0 || isMarked(ic, p)) return 0; Mark(ic, p); n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p)); return slength(p->stmts) + n + 1 + p->longjt + p->longjf; } /* * Allocate memory. All allocation is done before optimization * is begun. A linear bound on the size of all data structures is computed * from the total number of blocks and/or statements. */ static void opt_init(opt_state_t *opt_state, struct icode *ic) { bpf_u_int32 *p; int i, n, max_stmts; u_int product; size_t block_memsize, edge_memsize; /* * First, count the blocks, so we can malloc an array to map * block number to block. Then, put the blocks into the array. */ unMarkAll(ic); n = count_blocks(ic, ic->root); opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks)); if (opt_state->blocks == NULL) opt_error(opt_state, "malloc"); unMarkAll(ic); opt_state->n_blocks = 0; number_blks_r(opt_state, ic, ic->root); /* * This "should not happen". */ if (opt_state->n_blocks == 0) opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue"); opt_state->n_edges = 2 * opt_state->n_blocks; if ((opt_state->n_edges / 2) != opt_state->n_blocks) { /* * Overflow. */ opt_error(opt_state, "filter is too complex to optimize"); } opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges)); if (opt_state->edges == NULL) { opt_error(opt_state, "malloc"); } /* * The number of levels is bounded by the number of nodes. */ opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels)); if (opt_state->levels == NULL) { opt_error(opt_state, "malloc"); } opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1; opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1; /* * Make sure opt_state->n_blocks * opt_state->nodewords fits * in a u_int; we use it as a u_int number-of-iterations * value. */ product = opt_state->n_blocks * opt_state->nodewords; if ((product / opt_state->n_blocks) != opt_state->nodewords) { /* * XXX - just punt and don't try to optimize? * In practice, this is unlikely to happen with * a normal filter. */ opt_error(opt_state, "filter is too complex to optimize"); } /* * Make sure the total memory required for that doesn't * overflow. */ block_memsize = (size_t)2 * product * sizeof(*opt_state->space); if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) { opt_error(opt_state, "filter is too complex to optimize"); } /* * Make sure opt_state->n_edges * opt_state->edgewords fits * in a u_int; we use it as a u_int number-of-iterations * value. */ product = opt_state->n_edges * opt_state->edgewords; if ((product / opt_state->n_edges) != opt_state->edgewords) { opt_error(opt_state, "filter is too complex to optimize"); } /* * Make sure the total memory required for that doesn't * overflow. */ edge_memsize = (size_t)product * sizeof(*opt_state->space); if (edge_memsize / product != sizeof(*opt_state->space)) { opt_error(opt_state, "filter is too complex to optimize"); } /* * Make sure the total memory required for both of them doesn't * overflow. */ if (block_memsize > SIZE_MAX - edge_memsize) { opt_error(opt_state, "filter is too complex to optimize"); } /* XXX */ opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize); if (opt_state->space == NULL) { opt_error(opt_state, "malloc"); } p = opt_state->space; opt_state->all_dom_sets = p; for (i = 0; i < n; ++i) { opt_state->blocks[i]->dom = p; p += opt_state->nodewords; } opt_state->all_closure_sets = p; for (i = 0; i < n; ++i) { opt_state->blocks[i]->closure = p; p += opt_state->nodewords; } opt_state->all_edge_sets = p; for (i = 0; i < n; ++i) { register struct block *b = opt_state->blocks[i]; b->et.edom = p; p += opt_state->edgewords; b->ef.edom = p; p += opt_state->edgewords; b->et.id = i; opt_state->edges[i] = &b->et; b->ef.id = opt_state->n_blocks + i; opt_state->edges[opt_state->n_blocks + i] = &b->ef; b->et.pred = b; b->ef.pred = b; } max_stmts = 0; for (i = 0; i < n; ++i) max_stmts += slength(opt_state->blocks[i]->stmts) + 1; /* * We allocate at most 3 value numbers per statement, * so this is an upper bound on the number of valnodes * we'll need. */ opt_state->maxval = 3 * max_stmts; opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap)); if (opt_state->vmap == NULL) { opt_error(opt_state, "malloc"); } opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base)); if (opt_state->vnode_base == NULL) { opt_error(opt_state, "malloc"); } } /* * This is only used when supporting optimizer debugging. It is * global state, so do *not* do more than one compile in parallel * and expect it to provide meaningful information. */ #ifdef BDEBUG int bids[NBIDS]; #endif static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...) PCAP_PRINTFLIKE(2, 3); /* * Returns true if successful. Returns false if a branch has * an offset that is too large. If so, we have marked that * branch so that on a subsequent iteration, it will be treated * properly. */ static int convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p) { struct bpf_insn *dst; struct slist *src; u_int slen; u_int off; struct slist **offset = NULL; if (p == 0 || isMarked(ic, p)) return (1); Mark(ic, p); if (convert_code_r(conv_state, ic, JF(p)) == 0) return (0); if (convert_code_r(conv_state, ic, JT(p)) == 0) return (0); slen = slength(p->stmts); dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf); /* inflate length by any extra jumps */ p->offset = (int)(dst - conv_state->fstart); /* generate offset[] for convenience */ if (slen) { offset = (struct slist **)calloc(slen, sizeof(struct slist *)); if (!offset) { conv_error(conv_state, "not enough core"); /*NOTREACHED*/ } } src = p->stmts; for (off = 0; off < slen && src; off++) { #if 0 printf("off=%d src=%x\n", off, src); #endif offset[off] = src; src = src->next; } off = 0; for (src = p->stmts; src; src = src->next) { if (src->s.code == NOP) continue; dst->code = (u_short)src->s.code; dst->k = src->s.k; /* fill block-local relative jump */ if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) { #if 0 if (src->s.jt || src->s.jf) { free(offset); conv_error(conv_state, "illegal jmp destination"); /*NOTREACHED*/ } #endif goto filled; } if (off == slen - 2) /*???*/ goto filled; { u_int i; int jt, jf; const char ljerr[] = "%s for block-local relative jump: off=%d"; #if 0 printf("code=%x off=%d %x %x\n", src->s.code, off, src->s.jt, src->s.jf); #endif if (!src->s.jt || !src->s.jf) { free(offset); conv_error(conv_state, ljerr, "no jmp destination", off); /*NOTREACHED*/ } jt = jf = 0; for (i = 0; i < slen; i++) { if (offset[i] == src->s.jt) { if (jt) { free(offset); conv_error(conv_state, ljerr, "multiple matches", off); /*NOTREACHED*/ } if (i - off - 1 >= 256) { free(offset); conv_error(conv_state, ljerr, "out-of-range jump", off); /*NOTREACHED*/ } dst->jt = (u_char)(i - off - 1); jt++; } if (offset[i] == src->s.jf) { if (jf) { free(offset); conv_error(conv_state, ljerr, "multiple matches", off); /*NOTREACHED*/ } if (i - off - 1 >= 256) { free(offset); conv_error(conv_state, ljerr, "out-of-range jump", off); /*NOTREACHED*/ } dst->jf = (u_char)(i - off - 1); jf++; } } if (!jt || !jf) { free(offset); conv_error(conv_state, ljerr, "no destination found", off); /*NOTREACHED*/ } } filled: ++dst; ++off; } if (offset) free(offset); #ifdef BDEBUG if (dst - conv_state->fstart < NBIDS) bids[dst - conv_state->fstart] = p->id + 1; #endif dst->code = (u_short)p->s.code; dst->k = p->s.k; if (JT(p)) { /* number of extra jumps inserted */ u_char extrajmps = 0; off = JT(p)->offset - (p->offset + slen) - 1; if (off >= 256) { /* offset too large for branch, must add a jump */ if (p->longjt == 0) { /* mark this instruction and retry */ p->longjt++; return(0); } dst->jt = extrajmps; extrajmps++; dst[extrajmps].code = BPF_JMP|BPF_JA; dst[extrajmps].k = off - extrajmps; } else dst->jt = (u_char)off; off = JF(p)->offset - (p->offset + slen) - 1; if (off >= 256) { /* offset too large for branch, must add a jump */ if (p->longjf == 0) { /* mark this instruction and retry */ p->longjf++; return(0); } /* branch if F to following jump */ /* if two jumps are inserted, F goes to second one */ dst->jf = extrajmps; extrajmps++; dst[extrajmps].code = BPF_JMP|BPF_JA; dst[extrajmps].k = off - extrajmps; } else dst->jf = (u_char)off; } return (1); } /* * Convert flowgraph intermediate representation to the * BPF array representation. Set *lenp to the number of instructions. * * This routine does *NOT* leak the memory pointed to by fp. It *must * not* do free(fp) before returning fp; doing so would make no sense, * as the BPF array pointed to by the return value of icode_to_fcode() * must be valid - it's being returned for use in a bpf_program structure. * * If it appears that icode_to_fcode() is leaking, the problem is that * the program using pcap_compile() is failing to free the memory in * the BPF program when it's done - the leak is in the program, not in * the routine that happens to be allocating the memory. (By analogy, if * a program calls fopen() without ever calling fclose() on the FILE *, * it will leak the FILE structure; the leak is not in fopen(), it's in * the program.) Change the program to use pcap_freecode() when it's * done with the filter program. See the pcap man page. */ struct bpf_insn * icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp, char *errbuf) { u_int n; struct bpf_insn *fp; conv_state_t conv_state; conv_state.fstart = NULL; conv_state.errbuf = errbuf; if (setjmp(conv_state.top_ctx) != 0) { free(conv_state.fstart); return NULL; } /* * Loop doing convert_code_r() until no branches remain * with too-large offsets. */ for (;;) { unMarkAll(ic); n = *lenp = count_stmts(ic, root); fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); if (fp == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc"); return NULL; } memset((char *)fp, 0, sizeof(*fp) * n); conv_state.fstart = fp; conv_state.ftail = fp + n; unMarkAll(ic); if (convert_code_r(&conv_state, ic, root)) break; free(fp); } return fp; } /* * For iconv_to_fconv() errors. */ static void PCAP_NORETURN conv_error(conv_state_t *conv_state, const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vsnprintf(conv_state->errbuf, PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); longjmp(conv_state->top_ctx, 1); /* NOTREACHED */ #ifdef _AIX PCAP_UNREACHABLE #endif /* _AIX */ } /* * Make a copy of a BPF program and put it in the "fcode" member of * a "pcap_t". * * If we fail to allocate memory for the copy, fill in the "errbuf" * member of the "pcap_t" with an error message, and return -1; * otherwise, return 0. */ int install_bpf_program(pcap_t *p, struct bpf_program *fp) { size_t prog_size; /* * Validate the program. */ if (!pcap_validate_filter(fp->bf_insns, fp->bf_len)) { snprintf(p->errbuf, sizeof(p->errbuf), "BPF program is not valid"); return (-1); } /* * Free up any already installed program. */ pcap_freecode(&p->fcode); prog_size = sizeof(*fp->bf_insns) * fp->bf_len; p->fcode.bf_len = fp->bf_len; p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); if (p->fcode.bf_insns == NULL) { pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), errno, "malloc"); return (-1); } memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size); return (0); } #ifdef BDEBUG static void dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog, FILE *out) { int icount, noffset; int i; if (block == NULL || isMarked(ic, block)) return; Mark(ic, block); icount = slength(block->stmts) + 1 + block->longjt + block->longjf; noffset = min(block->offset + icount, (int)prog->bf_len); fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id); for (i = block->offset; i < noffset; i++) { fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i)); } fprintf(out, "\" tooltip=\""); for (i = 0; i < BPF_MEMWORDS; i++) if (block->val[i] != VAL_UNKNOWN) fprintf(out, "val[%d]=%d ", i, block->val[i]); fprintf(out, "val[A]=%d ", block->val[A_ATOM]); fprintf(out, "val[X]=%d", block->val[X_ATOM]); fprintf(out, "\""); if (JT(block) == NULL) fprintf(out, ", peripheries=2"); fprintf(out, "];\n"); dot_dump_node(ic, JT(block), prog, out); dot_dump_node(ic, JF(block), prog, out); } static void dot_dump_edge(struct icode *ic, struct block *block, FILE *out) { if (block == NULL || isMarked(ic, block)) return; Mark(ic, block); if (JT(block)) { fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n", block->id, JT(block)->id); fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n", block->id, JF(block)->id); } dot_dump_edge(ic, JT(block), out); dot_dump_edge(ic, JF(block), out); } /* Output the block CFG using graphviz/DOT language * In the CFG, block's code, value index for each registers at EXIT, * and the jump relationship is show. * * example DOT for BPF `ip src host 1.1.1.1' is: digraph BPF { - block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh [12]\n(001) jeq #0x800 jt 2 jf 5" tooltip="val[A]=0 val[X]=0"]; - block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld [26]\n(003) jeq #0x1010101 jt 4 jf 5" tooltip="val[A]=0 val[X]=0"]; - block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2]; - block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2]; - "block0":se -> "block1":n [label="T"]; - "block0":sw -> "block3":n [label="F"]; - "block1":se -> "block2":n [label="T"]; - "block1":sw -> "block3":n [label="F"]; + block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh [12]\n(001) jeq #0x800 jt 2 jf 5" tooltip="val[A]=0 val[X]=0"]; + block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld [26]\n(003) jeq #0x1010101 jt 4 jf 5" tooltip="val[A]=0 val[X]=0"]; + block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2]; + block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2]; + "block0":se -> "block1":n [label="T"]; + "block0":sw -> "block3":n [label="F"]; + "block1":se -> "block2":n [label="T"]; + "block1":sw -> "block3":n [label="F"]; } * * After install graphviz on https://www.graphviz.org/, save it as bpf.dot * and run `dot -Tpng -O bpf.dot' to draw the graph. */ static int dot_dump(struct icode *ic, char *errbuf) { struct bpf_program f; FILE *out = stdout; memset(bids, 0, sizeof bids); f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); if (f.bf_insns == NULL) return -1; fprintf(out, "digraph BPF {\n"); unMarkAll(ic); dot_dump_node(ic, ic->root, &f, out); unMarkAll(ic); dot_dump_edge(ic, ic->root, out); fprintf(out, "}\n"); free((char *)f.bf_insns); return 0; } static int plain_dump(struct icode *ic, char *errbuf) { struct bpf_program f; memset(bids, 0, sizeof bids); f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); if (f.bf_insns == NULL) return -1; bpf_dump(&f, 1); putchar('\n'); free((char *)f.bf_insns); return 0; } static void opt_dump(opt_state_t *opt_state, struct icode *ic) { int status; char errbuf[PCAP_ERRBUF_SIZE]; /* * If the CFG, in DOT format, is requested, output it rather than * the code that would be generated from that graph. */ if (pcap_print_dot_graph) status = dot_dump(ic, errbuf); else status = plain_dump(ic, errbuf); if (status == -1) opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf); } #endif diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c index 37c805658253..c7bfef1dfad7 100644 --- a/pcap-bt-linux.c +++ b/pcap-bt-linux.c @@ -1,451 +1,451 @@ /* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Bluetooth sniffing API implementation for Linux platform * By Paolo Abeni * */ #ifdef HAVE_CONFIG_H #include #endif #include "pcap-int.h" #include "pcap-bt-linux.h" #include "pcap/bluetooth.h" #include #include #include #include #include #include #include #include #include #include #define BT_IFACE "bluetooth" #define BT_CTRL_SIZE 128 /* forward declaration */ static int bt_activate(pcap_t *); static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); static int bt_inject_linux(pcap_t *, const void *, int); static int bt_setdirection_linux(pcap_t *, pcap_direction_t); static int bt_stats_linux(pcap_t *, struct pcap_stat *); /* * Private data for capturing on Linux Bluetooth devices. */ struct pcap_bt { int dev_id; /* device ID of device we're bound to */ }; int bt_findalldevs(pcap_if_list_t *devlistp, char *err_str) { struct hci_dev_list_req *dev_list; struct hci_dev_req *dev_req; int sock; unsigned i; int ret = 0; sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (sock < 0) { /* if bluetooth is not supported this is not fatal*/ if (errno == EAFNOSUPPORT) return 0; pcap_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, errno, "Can't open raw Bluetooth socket"); return -1; } dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); if (!dev_list) { snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list", HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); ret = -1; goto done; } /* * Zero the complete header, which is larger than dev_num because of tail * padding, to silence Valgrind, which overshoots validating that dev_num * has been set. * https://github.com/the-tcpdump-group/libpcap/issues/1083 * https://bugs.kde.org/show_bug.cgi?id=448464 */ memset(dev_list, 0, sizeof(*dev_list)); dev_list->dev_num = HCI_MAX_DEV; if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) { pcap_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, errno, "Can't get Bluetooth device list via ioctl"); ret = -1; goto free; } dev_req = dev_list->dev_req; for (i = 0; i < dev_list->dev_num; i++, dev_req++) { char dev_name[20], dev_descr[40]; snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id); snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i); /* * Bluetooth is a wireless technology. * XXX - if there's the notion of associating with a * network, and we can determine whether the interface * is associated with a network, check that and set * the status to PCAP_IF_CONNECTION_STATUS_CONNECTED * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED. */ if (add_dev(devlistp, dev_name, PCAP_IF_WIRELESS, dev_descr, err_str) == NULL) { ret = -1; break; } } free: free(dev_list); done: close(sock); return ret; } pcap_t * bt_create(const char *device, char *ebuf, int *is_ours) { const char *cp; char *cpend; long devnum; pcap_t *p; /* Does this look like a Bluetooth device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with BT_IFACE? */ if (strncmp(cp, BT_IFACE, sizeof BT_IFACE - 1) != 0) { /* Nope, doesn't begin with BT_IFACE */ *is_ours = 0; return NULL; } /* Yes - is BT_IFACE followed by a number? */ cp += sizeof BT_IFACE - 1; devnum = strtol(cp, &cpend, 10); if (cpend == cp || *cpend != '\0') { /* Not followed by a number. */ *is_ours = 0; return NULL; } if (devnum < 0) { /* Followed by a non-valid number. */ *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt); if (p == NULL) return (NULL); p->activate_op = bt_activate; return (p); } static int bt_activate(pcap_t* handle) { struct pcap_bt *handlep = handle->priv; struct sockaddr_hci addr; int opt; int dev_id; struct hci_filter flt; int err = PCAP_ERROR; /* get bt interface id */ if (sscanf(handle->opt.device, BT_IFACE"%d", &dev_id) != 1) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get Bluetooth device index from %s", handle->opt.device); return PCAP_ERROR; } /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) handle->snapshot = MAXIMUM_SNAPLEN; /* Initialize some components of the pcap structure. */ handle->bufsize = BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header)+handle->snapshot; handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR; handle->read_op = bt_read_linux; handle->inject_op = bt_inject_linux; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = bt_setdirection_linux; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = bt_stats_linux; handlep->dev_id = dev_id; /* Create HCI socket */ handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (handle->fd < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't create raw socket"); return PCAP_ERROR; } handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't allocate dump buffer"); goto close_fail; } opt = 1; if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't enable data direction info"); goto close_fail; } opt = 1; if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't enable time stamp"); goto close_fail; } /* Setup filter, do not call hci function to avoid dependence on * external libs */ memset(&flt, 0, sizeof(flt)); memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't set filter"); goto close_fail; } /* Bind socket to the HCI device */ addr.hci_family = AF_BLUETOOTH; addr.hci_dev = handlep->dev_id; #ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL addr.hci_channel = HCI_CHANNEL_RAW; #endif if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't attach to device %d", handlep->dev_id); goto close_fail; } if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to Bluetooth devices. */ err = PCAP_ERROR_RFMON_NOTSUP; goto close_fail; } if (handle->opt.buffer_size != 0) { /* * Set the socket buffer size to the specified value. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, errno, PCAP_ERRBUF_SIZE, "SO_RCVBUF"); goto close_fail; } } handle->selectable_fd = handle->fd; return 0; close_fail: pcap_cleanup_live_common(handle); return err; } static int bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) { struct cmsghdr *cmsg; struct msghdr msg; struct iovec iv; ssize_t ret; struct pcap_pkthdr pkth; pcap_bluetooth_h4_header* bthdr; u_char *pktd; int in = 0; pktd = (u_char *)handle->buffer + BT_CTRL_SIZE; bthdr = (pcap_bluetooth_h4_header*)(void *)pktd; iv.iov_base = pktd + sizeof(pcap_bluetooth_h4_header); iv.iov_len = handle->snapshot; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iv; msg.msg_iovlen = 1; msg.msg_control = handle->buffer; msg.msg_controllen = BT_CTRL_SIZE; /* ignore interrupt system call error */ do { ret = recvmsg(handle->fd, &msg, 0); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Nonblocking mode, no data */ return 0; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't receive packet"); return -1; } pkth.caplen = (bpf_u_int32)ret; /* get direction and timestamp*/ cmsg = CMSG_FIRSTHDR(&msg); while (cmsg) { switch (cmsg->cmsg_type) { case HCI_CMSG_DIR: memcpy(&in, CMSG_DATA(cmsg), sizeof in); break; - case HCI_CMSG_TSTAMP: - memcpy(&pkth.ts, CMSG_DATA(cmsg), - sizeof pkth.ts); + case HCI_CMSG_TSTAMP: + memcpy(&pkth.ts, CMSG_DATA(cmsg), + sizeof pkth.ts); break; } cmsg = CMSG_NXTHDR(&msg, cmsg); } switch (handle->direction) { case PCAP_D_IN: if (!in) return 0; break; case PCAP_D_OUT: if (in) return 0; break; default: break; } bthdr->direction = htonl(in != 0); pkth.caplen+=sizeof(pcap_bluetooth_h4_header); pkth.len = pkth.caplen; if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { callback(user, &pkth, pktd); return 1; } return 0; /* didn't pass filter */ } static int bt_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Packet injection is not supported on Bluetooth devices"); return (-1); } static int bt_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_bt *handlep = handle->priv; int ret; struct hci_dev_info dev_info; struct hci_dev_stats * s = &dev_info.stat; dev_info.dev_id = handlep->dev_id; /* ignore eintr */ do { ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't get stats via ioctl"); return (-1); } /* we receive both rx and tx frames, so comulate all stats */ stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + s->acl_tx +s->sco_tx; stats->ps_drop = s->err_rx + s->err_tx; stats->ps_ifdrop = 0; return 0; } static int bt_setdirection_linux(pcap_t *p, pcap_direction_t d) { /* * It's guaranteed, at this point, that d is a valid * direction value. */ p->direction = d; return 0; } diff --git a/pcap-common.c b/pcap-common.c index 4f12d8abb18e..75461b12cf26 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -1,1400 +1,1400 @@ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * pcap-common.c - common code for pcap and pcapng files */ #ifdef HAVE_CONFIG_H #include #endif #include #include "pcap-int.h" #include "pcap-common.h" /* * We don't write DLT_* values to capture files, because they're not the * same on all platforms. * * Unfortunately, the various flavors of BSD have not always used the same * numerical values for the same data types, and various patches to * libpcap for non-BSD OSes have added their own DLT_* codes for link * layer encapsulation types seen on those OSes, and those codes have had, * in some cases, values that were also used, on other platforms, for other * link layer encapsulation types. * * This means that capture files of a type whose numerical DLT_* code * means different things on different BSDs, or with different versions * of libpcap, can't always be read on systems other than those like * the one running on the machine on which the capture was made. * * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_* * codes to DLT_* codes when reading a savefile header. * * For those DLT_* codes that have, as far as we know, the same values on * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as * DLT_xxx; that way, captures of those types can still be read by * versions of libpcap that map LINKTYPE_* values to DLT_* values, and * captures of those types written by versions of libpcap that map DLT_ * values to LINKTYPE_ values can still be read by older versions * of libpcap. * * The other LINKTYPE_* codes are given values starting at 100, in the * hopes that no DLT_* code will be given one of those values. * * In order to ensure that a given LINKTYPE_* code's value will refer to * the same encapsulation type on all platforms, you should not allocate * a new LINKTYPE_* value without consulting * "tcpdump-workers@lists.tcpdump.org". The tcpdump developers will * allocate a value for you, and will not subsequently allocate it to * anybody else; that value will be added to the "pcap.h" in the * tcpdump.org Git repository, so that a future libpcap release will * include it. * * You should, if possible, also contribute patches to libpcap and tcpdump * to handle the new encapsulation type, so that they can also be checked * into the tcpdump.org Git repository and so that they will appear in * future libpcap and tcpdump releases. * * Do *NOT* assume that any values after the largest value in this file * are available; you might not have the most up-to-date version of this * file, and new values after that one might have been assigned. Also, * do *NOT* use any values below 100 - those might already have been * taken by one (or more!) organizations. * * Any platform that defines additional DLT_* codes should: * * request a LINKTYPE_* code and value from tcpdump.org, * as per the above; * * add, in their version of libpcap, an entry to map * those DLT_* codes to the corresponding LINKTYPE_* * code; * * redefine, in their "net/bpf.h", any DLT_* values * that collide with the values used by their additional * DLT_* codes, to remove those collisions (but without * making them collide with any of the LINKTYPE_* * values equal to 50 or above; they should also avoid * defining DLT_* values that collide with those * LINKTYPE_* values, either). */ #define LINKTYPE_NULL DLT_NULL #define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */ #define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */ #define LINKTYPE_AX25 DLT_AX25 #define LINKTYPE_PRONET DLT_PRONET #define LINKTYPE_CHAOS DLT_CHAOS #define LINKTYPE_IEEE802_5 DLT_IEEE802 /* DLT_IEEE802 is used for 802.5 Token Ring */ #define LINKTYPE_ARCNET_BSD DLT_ARCNET /* BSD-style headers */ #define LINKTYPE_SLIP DLT_SLIP #define LINKTYPE_PPP DLT_PPP #define LINKTYPE_FDDI DLT_FDDI /* * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662 * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol * field) at the beginning of the packet. * * This is for use when there is always such a header; the address field * might be 0xff, for regular PPP, or it might be an address field for Cisco * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco * HDLC"). This is, for example, what you get with NetBSD's DLT_PPP_SERIAL. * * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL * captures will be written out with a link type that NetBSD's tcpdump * can read. */ #define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */ #define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */ #define LINKTYPE_SYMANTEC_FIREWALL 99 /* Symantec Enterprise Firewall */ /* * These correspond to DLT_s that have different values on different * platforms; we map between these values in capture files and * the DLT_ values as returned by pcap_datalink() and passed to * pcap_open_dead(). */ #define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */ #define LINKTYPE_RAW 101 /* raw IP */ #define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */ #define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */ /* * Values starting with 104 are used for newly-assigned link-layer * header type values; for those link-layer header types, the DLT_ * value returned by pcap_datalink() and passed to pcap_open_dead(), * and the LINKTYPE_ value that appears in capture files, are the * same. * * LINKTYPE_MATCHING_MIN is the lowest such value; LINKTYPE_MATCHING_MAX * is the highest such value. */ #define LINKTYPE_MATCHING_MIN 104 /* lowest value in the "matching" range */ #define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ #define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ #define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */ #define LINKTYPE_FRELAY 107 /* Frame Relay */ #define LINKTYPE_LOOP 108 /* OpenBSD loopback */ #define LINKTYPE_ENC 109 /* OpenBSD IPSEC enc */ /* * These two types are reserved for future use. */ #define LINKTYPE_LANE8023 110 /* ATM LANE + 802.3 */ #define LINKTYPE_HIPPI 111 /* NetBSD HIPPI */ /* * Used for NetBSD DLT_HDLC; from looking at the one driver in NetBSD * that uses it, it's Cisco HDLC, so it's the same as DLT_C_HDLC/ * LINKTYPE_C_HDLC, but we define a separate value to avoid some * compatibility issues with programs on NetBSD. * * All code should treat LINKTYPE_NETBSD_HDLC and LINKTYPE_C_HDLC the same. */ #define LINKTYPE_NETBSD_HDLC 112 /* NetBSD HDLC framing */ #define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */ #define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */ #define LINKTYPE_ECONET 115 /* Acorn Econet */ /* * Reserved for use with OpenBSD ipfilter. */ #define LINKTYPE_IPFILTER 116 #define LINKTYPE_PFLOG 117 /* OpenBSD DLT_PFLOG */ #define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */ #define LINKTYPE_IEEE802_11_PRISM 119 /* 802.11 plus Prism II monitor mode radio metadata header */ #define LINKTYPE_IEEE802_11_AIRONET 120 /* 802.11 plus FreeBSD Aironet driver radio metadata header */ /* * Reserved for Siemens HiPath HDLC. */ #define LINKTYPE_HHDLC 121 #define LINKTYPE_IP_OVER_FC 122 /* RFC 2625 IP-over-Fibre Channel */ #define LINKTYPE_SUNATM 123 /* Solaris+SunATM */ /* * Reserved as per request from Kent Dahlgren * for private use. */ #define LINKTYPE_RIO 124 /* RapidIO */ #define LINKTYPE_PCI_EXP 125 /* PCI Express */ #define LINKTYPE_AURORA 126 /* Xilinx Aurora link layer */ #define LINKTYPE_IEEE802_11_RADIOTAP 127 /* 802.11 plus radiotap radio metadata header */ /* * Reserved for the TZSP encapsulation, as per request from * Chris Waters * TZSP is a generic encapsulation for any other link type, * which includes a means to include meta-information * with the packet, e.g. signal strength and channel * for 802.11 packets. */ #define LINKTYPE_TZSP 128 /* Tazmen Sniffer Protocol */ #define LINKTYPE_ARCNET_LINUX 129 /* Linux-style headers */ /* * Juniper-private data link types, as per request from * Hannes Gredler . The corresponding * DLT_s are used for passing on chassis-internal * metainformation such as QOS profiles, etc.. */ #define LINKTYPE_JUNIPER_MLPPP 130 #define LINKTYPE_JUNIPER_MLFR 131 #define LINKTYPE_JUNIPER_ES 132 #define LINKTYPE_JUNIPER_GGSN 133 #define LINKTYPE_JUNIPER_MFR 134 #define LINKTYPE_JUNIPER_ATM2 135 #define LINKTYPE_JUNIPER_SERVICES 136 #define LINKTYPE_JUNIPER_ATM1 137 #define LINKTYPE_APPLE_IP_OVER_IEEE1394 138 /* Apple IP-over-IEEE 1394 cooked header */ #define LINKTYPE_MTP2_WITH_PHDR 139 #define LINKTYPE_MTP2 140 #define LINKTYPE_MTP3 141 #define LINKTYPE_SCCP 142 #define LINKTYPE_DOCSIS 143 /* DOCSIS MAC frames */ #define LINKTYPE_LINUX_IRDA 144 /* Linux-IrDA */ /* * Reserved for IBM SP switch and IBM Next Federation switch. */ #define LINKTYPE_IBM_SP 145 #define LINKTYPE_IBM_SN 146 /* * Reserved for private use. If you have some link-layer header type * that you want to use within your organization, with the capture files * using that link-layer header type not ever be sent outside your * organization, you can use these values. * * No libpcap release will use these for any purpose, nor will any * tcpdump release use them, either. * * Do *NOT* use these in capture files that you expect anybody not using * your private versions of capture-file-reading tools to read; in * particular, do *NOT* use them in products, otherwise you may find that * people won't be able to use tcpdump, or snort, or Ethereal, or... to * read capture files from your firewall/intrusion detection/traffic * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value, * and you may also find that the developers of those applications will * not accept patches to let them read those files. * * Also, do not use them if somebody might send you a capture using them * for *their* private type and tools using them for *your* private type * would have to read them. * * Instead, in those cases, ask "tcpdump-workers@lists.tcpdump.org" for a * new DLT_ and LINKTYPE_ value, as per the comment in pcap/bpf.h, and use * the type you're given. */ #define LINKTYPE_USER0 147 #define LINKTYPE_USER1 148 #define LINKTYPE_USER2 149 #define LINKTYPE_USER3 150 #define LINKTYPE_USER4 151 #define LINKTYPE_USER5 152 #define LINKTYPE_USER6 153 #define LINKTYPE_USER7 154 #define LINKTYPE_USER8 155 #define LINKTYPE_USER9 156 #define LINKTYPE_USER10 157 #define LINKTYPE_USER11 158 #define LINKTYPE_USER12 159 #define LINKTYPE_USER13 160 #define LINKTYPE_USER14 161 #define LINKTYPE_USER15 162 /* * For future use with 802.11 captures - defined by AbsoluteValue * Systems to store a number of bits of link-layer information * including radio information: * * http://www.shaftnet.org/~pizza/software/capturefrm.txt */ #define LINKTYPE_IEEE802_11_AVS 163 /* 802.11 plus AVS radio metadata header */ /* * Juniper-private data link type, as per request from * Hannes Gredler . The corresponding * DLT_s are used for passing on chassis-internal * metainformation such as QOS profiles, etc.. */ #define LINKTYPE_JUNIPER_MONITOR 164 /* * BACnet MS/TP frames. */ #define LINKTYPE_BACNET_MS_TP 165 /* * Another PPP variant as per request from Karsten Keil . * * This is used in some OSes to allow a kernel socket filter to distinguish * between incoming and outgoing packets, on a socket intended to * supply pppd with outgoing packets so it can do dial-on-demand and * hangup-on-lack-of-demand; incoming packets are filtered out so they * don't cause pppd to hold the connection up (you don't want random * input packets such as port scans, packets from old lost connections, * etc. to force the connection to stay up). * * The first byte of the PPP header (0xff03) is modified to accommodate * the direction - 0x00 = IN, 0x01 = OUT. */ #define LINKTYPE_PPP_PPPD 166 /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, cookies, etc.. */ #define LINKTYPE_JUNIPER_PPPOE 167 #define LINKTYPE_JUNIPER_PPPOE_ATM 168 #define LINKTYPE_GPRS_LLC 169 /* GPRS LLC */ #define LINKTYPE_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ #define LINKTYPE_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ /* * Requested by Oolan Zimmer for use in Gcom's T1/E1 line * monitoring equipment. */ #define LINKTYPE_GCOM_T1E1 172 #define LINKTYPE_GCOM_SERIAL 173 /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_ is used * for internal communication to Physical Interface Cards (PIC) */ #define LINKTYPE_JUNIPER_PIC_PEER 174 /* * Link types requested by Gregor Maier of Endace * Measurement Systems. They add an ERF header (see * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of * the link-layer header. */ #define LINKTYPE_ERF_ETH 175 /* Ethernet */ #define LINKTYPE_ERF_POS 176 /* Packet-over-SONET */ /* * Requested by Daniele Orlandi for raw LAPD * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header * includes additional information before the LAPD header, so it's * not necessarily a generic LAPD header. */ #define LINKTYPE_LINUX_LAPD 177 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The Link Types are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames */ #define LINKTYPE_JUNIPER_ETHER 178 #define LINKTYPE_JUNIPER_PPP 179 #define LINKTYPE_JUNIPER_FRELAY 180 #define LINKTYPE_JUNIPER_CHDLC 181 /* * Multi Link Frame Relay (FRF.16) */ #define LINKTYPE_MFR 182 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ #define LINKTYPE_JUNIPER_VP 183 /* * Arinc 429 frames. * DLT_ requested by Gianluca Varenni . * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define LINKTYPE_A429 184 /* * Arinc 653 Interpartition Communication messages. * DLT_ requested by Gianluca Varenni . * Please refer to the A653-1 standard for more information. */ #define LINKTYPE_A653_ICM 185 /* * This used to be "USB packets, beginning with a USB setup header; * requested by Paolo Abeni ." * * However, that header didn't work all that well - it left out some * useful information - and was abandoned in favor of the DLT_USB_LINUX * header. * * This is now used by FreeBSD for its BPF taps for USB; that has its * own headers. So it is written, so it is done. */ #define LINKTYPE_USB_FREEBSD 186 /* * Bluetooth HCI UART transport layer (part H:4); requested by * Paolo Abeni. */ #define LINKTYPE_BLUETOOTH_HCI_H4 187 /* * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz * . */ #define LINKTYPE_IEEE802_16_MAC_CPS 188 /* * USB packets, beginning with a Linux USB header; requested by * Paolo Abeni . */ #define LINKTYPE_USB_LINUX 189 /* * Controller Area Network (CAN) v. 2.0B packets. * DLT_ requested by Gianluca Varenni . * Used to dump CAN packets coming from a CAN Vector board. * More documentation on the CAN v2.0B frames can be found at * http://www.can-cia.org/downloads/?269 */ #define LINKTYPE_CAN20B 190 /* * IEEE 802.15.4, with address fields padded, as is done by Linux * drivers; requested by Juergen Schimmer. */ #define LINKTYPE_IEEE802_15_4_LINUX 191 /* * Per Packet Information encapsulated packets. * LINKTYPE_ requested by Gianluca Varenni . */ #define LINKTYPE_PPI 192 /* * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; * requested by Charles Clancy. */ #define LINKTYPE_IEEE802_16_MAC_CPS_RADIO 193 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ #define LINKTYPE_JUNIPER_ISM 194 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), and with the FCS at the end of the frame; requested by * Mikko Saarnivala . * * This should only be used if the FCS is present at the end of the * frame; if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be * used. */ #define LINKTYPE_IEEE802_15_4_WITHFCS 195 /* * Various link-layer types, with a pseudo-header, for SITA * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). */ #define LINKTYPE_SITA 196 /* * Various link-layer types, with a pseudo-header, for Endace DAG cards; * encapsulates Endace ERF records. Requested by Stephen Donnelly * . */ #define LINKTYPE_ERF 197 /* * Special header prepended to Ethernet packets when capturing from a * u10 Networks board. Requested by Phil Mulholland * . */ #define LINKTYPE_RAIF1 198 /* * IPMB packet for IPMI, beginning with a 2-byte header, followed by * the I2C slave address, followed by the netFn and LUN, etc.. * Requested by Chanthy Toeung . * * XXX - its DLT_ value used to be called DLT_IPMB, back when we got the * impression from the email thread requesting it that the packet * had no extra 2-byte header. We've renamed it; if anybody used * DLT_IPMB and assumed no 2-byte header, this will cause the compile * to fail, at which point we'll have to figure out what to do about * the two header types using the same DLT_/LINKTYPE_ value. If that * doesn't happen, we'll assume nobody used it and that the redefinition * is safe. */ #define LINKTYPE_IPMB_KONTRON 199 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define LINKTYPE_JUNIPER_ST 200 /* * Bluetooth HCI UART transport layer (part H:4), with pseudo-header * that includes direction information; requested by Paolo Abeni. */ #define LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR 201 /* * AX.25 packet with a 1-byte KISS header; see * * http://www.ax25.net/kiss.htm * * as per Richard Stearn . */ #define LINKTYPE_AX25_KISS 202 /* * LAPD packets from an ISDN channel, starting with the address field, * with no pseudo-header. * Requested by Varuna De Silva . */ #define LINKTYPE_LAPD 203 /* * PPP, with a one-byte direction pseudo-header prepended - zero means * "received by this host", non-zero (any non-zero value) means "sent by * this host" - as per Will Barker . */ #define LINKTYPE_PPP_WITH_DIR 204 /* Don't confuse with LINKTYPE_PPP_PPPD */ /* * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero * means "received by this host", non-zero (any non-zero value) means * "sent by this host" - as per Will Barker . */ #define LINKTYPE_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ /* * Frame Relay, with a one-byte direction pseudo-header prepended - zero * means "received by this host" (DCE -> DTE), non-zero (any non-zero * value) means "sent by this host" (DTE -> DCE) - as per Will Barker * . */ #define LINKTYPE_FRELAY_WITH_DIR 206 /* Frame Relay */ /* * LAPB, with a one-byte direction pseudo-header prepended - zero means * "received by this host" (DCE -> DTE), non-zero (any non-zero value) * means "sent by this host" (DTE -> DCE)- as per Will Barker * . */ #define LINKTYPE_LAPB_WITH_DIR 207 /* LAPB */ /* * 208 is reserved for an as-yet-unspecified proprietary link-layer * type, as requested by Will Barker. */ /* * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman * . */ #define LINKTYPE_IPMB_LINUX 209 /* * FlexRay automotive bus - http://www.flexray.com/ - as requested * by Hannes Kaelber . */ #define LINKTYPE_FLEXRAY 210 /* * Media Oriented Systems Transport (MOST) bus for multimedia * transport - https://www.mostcooperation.com/ - as requested * by Hannes Kaelber . */ #define LINKTYPE_MOST 211 /* * Local Interconnect Network (LIN) bus for vehicle networks - * http://www.lin-subbus.org/ - as requested by Hannes Kaelber * . */ #define LINKTYPE_LIN 212 /* * X2E-private data link type used for serial line capture, * as requested by Hannes Kaelber . */ #define LINKTYPE_X2E_SERIAL 213 /* * X2E-private data link type used for the Xoraya data logger * family, as requested by Hannes Kaelber . */ #define LINKTYPE_X2E_XORAYA 214 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), but with the PHY-level data for non-ASK PHYs (4 octets * of 0 as preamble, one octet of SFD, one octet of frame length+ * reserved bit, and then the MAC-layer data, starting with the * frame control field). * * Requested by Max Filippov . */ #define LINKTYPE_IEEE802_15_4_NONASK_PHY 215 /* * David Gibson requested this for * captures from the Linux kernel /dev/input/eventN devices. This * is used to communicate keystrokes and mouse movements from the * Linux kernel to display systems, such as Xorg. */ #define LINKTYPE_LINUX_EVDEV 216 /* * GSM Um and Abis interfaces, preceded by a "gsmtap" header. * * Requested by Harald Welte . */ #define LINKTYPE_GSMTAP_UM 217 #define LINKTYPE_GSMTAP_ABIS 218 /* * MPLS, with an MPLS label as the link-layer header. * Requested by Michele Marchetto on behalf * of OpenBSD. */ #define LINKTYPE_MPLS 219 /* * USB packets, beginning with a Linux USB header, with the USB header * padded to 64 bytes; required for memory-mapped access. */ #define LINKTYPE_USB_LINUX_MMAPPED 220 /* * DECT packets, with a pseudo-header; requested by * Matthias Wenzel . */ #define LINKTYPE_DECT 221 /* * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" * Date: Mon, 11 May 2009 11:18:30 -0500 * * DLT_AOS. We need it for AOS Space Data Link Protocol. * I have already written dissectors for but need an OK from * legal before I can submit a patch. * */ #define LINKTYPE_AOS 222 /* * Wireless HART (Highway Addressable Remote Transducer) * From the HART Communication Foundation * IES/PAS 62591 * * Requested by Sam Roberts . */ #define LINKTYPE_WIHART 223 /* * Fibre Channel FC-2 frames, beginning with a Frame_Header. * Requested by Kahou Lei . */ #define LINKTYPE_FC_2 224 /* * Fibre Channel FC-2 frames, beginning with an encoding of the * SOF, and ending with an encoding of the EOF. * * The encodings represent the frame delimiters as 4-byte sequences * representing the corresponding ordered sets, with K28.5 * represented as 0xBC, and the D symbols as the corresponding * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, * is represented as 0xBC 0xB5 0x55 0x55. * * Requested by Kahou Lei . */ #define LINKTYPE_FC_2_WITH_FRAME_DELIMS 225 /* * Solaris ipnet pseudo-header; requested by Darren Reed . * * The pseudo-header starts with a one-byte version number; for version 2, * the pseudo-header is: * * struct dl_ipnetinfo { * uint8_t dli_version; * uint8_t dli_family; * uint16_t dli_htype; * uint32_t dli_pktlen; * uint32_t dli_ifindex; * uint32_t dli_grifindex; * uint32_t dli_zsrc; * uint32_t dli_zdst; * }; * * dli_version is 2 for the current version of the pseudo-header. * * dli_family is a Solaris address family value, so it's 2 for IPv4 * and 26 for IPv6. * * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing * packets, and 2 for packets arriving from another zone on the same * machine. * * dli_pktlen is the length of the packet data following the pseudo-header * (so the captured length minus dli_pktlen is the length of the * pseudo-header, assuming the entire pseudo-header was captured). * * dli_ifindex is the interface index of the interface on which the * packet arrived. * * dli_grifindex is the group interface index number (for IPMP interfaces). * * dli_zsrc is the zone identifier for the source of the packet. * * dli_zdst is the zone identifier for the destination of the packet. * * A zone number of 0 is the global zone; a zone number of 0xffffffff * means that the packet arrived from another host on the network, not * from another zone on the same machine. * * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates * which of those it is. */ #define LINKTYPE_IPNET 226 /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied * by Linux SocketCAN, and with multi-byte numerical fields in that header * in big-endian byte order. * * See Documentation/networking/can.txt in the Linux source. * * Requested by Felix Obenhuber . */ #define LINKTYPE_CAN_SOCKETCAN 227 /* * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies * whether it's v4 or v6. Requested by Darren Reed . */ #define LINKTYPE_IPV4 228 #define LINKTYPE_IPV6 229 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), and with no FCS at the end of the frame; requested by * Jon Smirl . */ #define LINKTYPE_IEEE802_15_4_NOFCS 230 /* * Raw D-Bus: * * https://www.freedesktop.org/wiki/Software/dbus * * messages: * * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages * * starting with the endianness flag, followed by the message type, etc., * but without the authentication handshake before the message sequence: * * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * * Requested by Martin Vidner . */ #define LINKTYPE_DBUS 231 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define LINKTYPE_JUNIPER_VS 232 #define LINKTYPE_JUNIPER_SRX_E2E 233 #define LINKTYPE_JUNIPER_FIBRECHANNEL 234 /* * DVB-CI (DVB Common Interface for communication between a PC Card * module and a DVB receiver). See * * https://www.kaiser.cx/pcap-dvbci.html * * for the specification. * * Requested by Martin Kaiser . */ #define LINKTYPE_DVB_CI 235 /* * Variant of 3GPP TS 27.010 multiplexing protocol. Requested * by Hans-Christoph Schemmel . */ #define LINKTYPE_MUX27010 236 /* * STANAG 5066 D_PDUs. Requested by M. Baris Demiray * . */ #define LINKTYPE_STANAG_5066_D_PDU 237 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define LINKTYPE_JUNIPER_ATM_CEMIC 238 /* * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki */ #define LINKTYPE_NFLOG 239 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and always * with the payload including the FCS, as supplied by their * netANALYZER hardware and software. * * Requested by Holger P. Frommer */ #define LINKTYPE_NETANALYZER 240 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and FCS and * 1 byte of SFD, as supplied by their netANALYZER hardware and * software. * * Requested by Holger P. Frommer */ #define LINKTYPE_NETANALYZER_TRANSPARENT 241 /* * IP-over-InfiniBand, as specified by RFC 4391. * * Requested by Petr Sumbera . */ #define LINKTYPE_IPOIB 242 /* * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). * * Requested by Guy Martin . */ #define LINKTYPE_MPEG_2_TS 243 /* * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as * used by their ng40 protocol tester. * * Requested by Jens Grimmer . */ #define LINKTYPE_NG40 244 /* * Pseudo-header giving adapter number and flags, followed by an NFC * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, * as specified by NFC Forum Logical Link Control Protocol Technical * Specification LLCP 1.1. * * Requested by Mike Wakerly . */ #define LINKTYPE_NFC_LLCP 245 /* * pfsync output; DLT_PFSYNC is 18, which collides with DLT_CIP in * SuSE 6.3, on OpenBSD, NetBSD, DragonFly BSD, and macOS, and * is 121, which collides with DLT_HHDLC, in FreeBSD. We pick a * shiny new link-layer header type value that doesn't collide with * anything, in the hopes that future pfsync savefiles, if any, * won't require special hacks to distinguish from other savefiles. * */ #define LINKTYPE_PFSYNC 246 /* * Raw InfiniBand packets, starting with the Local Routing Header. * * Requested by Oren Kladnitsky . */ #define LINKTYPE_INFINIBAND 247 /* * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). * * Requested by Michael Tuexen . */ #define LINKTYPE_SCTP 248 /* * USB packets, beginning with a USBPcap header. * * Requested by Tomasz Mon */ #define LINKTYPE_USBPCAP 249 /* * Schweitzer Engineering Laboratories "RTAC" product serial-line * packets. * * Requested by Chris Bontje . */ #define LINKTYPE_RTAC_SERIAL 250 /* * Bluetooth Low Energy air interface link-layer packets. * * Requested by Mike Kershaw . */ #define LINKTYPE_BLUETOOTH_LE_LL 251 /* * Link-layer header type for upper-protocol layer PDU saves from wireshark. * * the actual contents are determined by two TAGs, one or more of * which is stored with each packet: * * EXP_PDU_TAG_DISSECTOR_NAME the name of the Wireshark dissector - * that can make sense of the data stored. + * that can make sense of the data stored. * * EXP_PDU_TAG_HEUR_DISSECTOR_NAME the name of the Wireshark heuristic * dissector that can make sense of the * data stored. */ #define LINKTYPE_WIRESHARK_UPPER_PDU 252 /* * Link-layer header type for the netlink protocol (nlmon devices). */ #define LINKTYPE_NETLINK 253 /* * Bluetooth Linux Monitor headers for the BlueZ stack. */ #define LINKTYPE_BLUETOOTH_LINUX_MONITOR 254 /* * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as * captured by Ubertooth. */ #define LINKTYPE_BLUETOOTH_BREDR_BB 255 /* * Bluetooth Low Energy link layer packets, as captured by Ubertooth. */ #define LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR 256 /* * PROFIBUS data link layer. */ #define LINKTYPE_PROFIBUS_DL 257 /* * Apple's DLT_PKTAP headers. * * Sadly, the folks at Apple either had no clue that the DLT_USERn values * are for internal use within an organization and partners only, and * didn't know that the right way to get a link-layer header type is to * ask tcpdump.org for one, or knew and didn't care, so they just * used DLT_USER2, which causes problems for everything except for * their version of tcpdump. * * So I'll just give them one; hopefully this will show up in a * libpcap release in time for them to get this into 10.10 Big Sur * or whatever Mavericks' successor is called. LINKTYPE_PKTAP * will be 258 *even on macOS*; that is *intentional*, so that * PKTAP files look the same on *all* OSes (different OSes can have * different numerical values for a given DLT_, but *MUST NOT* have * different values for what goes in a file, as files can be moved * between OSes!). */ #define LINKTYPE_PKTAP 258 /* * Ethernet packets preceded by a header giving the last 6 octets * of the preamble specified by 802.3-2012 Clause 65, section * 65.1.3.2 "Transmit". */ #define LINKTYPE_EPON 259 /* * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" * in the PICMG HPM.2 specification. */ #define LINKTYPE_IPMI_HPM_2 260 /* * per Joshua Wright , formats for Zwave captures. */ #define LINKTYPE_ZWAVE_R1_R2 261 #define LINKTYPE_ZWAVE_R3 262 /* * per Steve Karg , formats for Wattstopper * Digital Lighting Management room bus serial protocol captures. */ #define LINKTYPE_WATTSTOPPER_DLM 263 /* * ISO 14443 contactless smart card messages. */ #define LINKTYPE_ISO_14443 264 /* * Radio data system (RDS) groups. IEC 62106. * Per Jonathan Brucker . */ #define LINKTYPE_RDS 265 /* * USB packets, beginning with a Darwin (macOS, etc.) header. */ #define LINKTYPE_USB_DARWIN 266 /* * OpenBSD DLT_OPENFLOW. */ #define LINKTYPE_OPENFLOW 267 /* * SDLC frames containing SNA PDUs. */ #define LINKTYPE_SDLC 268 /* * per "Selvig, Bjorn" used for * TI protocol sniffer. */ #define LINKTYPE_TI_LLN_SNIFFER 269 /* * per: Erik de Jong for * https://github.com/eriknl/LoRaTap/releases/tag/v0.1 */ #define LINKTYPE_LORATAP 270 /* * per: Stefanha at gmail.com for * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h * for: https://qemu-project.org/Features/VirtioVsock */ #define LINKTYPE_VSOCK 271 /* * Nordic Semiconductor Bluetooth LE sniffer. */ #define LINKTYPE_NORDIC_BLE 272 /* * Excentis DOCSIS 3.1 RF sniffer (XRA-31) * per: bruno.verstuyft at excentis.com * https://www.xra31.com/xra-header */ #define LINKTYPE_DOCSIS31_XRA31 273 /* * mPackets, as specified by IEEE 802.3br Figure 99-4, starting * with the preamble and always ending with a CRC field. */ #define LINKTYPE_ETHERNET_MPACKET 274 /* * DisplayPort AUX channel monitoring data as specified by VESA * DisplayPort(DP) Standard preceded by a pseudo-header. * per dirk.eibach at gdsys.cc */ #define LINKTYPE_DISPLAYPORT_AUX 275 /* * Linux cooked sockets v2. */ #define LINKTYPE_LINUX_SLL2 276 /* * Sercos Monitor, per Manuel Jacob */ #define LINKTYPE_SERCOS_MONITOR 277 /* * OpenVizsla http://openvizsla.org is open source USB analyzer hardware. * It consists of FPGA with attached USB phy and FTDI chip for streaming * the data to the host PC. * * Current OpenVizsla data encapsulation format is described here: * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description * */ #define LINKTYPE_OPENVIZSLA 278 /* * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced * by a PCIe Card for interfacing high speed automotive interfaces. * * The specification for this frame format can be found at: * https://www.elektrobit.com/ebhscr * * for Guenter.Ebermann at elektrobit.com * */ #define LINKTYPE_EBHSCR 279 /* * The https://fd.io vpp graph dispatch tracer produces pcap trace files * in the format documented here: * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing */ #define LINKTYPE_VPP_DISPATCH 280 /* * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format. */ #define LINKTYPE_DSA_TAG_BRCM 281 #define LINKTYPE_DSA_TAG_BRCM_PREPEND 282 /* * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload * exactly as it appears in the spec (no padding, no nothing), and FCS if * specified by FCS Type TLV; requested by James Ko . * Specification at https://github.com/jkcko/ieee802.15.4-tap */ #define LINKTYPE_IEEE802_15_4_TAP 283 /* * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format. */ #define LINKTYPE_DSA_TAG_DSA 284 #define LINKTYPE_DSA_TAG_EDSA 285 /* * Payload of lawful intercept packets using the ELEE protocol; * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii */ #define LINKTYPE_ELEE 286 /* * Serial frames transmitted between a host and a Z-Wave chip. */ #define LINKTYPE_Z_WAVE_SERIAL 287 /* * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. */ #define LINKTYPE_USB_2_0 288 /* * ATSC Link-Layer Protocol (A/330) packets. */ #define LINKTYPE_ATSC_ALP 289 #define LINKTYPE_MATCHING_MAX 289 /* highest value in the "matching" range */ /* * The DLT_ and LINKTYPE_ values in the "matching" range should be the * same, so DLT_MATCHING_MAX and LINKTYPE_MATCHING_MAX should be the * same. */ #if LINKTYPE_MATCHING_MAX != DLT_MATCHING_MAX #error The LINKTYPE_ matching range does not match the DLT_ matching range #endif static struct linktype_map { int dlt; int linktype; } map[] = { /* * These DLT_* codes have LINKTYPE_* codes with values identical * to the values of the corresponding DLT_* code. */ { DLT_NULL, LINKTYPE_NULL }, { DLT_EN10MB, LINKTYPE_ETHERNET }, { DLT_EN3MB, LINKTYPE_EXP_ETHERNET }, { DLT_AX25, LINKTYPE_AX25 }, { DLT_PRONET, LINKTYPE_PRONET }, { DLT_CHAOS, LINKTYPE_CHAOS }, { DLT_IEEE802, LINKTYPE_IEEE802_5 }, { DLT_ARCNET, LINKTYPE_ARCNET_BSD }, { DLT_SLIP, LINKTYPE_SLIP }, { DLT_PPP, LINKTYPE_PPP }, { DLT_FDDI, LINKTYPE_FDDI }, { DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL }, /* * These DLT_* codes have different values on different * platforms; we map them to LINKTYPE_* codes that * have values that should never be equal to any DLT_* * code. */ #ifdef DLT_FR /* BSD/OS Frame Relay */ { DLT_FR, LINKTYPE_FRELAY }, #endif - { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 }, + { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 }, { DLT_RAW, LINKTYPE_RAW }, { DLT_SLIP_BSDOS, LINKTYPE_SLIP_BSDOS }, { DLT_PPP_BSDOS, LINKTYPE_PPP_BSDOS }, { DLT_HDLC, LINKTYPE_NETBSD_HDLC }, /* BSD/OS Cisco HDLC */ { DLT_C_HDLC, LINKTYPE_C_HDLC }, /* * These DLT_* codes are not on all platforms, but, so far, * there don't appear to be any platforms that define * other codes with those values; we map them to * different LINKTYPE_* values anyway, just in case. */ /* Linux ATM Classical IP */ { DLT_ATM_CLIP, LINKTYPE_ATM_CLIP }, /* NetBSD sync/async serial PPP (or Cisco HDLC) */ { DLT_PPP_SERIAL, LINKTYPE_PPP_HDLC }, /* NetBSD PPP over Ethernet */ { DLT_PPP_ETHER, LINKTYPE_PPP_ETHER }, /* * All LINKTYPE_ values between LINKTYPE_MATCHING_MIN * and LINKTYPE_MATCHING_MAX are mapped to identical * DLT_ values. */ { -1, -1 } }; int dlt_to_linktype(int dlt) { int i; /* * DLTs that, on some platforms, have values in the matching range * but that *don't* have the same value as the corresponding * LINKTYPE because, for some reason, not all OSes have the * same value for that DLT (note that the DLT's value might be * outside the matching range on some of those OSes). */ if (dlt == DLT_PFSYNC) return (LINKTYPE_PFSYNC); if (dlt == DLT_PKTAP) return (LINKTYPE_PKTAP); /* * For all other values in the matching range, the DLT * value is the same as the LINKTYPE value. */ if (dlt >= DLT_MATCHING_MIN && dlt <= DLT_MATCHING_MAX) return (dlt); /* * Map the values outside that range. */ for (i = 0; map[i].dlt != -1; i++) { if (map[i].dlt == dlt) return (map[i].linktype); } /* * If we don't have a mapping for this DLT, return an * error; that means that this is a value with no corresponding * LINKTYPE, and we need to assign one. */ return (-1); } int linktype_to_dlt(int linktype) { int i; /* * LINKTYPEs in the matching range that *don't* * have the same value as the corresponding DLTs * because, for some reason, not all OSes have the * same value for that DLT. */ if (linktype == LINKTYPE_PFSYNC) return (DLT_PFSYNC); if (linktype == LINKTYPE_PKTAP) return (DLT_PKTAP); /* * For all other values in the matching range, except for * LINKTYPE_ATM_CLIP, the LINKTYPE value is the same as * the DLT value. * * LINKTYPE_ATM_CLIP is a special case. DLT_ATM_CLIP is * not on all platforms, but, so far, there don't appear * to be any platforms that define it as anything other * than 19; we define LINKTYPE_ATM_CLIP as something * other than 19, just in case. That value is in the * matching range, so we have to check for it. */ if (linktype >= LINKTYPE_MATCHING_MIN && linktype <= LINKTYPE_MATCHING_MAX && linktype != LINKTYPE_ATM_CLIP) return (linktype); /* * Map the values outside that range. */ for (i = 0; map[i].linktype != -1; i++) { if (map[i].linktype == linktype) return (map[i].dlt); } /* * If we don't have an entry for this LINKTYPE, return * the link type value; it may be a DLT from an newer * version of libpcap. */ return linktype; } /* * Return the maximum snapshot length for a given DLT_ value. * * For most link-layer types, we use MAXIMUM_SNAPLEN. * * For DLT_DBUS, the maximum is 128MiB, as per * * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages * * For DLT_EBHSCR, the maximum is 8MiB, as per * * https://www.elektrobit.com/ebhscr * * For DLT_USBPCAP, the maximum is 1MiB, as per * * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985 */ u_int max_snaplen_for_dlt(int dlt) { switch (dlt) { case DLT_DBUS: return 128*1024*1024; case DLT_EBHSCR: return 8*1024*1024; case DLT_USBPCAP: return 1024*1024; default: return MAXIMUM_SNAPLEN; } } diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c index 70cb5d45f77f..f281fb93393b 100644 --- a/pcap-libdlpi.c +++ b/pcap-libdlpi.c @@ -1,517 +1,517 @@ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * This code contributed by Sagun Shakya (sagun.shakya@sun.com) */ /* * Packet capture routines for DLPI using libdlpi under SunOS 5.11. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #include "dlpisubs.h" /* Forwards. */ static int dlpromiscon(pcap_t *, bpf_u_int32); static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); static int pcap_inject_libdlpi(pcap_t *, const void *, int); static void pcap_libdlpi_err(const char *, const char *, int, char *); static void pcap_cleanup_libdlpi(pcap_t *); /* * list_interfaces() will list all the network links that are * available on a system. */ static boolean_t list_interfaces(const char *, void *); typedef struct linknamelist { char linkname[DLPI_LINKNAME_MAX]; struct linknamelist *lnl_next; } linknamelist_t; typedef struct linkwalk { linknamelist_t *lw_list; int lw_err; } linkwalk_t; /* * The caller of this function should free the memory allocated * for each linknamelist_t "entry" allocated. */ static boolean_t list_interfaces(const char *linkname, void *arg) { linkwalk_t *lwp = arg; linknamelist_t *entry; if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { lwp->lw_err = ENOMEM; return (B_TRUE); } (void) pcap_strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); if (lwp->lw_list == NULL) { lwp->lw_list = entry; } else { entry->lnl_next = lwp->lw_list; lwp->lw_list = entry; } return (B_FALSE); } static int pcap_activate_libdlpi(pcap_t *p) { struct pcap_dlpi *pd = p->priv; int status = 0; int retv; dlpi_handle_t dh; dlpi_info_t dlinfo; /* * Enable Solaris raw and passive DLPI extensions; * dlpi_open() will not fail if the underlying link does not support * passive mode. See dlpi(7P) for details. */ retv = dlpi_open(p->opt.device, &dh, DLPI_RAW|DLPI_PASSIVE); if (retv != DLPI_SUCCESS) { if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK) { /* * There's nothing more to say, so clear the * error message. */ status = PCAP_ERROR_NO_SUCH_DEVICE; p->errbuf[0] = '\0'; } else if (retv == DL_SYSERR && (errno == EPERM || errno == EACCES)) { status = PCAP_ERROR_PERM_DENIED; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Attempt to open DLPI device failed with %s - root privilege may be required", (errno == EPERM) ? "EPERM" : "EACCES"); } else { status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_open", retv, p->errbuf); } return (status); } pd->dlpi_hd = dh; if (p->opt.rfmon) { /* * This device exists, but we don't support monitor mode * any platforms that support DLPI. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } /* Bind with DLPI_ANY_SAP. */ if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_bind", retv, p->errbuf); goto bad; } /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) p->snapshot = MAXIMUM_SNAPLEN; /* Enable promiscuous mode. */ if (p->opt.promisc) { retv = dlpromiscon(p, DL_PROMISC_PHYS); if (retv < 0) { /* * "You don't have permission to capture on * this device" and "you don't have permission * to capture in promiscuous mode on this * device" are different; let the user know, * so if they can't get permission to * capture in promiscuous mode, they can at * least try to capture in non-promiscuous * mode. * * XXX - you might have to capture in * promiscuous mode to see outgoing packets. */ if (retv == PCAP_ERROR_PERM_DENIED) status = PCAP_ERROR_PROMISC_PERM_DENIED; else status = retv; goto bad; } } else { /* Try to enable multicast. */ retv = dlpromiscon(p, DL_PROMISC_MULTI); if (retv < 0) { status = retv; goto bad; } } /* Try to enable SAP promiscuity. */ retv = dlpromiscon(p, DL_PROMISC_SAP); if (retv < 0) { /* * Not fatal, since the DL_PROMISC_PHYS mode worked. * Report it as a warning, however. */ if (p->opt.promisc) status = PCAP_WARNING; else { status = retv; goto bad; } } /* Determine link type. */ if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { status = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_info", retv, p->errbuf); goto bad; } if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) { status = PCAP_ERROR; goto bad; } p->fd = dlpi_fd(pd->dlpi_hd); /* Push and configure bufmod. */ if (pcap_conf_bufmod(p, p->snapshot) != 0) { status = PCAP_ERROR; goto bad; } /* * Flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { status = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "FLUSHR"); goto bad; } /* Allocate data buffer. */ if (pcap_alloc_databuf(p) != 0) { status = PCAP_ERROR; goto bad; } /* * "p->fd" is a FD for a STREAMS device, so "select()" and * "poll()" should work on it. */ p->selectable_fd = p->fd; p->read_op = pcap_read_libdlpi; p->inject_op = pcap_inject_libdlpi; p->setfilter_op = install_bpf_program; /* No kernel filtering */ p->setdirection_op = NULL; /* Not implemented */ p->set_datalink_op = NULL; /* Can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_dlpi; p->cleanup_op = pcap_cleanup_libdlpi; return (status); bad: pcap_cleanup_libdlpi(p); return (status); } #define STRINGIFY(n) #n static int dlpromiscon(pcap_t *p, bpf_u_int32 level) { struct pcap_dlpi *pd = p->priv; int retv; int err; retv = dlpi_promiscon(pd->dlpi_hd, level); if (retv != DLPI_SUCCESS) { if (retv == DL_SYSERR && (errno == EPERM || errno == EACCES)) { if (level == DL_PROMISC_PHYS) { err = PCAP_ERROR_PROMISC_PERM_DENIED; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Attempt to set promiscuous mode failed with %s - root privilege may be required", (errno == EPERM) ? "EPERM" : "EACCES"); } else { err = PCAP_ERROR_PERM_DENIED; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Attempt to set %s mode failed with %s - root privilege may be required", (level == DL_PROMISC_MULTI) ? "multicast" : "SAP promiscuous", (errno == EPERM) ? "EPERM" : "EACCES"); } } else { err = PCAP_ERROR; pcap_libdlpi_err(p->opt.device, "dlpi_promiscon" STRINGIFY(level), retv, p->errbuf); } return (err); } return (0); } /* * Presumably everything returned by dlpi_walk() is a DLPI device, * so there's no work to be done here to check whether name refers * to a DLPI device. */ static int is_dlpi_interface(const char *name _U_) { return (1); } static int get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) { /* * Nothing we can do other than mark loopback devices as "the * connected/disconnected status doesn't apply". * * XXX - on Solaris, can we do what the dladm command does, * i.e. get a connected/disconnected indication from a kstat? * (Note that you can also get the link speed, and possibly * other information, from a kstat as well.) */ if (*flags & PCAP_IF_LOOPBACK) { /* * Loopback devices aren't wireless, and "connected"/ * "disconnected" doesn't apply to them. */ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; return (0); } return (0); } /* * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find * network links that are plumbed and are up. dlpi_walk(3DLPI) will find * additional network links present in the system. */ int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { int retv = 0; linknamelist_t *entry, *next; linkwalk_t lw = {NULL, 0}; - int save_errno; + int save_errno; /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(devlistp, errbuf, is_dlpi_interface, get_if_flags) == -1) return (-1); /* failure */ /* dlpi_walk() for loopback will be added here. */ /* * Find all DLPI devices in the current zone. * * XXX - will pcap_findalldevs_interfaces() find any devices * outside the current zone? If not, the only reason to call * it would be to get the interface addresses. */ dlpi_walk(list_interfaces, &lw, 0); if (lw.lw_err != 0) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, lw.lw_err, "dlpi_walk"); retv = -1; goto done; } /* Add linkname if it does not exist on the list. */ for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { /* * If it isn't already in the list of devices, try to * add it. */ if (find_or_add_dev(devlistp, entry->linkname, 0, get_if_flags, NULL, errbuf) == NULL) retv = -1; } done: save_errno = errno; for (entry = lw.lw_list; entry != NULL; entry = next) { next = entry->lnl_next; free(entry); } errno = save_errno; return (retv); } /* * Read data received on DLPI handle. Returns -2 if told to terminate, else * returns the number of packets read. */ static int pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) { struct pcap_dlpi *pd = p->priv; int len; u_char *bufp; size_t msglen; int retv; len = p->cc; if (len != 0) { bufp = p->bp; goto process_pkts; } do { /* Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it has, * and return -2 to indicate that we were told to * break out of the loop. */ p->break_loop = 0; return (-2); } msglen = p->bufsize; bufp = (u_char *)p->buffer + p->offset; retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp, &msglen, -1, NULL); if (retv != DLPI_SUCCESS) { /* * This is most likely a call to terminate out of the * loop. So, do not return an error message, instead * check if "pcap_breakloop()" has been called above. */ if (retv == DL_SYSERR && errno == EINTR) { len = 0; continue; } pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_recv", retv, p->errbuf); return (-1); } len = msglen; } while (len == 0); process_pkts: return (pcap_process_pkts(p, callback, user, count, bufp, len)); } static int pcap_inject_libdlpi(pcap_t *p, const void *buf, int size) { struct pcap_dlpi *pd = p->priv; int retv; retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL); if (retv != DLPI_SUCCESS) { pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv, p->errbuf); return (-1); } /* * dlpi_send(3DLPI) does not provide a way to return the number of * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was * returned we are assuming 'size' bytes were sent. */ return (size); } /* * Close dlpi handle. */ static void pcap_cleanup_libdlpi(pcap_t *p) { struct pcap_dlpi *pd = p->priv; if (pd->dlpi_hd != NULL) { dlpi_close(pd->dlpi_hd); pd->dlpi_hd = NULL; p->fd = -1; } pcap_cleanup_live_common(p); } /* * Write error message to buffer. */ static void pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", func, linkname, dlpi_strerror(err)); } pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi); if (p == NULL) return (NULL); p->activate_op = pcap_activate_libdlpi; return (p); } /* * Libpcap version string. */ const char * pcap_lib_version(void) { return (PCAP_VERSION_STRING); } diff --git a/pcap-linux.c b/pcap-linux.c index 43d2a9f0eec6..13bd8529f65c 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -1,5587 +1,5587 @@ /* * pcap-linux.c: Packet capture interface to the Linux kernel * * Copyright (c) 2000 Torsten Landschoff - * Sebastian Krahmer + * Sebastian Krahmer * * License: BSD * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Modifications: Added PACKET_MMAP support * Paolo Abeni * Added TPACKET_V3 support * Gabor Tatarka * * based on previous works of: * Simon Patarin * Phil Wood * * Monitor-mode support for mac80211 includes code taken from the iw * command; the copyright notice for that code is * * Copyright (c) 2007, 2008 Johannes Berg * Copyright (c) 2007 Andy Lutomirski * Copyright (c) 2007 Mike Kershaw * Copyright (c) 2008 Gábor Stefanik * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #include "pcap/sll.h" #include "pcap/vlan.h" #include "pcap/can_socketcan.h" #include "diag-control.h" /* * We require TPACKET_V2 support. */ #ifndef TPACKET2_HDRLEN #error "Libpcap will only work if TPACKET_V2 is supported; you must build for a 2.6.27 or later kernel" #endif /* check for memory mapped access avaibility. We assume every needed * struct is defined if the macro TPACKET_HDRLEN is defined, because it * uses many ring related structs and macros */ #ifdef TPACKET3_HDRLEN # define HAVE_TPACKET3 #endif /* TPACKET3_HDRLEN */ /* * Not all compilers that are used to compile code to run on Linux have * these builtins. For example, older versions of GCC don't, and at * least some people are doing cross-builds for MIPS with older versions * of GCC. */ #ifndef HAVE___ATOMIC_LOAD_N #define __atomic_load_n(ptr, memory_model) (*(ptr)) #endif #ifndef HAVE___ATOMIC_STORE_N #define __atomic_store_n(ptr, val, memory_model) *(ptr) = (val) #endif #define packet_mmap_acquire(pkt) \ (__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) #define packet_mmap_release(pkt) \ (__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) #define packet_mmap_v3_acquire(pkt) \ (__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) #define packet_mmap_v3_release(pkt) \ (__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) #include #include #ifdef HAVE_LINUX_NET_TSTAMP_H #include #endif /* * For checking whether a device is a bonding device. */ #include /* * Got libnl? */ #ifdef HAVE_LIBNL #include #include #include #include #include #include #endif /* HAVE_LIBNL */ #ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif #define MAX_LINKHEADER_SIZE 256 /* * When capturing on all interfaces we use this as the buffer size. * Should be bigger then all MTUs that occur in real life. * 64kB should be enough for now. */ #define BIGGER_THAN_ALL_MTUS (64*1024) /* * Private data for capturing on Linux PF_PACKET sockets. */ struct pcap_linux { long long sysfs_dropped; /* packets reported dropped by /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors */ struct pcap_stat stat; char *device; /* device name */ int filter_in_userland; /* must filter in userland */ int blocks_to_filter_in_userland; int must_do_on_close; /* stuff we must do when we close */ int timeout; /* timeout for buffering */ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ int netdown; /* we got an ENETDOWN and haven't resolved it */ bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ char *mondevice; /* mac80211 monitor device we created */ u_char *mmapbuf; /* memory-mapped region pointer */ size_t mmapbuflen; /* size of region */ int vlan_offset; /* offset at which to insert vlan tags; if -1, don't insert */ u_int tp_version; /* version of tpacket_hdr for mmaped ring */ u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ u_char *oneshot_buffer; /* buffer for copy of packet */ int poll_timeout; /* timeout to use in poll() */ #ifdef HAVE_TPACKET3 unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */ int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */ #endif int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */ }; /* * Stuff to do when we close. */ #define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ #define MUST_DELETE_MONIF 0x00000002 /* delete monitor-mode interface */ /* * Prototypes for internal functions and methods. */ static int get_if_flags(const char *, bpf_u_int32 *, char *); static int is_wifi(const char *); static void map_arphrd_to_dlt(pcap_t *, int, const char *, int); static int pcap_activate_linux(pcap_t *); static int setup_socket(pcap_t *, int); static int setup_mmapped(pcap_t *, int *); static int pcap_can_set_rfmon_linux(pcap_t *); static int pcap_inject_linux(pcap_t *, const void *, int); static int pcap_stats_linux(pcap_t *, struct pcap_stat *); static int pcap_setfilter_linux(pcap_t *, struct bpf_program *); static int pcap_setdirection_linux(pcap_t *, pcap_direction_t); static int pcap_set_datalink_linux(pcap_t *, int); static void pcap_cleanup_linux(pcap_t *); union thdr { struct tpacket2_hdr *h2; #ifdef HAVE_TPACKET3 struct tpacket_block_desc *h3; #endif u_char *raw; }; #define RING_GET_FRAME_AT(h, offset) (((u_char **)h->buffer)[(offset)]) #define RING_GET_CURRENT_FRAME(h) RING_GET_FRAME_AT(h, h->offset) static void destroy_ring(pcap_t *handle); static int create_ring(pcap_t *handle, int *status); static int prepare_tpacket_socket(pcap_t *handle); static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *); #ifdef HAVE_TPACKET3 static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *); #endif static int pcap_setnonblock_linux(pcap_t *p, int nonblock); static int pcap_getnonblock_linux(pcap_t *p); static void pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes); /* * In pre-3.0 kernels, the tp_vlan_tci field is set to whatever the * vlan_tci field in the skbuff is. 0 can either mean "not on a VLAN" * or "on VLAN 0". There is no flag set in the tp_status field to * distinguish between them. * * In 3.0 and later kernels, if there's a VLAN tag present, the tp_vlan_tci * field is set to the VLAN tag, and the TP_STATUS_VLAN_VALID flag is set * in the tp_status field, otherwise the tp_vlan_tci field is set to 0 and * the TP_STATUS_VLAN_VALID flag isn't set in the tp_status field. * * With a pre-3.0 kernel, we cannot distinguish between packets with no * VLAN tag and packets on VLAN 0, so we will mishandle some packets, and * there's nothing we can do about that. * * So, on those systems, which never set the TP_STATUS_VLAN_VALID flag, we * continue the behavior of earlier libpcaps, wherein we treated packets * with a VLAN tag of 0 as being packets without a VLAN tag rather than packets * on VLAN 0. We do this by treating packets with a tp_vlan_tci of 0 and * with the TP_STATUS_VLAN_VALID flag not set in tp_status as not having * VLAN tags. This does the right thing on 3.0 and later kernels, and * continues the old unfixably-imperfect behavior on pre-3.0 kernels. * * If TP_STATUS_VLAN_VALID isn't defined, we test it as the 0x10 bit; it * has that value in 3.0 and later kernels. */ #ifdef TP_STATUS_VLAN_VALID #define VLAN_VALID(hdr, hv) ((hv)->tp_vlan_tci != 0 || ((hdr)->tp_status & TP_STATUS_VLAN_VALID)) #else /* * This is being compiled on a system that lacks TP_STATUS_VLAN_VALID, * so we testwith the value it has in the 3.0 and later kernels, so * we can test it if we're running on a system that has it. (If we're * running on a system that doesn't have it, it won't be set in the * tp_status field, so the tests of it will always fail; that means * we behave the way we did before we introduced this macro.) */ #define VLAN_VALID(hdr, hv) ((hv)->tp_vlan_tci != 0 || ((hdr)->tp_status & 0x10)) #endif #ifdef TP_STATUS_VLAN_TPID_VALID # define VLAN_TPID(hdr, hv) (((hv)->tp_vlan_tpid || ((hdr)->tp_status & TP_STATUS_VLAN_TPID_VALID)) ? (hv)->tp_vlan_tpid : ETH_P_8021Q) #else # define VLAN_TPID(hdr, hv) ETH_P_8021Q #endif /* * Required select timeout if we're polling for an "interface disappeared" * indication - 1 millisecond. */ static const struct timeval netdown_timeout = { 0, 1000 /* 1000 microseconds = 1 millisecond */ }; /* * Wrap some ioctl calls */ static int iface_get_id(int fd, const char *device, char *ebuf); static int iface_get_mtu(int fd, const char *device, char *ebuf); -static int iface_get_arptype(int fd, const char *device, char *ebuf); -static int iface_bind(int fd, int ifindex, char *ebuf, int protocol); +static int iface_get_arptype(int fd, const char *device, char *ebuf); +static int iface_bind(int fd, int ifindex, char *ebuf, int protocol); static int enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device); static int iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf); static int iface_get_offload(pcap_t *handle); static int fix_program(pcap_t *handle, struct sock_fprog *fcode); static int fix_offset(pcap_t *handle, struct bpf_insn *p); static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode); static int reset_kernel_filter(pcap_t *handle); static struct sock_filter total_insn = BPF_STMT(BPF_RET | BPF_K, 0); static struct sock_fprog total_fcode = { 1, &total_insn }; static int iface_dsa_get_proto_info(const char *device, pcap_t *handle); pcap_t * pcap_create_interface(const char *device, char *ebuf) { pcap_t *handle; handle = PCAP_CREATE_COMMON(ebuf, struct pcap_linux); if (handle == NULL) return NULL; handle->activate_op = pcap_activate_linux; handle->can_set_rfmon_op = pcap_can_set_rfmon_linux; /* * See what time stamp types we support. */ if (iface_get_ts_types(device, handle, ebuf) == -1) { pcap_close(handle); return NULL; } /* * We claim that we support microsecond and nanosecond time * stamps. * * XXX - with adapter-supplied time stamps, can we choose * microsecond or nanosecond time stamps on arbitrary * adapters? */ handle->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (handle->tstamp_precision_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); pcap_close(handle); return NULL; } handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; handle->tstamp_precision_count = 2; struct pcap_linux *handlep = handle->priv; handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK); return handle; } #ifdef HAVE_LIBNL /* * If interface {if_name} is a mac80211 driver, the file * /sys/class/net/{if_name}/phy80211 is a symlink to * /sys/class/ieee80211/{phydev_name}, for some {phydev_name}. * * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at * least, has a "wmaster0" device and a "wlan0" device; the * latter is the one with the IP address. Both show up in * "tcpdump -D" output. Capturing on the wmaster0 device * captures with 802.11 headers. * * airmon-ng searches through /sys/class/net for devices named * monN, starting with mon0; as soon as one *doesn't* exist, * it chooses that as the monitor device name. If the "iw" * command exists, it does * * iw dev {if_name} interface add {monif_name} type monitor * * where {monif_name} is the monitor device. It then (sigh) sleeps * .1 second, and then configures the device up. Otherwise, if * /sys/class/ieee80211/{phydev_name}/add_iface is a file, it writes * {mondev_name}, without a newline, to that file, and again (sigh) * sleeps .1 second, and then iwconfig's that device into monitor * mode and configures it up. Otherwise, you can't do monitor mode. * * All these devices are "glued" together by having the * /sys/class/net/{if_name}/phy80211 links pointing to the same * place, so, given a wmaster, wlan, or mon device, you can * find the other devices by looking for devices with * the same phy80211 link. * * To turn monitor mode off, delete the monitor interface, * either with * * iw dev {monif_name} interface del * * or by sending {monif_name}, with no NL, down * /sys/class/ieee80211/{phydev_name}/remove_iface * * Note: if you try to create a monitor device named "monN", and * there's already a "monN" device, it fails, as least with * the netlink interface (which is what iw uses), with a return * value of -ENFILE. (Return values are negative errnos.) We * could probably use that to find an unused device. * * Yes, you can have multiple monitor devices for a given * physical device. */ /* * Is this a mac80211 device? If so, fill in the physical device path and * return 1; if not, return 0. On an error, fill in handle->errbuf and * return PCAP_ERROR. */ static int get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path, size_t phydev_max_pathlen) { char *pathstr; ssize_t bytes_read; /* * Generate the path string for the symlink to the physical device. */ if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: Can't generate path name string for /sys/class/net device", device); return PCAP_ERROR; } bytes_read = readlink(pathstr, phydev_path, phydev_max_pathlen); if (bytes_read == -1) { if (errno == ENOENT || errno == EINVAL) { /* * Doesn't exist, or not a symlink; assume that * means it's not a mac80211 device. */ free(pathstr); return 0; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't readlink %s", device, pathstr); free(pathstr); return PCAP_ERROR; } free(pathstr); phydev_path[bytes_read] = '\0'; return 1; } struct nl80211_state { struct nl_sock *nl_sock; struct nl_cache *nl_cache; struct genl_family *nl80211; }; static int nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device) { int err; state->nl_sock = nl_socket_alloc(); if (!state->nl_sock) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink handle", device); return PCAP_ERROR; } if (genl_connect(state->nl_sock)) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to connect to generic netlink", device); goto out_handle_destroy; } err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache); if (err < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate generic netlink cache: %s", device, nl_geterror(-err)); goto out_handle_destroy; } state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); if (!state->nl80211) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl80211 not found", device); goto out_cache_free; } return 0; out_cache_free: nl_cache_free(state->nl_cache); out_handle_destroy: nl_socket_free(state->nl_sock); return PCAP_ERROR; } static void nl80211_cleanup(struct nl80211_state *state) { genl_family_put(state->nl80211); nl_cache_free(state->nl_cache); nl_socket_free(state->nl_sock); } static int del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice); static int add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice) { struct pcap_linux *handlep = handle->priv; int ifindex; struct nl_msg *msg; int err; ifindex = iface_get_id(sock_fd, device, handle->errbuf); if (ifindex == -1) return PCAP_ERROR; msg = nlmsg_alloc(); if (!msg) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink msg", device); return PCAP_ERROR; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); DIAG_OFF_NARROWING NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice); DIAG_ON_NARROWING NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) { if (err == -NLE_FAILURE) { /* * Device not available; our caller should just * keep trying. (libnl 2.x maps ENFILE to * NLE_FAILURE; it can also map other errors * to that, but there's not much we can do * about that.) */ nlmsg_free(msg); return 0; } else { /* * Real failure, not just "that device is not * available. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_send_auto_complete failed adding %s interface: %s", device, mondevice, nl_geterror(-err)); nlmsg_free(msg); return PCAP_ERROR; } } err = nl_wait_for_ack(state->nl_sock); if (err < 0) { if (err == -NLE_FAILURE) { /* * Device not available; our caller should just * keep trying. (libnl 2.x maps ENFILE to * NLE_FAILURE; it can also map other errors * to that, but there's not much we can do * about that.) */ nlmsg_free(msg); return 0; } else { /* * Real failure, not just "that device is not * available. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_wait_for_ack failed adding %s interface: %s", device, mondevice, nl_geterror(-err)); nlmsg_free(msg); return PCAP_ERROR; } } /* * Success. */ nlmsg_free(msg); /* * Try to remember the monitor device. */ handlep->mondevice = strdup(mondevice); if (handlep->mondevice == NULL) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "strdup"); /* * Get rid of the monitor device. */ del_mon_if(handle, sock_fd, state, device, mondevice); return PCAP_ERROR; } return 1; nla_put_failure: snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_put failed adding %s interface", device, mondevice); nlmsg_free(msg); return PCAP_ERROR; } static int del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, const char *device, const char *mondevice) { int ifindex; struct nl_msg *msg; int err; ifindex = iface_get_id(sock_fd, mondevice, handle->errbuf); if (ifindex == -1) return PCAP_ERROR; msg = nlmsg_alloc(); if (!msg) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: failed to allocate netlink msg", device); return PCAP_ERROR; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_DEL_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_send_auto_complete failed deleting %s interface: %s", device, mondevice, nl_geterror(-err)); nlmsg_free(msg); return PCAP_ERROR; } err = nl_wait_for_ack(state->nl_sock); if (err < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_wait_for_ack failed adding %s interface: %s", device, mondevice, nl_geterror(-err)); nlmsg_free(msg); return PCAP_ERROR; } /* * Success. */ nlmsg_free(msg); return 1; nla_put_failure: snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: nl_put failed deleting %s interface", device, mondevice); nlmsg_free(msg); return PCAP_ERROR; } #endif /* HAVE_LIBNL */ static int pcap_protocol(pcap_t *handle) { int protocol; protocol = handle->opt.protocol; if (protocol == 0) protocol = ETH_P_ALL; return htons(protocol); } static int pcap_can_set_rfmon_linux(pcap_t *handle) { #ifdef HAVE_LIBNL char phydev_path[PATH_MAX+1]; int ret; #endif if (strcmp(handle->opt.device, "any") == 0) { /* * Monitor mode makes no sense on the "any" device. */ return 0; } #ifdef HAVE_LIBNL /* * Bleah. There doesn't seem to be a way to ask a mac80211 * device, through libnl, whether it supports monitor mode; * we'll just check whether the device appears to be a * mac80211 device and, if so, assume the device supports * monitor mode. */ ret = get_mac80211_phydev(handle, handle->opt.device, phydev_path, PATH_MAX); if (ret < 0) return ret; /* error */ if (ret == 1) return 1; /* mac80211 device */ #endif return 0; } /* * Grabs the number of missed packets by the interface from * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors. * * Compared to /proc/net/dev this avoids counting software drops, * but may be unimplemented and just return 0. * The author has found no straigthforward way to check for support. */ static long long int linux_get_stat(const char * if_name, const char * stat) { ssize_t bytes_read; int fd; char buffer[PATH_MAX]; snprintf(buffer, sizeof(buffer), "/sys/class/net/%s/statistics/%s", if_name, stat); fd = open(buffer, O_RDONLY); if (fd == -1) return 0; bytes_read = read(fd, buffer, sizeof(buffer) - 1); close(fd); if (bytes_read == -1) return 0; buffer[bytes_read] = '\0'; return strtoll(buffer, NULL, 10); } static long long int linux_if_drops(const char * if_name) { long long int missed = linux_get_stat(if_name, "rx_missed_errors"); long long int fifo = linux_get_stat(if_name, "rx_fifo_errors"); return missed + fifo; } /* * Monitor mode is kind of interesting because we have to reset the * interface before exiting. The problem can't really be solved without * some daemon taking care of managing usage counts. If we put the * interface into monitor mode, we set a flag indicating that we must * take it out of that mode when the interface is closed, and, when * closing the interface, if that flag is set we take it out of monitor * mode. */ static void pcap_cleanup_linux( pcap_t *handle ) { struct pcap_linux *handlep = handle->priv; #ifdef HAVE_LIBNL struct nl80211_state nlstate; int ret; #endif /* HAVE_LIBNL */ if (handlep->must_do_on_close != 0) { /* * There's something we have to do when closing this * pcap_t. */ #ifdef HAVE_LIBNL if (handlep->must_do_on_close & MUST_DELETE_MONIF) { ret = nl80211_init(handle, &nlstate, handlep->device); if (ret >= 0) { ret = del_mon_if(handle, handle->fd, &nlstate, handlep->device, handlep->mondevice); nl80211_cleanup(&nlstate); } if (ret < 0) { fprintf(stderr, "Can't delete monitor interface %s (%s).\n" "Please delete manually.\n", handlep->mondevice, handle->errbuf); } } #endif /* HAVE_LIBNL */ /* * Take this pcap out of the list of pcaps for which we * have to take the interface out of some mode. */ pcap_remove_from_pcaps_to_close(handle); } if (handle->fd != -1) { /* * Destroy the ring buffer (assuming we've set it up), * and unmap it if it's mapped. */ destroy_ring(handle); } if (handlep->oneshot_buffer != NULL) { free(handlep->oneshot_buffer); handlep->oneshot_buffer = NULL; } if (handlep->mondevice != NULL) { free(handlep->mondevice); handlep->mondevice = NULL; } if (handlep->device != NULL) { free(handlep->device); handlep->device = NULL; } if (handlep->poll_breakloop_fd != -1) { close(handlep->poll_breakloop_fd); handlep->poll_breakloop_fd = -1; } pcap_cleanup_live_common(handle); } #ifdef HAVE_TPACKET3 /* * Some versions of TPACKET_V3 have annoying bugs/misfeatures * around which we have to work. Determine if we have those * problems or not. * 3.19 is the first release with a fixed version of * TPACKET_V3. We treat anything before that as * not having a fixed version; that may really mean * it has *no* version. */ static int has_broken_tpacket_v3(void) { struct utsname utsname; const char *release; long major, minor; int matches, verlen; /* No version information, assume broken. */ if (uname(&utsname) == -1) return 1; release = utsname.release; /* A malformed version, ditto. */ matches = sscanf(release, "%ld.%ld%n", &major, &minor, &verlen); if (matches != 2) return 1; if (release[verlen] != '.' && release[verlen] != '\0') return 1; /* OK, a fixed version. */ if (major > 3 || (major == 3 && minor >= 19)) return 0; /* Too old :( */ return 1; } #endif /* * Set the timeout to be used in poll() with memory-mapped packet capture. */ static void set_poll_timeout(struct pcap_linux *handlep) { #ifdef HAVE_TPACKET3 int broken_tpacket_v3 = has_broken_tpacket_v3(); #endif if (handlep->timeout == 0) { #ifdef HAVE_TPACKET3 /* * XXX - due to a set of (mis)features in the TPACKET_V3 * kernel code prior to the 3.19 kernel, blocking forever * with a TPACKET_V3 socket can, if few packets are * arriving and passing the socket filter, cause most * packets to be dropped. See libpcap issue #335 for the * full painful story. * * The workaround is to have poll() time out very quickly, * so we grab the frames handed to us, and return them to * the kernel, ASAP. */ if (handlep->tp_version == TPACKET_V3 && broken_tpacket_v3) handlep->poll_timeout = 1; /* don't block for very long */ else #endif handlep->poll_timeout = -1; /* block forever */ } else if (handlep->timeout > 0) { #ifdef HAVE_TPACKET3 /* * For TPACKET_V3, the timeout is handled by the kernel, * so block forever; that way, we don't get extra timeouts. * Don't do that if we have a broken TPACKET_V3, though. */ if (handlep->tp_version == TPACKET_V3 && !broken_tpacket_v3) handlep->poll_timeout = -1; /* block forever, let TPACKET_V3 wake us up */ else #endif handlep->poll_timeout = handlep->timeout; /* block for that amount of time */ } else { /* * Non-blocking mode; we call poll() to pick up error * indications, but we don't want it to wait for * anything. */ handlep->poll_timeout = 0; } } static void pcap_breakloop_linux(pcap_t *handle) { pcap_breakloop_common(handle); struct pcap_linux *handlep = handle->priv; uint64_t value = 1; /* XXX - what if this fails? */ if (handlep->poll_breakloop_fd != -1) (void)write(handlep->poll_breakloop_fd, &value, sizeof(value)); } /* * Set the offset at which to insert VLAN tags. * That should be the offset of the type field. */ static void set_vlan_offset(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; switch (handle->linktype) { case DLT_EN10MB: /* * The type field is after the destination and source * MAC address. */ handlep->vlan_offset = 2 * ETH_ALEN; break; case DLT_LINUX_SLL: /* * The type field is in the last 2 bytes of the * DLT_LINUX_SLL header. */ handlep->vlan_offset = SLL_HDR_LEN - 2; break; default: handlep->vlan_offset = -1; /* unknown */ break; } } /* * Get a handle for a live capture from the given device. You can * pass NULL as device to get all packages (without link level * information of course). If you pass 1 as promisc the interface * will be set to promiscuous mode (XXX: I think this usage should * be deprecated and functions be added to select that later allow * modification of that values -- Torsten). */ static int pcap_activate_linux(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; const char *device; int is_any_device; struct ifreq ifr; int status = 0; int status2 = 0; int ret; device = handle->opt.device; /* * Make sure the name we were handed will fit into the ioctls we * might perform on the device; if not, return a "No such device" * indication, as the Linux kernel shouldn't support creating * a device whose name won't fit into those ioctls. * * "Will fit" means "will fit, complete with a null terminator", * so if the length, which does *not* include the null terminator, * is greater than *or equal to* the size of the field into which * we'll be copying it, that won't fit. */ if (strlen(device) >= sizeof(ifr.ifr_name)) { /* * There's nothing more to say, so clear the error * message. */ handle->errbuf[0] = '\0'; status = PCAP_ERROR_NO_SUCH_DEVICE; goto fail; } /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) handle->snapshot = MAXIMUM_SNAPLEN; handlep->device = strdup(device); if (handlep->device == NULL) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "strdup"); status = PCAP_ERROR; goto fail; } /* * The "any" device is a special device which causes us not * to bind to a particular device and thus to look at all * devices. */ is_any_device = (strcmp(device, "any") == 0); if (is_any_device) { if (handle->opt.promisc) { handle->opt.promisc = 0; /* Just a warning. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Promiscuous mode not supported on the \"any\" device"); status = PCAP_WARNING_PROMISC_NOTSUP; } } /* copy timeout value */ handlep->timeout = handle->opt.timeout; /* * If we're in promiscuous mode, then we probably want * to see when the interface drops packets too, so get an * initial count from * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors */ if (handle->opt.promisc) handlep->sysfs_dropped = linux_if_drops(handlep->device); /* * If the "any" device is specified, try to open a SOCK_DGRAM. * Otherwise, open a SOCK_RAW. */ ret = setup_socket(handle, is_any_device); if (ret < 0) { /* * Fatal error; the return value is the error code, * and handle->errbuf has been set to an appropriate * error message. */ status = ret; goto fail; } /* * Success. * Try to set up memory-mapped access. */ ret = setup_mmapped(handle, &status); if (ret == -1) { /* * We failed to set up to use it, or the * kernel supports it, but we failed to * enable it. status has been set to the * error status to return and, if it's * PCAP_ERROR, handle->errbuf contains * the error message. */ goto fail; } /* * We succeeded. status has been set to the status to return, * which might be 0, or might be a PCAP_WARNING_ value. */ /* * Now that we have activated the mmap ring, we can * set the correct protocol. */ if ((status2 = iface_bind(handle->fd, handlep->ifindex, handle->errbuf, pcap_protocol(handle))) != 0) { status = status2; goto fail; } handle->inject_op = pcap_inject_linux; handle->setfilter_op = pcap_setfilter_linux; handle->setdirection_op = pcap_setdirection_linux; handle->set_datalink_op = pcap_set_datalink_linux; handle->setnonblock_op = pcap_setnonblock_linux; handle->getnonblock_op = pcap_getnonblock_linux; handle->cleanup_op = pcap_cleanup_linux; handle->stats_op = pcap_stats_linux; handle->breakloop_op = pcap_breakloop_linux; switch (handlep->tp_version) { case TPACKET_V2: handle->read_op = pcap_read_linux_mmap_v2; break; #ifdef HAVE_TPACKET3 case TPACKET_V3: handle->read_op = pcap_read_linux_mmap_v3; break; #endif } handle->oneshot_callback = pcap_oneshot_linux; handle->selectable_fd = handle->fd; return status; fail: pcap_cleanup_linux(handle); return status; } static int pcap_set_datalink_linux(pcap_t *handle, int dlt) { handle->linktype = dlt; /* * Update the offset at which to insert VLAN tags for the * new link-layer type. */ set_vlan_offset(handle); return 0; } /* * linux_check_direction() * * Do checks based on packet direction. */ static inline int linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll) { struct pcap_linux *handlep = handle->priv; if (sll->sll_pkttype == PACKET_OUTGOING) { /* * Outgoing packet. * If this is from the loopback device, reject it; * we'll see the packet as an incoming packet as well, * and we don't want to see it twice. */ if (sll->sll_ifindex == handlep->lo_ifindex) return 0; /* * If this is an outgoing CAN or CAN FD frame, and * the user doesn't only want outgoing packets, * reject it; CAN devices and drivers, and the CAN * stack, always arrange to loop back transmitted * packets, so they also appear as incoming packets. * We don't want duplicate packets, and we can't * easily distinguish packets looped back by the CAN * layer than those received by the CAN layer, so we * eliminate this packet instead. * * We check whether this is a CAN or CAN FD frame * by checking whether the device's hardware type * is ARPHRD_CAN. */ if (sll->sll_hatype == ARPHRD_CAN && handle->direction != PCAP_D_OUT) return 0; /* * If the user only wants incoming packets, reject it. */ if (handle->direction == PCAP_D_IN) return 0; } else { /* * Incoming packet. * If the user only wants outgoing packets, reject it. */ if (handle->direction == PCAP_D_OUT) return 0; } return 1; } /* * Check whether the device to which the pcap_t is bound still exists. * We do so by asking what address the socket is bound to, and checking * whether the ifindex in the address is -1, meaning "that device is gone", * or some other value, meaning "that device still exists". */ static int device_still_exists(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; struct sockaddr_ll addr; socklen_t addr_len; /* * If handlep->ifindex is -1, the socket isn't bound, meaning * we're capturing on the "any" device; that device never * disappears. (It should also never be configured down, so * we shouldn't even get here, but let's make sure.) */ if (handlep->ifindex == -1) return (1); /* it's still here */ /* * OK, now try to get the address for the socket. */ addr_len = sizeof (addr); if (getsockname(handle->fd, (struct sockaddr *) &addr, &addr_len) == -1) { /* * Error - report an error and return -1. */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "getsockname failed"); return (-1); } if (addr.sll_ifindex == -1) { /* * This means the device went away. */ return (0); } /* * The device presumably just went down. */ return (1); } static int pcap_inject_linux(pcap_t *handle, const void *buf, int size) { struct pcap_linux *handlep = handle->priv; int ret; if (handlep->ifindex == -1) { /* * We don't support sending on the "any" device. */ pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on the \"any\" device", PCAP_ERRBUF_SIZE); return (-1); } if (handlep->cooked) { /* * We don't support sending on cooked-mode sockets. * * XXX - how do you send on a bound cooked-mode * socket? * Is a "sendto()" required there? */ pcap_strlcpy(handle->errbuf, "Sending packets isn't supported in cooked mode", PCAP_ERRBUF_SIZE); return (-1); } ret = (int)send(handle->fd, buf, size, 0); if (ret == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "send"); return (-1); } return (ret); } /* * Get the statistics for the given packet capture handle. */ static int pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_linux *handlep = handle->priv; #ifdef HAVE_TPACKET3 /* * For sockets using TPACKET_V2, the extra stuff at the end * of a struct tpacket_stats_v3 will not be filled in, and * we don't look at it so this is OK even for those sockets. * In addition, the PF_PACKET socket code in the kernel only * uses the length parameter to compute how much data to * copy out and to indicate how much data was copied out, so * it's OK to base it on the size of a struct tpacket_stats. * * XXX - it's probably OK, in fact, to just use a * struct tpacket_stats for V3 sockets, as we don't * care about the tp_freeze_q_cnt stat. */ struct tpacket_stats_v3 kstats; #else /* HAVE_TPACKET3 */ struct tpacket_stats kstats; #endif /* HAVE_TPACKET3 */ socklen_t len = sizeof (struct tpacket_stats); long long if_dropped = 0; /* * To fill in ps_ifdrop, we parse * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors * for the numbers */ if (handle->opt.promisc) { /* * XXX - is there any reason to do this by remembering * the last counts value, subtracting it from the * current counts value, and adding that to stat.ps_ifdrop, * maintaining stat.ps_ifdrop as a count, rather than just * saving the *initial* counts value and setting * stat.ps_ifdrop to the difference between the current * value and the initial value? * * One reason might be to handle the count wrapping * around, on platforms where the count is 32 bits * and where you might get more than 2^32 dropped * packets; is there any other reason? * * (We maintain the count as a long long int so that, * if the kernel maintains the counts as 64-bit even * on 32-bit platforms, we can handle the real count. * * Unfortunately, we can't report 64-bit counts; we * need a better API for reporting statistics, such as * one that reports them in a style similar to the * pcapng Interface Statistics Block, so that 1) the * counts are 64-bit, 2) it's easier to add new statistics * without breaking the ABI, and 3) it's easier to * indicate to a caller that wants one particular * statistic that it's not available by just not supplying * it.) */ if_dropped = handlep->sysfs_dropped; handlep->sysfs_dropped = linux_if_drops(handlep->device); handlep->stat.ps_ifdrop += (u_int)(handlep->sysfs_dropped - if_dropped); } /* * Try to get the packet counts from the kernel. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { /* * "ps_recv" counts only packets that *passed* the * filter, not packets that didn't pass the filter. * This includes packets later dropped because we * ran out of buffer space. * * "ps_drop" counts packets dropped because we ran * out of buffer space. It doesn't count packets * dropped by the interface driver. It counts only * packets that passed the filter. * * See above for ps_ifdrop. * * Both statistics include packets not yet read from * the kernel by libpcap, and thus not yet seen by * the application. * * In "linux/net/packet/af_packet.c", at least in 2.6.27 * through 5.6 kernels, "tp_packets" is incremented for * every packet that passes the packet filter *and* is * successfully copied to the ring buffer; "tp_drops" is * incremented for every packet dropped because there's * not enough free space in the ring buffer. * * When the statistics are returned for a PACKET_STATISTICS * "getsockopt()" call, "tp_drops" is added to "tp_packets", * so that "tp_packets" counts all packets handed to * the PF_PACKET socket, including packets dropped because * there wasn't room on the socket buffer - but not * including packets that didn't pass the filter. * * In the BSD BPF, the count of received packets is * incremented for every packet handed to BPF, regardless * of whether it passed the filter. * * We can't make "pcap_stats()" work the same on both * platforms, but the best approximation is to return * "tp_packets" as the count of packets and "tp_drops" * as the count of drops. * * Keep a running total because each call to * getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, .... * resets the counters to zero. */ handlep->stat.ps_recv += kstats.tp_packets; handlep->stat.ps_drop += kstats.tp_drops; *stats = handlep->stat; return 0; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "failed to get statistics from socket"); return -1; } /* * Description string for the "any" device. */ static const char any_descr[] = "Pseudo-device that captures on all interfaces"; /* * A PF_PACKET socket can be bound to any network interface. */ static int can_be_bound(const char *name _U_) { return (1); } /* * Get a socket to use with various interface ioctls. */ static int get_if_ioctl_socket(void) { int fd; /* * This is a bit ugly. * * There isn't a socket type that's guaranteed to work. * * AF_NETLINK will work *if* you have Netlink configured into the * kernel (can it be configured out if you have any networking * support at all?) *and* if you're running a sufficiently recent * kernel, but not all the kernels we support are sufficiently * recent - that feature was introduced in Linux 4.6. * * AF_UNIX will work *if* you have UNIX-domain sockets configured * into the kernel and *if* you're not on a system that doesn't * allow them - some SELinux systems don't allow you create them. * Most systems probably have them configured in, but not all systems * have them configured in and allow them to be created. * * AF_INET will work *if* you have IPv4 configured into the kernel, * but, apparently, some systems have network adapters but have * kernels without IPv4 support. * * AF_INET6 will work *if* you have IPv6 configured into the * kernel, but if you don't have AF_INET, you might not have * AF_INET6, either (that is, independently on its own grounds). * * AF_PACKET would work, except that some of these calls should * work even if you *don't* have capture permission (you should be * able to enumerate interfaces and get information about them * without capture permission; you shouldn't get a failure until * you try pcap_activate()). (If you don't allow programs to * get as much information as possible about interfaces if you * don't have permission to capture, you run the risk of users * asking "why isn't it showing XXX" - or, worse, if you don't * show interfaces *at all* if you don't have permission to * capture on them, "why do no interfaces show up?" - when the * real problem is a permissions problem. Error reports of that * type require a lot more back-and-forth to debug, as evidenced * by many Wireshark bugs/mailing list questions/Q&A questions.) * * So: * * we first try an AF_NETLINK socket, where "try" includes * "try to do a device ioctl on it", as, in the future, once * pre-4.6 kernels are sufficiently rare, that will probably * be the mechanism most likely to work; * * if that fails, we try an AF_UNIX socket, as that's less * likely to be configured out on a networking-capable system * than is IP; * * if that fails, we try an AF_INET6 socket; * * if that fails, we try an AF_INET socket. */ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (fd != -1) { /* * OK, let's make sure we can do an SIOCGIFNAME * ioctl. */ struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); if (ioctl(fd, SIOCGIFNAME, &ifr) == 0 || errno != EOPNOTSUPP) { /* * It succeeded, or failed for some reason * other than "netlink sockets don't support * device ioctls". Go with the AF_NETLINK * socket. */ return (fd); } /* * OK, that didn't work, so it's as bad as "netlink * sockets aren't available". Close the socket and * drive on. */ close(fd); } /* * Now try an AF_UNIX socket. */ fd = socket(AF_UNIX, SOCK_RAW, 0); if (fd != -1) { /* * OK, we got it! */ return (fd); } /* * Now try an AF_INET6 socket. */ fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd != -1) { return (fd); } /* * Now try an AF_INET socket. * * XXX - if that fails, is there anything else we should try? * AF_CAN, for embedded systems in vehicles, in case they're * built without Internet protocol support? Any other socket * types popular in non-Internet embedded systems? */ return (socket(AF_INET, SOCK_DGRAM, 0)); } /* * Get additional flags for a device, using SIOCGIFMEDIA. */ static int get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) { int sock; FILE *fh; unsigned int arptype; struct ifreq ifr; struct ethtool_value info; if (*flags & PCAP_IF_LOOPBACK) { /* * Loopback devices aren't wireless, and "connected"/ * "disconnected" doesn't apply to them. */ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; return 0; } sock = get_if_ioctl_socket(); if (sock == -1) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "Can't create socket to get ethtool information for %s", name); return -1; } /* * OK, what type of network is this? * In particular, is it wired or wireless? */ if (is_wifi(name)) { /* * Wi-Fi, hence wireless. */ *flags |= PCAP_IF_WIRELESS; } else { /* * OK, what does /sys/class/net/{if_name}/type contain? * (We don't use that for Wi-Fi, as it'll report * "Ethernet", i.e. ARPHRD_ETHER, for non-monitor- * mode devices.) */ char *pathstr; if (asprintf(&pathstr, "/sys/class/net/%s/type", name) == -1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: Can't generate path name string for /sys/class/net device", name); close(sock); return -1; } fh = fopen(pathstr, "r"); if (fh != NULL) { if (fscanf(fh, "%u", &arptype) == 1) { /* * OK, we got an ARPHRD_ type; what is it? */ switch (arptype) { case ARPHRD_LOOPBACK: /* * These are types to which * "connected" and "disconnected" * don't apply, so don't bother * asking about it. * * XXX - add other types? */ close(sock); fclose(fh); free(pathstr); return 0; case ARPHRD_IRDA: case ARPHRD_IEEE80211: case ARPHRD_IEEE80211_PRISM: case ARPHRD_IEEE80211_RADIOTAP: #ifdef ARPHRD_IEEE802154 case ARPHRD_IEEE802154: #endif #ifdef ARPHRD_IEEE802154_MONITOR case ARPHRD_IEEE802154_MONITOR: #endif #ifdef ARPHRD_6LOWPAN case ARPHRD_6LOWPAN: #endif /* * Various wireless types. */ *flags |= PCAP_IF_WIRELESS; break; } } fclose(fh); } free(pathstr); } #ifdef ETHTOOL_GLINK memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); info.cmd = ETHTOOL_GLINK; /* * XXX - while Valgrind handles SIOCETHTOOL and knows that * the ETHTOOL_GLINK command sets the .data member of the * structure, Memory Sanitizer doesn't yet do so: * * https://bugs.llvm.org/show_bug.cgi?id=45814 * * For now, we zero it out to squelch warnings; if the bug * in question is fixed, we can remove this. */ info.data = 0; ifr.ifr_data = (caddr_t)&info; if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) { int save_errno = errno; switch (save_errno) { case EOPNOTSUPP: case EINVAL: /* * OK, this OS version or driver doesn't support * asking for this information. * XXX - distinguish between "this doesn't * support ethtool at all because it's not * that type of device" vs. "this doesn't * support ethtool even though it's that * type of device", and return "unknown". */ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; close(sock); return 0; case ENODEV: /* * OK, no such device. * The user will find that out when they try to * activate the device; just say "OK" and * don't set anything. */ close(sock); return 0; default: /* * Other error. */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, save_errno, "%s: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed", name); close(sock); return -1; } } /* * Is it connected? */ if (info.data) { /* * It's connected. */ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; } else { /* * It's disconnected. */ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; } #endif close(sock); return 0; } int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { /* * Get the list of regular interfaces first. */ if (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound, get_if_flags) == -1) return (-1); /* failure */ /* * Add the "any" device. * As it refers to all network devices, not to any particular * network device, the notion of "connected" vs. "disconnected" * doesn't apply. */ if (add_dev(devlistp, "any", PCAP_IF_UP|PCAP_IF_RUNNING|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, any_descr, errbuf) == NULL) return (-1); return (0); } /* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ static int pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) { /* * It's guaranteed, at this point, that d is a valid * direction value. */ handle->direction = d; return 0; } static int is_wifi(const char *device) { char *pathstr; struct stat statb; /* * See if there's a sysfs wireless directory for it. * If so, it's a wireless interface. */ if (asprintf(&pathstr, "/sys/class/net/%s/wireless", device) == -1) { /* * Just give up here. */ return 0; } if (stat(pathstr, &statb) == 0) { free(pathstr); return 1; } free(pathstr); return 0; } /* * Linux uses the ARP hardware type to identify the type of an * interface. pcap uses the DLT_xxx constants for this. This * function takes a pointer to a "pcap_t", and an ARPHRD_xxx * constant, as arguments, and sets "handle->linktype" to the * appropriate DLT_XXX constant and sets "handle->offset" to * the appropriate value (to make "handle->offset" plus link-layer * header length be a multiple of 4, so that the link-layer payload * will be aligned on a 4-byte boundary when capturing packets). * (If the offset isn't set here, it'll be 0; add code as appropriate * for cases where it shouldn't be 0.) * * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture * in cooked mode; otherwise, we can't use cooked mode, so we have * to pick some type that works in raw mode, or fail. * * Sets the link type to -1 if unable to map the type. */ static void map_arphrd_to_dlt(pcap_t *handle, int arptype, const char *device, int cooked_ok) { static const char cdma_rmnet[] = "cdma_rmnet"; switch (arptype) { case ARPHRD_ETHER: /* * For various annoying reasons having to do with DHCP * software, some versions of Android give the mobile- * phone-network interface an ARPHRD_ value of * ARPHRD_ETHER, even though the packets supplied by * that interface have no link-layer header, and begin * with an IP header, so that the ARPHRD_ value should * be ARPHRD_NONE. * * Detect those devices by checking the device name, and * use DLT_RAW for them. */ if (strncmp(device, cdma_rmnet, sizeof cdma_rmnet - 1) == 0) { handle->linktype = DLT_RAW; return; } /* * Is this a real Ethernet device? If so, give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). * * XXX - are there any other sorts of "fake Ethernet" that * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as * a Cisco CMTS won't put traffic onto it or get traffic * bridged onto it? ISDN is handled in "setup_socket()", * as we fall back on cooked mode there, and we use * is_wifi() to check for 802.11 devices; are there any * others? */ if (!is_wifi(device)) { int ret; /* * This is not a Wi-Fi device but it could be * a DSA master/management network device. */ ret = iface_dsa_get_proto_info(device, handle); if (ret < 0) return; if (ret == 1) { /* * This is a DSA master/management network * device linktype is already set by * iface_dsa_get_proto_info() set an * appropriate offset here. */ handle->offset = 2; break; } /* * It's not a Wi-Fi device; offer DOCSIS. */ handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_EN10MB; handle->dlt_list[1] = DLT_DOCSIS; handle->dlt_count = 2; } } /* FALLTHROUGH */ case ARPHRD_METRICOM: case ARPHRD_LOOPBACK: handle->linktype = DLT_EN10MB; handle->offset = 2; break; case ARPHRD_EETHER: handle->linktype = DLT_EN3MB; break; case ARPHRD_AX25: handle->linktype = DLT_AX25_KISS; break; case ARPHRD_PRONET: handle->linktype = DLT_PRONET; break; case ARPHRD_CHAOS: handle->linktype = DLT_CHAOS; break; #ifndef ARPHRD_CAN #define ARPHRD_CAN 280 #endif case ARPHRD_CAN: handle->linktype = DLT_CAN_SOCKETCAN; break; #ifndef ARPHRD_IEEE802_TR #define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */ #endif case ARPHRD_IEEE802_TR: case ARPHRD_IEEE802: handle->linktype = DLT_IEEE802; handle->offset = 2; break; case ARPHRD_ARCNET: handle->linktype = DLT_ARCNET_LINUX; break; #ifndef ARPHRD_FDDI /* From Linux 2.2.13 */ #define ARPHRD_FDDI 774 #endif case ARPHRD_FDDI: handle->linktype = DLT_FDDI; handle->offset = 3; break; #ifndef ARPHRD_ATM /* FIXME: How to #include this? */ #define ARPHRD_ATM 19 #endif case ARPHRD_ATM: /* * The Classical IP implementation in ATM for Linux * supports both what RFC 1483 calls "LLC Encapsulation", * in which each packet has an LLC header, possibly * with a SNAP header as well, prepended to it, and * what RFC 1483 calls "VC Based Multiplexing", in which * different virtual circuits carry different network * layer protocols, and no header is prepended to packets. * * They both have an ARPHRD_ type of ARPHRD_ATM, so * you can't use the ARPHRD_ type to find out whether * captured packets will have an LLC header, and, * while there's a socket ioctl to *set* the encapsulation * type, there's no ioctl to *get* the encapsulation type. * * This means that * * programs that dissect Linux Classical IP frames * would have to check for an LLC header and, * depending on whether they see one or not, dissect * the frame as LLC-encapsulated or as raw IP (I * don't know whether there's any traffic other than * IP that would show up on the socket, or whether * there's any support for IPv6 in the Linux * Classical IP code); * * filter expressions would have to compile into * code that checks for an LLC header and does * the right thing. * * Both of those are a nuisance - and, at least on systems * that support PF_PACKET sockets, we don't have to put * up with those nuisances; instead, we can just capture * in cooked mode. That's what we'll do, if we can. * Otherwise, we'll just fail. */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else handle->linktype = -1; break; #ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */ #define ARPHRD_IEEE80211 801 #endif case ARPHRD_IEEE80211: handle->linktype = DLT_IEEE802_11; break; #ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ #define ARPHRD_IEEE80211_PRISM 802 #endif case ARPHRD_IEEE80211_PRISM: handle->linktype = DLT_PRISM_HEADER; break; #ifndef ARPHRD_IEEE80211_RADIOTAP /* new */ #define ARPHRD_IEEE80211_RADIOTAP 803 #endif case ARPHRD_IEEE80211_RADIOTAP: handle->linktype = DLT_IEEE802_11_RADIO; break; case ARPHRD_PPP: /* * Some PPP code in the kernel supplies no link-layer * header whatsoever to PF_PACKET sockets; other PPP * code supplies PPP link-layer headers ("syncppp.c"); * some PPP code might supply random link-layer * headers (PPP over ISDN - there's code in Ethereal, * for example, to cope with PPP-over-ISDN captures * with which the Ethereal developers have had to cope, * heuristically trying to determine which of the * oddball link-layer headers particular packets have). * * As such, we just punt, and run all PPP interfaces * in cooked mode, if we can; otherwise, we just treat * it as DLT_RAW, for now - if somebody needs to capture, * on a 2.0[.x] kernel, on PPP devices that supply a * link-layer header, they'll have to add code here to * map to the appropriate DLT_ type (possibly adding a * new DLT_ type, if necessary). */ if (cooked_ok) handle->linktype = DLT_LINUX_SLL; else { /* * XXX - handle ISDN types here? We can't fall * back on cooked sockets, so we'd have to * figure out from the device name what type of * link-layer encapsulation it's using, and map * that to an appropriate DLT_ value, meaning * we'd map "isdnN" devices to DLT_RAW (they * supply raw IP packets with no link-layer * header) and "isdY" devices to a new DLT_I4L_IP * type that has only an Ethernet packet type as * a link-layer header. * * But sometimes we seem to get random crap * in the link-layer header when capturing on * ISDN devices.... */ handle->linktype = DLT_RAW; } break; #ifndef ARPHRD_CISCO #define ARPHRD_CISCO 513 /* previously ARPHRD_HDLC */ #endif case ARPHRD_CISCO: handle->linktype = DLT_C_HDLC; break; /* Not sure if this is correct for all tunnels, but it * works for CIPE */ case ARPHRD_TUNNEL: #ifndef ARPHRD_SIT #define ARPHRD_SIT 776 /* From Linux 2.2.13 */ #endif case ARPHRD_SIT: case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: case ARPHRD_ADAPT: case ARPHRD_SLIP: #ifndef ARPHRD_RAWHDLC #define ARPHRD_RAWHDLC 518 #endif case ARPHRD_RAWHDLC: #ifndef ARPHRD_DLCI #define ARPHRD_DLCI 15 #endif case ARPHRD_DLCI: /* * XXX - should some of those be mapped to DLT_LINUX_SLL * instead? Should we just map all of them to DLT_LINUX_SLL? */ handle->linktype = DLT_RAW; break; #ifndef ARPHRD_FRAD #define ARPHRD_FRAD 770 #endif case ARPHRD_FRAD: handle->linktype = DLT_FRELAY; break; case ARPHRD_LOCALTLK: handle->linktype = DLT_LTALK; break; case 18: /* * RFC 4338 defines an encapsulation for IP and ARP * packets that's compatible with the RFC 2625 * encapsulation, but that uses a different ARP * hardware type and hardware addresses. That * ARP hardware type is 18; Linux doesn't define * any ARPHRD_ value as 18, but if it ever officially * supports RFC 4338-style IP-over-FC, it should define * one. * * For now, we map it to DLT_IP_OVER_FC, in the hopes * that this will encourage its use in the future, * should Linux ever officially support RFC 4338-style * IP-over-FC. */ handle->linktype = DLT_IP_OVER_FC; break; #ifndef ARPHRD_FCPP #define ARPHRD_FCPP 784 #endif case ARPHRD_FCPP: #ifndef ARPHRD_FCAL #define ARPHRD_FCAL 785 #endif case ARPHRD_FCAL: #ifndef ARPHRD_FCPL #define ARPHRD_FCPL 786 #endif case ARPHRD_FCPL: #ifndef ARPHRD_FCFABRIC #define ARPHRD_FCFABRIC 787 #endif case ARPHRD_FCFABRIC: /* * Back in 2002, Donald Lee at Cray wanted a DLT_ for * IP-over-FC: * * https://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html * * and one was assigned. * * In a later private discussion (spun off from a message * on the ethereal-users list) on how to get that DLT_ * value in libpcap on Linux, I ended up deciding that * the best thing to do would be to have him tweak the * driver to set the ARPHRD_ value to some ARPHRD_FCxx * type, and map all those types to DLT_IP_OVER_FC: * * I've checked into the libpcap and tcpdump CVS tree * support for DLT_IP_OVER_FC. In order to use that, * you'd have to modify your modified driver to return * one of the ARPHRD_FCxxx types, in "fcLINUXfcp.c" - * change it to set "dev->type" to ARPHRD_FCFABRIC, for * example (the exact value doesn't matter, it can be * any of ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, or * ARPHRD_FCFABRIC). * * 11 years later, Christian Svensson wanted to map * various ARPHRD_ values to DLT_FC_2 and * DLT_FC_2_WITH_FRAME_DELIMS for raw Fibre Channel * frames: * * https://github.com/mcr/libpcap/pull/29 * * There doesn't seem to be any network drivers that uses * any of the ARPHRD_FC* values for IP-over-FC, and * it's not exactly clear what the "Dummy types for non * ARP hardware" are supposed to mean (link-layer * header type? Physical network type?), so it's * not exactly clear why the ARPHRD_FC* types exist * in the first place. * * For now, we map them to DLT_FC_2, and provide an * option of DLT_FC_2_WITH_FRAME_DELIMS, as well as * DLT_IP_OVER_FC just in case there's some old * driver out there that uses one of those types for * IP-over-FC on which somebody wants to capture * packets. */ handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 3); /* * If that fails, just leave the list empty. */ if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_FC_2; handle->dlt_list[1] = DLT_FC_2_WITH_FRAME_DELIMS; handle->dlt_list[2] = DLT_IP_OVER_FC; handle->dlt_count = 3; } handle->linktype = DLT_FC_2; break; #ifndef ARPHRD_IRDA #define ARPHRD_IRDA 783 #endif case ARPHRD_IRDA: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_IRDA; /* We need to save packet direction for IrDA decoding, * so let's use "Linux-cooked" mode. Jean II * * XXX - this is handled in setup_socket(). */ /* handlep->cooked = 1; */ break; /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation * is needed, please report it to */ #ifndef ARPHRD_LAPD #define ARPHRD_LAPD 8445 #endif case ARPHRD_LAPD: /* Don't expect IP packet out of this interfaces... */ handle->linktype = DLT_LINUX_LAPD; break; #ifndef ARPHRD_NONE #define ARPHRD_NONE 0xFFFE #endif case ARPHRD_NONE: /* * No link-layer header; packets are just IP * packets, so use DLT_RAW. */ handle->linktype = DLT_RAW; break; #ifndef ARPHRD_IEEE802154 #define ARPHRD_IEEE802154 804 #endif case ARPHRD_IEEE802154: handle->linktype = DLT_IEEE802_15_4_NOFCS; break; #ifndef ARPHRD_NETLINK #define ARPHRD_NETLINK 824 #endif case ARPHRD_NETLINK: handle->linktype = DLT_NETLINK; /* * We need to use cooked mode, so that in sll_protocol we * pick up the netlink protocol type such as NETLINK_ROUTE, * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc. * * XXX - this is handled in setup_socket(). */ /* handlep->cooked = 1; */ break; #ifndef ARPHRD_VSOCKMON #define ARPHRD_VSOCKMON 826 #endif case ARPHRD_VSOCKMON: handle->linktype = DLT_VSOCK; break; default: handle->linktype = -1; break; } } static void set_dlt_list_cooked(pcap_t *handle) { /* * Support both DLT_LINUX_SLL and DLT_LINUX_SLL2. */ handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that failed, just leave the list empty. */ if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_LINUX_SLL; handle->dlt_list[1] = DLT_LINUX_SLL2; handle->dlt_count = 2; } } /* * Try to set up a PF_PACKET socket. * Returns 0 on success and a PCAP_ERROR_ value on failure. */ static int setup_socket(pcap_t *handle, int is_any_device) { struct pcap_linux *handlep = handle->priv; const char *device = handle->opt.device; int status = 0; int sock_fd, arptype; int val; int err = 0; struct packet_mreq mr; #if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) int bpf_extensions; socklen_t len = sizeof(bpf_extensions); #endif /* * Open a socket with protocol family packet. If cooked is true, * we open a SOCK_DGRAM socket for the cooked interface, otherwise * we open a SOCK_RAW socket for the raw interface. * * The protocol is set to 0. This means we will receive no * packets until we "bind" the socket with a non-zero * protocol. This allows us to setup the ring buffers without * dropping any packets. */ sock_fd = is_any_device ? socket(PF_PACKET, SOCK_DGRAM, 0) : socket(PF_PACKET, SOCK_RAW, 0); if (sock_fd == -1) { if (errno == EPERM || errno == EACCES) { /* * You don't have permission to open the * socket. */ status = PCAP_ERROR_PERM_DENIED; snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Attempt to create packet socket failed - CAP_NET_RAW may be required"); } else { /* * Other error. */ status = PCAP_ERROR; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "socket"); return status; } /* * Get the interface index of the loopback device. * If the attempt fails, don't fail, just set the * "handlep->lo_ifindex" to -1. * * XXX - can there be more than one device that loops * packets back, i.e. devices other than "lo"? If so, * we'd need to find them all, and have an array of * indices for them, and check all of them in * "pcap_read_packet()". */ handlep->lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf); /* * Default value for offset to align link-layer payload * on a 4-byte boundary. */ handle->offset = 0; /* * What kind of frames do we have to deal with? Fall back * to cooked mode if we have an unknown interface type * or a type we know doesn't work well in raw mode. */ if (!is_any_device) { /* Assume for now we don't need cooked mode. */ handlep->cooked = 0; if (handle->opt.rfmon) { /* * We were asked to turn on monitor mode. * Do so before we get the link-layer type, * because entering monitor mode could change * the link-layer type. */ err = enter_rfmon_mode(handle, sock_fd, device); if (err < 0) { /* Hard failure */ close(sock_fd); return err; } if (err == 0) { /* * Nothing worked for turning monitor mode * on. */ close(sock_fd); return PCAP_ERROR_RFMON_NOTSUP; } /* * Either monitor mode has been turned on for * the device, or we've been given a different * device to open for monitor mode. If we've * been given a different device, use it. */ if (handlep->mondevice != NULL) device = handlep->mondevice; } arptype = iface_get_arptype(sock_fd, device, handle->errbuf); if (arptype < 0) { close(sock_fd); return arptype; } map_arphrd_to_dlt(handle, arptype, device, 1); if (handle->linktype == -1 || handle->linktype == DLT_LINUX_SLL || handle->linktype == DLT_LINUX_IRDA || handle->linktype == DLT_LINUX_LAPD || handle->linktype == DLT_NETLINK || (handle->linktype == DLT_EN10MB && (strncmp("isdn", device, 4) == 0 || strncmp("isdY", device, 4) == 0))) { /* * Unknown interface type (-1), or a * device we explicitly chose to run * in cooked mode (e.g., PPP devices), * or an ISDN device (whose link-layer * type we can only determine by using * APIs that may be different on different * kernels) - reopen in cooked mode. * * If the type is unknown, return a warning; * map_arphrd_to_dlt() has already set the * warning message. */ if (close(sock_fd) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "close"); return PCAP_ERROR; } sock_fd = socket(PF_PACKET, SOCK_DGRAM, 0); if (sock_fd < 0) { /* * Fatal error. We treat this as * a generic error; we already know * that we were able to open a * PF_PACKET/SOCK_RAW socket, so * any failure is a "this shouldn't * happen" case. */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "socket"); return PCAP_ERROR; } handlep->cooked = 1; /* * Get rid of any link-layer type list * we allocated - this only supports cooked * capture. */ if (handle->dlt_list != NULL) { free(handle->dlt_list); handle->dlt_list = NULL; handle->dlt_count = 0; set_dlt_list_cooked(handle); } if (handle->linktype == -1) { /* * Warn that we're falling back on * cooked mode; we may want to * update "map_arphrd_to_dlt()" * to handle the new type. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "arptype %d not " "supported by libpcap - " "falling back to cooked " "socket", arptype); } /* * IrDA capture is not a real "cooked" capture, * it's IrLAP frames, not IP packets. The * same applies to LAPD capture. */ if (handle->linktype != DLT_LINUX_IRDA && handle->linktype != DLT_LINUX_LAPD && handle->linktype != DLT_NETLINK) handle->linktype = DLT_LINUX_SLL; if (handle->linktype == -1) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "unknown arptype %d, defaulting to cooked mode", arptype); status = PCAP_WARNING; } } handlep->ifindex = iface_get_id(sock_fd, device, handle->errbuf); if (handlep->ifindex == -1) { close(sock_fd); return PCAP_ERROR; } if ((err = iface_bind(sock_fd, handlep->ifindex, handle->errbuf, 0)) != 0) { close(sock_fd); return err; } } else { /* * The "any" device. */ if (handle->opt.rfmon) { /* * It doesn't support monitor mode. */ close(sock_fd); return PCAP_ERROR_RFMON_NOTSUP; } /* * It uses cooked mode. */ handlep->cooked = 1; handle->linktype = DLT_LINUX_SLL; handle->dlt_list = NULL; handle->dlt_count = 0; set_dlt_list_cooked(handle); /* * We're not bound to a device. * For now, we're using this as an indication * that we can't transmit; stop doing that only * if we figure out how to transmit in cooked * mode. */ handlep->ifindex = -1; } /* * Select promiscuous mode on if "promisc" is set. * * Do not turn allmulti mode on if we don't select * promiscuous mode - on some devices (e.g., Orinoco * wireless interfaces), allmulti mode isn't supported * and the driver implements it by turning promiscuous * mode on, and that screws up the operation of the * card as a normal networking interface, and on no * other platform I know of does starting a non- * promiscuous capture affect which multicast packets * are received by the interface. */ /* * Hmm, how can we set promiscuous mode on all interfaces? * I am not sure if that is possible at all. For now, we * silently ignore attempts to turn promiscuous mode on * for the "any" device (so you don't have to explicitly * disable it in programs such as tcpdump). */ if (!is_any_device && handle->opt.promisc) { memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = handlep->ifindex; mr.mr_type = PACKET_MR_PROMISC; if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_ADD_MEMBERSHIP)"); close(sock_fd); return PCAP_ERROR; } } /* * Enable auxiliary data and reserve room for reconstructing * VLAN headers. * * XXX - is enabling auxiliary data necessary, now that we * only support memory-mapped capture? The kernel's memory-mapped * capture code doesn't seem to check whether auxiliary data * is enabled, it seems to provide it whether it is or not. */ val = 1; if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_AUXDATA)"); close(sock_fd); return PCAP_ERROR; } handle->offset += VLAN_TAG_LEN; /* * If we're in cooked mode, make the snapshot length * large enough to hold a "cooked mode" header plus * 1 byte of packet data (so we don't pass a byte * count of 0 to "recvfrom()"). * XXX - we don't know whether this will be DLT_LINUX_SLL * or DLT_LINUX_SLL2, so make sure it's big enough for * a DLT_LINUX_SLL2 "cooked mode" header; a snapshot length * that small is silly anyway. */ if (handlep->cooked) { if (handle->snapshot < SLL2_HDR_LEN + 1) handle->snapshot = SLL2_HDR_LEN + 1; } handle->bufsize = handle->snapshot; /* * Set the offset at which to insert VLAN tags. */ set_vlan_offset(handle); if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { int nsec_tstamps = 1; if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS"); close(sock_fd); return PCAP_ERROR; } } /* * We've succeeded. Save the socket FD in the pcap structure. */ handle->fd = sock_fd; #if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) /* * Can we generate special code for VLAN checks? * (XXX - what if we need the special code but it's not supported * by the OS? Is that possible?) */ if (getsockopt(sock_fd, SOL_SOCKET, SO_BPF_EXTENSIONS, &bpf_extensions, &len) == 0) { if (bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT) { /* * Yes, we can. Request that we do so. */ handle->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING; } } #endif /* defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) */ return status; } /* * Attempt to setup memory-mapped access. * * On success, returns 1, and sets *status to 0 if there are no warnings * or to a PCAP_WARNING_ code if there is a warning. * * On error, returns -1, and sets *status to the appropriate error code; * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. */ static int setup_mmapped(pcap_t *handle, int *status) { struct pcap_linux *handlep = handle->priv; int ret; /* * Attempt to allocate a buffer to hold the contents of one * packet, for use by the oneshot callback. */ handlep->oneshot_buffer = malloc(handle->snapshot); if (handlep->oneshot_buffer == NULL) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't allocate oneshot buffer"); *status = PCAP_ERROR; return -1; } if (handle->opt.buffer_size == 0) { /* by default request 2M for the ring buffer */ handle->opt.buffer_size = 2*1024*1024; } ret = prepare_tpacket_socket(handle); if (ret == -1) { free(handlep->oneshot_buffer); handlep->oneshot_buffer = NULL; *status = PCAP_ERROR; return ret; } ret = create_ring(handle, status); if (ret == -1) { /* * Error attempting to enable memory-mapped capture; * fail. create_ring() has set *status. */ free(handlep->oneshot_buffer); handlep->oneshot_buffer = NULL; return -1; } /* * Success. *status has been set either to 0 if there are no * warnings or to a PCAP_WARNING_ value if there is a warning. * * handle->offset is used to get the current position into the rx ring. * handle->cc is used to store the ring size. */ /* * Set the timeout to use in poll() before returning. */ set_poll_timeout(handlep); return 1; } /* * Attempt to set the socket to the specified version of the memory-mapped * header. * * Return 0 if we succeed; return 1 if we fail because that version isn't * supported; return -1 on any other error, and set handle->errbuf. */ static int init_tpacket(pcap_t *handle, int version, const char *version_str) { struct pcap_linux *handlep = handle->priv; int val = version; socklen_t len = sizeof(val); /* * Probe whether kernel supports the specified TPACKET version; * this also gets the length of the header for that version. * * This socket option was introduced in 2.6.27, which was * also the first release with TPACKET_V2 support. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == EINVAL) { /* * EINVAL means this specific version of TPACKET * is not supported. Tell the caller they can try * with a different one; if they've run out of * others to try, let them set the error message * appropriately. */ return 1; } /* * All other errors are fatal. */ if (errno == ENOPROTOOPT) { /* * PACKET_HDRLEN isn't supported, which means * that memory-mapped capture isn't supported. * Indicate that in the message. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Kernel doesn't support memory-mapped capture; a 2.6.27 or later 2.x kernel is required, with CONFIG_PACKET_MMAP specified for 2.x kernels"); } else { /* * Some unexpected error. */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't get %s header len on packet socket", version_str); } return -1; } handlep->tp_hdrlen = val; val = version; if (setsockopt(handle->fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't activate %s on packet socket", version_str); return -1; } handlep->tp_version = version; return 0; } /* * Attempt to set the socket to version 3 of the memory-mapped header and, * if that fails because version 3 isn't supported, attempt to fall * back to version 2. If version 2 isn't supported, just fail. * * Return 0 if we succeed and -1 on any other error, and set handle->errbuf. */ static int prepare_tpacket_socket(pcap_t *handle) { int ret; #ifdef HAVE_TPACKET3 /* * Try setting the version to TPACKET_V3. * * The only mode in which buffering is done on PF_PACKET * sockets, so that packets might not be delivered * immediately, is TPACKET_V3 mode. * * The buffering cannot be disabled in that mode, so * if the user has requested immediate mode, we don't * use TPACKET_V3. */ if (!handle->opt.immediate) { ret = init_tpacket(handle, TPACKET_V3, "TPACKET_V3"); if (ret == 0) { /* * Success. */ return 0; } if (ret == -1) { /* * We failed for some reason other than "the * kernel doesn't support TPACKET_V3". */ return -1; } /* * This means it returned 1, which means "the kernel * doesn't support TPACKET_V3"; try TPACKET_V2. */ } #endif /* HAVE_TPACKET3 */ /* * Try setting the version to TPACKET_V2. */ ret = init_tpacket(handle, TPACKET_V2, "TPACKET_V2"); if (ret == 0) { /* * Success. */ return 0; } if (ret == 1) { /* * OK, the kernel supports memory-mapped capture, but * not TPACKET_V2. Set the error message appropriately. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Kernel doesn't support TPACKET_V2; a 2.6.27 or later kernel is required"); } /* * We failed. */ return -1; } #define MAX(a,b) ((a)>(b)?(a):(b)) /* * Attempt to set up memory-mapped access. * * On success, returns 1, and sets *status to 0 if there are no warnings * or to a PCAP_WARNING_ code if there is a warning. * * On error, returns -1, and sets *status to the appropriate error code; * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message. */ static int create_ring(pcap_t *handle, int *status) { struct pcap_linux *handlep = handle->priv; unsigned i, j, frames_per_block; #ifdef HAVE_TPACKET3 /* * For sockets using TPACKET_V2, the extra stuff at the end of a * struct tpacket_req3 will be ignored, so this is OK even for * those sockets. */ struct tpacket_req3 req; #else struct tpacket_req req; #endif socklen_t len; unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff; unsigned int frame_size; /* * Start out assuming no warnings or errors. */ *status = 0; /* * Reserve space for VLAN tag reconstruction. */ tp_reserve = VLAN_TAG_LEN; /* * If we're capturing in cooked mode, reserve space for * a DLT_LINUX_SLL2 header; we don't know yet whether * we'll be using DLT_LINUX_SLL or DLT_LINUX_SLL2, as * that can be changed on an open device, so we reserve * space for the larger of the two. * * XXX - we assume that the kernel is still adding * 16 bytes of extra space, so we subtract 16 from * SLL2_HDR_LEN to get the additional space needed. * (Are they doing that for DLT_LINUX_SLL, the link- * layer header for which is 16 bytes?) * * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - 16)? */ if (handlep->cooked) tp_reserve += SLL2_HDR_LEN - 16; /* * Try to request that amount of reserve space. * This must be done before creating the ring buffer. */ len = sizeof(tp_reserve); if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve, len) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_RESERVE)"); *status = PCAP_ERROR; return -1; } switch (handlep->tp_version) { case TPACKET_V2: /* Note that with large snapshot length (say 256K, which is * the default for recent versions of tcpdump, Wireshark, * TShark, dumpcap or 64K, the value that "-s 0" has given for * a long time with tcpdump), if we use the snapshot * length to calculate the frame length, only a few frames * will be available in the ring even with pretty * large ring size (and a lot of memory will be unused). * * Ideally, we should choose a frame length based on the * minimum of the specified snapshot length and the maximum * packet size. That's not as easy as it sounds; consider, * for example, an 802.11 interface in monitor mode, where * the frame would include a radiotap header, where the * maximum radiotap header length is device-dependent. * * So, for now, we just do this for Ethernet devices, where * there's no metadata header, and the link-layer header is * fixed length. We can get the maximum packet size by * adding 18, the Ethernet header length plus the CRC length * (just in case we happen to get the CRC in the packet), to * the MTU of the interface; we fetch the MTU in the hopes * that it reflects support for jumbo frames. (Even if the * interface is just being used for passive snooping, the * driver might set the size of buffers in the receive ring * based on the MTU, so that the MTU limits the maximum size * of packets that we can receive.) * * If segmentation/fragmentation or receive offload are * enabled, we can get reassembled/aggregated packets larger * than MTU, but bounded to 65535 plus the Ethernet overhead, * due to kernel and protocol constraints */ frame_size = handle->snapshot; if (handle->linktype == DLT_EN10MB) { unsigned int max_frame_len; int mtu; int offload; mtu = iface_get_mtu(handle->fd, handle->opt.device, handle->errbuf); if (mtu == -1) { *status = PCAP_ERROR; return -1; } offload = iface_get_offload(handle); if (offload == -1) { *status = PCAP_ERROR; return -1; } if (offload) max_frame_len = MAX(mtu, 65535); else max_frame_len = mtu; max_frame_len += 18; if (frame_size > max_frame_len) frame_size = max_frame_len; } /* NOTE: calculus matching those in tpacket_rcv() * in linux-2.6/net/packet/af_packet.c */ len = sizeof(sk_type); if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, &len) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "getsockopt (SO_TYPE)"); *status = PCAP_ERROR; return -1; } maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE; /* XXX: in the kernel maclen is calculated from * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len * in: packet_snd() in linux-2.6/net/packet/af_packet.c * then packet_alloc_skb() in linux-2.6/net/packet/af_packet.c * then sock_alloc_send_pskb() in linux-2.6/net/core/sock.c * but I see no way to get those sizes in userspace, * like for instance with an ifreq ioctl(); * the best thing I've found so far is MAX_HEADER in * the kernel part of linux-2.6/include/linux/netdevice.h * which goes up to 128+48=176; since pcap-linux.c * defines a MAX_LINKHEADER_SIZE of 256 which is * greater than that, let's use it.. maybe is it even * large enough to directly replace macoff.. */ tp_hdrlen = TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll) ; netoff = TPACKET_ALIGN(tp_hdrlen + (maclen < 16 ? 16 : maclen)) + tp_reserve; /* NOTE: AFAICS tp_reserve may break the TPACKET_ALIGN * of netoff, which contradicts * linux-2.6/Documentation/networking/packet_mmap.txt * documenting that: * "- Gap, chosen so that packet data (Start+tp_net) * aligns to TPACKET_ALIGNMENT=16" */ /* NOTE: in linux-2.6/include/linux/skbuff.h: * "CPUs often take a performance hit * when accessing unaligned memory locations" */ macoff = netoff - maclen; req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size); /* * Round the buffer size up to a multiple of the * frame size (rather than rounding down, which * would give a buffer smaller than our caller asked * for, and possibly give zero frames if the requested * buffer size is too small for one frame). */ req.tp_frame_nr = (handle->opt.buffer_size + req.tp_frame_size - 1)/req.tp_frame_size; break; #ifdef HAVE_TPACKET3 case TPACKET_V3: /* The "frames" for this are actually buffers that * contain multiple variable-sized frames. * * We pick a "frame" size of MAXIMUM_SNAPLEN to leave * enough room for at least one reasonably-sized packet * in the "frame". */ req.tp_frame_size = MAXIMUM_SNAPLEN; /* * Round the buffer size up to a multiple of the * "frame" size (rather than rounding down, which * would give a buffer smaller than our caller asked * for, and possibly give zero "frames" if the requested * buffer size is too small for one "frame"). */ req.tp_frame_nr = (handle->opt.buffer_size + req.tp_frame_size - 1)/req.tp_frame_size; break; #endif default: snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Internal error: unknown TPACKET_ value %u", handlep->tp_version); *status = PCAP_ERROR; return -1; } /* compute the minimum block size that will handle this frame. * The block has to be page size aligned. * The max block size allowed by the kernel is arch-dependent and * it's not explicitly checked here. */ req.tp_block_size = getpagesize(); while (req.tp_block_size < req.tp_frame_size) req.tp_block_size <<= 1; frames_per_block = req.tp_block_size/req.tp_frame_size; /* * PACKET_TIMESTAMP was added after linux/net_tstamp.h was, * so we check for PACKET_TIMESTAMP. We check for * linux/net_tstamp.h just in case a system somehow has * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might * be unnecessary. * * SIOCSHWTSTAMP was introduced in the patch that introduced * linux/net_tstamp.h, so we don't bother checking whether * SIOCSHWTSTAMP is defined (if your Linux system has * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your * Linux system is badly broken). */ #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) /* * If we were told to do so, ask the kernel and the driver * to use hardware timestamps. * * Hardware timestamps are only supported with mmapped * captures. */ if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER || handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) { struct hwtstamp_config hwconfig; struct ifreq ifr; int timesource; /* * Ask for hardware time stamps on all packets, * including transmitted packets. */ memset(&hwconfig, 0, sizeof(hwconfig)); hwconfig.tx_type = HWTSTAMP_TX_ON; hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&hwconfig; /* * This may require CAP_NET_ADMIN. */ if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) { switch (errno) { case EPERM: /* * Treat this as an error, as the * user should try to run this * with the appropriate privileges - * and, if they can't, shouldn't * try requesting hardware time stamps. */ *status = PCAP_ERROR_PERM_DENIED; snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Attempt to set hardware timestamp failed - CAP_NET_ADMIN may be required"); return -1; case EOPNOTSUPP: case ERANGE: /* * Treat this as a warning, as the * only way to fix the warning is to * get an adapter that supports hardware * time stamps for *all* packets. * (ERANGE means "we support hardware * time stamps, but for packets matching * that particular filter", so it means * "we don't support hardware time stamps * for all incoming packets" here.) * * We'll just fall back on the standard * host time stamps. */ *status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP; break; default: pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "SIOCSHWTSTAMP failed"); *status = PCAP_ERROR; return -1; } } else { /* * Well, that worked. Now specify the type of * hardware time stamp we want for this * socket. */ if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) { /* * Hardware timestamp, synchronized * with the system clock. */ timesource = SOF_TIMESTAMPING_SYS_HARDWARE; } else { /* * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware * timestamp, not synchronized with the * system clock. */ timesource = SOF_TIMESTAMPING_RAW_HARDWARE; } if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP, (void *)×ource, sizeof(timesource))) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't set PACKET_TIMESTAMP"); *status = PCAP_ERROR; return -1; } } } #endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */ /* ask the kernel to create the ring */ retry: req.tp_block_nr = req.tp_frame_nr / frames_per_block; /* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */ req.tp_frame_nr = req.tp_block_nr * frames_per_block; #ifdef HAVE_TPACKET3 /* timeout value to retire block - use the configured buffering timeout, or default if <0. */ if (handlep->timeout > 0) { /* Use the user specified timeout as the block timeout */ req.tp_retire_blk_tov = handlep->timeout; } else if (handlep->timeout == 0) { /* * In pcap, this means "infinite timeout"; TPACKET_V3 * doesn't support that, so just set it to UINT_MAX * milliseconds. In the TPACKET_V3 loop, if the * timeout is 0, and we haven't yet seen any packets, * and we block and still don't have any packets, we * keep blocking until we do. */ req.tp_retire_blk_tov = UINT_MAX; } else { /* * XXX - this is not valid; use 0, meaning "have the * kernel pick a default", for now. */ req.tp_retire_blk_tov = 0; } /* private data not used */ req.tp_sizeof_priv = 0; /* Rx ring - feature request bits - none (rxhash will not be filled) */ req.tp_feature_req_word = 0; #endif if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req))) { if ((errno == ENOMEM) && (req.tp_block_nr > 1)) { /* * Memory failure; try to reduce the requested ring * size. * * We used to reduce this by half -- do 5% instead. * That may result in more iterations and a longer * startup, but the user will be much happier with * the resulting buffer size. */ if (req.tp_frame_nr < 20) req.tp_frame_nr -= 1; else req.tp_frame_nr -= req.tp_frame_nr/20; goto retry; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't create rx ring on packet socket"); *status = PCAP_ERROR; return -1; } /* memory map the rx ring */ handlep->mmapbuflen = req.tp_block_nr * req.tp_block_size; handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); if (handlep->mmapbuf == MAP_FAILED) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't mmap rx ring"); /* clear the allocated ring on error*/ destroy_ring(handle); *status = PCAP_ERROR; return -1; } /* allocate a ring for each frame header pointer*/ handle->cc = req.tp_frame_nr; handle->buffer = malloc(handle->cc * sizeof(union thdr *)); if (!handle->buffer) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't allocate ring of frame headers"); destroy_ring(handle); *status = PCAP_ERROR; return -1; } /* fill the header ring with proper frame ptr*/ handle->offset = 0; for (i=0; immapbuf[i*req.tp_block_size]; for (j=0; joffset) { RING_GET_CURRENT_FRAME(handle) = base; base += req.tp_frame_size; } } handle->bufsize = req.tp_frame_size; handle->offset = 0; return 1; } /* free all ring related resources*/ static void destroy_ring(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; /* * Tell the kernel to destroy the ring. * We don't check for setsockopt failure, as 1) we can't recover * from an error and 2) we might not yet have set it up in the * first place. */ struct tpacket_req req; memset(&req, 0, sizeof(req)); (void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req)); /* if ring is mapped, unmap it*/ if (handlep->mmapbuf) { /* do not test for mmap failure, as we can't recover from any error */ (void)munmap(handlep->mmapbuf, handlep->mmapbuflen); handlep->mmapbuf = NULL; } } /* * Special one-shot callback, used for pcap_next() and pcap_next_ex(), * for Linux mmapped capture. * * The problem is that pcap_next() and pcap_next_ex() expect the packet * data handed to the callback to be valid after the callback returns, * but pcap_read_linux_mmap() has to release that packet as soon as * the callback returns (otherwise, the kernel thinks there's still * at least one unprocessed packet available in the ring, so a select() * will immediately return indicating that there's data to process), so, * in the callback, we have to make a copy of the packet. * * Yes, this means that, if the capture is using the ring buffer, using * pcap_next() or pcap_next_ex() requires more copies than using * pcap_loop() or pcap_dispatch(). If that bothers you, don't use * pcap_next() or pcap_next_ex(). */ static void pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct oneshot_userdata *sp = (struct oneshot_userdata *)user; pcap_t *handle = sp->pd; struct pcap_linux *handlep = handle->priv; *sp->hdr = *h; memcpy(handlep->oneshot_buffer, bytes, h->caplen); *sp->pkt = handlep->oneshot_buffer; } static int pcap_getnonblock_linux(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; /* use negative value of timeout to indicate non blocking ops */ return (handlep->timeout<0); } static int pcap_setnonblock_linux(pcap_t *handle, int nonblock) { struct pcap_linux *handlep = handle->priv; /* * Set the file descriptor to non-blocking mode, as we use * it for sending packets. */ if (pcap_setnonblock_fd(handle, nonblock) == -1) return -1; /* * Map each value to their corresponding negation to * preserve the timeout value provided with pcap_set_timeout. */ if (nonblock) { if (handlep->timeout >= 0) { /* * Indicate that we're switching to * non-blocking mode. */ handlep->timeout = ~handlep->timeout; } if (handlep->poll_breakloop_fd != -1) { /* Close the eventfd; we do not need it in nonblock mode. */ close(handlep->poll_breakloop_fd); handlep->poll_breakloop_fd = -1; } } else { if (handlep->poll_breakloop_fd == -1) { /* If we did not have an eventfd, open one now that we are blocking. */ if ( ( handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK) ) == -1 ) { int save_errno = errno; snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Could not open eventfd: %s", strerror(errno)); errno = save_errno; return -1; } } if (handlep->timeout < 0) { handlep->timeout = ~handlep->timeout; } } /* Update the timeout to use in poll(). */ set_poll_timeout(handlep); return 0; } /* * Get the status field of the ring buffer frame at a specified offset. */ static inline u_int pcap_get_ring_frame_status(pcap_t *handle, int offset) { struct pcap_linux *handlep = handle->priv; union thdr h; h.raw = RING_GET_FRAME_AT(handle, offset); switch (handlep->tp_version) { case TPACKET_V2: return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE); break; #ifdef HAVE_TPACKET3 case TPACKET_V3: return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE); break; #endif } /* This should not happen. */ return 0; } /* * Block waiting for frames to be available. */ static int pcap_wait_for_frames_mmap(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; int timeout; struct ifreq ifr; int ret; struct pollfd pollinfo[2]; int numpollinfo; pollinfo[0].fd = handle->fd; pollinfo[0].events = POLLIN; if ( handlep->poll_breakloop_fd == -1 ) { numpollinfo = 1; pollinfo[1].revents = 0; /* * We set pollinfo[1].revents to zero, even though * numpollinfo = 1 meaning that poll() doesn't see * pollinfo[1], so that we do not have to add a * conditional of numpollinfo > 1 below when we * test pollinfo[1].revents. */ } else { pollinfo[1].fd = handlep->poll_breakloop_fd; pollinfo[1].events = POLLIN; numpollinfo = 2; } /* * Keep polling until we either get some packets to read, see * that we got told to break out of the loop, get a fatal error, * or discover that the device went away. * * In non-blocking mode, we must still do one poll() to catch * any pending error indications, but the poll() has a timeout * of 0, so that it doesn't block, and we quit after that one * poll(). * * If we've seen an ENETDOWN, it might be the first indication * that the device went away, or it might just be that it was * configured down. Unfortunately, there's no guarantee that * the device has actually been removed as an interface, because: * * 1) if, as appears to be the case at least some of the time, * the PF_PACKET socket code first gets a NETDEV_DOWN indication * for the device and then gets a NETDEV_UNREGISTER indication * for it, the first indication will cause a wakeup with ENETDOWN * but won't set the packet socket's field for the interface index * to -1, and the second indication won't cause a wakeup (because * the first indication also caused the protocol hook to be * unregistered) but will set the packet socket's field for the * interface index to -1; * * 2) even if just a NETDEV_UNREGISTER indication is registered, * the packet socket's field for the interface index only gets * set to -1 after the wakeup, so there's a small but non-zero * risk that a thread blocked waiting for the wakeup will get * to the "fetch the socket name" code before the interface index * gets set to -1, so it'll get the old interface index. * * Therefore, if we got an ENETDOWN and haven't seen a packet * since then, we assume that we might be waiting for the interface * to disappear, and poll with a timeout to try again in a short * period of time. If we *do* see a packet, the interface has * come back up again, and is *definitely* still there, so we * don't need to poll. */ for (;;) { - /* + /* * Yes, we do this even in non-blocking mode, as it's * the only way to get error indications from a * tpacket socket. * * The timeout is 0 in non-blocking mode, so poll() * returns immediately. */ timeout = handlep->poll_timeout; /* * If we got an ENETDOWN and haven't gotten an indication * that the device has gone away or that the device is up, * we don't yet know for certain whether the device has * gone away or not, do a poll() with a 1-millisecond timeout, * as we have to poll indefinitely for "device went away" * indications until we either get one or see that the * device is up. */ if (handlep->netdown) { if (timeout != 0) timeout = 1; } ret = poll(pollinfo, numpollinfo, timeout); if (ret < 0) { /* * Error. If it's not EINTR, report it. */ if (errno != EINTR) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't poll on packet socket"); return PCAP_ERROR; } /* * It's EINTR; if we were told to break out of * the loop, do so. */ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } else if (ret > 0) { /* * OK, some descriptor is ready. * Check the socket descriptor first. * * As I read the Linux man page, pollinfo[0].revents * will either be POLLIN, POLLERR, POLLHUP, or POLLNVAL. */ if (pollinfo[0].revents == POLLIN) { /* * OK, we may have packets to * read. */ break; } if (pollinfo[0].revents != 0) { /* * There's some indication other than * "you can read on this descriptor" on * the descriptor. */ if (pollinfo[0].revents & POLLNVAL) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Invalid polling request on packet socket"); return PCAP_ERROR; } if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Hangup on packet socket"); return PCAP_ERROR; } if (pollinfo[0].revents & POLLERR) { /* * Get the error. */ int err; socklen_t errlen; errlen = sizeof(err); if (getsockopt(handle->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { /* * The call *itself* returned * an error; make *that* * the error. */ err = errno; } /* * OK, we have the error. */ if (err == ENETDOWN) { /* * The device on which we're * capturing went away or the * interface was taken down. * * We don't know for certain * which happened, and the * next poll() may indicate * that there are packets * to be read, so just set * a flag to get us to do * checks later, and set * the required select * timeout to 1 millisecond * so that event loops that * check our socket descriptor * also time out so that * they can call us and we * can do the checks. */ handlep->netdown = 1; handle->required_select_timeout = &netdown_timeout; } else if (err == 0) { /* * This shouldn't happen, so * report a special indication * that it did. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Error condition on packet socket: Reported error was 0"); return PCAP_ERROR; } else { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, err, "Error condition on packet socket"); return PCAP_ERROR; } } } /* * Now check the event device. */ if (pollinfo[1].revents & POLLIN) { ssize_t nread; uint64_t value; /* * This should never fail, but, just * in case.... */ nread = read(handlep->poll_breakloop_fd, &value, sizeof(value)); if (nread == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Error reading from event FD"); return PCAP_ERROR; } /* * According to the Linux read(2) man * page, read() will transfer at most * 2^31-1 bytes, so the return value is * either -1 or a value between 0 * and 2^31-1, so it's non-negative. * * Cast it to size_t to squelch * warnings from the compiler; add this * comment to squelch warnings from * humans reading the code. :-) * * Don't treat an EOF as an error, but * *do* treat a short read as an error; * that "shouldn't happen", but.... */ if (nread != 0 && (size_t)nread < sizeof(value)) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Short read from event FD: expected %zu, got %zd", sizeof(value), nread); return PCAP_ERROR; } /* * This event gets signaled by a * pcap_breakloop() call; if we were told * to break out of the loop, do so. */ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } } /* * Either: * * 1) we got neither an error from poll() nor any * readable descriptors, in which case there * are no packets waiting to read * * or * * 2) We got readable descriptors but the PF_PACKET * socket wasn't one of them, in which case there * are no packets waiting to read * * so, if we got an ENETDOWN, we've drained whatever * packets were available to read at the point of the * ENETDOWN. * * So, if we got an ENETDOWN and haven't gotten an indication * that the device has gone away or that the device is up, * we don't yet know for certain whether the device has * gone away or not, check whether the device exists and is * up. */ if (handlep->netdown) { if (!device_still_exists(handle)) { /* * The device doesn't exist any more; * report that. * * XXX - we should really return an * appropriate error for that, but * pcap_dispatch() etc. aren't documented * as having error returns other than * PCAP_ERROR or PCAP_ERROR_BREAK. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "The interface disappeared"); return PCAP_ERROR; } /* * The device still exists; try to see if it's up. */ memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, handlep->device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { if (errno == ENXIO || errno == ENODEV) { /* * OK, *now* it's gone. * * XXX - see above comment. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "The interface disappeared"); return PCAP_ERROR; } else { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't get flags", handlep->device); return PCAP_ERROR; } } if (ifr.ifr_flags & IFF_UP) { /* * It's up, so it definitely still exists. * Cancel the ENETDOWN indication - we * presumably got it due to the interface * going down rather than the device going * away - and revert to "no required select * timeout. */ handlep->netdown = 0; handle->required_select_timeout = NULL; } } /* * If we're in non-blocking mode, just quit now, rather * than spinning in a loop doing poll()s that immediately * time out if there's no indication on any descriptor. */ if (handlep->poll_timeout == 0) break; } return 0; } /* handle a single memory mapped packet */ static int pcap_handle_packet_mmap( pcap_t *handle, pcap_handler callback, u_char *user, unsigned char *frame, unsigned int tp_len, unsigned int tp_mac, unsigned int tp_snaplen, unsigned int tp_sec, unsigned int tp_usec, int tp_vlan_tci_valid, __u16 tp_vlan_tci, __u16 tp_vlan_tpid) { struct pcap_linux *handlep = handle->priv; unsigned char *bp; struct sockaddr_ll *sll; struct pcap_pkthdr pcaphdr; pcap_can_socketcan_hdr *canhdr; unsigned int snaplen = tp_snaplen; struct utsname utsname; /* perform sanity check on internal offset. */ if (tp_mac + tp_snaplen > handle->bufsize) { /* * Report some system information as a debugging aid. */ if (uname(&utsname) != -1) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "corrupted frame on kernel ring mac " "offset %u + caplen %u > frame len %d " "(kernel %.32s version %s, machine %.16s)", tp_mac, tp_snaplen, handle->bufsize, utsname.release, utsname.version, utsname.machine); } else { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "corrupted frame on kernel ring mac " "offset %u + caplen %u > frame len %d", tp_mac, tp_snaplen, handle->bufsize); } return -1; } /* run filter on received packet * If the kernel filtering is enabled we need to run the * filter until all the frames present into the ring * at filter creation time are processed. * In this case, blocks_to_filter_in_userland is used * as a counter for the packet we need to filter. * Note: alternatively it could be possible to stop applying * the filter when the ring became empty, but it can possibly * happen a lot later... */ bp = frame + tp_mac; /* if required build in place the sll header*/ sll = (void *)(frame + TPACKET_ALIGN(handlep->tp_hdrlen)); if (handlep->cooked) { if (handle->linktype == DLT_LINUX_SLL2) { struct sll2_header *hdrp; /* * The kernel should have left us with enough * space for an sll header; back up the packet * data pointer into that space, as that'll be * the beginning of the packet we pass to the * callback. */ bp -= SLL2_HDR_LEN; /* * Let's make sure that's past the end of * the tpacket header, i.e. >= * ((u_char *)thdr + TPACKET_HDRLEN), so we * don't step on the header when we construct * the sll header. */ if (bp < (u_char *)frame + TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll)) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "cooked-mode frame doesn't have room for sll header"); return -1; } /* * OK, that worked; construct the sll header. */ hdrp = (struct sll2_header *)bp; hdrp->sll2_protocol = sll->sll_protocol; hdrp->sll2_reserved_mbz = 0; hdrp->sll2_if_index = htonl(sll->sll_ifindex); hdrp->sll2_hatype = htons(sll->sll_hatype); hdrp->sll2_pkttype = sll->sll_pkttype; hdrp->sll2_halen = sll->sll_halen; memcpy(hdrp->sll2_addr, sll->sll_addr, SLL_ADDRLEN); snaplen += sizeof(struct sll2_header); } else { struct sll_header *hdrp; /* * The kernel should have left us with enough * space for an sll header; back up the packet * data pointer into that space, as that'll be * the beginning of the packet we pass to the * callback. */ bp -= SLL_HDR_LEN; /* * Let's make sure that's past the end of * the tpacket header, i.e. >= * ((u_char *)thdr + TPACKET_HDRLEN), so we * don't step on the header when we construct * the sll header. */ if (bp < (u_char *)frame + TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll)) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "cooked-mode frame doesn't have room for sll header"); return -1; } /* * OK, that worked; construct the sll header. */ hdrp = (struct sll_header *)bp; hdrp->sll_pkttype = htons(sll->sll_pkttype); hdrp->sll_hatype = htons(sll->sll_hatype); hdrp->sll_halen = htons(sll->sll_halen); memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); hdrp->sll_protocol = sll->sll_protocol; snaplen += sizeof(struct sll_header); } } else { /* * If this is a packet from a CAN device, so that * sll->sll_hatype is ARPHRD_CAN, then, as we're * not capturing in cooked mode, its link-layer * type is DLT_CAN_SOCKETCAN. Fix up the header * provided by the code below us to match what * DLT_CAN_SOCKETCAN is expected to provide. */ if (sll->sll_hatype == ARPHRD_CAN) { /* * DLT_CAN_SOCKETCAN is specified as having the * CAN ID and flags in network byte order, but * capturing on a CAN device provides it in host * byte order. Convert it to network byte order. */ canhdr = (pcap_can_socketcan_hdr *)bp; canhdr->can_id = htonl(canhdr->can_id); /* * In addition, set the CANFD_FDF flag if * the protocol is LINUX_SLL_P_CANFD, as * the protocol field itself isn't in * the packet to indicate that it's a * CAN FD packet. */ uint16_t protocol = ntohs(sll->sll_protocol); if (protocol == LINUX_SLL_P_CANFD) { canhdr->fd_flags |= CANFD_FDF; /* * Zero out all the unknown bits in * fd_flags and clear the reserved * fields, so that a program reading * this can assume that CANFD_FDF * is set because we set it, not * because some uninitialized crap * was provided in the fd_flags * field. * * (At least some LINKTYPE_CAN_SOCKETCAN * files attached to Wireshark bugs * had uninitialized junk there, so it * does happen.) * * Update this if Linux adds more flag * bits to the fd_flags field or uses * either of the reserved fields for * FD frames. */ canhdr->fd_flags &= ~(CANFD_FDF|CANFD_ESI|CANFD_BRS); canhdr->reserved1 = 0; canhdr->reserved2 = 0; } else { /* * Clear CANFD_FDF if it's set (probably * again meaning that this field is * uninitialized junk). */ canhdr->fd_flags &= ~CANFD_FDF; } } } if (handlep->filter_in_userland && handle->fcode.bf_insns) { struct pcap_bpf_aux_data aux_data; aux_data.vlan_tag_present = tp_vlan_tci_valid; aux_data.vlan_tag = tp_vlan_tci & 0x0fff; if (pcap_filter_with_aux_data(handle->fcode.bf_insns, bp, tp_len, snaplen, &aux_data) == 0) return 0; } if (!linux_check_direction(handle, sll)) return 0; /* get required packet info from ring header */ pcaphdr.ts.tv_sec = tp_sec; pcaphdr.ts.tv_usec = tp_usec; pcaphdr.caplen = tp_snaplen; pcaphdr.len = tp_len; /* if required build in place the sll header*/ if (handlep->cooked) { /* update packet len */ if (handle->linktype == DLT_LINUX_SLL2) { pcaphdr.caplen += SLL2_HDR_LEN; pcaphdr.len += SLL2_HDR_LEN; } else { pcaphdr.caplen += SLL_HDR_LEN; pcaphdr.len += SLL_HDR_LEN; } } if (tp_vlan_tci_valid && handlep->vlan_offset != -1 && tp_snaplen >= (unsigned int) handlep->vlan_offset) { struct vlan_tag *tag; /* * Move everything in the header, except the type field, * down VLAN_TAG_LEN bytes, to allow us to insert the * VLAN tag between that stuff and the type field. */ bp -= VLAN_TAG_LEN; memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); /* * Now insert the tag. */ tag = (struct vlan_tag *)(bp + handlep->vlan_offset); tag->vlan_tpid = htons(tp_vlan_tpid); tag->vlan_tci = htons(tp_vlan_tci); /* * Add the tag to the packet lengths. */ pcaphdr.caplen += VLAN_TAG_LEN; pcaphdr.len += VLAN_TAG_LEN; } /* * The only way to tell the kernel to cut off the * packet at a snapshot length is with a filter program; * if there's no filter program, the kernel won't cut * the packet off. * * Trim the snapshot length to be no longer than the * specified snapshot length. * * XXX - an alternative is to put a filter, consisting * of a "ret " instruction, on the socket * in the activate routine, so that the truncation is * done in the kernel even if nobody specified a filter; * that means that less buffer space is consumed in * the memory-mapped buffer. */ if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot) pcaphdr.caplen = handle->snapshot; /* pass the packet to the user */ callback(user, &pcaphdr, bp); return 1; } static int pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (!packet_mmap_acquire(h.h2)) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } /* * This can conceivably process more than INT_MAX packets, * which would overflow the packet count, causing it either * to look like a negative number, and thus cause us to * return a value that looks like an error, or overflow * back into positive territory, and thus cause us to * return a too-low count. * * Therefore, if the packet count is unlimited, we clip * it at INT_MAX; this routine is not expected to * process packets indefinitely, so that's not an issue. */ if (PACKET_COUNT_IS_UNLIMITED(max_packets)) max_packets = INT_MAX; while (pkts < max_packets) { /* * Get the current ring buffer frame, and break if * it's still owned by the kernel. */ h.raw = RING_GET_CURRENT_FRAME(handle); if (!packet_mmap_acquire(h.h2)) break; ret = pcap_handle_packet_mmap( handle, callback, user, h.raw, h.h2->tp_len, h.h2->tp_mac, h.h2->tp_snaplen, h.h2->tp_sec, handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? h.h2->tp_nsec : h.h2->tp_nsec / 1000, VLAN_VALID(h.h2, h.h2), h.h2->tp_vlan_tci, VLAN_TPID(h.h2, h.h2)); if (ret == 1) { pkts++; } else if (ret < 0) { return ret; } /* * Hand this block back to the kernel, and, if we're * counting blocks that need to be filtered in userland * after having been filtered by the kernel, count * the one we've just processed. */ packet_mmap_release(h.h2); if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } return pkts; } #ifdef HAVE_TPACKET3 static int pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_linux *handlep = handle->priv; union thdr h; int pkts = 0; int ret; again: if (handlep->current_packet == NULL) { /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); if (!packet_mmap_v3_acquire(h.h3)) { /* * The current frame is owned by the kernel; wait * for a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); if (ret) { return ret; } } } h.raw = RING_GET_CURRENT_FRAME(handle); if (!packet_mmap_v3_acquire(h.h3)) { if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ goto again; } return pkts; } /* * This can conceivably process more than INT_MAX packets, * which would overflow the packet count, causing it either * to look like a negative number, and thus cause us to * return a value that looks like an error, or overflow * back into positive territory, and thus cause us to * return a too-low count. * * Therefore, if the packet count is unlimited, we clip * it at INT_MAX; this routine is not expected to * process packets indefinitely, so that's not an issue. */ if (PACKET_COUNT_IS_UNLIMITED(max_packets)) max_packets = INT_MAX; while (pkts < max_packets) { int packets_to_read; if (handlep->current_packet == NULL) { h.raw = RING_GET_CURRENT_FRAME(handle); if (!packet_mmap_v3_acquire(h.h3)) break; handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt; handlep->packets_left = h.h3->hdr.bh1.num_pkts; } packets_to_read = handlep->packets_left; if (packets_to_read > (max_packets - pkts)) { /* * There are more packets in the buffer than * the number of packets we have left to * process to get up to the maximum number * of packets to process. Only process enough * of them to get us up to that maximum. */ packets_to_read = max_packets - pkts; } while (packets_to_read-- && !handle->break_loop) { struct tpacket3_hdr* tp3_hdr = (struct tpacket3_hdr*) handlep->current_packet; ret = pcap_handle_packet_mmap( handle, callback, user, handlep->current_packet, tp3_hdr->tp_len, tp3_hdr->tp_mac, tp3_hdr->tp_snaplen, tp3_hdr->tp_sec, handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? tp3_hdr->tp_nsec : tp3_hdr->tp_nsec / 1000, VLAN_VALID(tp3_hdr, &tp3_hdr->hv1), tp3_hdr->hv1.tp_vlan_tci, VLAN_TPID(tp3_hdr, &tp3_hdr->hv1)); if (ret == 1) { pkts++; } else if (ret < 0) { handlep->current_packet = NULL; return ret; } handlep->current_packet += tp3_hdr->tp_next_offset; handlep->packets_left--; } if (handlep->packets_left <= 0) { /* * Hand this block back to the kernel, and, if * we're counting blocks that need to be * filtered in userland after having been * filtered by the kernel, count the one we've * just processed. */ packet_mmap_v3_release(h.h3); if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { /* * No more blocks need to be filtered * in userland. */ handlep->filter_in_userland = 0; } } /* next block */ if (++handle->offset >= handle->cc) handle->offset = 0; handlep->current_packet = NULL; } /* check for break loop condition*/ if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } } if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ goto again; } return pkts; } #endif /* HAVE_TPACKET3 */ /* * Attach the given BPF code to the packet capture device. */ static int pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter) { struct pcap_linux *handlep; struct sock_fprog fcode; int can_filter_in_kernel; int err = 0; int n, offset; if (!handle) return -1; if (!filter) { pcap_strlcpy(handle->errbuf, "setfilter: No filter specified", PCAP_ERRBUF_SIZE); return -1; } handlep = handle->priv; /* Make our private copy of the filter */ if (install_bpf_program(handle, filter) < 0) /* install_bpf_program() filled in errbuf */ return -1; /* * Run user level packet filter by default. Will be overridden if * installing a kernel filter succeeds. */ handlep->filter_in_userland = 1; /* Install kernel level filter if possible */ #ifdef USHRT_MAX if (handle->fcode.bf_len > USHRT_MAX) { /* * fcode.len is an unsigned short for current kernel. * I have yet to see BPF-Code with that much * instructions but still it is possible. So for the * sake of correctness I added this check. */ fprintf(stderr, "Warning: Filter too complex for kernel\n"); fcode.len = 0; fcode.filter = NULL; can_filter_in_kernel = 0; } else #endif /* USHRT_MAX */ { /* * Oh joy, the Linux kernel uses struct sock_fprog instead * of struct bpf_program and of course the length field is * of different size. Pointed out by Sebastian * * Oh, and we also need to fix it up so that all "ret" * instructions with non-zero operands have MAXIMUM_SNAPLEN * as the operand if we're not capturing in memory-mapped * mode, and so that, if we're in cooked mode, all memory- * reference instructions use special magic offsets in * references to the link-layer header and assume that the * link-layer payload begins at 0; "fix_program()" will do * that. */ switch (fix_program(handle, &fcode)) { case -1: default: /* * Fatal error; just quit. * (The "default" case shouldn't happen; we * return -1 for that reason.) */ return -1; case 0: /* * The program performed checks that we can't make * work in the kernel. */ can_filter_in_kernel = 0; break; case 1: /* * We have a filter that'll work in the kernel. */ can_filter_in_kernel = 1; break; } } /* * NOTE: at this point, we've set both the "len" and "filter" * fields of "fcode". As of the 2.6.32.4 kernel, at least, * those are the only members of the "sock_fprog" structure, * so we initialize every member of that structure. * * If there is anything in "fcode" that is not initialized, * it is either a field added in a later kernel, or it's * padding. * * If a new field is added, this code needs to be updated * to set it correctly. * * If there are no other fields, then: * * if the Linux kernel looks at the padding, it's * buggy; * * if the Linux kernel doesn't look at the padding, * then if some tool complains that we're passing * uninitialized data to the kernel, then the tool * is buggy and needs to understand that it's just * padding. */ if (can_filter_in_kernel) { if ((err = set_kernel_filter(handle, &fcode)) == 0) { /* * Installation succeeded - using kernel filter, * so userland filtering not needed. */ handlep->filter_in_userland = 0; } else if (err == -1) /* Non-fatal error */ { /* * Print a warning if we weren't able to install * the filter for a reason other than "this kernel * isn't configured to support socket filters. */ if (errno == ENOMEM) { /* * Either a kernel memory allocation * failure occurred, or there's too * much "other/option memory" allocated * for this socket. Suggest that they * increase the "other/option memory" * limit. */ fprintf(stderr, "Warning: Couldn't allocate kernel memory for filter: try increasing net.core.optmem_max with sysctl\n"); } else if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) { fprintf(stderr, "Warning: Kernel filter failed: %s\n", pcap_strerror(errno)); } } } /* * If we're not using the kernel filter, get rid of any kernel * filter that might've been there before, e.g. because the * previous filter could work in the kernel, or because some other * code attached a filter to the socket by some means other than * calling "pcap_setfilter()". Otherwise, the kernel filter may * filter out packets that would pass the new userland filter. */ if (handlep->filter_in_userland) { if (reset_kernel_filter(handle) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't remove kernel filter"); err = -2; /* fatal error */ } } /* * Free up the copy of the filter that was made by "fix_program()". */ if (fcode.filter != NULL) free(fcode.filter); if (err == -2) /* Fatal error */ return -1; /* * If we're filtering in userland, there's nothing to do; * the new filter will be used for the next packet. */ if (handlep->filter_in_userland) return 0; /* * We're filtering in the kernel; the packets present in * all blocks currently in the ring were already filtered * by the old filter, and so will need to be filtered in * userland by the new filter. * * Get an upper bound for the number of such blocks; first, * walk the ring backward and count the free blocks. */ offset = handle->offset; if (--offset < 0) offset = handle->cc - 1; for (n=0; n < handle->cc; ++n) { if (--offset < 0) offset = handle->cc - 1; if (pcap_get_ring_frame_status(handle, offset) != TP_STATUS_KERNEL) break; } /* * If we found free blocks, decrement the count of free * blocks by 1, just in case we lost a race with another * thread of control that was adding a packet while * we were counting and that had run the filter before * we changed it. * * XXX - could there be more than one block added in * this fashion? * * XXX - is there a way to avoid that race, e.g. somehow * wait for all packets that passed the old filter to * be added to the ring? */ if (n != 0) n--; /* * Set the count of blocks worth of packets to filter * in userland to the total number of blocks in the * ring minus the number of free blocks we found, and * turn on userland filtering. (The count of blocks * worth of packets to filter in userland is guaranteed * not to be zero - n, above, couldn't be set to a * value > handle->cc, and if it were equal to * handle->cc, it wouldn't be zero, and thus would * be decremented to handle->cc - 1.) */ handlep->blocks_to_filter_in_userland = handle->cc - n; handlep->filter_in_userland = 1; return 0; } /* * Return the index of the given device name. Fill ebuf and return * -1 on failure. */ static int iface_get_id(int fd, const char *device, char *ebuf) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "SIOCGIFINDEX"); return -1; } return ifr.ifr_ifindex; } /* * Bind the socket associated with FD to the given device. * Return 0 on success or a PCAP_ERROR_ value on a hard error. */ static int iface_bind(int fd, int ifindex, char *ebuf, int protocol) { struct sockaddr_ll sll; int ret, err; socklen_t errlen = sizeof(err); memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex < 0 ? 0 : ifindex; sll.sll_protocol = protocol; if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { if (errno == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return PCAP_ERROR_IFACE_NOT_UP; } if (errno == ENODEV) { /* * There's nothing more to say, so clear the * error message. */ ebuf[0] = '\0'; ret = PCAP_ERROR_NO_SUCH_DEVICE; } else { ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "bind"); } return ret; } /* Any pending errors, e.g., network is down? */ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "getsockopt (SO_ERROR)"); return PCAP_ERROR; } if (err == ENETDOWN) { /* * Return a "network down" indication, so that * the application can report that rather than * saying we had a mysterious failure and * suggest that they report a problem to the * libpcap developers. */ return PCAP_ERROR_IFACE_NOT_UP; } else if (err > 0) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, err, "bind"); return PCAP_ERROR; } return 0; } /* * Try to enter monitor mode. * If we have libnl, try to create a new monitor-mode device and * capture on that; otherwise, just say "not supported". */ #ifdef HAVE_LIBNL static int enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device) { struct pcap_linux *handlep = handle->priv; int ret; char phydev_path[PATH_MAX+1]; struct nl80211_state nlstate; struct ifreq ifr; u_int n; /* * Is this a mac80211 device? */ ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); if (ret < 0) return ret; /* error */ if (ret == 0) return 0; /* no error, but not mac80211 device */ /* * XXX - is this already a monN device? * If so, we're done. */ /* * OK, it's apparently a mac80211 device. * Try to find an unused monN device for it. */ ret = nl80211_init(handle, &nlstate, device); if (ret != 0) return ret; for (n = 0; n < UINT_MAX; n++) { /* * Try mon{n}. */ char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ snprintf(mondevice, sizeof mondevice, "mon%u", n); ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); if (ret == 1) { /* * Success. We don't clean up the libnl state * yet, as we'll be using it later. */ goto added; } if (ret < 0) { /* * Hard failure. Just return ret; handle->errbuf * has already been set. */ nl80211_cleanup(&nlstate); return ret; } } snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "%s: No free monN interfaces", device); nl80211_cleanup(&nlstate); return PCAP_ERROR; added: #if 0 /* * Sleep for .1 seconds. */ delay.tv_sec = 0; delay.tv_nsec = 500000000; nanosleep(&delay, NULL); #endif /* * If we haven't already done so, arrange to have * "pcap_close_all()" called when we exit. */ if (!pcap_do_addexit(handle)) { /* * "atexit()" failed; don't put the interface * in rfmon mode, just give up. */ del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } /* * Now configure the monitor interface up. */ memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't get flags for %s", device, handlep->mondevice); del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } ifr.ifr_flags |= IFF_UP|IFF_RUNNING; if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags for %s", device, handlep->mondevice); del_mon_if(handle, sock_fd, &nlstate, device, handlep->mondevice); nl80211_cleanup(&nlstate); return PCAP_ERROR; } /* * Success. Clean up the libnl state. */ nl80211_cleanup(&nlstate); /* * Note that we have to delete the monitor device when we close * the handle. */ handlep->must_do_on_close |= MUST_DELETE_MONIF; /* * Add this to the list of pcaps to close when we exit. */ pcap_add_to_pcaps_to_close(handle); return 1; } #else /* HAVE_LIBNL */ static int enter_rfmon_mode(pcap_t *handle _U_, int sock_fd _U_, const char *device _U_) { /* * We don't have libnl, so we can't do monitor mode. */ return 0; } #endif /* HAVE_LIBNL */ #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) /* * Map SOF_TIMESTAMPING_ values to PCAP_TSTAMP_ values. */ static const struct { int soft_timestamping_val; int pcap_tstamp_val; } sof_ts_type_map[3] = { { SOF_TIMESTAMPING_SOFTWARE, PCAP_TSTAMP_HOST }, { SOF_TIMESTAMPING_SYS_HARDWARE, PCAP_TSTAMP_ADAPTER }, { SOF_TIMESTAMPING_RAW_HARDWARE, PCAP_TSTAMP_ADAPTER_UNSYNCED } }; #define NUM_SOF_TIMESTAMPING_TYPES (sizeof sof_ts_type_map / sizeof sof_ts_type_map[0]) /* * Set the list of time stamping types to include all types. */ static int iface_set_all_ts_types(pcap_t *handle, char *ebuf) { u_int i; handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int)); if (handle->tstamp_type_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val; handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES; return 0; } /* * Get a list of time stamp types. */ #ifdef ETHTOOL_GET_TS_INFO static int iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf) { int fd; struct ifreq ifr; struct ethtool_ts_info info; int num_ts_types; u_int i, j; /* * This doesn't apply to the "any" device; you can't say "turn on * hardware time stamping for all devices that exist now and arrange * that it be turned on for any device that appears in the future", * and not all devices even necessarily *support* hardware time * stamping, so don't report any time stamp types. */ if (strcmp(device, "any") == 0) { handle->tstamp_type_list = NULL; return 0; } /* * Create a socket from which to fetch time stamping capabilities. */ fd = get_if_ioctl_socket(); if (fd < 0) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO)"); return -1; } memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GET_TS_INFO; ifr.ifr_data = (caddr_t)&info; if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { int save_errno = errno; close(fd); switch (save_errno) { case EOPNOTSUPP: case EINVAL: /* * OK, this OS version or driver doesn't support * asking for the time stamping types, so let's * just return all the possible types. */ if (iface_set_all_ts_types(handle, ebuf) == -1) return -1; return 0; case ENODEV: /* * OK, no such device. * The user will find that out when they try to * activate the device; just return an empty * list of time stamp types. */ handle->tstamp_type_list = NULL; return 0; default: /* * Other error. */ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, save_errno, "%s: SIOCETHTOOL(ETHTOOL_GET_TS_INFO) ioctl failed", device); return -1; } } close(fd); /* * Do we support hardware time stamping of *all* packets? */ if (!(info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))) { /* * No, so don't report any time stamp types. * * XXX - some devices either don't report * HWTSTAMP_FILTER_ALL when they do support it, or * report HWTSTAMP_FILTER_ALL but map it to only * time stamping a few PTP packets. See * http://marc.info/?l=linux-netdev&m=146318183529571&w=2 * * Maybe that got fixed later. */ handle->tstamp_type_list = NULL; return 0; } num_ts_types = 0; for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) num_ts_types++; } if (num_ts_types != 0) { handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int)); if (handle->tstamp_type_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) { handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val; j++; } } handle->tstamp_type_count = num_ts_types; } else handle->tstamp_type_list = NULL; return 0; } #else /* ETHTOOL_GET_TS_INFO */ static int iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf) { /* * This doesn't apply to the "any" device; you can't say "turn on * hardware time stamping for all devices that exist now and arrange * that it be turned on for any device that appears in the future", * and not all devices even necessarily *support* hardware time * stamping, so don't report any time stamp types. */ if (strcmp(device, "any") == 0) { handle->tstamp_type_list = NULL; return 0; } /* * We don't have an ioctl to use to ask what's supported, * so say we support everything. */ if (iface_set_all_ts_types(handle, ebuf) == -1) return -1; return 0; } #endif /* ETHTOOL_GET_TS_INFO */ #else /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ static int iface_get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_) { /* * Nothing to fetch, so it always "succeeds". */ return 0; } #endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ /* * Find out if we have any form of fragmentation/reassembly offloading. * * We do so using SIOCETHTOOL checking for various types of offloading; * if SIOCETHTOOL isn't defined, or we don't have any #defines for any * of the types of offloading, there's nothing we can do to check, so * we just say "no, we don't". * * We treat EOPNOTSUPP, EINVAL and, if eperm_ok is true, EPERM as * indications that the operation isn't supported. We do EPERM * weirdly because the SIOCETHTOOL code in later kernels 1) doesn't * support ETHTOOL_GUFO, 2) also doesn't include it in the list * of ethtool operations that don't require CAP_NET_ADMIN privileges, * and 3) does the "is this permitted" check before doing the "is * this even supported" check, so it fails with "this is not permitted" * rather than "this is not even supported". To work around this * annoyance, we only treat EPERM as an error for the first feature, * and assume that they all do the same permission checks, so if the * first one is allowed all the others are allowed if supported. */ #if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO)) static int iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname, int eperm_ok) { struct ifreq ifr; struct ethtool_value eval; memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); eval.cmd = cmd; eval.data = 0; ifr.ifr_data = (caddr_t)&eval; if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) { if (errno == EOPNOTSUPP || errno == EINVAL || (errno == EPERM && eperm_ok)) { /* * OK, let's just return 0, which, in our * case, either means "no, what we're asking * about is not enabled" or "all the flags * are clear (i.e., nothing is enabled)". */ return 0; } pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: SIOCETHTOOL(%s) ioctl failed", handle->opt.device, cmdname); return -1; } return eval.data; } /* * XXX - it's annoying that we have to check for offloading at all, but, * given that we have to, it's still annoying that we have to check for * particular types of offloading, especially that shiny new types of * offloading may be added - and, worse, may not be checkable with * a particular ETHTOOL_ operation; ETHTOOL_GFEATURES would, in * theory, give those to you, but the actual flags being used are * opaque (defined in a non-uapi header), and there doesn't seem to * be any obvious way to ask the kernel what all the offloading flags * are - at best, you can ask for a set of strings(!) to get *names* * for various flags. (That whole mechanism appears to have been * designed for the sole purpose of letting ethtool report flags * by name and set flags by name, with the names having no semantics * ethtool understands.) */ static int iface_get_offload(pcap_t *handle) { int ret; #ifdef ETHTOOL_GTSO ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO", 0); if (ret == -1) return -1; if (ret) return 1; /* TCP segmentation offloading on */ #endif #ifdef ETHTOOL_GGSO /* * XXX - will this cause large unsegmented packets to be * handed to PF_PACKET sockets on transmission? If not, * this need not be checked. */ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO", 0); if (ret == -1) return -1; if (ret) return 1; /* generic segmentation offloading on */ #endif #ifdef ETHTOOL_GFLAGS ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS", 0); if (ret == -1) return -1; if (ret & ETH_FLAG_LRO) return 1; /* large receive offloading on */ #endif #ifdef ETHTOOL_GGRO /* * XXX - will this cause large reassembled packets to be * handed to PF_PACKET sockets on receipt? If not, * this need not be checked. */ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO", 0); if (ret == -1) return -1; if (ret) return 1; /* generic (large) receive offloading on */ #endif #ifdef ETHTOOL_GUFO /* * Do this one last, as support for it was removed in later * kernels, and it fails with EPERM on those kernels rather * than with EOPNOTSUPP (see explanation in comment for * iface_ethtool_flag_ioctl()). */ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO", 1); if (ret == -1) return -1; if (ret) return 1; /* UDP fragmentation offloading on */ #endif return 0; } #else /* SIOCETHTOOL */ static int iface_get_offload(pcap_t *handle _U_) { /* * XXX - do we need to get this information if we don't * have the ethtool ioctls? If so, how do we do that? */ return 0; } #endif /* SIOCETHTOOL */ static struct dsa_proto { const char *name; bpf_u_int32 linktype; } dsa_protos[] = { /* * None is special and indicates that the interface does not have * any tagging protocol configured, and is therefore a standard * Ethernet interface. */ { "none", DLT_EN10MB }, { "brcm", DLT_DSA_TAG_BRCM }, { "brcm-prepend", DLT_DSA_TAG_BRCM_PREPEND }, { "dsa", DLT_DSA_TAG_DSA }, { "edsa", DLT_DSA_TAG_EDSA }, }; static int iface_dsa_get_proto_info(const char *device, pcap_t *handle) { char *pathstr; unsigned int i; /* * Make this significantly smaller than PCAP_ERRBUF_SIZE; * the tag *shouldn't* have some huge long name, and making * it smaller keeps newer versions of GCC from whining that * the error message if we don't support the tag could * overflow the error message buffer. */ char buf[128]; ssize_t r; int fd; fd = asprintf(&pathstr, "/sys/class/net/%s/dsa/tagging", device); if (fd < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, fd, "asprintf"); return PCAP_ERROR; } fd = open(pathstr, O_RDONLY); free(pathstr); /* * This is not fatal, kernel >= 4.20 *might* expose this attribute */ if (fd < 0) return 0; r = read(fd, buf, sizeof(buf) - 1); if (r <= 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "read"); close(fd); return PCAP_ERROR; } close(fd); /* * Buffer should be LF terminated. */ if (buf[r - 1] == '\n') r--; buf[r] = '\0'; for (i = 0; i < sizeof(dsa_protos) / sizeof(dsa_protos[0]); i++) { if (strlen(dsa_protos[i].name) == (size_t)r && strcmp(buf, dsa_protos[i].name) == 0) { handle->linktype = dsa_protos[i].linktype; switch (dsa_protos[i].linktype) { case DLT_EN10MB: return 0; default: return 1; } } } snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "unsupported DSA tag: %s", buf); return PCAP_ERROR; } /* * Query the kernel for the MTU of the given interface. */ static int iface_get_mtu(int fd, const char *device, char *ebuf) { struct ifreq ifr; if (!device) return BIGGER_THAN_ALL_MTUS; memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "SIOCGIFMTU"); return -1; } return ifr.ifr_mtu; } /* * Get the hardware type of the given interface as ARPHRD_xxx constant. */ static int iface_get_arptype(int fd, const char *device, char *ebuf) { struct ifreq ifr; int ret; memset(&ifr, 0, sizeof(ifr)); pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { if (errno == ENODEV) { /* * No such device. * * There's nothing more to say, so clear * the error message. */ ret = PCAP_ERROR_NO_SUCH_DEVICE; ebuf[0] = '\0'; } else { ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "SIOCGIFHWADDR"); } return ret; } return ifr.ifr_hwaddr.sa_family; } static int fix_program(pcap_t *handle, struct sock_fprog *fcode) { struct pcap_linux *handlep = handle->priv; size_t prog_size; register int i; register struct bpf_insn *p; struct bpf_insn *f; int len; /* * Make a copy of the filter, and modify that copy if * necessary. */ prog_size = sizeof(*handle->fcode.bf_insns) * handle->fcode.bf_len; len = handle->fcode.bf_len; f = (struct bpf_insn *)malloc(prog_size); if (f == NULL) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } memcpy(f, handle->fcode.bf_insns, prog_size); fcode->len = len; fcode->filter = (struct sock_filter *) f; for (i = 0; i < len; ++i) { p = &f[i]; /* * What type of instruction is this? */ switch (BPF_CLASS(p->code)) { case BPF_LD: case BPF_LDX: /* * It's a load instruction; is it loading * from the packet? */ switch (BPF_MODE(p->code)) { case BPF_ABS: case BPF_IND: case BPF_MSH: /* * Yes; are we in cooked mode? */ if (handlep->cooked) { /* * Yes, so we need to fix this * instruction. */ if (fix_offset(handle, p) < 0) { /* * We failed to do so. * Return 0, so our caller * knows to punt to userland. */ return 0; } } break; } break; } } return 1; /* we succeeded */ } static int fix_offset(pcap_t *handle, struct bpf_insn *p) { /* * Existing references to auxiliary data shouldn't be adjusted. * * Note that SKF_AD_OFF is negative, but p->k is unsigned, so * we use >= and cast SKF_AD_OFF to unsigned. */ if (p->k >= (bpf_u_int32)SKF_AD_OFF) return 0; if (handle->linktype == DLT_LINUX_SLL2) { /* * What's the offset? */ if (p->k >= SLL2_HDR_LEN) { /* * It's within the link-layer payload; that starts * at an offset of 0, as far as the kernel packet * filter is concerned, so subtract the length of * the link-layer header. */ p->k -= SLL2_HDR_LEN; } else if (p->k == 0) { /* * It's the protocol field; map it to the * special magic kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; } else if (p->k == 4) { /* * It's the ifindex field; map it to the * special magic kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_IFINDEX; } else if (p->k == 10) { /* * It's the packet type field; map it to the * special magic kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; } else if ((bpf_int32)(p->k) > 0) { /* * It's within the header, but it's not one of * those fields; we can't do that in the kernel, * so punt to userland. */ return -1; } } else { /* * What's the offset? */ if (p->k >= SLL_HDR_LEN) { /* * It's within the link-layer payload; that starts * at an offset of 0, as far as the kernel packet * filter is concerned, so subtract the length of * the link-layer header. */ p->k -= SLL_HDR_LEN; } else if (p->k == 0) { /* * It's the packet type field; map it to the * special magic kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; } else if (p->k == 14) { /* * It's the protocol field; map it to the * special magic kernel offset for that field. */ p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; } else if ((bpf_int32)(p->k) > 0) { /* * It's within the header, but it's not one of * those fields; we can't do that in the kernel, * so punt to userland. */ return -1; } } return 0; } static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode) { int total_filter_on = 0; int save_mode; int ret; int save_errno; /* * The socket filter code doesn't discard all packets queued * up on the socket when the filter is changed; this means * that packets that don't match the new filter may show up * after the new filter is put onto the socket, if those * packets haven't yet been read. * * This means, for example, that if you do a tcpdump capture * with a filter, the first few packets in the capture might * be packets that wouldn't have passed the filter. * * We therefore discard all packets queued up on the socket * when setting a kernel filter. (This isn't an issue for * userland filters, as the userland filtering is done after * packets are queued up.) * * To flush those packets, we put the socket in read-only mode, * and read packets from the socket until there are no more to * read. * * In order to keep that from being an infinite loop - i.e., * to keep more packets from arriving while we're draining * the queue - we put the "total filter", which is a filter * that rejects all packets, onto the socket before draining * the queue. * * This code deliberately ignores any errors, so that you may * get bogus packets if an error occurs, rather than having * the filtering done in userland even if it could have been * done in the kernel. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, &total_fcode, sizeof(total_fcode)) == 0) { char drain[1]; /* * Note that we've put the total filter onto the socket. */ total_filter_on = 1; /* * Save the socket's current mode, and put it in * non-blocking mode; we drain it by reading packets * until we get an error (which is normally a * "nothing more to be read" error). */ save_mode = fcntl(handle->fd, F_GETFL, 0); if (save_mode == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't get FD flags when changing filter"); return -2; } if (fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't set nonblocking mode when changing filter"); return -2; } while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0) ; save_errno = errno; if (save_errno != EAGAIN) { /* * Fatal error. * * If we can't restore the mode or reset the * kernel filter, there's nothing we can do. */ (void)fcntl(handle->fd, F_SETFL, save_mode); (void)reset_kernel_filter(handle); pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, save_errno, "recv failed when changing filter"); return -2; } if (fcntl(handle->fd, F_SETFL, save_mode) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't restore FD flags when changing filter"); return -2; } } /* * Now attach the new filter. */ ret = setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, fcode, sizeof(*fcode)); if (ret == -1 && total_filter_on) { /* * Well, we couldn't set that filter on the socket, * but we could set the total filter on the socket. * * This could, for example, mean that the filter was * too big to put into the kernel, so we'll have to * filter in userland; in any case, we'll be doing * filtering in userland, so we need to remove the * total filter so we see packets. */ save_errno = errno; /* * If this fails, we're really screwed; we have the * total filter on the socket, and it won't come off. * Report it as a fatal error. */ if (reset_kernel_filter(handle) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "can't remove kernel total filter"); return -2; /* fatal error */ } errno = save_errno; } return ret; } static int reset_kernel_filter(pcap_t *handle) { int ret; /* * setsockopt() barfs unless it get a dummy parameter. * valgrind whines unless the value is initialized, * as it has no idea that setsockopt() ignores its * parameter. */ int dummy = 0; ret = setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); /* * Ignore ENOENT - it means "we don't have a filter", so there * was no filter to remove, and there's still no filter. * * Also ignore ENONET, as a lot of kernel versions had a * typo where ENONET, rather than ENOENT, was returned. */ if (ret == -1 && errno != ENOENT && errno != ENONET) return -1; return 0; } int pcap_set_protocol_linux(pcap_t *p, int protocol) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); p->opt.protocol = protocol; return (0); } /* * Libpcap version string. */ const char * pcap_lib_version(void) { #if defined(HAVE_TPACKET3) return (PCAP_VERSION_STRING " (with TPACKET_V3)"); #else return (PCAP_VERSION_STRING " (with TPACKET_V2)"); #endif } diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c index 33204a54e045..2eb0fc8c02ae 100644 --- a/pcap-netfilter-linux.c +++ b/pcap-netfilter-linux.c @@ -1,793 +1,793 @@ /* * Copyright (c) 2011 Jakub Zawadzki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include #endif #include "pcap-int.h" #include "diag-control.h" #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* NOTE: if your program drops privileges after pcap_activate() it WON'T work with nfqueue. * It took me quite some time to debug ;/ * * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privileges, * and in nfqueue we need to send verdict reply after recving packet. * * In tcpdump you can disable dropping privileges with -Z root */ #include "pcap-netfilter-linux.h" #define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) #define NFLOG_IFACE "nflog" #define NFQUEUE_IFACE "nfqueue" typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t; /* * Private data for capturing on Linux netfilter sockets. */ struct pcap_netfilter { u_int packets_read; /* count of packets read with recvfrom() */ u_int packets_nobufs; /* ENOBUFS counter */ }; static int nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict); static int netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_netfilter *handlep = handle->priv; register u_char *bp, *ep; int count = 0; ssize_t len; /* * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ handle->break_loop = 0; return PCAP_ERROR_BREAK; } len = handle->cc; if (len == 0) { /* * The buffer is empty; refill it. * * We ignore EINTR, as that might just be due to a signal * being delivered - if the signal should interrupt the * loop, the signal handler should call pcap_breakloop() * to set handle->break_loop (we ignore it on other * platforms as well). */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } if (errno == ENOBUFS) handlep->packets_nobufs++; } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); if (len < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't receive packet"); return PCAP_ERROR; } bp = (unsigned char *)handle->buffer; } else bp = handle->bp; /* * Loop through each message. * * This assumes that a single buffer of message will have * <= INT_MAX packets, so the message count doesn't overflow. */ ep = bp + len; while (bp < ep) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp; uint32_t msg_len; nftype_t type = OTHER; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (handle->break_loop) { handle->bp = bp; handle->cc = (int)(ep - bp); if (count == 0) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } else return count; } /* * NLMSG_SPACE(0) might be signed or might be unsigned, * depending on whether the kernel defines NLMSG_ALIGNTO * as 4, which older kernels do, or as 4U, which newer * kernels do. * * ep - bp is of type ptrdiff_t, which is signed. * * To squelch warnings, we cast both to size_t, which * is unsigned; ep >= bp, so the cast is safe. */ if ((size_t)(ep - bp) < (size_t)NLMSG_SPACE(0)) { /* * There's less than one netlink message left * in the buffer. Give up. */ break; } if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) type = NFLOG; else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) type = NFQUEUE; if (type != OTHER) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; const struct nfgenmsg *nfg = NULL; int id = 0; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } nfg = NLMSG_DATA(nlh); if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(nfg); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { if (type == NFQUEUE) { switch (NFA_TYPE(attr)) { case NFQA_PACKET_HDR: { const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); id = ntohl(pkt_hdr->packet_id); break; } case NFQA_PAYLOAD: payload_attr = attr; break; } } else if (type == NFLOG) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, payload); count++; } } if (type == NFQUEUE) { /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, so nfg is always initialized to NLMSG_DATA(nlh). */ if (nfg != NULL) nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); /* * If the message length would run past the end of the * buffer, truncate it to the remaining space in the * buffer. * * To squelch warnings, we cast ep - bp to uint32_t, which * is unsigned and is the type of msg_len; ep >= bp, and * len should fit in 32 bits (either it's set from an int * or it's set from a recv() call with a buffer size that's * an int, and we're assuming either ILP32 or LP64), so * the cast is safe. */ if (msg_len > (uint32_t)(ep - bp)) msg_len = (uint32_t)(ep - bp); bp += msg_len; if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) { handle->bp = bp; handle->cc = (int)(ep - bp); if (handle->cc < 0) handle->cc = 0; return count; } } handle->cc = 0; return count; } static int netfilter_set_datalink(pcap_t *handle, int dlt) { handle->linktype = dlt; return 0; } static int netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) { struct pcap_netfilter *handlep = handle->priv; stats->ps_recv = handlep->packets_read; stats->ps_drop = handlep->packets_nobufs; stats->ps_ifdrop = 0; return 0; } static int netfilter_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Packet injection is not supported on netfilter devices"); return (-1); } struct my_nfattr { uint16_t nfa_len; uint16_t nfa_type; void *data; }; static int netfilter_send_config_msg(const pcap_t *handle, uint16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) { char buf[1024] __attribute__ ((aligned)); memset(buf, 0, sizeof(buf)); struct nlmsghdr *nlh = (struct nlmsghdr *) buf; struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); struct sockaddr_nl snl; static unsigned int seq_id; if (!seq_id) DIAG_OFF_NARROWING seq_id = time(NULL); DIAG_ON_NARROWING ++seq_id; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg)); nlh->nlmsg_type = msg_type; nlh->nlmsg_flags = NLM_F_REQUEST | (ack ? NLM_F_ACK : 0); nlh->nlmsg_pid = 0; /* to kernel */ nlh->nlmsg_seq = seq_id; nfg->nfgen_family = family; nfg->version = NFNETLINK_V0; nfg->res_id = htons(res_id); if (mynfa) { struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len)); nfa->nfa_type = mynfa->nfa_type; nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len); memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len); nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len); } memset(&snl, 0, sizeof(snl)); snl.nl_family = AF_NETLINK; if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1) return -1; if (!ack) return 0; /* waiting for reply loop */ do { socklen_t addrlen = sizeof(snl); int len; /* ignore interrupt system call error */ do { /* * The buffer is not so big that its size won't * fit into an int. */ len = (int)recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen); } while ((len == -1) && (errno == EINTR)); if (len <= 0) return len; if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) { errno = EINVAL; return -1; } nlh = (struct nlmsghdr *) buf; if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */ continue; while ((u_int)len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, (u_int)len)) { if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) { if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { errno = EBADMSG; return -1; } errno = -(*((int *)NLMSG_DATA(nlh))); return (errno == 0) ? 0 : -1; } nlh = NLMSG_NEXT(nlh, len); } } while (1); return -1; /* never here */ } static int nflog_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) { return netfilter_send_config_msg(handle, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, 1, family, group_id, mynfa); } static int nflog_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int8_t family) { struct nfulnl_msg_config_cmd msg; struct my_nfattr nfa; msg.command = cmd; nfa.data = &msg; nfa.nfa_type = NFULA_CFG_CMD; nfa.nfa_len = sizeof(msg); return nflog_send_config_msg(handle, family, group_id, &nfa); } static int nflog_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) { struct nfulnl_msg_config_mode msg; struct my_nfattr nfa; msg.copy_range = htonl(copy_range); msg.copy_mode = copy_mode; nfa.data = &msg; nfa.nfa_type = NFULA_CFG_MODE; nfa.nfa_len = sizeof(msg); return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict) { struct nfqnl_msg_verdict_hdr msg; struct my_nfattr nfa; msg.id = htonl(id); msg.verdict = htonl(verdict); nfa.data = &msg; nfa.nfa_type = NFQA_VERDICT_HDR; nfa.nfa_len = sizeof(msg); return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT, 0, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) { return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG, 1, family, group_id, mynfa); } static int nfqueue_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int16_t pf) { struct nfqnl_msg_config_cmd msg; struct my_nfattr nfa; msg.command = cmd; msg.pf = htons(pf); nfa.data = &msg; nfa.nfa_type = NFQA_CFG_CMD; nfa.nfa_len = sizeof(msg); return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int nfqueue_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) { struct nfqnl_msg_config_params msg; struct my_nfattr nfa; msg.copy_range = htonl(copy_range); msg.copy_mode = copy_mode; nfa.data = &msg; nfa.nfa_type = NFQA_CFG_PARAMS; nfa.nfa_len = sizeof(msg); return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); } static int netfilter_activate(pcap_t* handle) { const char *dev = handle->opt.device; unsigned short groups[32]; int group_count = 0; nftype_t type = OTHER; int i; - if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { - dev += strlen(NFLOG_IFACE); + if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { + dev += strlen(NFLOG_IFACE); type = NFLOG; } else if (strncmp(dev, NFQUEUE_IFACE, strlen(NFQUEUE_IFACE)) == 0) { dev += strlen(NFQUEUE_IFACE); type = NFQUEUE; } if (type != OTHER && *dev == ':') { dev++; while (*dev) { long int group_id; char *end_dev; if (group_count == 32) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Maximum 32 netfilter groups! dev: %s", handle->opt.device); return PCAP_ERROR; } group_id = strtol(dev, &end_dev, 0); if (end_dev != dev) { if (group_id < 0 || group_id > 65535) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Netfilter group range from 0 to 65535 (got %ld)", group_id); return PCAP_ERROR; } groups[group_count++] = (unsigned short) group_id; dev = end_dev; } if (*dev != ',') break; dev++; } } if (type == OTHER || *dev) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get netfilter group(s) index from %s", handle->opt.device); return PCAP_ERROR; } /* if no groups, add default: 0 */ if (!group_count) { groups[0] = 0; group_count = 1; } /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) handle->snapshot = MAXIMUM_SNAPLEN; /* Initialize some components of the pcap structure. */ handle->bufsize = 128 + handle->snapshot; handle->offset = 0; handle->read_op = netfilter_read_linux; handle->inject_op = netfilter_inject_linux; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = NULL; handle->set_datalink_op = netfilter_set_datalink; handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->stats_op = netfilter_stats_linux; /* Create netlink socket */ handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (handle->fd < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't create raw socket"); return PCAP_ERROR; } if (type == NFLOG) { handle->linktype = DLT_NFLOG; handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); if (handle->dlt_list != NULL) { handle->dlt_list[0] = DLT_NFLOG; handle->dlt_list[1] = DLT_IPV4; handle->dlt_count = 2; } } else handle->linktype = DLT_IPV4; handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't allocate dump buffer"); goto close_fail; } if (type == NFLOG) { if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFULNL_CFG_CMD_PF_UNBIND"); goto close_fail; } if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFULNL_CFG_CMD_PF_BIND"); goto close_fail; } /* Bind socket to the nflog groups */ for (i = 0; i < group_count; i++) { if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't listen on group index"); goto close_fail; } if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFULNL_COPY_PACKET"); goto close_fail; } } } else { if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_UNBIND"); goto close_fail; } if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_BIND"); goto close_fail; } /* Bind socket to the nfqueue groups */ for (i = 0; i < group_count; i++) { if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't listen on group index"); goto close_fail; } if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "NFQNL_COPY_PACKET"); goto close_fail; } } } if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to netfilter devices. */ pcap_cleanup_live_common(handle); return PCAP_ERROR_RFMON_NOTSUP; } if (handle->opt.buffer_size != 0) { /* * Set the socket buffer size to the specified value. */ if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "SO_RCVBUF"); goto close_fail; } } handle->selectable_fd = handle->fd; return 0; close_fail: pcap_cleanup_live_common(handle); return PCAP_ERROR; } pcap_t * netfilter_create(const char *device, char *ebuf, int *is_ours) { const char *cp; pcap_t *p; /* Does this look like an netfilter device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */ if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0) cp += sizeof NFLOG_IFACE - 1; else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0) cp += sizeof NFQUEUE_IFACE - 1; else { /* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */ *is_ours = 0; return NULL; } /* * Yes - is that either the end of the name, or is it followed * by a colon? */ if (*cp != ':' && *cp != '\0') { /* Nope */ *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = PCAP_CREATE_COMMON(ebuf, struct pcap_netfilter); if (p == NULL) return (NULL); p->activate_op = netfilter_activate; return (p); } int netfilter_findalldevs(pcap_if_list_t *devlistp, char *err_str) { int sock; sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (sock < 0) { /* if netlink is not supported this is not fatal */ if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) return 0; pcap_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, errno, "Can't open netlink socket"); return -1; } close(sock); /* * The notion of "connected" vs. "disconnected" doesn't apply. * XXX - what about "up" and "running"? */ if (add_dev(devlistp, NFLOG_IFACE, PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "Linux netfilter log (NFLOG) interface", err_str) == NULL) return -1; if (add_dev(devlistp, NFQUEUE_IFACE, PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "Linux netfilter queue (NFQUEUE) interface", err_str) == NULL) return -1; return 0; } diff --git a/pcap-npf.c b/pcap-npf.c index 62c526d923ad..99b5981e5a57 100644 --- a/pcap-npf.c +++ b/pcap-npf.c @@ -1,2749 +1,2749 @@ /* * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include /* for INT_MAX */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include #include #include /* * XXX - Packet32.h defines bpf_program, so we can't include * , which also defines it; that's why we define * PCAP_DONT_INCLUDE_PCAP_BPF_H, * * However, no header in the WinPcap or Npcap SDKs defines the * macros for BPF code, so we have to define them ourselves. */ #define BPF_RET 0x06 #define BPF_K 0x00 /* Old-school MinGW have these headers in a different place. */ #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) #include #include #else #include /* MSVC/TDM-MinGW/MinGW64 */ #endif #ifdef HAVE_DAG_API #include #include #endif /* HAVE_DAG_API */ #include "diag-control.h" #include "pcap-airpcap.h" static int pcap_setfilter_npf(pcap_t *, struct bpf_program *); static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); static int pcap_getnonblock_npf(pcap_t *); static int pcap_setnonblock_npf(pcap_t *, int); /*dimension of the buffer in the pcap_t structure*/ #define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 /*dimension of the buffer in the kernel driver NPF */ #define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 /* Equivalent to ntohs(), but a lot faster under Windows */ #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) /* * Private data for capturing on WinPcap/Npcap devices. */ struct pcap_win { ADAPTER *adapter; /* the packet32 ADAPTER for the device */ int nonblock; int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ int filtering_in_kernel; /* using kernel filter */ #ifdef HAVE_DAG_API int dag_fcs_bits; /* Number of checksum bits from link layer */ #endif #ifdef ENABLE_REMOTE int samp_npkt; /* parameter needed for sampling, with '1 out of N' method has been requested */ struct timeval samp_time; /* parameter needed for sampling, with '1 every N ms' method has been requested */ #endif }; /* * Define stub versions of the monitor-mode support routines if this * isn't Npcap. HAVE_NPCAP_PACKET_API is defined by Npcap but not * WinPcap. */ #ifndef HAVE_NPCAP_PACKET_API static int PacketIsMonitorModeSupported(PCHAR AdapterName _U_) { /* * We don't support monitor mode. */ return (0); } static int PacketSetMonitorMode(PCHAR AdapterName _U_, int mode _U_) { /* * This should never be called, as PacketIsMonitorModeSupported() * will return 0, meaning "we don't support monitor mode, so * don't try to turn it on or off". */ return (0); } static int PacketGetMonitorMode(PCHAR AdapterName _U_) { /* * This should fail, so that pcap_activate_npf() returns * PCAP_ERROR_RFMON_NOTSUP if our caller requested monitor * mode. */ return (-1); } #endif /* * Sigh. PacketRequest() will have made a DeviceIoControl() * call to the NPF driver to perform the OID request, with a * BIOCQUERYOID ioctl. The kernel code should get back one * of NDIS_STATUS_INVALID_OID, NDIS_STATUS_NOT_SUPPORTED, * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't * supported by the OS or the driver, but that doesn't seem * to make it to the caller of PacketRequest() in a * reliable fashion. */ #define NDIS_STATUS_INVALID_OID 0xc0010017 #define NDIS_STATUS_NOT_SUPPORTED 0xc00000bb /* STATUS_NOT_SUPPORTED */ #define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 static int oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, char *errbuf) { PACKET_OID_DATA *oid_data_arg; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). * It should be big enough to hold "*lenp" bytes of data; it * will actually be slightly larger, as PACKET_OID_DATA has a * 1-byte data array at the end, standing in for the variable-length * data that's actually there. */ oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); if (oid_data_arg == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Couldn't allocate argument buffer for PacketRequest"); return (PCAP_ERROR); } /* * No need to copy the data - we're doing a fetch. */ oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ if (!PacketRequest(adapter, FALSE, oid_data_arg)) { pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (-1); } /* * Get the length actually supplied. */ *lenp = oid_data_arg->Length; /* * Copy back the data we fetched. */ memcpy(data, oid_data_arg->Data, *lenp); free(oid_data_arg); return (0); } static int pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) { struct pcap_win *pw = p->priv; struct bpf_stat bstats; /* * Try to get statistics. * * (Please note - "struct pcap_stat" is *not* the same as * WinPcap's "struct bpf_stat". It might currently have the * same layout, but let's not cheat. * * Note also that we don't fill in ps_capt, as we might have * been called by code compiled against an earlier version of * WinPcap that didn't have ps_capt, in which case filling it * in would stomp on whatever comes after the structure passed * to us. */ if (!PacketGetStats(pw->adapter, &bstats)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketGetStats error"); return (-1); } ps->ps_recv = bstats.bs_recv; ps->ps_drop = bstats.bs_drop; /* * XXX - PacketGetStats() doesn't fill this in, so we just * return 0. */ #if 0 ps->ps_ifdrop = bstats.ps_ifdrop; #else ps->ps_ifdrop = 0; #endif return (0); } /* * Win32-only routine for getting statistics. * * This way is definitely safer than passing the pcap_stat * from the userland. * In fact, there could happen than the user allocates a variable which is not * big enough for the new structure, and the library will write in a zone * which is not allocated to this variable. * * In this way, we're pretty sure we are writing on memory allocated to this * variable. * * XXX - but this is the wrong way to handle statistics. Instead, we should * have an API that returns data in a form like the Options section of a * pcapng Interface Statistics Block: * * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6 * * which would let us add new statistics straightforwardly and indicate which * statistics we are and are *not* providing, rather than having to provide * possibly-bogus values for statistics we can't provide. */ static struct pcap_stat * pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) { struct pcap_win *pw = p->priv; struct bpf_stat bstats; *pcap_stat_size = sizeof (p->stat); /* * Try to get statistics. * * (Please note - "struct pcap_stat" is *not* the same as * WinPcap's "struct bpf_stat". It might currently have the * same layout, but let's not cheat.) */ if (!PacketGetStatsEx(pw->adapter, &bstats)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketGetStatsEx error"); return (NULL); } p->stat.ps_recv = bstats.bs_recv; p->stat.ps_drop = bstats.bs_drop; p->stat.ps_ifdrop = bstats.ps_ifdrop; /* * Just in case this is ever compiled for a target other than * Windows, which is somewhere between extremely unlikely and * impossible. */ #ifdef _WIN32 p->stat.ps_capt = bstats.bs_capt; #endif return (&p->stat); } /* Set the dimension of the kernel-level capture buffer */ static int pcap_setbuff_npf(pcap_t *p, int dim) { struct pcap_win *pw = p->priv; if(PacketSetBuff(pw->adapter,dim)==FALSE) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); return (-1); } return (0); } /* Set the driver working mode */ static int pcap_setmode_npf(pcap_t *p, int mode) { struct pcap_win *pw = p->priv; if(PacketSetMode(pw->adapter,mode)==FALSE) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); return (-1); } return (0); } /*set the minimum amount of data that will release a read call*/ static int pcap_setmintocopy_npf(pcap_t *p, int size) { struct pcap_win *pw = p->priv; if(PacketSetMinToCopy(pw->adapter, size)==FALSE) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); return (-1); } return (0); } static HANDLE pcap_getevent_npf(pcap_t *p) { struct pcap_win *pw = p->priv; return (PacketGetReadEvent(pw->adapter)); } static int pcap_oid_get_request_npf(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) { struct pcap_win *pw = p->priv; return (oid_get_request(pw->adapter, oid, data, lenp, p->errbuf)); } static int pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp) { struct pcap_win *pw = p->priv; PACKET_OID_DATA *oid_data_arg; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). * It should be big enough to hold "*lenp" bytes of data; it * will actually be slightly larger, as PACKET_OID_DATA has a * 1-byte data array at the end, standing in for the variable-length * data that's actually there. */ oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); if (oid_data_arg == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Couldn't allocate argument buffer for PacketRequest"); return (PCAP_ERROR); } oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ memcpy(oid_data_arg->Data, data, *lenp); if (!PacketRequest(pw->adapter, TRUE, oid_data_arg)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (PCAP_ERROR); } /* * Get the length actually copied. */ *lenp = oid_data_arg->Length; /* * No need to copy the data - we're doing a set. */ free(oid_data_arg); return (0); } static u_int pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) { struct pcap_win *pw = p->priv; u_int res; res = PacketSendPackets(pw->adapter, queue->buffer, queue->len, (BOOLEAN)sync); if(res != queue->len){ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error queueing packets"); } return (res); } static int pcap_setuserbuffer_npf(pcap_t *p, int size) { unsigned char *new_buff; if (size<=0) { /* Bogus parameter */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error: invalid size %d",size); return (-1); } /* Allocate the buffer */ new_buff=(unsigned char*)malloc(sizeof(char)*size); if (!new_buff) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error: not enough memory"); return (-1); } free(p->buffer); p->buffer=new_buff; p->bufsize=size; return (0); } #ifdef HAVE_NPCAP_PACKET_API /* * Kernel dump mode isn't supported in Npcap; calls to PacketSetDumpName(), * PacketSetDumpLimits(), and PacketIsDumpEnded() will get compile-time * deprecation warnings. * * Avoid calling them; just return errors indicating that kernel dump * mode isn't supported in Npcap. */ static int pcap_live_dump_npf(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Npcap doesn't support kernel dump mode"); return (-1); } static int pcap_live_dump_ended_npf(pcap_t *p, int sync) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Npcap doesn't support kernel dump mode"); return (-1); } #else /* HAVE_NPCAP_PACKET_API */ static int pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks) { struct pcap_win *pw = p->priv; BOOLEAN res; /* Set the packet driver in dump mode */ res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP); if(res == FALSE){ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error setting dump mode"); return (-1); } /* Set the name of the dump file */ res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename)); if(res == FALSE){ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error setting kernel dump file name"); return (-1); } /* Set the limits of the dump file */ res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks); if(res == FALSE) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error setting dump limit"); return (-1); } return (0); } static int pcap_live_dump_ended_npf(pcap_t *p, int sync) { struct pcap_win *pw = p->priv; return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync)); } #endif /* HAVE_NPCAP_PACKET_API */ #ifdef HAVE_AIRPCAP_API static PAirpcapHandle pcap_get_airpcap_handle_npf(pcap_t *p) { struct pcap_win *pw = p->priv; return (PacketGetAirPcapHandle(pw->adapter)); } #else /* HAVE_AIRPCAP_API */ static PAirpcapHandle pcap_get_airpcap_handle_npf(pcap_t *p _U_) { return (NULL); } #endif /* HAVE_AIRPCAP_API */ static int pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { PACKET Packet; int cc; int n; register u_char *bp, *ep; u_char *datap; struct pcap_win *pw = p->priv; cc = p->cc; if (cc == 0) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ p->break_loop = 0; return (PCAP_ERROR_BREAK); } /* * Capture the packets. * * The PACKET structure had a bunch of extra stuff for * Windows 9x/Me, but the only interesting data in it * in the versions of Windows that we support is just * a copy of p->buffer, a copy of p->buflen, and the * actual number of bytes read returned from * PacketReceivePacket(), none of which has to be * retained from call to call, so we just keep one on * the stack. */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { /* * Did the device go away? * If so, the error we get can either be * ERROR_GEN_FAILURE or ERROR_DEVICE_REMOVED. */ DWORD errcode = GetLastError(); if (errcode == ERROR_GEN_FAILURE || errcode == ERROR_DEVICE_REMOVED) { /* * The device on which we're capturing * went away, or it became unusable * by NPF due to a suspend/resume. * * ERROR_GEN_FAILURE comes from * STATUS_UNSUCCESSFUL, as well as some * other NT status codes that the Npcap * driver is unlikely to return. * XXX - hopefully no other error * conditions are indicated by this. * * ERROR_DEVICE_REMOVED comes from * STATUS_DEVICE_REMOVED. * * We report the Windows status code * name and the corresponding NT status * code name, for the benefit of attempts * to debug cases where this error is * reported when the device *wasn't* * removed, either because it's not * removable, it's removable but wasn't * removed, or it's a device that doesn't * correspond to a physical device. * * XXX - we really should return an * appropriate error for that, but * pcap_dispatch() etc. aren't * documented as having error returns * other than PCAP_ERROR or PCAP_ERROR_BREAK. */ const char *errcode_msg; if (errcode == ERROR_GEN_FAILURE) errcode_msg = "ERROR_GEN_FAILURE/STATUS_UNSUCCESSFUL"; else errcode_msg = "ERROR_DEVICE_REMOVED/STATUS_DEVICE_REMOVED"; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The interface disappeared (error code %s)", errcode_msg); } else { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, errcode, "PacketReceivePacket error"); } return (PCAP_ERROR); } cc = Packet.ulBytesReceived; bp = p->buffer; } else bp = p->bp; /* * Loop through each packet. * * This assumes that a single buffer of packets will have * <= INT_MAX packets, so the packet count doesn't overflow. */ #define bhp ((struct bpf_hdr *)bp) n = 0; ep = bp + cc; for (;;) { register u_int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (PCAP_ERROR_BREAK); } else { p->bp = bp; p->cc = (int) (ep - bp); return (n); } } if (bp >= ep) break; caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; datap = bp + hdrlen; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now - we already know * the packet passed the filter. * * XXX - pcap_filter() should always return TRUE if * handed a null pointer for the program, but it might * just try to "run" the filter, so we check here. */ if (pw->filtering_in_kernel || p->fcode.bf_insns == NULL || pcap_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { #ifdef ENABLE_REMOTE switch (p->rmt_samp.method) { case PCAP_SAMP_1_EVERY_N: pw->samp_npkt = (pw->samp_npkt + 1) % p->rmt_samp.value; /* Discard all packets that are not '1 out of N' */ if (pw->samp_npkt != 0) { bp += Packet_WORDALIGN(caplen + hdrlen); continue; } break; case PCAP_SAMP_FIRST_AFTER_N_MS: { struct pcap_pkthdr *pkt_header = (struct pcap_pkthdr*) bp; /* * Check if the timestamp of the arrived * packet is smaller than our target time. */ if (pkt_header->ts.tv_sec < pw->samp_time.tv_sec || (pkt_header->ts.tv_sec == pw->samp_time.tv_sec && pkt_header->ts.tv_usec < pw->samp_time.tv_usec)) { bp += Packet_WORDALIGN(caplen + hdrlen); continue; } /* * The arrived packet is suitable for being * delivered to our caller, so let's update * the target time. */ pw->samp_time.tv_usec = pkt_header->ts.tv_usec + p->rmt_samp.value * 1000; if (pw->samp_time.tv_usec > 1000000) { pw->samp_time.tv_sec = pkt_header->ts.tv_sec + pw->samp_time.tv_usec / 1000000; pw->samp_time.tv_usec = pw->samp_time.tv_usec % 1000000; } } } #endif /* ENABLE_REMOTE */ /* * XXX A bpf_hdr matches a pcap_pkthdr. */ (*callback)(user, (struct pcap_pkthdr*)bp, datap); bp += Packet_WORDALIGN(caplen + hdrlen); if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = bp; p->cc = (int) (ep - bp); return (n); } } else { /* * Skip this packet. */ bp += Packet_WORDALIGN(caplen + hdrlen); } } #undef bhp p->cc = 0; return (n); } #ifdef HAVE_DAG_API static int pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_win *pw = p->priv; PACKET Packet; u_char *dp = NULL; int packet_len = 0, caplen = 0; struct pcap_pkthdr pcap_header; u_char *endofbuf; int n = 0; dag_record_t *header; unsigned erf_record_len; ULONGLONG ts; int cc; unsigned swt; unsigned dfp = pw->adapter->DagFastProcess; cc = p->cc; if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ { /* * Get new packets from the network. * * The PACKET structure had a bunch of extra stuff for * Windows 9x/Me, but the only interesting data in it * in the versions of Windows that we support is just * a copy of p->buffer, a copy of p->buflen, and the * actual number of bytes read returned from * PacketReceivePacket(), none of which has to be * retained from call to call, so we just keep one on * the stack. */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); return (-1); } cc = Packet.ulBytesReceived; if(cc == 0) /* The timeout has expired but we no packets arrived */ return (0); header = (dag_record_t*)pw->adapter->DagBuffer; } else header = (dag_record_t*)p->bp; endofbuf = (char*)header + cc; /* * This can conceivably process more than INT_MAX packets, * which would overflow the packet count, causing it either * to look like a negative number, and thus cause us to * return a value that looks like an error, or overflow * back into positive territory, and thus cause us to * return a too-low count. * * Therefore, if the packet count is unlimited, we clip * it at INT_MAX; this routine is not expected to * process packets indefinitely, so that's not an issue. */ if (PACKET_COUNT_IS_UNLIMITED(cnt)) cnt = INT_MAX; /* * Cycle through the packets */ do { erf_record_len = SWAPS(header->rlen); if((char*)header + erf_record_len > endofbuf) break; /* Increase the number of captured packets */ p->stat.ps_recv++; /* Find the beginning of the packet */ dp = ((u_char *)header) + dag_record_size; /* Determine actual packet len */ switch(header->type) { case TYPE_ATM: packet_len = ATM_SNAPLEN; caplen = ATM_SNAPLEN; dp += 4; break; case TYPE_ETH: swt = SWAPS(header->wlen); packet_len = swt - (pw->dag_fcs_bits); caplen = erf_record_len - dag_record_size - 2; if (caplen > packet_len) { caplen = packet_len; } dp += 2; break; case TYPE_HDLC_POS: swt = SWAPS(header->wlen); packet_len = swt - (pw->dag_fcs_bits); caplen = erf_record_len - dag_record_size; if (caplen > packet_len) { caplen = packet_len; } break; } if(caplen > p->snapshot) caplen = p->snapshot; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = (char*)header; p->cc = endofbuf - (char*)header; return (n); } } if(!dfp) { /* convert between timestamp formats */ ts = header->ts; pcap_header.ts.tv_sec = (int)(ts >> 32); ts = (ts & 0xffffffffi64) * 1000000; ts += 0x80000000; /* rounding */ pcap_header.ts.tv_usec = (int)(ts >> 32); if (pcap_header.ts.tv_usec >= 1000000) { pcap_header.ts.tv_usec -= 1000000; pcap_header.ts.tv_sec++; } } /* No underlying filtering system. We need to filter on our own */ if (p->fcode.bf_insns) { if (pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) { /* Move to next packet */ header = (dag_record_t*)((char*)header + erf_record_len); continue; } } /* Fill the header for the user supplied callback function */ pcap_header.caplen = caplen; pcap_header.len = packet_len; /* Call the callback function */ (*callback)(user, &pcap_header, dp); /* Move to next packet */ header = (dag_record_t*)((char*)header + erf_record_len); /* Stop if the number of packets requested by user has been reached*/ if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = (char*)header; p->cc = endofbuf - (char*)header; return (n); } } while((u_char*)header < endofbuf); return (1); } #endif /* HAVE_DAG_API */ /* Send a packet to the network */ static int pcap_inject_npf(pcap_t *p, const void *buf, int size) { struct pcap_win *pw = p->priv; PACKET pkt; PacketInitPacket(&pkt, (PVOID)buf, size); if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "send error: PacketSendPacket failed"); return (-1); } /* * We assume it all got sent if "PacketSendPacket()" succeeded. * "pcap_inject()" is expected to return the number of bytes * sent. */ return (size); } static void pcap_cleanup_npf(pcap_t *p) { struct pcap_win *pw = p->priv; if (pw->adapter != NULL) { PacketCloseAdapter(pw->adapter); pw->adapter = NULL; } if (pw->rfmon_selfstart) { PacketSetMonitorMode(p->opt.device, 0); } pcap_cleanup_live_common(p); } static void pcap_breakloop_npf(pcap_t *p) { pcap_breakloop_common(p); struct pcap_win *pw = p->priv; /* XXX - what if this fails? */ SetEvent(PacketGetReadEvent(pw->adapter)); } /* * These are NTSTATUS values: * * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781 * * with the "Customer" bit set. If a driver returns them, they are not * mapped to Windows error values in userland; they're returned by * GetLastError(). * * Note that "driver" here includes the Npcap NPF driver, as various * versions would take NT status values and set the "Customer" bit * before returning the status code. The commit message for the * change that started doing that is * * Returned a customer-defined NTSTATUS in OID requests to avoid * NTSTATUS-to-Win32 Error code translation. * * but I don't know why the goal was to avoid that translation. * * Attempting to set the hardware filter on a Microsoft Surface Pro's * Mobile Broadband Adapter returns an error that appears to be * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's * probably indicating that it doesn't support that. * * It is likely that there are other devices which throw spurious errors, * at which point this will need refactoring to efficiently check against * a list, but for now we can just check this one value. Perhaps the * right way to do this is compare against various NDIS errors with * the "customer" bit ORed in. */ #define NT_STATUS_CUSTOMER_DEFINED 0x20000000 static int pcap_activate_npf(pcap_t *p) { struct pcap_win *pw = p->priv; NetType type; int res; int status = 0; struct bpf_insn total_insn; struct bpf_program total_prog; if (p->opt.rfmon) { /* * Monitor mode is supported on Windows Vista and later. */ if (PacketGetMonitorMode(p->opt.device) == 1) { pw->rfmon_selfstart = 0; } else { if ((res = PacketSetMonitorMode(p->opt.device, 1)) != 1) { pw->rfmon_selfstart = 0; // Monitor mode is not supported. if (res == 0) { return PCAP_ERROR_RFMON_NOTSUP; } else { return PCAP_ERROR; } } else { pw->rfmon_selfstart = 1; } } } /* Init Winsock if it hasn't already been initialized */ pcap_wsockinit(); pw->adapter = PacketOpenAdapter(p->opt.device); if (pw->adapter == NULL) { DWORD errcode = GetLastError(); /* * What error did we get when trying to open the adapter? */ switch (errcode) { case ERROR_BAD_UNIT: /* * There's no such device. * There's nothing to add, so clear the error * message. */ p->errbuf[0] = '\0'; return (PCAP_ERROR_NO_SUCH_DEVICE); case ERROR_ACCESS_DENIED: /* * There is, but we don't have permission to * use it. * * XXX - we currently get ERROR_BAD_UNIT if the * user says "no" to the UAC prompt. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The helper program for \"Admin-only Mode\" must be allowed to make changes to your device"); return (PCAP_ERROR_PERM_DENIED); default: /* * Unknown - report details. */ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, errcode, "Error opening adapter"); if (pw->rfmon_selfstart) { PacketSetMonitorMode(p->opt.device, 0); } return (PCAP_ERROR); } } /*get network type*/ if(PacketGetNetType (pw->adapter,&type) == FALSE) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Cannot determine the network type"); goto bad; } /*Set the linktype*/ switch (type.LinkType) { /* * NDIS-defined medium types. */ case NdisMedium802_3: p->linktype = DLT_EN10MB; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } break; case NdisMedium802_5: /* * Token Ring. */ p->linktype = DLT_IEEE802; break; case NdisMediumFddi: p->linktype = DLT_FDDI; break; case NdisMediumWan: p->linktype = DLT_EN10MB; break; case NdisMediumArcnetRaw: p->linktype = DLT_ARCNET; break; case NdisMediumArcnet878_2: p->linktype = DLT_ARCNET; break; case NdisMediumAtm: p->linktype = DLT_ATM_RFC1483; break; case NdisMediumWirelessWan: p->linktype = DLT_RAW; break; case NdisMediumIP: p->linktype = DLT_RAW; break; /* * Npcap-defined medium types. */ case NdisMediumNull: p->linktype = DLT_NULL; break; case NdisMediumCHDLC: p->linktype = DLT_CHDLC; break; case NdisMediumPPPSerial: p->linktype = DLT_PPP_SERIAL; break; case NdisMediumBare80211: p->linktype = DLT_IEEE802_11; break; case NdisMediumRadio80211: p->linktype = DLT_IEEE802_11_RADIO; break; case NdisMediumPpi: p->linktype = DLT_PPI; break; default: /* * An unknown medium type is assumed to supply Ethernet * headers; if not, the user will have to report it, * so that the medium type and link-layer header type * can be determined. If we were to fail here, we * might get the link-layer type in the error, but * the user wouldn't get a capture, so we wouldn't * be able to determine the link-layer type; we report * a warning with the link-layer type, so at least * some programs will report the warning. */ p->linktype = DLT_EN10MB; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Unknown NdisMedium value %d, defaulting to DLT_EN10MB", type.LinkType); status = PCAP_WARNING; break; } #ifdef HAVE_PACKET_GET_TIMESTAMP_MODES /* * Set the timestamp type. * (Yes, we require PacketGetTimestampModes(), not just * PacketSetTimestampMode(). If we have the former, we * have the latter, unless somebody's using a version * of Npcap that they've hacked to provide the former * but not the latter; if they've done that, either * they're confused or they're trolling us.) */ switch (p->opt.tstamp_type) { case PCAP_TSTAMP_HOST_HIPREC_UNSYNCED: /* * Better than low-res, but *not* synchronized with * the OS clock. */ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_SINGLE_SYNCHRONIZATION)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_SINGLE_SYNCHRONIZATION"); goto bad; } break; case PCAP_TSTAMP_HOST_LOWPREC: /* * Low-res, but synchronized with the OS clock. */ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME"); goto bad; } break; case PCAP_TSTAMP_HOST_HIPREC: /* * High-res, and synchronized with the OS clock. */ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE"); goto bad; } break; case PCAP_TSTAMP_HOST: /* * XXX - do whatever the default is, for now. * Set to the highest resolution that's synchronized * with the system clock? */ break; } #endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */ /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) p->snapshot = MAXIMUM_SNAPLEN; /* Set promiscuous mode */ if (p->opt.promisc) { if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) { DWORD errcode = GetLastError(); /* * Suppress spurious error generated by non-compiant * MS Surface mobile adapters that appear to * return NDIS_STATUS_NOT_SUPPORTED for attempts * to set the hardware filter. * * It appears to be reporting NDIS_STATUS_NOT_SUPPORTED, * but with the NT status value "Customer" bit set; * the Npcap NPF driver sets that bit in some cases. * * If we knew that this meant "promiscuous mode * isn't supported", we could add a "promiscuous * mode isn't supported" error code and return * that, but: * * 1) we don't know that it means that * rather than meaning "we reject attempts * to set the filter, even though the NDIS * specifications say you shouldn't do that" * * and * * 2) other interface types that don't * support promiscuous mode, at least * on UN*Xes, just silently ignore * attempts to set promiscuous mode * * and rejecting it with an error could disrupt * attempts to capture, as many programs (tcpdump, * *shark) default to promiscuous mode. * * Alternatively, we could return the "promiscuous * mode not supported" *warning* value, so that * correct code will either ignore it or report * it and continue capturing. (This may require * a pcap_init() flag to request that return * value, so that old incorrect programs that * assume a non-zero return from pcap_activate() * is an error don't break.) */ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, errcode, "failed to set hardware filter to promiscuous mode"); goto bad; } } } else { /* * NDIS_PACKET_TYPE_ALL_LOCAL selects "All packets sent by * installed protocols and all packets indicated by the NIC", * but if no protocol drivers (like TCP/IP) are installed, * NDIS_PACKET_TYPE_DIRECTED, NDIS_PACKET_TYPE_BROADCAST, * and NDIS_PACKET_TYPE_MULTICAST are needed to capture * incoming frames. */ if (PacketSetHwFilter(pw->adapter, NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST) == FALSE) { DWORD errcode = GetLastError(); /* * Suppress spurious error generated by non-compiant * MS Surface mobile adapters. */ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, errcode, "failed to set hardware filter to non-promiscuous mode"); goto bad; } } } /* Set the buffer size */ p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; if(!(pw->adapter->Flags & INFO_FLAG_DAG_CARD)) { /* * Traditional Adapter */ /* * If the buffer size wasn't explicitly set, default to * WIN32_DEFAULT_KERNEL_BUFFER_SIZE. */ if (p->opt.buffer_size == 0) p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); goto bad; } p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); goto bad; } if (p->opt.immediate) { /* tell the driver to copy the buffer as soon as data arrives */ if(PacketSetMinToCopy(pw->adapter,0)==FALSE) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error calling PacketSetMinToCopy"); goto bad; } } else { /* tell the driver to copy the buffer only if it contains at least 16K */ if(PacketSetMinToCopy(pw->adapter,16000)==FALSE) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error calling PacketSetMinToCopy"); goto bad; } } } else { /* * Dag Card */ #ifdef HAVE_DAG_API /* * We have DAG support. */ LONG status; HKEY dagkey; DWORD lptype; DWORD lpcbdata; int postype = 0; char keyname[512]; snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", "SYSTEM\\CurrentControlSet\\Services\\DAG", strstr(_strlwr(p->opt.device), "dag")); do { status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); if(status != ERROR_SUCCESS) break; status = RegQueryValueEx(dagkey, "PosType", NULL, &lptype, (char*)&postype, &lpcbdata); if(status != ERROR_SUCCESS) { postype = 0; } RegCloseKey(dagkey); } while(FALSE); p->snapshot = PacketSetSnapLen(pw->adapter, p->snapshot); /* Set the length of the FCS associated to any packet. This value * will be subtracted to the packet length */ pw->dag_fcs_bits = pw->adapter->DagFcsLen; #else /* HAVE_DAG_API */ /* * No DAG support. */ goto bad; #endif /* HAVE_DAG_API */ } /* * If there's no filter program installed, there's * no indication to the kernel of what the snapshot * length should be, so no snapshotting is done. * * Therefore, when we open the device, we install * an "accept everything" filter with the specified * snapshot length. */ total_insn.code = (u_short)(BPF_RET | BPF_K); total_insn.jt = 0; total_insn.jf = 0; total_insn.k = p->snapshot; total_prog.bf_len = 1; total_prog.bf_insns = &total_insn; if (!PacketSetBpf(pw->adapter, &total_prog)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketSetBpf"); status = PCAP_ERROR; goto bad; } PacketSetReadTimeout(pw->adapter, p->opt.timeout); /* disable loopback capture if requested */ if (p->opt.nocapture_local) { if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK)) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Unable to disable the capture of loopback packets."); goto bad; } } #ifdef HAVE_DAG_API if(pw->adapter->Flags & INFO_FLAG_DAG_CARD) { /* install dag specific handlers for read and setfilter */ p->read_op = pcap_read_win32_dag; p->setfilter_op = pcap_setfilter_win32_dag; } else { #endif /* HAVE_DAG_API */ /* install traditional npf handlers for read and setfilter */ p->read_op = pcap_read_npf; p->setfilter_op = pcap_setfilter_npf; #ifdef HAVE_DAG_API } #endif /* HAVE_DAG_API */ p->setdirection_op = NULL; /* Not implemented. */ /* XXX - can this be implemented on some versions of Windows? */ p->inject_op = pcap_inject_npf; p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_npf; p->setnonblock_op = pcap_setnonblock_npf; p->stats_op = pcap_stats_npf; p->breakloop_op = pcap_breakloop_npf; p->stats_ex_op = pcap_stats_ex_npf; p->setbuff_op = pcap_setbuff_npf; p->setmode_op = pcap_setmode_npf; p->setmintocopy_op = pcap_setmintocopy_npf; p->getevent_op = pcap_getevent_npf; p->oid_get_request_op = pcap_oid_get_request_npf; p->oid_set_request_op = pcap_oid_set_request_npf; p->sendqueue_transmit_op = pcap_sendqueue_transmit_npf; p->setuserbuffer_op = pcap_setuserbuffer_npf; p->live_dump_op = pcap_live_dump_npf; p->live_dump_ended_op = pcap_live_dump_ended_npf; p->get_airpcap_handle_op = pcap_get_airpcap_handle_npf; p->cleanup_op = pcap_cleanup_npf; /* * XXX - this is only done because WinPcap supported * pcap_fileno() returning the hFile HANDLE from the * ADAPTER structure. We make no general guarantees * that the caller can do anything useful with it. * * (Not that we make any general guarantee of that * sort on UN*X, either, any more, given that not * all capture devices are regular OS network * interfaces.) */ p->handle = pw->adapter->hFile; return (status); bad: pcap_cleanup_npf(p); return (PCAP_ERROR); } /* * Check if rfmon mode is supported on the pcap_t for Windows systems. */ static int pcap_can_set_rfmon_npf(pcap_t *p) { return (PacketIsMonitorModeSupported(p->opt.device) == 1); } /* * Get a list of time stamp types. */ #ifdef HAVE_PACKET_GET_TIMESTAMP_MODES static int get_ts_types(const char *device, pcap_t *p, char *ebuf) { char *device_copy = NULL; ADAPTER *adapter = NULL; ULONG num_ts_modes; BOOL ret; DWORD error = ERROR_SUCCESS; ULONG *modes = NULL; int status = 0; do { /* * First, find out how many time stamp modes we have. * To do that, we have to open the adapter. * * XXX - PacketOpenAdapter() takes a non-const pointer * as an argument, so we make a copy of the argument and * pass that to it. */ device_copy = strdup(device); if (device_copy == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); status = -1; break; } adapter = PacketOpenAdapter(device_copy); if (adapter == NULL) { error = GetLastError(); /* * If we can't open the device now, we won't be * able to later, either. * * If the error is something that indicates * that the device doesn't exist, or that they * don't have permission to open the device - or * perhaps that they don't have permission to get * a list of devices, if PacketOpenAdapter() does * that - the user will find that out when they try * to activate the device; just return an empty * list of time stamp types. * * Treating either of those as errors will, for * example, cause "tcpdump -i " to fail, * because it first tries to pass the interface * name to pcap_create() and pcap_activate(), * in order to handle OSes where interfaces can * have names that are just numbers (stand up * and say hello, Linux!), and, if pcap_activate() * fails with a "no such device" error, checks * whether the interface name is a valid number * and, if so, tries to use it as an index in * the list of interfaces. * * That means pcap_create() must succeed even * for interfaces that don't exist, with the * failure occurring at pcap_activate() time. */ if (error == ERROR_BAD_UNIT || error == ERROR_ACCESS_DENIED) { p->tstamp_type_count = 0; p->tstamp_type_list = NULL; status = 0; } else { pcap_fmt_errmsg_for_win32_err(ebuf, PCAP_ERRBUF_SIZE, error, "Error opening adapter"); status = -1; } break; } /* * Get the total number of time stamp modes. * * The buffer for PacketGetTimestampModes() is * a sequence of 1 or more ULONGs. What's * passed to PacketGetTimestampModes() should have * the total number of ULONGs in the first ULONG; * what's returned *from* PacketGetTimestampModes() * has the total number of time stamp modes in * the first ULONG. * * Yes, that means if there are N time stamp * modes, the first ULONG should be set to N+1 * on input, and will be set to N on output. * * We first make a call to PacketGetTimestampModes() * with a pointer to a single ULONG set to 1; the * call should fail with ERROR_MORE_DATA (unless * there are *no* modes, but that should never * happen), and that ULONG should be set to the * number of modes. */ num_ts_modes = 1; ret = PacketGetTimestampModes(adapter, &num_ts_modes); if (!ret) { /* * OK, it failed. Did it fail with * ERROR_MORE_DATA? */ error = GetLastError(); if (error != ERROR_MORE_DATA) { /* * No, did it fail with ERROR_INVALID_FUNCTION? */ if (error == ERROR_INVALID_FUNCTION) { /* * This is probably due to * the driver with which Packet.dll * communicates being older, or * being a WinPcap driver, so * that it doesn't support * BIOCGTIMESTAMPMODES. * * Tell the user to try uninstalling * Npcap - and WinPcap if installed - * and re-installing it, to flush * out all older drivers. */ snprintf(ebuf, PCAP_ERRBUF_SIZE, "PacketGetTimestampModes() failed with ERROR_INVALID_FUNCTION; try uninstalling Npcap, and WinPcap if installed, and re-installing it from npcap.com"); status = -1; break; } /* * No, some other error. Fail. */ pcap_fmt_errmsg_for_win32_err(ebuf, PCAP_ERRBUF_SIZE, error, "Error calling PacketGetTimestampModes"); status = -1; break; } } /* else (ret == TRUE) * Unexpected success. Let's act like we got ERROR_MORE_DATA. * If it doesn't work, we'll hit some other error condition farther on. */ /* If the driver reports no modes supported *and* * ERROR_MORE_DATA, something is seriously wrong. * We *could* ignore the error and continue without supporting * settable timestamp modes, but that would hide a bug. */ if (num_ts_modes == 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "PacketGetTimestampModes() reports 0 modes supported."); status = -1; break; } /* * Yes, so we now know how many types to fetch. * * The buffer needs to have one ULONG for the * count and num_ts_modes ULONGs for the * num_ts_modes time stamp types. */ modes = (ULONG *)malloc((1 + num_ts_modes) * sizeof(ULONG)); if (modes == NULL) { /* Out of memory. */ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); status = -1; break; } modes[0] = 1 + num_ts_modes; if (!PacketGetTimestampModes(adapter, modes)) { pcap_fmt_errmsg_for_win32_err(ebuf, PCAP_ERRBUF_SIZE, GetLastError(), "Error calling PacketGetTimestampModes"); status = -1; break; } if (modes[0] != num_ts_modes) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "First PacketGetTimestampModes() call gives %lu modes, second call gives %lu modes", num_ts_modes, modes[0]); status = -1; break; } /* * Allocate a buffer big enough for * PCAP_TSTAMP_HOST (default) plus * the explicitly specified modes. */ p->tstamp_type_list = malloc((1 + num_ts_modes) * sizeof(u_int)); if (p->tstamp_type_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); status = -1; break; } u_int num_ts_types = 0; p->tstamp_type_list[num_ts_types] = PCAP_TSTAMP_HOST; num_ts_types++; for (ULONG i = 0; i < num_ts_modes; i++) { switch (modes[i + 1]) { case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION: /* * Better than low-res, * but *not* synchronized * with the OS clock. */ p->tstamp_type_list[num_ts_types] = PCAP_TSTAMP_HOST_HIPREC_UNSYNCED; num_ts_types++; break; case TIMESTAMPMODE_QUERYSYSTEMTIME: /* * Low-res, but synchronized * with the OS clock. */ p->tstamp_type_list[num_ts_types] = PCAP_TSTAMP_HOST_LOWPREC; num_ts_types++; break; case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE: /* * High-res, and synchronized * with the OS clock. */ p->tstamp_type_list[num_ts_types] = PCAP_TSTAMP_HOST_HIPREC; num_ts_types++; break; default: /* * Unknown, so we can't * report it. */ break; } } p->tstamp_type_count = num_ts_types; } while (0); /* Clean up temporary allocations */ if (device_copy != NULL) { free(device_copy); } if (modes != NULL) { free(modes); } if (adapter != NULL) { PacketCloseAdapter(adapter); } return status; } #else /* HAVE_PACKET_GET_TIMESTAMP_MODES */ static int get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_) { /* * Nothing to fetch, so it always "succeeds". */ return 0; } #endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */ pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = PCAP_CREATE_COMMON(ebuf, struct pcap_win); if (p == NULL) return (NULL); p->activate_op = pcap_activate_npf; p->can_set_rfmon_op = pcap_can_set_rfmon_npf; if (get_ts_types(device, p, ebuf) == -1) { pcap_close(p); return (NULL); } return (p); } static int pcap_setfilter_npf(pcap_t *p, struct bpf_program *fp) { struct pcap_win *pw = p->priv; if(PacketSetBpf(pw->adapter,fp)==FALSE){ /* * Kernel filter not installed. * * XXX - we don't know whether this failed because: * * the kernel rejected the filter program as invalid, * in which case we should fall back on userland * filtering; * * the kernel rejected the filter program as too big, * in which case we should again fall back on * userland filtering; * * there was some other problem, in which case we * should probably report an error. * * For NPF devices, the Win32 status will be * STATUS_INVALID_DEVICE_REQUEST for invalid * filters, but I don't know what it'd be for * other problems, and for some other devices * it might not be set at all. * * So we just fall back on userland filtering in * all cases. */ /* * install_bpf_program() validates the program. * * XXX - what if we already have a filter in the kernel? */ if (install_bpf_program(p, fp) < 0) return (-1); pw->filtering_in_kernel = 0; /* filtering in userland */ return (0); } /* * It worked. */ pw->filtering_in_kernel = 1; /* filtering in the kernel */ /* * Discard any previously-received packets, as they might have * passed whatever filter was formerly in effect, but might * not pass this filter (BIOCSETF discards packets buffered * in the kernel, so you can lose packets in any case). */ p->cc = 0; return (0); } /* * We filter at user level, since the kernel driver doesn't process the packets */ static int pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { if(!fp) { pcap_strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return (-1); } /* Install a user level filter */ if (install_bpf_program(p, fp) < 0) return (-1); return (0); } static int pcap_getnonblock_npf(pcap_t *p) { struct pcap_win *pw = p->priv; /* * XXX - if there were a PacketGetReadTimeout() call, we * would use it, and return 1 if the timeout is -1 * and 0 otherwise. */ return (pw->nonblock); } static int pcap_setnonblock_npf(pcap_t *p, int nonblock) { struct pcap_win *pw = p->priv; int newtimeout; if (nonblock) { /* * Set the packet buffer timeout to -1 for non-blocking * mode. */ newtimeout = -1; } else { /* * Restore the timeout set when the device was opened. * (Note that this may be -1, in which case we're not * really leaving non-blocking mode. However, although * the timeout argument to pcap_set_timeout() and * pcap_open_live() is an int, you're not supposed to * supply a negative value, so that "shouldn't happen".) */ newtimeout = p->opt.timeout; } if (!PacketSetReadTimeout(pw->adapter, newtimeout)) { pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketSetReadTimeout"); return (-1); } pw->nonblock = (newtimeout == -1); return (0); } static int pcap_add_if_npf(pcap_if_list_t *devlistp, char *name, bpf_u_int32 flags, const char *description, char *errbuf) { pcap_if_t *curdev; npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; LONG if_addr_size; int res = 0; if_addr_size = MAX_NETWORK_ADDRESSES; /* * Add an entry for this interface, with no addresses. */ curdev = add_dev(devlistp, name, flags, description, errbuf); if (curdev == NULL) { /* * Failure. */ return (-1); } /* * Get the list of addresses for the interface. */ if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { /* * Failure. * * We don't return an error, because this can happen with * NdisWan interfaces, and we want to supply them even * if we can't supply their addresses. * * We return an entry with an empty address list. */ return (0); } /* * Now add the addresses. */ while (if_addr_size-- > 0) { /* * "curdev" is an entry for this interface; add an entry for * this address to its list of addresses. */ res = add_addr_to_dev(curdev, (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, sizeof (struct sockaddr_storage), (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, sizeof (struct sockaddr_storage), (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, sizeof (struct sockaddr_storage), NULL, 0, errbuf); if (res == -1) { /* * Failure. */ break; } } return (res); } static int get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) { char *name_copy; ADAPTER *adapter; int status; size_t len; NDIS_HARDWARE_STATUS hardware_status; #ifdef OID_GEN_PHYSICAL_MEDIUM NDIS_PHYSICAL_MEDIUM phys_medium; bpf_u_int32 gen_physical_medium_oids[] = { #ifdef OID_GEN_PHYSICAL_MEDIUM_EX OID_GEN_PHYSICAL_MEDIUM_EX, #endif - OID_GEN_PHYSICAL_MEDIUM - }; + OID_GEN_PHYSICAL_MEDIUM + }; #define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0]) size_t i; #endif /* OID_GEN_PHYSICAL_MEDIUM */ #ifdef OID_GEN_LINK_STATE NDIS_LINK_STATE link_state; #endif int connect_status; if (*flags & PCAP_IF_LOOPBACK) { /* * Loopback interface, so the connection status doesn't * apply. and it's not wireless (or wired, for that * matter...). We presume it's up and running. */ *flags |= PCAP_IF_UP | PCAP_IF_RUNNING | PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; return (0); } /* * We need to open the adapter to get this information. * * XXX - PacketOpenAdapter() takes a non-const pointer * as an argument, so we make a copy of the argument and * pass that to it. */ name_copy = strdup(name); adapter = PacketOpenAdapter(name_copy); free(name_copy); if (adapter == NULL) { /* * Give up; if they try to open this device, it'll fail. */ return (0); } #ifdef HAVE_AIRPCAP_API /* * Airpcap.sys do not support the below 'OID_GEN_x' values. * Just set these flags (and none of the '*flags' entered with). */ if (PacketGetAirPcapHandle(adapter)) { /* * Must be "up" and "running" if the above if succeeded. */ *flags = PCAP_IF_UP | PCAP_IF_RUNNING; /* * An airpcap device is a wireless device (duh!) */ *flags |= PCAP_IF_WIRELESS; /* * A "network association state" makes no sense for airpcap. */ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; PacketCloseAdapter(adapter); return (0); } #endif /* * Get the hardware status, and derive "up" and "running" from * that. */ len = sizeof (hardware_status); status = oid_get_request(adapter, OID_GEN_HARDWARE_STATUS, &hardware_status, &len, errbuf); if (status == 0) { switch (hardware_status) { case NdisHardwareStatusReady: /* * "Available and capable of sending and receiving * data over the wire", so up and running. */ *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; break; case NdisHardwareStatusInitializing: case NdisHardwareStatusReset: /* * "Initializing" or "Resetting", so up, but * not running. */ *flags |= PCAP_IF_UP; break; case NdisHardwareStatusClosing: case NdisHardwareStatusNotReady: /* * "Closing" or "Not ready", so neither up nor * running. */ break; default: /* * Unknown. */ break; } } else { /* * Can't get the hardware status, so assume both up and * running. */ *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; } /* * Get the network type. */ #ifdef OID_GEN_PHYSICAL_MEDIUM /* * Try the OIDs we have for this, in order. */ for (i = 0; i < N_GEN_PHYSICAL_MEDIUM_OIDS; i++) { len = sizeof (phys_medium); status = oid_get_request(adapter, gen_physical_medium_oids[i], &phys_medium, &len, errbuf); if (status == 0) { /* * Success. */ break; } /* * Failed. We can't determine whether it failed * because that particular OID isn't supported * or because some other problem occurred, so we * just drive on and try the next OID. */ } if (status == 0) { /* * We got the physical medium. * * XXX - we might want to check for NdisPhysicalMediumWiMax * and NdisPhysicalMediumNative802_15_4 being * part of the enum, and check for those in the "wireless" * case. */ DIAG_OFF_ENUM_SWITCH switch (phys_medium) { case NdisPhysicalMediumWirelessLan: case NdisPhysicalMediumWirelessWan: case NdisPhysicalMediumNative802_11: case NdisPhysicalMediumBluetooth: case NdisPhysicalMediumUWB: case NdisPhysicalMediumIrda: /* * Wireless. */ *flags |= PCAP_IF_WIRELESS; break; default: /* * Not wireless or unknown */ break; } DIAG_ON_ENUM_SWITCH } #endif /* * Get the connection status. */ #ifdef OID_GEN_LINK_STATE len = sizeof(link_state); status = oid_get_request(adapter, OID_GEN_LINK_STATE, &link_state, &len, errbuf); if (status == 0) { /* * NOTE: this also gives us the receive and transmit * link state. */ switch (link_state.MediaConnectState) { case MediaConnectStateConnected: /* * It's connected. */ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; break; case MediaConnectStateDisconnected: /* * It's disconnected. */ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; break; case MediaConnectStateUnknown: default: /* * It's unknown whether it's connected or not. */ break; } } #else /* * OID_GEN_LINK_STATE isn't supported because it's not in our SDK. */ status = -1; #endif if (status == -1) { /* * OK, OID_GEN_LINK_STATE didn't work, try * OID_GEN_MEDIA_CONNECT_STATUS. */ status = oid_get_request(adapter, OID_GEN_MEDIA_CONNECT_STATUS, &connect_status, &len, errbuf); if (status == 0) { switch (connect_status) { case NdisMediaStateConnected: /* * It's connected. */ *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; break; case NdisMediaStateDisconnected: /* * It's disconnected. */ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; break; } } } PacketCloseAdapter(adapter); return (0); } int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { int ret = 0; const char *desc; char *AdaptersName; ULONG NameLength; char *name; /* * Find out how big a buffer we need. * * This call should always return FALSE; if the error is * ERROR_INSUFFICIENT_BUFFER, NameLength will be set to * the size of the buffer we need, otherwise there's a * problem, and NameLength should be set to 0. * * It shouldn't require NameLength to be set, but, * at least as of WinPcap 4.1.3, it checks whether * NameLength is big enough before it checks for a * NULL buffer argument, so, while it'll still do * the right thing if NameLength is uninitialized and * whatever junk happens to be there is big enough * (because the pointer argument will be null), it's * still reading an uninitialized variable. */ NameLength = 0; if (!PacketGetAdapterNames(NULL, &NameLength)) { DWORD last_error = GetLastError(); if (last_error != ERROR_INSUFFICIENT_BUFFER) { pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, last_error, "PacketGetAdapterNames"); return (-1); } } if (NameLength <= 0) return 0; AdaptersName = (char*) malloc(NameLength); if (AdaptersName == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); return (-1); } if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketGetAdapterNames"); free(AdaptersName); return (-1); } /* * "PacketGetAdapterNames()" returned a list of * null-terminated ASCII interface name strings, * terminated by a null string, followed by a list * of null-terminated ASCII interface description * strings, terminated by a null string. * This means there are two ASCII nulls at the end * of the first list. * * Find the end of the first list; that's the * beginning of the second list. */ desc = &AdaptersName[0]; while (*desc != '\0' || *(desc + 1) != '\0') desc++; /* - * Found it - "desc" points to the first of the two + * Found it - "desc" points to the first of the two * nulls at the end of the list of names, so the * first byte of the list of descriptions is two bytes * after it. */ desc += 2; /* * Loop over the elements in the first list. */ name = &AdaptersName[0]; while (*name != '\0') { bpf_u_int32 flags = 0; #ifdef HAVE_AIRPCAP_API /* * Is this an AirPcap device? * If so, ignore it; it'll get added later, by the * AirPcap code. */ if (device_is_airpcap(name, errbuf) == 1) { name += strlen(name) + 1; desc += strlen(desc) + 1; continue; } #endif #ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER /* * Is this a loopback interface? */ if (PacketIsLoopbackAdapter(name)) { /* Yes */ flags |= PCAP_IF_LOOPBACK; } #endif /* * Get additional flags. */ if (get_if_flags(name, &flags, errbuf) == -1) { /* * Failure. */ ret = -1; break; } /* * Add an entry for this interface. */ if (pcap_add_if_npf(devlistp, name, flags, desc, errbuf) == -1) { /* * Failure. */ ret = -1; break; } name += strlen(name) + 1; desc += strlen(desc) + 1; } free(AdaptersName); return (ret); } /* * Return the name of a network interface attached to the system, or NULL * if none can be found. The interface must be configured up; the * lowest unit number is preferred; loopback is ignored. * * In the best of all possible worlds, this would be the same as on * UN*X, but there may be software that expects this to return a * full list of devices after the first device. */ #define ADAPTERSNAME_LEN 8192 char * pcap_lookupdev(char *errbuf) { DWORD dwVersion; DWORD dwWindowsMajorVersion; /* * We disable this in "new API" mode, because 1) in WinPcap/Npcap, * it may return UTF-16 strings, for backwards-compatibility * reasons, and we're also disabling the hack to make that work, * for not-going-past-the-end-of-a-string reasons, and 2) we * want its behavior to be consistent. * * In addition, it's not thread-safe, so we've marked it as * deprecated. */ if (pcap_new_api) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()"); return (NULL); } /* disable MSVC's GetVersion() deprecated warning here */ DIAG_OFF_DEPRECATION dwVersion = GetVersion(); /* get the OS version */ DIAG_ON_DEPRECATION dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { /* * Windows 95, 98, ME. */ ULONG NameLength = ADAPTERSNAME_LEN; static char AdaptersName[ADAPTERSNAME_LEN]; if (PacketGetAdapterNames(AdaptersName,&NameLength) ) return (AdaptersName); else return NULL; } else { /* * Windows NT (NT 4.0 and later). * Convert the names to Unicode for backward compatibility. */ ULONG NameLength = ADAPTERSNAME_LEN; static WCHAR AdaptersName[ADAPTERSNAME_LEN]; size_t BufferSpaceLeft; char *tAstr; WCHAR *Unameptr; char *Adescptr; size_t namelen, i; WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR)); int NAdapts = 0; if(TAdaptersName == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); return NULL; } if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) { pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, GetLastError(), "PacketGetAdapterNames"); free(TAdaptersName); return NULL; } BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR); tAstr = (char*)TAdaptersName; Unameptr = AdaptersName; /* * Convert the device names to Unicode into AdapterName. */ do { /* * Length of the name, including the terminating * NUL. */ namelen = strlen(tAstr) + 1; /* * Do we have room for the name in the Unicode * buffer? */ if (BufferSpaceLeft < namelen * sizeof(WCHAR)) { /* * No. */ goto quit; } BufferSpaceLeft -= namelen * sizeof(WCHAR); /* * Copy the name, converting ASCII to Unicode. * namelen includes the NUL, so we copy it as * well. */ for (i = 0; i < namelen; i++) *Unameptr++ = *tAstr++; /* * Count this adapter. */ NAdapts++; } while (namelen != 1); /* * Copy the descriptions, but don't convert them from * ASCII to Unicode. */ Adescptr = (char *)Unameptr; while(NAdapts--) { size_t desclen; desclen = strlen(tAstr) + 1; /* * Do we have room for the name in the Unicode * buffer? */ if (BufferSpaceLeft < desclen) { /* * No. */ goto quit; } /* * Just copy the ASCII string. * namelen includes the NUL, so we copy it as * well. */ memcpy(Adescptr, tAstr, desclen); Adescptr += desclen; tAstr += desclen; BufferSpaceLeft -= desclen; } quit: free(TAdaptersName); return (char *)(AdaptersName); } } /* * We can't use the same code that we use on UN*X, as that's doing * UN*X-specific calls. * * We don't just fetch the entire list of devices, search for the * particular device, and use its first IPv4 address, as that's too * much work to get just one device's netmask. */ int pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf) { /* * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() * in order to skip non IPv4 (i.e. IPv6 addresses) */ npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; LONG if_addr_size = MAX_NETWORK_ADDRESSES; struct sockaddr_in *t_addr; LONG i; if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { *netp = *maskp = 0; return (0); } for(i = 0; i < if_addr_size; i++) { if(if_addrs[i].IPAddress.ss_family == AF_INET) { t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress); *netp = t_addr->sin_addr.S_un.S_addr; t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); *maskp = t_addr->sin_addr.S_un.S_addr; *netp &= *maskp; return (0); } } *netp = *maskp = 0; return (0); } static const char *pcap_lib_version_string; #ifdef HAVE_VERSION_H /* * libpcap being built for Windows, as part of a WinPcap/Npcap source * tree. Include version.h from that source tree to get the WinPcap/Npcap * version. * * XXX - it'd be nice if we could somehow generate the WinPcap/Npcap version * number when building as part of WinPcap/Npcap. (It'd be nice to do so * for the packet.dll version number as well.) */ #include "../../version.h" static const char pcap_version_string[] = WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING ", based on " PCAP_VERSION_STRING; const char * pcap_lib_version(void) { if (pcap_lib_version_string == NULL) { /* * Generate the version string. */ const char *packet_version_string = PacketGetVersion(); if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) { /* * WinPcap/Npcap version string and packet.dll version * string are the same; just report the WinPcap/Npcap * version. */ pcap_lib_version_string = pcap_version_string; } else { /* * WinPcap/Npcap version string and packet.dll version * string are different; that shouldn't be the * case (the two libraries should come from the * same version of WinPcap/Npcap), so we report both * versions. */ char *full_pcap_version_string; if (pcap_asprintf(&full_pcap_version_string, WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING " (packet.dll version %s), based on " PCAP_VERSION_STRING, packet_version_string) != -1) { /* Success */ pcap_lib_version_string = full_pcap_version_string; } } } return (pcap_lib_version_string); } #else /* HAVE_VERSION_H */ /* * libpcap being built for Windows, not as part of a WinPcap/Npcap source * tree. */ const char * pcap_lib_version(void) { if (pcap_lib_version_string == NULL) { /* * Generate the version string. Report the packet.dll * version. */ char *full_pcap_version_string; if (pcap_asprintf(&full_pcap_version_string, PCAP_VERSION_STRING " (packet.dll version %s)", PacketGetVersion()) != -1) { /* Success */ pcap_lib_version_string = full_pcap_version_string; } } return (pcap_lib_version_string); } #endif /* HAVE_VERSION_H */ diff --git a/pcap-sita.c b/pcap-sita.c index 2e5d4426adb7..70a36471d03e 100644 --- a/pcap-sita.c +++ b/pcap-sita.c @@ -1,1082 +1,1082 @@ /* * pcap-sita.c: Packet capture interface additions for SITA ACN devices * * Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc * * License: BSD * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "pcap-int.h" #include "pcap-sita.h" /* non-configureable manifests follow */ #define IOP_SNIFFER_PORT 49152 /* TCP port on the IOP used for 'distributed pcap' usage */ #define MAX_LINE_SIZE 255 /* max size of a buffer/line in /etc/hosts we allow */ #define MAX_CHASSIS 8 /* number of chassis in an ACN site */ #define MAX_GEOSLOT 8 /* max number of access units in an ACN site */ #define FIND 0 #define LIVE 1 typedef struct iface { struct iface *next; /* a pointer to the next interface */ char *name; /* this interface's name */ char *IOPname; /* this interface's name on an IOP */ uint32_t iftype; /* the type of interface (DLT values) */ } iface_t; typedef struct unit { char *ip; /* this unit's IP address (as extracted from /etc/hosts) */ int fd; /* the connection to this unit (if it exists) */ int find_fd; /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */ int first_time; /* 0 = just opened via acn_open_live(), ie. the first time, NZ = nth time */ struct sockaddr_in *serv_addr; /* the address control block for comms to this unit */ int chassis; int geoslot; iface_t *iface; /* a pointer to a linked list of interface structures */ char *imsg; /* a pointer to an inbound message */ int len; /* the current size of the inbound message */ } unit_t; /* * Private data. * Currently contains nothing. */ struct pcap_sita { int dummy; }; static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */ static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */ static int max_fs; pcap_if_t *acn_if_list; /* pcap's list of available interfaces */ static void dump_interface_list(void) { pcap_if_t *iff; pcap_addr_t *addr; int longest_name_len = 0; char *n, *d, *f; int if_number = 0; iff = acn_if_list; while (iff) { if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name); iff = iff->next; } iff = acn_if_list; printf("Interface List:\n"); while (iff) { n = (iff->name) ? iff->name : ""; d = (iff->description) ? iff->description : ""; f = (iff->flags == PCAP_IF_LOOPBACK) ? "L" : ""; printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d); addr = iff->addresses; while (addr) { printf("%*s ", (5 + longest_name_len), ""); /* add some indentation */ printf("%15s ", (addr->addr) ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr) : ""); printf("%15s ", (addr->netmask) ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr) : ""); printf("%15s ", (addr->broadaddr) ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr) : ""); printf("%15s ", (addr->dstaddr) ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr) : ""); printf("\n"); addr = addr->next; } iff = iff->next; } } static void dump(unsigned char *ptr, int i, int indent) { fprintf(stderr, "%*s", indent, " "); for (; i > 0; i--) { fprintf(stderr, "%2.2x ", *ptr++); } fprintf(stderr, "\n"); } static void dump_interface_list_p(void) { pcap_if_t *iff; pcap_addr_t *addr; int if_number = 0; iff = acn_if_list; printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff); while (iff) { printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next); dump((unsigned char *)iff, sizeof(pcap_if_t), 5); addr = iff->addresses; while (addr) { printf(" %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next); dump((unsigned char *)addr, sizeof(pcap_addr_t), 10); addr = addr->next; } iff = iff->next; } } static void dump_unit_table(void) { int chassis, geoslot; iface_t *p; printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address"); for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { if (units[chassis][geoslot].ip != NULL) printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip); p = units[chassis][geoslot].iface; while (p) { char *n = (p->name) ? p->name : ""; char *i = (p->IOPname) ? p->IOPname : ""; p = p->next; printf(" %12s -> %12s\n", i, n); } } } } static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) { int c, s; for (c = 0; c <= MAX_CHASSIS; c++) { for (s = 0; s <= MAX_GEOSLOT; s++) { if (units[c][s].fd == fd || units[c][s].find_fd == fd) { if (chassis) *chassis = c; if (geoslot) *geoslot = s; if (unit_ptr) *unit_ptr = &units[c][s]; return 1; } } } return 0; } static int read_client_nbytes(int fd, int count, unsigned char *buf) { unit_t *u; int chassis, geoslot; int len; find_unit_by_fd(fd, &chassis, &geoslot, &u); while (count) { if ((len = recv(fd, buf, count, 0)) <= 0) return -1; /* read in whatever data was sent to us */ count -= len; buf += len; } /* till we have everything we are looking for */ return 0; } static void empty_unit_iface(unit_t *u) { iface_t *p, *cur; cur = u->iface; while (cur) { /* loop over all the interface entries */ if (cur->name) free(cur->name); /* throwing away the contents if they exist */ if (cur->IOPname) free(cur->IOPname); p = cur->next; free(cur); /* then throw away the structure itself */ cur = p; } u->iface = 0; /* and finally remember that there are no remaining structure */ } static void empty_unit(int chassis, int geoslot) { unit_t *u = &units[chassis][geoslot]; empty_unit_iface(u); if (u->imsg) { /* then if an inbound message buffer exists */ void *bigger_buffer; bigger_buffer = (char *)realloc(u->imsg, 1); /* and re-allocate the old large buffer into a new small one */ if (bigger_buffer == NULL) { /* oops, realloc call failed */ fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno); return; } u->imsg = bigger_buffer; } } static void empty_unit_table(void) { int chassis, geoslot; for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { if (units[chassis][geoslot].ip != NULL) { free(units[chassis][geoslot].ip); /* get rid of the malloc'ed space that holds the IP address */ units[chassis][geoslot].ip = 0; /* then set the pointer to NULL */ } empty_unit(chassis, geoslot); } } } static char *find_nth_interface_name(int n) { int chassis, geoslot; iface_t *p; char *last_name = 0; if (n < 0) n = 0; /* ensure we are working with a valid number */ for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { if (units[chassis][geoslot].ip != NULL) { p = units[chassis][geoslot].iface; while (p) { /* and all interfaces... */ if (p->IOPname) last_name = p->name; /* remembering the last name found */ if (n-- == 0) return last_name; /* and if we hit the instance requested */ p = p->next; } } } } /* if we couldn't fine the selected entry */ if (last_name) return last_name; /* ... but we did have at least one entry... return the last entry found */ return ""; /* ... but if there wasn't any entry... return an empty string instead */ } int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */ FILE *fp; char buf[MAX_LINE_SIZE]; char *ptr, *ptr2; int pos; int chassis, geoslot; unit_t *u; empty_unit_table(); if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */ return -1; } while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */ pos = strcspn(buf, "#\n\r"); /* find the first comment character or EOL */ *(buf + pos) = '\0'; /* and clobber it and anything that follows it */ pos = strspn(buf, " \t"); /* then find the first non-white space */ if (pos == strlen(buf)) /* if there is nothing but white space on the line */ continue; /* ignore that empty line */ ptr = buf + pos; /* and skip over any of that leading whitespace */ if ((ptr2 = strstr(ptr, "_I_")) == NULL) /* skip any lines that don't have names that look like they belong to IOPs */ continue; if (*(ptr2 + 4) != '_') /* and skip other lines that have names that don't look like ACN components */ continue; *(ptr + strcspn(ptr, " \t")) = '\0'; /* null terminate the IP address so its a standalone string */ chassis = *(ptr2 + 3) - '0'; /* extract the chassis number */ geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */ if (chassis < 1 || chassis > MAX_CHASSIS || geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */ continue; /* and ignore the entry */ } ptr2 = strdup(ptr); /* copy the IP address into our malloc'ed memory */ if (ptr2 == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); continue; } u = &units[chassis][geoslot]; u->ip = ptr2; /* and remember the whole shebang */ u->chassis = chassis; u->geoslot = geoslot; } fclose(fp); if (*errbuf) return -1; else return 0; } static int open_with_IOP(unit_t *u, int flag) { int sockfd; char *ip; if (u->serv_addr == NULL) { u->serv_addr = malloc(sizeof(struct sockaddr_in)); /* since we called malloc(), lets check to see if we actually got the memory */ if (u->serv_addr == NULL) { /* oops, we didn't get the memory requested */ fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno); return 0; } } ip = u->ip; /* bzero() is deprecated, replaced with memset() */ memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in)); u->serv_addr->sin_family = AF_INET; u->serv_addr->sin_addr.s_addr = inet_addr(ip); u->serv_addr->sin_port = htons(IOP_SNIFFER_PORT); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip); return 0; } if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) { fprintf(stderr, "pcap can't connect to IOP at %s\n", ip); return 0; } if (flag == LIVE) u->fd = sockfd; else u->find_fd = sockfd; u->first_time = 0; return sockfd; /* return the non-zero file descriptor as a 'success' indicator */ } static void close_with_IOP(int chassis, int geoslot, int flag) { int *id; if (flag == LIVE) id = &units[chassis][geoslot].fd; else id = &units[chassis][geoslot].find_fd; if (*id) { /* this was the last time, so... if we are connected... */ close(*id); /* disconnect us */ *id = 0; /* and forget that the descriptor exists because we are not open */ } } static void pcap_cleanup_acn(pcap_t *handle) { int chassis, geoslot; unit_t *u; if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0) return; close_with_IOP(chassis, geoslot, LIVE); if (u) u->first_time = 0; pcap_cleanup_live_common(handle); } static void send_to_fd(int fd, int len, unsigned char *str) { int nwritten; int chassis, geoslot; while (len > 0) { if ((nwritten = write(fd, str, len)) <= 0) { find_unit_by_fd(fd, &chassis, &geoslot, NULL); if (units[chassis][geoslot].fd == fd) close_with_IOP(chassis, geoslot, LIVE); else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND); empty_unit(chassis, geoslot); return; } len -= nwritten; str += nwritten; } } static void acn_freealldevs(void) { pcap_if_t *iff, *next_iff; pcap_addr_t *addr, *next_addr; for (iff = acn_if_list; iff != NULL; iff = next_iff) { next_iff = iff->next; for (addr = iff->addresses; addr != NULL; addr = next_addr) { next_addr = addr->next; if (addr->addr) free(addr->addr); if (addr->netmask) free(addr->netmask); if (addr->broadaddr) free(addr->broadaddr); if (addr->dstaddr) free(addr->dstaddr); free(addr); } if (iff->name) free(iff->name); if (iff->description) free(iff->description); free(iff); } } static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) { snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot); } static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) { int portnum; portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1; snprintf(buf, bufsize, "%s_%d", proto, portnum); } static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) { iface_t *iface_ptr, *iface; char buf[32]; char *proto; char *port; int IOPportnum = 0; iface = malloc(sizeof(iface_t)); /* get memory for a structure */ if (iface == NULL) { /* oops, we didn't get the memory requested */ fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno); return NULL; } memset((char *)iface, 0, sizeof(iface_t)); /* bzero is deprecated(), replaced with memset() */ iface->iftype = iftype; /* remember the interface type of this interface */ iface->IOPname = strdup(IOPname); /* copy it and stick it into the structure */ if (iface->IOPname == NULL) { /* oops, we didn't get the memory requested */ fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno); return NULL; } if (strncmp(IOPname, "lo", 2) == 0) { IOPportnum = atoi(&IOPname[2]); switch (iftype) { case DLT_EN10MB: nonUnified_IOP_port_name(buf, sizeof buf, "lo", u); break; default: unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); break; } } else if (strncmp(IOPname, "eth", 3) == 0) { IOPportnum = atoi(&IOPname[3]); switch (iftype) { case DLT_EN10MB: nonUnified_IOP_port_name(buf, sizeof buf, "eth", u); break; default: unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); break; } } else if (strncmp(IOPname, "wan", 3) == 0) { IOPportnum = atoi(&IOPname[3]); switch (iftype) { case DLT_SITA: unified_IOP_port_name(buf, sizeof buf, "wan", u, IOPportnum); break; default: unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); break; } } else { fprintf(stderr, "Error... invalid IOP name %s\n", IOPname); return NULL; } iface->name = strdup(buf); /* make a copy and stick it into the structure */ if (iface->name == NULL) { /* oops, we didn't get the memory requested */ fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno); return NULL; } if (u->iface == 0) { /* if this is the first name */ u->iface = iface; /* stick this entry at the head of the list */ } else { iface_ptr = u->iface; while (iface_ptr->next) { /* otherwise scan the list */ iface_ptr = iface_ptr->next; /* till we're at the last entry */ } iface_ptr->next = iface; /* then tack this entry on the end of the list */ } return iface->name; } static int if_sort(char *s1, char *s2) { char *s1_p2, *s2_p2; char str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE]; int s1_p1_len, s2_p1_len; int retval; if ((s1_p2 = strchr(s1, '_'))) { /* if an underscore is found... */ s1_p1_len = s1_p2 - s1; /* the prefix length is the difference in pointers */ s1_p2++; /* the suffix actually starts _after_ the underscore */ } else { /* otherwise... */ s1_p1_len = strlen(s1); /* the prefix length is the length of the string itself */ s1_p2 = 0; /* and there is no suffix */ } if ((s2_p2 = strchr(s2, '_'))) { /* now do the same for the second string */ s2_p1_len = s2_p2 - s2; s2_p2++; } else { s2_p1_len = strlen(s2); s2_p2 = 0; } strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1)); *(str1 + s1_p1_len) = 0; strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2)); *(str2 + s2_p1_len) = 0; retval = strcmp(str1, str2); if (retval != 0) return retval; /* if they are not identical, then we can quit now and return the indication */ return strcmp(s1_p2, s2_p2); /* otherwise we return the result of comparing the 2nd half of the string */ } static void sort_if_table(void) { pcap_if_t *p1, *p2, *prev, *temp; int has_swapped; if (!acn_if_list) return; /* nothing to do if the list is empty */ while (1) { p1 = acn_if_list; /* start at the head of the list */ prev = 0; has_swapped = 0; while ((p2 = p1->next)) { if (if_sort(p1->name, p2->name) > 0) { if (prev) { /* we are swapping things that are _not_ at the head of the list */ temp = p2->next; prev->next = p2; p2->next = p1; p1->next = temp; } else { /* special treatment if we are swapping with the head of the list */ temp = p2->next; acn_if_list= p2; p2->next = p1; p1->next = temp; } p1 = p2; prev = p1; has_swapped = 1; } prev = p1; p1 = p1->next; } if (has_swapped == 0) return; } return; } static int process_client_data (char *errbuf) { /* returns: -1 = error, 0 = OK */ int chassis, geoslot; unit_t *u; pcap_if_t *iff, *prev_iff; pcap_addr_t *addr, *prev_addr; char *ptr; int address_count; struct sockaddr_in *s; char *newname; bpf_u_int32 interfaceType; unsigned char flags; void *bigger_buffer; prev_iff = 0; for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { /* now loop over all the devices */ u = &units[chassis][geoslot]; empty_unit_iface(u); ptr = u->imsg; /* point to the start of the msg for this IOP */ while (ptr < (u->imsg + u->len)) { if ((iff = malloc(sizeof(pcap_if_t))) == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */ if (acn_if_list == 0) acn_if_list = iff; /* remember the head of the list */ if (prev_iff) prev_iff->next = iff; /* insert a forward link */ if (*ptr) { /* if there is a count for the name */ if ((iff->name = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } memcpy(iff->name, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ *(iff->name + *ptr) = 0; /* and null terminate the string */ ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ } ptr++; if (*ptr) { /* if there is a count for the description */ if ((iff->description = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } memcpy(iff->description, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ *(iff->description + *ptr) = 0; /* and null terminate the string */ ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ } ptr++; interfaceType = ntohl(*(bpf_u_int32 *)ptr); ptr += 4; /* skip over the interface type */ flags = *ptr++; if (flags) iff->flags = PCAP_IF_LOOPBACK; /* if this is a loopback style interface, lets mark it as such */ address_count = *ptr++; prev_addr = 0; while (address_count--) { if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } - memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */ + memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */ if (iff->addresses == 0) iff->addresses = addr; if (prev_addr) prev_addr->next = addr; /* insert a forward link */ if (*ptr) { /* if there is a count for the address */ if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { /* get that amount of space */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */ addr->addr = (struct sockaddr *)s; s->sin_family = AF_INET; s->sin_addr.s_addr = *(bpf_u_int32 *)(ptr + 1); /* copy the address in */ ptr += *ptr; /* now move the pointer forwards according to the specified length of the address */ } ptr++; /* then forwards one more for the 'length of the address' field */ if (*ptr) { /* process any netmask */ if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } /* bzero() is deprecated, replaced with memset() */ memset((char *)s, 0, sizeof(struct sockaddr_in)); addr->netmask = (struct sockaddr *)s; s->sin_family = AF_INET; s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); ptr += *ptr; } ptr++; if (*ptr) { /* process any broadcast address */ if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } /* bzero() is deprecated, replaced with memset() */ memset((char *)s, 0, sizeof(struct sockaddr_in)); addr->broadaddr = (struct sockaddr *)s; s->sin_family = AF_INET; s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); ptr += *ptr; } ptr++; if (*ptr) { /* process any destination address */ if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return -1; } /* bzero() is deprecated, replaced with memset() */ memset((char *)s, 0, sizeof(struct sockaddr_in)); addr->dstaddr = (struct sockaddr *)s; s->sin_family = AF_INET; s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); ptr += *ptr; } ptr++; prev_addr = addr; } prev_iff = iff; newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */ bigger_buffer = realloc(iff->name, strlen(newname) + 1); if (bigger_buffer == NULL) { /* we now re-write the name stored in the interface list */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "realloc"); return -1; } iff->name = bigger_buffer; strcpy(iff->name, newname); /* to this new name */ } } } return 0; } static int read_client_data (int fd) { unsigned char buf[256]; int chassis, geoslot; unit_t *u; int len; find_unit_by_fd(fd, &chassis, &geoslot, &u); if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0; /* read in whatever data was sent to us */ if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL) /* extend the buffer for the new data */ return 0; memcpy((u->imsg + u->len), buf, len); /* append the new data */ u->len += len; return 1; } static void wait_for_all_answers(void) { int retval; struct timeval tv; int fd; int chassis, geoslot; tv.tv_sec = 2; tv.tv_usec = 0; while (1) { int flag = 0; fd_set working_set; for (fd = 0; fd <= max_fs; fd++) { /* scan the list of descriptors we may be listening to */ if (FD_ISSET(fd, &readfds)) flag = 1; /* and see if there are any still set */ } if (flag == 0) return; /* we are done, when they are all gone */ memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */ retval = select(max_fs + 1, &working_set, NULL, NULL, &tv); if (retval == -1) { /* an error occurred !!!!! */ return; } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */ printf("timeout\n"); return; } else { for (fd = 0; fd <= max_fs; fd++) { /* scan the list of things to do, and do them */ if (FD_ISSET(fd, &working_set)) { if (read_client_data(fd) == 0) { /* if the socket has closed */ FD_CLR(fd, &readfds); /* and descriptors we listen to for errors */ find_unit_by_fd(fd, &chassis, &geoslot, NULL); close_with_IOP(chassis, geoslot, FIND); /* and close out connection to him */ } } } } } } static char *get_error_response(int fd, char *errbuf) { /* return a pointer on error, NULL on no error */ char byte; int len = 0; while (1) { recv(fd, &byte, 1, 0); /* read another byte in */ if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) { /* and if there is still room in the buffer */ *errbuf++ = byte; /* stick it in */ *errbuf = '\0'; /* ensure the string is null terminated just in case we might exceed the buffer's size */ } if (byte == '\0') { if (len > 1) { return errbuf; } else { return NULL; } } } } int acn_findalldevs(char *errbuf) { /* returns: -1 = error, 0 = OK */ int chassis, geoslot; unit_t *u; FD_ZERO(&readfds); max_fs = 0; for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { u = &units[chassis][geoslot]; if (u->ip && (open_with_IOP(u, FIND))) { /* connect to the remote IOP */ send_to_fd(u->find_fd, 1, (unsigned char *)"\0"); if (get_error_response(u->find_fd, errbuf)) close_with_IOP(chassis, geoslot, FIND); else { if (u->find_fd > max_fs) max_fs = u->find_fd; /* remember the highest number currently in use */ FD_SET(u->find_fd, &readfds); /* we are going to want to read this guy's response to */ u->len = 0; send_to_fd(u->find_fd, 1, (unsigned char *)"Q"); /* this interface query request */ } } } } wait_for_all_answers(); if (process_client_data(errbuf)) return -1; sort_if_table(); return 0; } static int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) { unsigned char buf[12]; send_to_fd(handle->fd, 1, (unsigned char *)"S"); /* send the get_stats command to the IOP */ if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1; /* try reading the required bytes */ ps->ps_recv = ntohl(*(uint32_t *)&buf[0]); /* break the buffer into its three 32 bit components */ ps->ps_drop = ntohl(*(uint32_t *)&buf[4]); ps->ps_ifdrop = ntohl(*(uint32_t *)&buf[8]); return 0; } static int acn_open_live(const char *name, char *errbuf, int *linktype) { /* returns 0 on error, else returns the file descriptor */ int chassis, geoslot; unit_t *u; iface_t *p; pcap_if_list_t devlist; pcap_platform_finddevs(&devlist, errbuf); for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { u = &units[chassis][geoslot]; if (u->ip != NULL) { p = u->iface; while (p) { /* and all interfaces... */ if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) { /* and if we found the interface we want... */ *linktype = p->iftype; open_with_IOP(u, LIVE); /* start a connection with that IOP */ send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname); /* send the IOP's interface name, and a terminating null */ if (get_error_response(u->fd, errbuf)) { return -1; } return u->fd; /* and return that open descriptor */ } p = p->next; } } } } return -1; /* if the interface wasn't found, return an error */ } static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) { unsigned char buf[8]; unit_t *u; //printf("acn_start_monitor()\n"); // fulko find_unit_by_fd(fd, NULL, NULL, &u); if (u->first_time == 0) { buf[0] = 'M'; *(uint32_t *)&buf[1] = htonl(snaplen); buf[5] = timeout; buf[6] = promiscuous; buf[7] = direction; //printf("acn_start_monitor() first time\n"); // fulko send_to_fd(fd, 8, buf); /* send the start monitor command with its parameters to the IOP */ u->first_time = 1; } //printf("acn_start_monitor() complete\n"); // fulko } static int pcap_inject_acn(pcap_t *p, const void *buf _U_, int size _U_) { pcap_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters", PCAP_ERRBUF_SIZE); return (-1); } static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) { int fd = handle->fd; int count; struct bpf_insn *p; uint16_t shortInt; uint32_t longInt; send_to_fd(fd, 1, (unsigned char *)"F"); /* BPF filter follows command */ count = bpf->bf_len; longInt = htonl(count); send_to_fd(fd, 4, (unsigned char *)&longInt); /* send the instruction sequence count */ p = bpf->bf_insns; while (count--) { /* followed by the list of instructions */ shortInt = htons(p->code); longInt = htonl(p->k); send_to_fd(fd, 2, (unsigned char *)&shortInt); send_to_fd(fd, 1, (unsigned char *)&p->jt); send_to_fd(fd, 1, (unsigned char *)&p->jf); send_to_fd(fd, 4, (unsigned char *)&longInt); p++; } if (get_error_response(fd, NULL)) return -1; return 0; } static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) { struct timeval tv; int retval, fd; fd_set r_fds; fd_set w_fds; u_char *bp; int len = 0; int offset = 0; tv.tv_sec = 5; tv.tv_usec = 0; fd = handle->fd; FD_ZERO(&r_fds); FD_SET(fd, &r_fds); memcpy(&w_fds, &r_fds, sizeof(r_fds)); bp = handle->bp; while (count) { retval = select(fd + 1, &w_fds, NULL, NULL, &tv); if (retval == -1) { /* an error occurred !!!!! */ // fprintf(stderr, "error during packet data read\n"); return -1; /* but we need to return a good indication to prevent unnecessary popups */ } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */ // fprintf(stderr, "timeout during packet data read\n"); return -1; } else { if ((len = recv(fd, (bp + offset), count, 0)) <= 0) { // fprintf(stderr, "premature exit during packet data rx\n"); return -1; } count -= len; offset += len; } } return 0; } static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { #define HEADER_SIZE (4 * 4) unsigned char packet_header[HEADER_SIZE]; struct pcap_pkthdr pcap_header; //printf("pcap_read_acn()\n"); // fulko acn_start_monitor(handle->fd, handle->snapshot, handle->opt.timeout, handle->opt.promisc, handle->direction); /* maybe tell him to start monitoring */ //printf("pcap_read_acn() after start monitor\n"); // fulko handle->bp = packet_header; if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0; /* try to read a packet header in so we can get the sizeof the packet data */ pcap_header.ts.tv_sec = ntohl(*(uint32_t *)&packet_header[0]); /* tv_sec */ pcap_header.ts.tv_usec = ntohl(*(uint32_t *)&packet_header[4]); /* tv_usec */ pcap_header.caplen = ntohl(*(uint32_t *)&packet_header[8]); /* caplen */ pcap_header.len = ntohl(*(uint32_t *)&packet_header[12]); /* len */ handle->bp = (u_char *)handle->buffer + handle->offset; /* start off the receive pointer at the right spot */ if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0; /* then try to read in the rest of the data */ callback(user, &pcap_header, handle->bp); /* call the user supplied callback function */ return 1; } static int pcap_activate_sita(pcap_t *handle) { int fd; if (handle->opt.rfmon) { /* * No monitor mode on SITA devices (they're not Wi-Fi * devices). */ return PCAP_ERROR_RFMON_NOTSUP; } /* Initialize some components of the pcap structure. */ handle->inject_op = pcap_inject_acn; handle->setfilter_op = pcap_setfilter_acn; handle->setdirection_op = NULL; /* Not implemented */ handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; handle->cleanup_op = pcap_cleanup_acn; handle->read_op = pcap_read_acn; handle->stats_op = pcap_stats_acn; fd = acn_open_live(handle->opt.device, handle->errbuf, &handle->linktype); if (fd == -1) return PCAP_ERROR; /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) handle->snapshot = MAXIMUM_SNAPLEN; handle->fd = fd; handle->bufsize = handle->snapshot; /* Allocate the buffer */ handle->buffer = malloc(handle->bufsize + handle->offset); if (!handle->buffer) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); pcap_cleanup_acn(handle); return PCAP_ERROR; } /* * "handle->fd" is a socket, so "select()" and "poll()" * should work on it. */ handle->selectable_fd = handle->fd; return 0; } pcap_t *pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; p = PCAP_CREATE_COMMON(ebuf, struct pcap_sita); if (p == NULL) return (NULL); p->activate_op = pcap_activate_sita; return (p); } int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { //printf("pcap_findalldevs()\n"); // fulko *alldevsp = 0; /* initialize the returned variables before we do anything */ strcpy(errbuf, ""); if (acn_parse_hosts_file(errbuf)) /* scan the hosts file for potential IOPs */ { //printf("pcap_findalldevs() returning BAD after parsehosts\n"); // fulko return -1; } //printf("pcap_findalldevs() got hostlist now finding devs\n"); // fulko if (acn_findalldevs(errbuf)) /* then ask the IOPs for their monitorable devices */ { //printf("pcap_findalldevs() returning BAD after findalldevs\n"); // fulko return -1; } devlistp->beginning = acn_if_list; acn_if_list = 0; /* then forget our list head, because someone will call pcap_freealldevs() to empty the malloc'ed stuff */ //printf("pcap_findalldevs() returning ZERO OK\n"); // fulko return 0; } /* * Libpcap version string. */ const char * pcap_lib_version(void) { return PCAP_VERSION_STRING " (SITA-only)"; } diff --git a/pcap-sita.html b/pcap-sita.html index 33f1e10fa52c..04f51292f03c 100644 --- a/pcap-sita.html +++ b/pcap-sita.html @@ -1,943 +1,943 @@
A "Distributed Pcap" for
Remote Monitoring LANs & WANs

(Design Notes for the SITA ACN device)
Fulko Hew
SITA INC Canada, Inc.
Revised: October 2, 2007

SUMMARY

    Note: This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07).

    The ACN provides a customized/distributed version of this library that allows SMPs to interact with the various IOPs within the site providing a standard mechanism to capture LAN and WAN message traffic.

    SMP The Supervisory Management Processor where Wireshark (or equivalent) runs in conjunction with a libpcap front-end.
    IOP I/O Processors where the monitored ports exist in conjunction with a custom device driver/libpcap back-end.

    Each IOP will be capable of supporting multiple connections from an SMP enabling monitoring of more than one interface at a time, each through its own separate connection. The IOP is responsible to ensure and report an error if any attempt is made to monitor the same interface more than once.

    There are three applications that will be supported by the ACN version of libpcap. They each use a slightly different mode for looping/capturing and termination as summarized in the following table:

    - - + + - + - +
    Application Capture Termination
    wireshark
    Application Capture Termination
    wireshark pcap_dispatch(all packets in one buffer of capture only) pcap_breakloop()
    tshark
    tshark pcap_dispatch(one buffer of capture only) Since a CTRL-C was used to terminate the application, pcap_breakloop() is never called.
    tcpdump
    tcpdump pcap_loop(all packets in the next buffer, and loop forever) pcap_breakloop()

    Note: In all cases, the termination of capturing is always (apparently) followed by pcap_close(). Pcap_breakloop() is only used to stop/suspend looping/processing, and upon close interpretation of the function definitions, it is possible to resume capturing following a pcap_breakloop() without any re-initialization.

    ACN Limitations

    1. Monitoring of backup IOPs is not currently supported.
    2. Ethernet interfaces cannot be monitored in promiscuous mode.

ROUTINES

    The following list of functions is the sub-set of Pcap functions that have been altered/enhanced to support the ACN remote monitoring facility. The remainder of the Pcap functions continue to perform their duties un-altered. Libpcap only supports this mode of operation if it has been configured/compiled for SITA/ACN support.

      pcap_findalldevs
      pcap_freealldevs
      pcap_open_live
      pcap_close
      pcap_setfilter
      pcap_dispatch
      pcap_loop
      pcap_next
      pcap_next_ex
      pcap_stats
    These subroutines have been modified for the ACN specific distributed and remote monitoring ability perform the following basic functions. More detail is provided in the "SMP/IOP Inter-Process Communication Protocol" section.

    pcap_open_live() Used to obtain a packet capture descriptor to look at packets on the network.
    SMP -> IOP The SMP will open a connection to the selected IOP on its 'sniffer' port to ensure it is available. It sends a null terminated string identifying the interface to be monitored.
    IOP -> SMP After any required processing is complete, the IOP will return a null terminated string containing an error message if one occurred. If no error occurred, a empty string is still returned. Errors are:
    • "Interface (xxx) does not exist."
    • "Interface (xxx) not configured."
    • "Interface (xxx) already being monitored."
    pcap_findalldevs() It constructs a list of network devices that can be opened with pcap_open_live().
    SMP It obtains a list of IOPs currently available (via /etc/hosts).
    SMP -> IOP The SMP will sequentially open a connection to each IOP on its 'sniffer' port to ensure the IOP is available. It sends a null terminated empty interface ID followed by the query request command.
    IOP -> SMP The IOP returns an error response and its list of devices.
    SMP -> IOP The SMP closes the TCP connection with each IOP.
    SMP The SMP adds the received information to its internal structure.
    pcap_freealldevs() Used to free a list allocated by pcap_findalldevs().
    SMP The SMP frees the structure it built as a result of the previous invocation of pcap_findalldevs().
    pcap_dispatch() Used to collect and process packets.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP will read the reverse channel of the connection between the SMP and the IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' until the select() call returns a 'no more data' indication. It will the process (at most) the next 'cnt' packets and invoke the specified callback function for each packet processed.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_loop() Is similar to pcap_dispatch() except it keeps reading packets until the requested number of packets are processed or an error occurs.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP continuously reads the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' until 'cnt' packets have been received. The specified callback function will be invoked for each packet received.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_next() It reads the next packet (by calling pcap_dispatch() with a count of 1) and returns a pointer to the data in that packet.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP reads only the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() with a count of 1) and returns a pointer to that data by invoking an internal callback.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_next_ex() Reads the next packet and returns a success/failure indication.
    SMP -> IOP On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), the SMP will pass down the monitor start command and various parameters the IOP should use.
    IOP -> SMP The IOP now sends a stream of captured data.
    SMP The SMP reads only the next packet from the reverse channel of the connection between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() with a count of 1) and returns separate pointers to both the packet header and packet data by invoking an internal callback.
    IOP The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
    pcap_setfilter() Used to specify a filter program.
    SMP -> IOP The SMP sends a 'set filter' command followed by the BPF commands.
    IOP -> SMP The IOP returns a null terminated error string if it failed to accept the filter. If no error occurred, then a NULL terminated empty string is returned instead. Errors are:
    • "Invalid BPF."
    • "Insufficient resources for BPF."
    pcap_stats() Fills in a pcap_stat struct with packet statistics.
    SMP -> IOP The SMP sends a message to the IOP requesting its statistics.
    IOP -> SMP The IOP returns the statistics.
    SMP The SMP fills in the structure provided with the information retrieved from the IOP.
    pcap_close() Closes the file and deallocates resources.
    SMP -> IOP The SMP closes the file descriptor, and if the descriptor is that of the communication session with an IOP, it too is terminated.
    IOP If the IOP detects that its communication session with an SMP has closed, it will terminate any monitoring in progress, release any resources and close its end of the session. It will not maintain persistence of any information or prior mode of operation.

SMP/IOP Inter-Process Communication Protocol

  • Communications between an SMP and an IOP consists of a TCP session between an ephemeral port on the SMP and the well known port of 49152 (which is the first available port in the 'dynamic and/or private port' range) on an IOP.

  • Following a TCP open operation the IOP receives a null terminated 'interface ID' string to determine the type of operation that follows:

  • Every command received by an IOP implies a 'stop trace/stop forwarding' operation must occur before executing the received command.

  • A session is closed when the SMP closes the TCP session with the IOP. Obviously monitoring and forwarding is also stopped at that time. Note: All multi-octet entities are sent in network neutral order.


    pcap_findalldevs() SMP -> IOP Open socket (to each IOP), and sends:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 1 A NULL to indicate an empty 'interface ID'.

    IOP -> SMP Send its (possibly empty) NULL terminated error response string.
    SMP -> IOP Sends the 'interface query request':

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 1 A 'Q' (indicating 'interface query request').

    IOP -> SMP The IOP returns a list of sequences of information as defined by the return parameter of this function call (as shown in the following table). Elements are specified by providing an unsigned byte preceding the actual data that contains length information.

    Notes: Name/
    Purpose
    Size
    (in bytes)
    Description
      length 1 The number of octets in the name field that follows.
    Name 1-255 The name of the interface. The format of the name is an alphabetic string (indicating the type of interface) followed by an optional numeric string (indicating the interface's sequence number). Sequence numbers (if needed) will begin at zero and progress monotonically upwards. (i.e. 'eth0', 'lo', 'wan0', etc.)

    For an IOP, the alphabetic string will be one of: 'eth', 'wan', and 'lo' for Ethernet, WAN ports and the IP loopback device respectively. An IOP currently supports: 'eth0', 'eth1', 'lo', 'wan0' ... 'wan7'.

    Note: IOPs and ACNs will not currently support the concept of 'any' interface.

    length 1 The number of octets in the interface description field that follows.
    Interface Description 0-255 A description of the interface or it may be an empty string. (i.e. 'ALC')
    Interface Type 4 The type of interface as defined in the description for pcap_datalink() (in network neutral order).
    Loopback Flag 1 1 = if the interface is a loopback interface, zero = otherwise.
    count 1 # of address entries that follow. Each entry is a series of bytes in network neutral order. See the parameter definition above for more details.
    Repeated 'count' number of times. length 1 The number of octets in the address field that follows.
    Address 1-255 The address of this interface (in network neutral order).
    length 1 The number of octets in the netmask field that follows.
    Network Mask 0-255 The network mask used on this interface (if applicable) (in network neutral order).
    length 1 The number of octets in the broadcast address field that follows.
    Broadcast Address 0-255 The broadcast address of this interface (if applicable) (in network neutral order).
    length 1 The number of octets in the destination address field that follows.
    Destination Address 0-255 The destination address of this interface (if applicable) (in network neutral order).

    SMP -> IOP Close the socket.
    IOP -> SMP Close the socket.

    pcap_open_live() SMP -> IOP Open socket, and sends:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID 'n' 'n' octets containing a NULL terminated interface name string.

    IOP -> SMP Send its NULL terminated error response string.

    pcap_dispatch()
    pcap_loop()
    pcap_next()
    pcap_next_ex()
    SMP -> IOP On the first invocation following a pcap_open_live() or pcap_breakloop() additional information is sent:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'M' (indicating 'monitor start')
    snaplen 4 snaplen
    timeout 1 timeout value (in milliseconds)
    promiscuous 1 A flag indicating that the interface being monitored show operate in promiscuous mode. [off(0) / on(NZ)]
    direction 1 A flag indicating the direction of traffic that should be captuted [both(0) / in(1) / out(2)]

    IOP -> SMP Sends captured packets.

    pcap_setfilter() SMP -> IOP At any time, the SMP can issue a set filter command which contains an indicator, a count of the number of statements in the filter, followed by the sequence of filter commands represented as a sequence of C-style structures.

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'F' (indicating 'filter')
    count 4 The number of command in the Berkeley Packet Filter that follow.
    BPF program 'n' 8 bytes of each command (repeated 'n' times).
    Each command consists of that C-style structure which contains:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    opcode 2 The command's opcode.
    'jt' 1 The 'jump if true' program counter offset.
    'jf' 1 The 'jump if false' program counter offset.
    'k' 4 The 'other' data field.

    Refer to the bpf(4) man page for more details.

    IOP -> SMP In return the IOP will send its (possibly empty) NULL terminated error response string.

    pcap_stats() SMP -> IOP At any time, the SMP can issue a 'retrieve statistics' command which contains:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    command 1 'S' (indicating 'request statistics')

    IOP -> SMP In return the IOP will send:

    Name/
    Purpose
    Size
    (in bytes)
    Description
    ps_recv 4 The number of packets that passed the filter.
    ps_drop 4 The number of packets that were dropped because the input queue was full, regardless of whether they passed the filter.
    ps_ifdrop 4 The number of packets dropped by the network interface (regardless of whether they would have passed the input filter).


    pcap_close() SMP -> IOP At any time, the SMP can close the TCP session with the IOP.

Interface ID Naming Convention

    Each interface within an IOP will be referred to uniquely. Since an currently contains 8 monitorable WAN ports and a monitorable Ethernet port, the naming convention is:

    Interface # Type Name
    1 WAN wan0
    2 WAN wan1
    3 WAN wan2
    4 WAN wan3
    5 WAN wan4
    6 WAN wan5
    7 WAN wan6
    8 WAN wan7
    9 Ethernet eth0
    10 Ethernet eth1

Packet Trace Data Format

    The format of the trace data that is sent to the SMP follows a portion of the libpcap file format and is summarized here. This format specifies the generic requirements needed to be able to decode packets, but does not cover ACN specifics such as custom MAC addressing and WAN protocol support.

    Although a libpcap file begins with a global header followed by zero or more records for each captured packet, trace data sent to the SMP does NOT begin with a global header. A trace sequence looks like this:

    - - - - - - - + + + + + + +
     [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data] ... [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data] ...

    Packet Header

      Each captured packet starts with a header that contains the following values (in network neutral order):
        uint32 tv_sec;  /* timestamp seconds */
        uint32 tv_usec; /* timestamp microseconds */
        uint32 caplen;  /* number of octets in the following packet */
        uint32 len;     /* original length of packet on the wire */
       		
      tv_sec The date and time when this packet was captured. This value is in seconds since January 1, 1970 00:00:00 GMT; this is also known as a UN*X time_t. You can use the ANSI C time() function from time.h to get this value, but you might use a more optimized way to get this timestamp value. If this timestamp isn't based on GMT (UTC), use thiszone from the global header for adjustments.
      tv_usec The microseconds when this packet was captured, as an offset to ts_sec. Beware: this value must never reach 1 second (1,000,000), in this case ts_sec must be increased instead!
      caplen The number of bytes actually provided in the capture record. This value should never become larger than len or the snaplen value specified during the capture.
      len The length of the packet "on the wire" when it was captured. If caplen and len differ, the actually saved packet size was limited by the value of snaplen specified during one of the capture directives such as pcap_dispatch().

    Packet Data

      The actual packet data will immediately follow the packet header as a sequence of caplen octets. Depending on the DLT encoding number assigned to the interface, the packet data will contain an additional custom header used to convey WAN port related information.

    ACN Custom Packet Header

      PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support monitoring of its ports, however each of these facilities were focused on capturing and displaying traffic from LAN interfaces. The SITA extensions to these facilities are used to also provide the ability to capture, filter, and display information from an ACN's WAN ports.

      Although each packet follows the standard libpcap format, since there are two types of interfaces that can be monitored, the format of the data packet varies slightly.

      • For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format.
      • For WAN devices, the packet contains a 5 byte header that precedes the actual captured data described by the following table:

      Octet Name Mask/Value Definition
      0 Control / Status xxxxxxx0 Transmitted by capture device (see 'Errors' octets)
      xxxxxxx1 Received by capture device
      1xxxxxxx No buffer was available during capture of previous packet.
      1 Signals xxxxxxx1 DSR asserted
      xxxxxx1x DTR asserted
      xxxxx1xx CTS asserted
      xxxx1xxx RTS asserted
      xxx1xxxx DCD asserted
      xx1xxxxx Undefined
      x1xxxxxx Undefined
      1xxxxxxx Undefined
      2 Errors
      (octet 1)
        Tx Rx
      xxxxxxx1 Underrun Framing
      xxxxxx1x CTS Lost Parity
      xxxxx1xx UART Error Collision
      xxxx1xxx Re-Tx Limit Reached Long Frame
      xxx1xxxx Undefined Short Frame
      xx1xxxxx Undefined Undefined
      x1xxxxxx Undefined Undefined
      1xxxxxxx Undefined Undefined
      3 Errors
      (octet 2)
        Tx Rx
      xxxxxxx1 Undefined Non-Octet Aligned
      xxxxxx1x Undefined Abort Received
      xxxxx1xx Undefined CD Lost
      xxxx1xxx Undefined Digital PLL Error
      xxx1xxxx Undefined Overrun
      xx1xxxxx Undefined Frame Length Violation
      x1xxxxxx Undefined CRC Error
      1xxxxxxx Undefined Break Received
      4 Protocol
      0x01 - LAPB (BOP)  
      0x02 - Ethernet 1
      0x03 - Async (Interrupt IO)  
      0x04 - Async (Block IO)  
      0x05 - IPARS  
      0x06 - UTS  
      0x07 - PPP (HDLC)  
      0x08 - SDLC  
      0x09 - Token Ring 1
      0x10 - I2C  
      0x11 - DPM Link  
      0x12 - Frame Relay (BOP)  

      Note 1: Ethernet and Token Ring frames will never be sent as DLT_SITA (with the 5 octet header), but will be sent as their corresponding DLT types instead.

diff --git a/pcap-snf.c b/pcap-snf.c index b885e02657c1..fe9cc9c8d18a 100644 --- a/pcap-snf.c +++ b/pcap-snf.c @@ -1,617 +1,617 @@ #ifdef HAVE_CONFIG_H #include #endif #ifndef _WIN32 #include #endif /* !_WIN32 */ #include #include #include #include /* for INT_MAX */ #ifndef _WIN32 #include #include #include #include #include #endif /* !_WIN32 */ #include #if SNF_VERSION_API >= 0x0003 #define SNF_HAVE_INJECT_API #endif #include "pcap-int.h" #include "pcap-snf.h" /* * Private data for capturing on SNF devices. */ struct pcap_snf { snf_handle_t snf_handle; /* opaque device handle */ snf_ring_t snf_ring; /* opaque device ring handle */ #ifdef SNF_HAVE_INJECT_API snf_inject_t snf_inj; /* inject handle, if inject is used */ #endif int snf_timeout; int snf_boardnum; }; static int snf_set_datalink(pcap_t *p, int dlt) { p->linktype = dlt; return (0); } static int snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) { struct snf_ring_stats stats; struct pcap_snf *snfps = p->priv; int rc; if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, rc, "snf_get_stats"); return -1; } ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; ps->ps_drop = stats.ring_pkt_overflow; ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; return 0; } static void snf_platform_cleanup(pcap_t *p) { struct pcap_snf *ps = p->priv; #ifdef SNF_HAVE_INJECT_API if (ps->snf_inj) snf_inject_close(ps->snf_inj); #endif snf_ring_close(ps->snf_ring); snf_close(ps->snf_handle); pcap_cleanup_live_common(p); } static int snf_getnonblock(pcap_t *p) { struct pcap_snf *ps = p->priv; return (ps->snf_timeout == 0); } static int snf_setnonblock(pcap_t *p, int nonblock) { struct pcap_snf *ps = p->priv; if (nonblock) ps->snf_timeout = 0; else { if (p->opt.timeout <= 0) ps->snf_timeout = -1; /* forever */ else ps->snf_timeout = p->opt.timeout; } return (0); } #define _NSEC_PER_SEC 1000000000 static inline struct timeval snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) { struct timeval tv; long tv_nsec; const static struct timeval zero_timeval; if (ts_nanosec == 0) return zero_timeval; tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; tv_nsec = (ts_nanosec % _NSEC_PER_SEC); /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) tv.tv_usec = tv_nsec; else tv.tv_usec = tv_nsec / 1000; return tv; } static int snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_snf *ps = p->priv; struct pcap_pkthdr hdr; int i, flags, err, caplen, n; struct snf_recv_req req; int nonblock, timeout; if (!p) return -1; /* * This can conceivably process more than INT_MAX packets, * which would overflow the packet count, causing it either * to look like a negative number, and thus cause us to * return a value that looks like an error, or overflow * back into positive territory, and thus cause us to * return a too-low count. * * Therefore, if the packet count is unlimited, we clip * it at INT_MAX; this routine is not expected to * process packets indefinitely, so that's not an issue. */ if (PACKET_COUNT_IS_UNLIMITED(cnt)) cnt = INT_MAX; n = 0; timeout = ps->snf_timeout; while (n < cnt) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { return (n); } } err = snf_ring_recv(ps->snf_ring, timeout, &req); if (err) { if (err == EBUSY || err == EAGAIN) { return (n); } else if (err == EINTR) { timeout = 0; continue; } else { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, err, "snf_read"); return -1; } } caplen = req.length; if (caplen > p->snapshot) caplen = p->snapshot; if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); hdr.caplen = caplen; hdr.len = req.length; callback(user, &hdr, req.pkt_addr); n++; } /* After one successful packet is received, we won't block * again for that timeout. */ if (timeout != 0) timeout = 0; } return (n); } static int snf_inject(pcap_t *p, const void *buf _U_, int size _U_) { #ifdef SNF_HAVE_INJECT_API struct pcap_snf *ps = p->priv; int rc; if (ps->snf_inj == NULL) { rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); if (rc) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, rc, "snf_inject_open"); return (-1); } } rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); if (!rc) { return (size); } else { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, rc, "snf_inject_send"); return (-1); } #else pcap_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", PCAP_ERRBUF_SIZE); return (-1); #endif } static int snf_activate(pcap_t* p) { struct pcap_snf *ps = p->priv; char *device = p->opt.device; const char *nr = NULL; int err; int flags = -1, ring_id = -1; if (device == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); return -1; } /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. * Since libpcap isn't thread-safe */ if ((nr = getenv("SNF_FLAGS")) && *nr) flags = strtol(nr, NULL, 0); else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) flags = SNF_F_PSHARED; else nr = NULL; /* Allow pcap_set_buffer_size() to set dataring_size. * Default is zero which allows setting from env SNF_DATARING_SIZE. * pcap_set_buffer_size() is in bytes while snf_open() accepts values * between 0 and 1048576 in Megabytes. Values in this range are * mapped to 1MB. */ err = snf_open(ps->snf_boardnum, 0, /* let SNF API parse SNF_NUM_RINGS, if set */ NULL, /* default RSS, or use SNF_RSS_FLAGS env */ (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ flags, /* may want pshared */ &ps->snf_handle); if (err != 0) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, err, "snf_open failed"); return -1; } if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { ring_id = (int) strtol(nr, NULL, 0); } err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); if (err != 0) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, err, "snf_ring_open_id(ring=%d) failed", ring_id); return -1; } /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) p->snapshot = MAXIMUM_SNAPLEN; if (p->opt.timeout <= 0) ps->snf_timeout = -1; else ps->snf_timeout = p->opt.timeout; err = snf_start(ps->snf_handle); if (err != 0) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, err, "snf_start failed"); return -1; } /* * "select()" and "poll()" don't work on snf descriptors. */ #ifndef _WIN32 p->selectable_fd = -1; #endif /* !_WIN32 */ p->linktype = DLT_EN10MB; p->read_op = snf_read; p->inject_op = snf_inject; p->setfilter_op = install_bpf_program; p->setdirection_op = NULL; /* Not implemented.*/ p->set_datalink_op = snf_set_datalink; p->getnonblock_op = snf_getnonblock; p->setnonblock_op = snf_setnonblock; p->stats_op = snf_pcap_stats; p->cleanup_op = snf_platform_cleanup; #ifdef SNF_HAVE_INJECT_API ps->snf_inj = NULL; #endif return 0; } #define MAX_DESC_LENGTH 128 int snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) { pcap_if_t *dev; #ifdef _WIN32 struct sockaddr_in addr; #endif struct snf_ifaddrs *ifaddrs, *ifa; char name[MAX_DESC_LENGTH]; char desc[MAX_DESC_LENGTH]; int ret, allports = 0, merge = 0; const char *nr = NULL; if (snf_init(SNF_VERSION_API)) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_getifaddrs: snf_init failed"); return (-1); } if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "snf_getifaddrs"); return (-1); } if ((nr = getenv("SNF_FLAGS")) && *nr) { errno = 0; merge = strtol(nr, NULL, 0); if (errno) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "snf_getifaddrs: SNF_FLAGS is not a valid number"); return (-1); } merge = merge & SNF_F_AGGREGATE_PORTMASK; } for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { /* * Myricom SNF adapter ports may appear as regular * network interfaces, which would already have been * added to the list of adapters by pcap_platform_finddevs() * if this isn't an SNF-only version of libpcap. * * Our create routine intercepts pcap_create() calls for * those interfaces and arranges that they will be * opened using the SNF API instead. * * So if we already have an entry for the device, we * don't add an additional entry for it, we just * update the description for it, if any, to indicate * which snfN device it is. Otherwise, we add an entry * for it. * * In either case, if SNF_F_AGGREGATE_PORTMASK is set * in SNF_FLAGS, we add this port to the bitmask * of ports, which we use to generate a device * we can use to capture on all ports. * * Generate the description string. If port aggregation * is set, use 2^{port number} as the unit number, * rather than {port number}. * * XXX - do entries in this list have IP addresses for * the port? If so, should we add them to the * entry for the device, if they're not already in the * list of IP addresses for the device? - */ + */ (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", merge ? "Merge Bitmask Port " : "", merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); /* * Add the port to the bitmask. */ if (merge) allports |= 1 << ifa->snf_ifa_portnum; /* * See if there's already an entry for the device * with the name ifa->snf_ifa_name. */ dev = find_dev(devlistp, ifa->snf_ifa_name); if (dev != NULL) { /* * Yes. Update its description. */ char *desc_str; desc_str = strdup(desc); if (desc_str == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "snf_findalldevs strdup"); return -1; } free(dev->description); dev->description = desc_str; } else { /* * No. Add an entry for it. * * XXX - is there a notion of "up" or "running", * and can we determine whether something's * plugged into the adapter and set * PCAP_IF_CONNECTION_STATUS_CONNECTED or * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? */ dev = add_dev(devlistp, ifa->snf_ifa_name, 0, desc, errbuf); if (dev == NULL) return -1; #ifdef _WIN32 /* * On Windows, fill in IP# from device name */ ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); if (ret == 1) { - /* - * Successful conversion of device name - * to IPv4 address. - */ - addr.sin_family = AF_INET; - if (add_addr_to_dev(dev, &addr, sizeof(addr), - NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) - return -1; + /* + * Successful conversion of device name + * to IPv4 address. + */ + addr.sin_family = AF_INET; + if (add_addr_to_dev(dev, &addr, sizeof(addr), + NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) + return -1; } else if (ret == -1) { /* * Error. */ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "sinf_findalldevs inet_pton"); return -1; } #endif _WIN32 } } snf_freeifaddrs(ifaddrs); /* * Create a snfX entry if port aggregation is enabled - */ + */ if (merge) { /* * Add a new entry with all ports bitmask */ (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", allports); /* * XXX - is there any notion of "up" and "running" that * would apply to this device, given that it handles * multiple ports? * * Presumably, there's no notion of "connected" vs. * "disconnected", as "is this plugged into a network?" * would be a per-port property. */ if (add_dev(devlistp, name, PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, errbuf) == NULL) return (-1); /* * XXX - should we give it a list of addresses with all * the addresses for all the ports? */ } return 0; } pcap_t * snf_create(const char *device, char *ebuf, int *is_ours) { pcap_t *p; int boardnum = -1; struct snf_ifaddrs *ifaddrs, *ifa; size_t devlen; struct pcap_snf *ps; if (snf_init(SNF_VERSION_API)) { /* Can't initialize the API, so no SNF devices */ *is_ours = 0; return NULL; } /* * Match a given interface name to our list of interface names, from * which we can obtain the intended board number */ if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { /* Can't get SNF addresses */ *is_ours = 0; return NULL; } devlen = strlen(device) + 1; ifa = ifaddrs; while (ifa) { if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { boardnum = ifa->snf_ifa_boardnum; break; } ifa = ifa->snf_ifa_next; } snf_freeifaddrs(ifaddrs); if (ifa == NULL) { /* * If we can't find the device by name, support the name "snfX" * and "snf10gX" where X is the board number. */ if (sscanf(device, "snf10g%d", &boardnum) != 1 && sscanf(device, "snf%d", &boardnum) != 1) { /* Nope, not a supported name */ *is_ours = 0; return NULL; } } /* OK, it's probably ours. */ *is_ours = 1; p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf); if (p == NULL) return NULL; ps = p->priv; /* * We support microsecond and nanosecond time stamps. */ p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); pcap_close(p); return NULL; } p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; p->tstamp_precision_count = 2; p->activate_op = snf_activate; ps->snf_boardnum = boardnum; return p; } #ifdef SNF_ONLY /* * This libpcap build supports only SNF cards, not regular network * interfaces.. */ /* * There are no regular interfaces, just SNF interfaces. */ int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { return (0); } /* * Attempts to open a regular interface fail. */ pcap_t * pcap_create_interface(const char *device, char *errbuf) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "This version of libpcap only supports SNF cards"); return NULL; } /* * Libpcap version string. */ const char * pcap_lib_version(void) { return (PCAP_VERSION_STRING " (SNF-only)"); } #endif diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index 7020577ca6cb..726e4a8a6462 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -1,944 +1,944 @@ /* * Copyright (c) 2006 Paolo Abeni (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * USB sniffing API implementation for Linux platform * By Paolo Abeni * Modifications: Kris Katterjohn * */ #ifdef HAVE_CONFIG_H #include #endif #include "pcap-int.h" #include "pcap-usb-linux.h" #include "pcap-usb-linux-common.h" #include "pcap/usb.h" #include "extract.h" #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_USBDEVICE_FS_H /* * We might need to define __user for * . */ #ifdef HAVE_LINUX_COMPILER_H #include #endif /* HAVE_LINUX_COMPILER_H */ #include #endif /* HAVE_LINUX_USBDEVICE_FS_H */ #include "diag-control.h" #define USB_IFACE "usbmon" #define USBMON_DEV_PREFIX "usbmon" #define USBMON_DEV_PREFIX_LEN (sizeof USBMON_DEV_PREFIX - 1) #define USB_LINE_LEN 4096 #if __BYTE_ORDER == __LITTLE_ENDIAN #define htols(s) s #define htoll(l) l #define htol64(ll) ll #else #define htols(s) bswap_16(s) #define htoll(l) bswap_32(l) #define htol64(ll) bswap_64(ll) #endif struct mon_bin_stats { uint32_t queued; uint32_t dropped; }; struct mon_bin_get { pcap_usb_header *hdr; void *data; size_t data_len; /* Length of data (can be zero) */ }; struct mon_bin_mfetch { int32_t *offvec; /* Vector of events fetched */ int32_t nfetch; /* Number of events to fetch (out: fetched) */ int32_t nflush; /* Number of events to flush */ }; #define MON_IOC_MAGIC 0x92 #define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) #define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr) #define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) #define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) #define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) #define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) -#define MON_BIN_SETUP 0x1 /* setup hdr is present*/ -#define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ -#define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ -#define MON_BIN_ERROR 0x8 +#define MON_BIN_SETUP 0x1 /* setup hdr is present*/ +#define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ +#define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ +#define MON_BIN_ERROR 0x8 /* * Private data for capturing on Linux USB. */ struct pcap_usb_linux { u_char *mmapbuf; /* memory-mapped region pointer */ size_t mmapbuflen; /* size of region */ int bus_index; u_int packets_read; }; /* forward declaration */ static int usb_activate(pcap_t *); static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *); static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *); static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *); static int usb_inject_linux(pcap_t *, const void *, int); static int usb_setdirection_linux(pcap_t *, pcap_direction_t); static void usb_cleanup_linux_mmap(pcap_t *); /* facility to add an USB device to the device list*/ static int usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str) { char dev_name[10]; char dev_descr[30]; snprintf(dev_name, 10, USB_IFACE"%d", n); /* * XXX - is there any notion of "up" and "running"? */ if (n == 0) { /* * As this refers to all buses, there's no notion of * "connected" vs. "disconnected", as that's a property * that would apply to a particular USB interface. */ if (add_dev(devlistp, dev_name, PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "Raw USB traffic, all USB buses", err_str) == NULL) return -1; } else { /* * XXX - is there a way to determine whether anything's * plugged into this bus interface or not, and set * PCAP_IF_CONNECTION_STATUS_CONNECTED or * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? */ snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n); if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL) return -1; } return 0; } int usb_findalldevs(pcap_if_list_t *devlistp, char *err_str) { struct dirent* data; int ret = 0; DIR* dir; int n; char* name; /* * We require 2.6.27 or later kernels, so we have binary-mode support. * The devices are of the form /dev/usbmon{N}. * Open /dev and scan it. */ dir = opendir("/dev"); if (dir != NULL) { while ((ret == 0) && ((data = readdir(dir)) != 0)) { name = data->d_name; /* * Is this a usbmon device? */ if (strncmp(name, USBMON_DEV_PREFIX, USBMON_DEV_PREFIX_LEN) != 0) continue; /* no */ /* * What's the device number? */ if (sscanf(&name[USBMON_DEV_PREFIX_LEN], "%d", &n) == 0) continue; /* failed */ ret = usb_dev_add(devlistp, n, err_str); } closedir(dir); } return 0; } /* * Matches what's in mon_bin.c in the Linux kernel. */ #define MIN_RING_SIZE (8*1024) #define MAX_RING_SIZE (1200*1024) static int usb_set_ring_size(pcap_t* handle, int header_size) { /* * A packet from binary usbmon has: * * 1) a fixed-length header, of size header_size; * 2) descriptors, for isochronous transfers; * 3) the payload. * * The kernel buffer has a size, defaulting to 300KB, with a * minimum of 8KB and a maximum of 1200KB. The size is set with * the MON_IOCT_RING_SIZE ioctl; the size passed in is rounded up * to a page size. * * No more than {buffer size}/5 bytes worth of payload is saved. * Therefore, if we subtract the fixed-length size from the * snapshot length, we have the biggest payload we want (we * don't worry about the descriptors - if we have descriptors, * we'll just discard the last bit of the payload to get it * to fit). We multiply that result by 5 and set the buffer * size to that value. */ int ring_size; if (handle->snapshot < header_size) handle->snapshot = header_size; /* The maximum snapshot size is small enough that this won't overflow */ ring_size = (handle->snapshot - header_size) * 5; /* * Will this get an error? * (There's no wqy to query the minimum or maximum, so we just * copy the value from the kernel source. We don't round it * up to a multiple of the page size.) */ if (ring_size > MAX_RING_SIZE) { /* * Yes. Lower the ring size to the maximum, and set the * snapshot length to the value that would give us a * maximum-size ring. */ ring_size = MAX_RING_SIZE; handle->snapshot = header_size + (MAX_RING_SIZE/5); } else if (ring_size < MIN_RING_SIZE) { /* * Yes. Raise the ring size to the minimum, but leave * the snapshot length unchanged, so we show the * callback no more data than specified by the * snapshot length. */ ring_size = MIN_RING_SIZE; } if (ioctl(handle->fd, MON_IOCT_RING_SIZE, ring_size) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't set ring size from fd %d", handle->fd); return -1; } return ring_size; } static int usb_mmap(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; int len; /* * Attempt to set the ring size as appropriate for the snapshot * length, reducing the snapshot length if that'd make the ring * bigger than the kernel supports. */ len = usb_set_ring_size(handle, (int)sizeof(pcap_usb_header_mmapped)); if (len == -1) { /* Failed. Fall back on non-memory-mapped access. */ return 0; } handlep->mmapbuflen = len; handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ, MAP_SHARED, handle->fd, 0); if (handlep->mmapbuf == MAP_FAILED) { /* * Failed. We don't treat that as a fatal error, we * just try to fall back on non-memory-mapped access. */ return 0; } return 1; } #ifdef HAVE_LINUX_USBDEVICE_FS_H #define CTRL_TIMEOUT (5*1000) /* milliseconds */ #define USB_DIR_IN 0x80 #define USB_TYPE_STANDARD 0x00 #define USB_RECIP_DEVICE 0x00 #define USB_REQ_GET_DESCRIPTOR 6 #define USB_DT_DEVICE 1 #define USB_DT_CONFIG 2 #define USB_DEVICE_DESCRIPTOR_SIZE 18 #define USB_CONFIG_DESCRIPTOR_SIZE 9 /* probe the descriptors of the devices attached to the bus */ /* the descriptors will end up in the captured packet stream */ /* and be decoded by external apps like wireshark */ /* without these identifying probes packet data can't be fully decoded */ static void probe_devices(int bus) { struct usbdevfs_ctrltransfer ctrl; struct dirent* data; int ret = 0; char busdevpath[sizeof("/dev/bus/usb/000/") + NAME_MAX]; DIR* dir; uint8_t descriptor[USB_DEVICE_DESCRIPTOR_SIZE]; uint8_t configdesc[USB_CONFIG_DESCRIPTOR_SIZE]; /* scan usb bus directories for device nodes */ snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d", bus); dir = opendir(busdevpath); if (!dir) return; while ((ret >= 0) && ((data = readdir(dir)) != 0)) { int fd; char* name = data->d_name; if (name[0] == '.') continue; snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d/%s", bus, data->d_name); fd = open(busdevpath, O_RDWR); if (fd == -1) continue; /* * Sigh. Different kernels have different member names * for this structure. */ #ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; ctrl.wValue = USB_DT_DEVICE << 8; ctrl.wIndex = 0; - ctrl.wLength = sizeof(descriptor); + ctrl.wLength = sizeof(descriptor); #else ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ctrl.request = USB_REQ_GET_DESCRIPTOR; ctrl.value = USB_DT_DEVICE << 8; ctrl.index = 0; - ctrl.length = sizeof(descriptor); + ctrl.length = sizeof(descriptor); #endif ctrl.data = descriptor; ctrl.timeout = CTRL_TIMEOUT; ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); /* Request CONFIGURATION descriptor alone to know wTotalLength */ #ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE ctrl.wValue = USB_DT_CONFIG << 8; ctrl.wLength = sizeof(configdesc); #else ctrl.value = USB_DT_CONFIG << 8; ctrl.length = sizeof(configdesc); #endif ctrl.data = configdesc; ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); if (ret >= 0) { uint16_t wtotallength; wtotallength = EXTRACT_LE_U_2(&configdesc[2]); #ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE ctrl.wLength = wtotallength; #else ctrl.length = wtotallength; #endif ctrl.data = malloc(wtotallength); if (ctrl.data) { ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); free(ctrl.data); } } close(fd); } closedir(dir); } #endif /* HAVE_LINUX_USBDEVICE_FS_H */ pcap_t * usb_create(const char *device, char *ebuf, int *is_ours) { const char *cp; char *cpend; long devnum; pcap_t *p; /* Does this look like a USB monitoring device? */ cp = strrchr(device, '/'); if (cp == NULL) cp = device; /* Does it begin with USB_IFACE? */ if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) { /* Nope, doesn't begin with USB_IFACE */ *is_ours = 0; return NULL; } /* Yes - is USB_IFACE followed by a number? */ cp += sizeof USB_IFACE - 1; devnum = strtol(cp, &cpend, 10); if (cpend == cp || *cpend != '\0') { /* Not followed by a number. */ *is_ours = 0; return NULL; } if (devnum < 0) { /* Followed by a non-valid number. */ *is_ours = 0; return NULL; } /* OK, it's probably ours. */ *is_ours = 1; p = PCAP_CREATE_COMMON(ebuf, struct pcap_usb_linux); if (p == NULL) return (NULL); p->activate_op = usb_activate; return (p); } static int usb_activate(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; - char full_path[USB_LINE_LEN]; + char full_path[USB_LINE_LEN]; /* * Turn a negative snapshot value (invalid), a snapshot value of * 0 (unspecified), or a value bigger than the normal maximum * value, into the maximum allowed value. * * If some application really *needs* a bigger snapshot * length, we should just increase MAXIMUM_SNAPLEN. */ if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) handle->snapshot = MAXIMUM_SNAPLEN; /* Initialize some components of the pcap structure. */ handle->bufsize = handle->snapshot; handle->offset = 0; handle->linktype = DLT_USB_LINUX; handle->inject_op = usb_inject_linux; handle->setfilter_op = install_bpf_program; /* no kernel filtering */ handle->setdirection_op = usb_setdirection_linux; handle->set_datalink_op = NULL; /* can't change data link type */ handle->getnonblock_op = pcap_getnonblock_fd; handle->setnonblock_op = pcap_setnonblock_fd; /*get usb bus index from device name */ if (sscanf(handle->opt.device, USB_IFACE"%d", &handlep->bus_index) != 1) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get USB bus index from %s", handle->opt.device); return PCAP_ERROR; } /* * We require 2.6.27 or later kernels, so we have binary-mode support. * Try to open the binary interface. */ snprintf(full_path, USB_LINE_LEN, "/dev/"USBMON_DEV_PREFIX"%d", handlep->bus_index); handle->fd = open(full_path, O_RDONLY, 0); if (handle->fd < 0) { /* * The attempt failed; why? */ switch (errno) { case ENOENT: /* * The device doesn't exist. * That could either mean that there's * no support for monitoring USB buses * (which probably means "the usbmon * module isn't loaded") or that there * is but that *particular* device * doesn't exist (no "scan all buses" * device if the bus index is 0, no * such bus if the bus index isn't 0). * * For now, don't provide an error message; * if we can determine what the particular * problem is, we should report that. */ handle->errbuf[0] = '\0'; return PCAP_ERROR_NO_SUCH_DEVICE; case EACCES: /* * We didn't have permission to open it. */ DIAG_OFF_FORMAT_TRUNCATION snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Attempt to open %s failed with EACCES - root privileges may be required", full_path); DIAG_ON_FORMAT_TRUNCATION return PCAP_ERROR_PERM_DENIED; default: /* * Something went wrong. */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't open USB bus file %s", full_path); return PCAP_ERROR; } } if (handle->opt.rfmon) { /* * Monitor mode doesn't apply to USB devices. */ close(handle->fd); return PCAP_ERROR_RFMON_NOTSUP; } /* try to use fast mmap access */ if (usb_mmap(handle)) { /* We succeeded. */ handle->linktype = DLT_USB_LINUX_MMAPPED; handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_mmap; handle->cleanup_op = usb_cleanup_linux_mmap; #ifdef HAVE_LINUX_USBDEVICE_FS_H probe_devices(handlep->bus_index); #endif /* * "handle->fd" is a real file, so * "select()" and "poll()" work on it. */ handle->selectable_fd = handle->fd; return 0; } /* * We failed; try plain binary interface access. * * Attempt to set the ring size as appropriate for * the snapshot length, reducing the snapshot length * if that'd make the ring bigger than the kernel * supports. */ if (usb_set_ring_size(handle, (int)sizeof(pcap_usb_header)) == -1) { /* Failed. */ close(handle->fd); return PCAP_ERROR; } handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_bin; #ifdef HAVE_LINUX_USBDEVICE_FS_H probe_devices(handlep->bus_index); #endif /* * "handle->fd" is a real file, so "select()" and "poll()" * work on it. */ handle->selectable_fd = handle->fd; /* for plain binary access and text access we need to allocate the read * buffer */ handle->buffer = malloc(handle->bufsize); if (!handle->buffer) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "malloc"); close(handle->fd); return PCAP_ERROR; } return 0; } static int usb_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Packet injection is not supported on USB devices"); return (-1); } static int usb_setdirection_linux(pcap_t *p, pcap_direction_t d) { /* * It's guaranteed, at this point, that d is a valid * direction value. */ p->direction = d; return 0; } static int usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) { struct pcap_usb_linux *handlep = handle->priv; int ret; struct mon_bin_stats st; ret = ioctl(handle->fd, MON_IOCG_STATS, &st); if (ret < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't read stats from fd %d", handle->fd); return -1; } stats->ps_recv = handlep->packets_read + st.queued; stats->ps_drop = st.dropped; stats->ps_ifdrop = 0; return 0; } /* * see /Documentation/usb/usbmon.txt and * /drivers/usb/mon/mon_bin.c binary ABI */ static int usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) { struct pcap_usb_linux *handlep = handle->priv; struct mon_bin_get info; int ret; struct pcap_pkthdr pkth; u_int clen = handle->snapshot - sizeof(pcap_usb_header); /* the usb header is going to be part of 'packet' data*/ info.hdr = (pcap_usb_header*) handle->buffer; info.data = (u_char *)handle->buffer + sizeof(pcap_usb_header); info.data_len = clen; /* ignore interrupt system call errors */ do { ret = ioctl(handle->fd, MON_IOCX_GET, &info); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN) return 0; /* no data there */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't read from fd %d", handle->fd); return -1; } /* * info.hdr->data_len is the number of bytes of isochronous * descriptors (if any) plus the number of bytes of data * provided. There are no isochronous descriptors here, * because we're using the old 48-byte header. * * If info.hdr->data_flag is non-zero, there's no URB data; * info.hdr->urb_len is the size of the buffer into which * data is to be placed; it does not represent the amount * of data transferred. If info.hdr->data_flag is zero, * there is URB data, and info.hdr->urb_len is the number * of bytes transmitted or received; it doesn't include * isochronous descriptors. * * The kernel may give us more data than the snaplen; if it did, * reduce the data length so that the total number of bytes we * tell our client we have is not greater than the snaplen. */ if (info.hdr->data_len < clen) clen = info.hdr->data_len; info.hdr->data_len = clen; pkth.caplen = sizeof(pcap_usb_header) + clen; if (info.hdr->data_flag) { /* * No data; just base the on-the-wire length on * info.hdr->data_len (so that it's >= the captured * length). */ pkth.len = sizeof(pcap_usb_header) + info.hdr->data_len; } else { /* * We got data; base the on-the-wire length on * info.hdr->urb_len, so that it includes data * discarded by the USB monitor device due to * its buffer being too small. */ pkth.len = sizeof(pcap_usb_header) + info.hdr->urb_len; } pkth.ts.tv_sec = (time_t)info.hdr->ts_sec; pkth.ts.tv_usec = info.hdr->ts_usec; if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, handle->buffer, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, handle->buffer); return 1; } return 0; /* didn't pass filter */ } /* * see /Documentation/usb/usbmon.txt and * /drivers/usb/mon/mon_bin.c binary ABI */ #define VEC_SIZE 32 static int usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_usb_linux *handlep = handle->priv; struct mon_bin_mfetch fetch; int32_t vec[VEC_SIZE]; struct pcap_pkthdr pkth; u_char *bp; pcap_usb_header_mmapped* hdr; int nflush = 0; int packets = 0; u_int clen, max_clen; max_clen = handle->snapshot - sizeof(pcap_usb_header_mmapped); for (;;) { int i, ret; int limit; if (PACKET_COUNT_IS_UNLIMITED(max_packets)) { /* * There's no limit on the number of packets * to process, so try to fetch VEC_SIZE packets. */ limit = VEC_SIZE; } else { /* * Try to fetch as many packets as we have left * to process, or VEC_SIZE packets, whichever * is less. * * At this point, max_packets > 0 (otherwise, * PACKET_COUNT_IS_UNLIMITED(max_packets) * would be true) and max_packets > packets * (packet starts out as 0, and the test * at the bottom of the loop exits if * max_packets <= packets), so limit is * guaranteed to be > 0. */ limit = max_packets - packets; if (limit > VEC_SIZE) limit = VEC_SIZE; } /* * Try to fetch as many events as possible, up to * the limit, and flush the events we've processed * earlier (nflush) - MON_IOCX_MFETCH does both * (presumably to reduce the number of system * calls in loops like this). */ fetch.offvec = vec; fetch.nfetch = limit; fetch.nflush = nflush; /* ignore interrupt system call errors */ do { ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { if (errno == EAGAIN) return 0; /* no data there */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't mfetch fd %d", handle->fd); return -1; } /* keep track of processed events, we will flush them later */ nflush = fetch.nfetch; for (i=0; immapbuf[vec[i]]; /* That begins with a metadata header */ hdr = (pcap_usb_header_mmapped*) bp; /* discard filler */ if (hdr->event_type == '@') continue; /* * hdr->data_len is the number of bytes of * isochronous descriptors (if any) plus the * number of bytes of data provided. * * If hdr->data_flag is non-zero, there's no * URB data; hdr->urb_len is the size of the * buffer into which data is to be placed; it does * not represent the amount of data transferred. * If hdr->data_flag is zero, there is URB data, * and hdr->urb_len is the number of bytes * transmitted or received; it doesn't include * isochronous descriptors. * * The kernel may give us more data than the * snaplen; if it did, reduce the data length * so that the total number of bytes we * tell our client we have is not greater than * the snaplen. */ clen = max_clen; if (hdr->data_len < clen) clen = hdr->data_len; pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen; if (hdr->data_flag) { /* * No data; just base the on-the-wire length * on hdr->data_len (so that it's >= the * captured length). */ pkth.len = sizeof(pcap_usb_header_mmapped) + hdr->data_len; } else { /* * We got data; base the on-the-wire length * on hdr->urb_len, so that it includes * data discarded by the USB monitor device * due to its buffer being too small. */ pkth.len = sizeof(pcap_usb_header_mmapped) + (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len; /* * Now clean it up if it's a completion * event for an incoming isochronous * transfer. */ fix_linux_usb_mmapped_length(&pkth, bp); } pkth.ts.tv_sec = (time_t)hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; if (handle->fcode.bf_insns == NULL || pcap_filter(handle->fcode.bf_insns, (u_char*) hdr, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, (u_char*) hdr); packets++; } } /* * If max_packets specifiesg "unlimited", we stop after * the first chunk. */ if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets >= max_packets)) break; } /* flush pending events*/ if (ioctl(handle->fd, MON_IOCH_MFLUSH, nflush) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't mflush fd %d", handle->fd); return -1; } return packets; } static void usb_cleanup_linux_mmap(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; /* if we have a memory-mapped buffer, unmap it */ if (handlep->mmapbuf != NULL) { munmap(handlep->mmapbuf, handlep->mmapbuflen); handlep->mmapbuf = NULL; } pcap_cleanup_live_common(handle); } diff --git a/pcap/bpf.h b/pcap/bpf.h index a8eb177b43bc..3970d0a18426 100644 --- a/pcap/bpf.h +++ b/pcap/bpf.h @@ -1,291 +1,291 @@ /*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 */ /* * This is libpcap's cut-down version of bpf.h; it includes only * the stuff needed for the code generator and the userland BPF * interpreter, and the libpcap APIs for setting filters, etc.. * * "pcap-bpf.c" will include the native OS version, as it deals with * the OS's BPF implementation. * * At least two programs found by Google Code Search explicitly includes * (even though / includes it for you), * so moving that stuff to would break the build for some * programs. */ /* * If we've already included , don't re-define this stuff. * We assume BSD-style multiple-include protection in , * which is true of all but the oldest versions of FreeBSD and NetBSD, * or Tru64 UNIX-style multiple-include protection (or, at least, * Tru64 UNIX 5.x-style; I don't have earlier versions available to check), * or AIX-style multiple-include protection (or, at least, AIX 5.x-style; * I don't have earlier versions available to check), or QNX-style * multiple-include protection (as per GitHub pull request #394). * * We trust that they will define structures and macros and types in * a fashion that's source-compatible and binary-compatible with our * definitions. * * We do not check for BPF_MAJOR_VERSION, as that's defined by * , which is directly or indirectly included in some * programs that also include pcap.h, and doesn't * define stuff we need. We *do* protect against * defining various macros for BPF code itself; says * * Try and keep these values and structures similar to BSD, especially * the BPF code definitions which need to match so you can share filters * * so we trust that it will define them in a fashion that's source-compatible * and binary-compatible with our definitions. * * This also provides our own multiple-include protection. */ #if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) #define lib_pcap_bpf_h #include #include #ifdef __cplusplus extern "C" { #endif /* BSD style release date */ #define BPF_RELEASE 199606 #ifdef MSDOS /* must be 32-bit */ typedef long bpf_int32; typedef unsigned long bpf_u_int32; #else typedef int bpf_int32; typedef u_int bpf_u_int32; #endif /* * Alignment macros. BPF_WORDALIGN rounds up to the next * even multiple of BPF_ALIGNMENT. * * Tcpdump's print-pflog.c uses this, so we define it here. */ #ifndef __NetBSD__ #define BPF_ALIGNMENT sizeof(bpf_int32) #else #define BPF_ALIGNMENT sizeof(long) #endif #define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) /* * Structure for "pcap_compile()", "pcap_setfilter()", etc.. */ struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; /* * The instruction encodings. * * Please inform tcpdump-workers@lists.tcpdump.org if you use any * of the reserved values, so that we can note that they're used * (and perhaps implement it in the reference BPF implementation * and encourage its implementation elsewhere). */ /* * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000. */ /* instruction classes */ #define BPF_CLASS(code) ((code) & 0x07) #define BPF_LD 0x00 #define BPF_LDX 0x01 #define BPF_ST 0x02 #define BPF_STX 0x03 #define BPF_ALU 0x04 #define BPF_JMP 0x05 #define BPF_RET 0x06 #define BPF_MISC 0x07 /* ld/ldx fields */ #define BPF_SIZE(code) ((code) & 0x18) #define BPF_W 0x00 #define BPF_H 0x08 #define BPF_B 0x10 /* 0x18 reserved; used by BSD/OS */ #define BPF_MODE(code) ((code) & 0xe0) -#define BPF_IMM 0x00 +#define BPF_IMM 0x00 #define BPF_ABS 0x20 #define BPF_IND 0x40 #define BPF_MEM 0x60 #define BPF_LEN 0x80 #define BPF_MSH 0xa0 /* 0xc0 reserved; used by BSD/OS */ /* 0xe0 reserved; used by BSD/OS */ /* alu/jmp fields */ #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 #define BPF_MUL 0x20 #define BPF_DIV 0x30 #define BPF_OR 0x40 #define BPF_AND 0x50 #define BPF_LSH 0x60 #define BPF_RSH 0x70 #define BPF_NEG 0x80 #define BPF_MOD 0x90 #define BPF_XOR 0xa0 /* 0xb0 reserved */ /* 0xc0 reserved */ /* 0xd0 reserved */ /* 0xe0 reserved */ /* 0xf0 reserved */ #define BPF_JA 0x00 #define BPF_JEQ 0x10 #define BPF_JGT 0x20 #define BPF_JGE 0x30 #define BPF_JSET 0x40 /* 0x50 reserved; used on BSD/OS */ /* 0x60 reserved */ /* 0x70 reserved */ /* 0x80 reserved */ /* 0x90 reserved */ /* 0xa0 reserved */ /* 0xb0 reserved */ /* 0xc0 reserved */ /* 0xd0 reserved */ /* 0xe0 reserved */ /* 0xf0 reserved */ #define BPF_SRC(code) ((code) & 0x08) #define BPF_K 0x00 #define BPF_X 0x08 /* ret - BPF_K and BPF_X also apply */ #define BPF_RVAL(code) ((code) & 0x18) #define BPF_A 0x10 /* 0x18 reserved */ /* misc */ #define BPF_MISCOP(code) ((code) & 0xf8) #define BPF_TAX 0x00 /* 0x08 reserved */ /* 0x10 reserved */ /* 0x18 reserved */ /* #define BPF_COP 0x20 NetBSD "coprocessor" extensions */ /* 0x28 reserved */ /* 0x30 reserved */ /* 0x38 reserved */ /* #define BPF_COPX 0x40 NetBSD "coprocessor" extensions */ /* also used on BSD/OS */ /* 0x48 reserved */ /* 0x50 reserved */ /* 0x58 reserved */ /* 0x60 reserved */ /* 0x68 reserved */ /* 0x70 reserved */ /* 0x78 reserved */ #define BPF_TXA 0x80 /* 0x88 reserved */ /* 0x90 reserved */ /* 0x98 reserved */ /* 0xa0 reserved */ /* 0xa8 reserved */ /* 0xb0 reserved */ /* 0xb8 reserved */ /* 0xc0 reserved; used on BSD/OS */ /* 0xc8 reserved */ /* 0xd0 reserved */ /* 0xd8 reserved */ /* 0xe0 reserved */ /* 0xe8 reserved */ /* 0xf0 reserved */ /* 0xf8 reserved */ /* * The instruction data structure. */ struct bpf_insn { u_short code; - u_char jt; - u_char jf; + u_char jt; + u_char jf; bpf_u_int32 k; }; /* * Macros for insn array initializers. * * In case somebody's included , or something else that * gives the kernel's definitions of BPF statements, get rid of its * definitions, so we can supply ours instead. If some kernel's * definitions aren't *binary-compatible* with what BPF has had * since it first sprung from the brows of Van Jacobson and Steve * McCanne, that kernel should be fixed. */ #ifdef BPF_STMT #undef BPF_STMT #endif #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #ifdef BPF_JUMP #undef BPF_JUMP #endif #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } PCAP_AVAILABLE_0_4 PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); PCAP_AVAILABLE_0_6 PCAP_API int bpf_validate(const struct bpf_insn *f, int len); PCAP_AVAILABLE_0_4 PCAP_API char *bpf_image(const struct bpf_insn *, int); PCAP_AVAILABLE_0_6 PCAP_API void bpf_dump(const struct bpf_program *, int); /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). */ #define BPF_MEMWORDS 16 #ifdef __cplusplus } #endif #endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */ diff --git a/pcap/dlt.h b/pcap/dlt.h index ea8a5ba0d8ba..0da6de236ab6 100644 --- a/pcap/dlt.h +++ b/pcap/dlt.h @@ -1,1588 +1,1588 @@ /*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 */ #ifndef lib_pcap_dlt_h #define lib_pcap_dlt_h /* * Link-layer header type codes. * * Do *NOT* add new values to this list without asking * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run * the risk of using a value that's already being used for some other * purpose, and of having tools that read libpcap-format captures not * being able to handle captures with your new DLT_ value, with no hope * that they will ever be changed to do so (as that would destroy their * ability to read captures using that value for that other purpose). * * See * * https://www.tcpdump.org/linktypes.html * * for detailed descriptions of some of these link-layer header types. */ /* * These are the types that are the same on all platforms, and that * have been defined by for ages. */ #define DLT_NULL 0 /* BSD loopback encapsulation */ #define DLT_EN10MB 1 /* Ethernet (10Mb) */ #define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ #define DLT_AX25 3 /* Amateur Radio AX.25 */ #define DLT_PRONET 4 /* Proteon ProNET Token Ring */ #define DLT_CHAOS 5 /* Chaos */ #define DLT_IEEE802 6 /* 802.5 Token Ring */ #define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ #define DLT_SLIP 8 /* Serial Line IP */ #define DLT_PPP 9 /* Point-to-point Protocol */ #define DLT_FDDI 10 /* FDDI */ /* * These are types that are different on some platforms, and that * have been defined by for ages. We use #ifdefs to * detect the BSDs that define them differently from the traditional * libpcap * * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, * but I don't know what the right #define is for BSD/OS. */ #define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ #ifdef __OpenBSD__ #define DLT_RAW 14 /* raw IP */ #else #define DLT_RAW 12 /* raw IP */ #endif /* * Given that the only OS that currently generates BSD/OS SLIP or PPP * is, well, BSD/OS, arguably everybody should have chosen its values * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they * didn't. So it goes. */ #if defined(__NetBSD__) || defined(__FreeBSD__) #ifndef DLT_SLIP_BSDOS #define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ #define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ #endif #else #define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ #define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ #endif /* * NetBSD uses 15 for HIPPI. * * From a quick look at sys/net/if_hippi.h and sys/net/if_hippisubr.c * in an older version of NetBSD , the header appears to be: * - * a 1-byte ULP field (ULP-id)? + * a 1-byte ULP field (ULP-id)? * * a 1-byte flags field; * * a 2-byte "offsets" field; * * a 4-byte "D2 length" field (D2_Size?); * * a 4-byte "destination switch" field (or a 1-byte field * containing the Forwarding Class, Double_Wide, and Message_Type * sub fields, followed by a 3-byte Destination_Switch_Address * field?, HIPPI-LE 3.4-style?); * * a 4-byte "source switch" field (or a 1-byte field containing the * Destination_Address_type and Source_Address_Type fields, followed * by a 3-byte Source_Switch_Address field, HIPPI-LE 3.4-style?); * * a 2-byte reserved field; * * a 6-byte destination address field; * * a 2-byte "local admin" field; * * a 6-byte source address field; * * followed by an 802.2 LLC header. * * This looks somewhat like something derived from the HIPPI-FP 4.4 * Header_Area, followed an HIPPI-FP 4.4 D1_Area containing a D1 data set * with the header in HIPPI-LE 3.4 (ANSI X3.218-1993), followed by an * HIPPI-FP 4.4 D2_Area (with no Offset) containing the 802.2 LLC header * and payload? Or does the "offsets" field contain the D2_Offset, * with that many bytes of offset before the payload? * * See http://wotug.org/parallel/standards/hippi/ for an archive of * HIPPI specifications. * * RFC 2067 imposes some additional restrictions. It says that the * Offset is always zero * * HIPPI is long-gone, and the source files found in an older version * of NetBSD don't appear to be in the main CVS branch, so we may never * see a capture with this link-layer type. */ #if defined(__NetBSD__) #define DLT_HIPPI 15 /* HIPPI */ #endif /* * NetBSD uses 16 for DLT_HDLC; see below. * BSD/OS uses it for PPP; see above. * As far as I know, no other OS uses it for anything; don't use it * for anything else. */ /* * 17 was used for DLT_PFLOG in OpenBSD; it no longer is. * * It was DLT_LANE8023 in SuSE 6.3, so we defined LINKTYPE_PFLOG * as 117 so that pflog captures would use a link-layer header type * value that didn't collide with any other values. On all * platforms other than OpenBSD, we defined DLT_PFLOG as 117, * and we mapped between LINKTYPE_PFLOG and DLT_PFLOG. * * OpenBSD eventually switched to using 117 for DLT_PFLOG as well. * * Don't use 17 for anything else. */ /* * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and * macOS; don't use it for anything else. (FreeBSD uses 121, which * collides with DLT_HHDLC, even though it doesn't use 18 for * anything and doesn't appear to have ever used it for anything.) * * We define it as 18 on those platforms; it is, unfortunately, used * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC * in general. As the packet format for it, like that for * DLT_PFLOG, is not only OS-dependent but OS-version-dependent, * we don't support printing it in tcpdump except on OSes that * have the relevant header files, so it's not that useful on * other platforms. */ #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) #define DLT_PFSYNC 18 #endif #define DLT_ATM_CLIP 19 /* Linux Classical IP over ATM */ /* * Apparently Redback uses this for its SmartEdge 400/800. I hope * nobody else decided to use it, too. */ #define DLT_REDBACK_SMARTEDGE 32 /* * These values are defined by NetBSD; other platforms should refrain from * using them for other purposes, so that NetBSD savefiles with link * types of 50 or 51 can be read as this type on all platforms. */ #define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ #define DLT_PPP_ETHER 51 /* PPP over Ethernet */ /* * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses * a link-layer type of 99 for the tcpdump it supplies. The link-layer * header has 6 bytes of unknown data, something that appears to be an * Ethernet type, and 36 bytes that appear to be 0 in at least one capture * I've seen. */ #define DLT_SYMANTEC_FIREWALL 99 /* * Values between 100 and 103 are used in capture file headers as * link-layer header type LINKTYPE_ values corresponding to DLT_ types * that differ between platforms; don't use those values for new DLT_ * new types. */ /* * Values starting with 104 are used for newly-assigned link-layer * header type values; for those link-layer header types, the DLT_ * value returned by pcap_datalink() and passed to pcap_open_dead(), * and the LINKTYPE_ value that appears in capture files, are the * same. * * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is * the highest such value. */ #define DLT_MATCHING_MIN 104 /* * This value was defined by libpcap 0.5; platforms that have defined * it with a different value should define it here with that value - * a link type of 104 in a save file will be mapped to DLT_C_HDLC, * whatever value that happens to be, so programs will correctly * handle files with that link type regardless of the value of * DLT_C_HDLC. * * The name DLT_C_HDLC was used by BSD/OS; we use that name for source * compatibility with programs written for BSD/OS. * * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, * for source compatibility with programs written for libpcap 0.5. */ #define DLT_C_HDLC 104 /* Cisco HDLC */ #define DLT_CHDLC DLT_C_HDLC #define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ /* * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, * except when it isn't. (I.e., sometimes it's just raw IP, and * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, * so that we don't have to worry about the link-layer header.) */ /* * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides * with other values. * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header * (DLCI, etc.). */ #define DLT_FRELAY 107 /* * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except * that the AF_ type in the link-layer header is in network byte order. * * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so * we don't use 12 for it in OSes other than OpenBSD; instead, we * use the same value as LINKTYPE_LOOP. */ #ifdef __OpenBSD__ #define DLT_LOOP 12 #else #define DLT_LOOP 108 #endif /* * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other * than OpenBSD; instead, we use the same value as LINKTYPE_ENC. */ #ifdef __OpenBSD__ #define DLT_ENC 13 #else #define DLT_ENC 109 #endif /* * Values 110 and 111 are reserved for use in capture file headers * as link-layer types corresponding to DLT_ types that might differ * between platforms; don't use those values for new DLT_ types * other than the corresponding DLT_ types. */ /* * NetBSD uses 16 for (Cisco) "HDLC framing". For other platforms, * we define it to have the same value as LINKTYPE_NETBSD_HDLC. */ #if defined(__NetBSD__) #define DLT_HDLC 16 /* Cisco HDLC */ #else #define DLT_HDLC 112 #endif /* * Linux cooked sockets. */ #define DLT_LINUX_SLL 113 /* * Apple LocalTalk hardware. */ #define DLT_LTALK 114 /* * Acorn Econet. */ #define DLT_ECONET 115 /* * Reserved for use with OpenBSD ipfilter. */ #define DLT_IPFILTER 116 /* * OpenBSD DLT_PFLOG. */ #define DLT_PFLOG 117 /* * Registered for Cisco-internal use. */ #define DLT_CISCO_IOS 118 /* * For 802.11 cards using the Prism II chips, with a link-layer * header including Prism monitor mode information plus an 802.11 * header. */ #define DLT_PRISM_HEADER 119 /* * Reserved for Aironet 802.11 cards, with an Aironet link-layer header * (see Doug Ambrisko's FreeBSD patches). */ #define DLT_AIRONET_HEADER 120 /* * Sigh. * * 121 was reserved for Siemens HiPath HDLC on 2002-01-25, as * requested by Tomas Kukosa. * * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that * assigned 121 as DLT_PFSYNC. In current versions, its libpcap * does DLT_ <-> LINKTYPE_ mapping, mapping DLT_PFSYNC to a * LINKTYPE_PFSYNC value of 246, so it should write out DLT_PFSYNC * dump files with 246 as the link-layer header type. (Earlier * versions might not have done mapping, in which case they would * have written them out with a link-layer header type of 121.) * * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC; * its libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would * write out DLT_PFSYNC dump files with use 18 as the link-layer * header type. * * NetBSD, DragonFly BSD, and Darwin also use 18 for DLT_PFSYNC; in * current versions, their libpcaps do DLT_ <-> LINKTYPE_ mapping, * mapping DLT_PFSYNC to a LINKTYPE_PFSYNC value of 246, so they * should write out DLT_PFSYNC dump files with 246 as the link-layer * header type. (Earlier versions might not have done mapping, * in which case they'd work the same way OpenBSD does, writing * them out with a link-layer header type of 18.) * * We'll define DLT_PFSYNC as: * * 18 on NetBSD, OpenBSD, DragonFly BSD, and Darwin; * * 121 on FreeBSD; * * 246 everywhere else. * * We'll define DLT_HHDLC as 121 on everything except for FreeBSD; * anybody who wants to compile, on FreeBSD, code that uses DLT_HHDLC * is out of luck. * * We'll define LINKTYPE_PFSYNC as 246 on *all* platforms, so that * savefiles written using *this* code won't use 18 or 121 for PFSYNC, * they'll all use 246. * * Code that uses pcap_datalink() to determine the link-layer header * type of a savefile won't, when built and run on FreeBSD, be able * to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC capture * files, as pcap_datalink() will give 121 for both of them. Code * that doesn't, such as the code in Wireshark, will be able to * distinguish between them. * * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e., * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD, * DragonFly BSD, and macOS - to DLT_PFSYNC, so code built with FreeBSD's * libpcap won't treat those files as DLT_PFSYNC files. * * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC; * this means they can read DLT_HHDLC files, if any exist, but won't * treat pcap files written by any older versions of FreeBSD libpcap that * didn't map to 246 as DLT_PFSYNC files. */ #ifdef __FreeBSD__ #define DLT_PFSYNC 121 #else #define DLT_HHDLC 121 #endif /* * This is for RFC 2625 IP-over-Fibre Channel. * * This is not for use with raw Fibre Channel, where the link-layer * header starts with a Fibre Channel frame header; it's for IP-over-FC, * where the link-layer header starts with an RFC 2625 Network_Header * field. */ #define DLT_IP_OVER_FC 122 /* * This is for Full Frontal ATM on Solaris with SunATM, with a * pseudo-header followed by an AALn PDU. * * There may be other forms of Full Frontal ATM on other OSes, * with different pseudo-headers. * * If ATM software returns a pseudo-header with VPI/VCI information * (and, ideally, packet type information, e.g. signalling, ILMI, * LANE, LLC-multiplexed traffic, etc.), it should not use * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump * and the like don't have to infer the presence or absence of a * pseudo-header and the form of the pseudo-header. */ #define DLT_SUNATM 123 /* Solaris+SunATM */ /* * Reserved as per request from Kent Dahlgren * for private use. */ #define DLT_RIO 124 /* RapidIO */ #define DLT_PCI_EXP 125 /* PCI Express */ #define DLT_AURORA 126 /* Xilinx Aurora link layer */ /* * Header for 802.11 plus a number of bits of link-layer information * including radio information, used by some recent BSD drivers as * well as the madwifi Atheros driver for Linux. */ #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ /* * Reserved for the TZSP encapsulation, as per request from * Chris Waters * TZSP is a generic encapsulation for any other link type, * which includes a means to include meta-information * with the packet, e.g. signal strength and channel * for 802.11 packets. */ #define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ /* * BSD's ARCNET headers have the source host, destination host, * and type at the beginning of the packet; that's what's handed * up to userland via BPF. * * Linux's ARCNET headers, however, have a 2-byte offset field * between the host IDs and the type; that's what's handed up * to userland via PF_PACKET sockets. * * We therefore have to have separate DLT_ values for them. */ #define DLT_ARCNET_LINUX 129 /* ARCNET */ /* * Juniper-private data link types, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, etc.. */ #define DLT_JUNIPER_MLPPP 130 #define DLT_JUNIPER_MLFR 131 #define DLT_JUNIPER_ES 132 #define DLT_JUNIPER_GGSN 133 #define DLT_JUNIPER_MFR 134 #define DLT_JUNIPER_ATM2 135 #define DLT_JUNIPER_SERVICES 136 #define DLT_JUNIPER_ATM1 137 /* * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund * . The header that's presented is an Ethernet-like * header: * * #define FIREWIRE_EUI64_LEN 8 * struct firewire_header { * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; * u_char firewire_shost[FIREWIRE_EUI64_LEN]; * u_short firewire_type; * }; * * with "firewire_type" being an Ethernet type value, rather than, * for example, raw GASP frames being handed up. */ #define DLT_APPLE_IP_OVER_IEEE1394 138 /* * Various SS7 encapsulations, as per a request from Jeff Morriss * and subsequent discussions. */ #define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ #define DLT_MTP2 140 /* MTP2, without pseudo-header */ #define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ #define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ /* * DOCSIS MAC frames. */ #define DLT_DOCSIS 143 /* * Linux-IrDA packets. Protocol defined at https://www.irda.org. * Those packets include IrLAP headers and above (IrLMP...), but * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy * framing can be handled by the hardware and depend on the bitrate. * This is exactly the format you would get capturing on a Linux-IrDA * interface (irdaX), but not on a raw serial port. * Note the capture is done in "Linux-cooked" mode, so each packet include * a fake packet header (struct sll_header). This is because IrDA packet * decoding is dependent on the direction of the packet (incoming or * outgoing). * When/if other platform implement IrDA capture, we may revisit the * issue and define a real DLT_IRDA... * Jean II */ #define DLT_LINUX_IRDA 144 /* * Reserved for IBM SP switch and IBM Next Federation switch. */ #define DLT_IBM_SP 145 #define DLT_IBM_SN 146 /* * Reserved for private use. If you have some link-layer header type * that you want to use within your organization, with the capture files * using that link-layer header type not ever be sent outside your * organization, you can use these values. * * No libpcap release will use these for any purpose, nor will any * tcpdump release use them, either. * * Do *NOT* use these in capture files that you expect anybody not using * your private versions of capture-file-reading tools to read; in * particular, do *NOT* use them in products, otherwise you may find that * people won't be able to use tcpdump, or snort, or Ethereal, or... to * read capture files from your firewall/intrusion detection/traffic * monitoring/etc. appliance, or whatever product uses that DLT_ value, * and you may also find that the developers of those applications will * not accept patches to let them read those files. * * Also, do not use them if somebody might send you a capture using them * for *their* private type and tools using them for *your* private type * would have to read them. * * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, * as per the comment above, and use the type you're given. */ #define DLT_USER0 147 #define DLT_USER1 148 #define DLT_USER2 149 #define DLT_USER3 150 #define DLT_USER4 151 #define DLT_USER5 152 #define DLT_USER6 153 #define DLT_USER7 154 #define DLT_USER8 155 #define DLT_USER9 156 #define DLT_USER10 157 #define DLT_USER11 158 #define DLT_USER12 159 #define DLT_USER13 160 #define DLT_USER14 161 #define DLT_USER15 162 /* * For future use with 802.11 captures - defined by AbsoluteValue * Systems to store a number of bits of link-layer information * including radio information: * * http://www.shaftnet.org/~pizza/software/capturefrm.txt * * but it might be used by some non-AVS drivers now or in the * future. */ #define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, etc.. */ #define DLT_JUNIPER_MONITOR 164 /* * BACnet MS/TP frames. */ #define DLT_BACNET_MS_TP 165 /* * Another PPP variant as per request from Karsten Keil . * * This is used in some OSes to allow a kernel socket filter to distinguish * between incoming and outgoing packets, on a socket intended to * supply pppd with outgoing packets so it can do dial-on-demand and * hangup-on-lack-of-demand; incoming packets are filtered out so they * don't cause pppd to hold the connection up (you don't want random * input packets such as port scans, packets from old lost connections, * etc. to force the connection to stay up). * * The first byte of the PPP header (0xff03) is modified to accommodate * the direction - 0x00 = IN, 0x01 = OUT. */ #define DLT_PPP_PPPD 166 /* * Names for backwards compatibility with older versions of some PPP * software; new software should use DLT_PPP_PPPD. */ #define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD #define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_s are used * for passing on chassis-internal metainformation such as * QOS profiles, cookies, etc.. */ #define DLT_JUNIPER_PPPOE 167 #define DLT_JUNIPER_PPPOE_ATM 168 #define DLT_GPRS_LLC 169 /* GPRS LLC */ #define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ #define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ /* * Requested by Oolan Zimmer for use in Gcom's T1/E1 line * monitoring equipment. */ #define DLT_GCOM_T1E1 172 #define DLT_GCOM_SERIAL 173 /* * Juniper-private data link type, as per request from * Hannes Gredler . The DLT_ is used * for internal communication to Physical Interface Cards (PIC) */ #define DLT_JUNIPER_PIC_PEER 174 /* * Link types requested by Gregor Maier of Endace * Measurement Systems. They add an ERF header (see * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of * the link-layer header. */ #define DLT_ERF_ETH 175 /* Ethernet */ #define DLT_ERF_POS 176 /* Packet-over-SONET */ /* * Requested by Daniele Orlandi for raw LAPD * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header * includes additional information before the LAPD header, so it's * not necessarily a generic LAPD header. */ #define DLT_LINUX_LAPD 177 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames */ #define DLT_JUNIPER_ETHER 178 #define DLT_JUNIPER_PPP 179 #define DLT_JUNIPER_FRELAY 180 #define DLT_JUNIPER_CHDLC 181 /* * Multi Link Frame Relay (FRF.16) */ #define DLT_MFR 182 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ #define DLT_JUNIPER_VP 183 /* * Arinc 429 frames. * DLT_ requested by Gianluca Varenni . * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define DLT_A429 184 /* * Arinc 653 Interpartition Communication messages. * DLT_ requested by Gianluca Varenni . * Please refer to the A653-1 standard for more information. */ #define DLT_A653_ICM 185 /* * This used to be "USB packets, beginning with a USB setup header; * requested by Paolo Abeni ." * * However, that header didn't work all that well - it left out some * useful information - and was abandoned in favor of the DLT_USB_LINUX * header. * * This is now used by FreeBSD for its BPF taps for USB; that has its * own headers. So it is written, so it is done. * * For source-code compatibility, we also define DLT_USB to have this * value. We do it numerically so that, if code that includes this * file (directly or indirectly) also includes an OS header that also * defines DLT_USB as 186, we don't get a redefinition warning. * (NetBSD 7 does that.) */ #define DLT_USB_FREEBSD 186 #define DLT_USB 186 /* * Bluetooth HCI UART transport layer (part H:4); requested by * Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4 187 /* * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz * . */ #define DLT_IEEE802_16_MAC_CPS 188 /* * USB packets, beginning with a Linux USB header; requested by * Paolo Abeni . */ #define DLT_USB_LINUX 189 /* * Controller Area Network (CAN) v. 2.0B packets. * DLT_ requested by Gianluca Varenni . * Used to dump CAN packets coming from a CAN Vector board. * More documentation on the CAN v2.0B frames can be found at * http://www.can-cia.org/downloads/?269 */ #define DLT_CAN20B 190 /* * IEEE 802.15.4, with address fields padded, as is done by Linux * drivers; requested by Juergen Schimmer. */ #define DLT_IEEE802_15_4_LINUX 191 /* * Per Packet Information encapsulated packets. * DLT_ requested by Gianluca Varenni . */ #define DLT_PPI 192 /* * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; * requested by Charles Clancy. */ #define DLT_IEEE802_16_MAC_CPS_RADIO 193 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ #define DLT_JUNIPER_ISM 194 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing); requested by Mikko Saarnivala . * For this one, we expect the FCS to be present at the end of the frame; * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used. * * We keep the name DLT_IEEE802_15_4 as an alias for backwards * compatibility, but, again, this should *only* be used for 802.15.4 * frames that include the FCS. */ #define DLT_IEEE802_15_4_WITHFCS 195 #define DLT_IEEE802_15_4 DLT_IEEE802_15_4_WITHFCS /* * Various link-layer types, with a pseudo-header, for SITA * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). */ #define DLT_SITA 196 /* * Various link-layer types, with a pseudo-header, for Endace DAG cards; * encapsulates Endace ERF records. Requested by Stephen Donnelly * . */ #define DLT_ERF 197 /* * Special header prepended to Ethernet packets when capturing from a * u10 Networks board. Requested by Phil Mulholland * . */ #define DLT_RAIF1 198 /* * IPMB packet for IPMI, beginning with a 2-byte header, followed by * the I2C slave address, followed by the netFn and LUN, etc.. * Requested by Chanthy Toeung . * * XXX - this used to be called DLT_IPMB, back when we got the * impression from the email thread requesting it that the packet * had no extra 2-byte header. We've renamed it; if anybody used * DLT_IPMB and assumed no 2-byte header, this will cause the compile * to fail, at which point we'll have to figure out what to do about * the two header types using the same DLT_/LINKTYPE_ value. If that * doesn't happen, we'll assume nobody used it and that the redefinition * is safe. */ #define DLT_IPMB_KONTRON 199 /* * Juniper-private data link type, as per request from * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define DLT_JUNIPER_ST 200 /* * Bluetooth HCI UART transport layer (part H:4), with pseudo-header * that includes direction information; requested by Paolo Abeni. */ #define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 /* * AX.25 packet with a 1-byte KISS header; see * * http://www.ax25.net/kiss.htm * * as per Richard Stearn . */ #define DLT_AX25_KISS 202 /* * LAPD packets from an ISDN channel, starting with the address field, * with no pseudo-header. * Requested by Varuna De Silva . */ #define DLT_LAPD 203 /* * PPP, with a one-byte direction pseudo-header prepended - zero means * "received by this host", non-zero (any non-zero value) means "sent by * this host" - as per Will Barker . * * Don't confuse this with DLT_PPP_WITH_DIRECTION, which is an old * name for what is now called DLT_PPP_PPPD. */ #define DLT_PPP_WITH_DIR 204 /* * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero * means "received by this host", non-zero (any non-zero value) means * "sent by this host" - as per Will Barker . */ #define DLT_C_HDLC_WITH_DIR 205 /* * Frame Relay, with a one-byte direction pseudo-header prepended - zero * means "received by this host" (DCE -> DTE), non-zero (any non-zero * value) means "sent by this host" (DTE -> DCE) - as per Will Barker * . */ #define DLT_FRELAY_WITH_DIR 206 /* * LAPB, with a one-byte direction pseudo-header prepended - zero means * "received by this host" (DCE -> DTE), non-zero (any non-zero value) * means "sent by this host" (DTE -> DCE)- as per Will Barker * . */ #define DLT_LAPB_WITH_DIR 207 /* * 208 is reserved for an as-yet-unspecified proprietary link-layer * type, as requested by Will Barker. */ /* * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman * . */ #define DLT_IPMB_LINUX 209 /* * FlexRay automotive bus - http://www.flexray.com/ - as requested * by Hannes Kaelber . */ #define DLT_FLEXRAY 210 /* * Media Oriented Systems Transport (MOST) bus for multimedia * transport - https://www.mostcooperation.com/ - as requested * by Hannes Kaelber . */ #define DLT_MOST 211 /* * Local Interconnect Network (LIN) bus for vehicle networks - * http://www.lin-subbus.org/ - as requested by Hannes Kaelber * . */ #define DLT_LIN 212 /* * X2E-private data link type used for serial line capture, * as requested by Hannes Kaelber . */ #define DLT_X2E_SERIAL 213 /* * X2E-private data link type used for the Xoraya data logger * family, as requested by Hannes Kaelber . */ #define DLT_X2E_XORAYA 214 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), but with the PHY-level data for non-ASK PHYs (4 octets * of 0 as preamble, one octet of SFD, one octet of frame length+ * reserved bit, and then the MAC-layer data, starting with the * frame control field). * * Requested by Max Filippov . */ #define DLT_IEEE802_15_4_NONASK_PHY 215 /* * David Gibson requested this for * captures from the Linux kernel /dev/input/eventN devices. This * is used to communicate keystrokes and mouse movements from the * Linux kernel to display systems, such as Xorg. */ #define DLT_LINUX_EVDEV 216 /* * GSM Um and Abis interfaces, preceded by a "gsmtap" header. * * Requested by Harald Welte . */ #define DLT_GSMTAP_UM 217 #define DLT_GSMTAP_ABIS 218 /* * MPLS, with an MPLS label as the link-layer header. * Requested by Michele Marchetto on behalf * of OpenBSD. */ #define DLT_MPLS 219 /* * USB packets, beginning with a Linux USB header, with the USB header * padded to 64 bytes; required for memory-mapped access. */ #define DLT_USB_LINUX_MMAPPED 220 /* * DECT packets, with a pseudo-header; requested by * Matthias Wenzel . */ #define DLT_DECT 221 /* * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" * Date: Mon, 11 May 2009 11:18:30 -0500 * * DLT_AOS. We need it for AOS Space Data Link Protocol. * I have already written dissectors for but need an OK from * legal before I can submit a patch. * */ #define DLT_AOS 222 /* * Wireless HART (Highway Addressable Remote Transducer) * From the HART Communication Foundation * IES/PAS 62591 * * Requested by Sam Roberts . */ #define DLT_WIHART 223 /* * Fibre Channel FC-2 frames, beginning with a Frame_Header. * Requested by Kahou Lei . */ #define DLT_FC_2 224 /* * Fibre Channel FC-2 frames, beginning with an encoding of the * SOF, and ending with an encoding of the EOF. * * The encodings represent the frame delimiters as 4-byte sequences * representing the corresponding ordered sets, with K28.5 * represented as 0xBC, and the D symbols as the corresponding * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, * is represented as 0xBC 0xB5 0x55 0x55. * * Requested by Kahou Lei . */ #define DLT_FC_2_WITH_FRAME_DELIMS 225 /* * Solaris ipnet pseudo-header; requested by Darren Reed . * * The pseudo-header starts with a one-byte version number; for version 2, * the pseudo-header is: * * struct dl_ipnetinfo { * uint8_t dli_version; * uint8_t dli_family; * uint16_t dli_htype; * uint32_t dli_pktlen; * uint32_t dli_ifindex; * uint32_t dli_grifindex; * uint32_t dli_zsrc; * uint32_t dli_zdst; * }; * * dli_version is 2 for the current version of the pseudo-header. * * dli_family is a Solaris address family value, so it's 2 for IPv4 * and 26 for IPv6. * * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing * packets, and 2 for packets arriving from another zone on the same * machine. * * dli_pktlen is the length of the packet data following the pseudo-header * (so the captured length minus dli_pktlen is the length of the * pseudo-header, assuming the entire pseudo-header was captured). * * dli_ifindex is the interface index of the interface on which the * packet arrived. * * dli_grifindex is the group interface index number (for IPMP interfaces). * * dli_zsrc is the zone identifier for the source of the packet. * * dli_zdst is the zone identifier for the destination of the packet. * * A zone number of 0 is the global zone; a zone number of 0xffffffff * means that the packet arrived from another host on the network, not * from another zone on the same machine. * * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates * which of those it is. */ #define DLT_IPNET 226 /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied * by Linux SocketCAN, and with multi-byte numerical fields in that header * in big-endian byte order. * * See Documentation/networking/can.txt in the Linux source. * * Requested by Felix Obenhuber . */ #define DLT_CAN_SOCKETCAN 227 /* * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies * whether it's v4 or v6. Requested by Darren Reed . */ #define DLT_IPV4 228 #define DLT_IPV6 229 /* * IEEE 802.15.4, exactly as it appears in the spec (no padding, no * nothing), and with no FCS at the end of the frame; requested by * Jon Smirl . */ #define DLT_IEEE802_15_4_NOFCS 230 /* * Raw D-Bus: * * https://www.freedesktop.org/wiki/Software/dbus * * messages: * * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages * * starting with the endianness flag, followed by the message type, etc., * but without the authentication handshake before the message sequence: * * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol * * Requested by Martin Vidner . */ #define DLT_DBUS 231 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_VS 232 #define DLT_JUNIPER_SRX_E2E 233 #define DLT_JUNIPER_FIBRECHANNEL 234 /* * DVB-CI (DVB Common Interface for communication between a PC Card * module and a DVB receiver). See * * https://www.kaiser.cx/pcap-dvbci.html * * for the specification. * * Requested by Martin Kaiser . */ #define DLT_DVB_CI 235 /* * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but * *not* the same as, 27.010). Requested by Hans-Christoph Schemmel * . */ #define DLT_MUX27010 236 /* * STANAG 5066 D_PDUs. Requested by M. Baris Demiray * . */ #define DLT_STANAG_5066_D_PDU 237 /* * Juniper-private data link type, as per request from * Hannes Gredler . */ #define DLT_JUNIPER_ATM_CEMIC 238 /* * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki */ #define DLT_NFLOG 239 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and always * with the payload including the FCS, as supplied by their * netANALYZER hardware and software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER 240 /* * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type * for Ethernet packets with a 4-byte pseudo-header and FCS and * with the Ethernet header preceded by 7 bytes of preamble and * 1 byte of SFD, as supplied by their netANALYZER hardware and * software. * * Requested by Holger P. Frommer */ #define DLT_NETANALYZER_TRANSPARENT 241 /* * IP-over-InfiniBand, as specified by RFC 4391. * * Requested by Petr Sumbera . */ #define DLT_IPOIB 242 /* * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). * * Requested by Guy Martin . */ #define DLT_MPEG_2_TS 243 /* * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as * used by their ng40 protocol tester. * * Requested by Jens Grimmer . */ #define DLT_NG40 244 /* * Pseudo-header giving adapter number and flags, followed by an NFC * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, * as specified by NFC Forum Logical Link Control Protocol Technical * Specification LLCP 1.1. * * Requested by Mike Wakerly . */ #define DLT_NFC_LLCP 245 /* * 246 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. * * DLT_PFSYNC has different values on different platforms, and all of * them collide with something used elsewhere. On platforms that * don't already define it, define it as 246. */ #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) #define DLT_PFSYNC 246 #endif /* * Raw InfiniBand packets, starting with the Local Routing Header. * * Requested by Oren Kladnitsky . */ #define DLT_INFINIBAND 247 /* * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). * * Requested by Michael Tuexen . */ #define DLT_SCTP 248 /* * USB packets, beginning with a USBPcap header. * * Requested by Tomasz Mon */ #define DLT_USBPCAP 249 /* * Schweitzer Engineering Laboratories "RTAC" product serial-line * packets. * * Requested by Chris Bontje . */ #define DLT_RTAC_SERIAL 250 /* * Bluetooth Low Energy air interface link-layer packets. * * Requested by Mike Kershaw . */ #define DLT_BLUETOOTH_LE_LL 251 /* * DLT type for upper-protocol layer PDU saves from Wireshark. * * the actual contents are determined by two TAGs, one or more of * which is stored with each packet: * * EXP_PDU_TAG_DISSECTOR_NAME the name of the Wireshark dissector - * that can make sense of the data stored. + * that can make sense of the data stored. * * EXP_PDU_TAG_HEUR_DISSECTOR_NAME the name of the Wireshark heuristic * dissector that can make sense of the * data stored. */ #define DLT_WIRESHARK_UPPER_PDU 252 /* * DLT type for the netlink protocol (nlmon devices). */ #define DLT_NETLINK 253 /* * Bluetooth Linux Monitor headers for the BlueZ stack. */ #define DLT_BLUETOOTH_LINUX_MONITOR 254 /* * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as * captured by Ubertooth. */ #define DLT_BLUETOOTH_BREDR_BB 255 /* * Bluetooth Low Energy link layer packets, as captured by Ubertooth. */ #define DLT_BLUETOOTH_LE_LL_WITH_PHDR 256 /* * PROFIBUS data link layer. */ #define DLT_PROFIBUS_DL 257 /* * Apple's DLT_PKTAP headers. * * Sadly, the folks at Apple either had no clue that the DLT_USERn values * are for internal use within an organization and partners only, and * didn't know that the right way to get a link-layer header type is to * ask tcpdump.org for one, or knew and didn't care, so they just * used DLT_USER2, which causes problems for everything except for * their version of tcpdump. * * So I'll just give them one; hopefully this will show up in a * libpcap release in time for them to get this into 10.10 Big Sur * or whatever Mavericks' successor is called. LINKTYPE_PKTAP * will be 258 *even on macOS*; that is *intentional*, so that * PKTAP files look the same on *all* OSes (different OSes can have * different numerical values for a given DLT_, but *MUST NOT* have * different values for what goes in a file, as files can be moved * between OSes!). * * When capturing, on a system with a Darwin-based OS, on a device * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this * version of libpcap, the DLT_ value for the pcap_t will be DLT_PKTAP, * and that will continue to be DLT_USER2 on Darwin-based OSes. That way, * binary compatibility with Mavericks is preserved for programs using * this version of libpcap. This does mean that if you were using * DLT_USER2 for some capture device on macOS, you can't do so with * this version of libpcap, just as you can't with Apple's libpcap - * on macOS, they define DLT_PKTAP to be DLT_USER2, so programs won't * be able to distinguish between PKTAP and whatever you were using * DLT_USER2 for. * * If the program saves the capture to a file using this version of * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes. * That way, the file will *not* be a DLT_USER2 file. That means * that the latest version of tcpdump, when built with this version * of libpcap, and sufficiently recent versions of Wireshark will * be able to read those files and interpret them correctly; however, * Apple's version of tcpdump in OS X 10.9 won't be able to handle * them. (Hopefully, Apple will pick up this version of libpcap, * and the corresponding version of tcpdump, so that tcpdump will * be able to handle the old LINKTYPE_USER2 captures *and* the new * LINKTYPE_PKTAP captures.) */ #ifdef __APPLE__ #define DLT_PKTAP DLT_USER2 #else #define DLT_PKTAP 258 #endif /* * Ethernet packets preceded by a header giving the last 6 octets * of the preamble specified by 802.3-2012 Clause 65, section * 65.1.3.2 "Transmit". */ #define DLT_EPON 259 /* * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" * in the PICMG HPM.2 specification. */ #define DLT_IPMI_HPM_2 260 /* * per Joshua Wright , formats for Zwave captures. */ #define DLT_ZWAVE_R1_R2 261 #define DLT_ZWAVE_R3 262 /* * per Steve Karg , formats for Wattstopper * Digital Lighting Management room bus serial protocol captures. */ #define DLT_WATTSTOPPER_DLM 263 /* * ISO 14443 contactless smart card messages. */ #define DLT_ISO_14443 264 /* * Radio data system (RDS) groups. IEC 62106. * Per Jonathan Brucker . */ #define DLT_RDS 265 /* * USB packets, beginning with a Darwin (macOS, etc.) header. */ #define DLT_USB_DARWIN 266 /* * OpenBSD DLT_OPENFLOW. */ #define DLT_OPENFLOW 267 /* * SDLC frames containing SNA PDUs. */ #define DLT_SDLC 268 /* * per "Selvig, Bjorn" used for * TI protocol sniffer. */ #define DLT_TI_LLN_SNIFFER 269 /* * per: Erik de Jong for * https://github.com/eriknl/LoRaTap/releases/tag/v0.1 */ #define DLT_LORATAP 270 /* * per: Stefanha at gmail.com for * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h * for: https://qemu-project.org/Features/VirtioVsock */ #define DLT_VSOCK 271 /* * Nordic Semiconductor Bluetooth LE sniffer. */ #define DLT_NORDIC_BLE 272 /* * Excentis DOCSIS 3.1 RF sniffer (XRA-31) * per: bruno.verstuyft at excentis.com * https://www.xra31.com/xra-header */ #define DLT_DOCSIS31_XRA31 273 /* * mPackets, as specified by IEEE 802.3br Figure 99-4, starting * with the preamble and always ending with a CRC field. */ #define DLT_ETHERNET_MPACKET 274 /* * DisplayPort AUX channel monitoring data as specified by VESA * DisplayPort(DP) Standard preceded by a pseudo-header. * per dirk.eibach at gdsys.cc */ #define DLT_DISPLAYPORT_AUX 275 /* * Linux cooked sockets v2. */ #define DLT_LINUX_SLL2 276 /* * Sercos Monitor, per Manuel Jacob */ #define DLT_SERCOS_MONITOR 277 /* * OpenVizsla http://openvizsla.org is open source USB analyzer hardware. * It consists of FPGA with attached USB phy and FTDI chip for streaming * the data to the host PC. * * Current OpenVizsla data encapsulation format is described here: * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description * */ #define DLT_OPENVIZSLA 278 /* * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced * by a PCIe Card for interfacing high speed automotive interfaces. * * The specification for this frame format can be found at: * https://www.elektrobit.com/ebhscr * * for Guenter.Ebermann at elektrobit.com * */ #define DLT_EBHSCR 279 /* * The https://fd.io vpp graph dispatch tracer produces pcap trace files * in the format documented here: * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing */ #define DLT_VPP_DISPATCH 280 /* * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format. */ #define DLT_DSA_TAG_BRCM 281 #define DLT_DSA_TAG_BRCM_PREPEND 282 /* * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload * exactly as it appears in the spec (no padding, no nothing), and FCS if * specified by FCS Type TLV; requested by James Ko . * Specification at https://github.com/jkcko/ieee802.15.4-tap */ #define DLT_IEEE802_15_4_TAP 283 /* * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format. */ #define DLT_DSA_TAG_DSA 284 #define DLT_DSA_TAG_EDSA 285 /* * Payload of lawful intercept packets using the ELEE protocol; * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii */ #define DLT_ELEE 286 /* * Serial frames transmitted between a host and a Z-Wave chip. */ #define DLT_Z_WAVE_SERIAL 287 /* * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. */ #define DLT_USB_2_0 288 /* * ATSC Link-Layer Protocol (A/330) packets. */ #define DLT_ATSC_ALP 289 /* * In case the code that includes this file (directly or indirectly) * has also included OS files that happen to define DLT_MATCHING_MAX, * with a different value (perhaps because that OS hasn't picked up * the latest version of our DLT definitions), we undefine the * previous value of DLT_MATCHING_MAX. */ #ifdef DLT_MATCHING_MAX #undef DLT_MATCHING_MAX #endif #define DLT_MATCHING_MAX 289 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and * a member of that class. A class value of 0 indicates a regular * DLT_/LINKTYPE_ value. */ #define DLT_CLASS(x) ((x) & 0x03ff0000) /* * NetBSD-specific generic "raw" link type. The class value indicates * that this is the generic raw type, and the lower 16 bits are the * address family we're dealing with. Those values are NetBSD-specific; * do not assume that they correspond to AF_ values for your operating * system. */ #define DLT_CLASS_NETBSD_RAWAF 0x02240000 #define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) #define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) #define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) #endif /* !defined(lib_pcap_dlt_h) */ diff --git a/pcap/pcap.h b/pcap/pcap.h index 9fd14f5e9688..6894b3cd3265 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -1,1221 +1,1221 @@ /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Remote packet capture mechanisms and extensions from WinPcap: * * Copyright (c) 2002 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef lib_pcap_pcap_h #define lib_pcap_pcap_h /* * Some software that uses libpcap/WinPcap/Npcap defines _MSC_VER before * including pcap.h if it's not defined - and it defines it to 1500. * (I'm looking at *you*, lwIP!) * * Attempt to detect this, and undefine _MSC_VER so that we can *reliably* * use it to know what compiler is being used and, if it's Visual Studio, * what version is being used. */ #if defined(_MSC_VER) /* * We assume here that software such as that doesn't define _MSC_FULL_VER * as well and that it defines _MSC_VER with a value > 1200. * * DO NOT BREAK THESE ASSUMPTIONS. IF YOU FEEL YOU MUST DEFINE _MSC_VER * WITH A COMPILER THAT'S NOT MICROSOFT'S C COMPILER, PLEASE CONTACT * US SO THAT WE CAN MAKE IT SO THAT YOU DON'T HAVE TO DO THAT. THANK * YOU. * * OK, is _MSC_FULL_VER defined? */ #if !defined(_MSC_FULL_VER) /* * According to * * https://sourceforge.net/p/predef/wiki/Compilers/ * * with "Visual C++ 6.0 Processor Pack"/Visual C++ 6.0 SP6 and * later, _MSC_FULL_VER is defined, so either this is an older * version of Visual C++ or it's not Visual C++ at all. * * For Visual C++ 6.0, _MSC_VER is defined as 1200. */ #if _MSC_VER > 1200 /* * If this is Visual C++, _MSC_FULL_VER should be defined, so we * assume this isn't Visual C++, and undo the lie that it is. */ #undef _MSC_VER #endif #endif #endif #include #include #if defined(_WIN32) #include /* u_int, u_char etc. */ #include /* _get_osfhandle() */ #elif defined(MSDOS) #include /* u_int, u_char etc. */ #include #else /* UN*X */ #include /* u_int, u_char etc. */ #include #endif /* _WIN32/MSDOS/UN*X */ #include /* for SOCKET, as the active-mode rpcap APIs use it */ #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H #include #endif #include #ifdef __cplusplus extern "C" { #endif /* * Version number of the current version of the pcap file format. * * NOTE: this is *NOT* the version number of the libpcap library. * To fetch the version information for the version of libpcap * you're using, use pcap_lib_version(). */ #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define PCAP_ERRBUF_SIZE 256 /* * Compatibility for systems that have a bpf.h that * predates the bpf typedefs for 64-bit support. */ #if BPF_RELEASE - 0 < 199406 typedef int bpf_int32; typedef u_int bpf_u_int32; #endif typedef struct pcap pcap_t; typedef struct pcap_dumper pcap_dumper_t; typedef struct pcap_if pcap_if_t; typedef struct pcap_addr pcap_addr_t; /* * The first record in the file contains saved values for some * of the flags used in the printout phases of tcpdump. * Many fields here are 32 bit ints so compilers won't insert unwanted * padding; these files need to be interchangeable across architectures. * Documentation: https://www.tcpdump.org/manpages/pcap-savefile.5.txt. * * Do not change the layout of this structure, in any way (this includes * changes that only affect the length of fields in this structure). * * Also, do not change the interpretation of any of the members of this * structure, in any way (this includes using values other than * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" * field). * * Instead: * * introduce a new structure for the new format, if the layout * of the structure changed; * * send mail to "tcpdump-workers@lists.tcpdump.org", requesting * a new magic number for your new capture file format, and, when * you get the new magic number, put it in "savefile.c"; * * use that magic number for save files with the changed file * header; * * make the code in "savefile.c" capable of reading files with * the old file header as well as files with the new file header * (using the magic number to determine the header format). * * Then supply the changes by forking the branch at * * https://github.com/the-tcpdump-group/libpcap/tree/master * * and issuing a pull request, so that future versions of libpcap and * programs that use it (such as tcpdump) will be able to read your new * capture file format. */ struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction; this is always 0 */ bpf_u_int32 sigfigs; /* accuracy of timestamps; this is always 0 */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ }; /* * Macros for the value returned by pcap_datalink_ext(). * * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro * gives the FCS length of packets in the capture. */ #define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) #define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) #define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) typedef enum { PCAP_D_INOUT = 0, PCAP_D_IN, PCAP_D_OUT } pcap_direction_t; /* * Generic per-packet information, as supplied by libpcap. * * The time stamp can and should be a "struct timeval", regardless of * whether your system supports 32-bit tv_sec in "struct timeval", * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit * and 64-bit applications. The on-disk format of savefiles uses 32-bit * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit * and 64-bit versions of libpcap, even if they're on the same platform, * should supply the appropriate version of "struct timeval", even if * that's not what the underlying packet capture mechanism supplies. */ struct pcap_pkthdr { struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length of this packet (off wire) */ }; /* * As returned by the pcap_stats() */ struct pcap_stat { u_int ps_recv; /* number of packets received */ u_int ps_drop; /* number of packets dropped */ u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */ #ifdef _WIN32 u_int ps_capt; /* number of packets that reach the application */ u_int ps_sent; /* number of packets sent by the server on the network */ u_int ps_netdrop; /* number of packets lost on the network */ #endif /* _WIN32 */ }; #ifdef MSDOS /* * As returned by the pcap_stats_ex() */ struct pcap_stat_ex { u_long rx_packets; /* total packets received */ u_long tx_packets; /* total packets transmitted */ u_long rx_bytes; /* total bytes received */ u_long tx_bytes; /* total bytes transmitted */ u_long rx_errors; /* bad packets received */ u_long tx_errors; /* packet transmit problems */ u_long rx_dropped; /* no space in Rx buffers */ u_long tx_dropped; /* no space available for Tx */ u_long multicast; /* multicast packets received */ u_long collisions; /* detailed rx_errors: */ u_long rx_length_errors; u_long rx_over_errors; /* receiver ring buff overflow */ u_long rx_crc_errors; /* recv'd pkt with crc error */ u_long rx_frame_errors; /* recv'd frame alignment error */ u_long rx_fifo_errors; /* recv'r fifo overrun */ u_long rx_missed_errors; /* recv'r missed packet */ /* detailed tx_errors */ u_long tx_aborted_errors; u_long tx_carrier_errors; u_long tx_fifo_errors; u_long tx_heartbeat_errors; u_long tx_window_errors; }; #endif /* * Item in a list of interfaces. */ struct pcap_if { struct pcap_if *next; char *name; /* name to hand to "pcap_open_live()" */ char *description; /* textual description of interface, or NULL */ struct pcap_addr *addresses; bpf_u_int32 flags; /* PCAP_IF_ interface flags */ }; #define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ #define PCAP_IF_UP 0x00000002 /* interface is up */ #define PCAP_IF_RUNNING 0x00000004 /* interface is running */ #define PCAP_IF_WIRELESS 0x00000008 /* interface is wireless (*NOT* necessarily Wi-Fi!) */ #define PCAP_IF_CONNECTION_STATUS 0x00000030 /* connection status: */ #define PCAP_IF_CONNECTION_STATUS_UNKNOWN 0x00000000 /* unknown */ #define PCAP_IF_CONNECTION_STATUS_CONNECTED 0x00000010 /* connected */ #define PCAP_IF_CONNECTION_STATUS_DISCONNECTED 0x00000020 /* disconnected */ #define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE 0x00000030 /* not applicable */ /* * Representation of an interface address. */ struct pcap_addr { struct pcap_addr *next; struct sockaddr *addr; /* address */ struct sockaddr *netmask; /* netmask for that address */ struct sockaddr *broadaddr; /* broadcast address for that address */ struct sockaddr *dstaddr; /* P2P destination address for that address */ }; typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *); /* * Error codes for the pcap API. * These will all be negative, so you can check for the success or * failure of a call that returns these codes by checking for a * negative value. */ #define PCAP_ERROR -1 /* generic error code */ #define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ #define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ #define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ #define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ #define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ #define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ #define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ #define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ #define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */ #define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ #define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */ /* * Warning codes for the pcap API. * These will all be positive and non-zero, so they won't look like * errors. */ #define PCAP_WARNING 1 /* generic warning code */ #define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ #define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */ /* * Value to pass to pcap_compile() as the netmask if you don't know what * the netmask is. */ #define PCAP_NETMASK_UNKNOWN 0xffffffff /* * Initialize pcap. If this isn't called, pcap is initialized to * a mode source-compatible and binary-compatible with older versions * that lack this routine. */ /* * Initialization options. * All bits not listed here are reserved for expansion. * * On UNIX-like systems, the local character encoding is assumed to be * UTF-8, so no character encoding transformations are done. * * On Windows, the local character encoding is the local ANSI code page. */ #define PCAP_CHAR_ENC_LOCAL 0x00000000U /* strings are in the local character encoding */ #define PCAP_CHAR_ENC_UTF_8 0x00000001U /* strings are in UTF-8 */ PCAP_AVAILABLE_1_10 PCAP_API int pcap_init(unsigned int, char *); /* * We're deprecating pcap_lookupdev() for various reasons (not * thread-safe, can behave weirdly with WinPcap). Callers * should use pcap_findalldevs() and use the first device. */ PCAP_AVAILABLE_0_4 PCAP_DEPRECATED("use 'pcap_findalldevs' and use the first device") PCAP_API char *pcap_lookupdev(char *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); PCAP_AVAILABLE_1_0 PCAP_API pcap_t *pcap_create(const char *, char *); PCAP_AVAILABLE_1_0 PCAP_API int pcap_set_snaplen(pcap_t *, int); PCAP_AVAILABLE_1_0 PCAP_API int pcap_set_promisc(pcap_t *, int); PCAP_AVAILABLE_1_0 PCAP_API int pcap_can_set_rfmon(pcap_t *); PCAP_AVAILABLE_1_0 PCAP_API int pcap_set_rfmon(pcap_t *, int); PCAP_AVAILABLE_1_0 PCAP_API int pcap_set_timeout(pcap_t *, int); PCAP_AVAILABLE_1_2 PCAP_API int pcap_set_tstamp_type(pcap_t *, int); PCAP_AVAILABLE_1_5 PCAP_API int pcap_set_immediate_mode(pcap_t *, int); PCAP_AVAILABLE_1_0 PCAP_API int pcap_set_buffer_size(pcap_t *, int); PCAP_AVAILABLE_1_5 PCAP_API int pcap_set_tstamp_precision(pcap_t *, int); PCAP_AVAILABLE_1_5 PCAP_API int pcap_get_tstamp_precision(pcap_t *); PCAP_AVAILABLE_1_0 PCAP_API int pcap_activate(pcap_t *); PCAP_AVAILABLE_1_2 PCAP_API int pcap_list_tstamp_types(pcap_t *, int **); PCAP_AVAILABLE_1_2 PCAP_API void pcap_free_tstamp_types(int *); PCAP_AVAILABLE_1_2 PCAP_API int pcap_tstamp_type_name_to_val(const char *); PCAP_AVAILABLE_1_2 PCAP_API const char *pcap_tstamp_type_val_to_name(int); PCAP_AVAILABLE_1_2 PCAP_API const char *pcap_tstamp_type_val_to_description(int); #ifdef __linux__ PCAP_AVAILABLE_1_9 PCAP_API int pcap_set_protocol_linux(pcap_t *, int); #endif /* * Time stamp types. * Not all systems and interfaces will necessarily support all of these. * * A system that supports PCAP_TSTAMP_HOST is offering time stamps * provided by the host machine, rather than by the capture device, * but not committing to any characteristics of the time stamp. * * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine, * that's low-precision but relatively cheap to fetch; it's normally done * using the system clock, so it's normally synchronized with times you'd * fetch from system calls. * * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine, * that's high-precision; it might be more expensive to fetch. It is * synchronized with the system clock. * * PCAP_TSTAMP_HOST_HIPREC_UNSYNCED is a time stamp, provided by the host * machine, that's high-precision; it might be more expensive to fetch. * It is not synchronized with the system clock, and might have * problems with time stamps for packets received on different CPUs, * depending on the platform. It might be more likely to be strictly * monotonic than PCAP_TSTAMP_HOST_HIPREC. * * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the * capture device; it's synchronized with the system clock. * * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by * the capture device; it's not synchronized with the system clock. * * Note that time stamps synchronized with the system clock can go * backwards, as the system clock can go backwards. If a clock is * not in sync with the system clock, that could be because the * system clock isn't keeping accurate time, because the other * clock isn't keeping accurate time, or both. * * Note that host-provided time stamps generally correspond to the * time when the time-stamping code sees the packet; this could * be some unknown amount of time after the first or last bit of * the packet is received by the network adapter, due to batching * of interrupts for packet arrival, queueing delays, etc.. */ #define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */ #define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision, synced with the system clock */ #define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision, synced with the system clock */ #define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */ #define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */ #define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED 5 /* host-provided, high precision, not synced with the system clock */ /* * Time stamp resolution types. * Not all systems and interfaces will necessarily support all of these * resolutions when doing live captures; all of them can be requested * when reading a savefile. */ #define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */ #define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */ PCAP_AVAILABLE_0_4 PCAP_API pcap_t *pcap_open_live(const char *, int, int, int, char *); PCAP_AVAILABLE_0_6 PCAP_API pcap_t *pcap_open_dead(int, int); PCAP_AVAILABLE_1_5 PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int); PCAP_AVAILABLE_1_5 PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *); PCAP_AVAILABLE_0_4 PCAP_API pcap_t *pcap_open_offline(const char *, char *); #ifdef _WIN32 PCAP_AVAILABLE_1_5 PCAP_API pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *); PCAP_API pcap_t *pcap_hopen_offline(intptr_t, char *); /* * If we're building libpcap, these are internal routines in savefile.c, * so we must not define them as macros. * * If we're not building libpcap, given that the version of the C runtime * with which libpcap was built might be different from the version * of the C runtime with which an application using libpcap was built, * and that a FILE structure may differ between the two versions of the * C runtime, calls to _fileno() must use the version of _fileno() in * the C runtime used to open the FILE *, not the version in the C * runtime with which libpcap was built. (Maybe once the Universal CRT * rules the world, this will cease to be a problem.) */ #ifndef BUILDING_PCAP #define pcap_fopen_offline_with_tstamp_precision(f,p,b) \ pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b) #define pcap_fopen_offline(f,b) \ pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) #endif #else /*_WIN32*/ PCAP_AVAILABLE_1_5 PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); PCAP_AVAILABLE_0_9 PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *); #endif /*_WIN32*/ PCAP_AVAILABLE_0_4 PCAP_API void pcap_close(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); PCAP_AVAILABLE_0_4 PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *); PCAP_AVAILABLE_0_8 -PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); PCAP_AVAILABLE_0_8 PCAP_API void pcap_breakloop(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *); PCAP_AVAILABLE_0_9 -PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t); +PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t); PCAP_AVAILABLE_0_7 PCAP_API int pcap_getnonblock(pcap_t *, char *); PCAP_AVAILABLE_0_7 PCAP_API int pcap_setnonblock(pcap_t *, int, char *); PCAP_AVAILABLE_0_9 PCAP_API int pcap_inject(pcap_t *, const void *, size_t); PCAP_AVAILABLE_0_8 PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int); PCAP_AVAILABLE_1_0 PCAP_API const char *pcap_statustostr(int); PCAP_AVAILABLE_0_4 PCAP_API const char *pcap_strerror(int); PCAP_AVAILABLE_0_4 PCAP_API char *pcap_geterr(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API void pcap_perror(pcap_t *, const char *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32); PCAP_AVAILABLE_0_5 PCAP_DEPRECATED("use pcap_open_dead(), pcap_compile() and pcap_close()") PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *, const char *, int, bpf_u_int32); /* XXX - this took two arguments in 0.4 and 0.5 */ PCAP_AVAILABLE_0_6 PCAP_API void pcap_freecode(struct bpf_program *); PCAP_AVAILABLE_1_0 PCAP_API int pcap_offline_filter(const struct bpf_program *, const struct pcap_pkthdr *, const u_char *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_datalink(pcap_t *); PCAP_AVAILABLE_1_0 PCAP_API int pcap_datalink_ext(pcap_t *); PCAP_AVAILABLE_0_8 PCAP_API int pcap_list_datalinks(pcap_t *, int **); PCAP_AVAILABLE_0_8 PCAP_API int pcap_set_datalink(pcap_t *, int); PCAP_AVAILABLE_0_8 PCAP_API void pcap_free_datalinks(int *); PCAP_AVAILABLE_0_8 PCAP_API int pcap_datalink_name_to_val(const char *); PCAP_AVAILABLE_0_8 PCAP_API const char *pcap_datalink_val_to_name(int); PCAP_AVAILABLE_0_8 PCAP_API const char *pcap_datalink_val_to_description(int); PCAP_AVAILABLE_1_10 PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int); PCAP_AVAILABLE_0_4 PCAP_API int pcap_snapshot(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_is_swapped(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_major_version(pcap_t *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_minor_version(pcap_t *); PCAP_AVAILABLE_1_9 PCAP_API int pcap_bufsize(pcap_t *); /* XXX */ PCAP_AVAILABLE_0_4 PCAP_API FILE *pcap_file(pcap_t *); #ifdef _WIN32 /* * This probably shouldn't have been kept in WinPcap; most if not all * UN*X code that used it won't work on Windows. We deprecate it; if * anybody really needs access to whatever HANDLE may be associated * with a pcap_t (there's no guarantee that there is one), we can add * a Windows-only pcap_handle() API that returns the HANDLE. */ PCAP_AVAILABLE_0_4 PCAP_DEPRECATED("request a 'pcap_handle' that returns a HANDLE if you need it") PCAP_API int pcap_fileno(pcap_t *); #else /* _WIN32 */ PCAP_AVAILABLE_0_4 PCAP_API int pcap_fileno(pcap_t *); #endif /* _WIN32 */ #ifdef _WIN32 PCAP_API int pcap_wsockinit(void); #endif PCAP_AVAILABLE_0_4 PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); #ifdef _WIN32 PCAP_AVAILABLE_0_9 PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t); /* * If we're building libpcap, this is an internal routine in sf-pcap.c, so * we must not define it as a macro. * * If we're not building libpcap, given that the version of the C runtime * with which libpcap was built might be different from the version * of the C runtime with which an application using libpcap was built, * and that a FILE structure may differ between the two versions of the * C runtime, calls to _fileno() must use the version of _fileno() in * the C runtime used to open the FILE *, not the version in the C * runtime with which libpcap was built. (Maybe once the Universal CRT * rules the world, this will cease to be a problem.) */ #ifndef BUILDING_PCAP #define pcap_dump_fopen(p,f) \ pcap_dump_hopen(p, _get_osfhandle(_fileno(f))) #endif #else /*_WIN32*/ PCAP_AVAILABLE_0_9 PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); #endif /*_WIN32*/ PCAP_AVAILABLE_1_7 PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); PCAP_AVAILABLE_0_8 PCAP_API FILE *pcap_dump_file(pcap_dumper_t *); PCAP_AVAILABLE_0_9 PCAP_API long pcap_dump_ftell(pcap_dumper_t *); PCAP_AVAILABLE_1_9 PCAP_API int64_t pcap_dump_ftell64(pcap_dumper_t *); PCAP_AVAILABLE_0_8 PCAP_API int pcap_dump_flush(pcap_dumper_t *); PCAP_AVAILABLE_0_4 PCAP_API void pcap_dump_close(pcap_dumper_t *); PCAP_AVAILABLE_0_4 PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); PCAP_AVAILABLE_0_7 PCAP_API int pcap_findalldevs(pcap_if_t **, char *); PCAP_AVAILABLE_0_7 PCAP_API void pcap_freealldevs(pcap_if_t *); /* * We return a pointer to the version string, rather than exporting the * version string directly. * * On at least some UNIXes, if you import data from a shared library into * a program, the data is bound into the program binary, so if the string * in the version of the library with which the program was linked isn't * the same as the string in the version of the library with which the * program is being run, various undesirable things may happen (warnings, * the string being the one from the version of the library with which the * program was linked, or even weirder things, such as the string being the * one from the library but being truncated). * * On Windows, the string is constructed at run time. */ PCAP_AVAILABLE_0_8 PCAP_API const char *pcap_lib_version(void); #if defined(_WIN32) /* * Win32 definitions */ /*! \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). */ struct pcap_send_queue { u_int maxlen; /* Maximum size of the queue, in bytes. This variable contains the size of the buffer field. */ u_int len; /* Current size of the queue, in bytes. */ char *buffer; /* Buffer containing the packets to be sent. */ }; typedef struct pcap_send_queue pcap_send_queue; /*! \brief This typedef is a support for the pcap_get_airpcap_handle() function */ #if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) #define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ typedef struct _AirpcapHandle *PAirpcapHandle; #endif PCAP_API int pcap_setbuff(pcap_t *p, int dim); PCAP_API int pcap_setmode(pcap_t *p, int mode); PCAP_API int pcap_setmintocopy(pcap_t *p, int size); PCAP_API HANDLE pcap_getevent(pcap_t *p); PCAP_AVAILABLE_1_8 PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *); PCAP_AVAILABLE_1_8 PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *); PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); PCAP_API void pcap_sendqueue_destroy(pcap_send_queue* queue); PCAP_API int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); PCAP_API u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); PCAP_API struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); PCAP_API int pcap_setuserbuffer(pcap_t *p, int size); PCAP_API int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); PCAP_API int pcap_live_dump_ended(pcap_t *p, int sync); PCAP_API int pcap_start_oem(char* err_str, int flags); PCAP_API PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); #define MODE_CAPT 0 #define MODE_STAT 1 #define MODE_MON 2 #elif defined(MSDOS) /* * MS-DOS definitions */ PCAP_API int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); PCAP_API void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); PCAP_API u_long pcap_mac_packets (void); #else /* UN*X */ /* * UN*X definitions */ PCAP_AVAILABLE_0_8 PCAP_API int pcap_get_selectable_fd(pcap_t *); PCAP_AVAILABLE_1_9 PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *); #endif /* _WIN32/MSDOS/UN*X */ /* * Remote capture definitions. * * These routines are only present if libpcap has been configured to * include remote capture support. */ /* * The maximum buffer size in which address, port, interface names are kept. * * In case the adapter name or such is larger than this value, it is truncated. * This is not used by the user; however it must be aware that an hostname / interface * name longer than this value will be truncated. */ #define PCAP_BUF_SIZE 1024 /* * The type of input source, passed to pcap_open(). */ #define PCAP_SRC_FILE 2 /* local savefile */ #define PCAP_SRC_IFLOCAL 3 /* local network interface */ #define PCAP_SRC_IFREMOTE 4 /* interface on a remote host, using RPCAP */ /* * The formats allowed by pcap_open() are the following: * - file://path_and_filename [opens a local file] * - rpcap://devicename [opens the selected device available on the local host, without using the RPCAP protocol] * - rpcap://host/devicename [opens the selected device available on a remote host] * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged] * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged] * * The formats allowed by the pcap_findalldevs_ex() are the following: * - file://folder/ [lists all the files in the given folder] * - rpcap:// [lists all local adapters] * - rpcap://host:port/ [lists the devices available on a remote host] * * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable * SSL (if it has been compiled in). * * Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since * IPv6 is fully supported, these are the allowed formats: * * - host (literal): e.g. host.foo.bar * - host (numeric IPv4): e.g. 10.11.12.13 * - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] * - host (numeric IPv6): e.g. [1:2:3::4] * - port: can be either numeric (e.g. '80') or literal (e.g. 'http') * * Here you find some allowed examples: * - rpcap://host.foo.bar/devicename [everything literal, no port number] * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] * - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] * - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] * - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] */ /* * URL schemes for capture source. */ /* * This string indicates that the user wants to open a capture from a * local file. */ #define PCAP_SRC_FILE_STRING "file://" /* * This string indicates that the user wants to open a capture from a * network interface. This string does not necessarily involve the use * of the RPCAP protocol. If the interface required resides on the local * host, the RPCAP protocol is not involved and the local functions are used. */ #define PCAP_SRC_IF_STRING "rpcap://" /* * Flags to pass to pcap_open(). */ /* * Specifies whether promiscuous mode is to be used. */ #define PCAP_OPENFLAG_PROMISCUOUS 0x00000001 /* * Specifies, for an RPCAP capture, whether the data transfer (in * case of a remote capture) has to be done with UDP protocol. * * If it is '1' if you want a UDP data connection, '0' if you want * a TCP data connection; control connection is always TCP-based. * A UDP connection is much lighter, but it does not guarantee that all * the captured packets arrive to the client workstation. Moreover, * it could be harmful in case of network congestion. * This flag is meaningless if the source is not a remote interface. * In that case, it is simply ignored. */ #define PCAP_OPENFLAG_DATATX_UDP 0x00000002 /* * Specifies whether the remote probe will capture its own generated * traffic. * * In case the remote probe uses the same interface to capture traffic * and to send data back to the caller, the captured traffic includes * the RPCAP traffic as well. If this flag is turned on, the RPCAP * traffic is excluded from the capture, so that the trace returned * back to the collector is does not include this traffic. * * Has no effect on local interfaces or savefiles. */ #define PCAP_OPENFLAG_NOCAPTURE_RPCAP 0x00000004 /* * Specifies whether the local adapter will capture its own generated traffic. * * This flag tells the underlying capture driver to drop the packets * that were sent by itself. This is useful when building applications * such as bridges that should ignore the traffic they just sent. * * Supported only on Windows. */ #define PCAP_OPENFLAG_NOCAPTURE_LOCAL 0x00000008 /* * This flag configures the adapter for maximum responsiveness. * * In presence of a large value for nbytes, WinPcap waits for the arrival * of several packets before copying the data to the user. This guarantees * a low number of system calls, i.e. lower processor usage, i.e. better * performance, which is good for applications like sniffers. If the user * sets the PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will * copy the packets as soon as the application is ready to receive them. * This is suggested for real time applications (such as, for example, * a bridge) that need the best responsiveness. * * The equivalent with pcap_create()/pcap_activate() is "immediate mode". */ #define PCAP_OPENFLAG_MAX_RESPONSIVENESS 0x00000010 /* * Remote authentication methods. * These are used in the 'type' member of the pcap_rmtauth structure. */ /* * NULL authentication. * * The 'NULL' authentication has to be equal to 'zero', so that old * applications can just put every field of struct pcap_rmtauth to zero, * and it does work. */ #define RPCAP_RMTAUTH_NULL 0 /* * Username/password authentication. * * With this type of authentication, the RPCAP protocol will use the username/ * password provided to authenticate the user on the remote machine. If the * authentication is successful (and the user has the right to open network * devices) the RPCAP connection will continue; otherwise it will be dropped. * * *******NOTE********: unless TLS is being used, the username and password * are sent over the network to the capture server *IN CLEAR TEXT*. Don't * use this, without TLS (i.e., with rpcap:// rather than rpcaps://) on * a network that you don't completely control! (And be *really* careful * in your definition of "completely"!) */ #define RPCAP_RMTAUTH_PWD 1 /* * This structure keeps the information needed to authenticate the user * on a remote machine. * * The remote machine can either grant or refuse the access according * to the information provided. * In case the NULL authentication is required, both 'username' and * 'password' can be NULL pointers. * * This structure is meaningless if the source is not a remote interface; * in that case, the functions which requires such a structure can accept * a NULL pointer as well. */ struct pcap_rmtauth { /* * \brief Type of the authentication required. * * In order to provide maximum flexibility, we can support different types * of authentication based on the value of this 'type' variable. The currently * supported authentication methods are defined into the * \link remote_auth_methods Remote Authentication Methods Section\endlink. */ int type; /* * \brief Zero-terminated string containing the username that has to be * used on the remote machine for authentication. * * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication * and it can be NULL. */ char *username; /* * \brief Zero-terminated string containing the password that has to be * used on the remote machine for authentication. * * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication * and it can be NULL. */ char *password; }; /* * This routine can open a savefile, a local device, or a device on * a remote machine running an RPCAP server. * * For opening a savefile, the pcap_open_offline routines can be used, * and will work just as well; code using them will work on more * platforms than code using pcap_open() to open savefiles. * * For opening a local device, pcap_open_live() can be used; it supports * most of the capabilities that pcap_open() supports, and code using it * will work on more platforms than code using pcap_open(). pcap_create() * and pcap_activate() can also be used; they support all capabilities * that pcap_open() supports, except for the Windows-only * PCAP_OPENFLAG_NOCAPTURE_LOCAL, and support additional capabilities. * * For opening a remote capture, pcap_open() is currently the only * API available. */ PCAP_AVAILABLE_1_9 PCAP_API pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); PCAP_AVAILABLE_1_9 PCAP_API int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); PCAP_AVAILABLE_1_9 PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); /* * This routine can scan a directory for savefiles, list local capture * devices, or list capture devices on a remote machine running an RPCAP * server. * * For scanning for savefiles, it can be used on both UN*X systems and * Windows systems; for each directory entry it sees, it tries to open * the file as a savefile using pcap_open_offline(), and only includes * it in the list of files if the open succeeds, so it filters out * files for which the user doesn't have read permission, as well as * files that aren't valid savefiles readable by libpcap. * * For listing local capture devices, it's just a wrapper around * pcap_findalldevs(); code using pcap_findalldevs() will work on more * platforms than code using pcap_findalldevs_ex(). * * For listing remote capture devices, pcap_findalldevs_ex() is currently * the only API available. */ PCAP_AVAILABLE_1_9 PCAP_API int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); /* * Sampling methods. * * These allow pcap_loop(), pcap_dispatch(), pcap_next(), and pcap_next_ex() * to see only a sample of packets, rather than all packets. * * Currently, they work only on Windows local captures. */ /* * Specifies that no sampling is to be done on the current capture. * * In this case, no sampling algorithms are applied to the current capture. */ #define PCAP_SAMP_NOSAMP 0 /* * Specifies that only 1 out of N packets must be returned to the user. * * In this case, the 'value' field of the 'pcap_samp' structure indicates the * number of packets (minus 1) that must be discarded before one packet got * accepted. * In other words, if 'value = 10', the first packet is returned to the * caller, while the following 9 are discarded. */ #define PCAP_SAMP_1_EVERY_N 1 /* * Specifies that we have to return 1 packet every N milliseconds. * * In this case, the 'value' field of the 'pcap_samp' structure indicates * the 'waiting time' in milliseconds before one packet got accepted. * In other words, if 'value = 10', the first packet is returned to the * caller; the next returned one will be the first packet that arrives * when 10ms have elapsed. */ #define PCAP_SAMP_FIRST_AFTER_N_MS 2 /* * This structure defines the information related to sampling. * * In case the sampling is requested, the capturing device should read * only a subset of the packets coming from the source. The returned packets * depend on the sampling parameters. * * WARNING: The sampling process is applied *after* the filtering process. * In other words, packets are filtered first, then the sampling process * selects a subset of the 'filtered' packets and it returns them to the * caller. */ struct pcap_samp { /* * Method used for sampling; see above. */ int method; /* * This value depends on the sampling method defined. * For its meaning, see above. */ int value; }; /* * New functions. */ PCAP_AVAILABLE_1_9 PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p); /* * RPCAP active mode. */ /* Maximum length of an host name (needed for the RPCAP active mode) */ #define RPCAP_HOSTLIST_SIZE 1024 PCAP_AVAILABLE_1_9 PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); PCAP_AVAILABLE_1_10 PCAP_API SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, int uses_ssl, char *errbuf); PCAP_AVAILABLE_1_9 PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); PCAP_AVAILABLE_1_9 PCAP_API int pcap_remoteact_close(const char *host, char *errbuf); PCAP_AVAILABLE_1_9 PCAP_API void pcap_remoteact_cleanup(void); #ifdef __cplusplus } #endif #endif /* lib_pcap_pcap_h */ diff --git a/rpcapd/Makefile.in b/rpcapd/Makefile.in index 32906790fba1..b0145cf23612 100644 --- a/rpcapd/Makefile.in +++ b/rpcapd/Makefile.in @@ -1,142 +1,142 @@ # Copyright (c) 1993, 1994, 1995, 1996 -# The Regents of the University of California. All rights reserved. +# The Regents of the University of California. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that: (1) source code distributions # retain the above copyright notice and this paragraph in its entirety, (2) # distributions including binary code include the above copyright notice and # this paragraph in its entirety in the documentation or other materials # provided with the distribution, and (3) all advertising materials mentioning # features or use of this software display the following acknowledgement: # ``This product includes software developed by the University of California, # Lawrence Berkeley Laboratory and its contributors.'' Neither the name of # the University nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior # written permission. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # Various configurable paths (remember to edit Makefile.in, not Makefile) # # Top level hierarchy prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ # Pathname of directory to install the configure program bindir = @bindir@ # Pathname of directory to install the rpcapd daemon sbindir = @sbindir@ # Pathname of directory to install the include files includedir = @includedir@ # Pathname of directory to install the library libdir = @libdir@ # Pathname of directory to install the man pages mandir = @mandir@ # VPATH srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ # # You shouldn't need to edit anything below. # LD = /usr/bin/ld CC = @CC@ AR = @AR@ LN_S = @LN_S@ MKDEP = @MKDEP@ CCOPT = @V_CCOPT@ INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ DEFS = @DEFS@ @V_DEFS@ ADDLOBJS = @ADDLOBJS@ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ LIBS = @LIBS@ PTHREAD_LIBS = @PTHREAD_LIBS@ CROSSFLAGS= CFLAGS = @CFLAGS@ ${CROSSFLAGS} LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} DYEXT = @DYEXT@ V_RPATH_OPT = @V_RPATH_OPT@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ PROG=libpcap RPCAPD_LIBS = @RPCAPD_LIBS@ # Standard CFLAGS FULL_CFLAGS = $(CCOPT) @V_PROG_CCOPT_FAT@ $(INCLS) $(DEFS) $(CFLAGS) INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ # Explicitly define compilation rule since SunOS 4's make doesn't like gcc. # Also, gcc does not remove the .o before forking 'as', which can be a # problem if you don't own the file but can write to the directory. .c.o: @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c SRC = daemon.c \ fileconf.c \ log.c \ rpcapd.c OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o ../sslutils.o PUBHDR = HDR = $(PUBHDR) log.h TAGFILES = \ $(SRC) $(HDR) CLEANFILES = $(OBJ) rpcapd MANADMIN = \ rpcapd.manadmin.in MANFILE = \ rpcapd-config.manfile.in rpcapd: $(OBJ) ../libpcap.a $(CC) $(CCOPT) $(CFLAGS) $(LDFLAGS) @V_PROG_LDFLAGS_FAT@ \ -o $@ $(OBJ) ../libpcap.a $(LIBS) $(RPCAPD_LIBS) $(PTHREAD_LIBS) clean: rm -f $(CLEANFILES) distclean: clean rm -f Makefile config.cache config.log config.status \ config.h stamp-h stamp-h.in rm -f $(MANADMIN:.in=) $(MANFILE:.in=) rm -rf autom4te.cache install: rpcapd [ -d $(DESTDIR)$(sbindir) ] || \ (mkdir -p $(DESTDIR)$(sbindir); chmod 755 $(DESTDIR)$(sbindir)) $(INSTALL_PROGRAM) rpcapd $(DESTDIR)$(sbindir)/rpcapd [ -d $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@) [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) for i in $(MANADMIN); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manadmin.in/.manadmin/'` \ $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done for i in $(MANFILE); do \ $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done uninstall: rm -f $(DESTDIR)$(sbindir)/rpcapd for i in $(MANADMIN); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done for i in $(MANFILE); do \ rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done tags: $(TAGFILES) ctags -wtd $(TAGFILES) depend: $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/rpcapd/org.tcpdump.rpcapd.plist b/rpcapd/org.tcpdump.rpcapd.plist index b0e24398b677..c485787552df 100644 --- a/rpcapd/org.tcpdump.rpcapd.plist +++ b/rpcapd/org.tcpdump.rpcapd.plist @@ -1,30 +1,30 @@ Disabled Label - com.tcpdump.rpcapd + org.tcpdump.rpcapd Program /usr/local/libexec/rpcapd ProgramArguments /usr/local/libexec/rpcapd -i Sockets Listeners SockServiceName 2002 inetdCompatibility Wait diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in index 791b4ad1735e..f3ab6ea4a99a 100644 --- a/rpcapd/rpcapd.manadmin.in +++ b/rpcapd/rpcapd.manadmin.in @@ -1,282 +1,322 @@ .\" rpcapd.8 .\" .\" Copyright (c) 2002-2005 NetGroup, Politecnico di Torino (Italy) .\" Copyright (c) 2005-2009 CACE Technologies .\" Copyright (c) 2018- The TCPdump Group .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the Politecnico di Torino nor the names of its .\" contributors may be used to endorse or promote products derived from .\" this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.TH RPCAPD @MAN_ADMIN_COMMANDS@ "13 January 2019" +.TH RPCAPD @MAN_ADMIN_COMMANDS@ "20 January 2023" .SH NAME rpcapd \- capture daemon to be controlled by a remote libpcap application .SH SYNOPSIS .na rpcapd [ .B \-b .I address ] [ .B \-p .I port ] [ .B \-4 ] [ .B \-l .I host_list ] .ti +8 [ .B \-a .IR host , port ] [ .B \-n ] [ .B \-v ] [ .B \-d ] [ .B \-i ] .ti +8 [ .B \-D ] [ .B \-s .I config_file ] [ .B \-f .I config_file ] [ .B \-S ] .ti +8 [ .B \-K .I ssl_keyfile ] [ .B \-X .I ssl_certfile ] [ .B \-C ] .br .ad .SH DESCRIPTION .LP \fIRpcapd\fP is a daemon (Unix) or service (Win32) that allows the capture and filter part of libpcap to be run on a remote system. .LP Rpcapd can run in two modes: passive mode (default) and active mode. .LP In passive mode, the client (e.g., a network sniffer) connects to .BR rpcapd . The client then sends the appropriate commands to .B rpcapd to start the capture. .LP In active mode, .B rpcapd tries to establish a connection toward the client (e.g., a network sniffer). The client then sends the appropriate commands to rpcapd to start the capture. .LP Active mode is useful in case .B rpcapd is run behind a firewall and cannot receive connections from the external world. In this case, .B rpcapd can be configured to establish the connection to a given host, which has to be configured in order to wait for that connection. After establishing the connection, the protocol continues its job in almost the same way in both active and passive mode. .SH Configuration file .LP The user can create a configuration file in the same directory as the executable, and put the configuration commands in there. In order for .B rpcapd to execute the commands, it needs to be restarted on Win32, i.e. the configuration file is parsed only at the beginning. The UNIX version of .B rpcapd will reread the configuration file upon receiving a HUP signal. In that case, all the existing connections remain in place, while the new connections will be created according to the new parameters. .LP In case a user does not want to create the configuration file manually, they can launch .B rpcapd with the desired flags plus .BR "-s filename" . Rpcapd will parse all the parameters and save them into the specified configuration file. .SH Installing rpcapd on Win32 .LP The remote daemon is installed automatically when installing WinPcap. The installation process places the .B rpcapd executable file into the WinPcap folder. This file can be executed either from the command line, or as a service. For instance, the installation process updates the list of available services list and it creates a new item (Remote Packet Capture Protocol v.0 (experimental)). To avoid security problems, the service is inactive and it has to be started manually (control panel - administrative tools - services - start). .LP The service has a set of "standard" parameters, i.e. it is launched with the .B \-d flag (in order to make it run as a service) and the .B "-f rpcapd.ini" flag. .SH Starting rpcapd on Win32 .LP The .B rpcapd executable can be launched directly, i.e. it can run in the foreground as well (not as a daemon/service). The procedure is quite simple: you have to invoke the executable from the command line with all the requested parameters except for the .B \-d flag. The capture server will start in the foreground. .SH Installing rpcapd on Unix-like systems TBD .SH Starting rpcapd on Unix-like systems .B rpcapd needs sufficient privileges to perform packet capture, e.g. run as root or be owned by root and have suid set. Most operating systems provide more elegant solutions when run as user than the above solutions, all of them different. +.LP +If your system supports +.BR systemd (1) +and the corresponding +.B rpcapd.socket +and +.B rpcapd@.service +service files have been +installed, the rpcapd service can be enabled by enabling the +.B rpcapd.socket +unit. +.LP +If your system supports +.BR launchd (@MAN_ADMIN_COMMANDS@) +and the +.B org.tcpdump.rpcapd.plist +file has been installed, the rpcapd service can be enabled by loading +the +.B org.tcpdump.rpcapd +service. +.LP +If your system supports +.BR inetd (@MAN_ADMIN_COMMANDS@) +and the +.B rpcapd.inetd.conf +entry has been added to +.BR inetd.conf (@MAN_FILE_FORMATS@), +the rpcapd service can be enabled by telling +.B inetd +to reread its configuration file. +.LP +If your system supports +.BR xinetd (@MAN_ADMIN_COMMANDS@) +and the +.B rpcapd.xinetd.conf +entry has been added to +.BR xinetd.conf (@MAN_FILE_FORMATS@), +the rpcapd service can be enabled by telling +.B xinetd +to reread its configuration file. .SH OPTIONS .TP .BI \-b " address" Bind to the IP address specified by .I address (either numeric or literal). By default, .B rpcapd binds to all local IPv4 and IPv6 addresses. .TP .BI \-p " port" Bind to the port specified by .IR port . By default, .B rpcapd binds to port 2002. .TP .B \-4 Listen only on IPv4 addresses. By default, .B rpcapd listens on both IPv4 and IPv6 addresses. .TP .BI \-l " host_list" Only allow hosts specified in the .I host_list argument to connect to this server. .I host_list is a list of host names or IP addresses, separated by commas. We suggest that you use host names rather than literal IP addresses in order to avoid problems with different address families. .TP .B \-n Permit NULL authentication (usually used with .BR \-l ). .TP .BI \-a " host" , "port" Run in active mode, connecting to host .I host on port .IR port . In case .I port is omitted, the default port (2003) is used. .TP .B -v Run in active mode only; by default, if .B \-a is specified, .B rpcapd it accepts passive connections as well. .TP .B \-d Run in daemon mode (UNIX only) or as a service (Win32 only). Warning (Win32): this flag is specified automatically when the service is started from the control panel. .TP .B \-i Run in inetd mode (UNIX only). .TP .B \-D Log debugging messages. .TP .BI \-s " config_file" Save the current configuration to .I config_file in the format specified by .BR rpcapd-config (@MAN_FILE_FORMATS@). .TP .BI \-f " config_file" Load the current configuration from .I config_file in the format specified by .BR rpcapd-config (@MAN_FILE_FORMATS@) and ignore all flags specified on the command line. .TP .B \-h Print this help screen. .LP If .B rpcapd was compiled with SSL support, the following options are also available: .TP .B \-S Require that SSL be used on connections. .TP .B \-C With SSL enabled, XXX - I'm not sure how *fetching* the list of compression mechanisms does anything to compression. .TP .B \-S .I ssl_keyfile With SSL enabled, use .I ssl_keyfile as the SSL key file. .TP .B \-X .I ssl_certfile With SSL enabled, use .I ssl_certfile as the SSL certificate file. .br .ad .SH "SEE ALSO" .BR pcap (3PCAP), .BR rpcapd-config (@MAN_FILE_FORMATS@) diff --git a/sockutils.c b/sockutils.c index 933f32670761..1c07f76fd1c0 100644 --- a/sockutils.c +++ b/sockutils.c @@ -1,2112 +1,2112 @@ /* * Copyright (c) 2002 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifdef HAVE_CONFIG_H #include #endif /* * \file sockutils.c * * The goal of this file is to provide a common set of primitives for socket * manipulation. * * Although the socket interface defined in the RFC 2553 (and its updates) * is excellent, there are still differences between the behavior of those * routines on UN*X and Windows, and between UN*Xes. * * These calls provide an interface similar to the socket interface, but * that hides the differences between operating systems. It does not * attempt to significantly improve on the socket interface in other * ways. */ #include "ftmacros.h" #include #include /* for the errno variable */ #include /* for the stderr file */ #include /* for malloc() and free() */ #include /* for INT_MAX */ #include "pcap-int.h" #include "sockutils.h" #include "portability.h" #ifdef _WIN32 /* * Winsock initialization. * * Ask for Winsock 2.2. */ #define WINSOCK_MAJOR_VERSION 2 #define WINSOCK_MINOR_VERSION 2 static int sockcount = 0; /*!< Variable that allows calling the WSAStartup() only one time */ #endif /* Some minor differences between UNIX and Win32 */ #ifdef _WIN32 #define SHUT_WR SD_SEND /* The control code for shutdown() is different in Win32 */ #endif /* Size of the buffer that has to keep error messages */ #define SOCK_ERRBUF_SIZE 1024 /* Constants; used in order to keep strings here */ #define SOCKET_NO_NAME_AVAILABLE "No name available" #define SOCKET_NO_PORT_AVAILABLE "No port available" #define SOCKET_NAME_NULL_DAD "Null address (possibly DAD Phase)" /* * On UN*X, send() and recv() return ssize_t. * * On Windows, send() and recv() return an int. * * With MSVC, there *is* no ssize_t. * * With MinGW, there is an ssize_t type; it is either an int (32 bit) * or a long long (64 bit). * * So, on Windows, if we don't have ssize_t defined, define it as an * int, so we can use it, on all platforms, as the type of variables * that hold the return values from send() and recv(). */ #if defined(_WIN32) && !defined(_SSIZE_T_DEFINED) typedef int ssize_t; #endif /**************************************************** * * * Locally defined functions * * * ****************************************************/ static int sock_ismcastaddr(const struct sockaddr *saddr); /**************************************************** * * * Function bodies * * * ****************************************************/ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION const uint8_t *fuzzBuffer; size_t fuzzSize; size_t fuzzPos; void sock_initfuzz(const uint8_t *Data, size_t Size) { fuzzPos = 0; fuzzSize = Size; fuzzBuffer = Data; } static int fuzz_recv(char *bufp, int remaining) { if (remaining > fuzzSize - fuzzPos) { remaining = fuzzSize - fuzzPos; } if (fuzzPos < fuzzSize) { memcpy(bufp, fuzzBuffer + fuzzPos, remaining); } fuzzPos += remaining; return remaining; } #endif int sock_geterrcode(void) { #ifdef _WIN32 return GetLastError(); #else return errno; #endif } /* * Format an error message given an errno value (UN*X) or a Winsock error * (Windows). */ void sock_vfmterrmsg(char *errbuf, size_t errbuflen, int errcode, const char *fmt, va_list ap) { if (errbuf == NULL) return; #ifdef _WIN32 pcap_vfmt_errmsg_for_win32_err(errbuf, errbuflen, errcode, fmt, ap); #else pcap_vfmt_errmsg_for_errno(errbuf, errbuflen, errcode, fmt, ap); #endif } void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, const char *fmt, ...) { va_list ap; va_start(ap, fmt); sock_vfmterrmsg(errbuf, errbuflen, errcode, fmt, ap); va_end(ap); } /* * Format an error message for the last socket error. */ void sock_geterrmsg(char *errbuf, size_t errbuflen, const char *fmt, ...) { va_list ap; va_start(ap, fmt); sock_vfmterrmsg(errbuf, errbuflen, sock_geterrcode(), fmt, ap); va_end(ap); } /* * Types of error. * * These are sorted by how likely they are to be the "underlying" problem, * so that lower-rated errors for a given address in a given family * should not overwrite higher-rated errors for another address in that * family, and higher-rated errors should overwrit elower-rated errors. */ typedef enum { SOCK_CONNERR, /* connection error */ SOCK_HOSTERR, /* host error */ SOCK_NETERR, /* network error */ SOCK_AFNOTSUPERR, /* address family not supported */ SOCK_UNKNOWNERR, /* unknown error */ SOCK_NOERR /* no error */ } sock_errtype; static sock_errtype sock_geterrtype(int errcode) { switch (errcode) { #ifdef _WIN32 case WSAECONNRESET: case WSAECONNABORTED: case WSAECONNREFUSED: #else case ECONNRESET: case ECONNABORTED: case ECONNREFUSED: #endif /* * Connection error; this means the problem is probably * that there's no server set up on the remote machine, * or that it is set up, but it's IPv4-only or IPv6-only * and we're trying the wrong address family. * * These overwrite all other errors, as they indicate * that, even if somethng else went wrong in another * attempt, this probably wouldn't work even if the * other problems were fixed. */ return (SOCK_CONNERR); #ifdef _WIN32 case WSAENETUNREACH: case WSAETIMEDOUT: case WSAEHOSTDOWN: case WSAEHOSTUNREACH: #else case ENETUNREACH: case ETIMEDOUT: case EHOSTDOWN: case EHOSTUNREACH: #endif /* * Network errors that could be IPv4-specific, IPv6- * specific, or present with both. * * Don't overwrite connection errors, but overwrite * everything else. */ return (SOCK_HOSTERR); #ifdef _WIN32 case WSAENETDOWN: case WSAENETRESET: #else case ENETDOWN: case ENETRESET: #endif /* * Network error; this means we don't know whether * there's a server set up on the remote machine, * and we don't have a reason to believe that IPv6 * any worse or better than IPv4. * * These probably indicate a local failure, e.g. * an interface is down. * * Don't overwrite connection errors or host errors, * but overwrite everything else. */ return (SOCK_NETERR); #ifdef _WIN32 case WSAEAFNOSUPPORT: #else case EAFNOSUPPORT: #endif /* * "Address family not supported" probably means * "No soup^WIPv6 for you!". * * Don't overwrite connection errors, host errors, or * network errors (none of which we should get for this * address family if it's not supported), but overwrite * everything else. */ return (SOCK_AFNOTSUPERR); default: /* * Anything else. * * Don't overwrite any errors. */ return (SOCK_UNKNOWNERR); } } /* * \brief This function initializes the socket mechanism if it hasn't * already been initialized or reinitializes it after it has been * cleaned up. * * On UN*Xes, it doesn't need to do anything; on Windows, it needs to * initialize Winsock. * * \param errbuf: a pointer to an user-allocated buffer that will contain * the complete error message. This buffer has to be at least 'errbuflen' * in length. It can be NULL; in this case no error message is supplied. * * \param errbuflen: length of the buffer that will contains the error. * The error message cannot be larger than 'errbuflen - 1' because the * last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if some errors occurred. The * error message is returned in the buffer pointed to by 'errbuf' variable. */ #ifdef _WIN32 int sock_init(char *errbuf, int errbuflen) { if (sockcount == 0) { WSADATA wsaData; /* helper variable needed to initialize Winsock */ if (WSAStartup(MAKEWORD(WINSOCK_MAJOR_VERSION, WINSOCK_MINOR_VERSION), &wsaData) != 0) { if (errbuf) snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n"); WSACleanup(); return -1; } } sockcount++; return 0; } #else int sock_init(char *errbuf _U_, int errbuflen _U_) { /* * Nothing to do on UN*Xes. */ return 0; } #endif /* * \brief This function cleans up the socket mechanism if we have no * sockets left open. * * On UN*Xes, it doesn't need to do anything; on Windows, it needs * to clean up Winsock. * * \return No error values. */ void sock_cleanup(void) { #ifdef _WIN32 sockcount--; if (sockcount == 0) WSACleanup(); #endif } /* * \brief It checks if the sockaddr variable contains a multicast address. * * \return '0' if the address is multicast, '-1' if it is not. */ static int sock_ismcastaddr(const struct sockaddr *saddr) { if (saddr->sa_family == PF_INET) { struct sockaddr_in *saddr4 = (struct sockaddr_in *) saddr; if (IN_MULTICAST(ntohl(saddr4->sin_addr.s_addr))) return 0; else return -1; } else { struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr; if (IN6_IS_ADDR_MULTICAST(&saddr6->sin6_addr)) return 0; else return -1; } } struct addr_status { struct addrinfo *info; int errcode; sock_errtype errtype; }; /* * Sort by IPv4 address vs. IPv6 address. */ static int compare_addrs_to_try_by_address_family(const void *a, const void *b) { const struct addr_status *addr_a = (const struct addr_status *)a; const struct addr_status *addr_b = (const struct addr_status *)b; return addr_a->info->ai_family - addr_b->info->ai_family; } /* * Sort by error type and, within a given error type, by error code and, * within a given error code, by IPv4 address vs. IPv6 address. */ static int compare_addrs_to_try_by_status(const void *a, const void *b) { const struct addr_status *addr_a = (const struct addr_status *)a; const struct addr_status *addr_b = (const struct addr_status *)b; if (addr_a->errtype == addr_b->errtype) { if (addr_a->errcode == addr_b->errcode) { return addr_a->info->ai_family - addr_b->info->ai_family; } return addr_a->errcode - addr_b->errcode; } return addr_a->errtype - addr_b->errtype; } static SOCKET sock_create_socket(struct addrinfo *addrinfo, char *errbuf, int errbuflen) { SOCKET sock; #ifdef SO_NOSIGPIPE int on = 1; #endif sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (sock == INVALID_SOCKET) { sock_geterrmsg(errbuf, errbuflen, "socket() failed"); return INVALID_SOCKET; } /* * Disable SIGPIPE, if we have SO_NOSIGPIPE. We don't want to * have to deal with signals if the peer closes the connection, * especially in client programs, which may not even be aware that * they're sending to sockets. */ #ifdef SO_NOSIGPIPE if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, sizeof (int)) == -1) { sock_geterrmsg(errbuf, errbuflen, "setsockopt(SO_NOSIGPIPE) failed"); closesocket(sock); return INVALID_SOCKET; } #endif return sock; } /* * \brief It initializes a network connection both from the client and the server side. * * In case of a client socket, this function calls socket() and connect(). * In the meanwhile, it checks for any socket error. * If an error occurs, it writes the error message into 'errbuf'. * * In case of a server socket, the function calls socket(), bind() and listen(). * * This function is usually preceded by the sock_initaddress(). * * \param host: for client sockets, the host name to which we're trying * to connect. * * \param addrinfo: pointer to an addrinfo variable which will be used to * open the socket and such. This variable is the one returned by the previous call to * sock_initaddress(). * * \param server: '1' if this is a server socket, '0' otherwise. * * \param nconn: number of the connections that are allowed to wait into the listen() call. * This value has no meanings in case of a client socket. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return the socket that has been opened (that has to be used in the following sockets calls) * if everything is fine, INVALID_SOCKET if some errors occurred. The error message is returned * in the 'errbuf' variable. */ SOCKET sock_open(const char *host, struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen) { SOCKET sock; /* This is a server socket */ if (server) { int on; /* * Attempt to create the socket. */ sock = sock_create_socket(addrinfo, errbuf, errbuflen); if (sock == INVALID_SOCKET) { return INVALID_SOCKET; } /* * Allow a new server to bind the socket after the old one * exited, even if lingering sockets are still present. * * Don't treat an error as a failure. */ on = 1; (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)); #if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) /* * Force the use of IPv6-only addresses. * * RFC 3493 indicates that you can support IPv4 on an * IPv6 socket: * * https://tools.ietf.org/html/rfc3493#section-3.7 * * and that this is the default behavior. This means * that if we first create an IPv6 socket bound to the * "any" address, it is, in effect, also bound to the * IPv4 "any" address, so when we create an IPv4 socket * and try to bind it to the IPv4 "any" address, it gets * EADDRINUSE. * * Not all network stacks support IPv4 on IPv6 sockets; * pre-NT 6 Windows stacks don't support it, and the * OpenBSD stack doesn't support it for security reasons * (see the OpenBSD inet6(4) man page). Therefore, we * don't want to rely on this behavior. * * So we try to disable it, using either the IPV6_V6ONLY * option from RFC 3493: * * https://tools.ietf.org/html/rfc3493#section-5.3 * * or the IPV6_BINDV6ONLY option from older UN*Xes. */ #ifndef IPV6_V6ONLY /* For older systems */ #define IPV6_V6ONLY IPV6_BINDV6ONLY #endif /* IPV6_V6ONLY */ if (addrinfo->ai_family == PF_INET6) { on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof (int)) == -1) { if (errbuf) snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)"); closesocket(sock); return INVALID_SOCKET; } } #endif /* defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) */ /* WARNING: if the address is a mcast one, I should place the proper Win32 code here */ if (bind(sock, addrinfo->ai_addr, (int) addrinfo->ai_addrlen) != 0) { sock_geterrmsg(errbuf, errbuflen, "bind() failed"); closesocket(sock); return INVALID_SOCKET; } if (addrinfo->ai_socktype == SOCK_STREAM) if (listen(sock, nconn) == -1) { sock_geterrmsg(errbuf, errbuflen, "listen() failed"); closesocket(sock); return INVALID_SOCKET; } /* server side ended */ return sock; } else /* we're the client */ { struct addr_status *addrs_to_try; struct addrinfo *tempaddrinfo; size_t numaddrinfos; size_t i; int current_af = AF_UNSPEC; /* * We have to loop though all the addrinfos returned. * For instance, we can have both IPv6 and IPv4 addresses, * but the service we're trying to connect to is unavailable * in IPv6, so we have to try in IPv4 as well. * * How many addrinfos do we have? */ numaddrinfos = 0; for (tempaddrinfo = addrinfo; tempaddrinfo != NULL; tempaddrinfo = tempaddrinfo->ai_next) { numaddrinfos++; } if (numaddrinfos == 0) { snprintf(errbuf, errbuflen, "There are no addresses in the address list"); return INVALID_SOCKET; } /* * Allocate an array of struct addr_status and fill it in. */ addrs_to_try = calloc(numaddrinfos, sizeof *addrs_to_try); if (addrs_to_try == NULL) { snprintf(errbuf, errbuflen, "Out of memory connecting to %s", host); return INVALID_SOCKET; } for (tempaddrinfo = addrinfo, i = 0; tempaddrinfo != NULL; tempaddrinfo = tempaddrinfo->ai_next, i++) { addrs_to_try[i].info = tempaddrinfo; addrs_to_try[i].errcode = 0; addrs_to_try[i].errtype = SOCK_NOERR; } /* * Sort the structures to put the IPv4 addresses before the * IPv6 addresses; we will have to create an IPv4 socket * for the IPv4 addresses and an IPv6 socket for the IPv6 * addresses (one of the arguments to socket() is the * address/protocol family to use, and IPv4 and IPv6 are * separate address/protocol families). */ qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, compare_addrs_to_try_by_address_family); /* Start out with no socket. */ sock = INVALID_SOCKET; /* * Now try them all. */ for (i = 0; i < numaddrinfos; i++) { tempaddrinfo = addrs_to_try[i].info; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION break; #endif /* * If we have a socket, but it's for a * different address family, close it. */ if (sock != INVALID_SOCKET && current_af != tempaddrinfo->ai_family) { closesocket(sock); sock = INVALID_SOCKET; } /* * If we don't have a socket, open one * for *this* address's address family. */ if (sock == INVALID_SOCKET) { sock = sock_create_socket(tempaddrinfo, errbuf, errbuflen); if (sock == INVALID_SOCKET) { free(addrs_to_try); return INVALID_SOCKET; } } if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1) { addrs_to_try[i].errcode = sock_geterrcode(); addrs_to_try[i].errtype = sock_geterrtype(addrs_to_try[i].errcode); } else break; } /* * Check how we exited from the previous loop. * If tempaddrinfo is equal to NULL, it means that all * the connect() attempts failed. Construct an * error message. */ if (i == numaddrinfos) { int same_error_for_all; int first_error; closesocket(sock); /* * Sort the statuses to group together categories * of errors, errors within categories, and * address families within error sets. */ qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, compare_addrs_to_try_by_status); /* * Are all the errors the same? */ same_error_for_all = 1; first_error = addrs_to_try[0].errcode; for (i = 1; i < numaddrinfos; i++) { if (addrs_to_try[i].errcode != first_error) { same_error_for_all = 0; break; } } if (same_error_for_all) { /* * Yes. No need to show the IP * addresses. */ if (addrs_to_try[0].errtype == SOCK_CONNERR) { /* * Connection error; note that * the daemon might not be set * up correctly, or set up at all. */ sock_fmterrmsg(errbuf, errbuflen, addrs_to_try[0].errcode, "Is the server properly installed? Cannot connect to %s", host); } else { sock_fmterrmsg(errbuf, errbuflen, addrs_to_try[0].errcode, "Cannot connect to %s", host); } } else { /* * Show all the errors and the IP addresses * to which they apply. */ char *errbufptr; size_t bufspaceleft; size_t msglen; snprintf(errbuf, errbuflen, "Connect to %s failed: ", host); msglen = strlen(errbuf); errbufptr = errbuf + msglen; bufspaceleft = errbuflen - msglen; for (i = 0; i < numaddrinfos && addrs_to_try[i].errcode != SOCK_NOERR; i++) { /* * Get the string for the address * and port that got this error. */ sock_getascii_addrport((struct sockaddr_storage *) addrs_to_try[i].info->ai_addr, errbufptr, (int)bufspaceleft, NULL, 0, NI_NUMERICHOST, NULL, 0); msglen = strlen(errbuf); errbufptr = errbuf + msglen; bufspaceleft = errbuflen - msglen; if (i + 1 < numaddrinfos && addrs_to_try[i + 1].errcode == addrs_to_try[i].errcode) { /* * There's another error * after this, and it has * the same error code. * * Append a comma, as the * list of addresses with * this error has another * entry. */ snprintf(errbufptr, bufspaceleft, ", "); } else { /* * Either there are no * more errors after this, * or the next error is * different. * * Append a colon and * the message for tis * error, followed by a * comma if there are * more errors. */ sock_fmterrmsg(errbufptr, bufspaceleft, addrs_to_try[i].errcode, "%s", ""); msglen = strlen(errbuf); errbufptr = errbuf + msglen; bufspaceleft = errbuflen - msglen; if (i + 1 < numaddrinfos && addrs_to_try[i + 1].errcode != SOCK_NOERR) { /* * More to come. */ snprintf(errbufptr, bufspaceleft, ", "); } } msglen = strlen(errbuf); errbufptr = errbuf + msglen; bufspaceleft = errbuflen - msglen; } } free(addrs_to_try); return INVALID_SOCKET; } else { free(addrs_to_try); return sock; } } } /* * \brief Closes the present (TCP and UDP) socket connection. * * This function sends a shutdown() on the socket in order to disable send() calls * (while recv() ones are still allowed). Then, it closes the socket. * * \param sock: the socket identifier of the connection that has to be closed. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned * in the 'errbuf' variable. */ int sock_close(SOCKET sock, char *errbuf, int errbuflen) { /* * SHUT_WR: subsequent calls to the send function are disallowed. * For TCP sockets, a FIN will be sent after all data is sent and * acknowledged by the Server. */ if (shutdown(sock, SHUT_WR)) { sock_geterrmsg(errbuf, errbuflen, "shutdown() feiled"); /* close the socket anyway */ closesocket(sock); return -1; } closesocket(sock); return 0; } /* * gai_strerror() has some problems: * * 1) on Windows, Microsoft explicitly says it's not thread-safe; * 2) on UN*X, the Single UNIX Specification doesn't say it *is* * thread-safe, so an implementation might use a static buffer * for unknown error codes; * 3) the error message for the most likely error, EAI_NONAME, is * truly horrible on several platforms ("nodename nor servname * provided, or not known"? It's typically going to be "not * known", not "oopsie, I passed null pointers for the host name * and service name", not to mention they forgot the "neither"); * * so we roll our own. */ static void get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, const char *hostname, const char *portname) { char hostport[PCAP_ERRBUF_SIZE]; if (hostname != NULL && portname != NULL) snprintf(hostport, PCAP_ERRBUF_SIZE, "host and port %s:%s", hostname, portname); else if (hostname != NULL) snprintf(hostport, PCAP_ERRBUF_SIZE, "host %s", hostname); else if (portname != NULL) snprintf(hostport, PCAP_ERRBUF_SIZE, "port %s", portname); else snprintf(hostport, PCAP_ERRBUF_SIZE, ""); switch (err) { #ifdef EAI_ADDRFAMILY case EAI_ADDRFAMILY: snprintf(errbuf, errbuflen, "%sAddress family for %s not supported", prefix, hostport); break; #endif case EAI_AGAIN: snprintf(errbuf, errbuflen, "%s%s could not be resolved at this time", prefix, hostport); break; case EAI_BADFLAGS: snprintf(errbuf, errbuflen, "%sThe ai_flags parameter for looking up %s had an invalid value", prefix, hostport); break; case EAI_FAIL: snprintf(errbuf, errbuflen, "%sA non-recoverable error occurred when attempting to resolve %s", prefix, hostport); break; case EAI_FAMILY: snprintf(errbuf, errbuflen, "%sThe address family for looking up %s was not recognized", prefix, hostport); break; case EAI_MEMORY: snprintf(errbuf, errbuflen, "%sOut of memory trying to allocate storage when looking up %s", prefix, hostport); break; /* * RFC 2553 had both EAI_NODATA and EAI_NONAME. * * RFC 3493 has only EAI_NONAME. * * Some implementations define EAI_NODATA and EAI_NONAME * to the same value, others don't. If EAI_NODATA is * defined and isn't the same as EAI_NONAME, we handle * EAI_NODATA. */ #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME case EAI_NODATA: snprintf(errbuf, errbuflen, "%sNo address associated with %s", prefix, hostport); break; #endif case EAI_NONAME: snprintf(errbuf, errbuflen, "%sThe %s couldn't be resolved", prefix, hostport); break; case EAI_SERVICE: snprintf(errbuf, errbuflen, "%sThe service value specified when looking up %s as not recognized for the socket type", prefix, hostport); break; case EAI_SOCKTYPE: snprintf(errbuf, errbuflen, "%sThe socket type specified when looking up %s as not recognized", prefix, hostport); break; #ifdef EAI_SYSTEM case EAI_SYSTEM: /* * Assumed to be UN*X. */ pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errno, "%sAn error occurred when looking up %s", prefix, hostport); break; #endif #ifdef EAI_BADHINTS case EAI_BADHINTS: snprintf(errbuf, errbuflen, "%sInvalid value for hints when looking up %s", prefix, hostport); break; #endif #ifdef EAI_PROTOCOL case EAI_PROTOCOL: snprintf(errbuf, errbuflen, "%sResolved protocol when looking up %s is unknown", prefix, hostport); break; #endif #ifdef EAI_OVERFLOW case EAI_OVERFLOW: snprintf(errbuf, errbuflen, "%sArgument buffer overflow when looking up %s", prefix, hostport); break; #endif default: snprintf(errbuf, errbuflen, "%sgetaddrinfo() error %d when looking up %s", prefix, err, hostport); break; } } /* * \brief Checks that the address, port and flags given are valids and it returns an 'addrinfo' structure. * * This function basically calls the getaddrinfo() calls, and it performs a set of sanity checks * to control that everything is fine (e.g. a TCP socket cannot have a mcast address, and such). * If an error occurs, it writes the error message into 'errbuf'. * * \param host: a pointer to a string identifying the host. It can be * a host name, a numeric literal address, or NULL or "" (useful * in case of a server socket which has to bind to all addresses). * * \param port: a pointer to a user-allocated buffer containing the network port to use. * * \param hints: an addrinfo variable (passed by reference) containing the flags needed to create the * addrinfo structure appropriately. * * \param addrinfo: it represents the true returning value. This is a pointer to an addrinfo variable * (passed by reference), which will be allocated by this function and returned back to the caller. * This variable will be used in the next sockets calls. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned * in the 'errbuf' variable. The addrinfo variable that has to be used in the following sockets calls is * returned into the addrinfo parameter. * * \warning The 'addrinfo' variable has to be deleted by the programmer by calling freeaddrinfo() when * it is no longer needed. * * \warning This function requires the 'hints' variable as parameter. The semantic of this variable is the same * of the one of the corresponding variable used into the standard getaddrinfo() socket function. We suggest * the programmer to look at that function in order to set the 'hints' variable appropriately. */ int sock_initaddress(const char *host, const char *port, struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen) { int retval; /* * We allow both the host and port to be null, but getaddrinfo() * is not guaranteed to do so; to handle that, if port is null, * we provide "0" as the port number. * * This results in better error messages from get_gai_errstring(), * as those messages won't talk about a problem with the port if * no port was specified. */ retval = getaddrinfo(host, port == NULL ? "0" : port, hints, addrinfo); if (retval != 0) { if (errbuf) { if (host != NULL && port != NULL) { /* * Try with just a host, to distinguish * between "host is bad" and "port is * bad". */ int try_retval; try_retval = getaddrinfo(host, NULL, hints, addrinfo); if (try_retval == 0) { /* * Worked with just the host, * so assume the problem is * with the port. * * Free up the address info first. */ freeaddrinfo(*addrinfo); get_gai_errstring(errbuf, errbuflen, "", retval, NULL, port); } else { /* * Didn't work with just the host, * so assume the problem is * with the host. */ get_gai_errstring(errbuf, errbuflen, "", retval, host, NULL); } } else { /* * Either the host or port was null, so * there's nothing to determine. */ get_gai_errstring(errbuf, errbuflen, "", retval, host, port); } } return -1; } /* * \warning SOCKET: I should check all the accept() in order to bind to all addresses in case * addrinfo has more han one pointers */ /* * This software only supports PF_INET and PF_INET6. * * XXX - should we just check that at least *one* address is * either PF_INET or PF_INET6, and, when using the list, * ignore all addresses that are neither? (What, no IPX * support? :-)) */ if (((*addrinfo)->ai_family != PF_INET) && ((*addrinfo)->ai_family != PF_INET6)) { if (errbuf) snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported"); freeaddrinfo(*addrinfo); *addrinfo = NULL; return -1; } /* * You can't do multicast (or broadcast) TCP. */ if (((*addrinfo)->ai_socktype == SOCK_STREAM) && (sock_ismcastaddr((*addrinfo)->ai_addr) == 0)) { if (errbuf) snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); freeaddrinfo(*addrinfo); *addrinfo = NULL; return -1; } return 0; } /* * \brief It sends the amount of data contained into 'buffer' on the given socket. * * This function basically calls the send() socket function and it checks that all * the data specified in 'buffer' (of size 'size') will be sent. If an error occurs, * it writes the error message into 'errbuf'. * In case the socket buffer does not have enough space, it loops until all data * has been sent. * * \param socket: the connected socket currently opened. * * \param buffer: a char pointer to a user-allocated buffer in which data is contained. * * \param size: number of bytes that have to be sent. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if an error other than * "connection reset" or "peer has closed the receive side" occurred, * '-2' if we got one of those errors. * For errors, an error message is returned in the 'errbuf' variable. */ int sock_send(SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, size_t size, char *errbuf, int errbuflen) { int remaining; ssize_t nsent; if (size > INT_MAX) { if (errbuf) { snprintf(errbuf, errbuflen, "Can't send more than %u bytes with sock_send", INT_MAX); } return -1; } remaining = (int)size; do { #ifdef HAVE_OPENSSL if (ssl) return ssl_send(ssl, buffer, remaining, errbuf, errbuflen); #endif #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION nsent = remaining; #else #ifdef MSG_NOSIGNAL /* * Send with MSG_NOSIGNAL, so that we don't get SIGPIPE * on errors on stream-oriented sockets when the other * end breaks the connection. * The EPIPE error is still returned. */ nsent = send(sock, buffer, remaining, MSG_NOSIGNAL); #else nsent = send(sock, buffer, remaining, 0); #endif #endif //FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (nsent == -1) { /* * If the client closed the connection out from * under us, there's no need to log that as an * error. */ int errcode; #ifdef _WIN32 errcode = GetLastError(); if (errcode == WSAECONNRESET || errcode == WSAECONNABORTED) { /* * WSAECONNABORTED appears to be the error * returned in Winsock when you try to send * on a connection where the peer has closed * the receive side. */ return -2; } sock_fmterrmsg(errbuf, errbuflen, errcode, "send() failed"); #else errcode = errno; if (errcode == ECONNRESET || errcode == EPIPE) { /* * EPIPE is what's returned on UN*X when * you try to send on a connection when * the peer has closed the receive side. */ return -2; } sock_fmterrmsg(errbuf, errbuflen, errcode, "send() failed"); #endif return -1; } remaining -= nsent; buffer += nsent; } while (remaining != 0); return 0; } /* * \brief It copies the amount of data contained in 'data' into 'outbuf'. * and it checks for buffer overflows. * * This function basically copies 'size' bytes of data contained in 'data' * into 'outbuf', starting at offset 'offset'. Before that, it checks that the * resulting buffer will not be larger than 'totsize'. Finally, it updates * the 'offset' variable in order to point to the first empty location of the buffer. * * In case the function is called with 'checkonly' equal to 1, it does not copy * the data into the buffer. It only checks for buffer overflows and it updates the * 'offset' variable. This mode can be useful when the buffer already contains the * data (maybe because the producer writes directly into the target buffer), so * only the buffer overflow check has to be made. * In this case, both 'data' and 'outbuf' can be NULL values. * * This function is useful in case the userland application does not know immediately * all the data it has to write into the socket. This function provides a way to create * the "stream" step by step, appending the new data to the old one. Then, when all the * data has been bufferized, the application can call the sock_send() function. * * \param data: a void pointer to the data that has to be copied. * * \param size: number of bytes that have to be copied. * * \param outbuf: user-allocated buffer (of size 'totsize') into which data * has to be copied. * * \param offset: an index into 'outbuf' which keeps the location of its first * empty location. * * \param totsize: total size of the buffer into which data is being copied. * * \param checkonly: '1' if we do not want to copy data into the buffer and we * want just do a buffer ovreflow control, '0' if data has to be copied as well. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if some errors occurred. The error message * is returned in the 'errbuf' variable. When the function returns, 'outbuf' will * have the new string appended, and 'offset' will keep the length of that buffer. * In case of 'checkonly == 1', data is not copied, but 'offset' is updated in any case. * * \warning This function assumes that the buffer in which data has to be stored is * large 'totbuf' bytes. * * \warning In case of 'checkonly', be carefully to call this function *before* copying * the data into the buffer. Otherwise, the control about the buffer overflow is useless. */ int sock_bufferize(const void *data, int size, char *outbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen) { if ((*offset + size) > totsize) { if (errbuf) snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer."); return -1; } if (!checkonly) memcpy(outbuf + (*offset), data, size); (*offset) += size; return 0; } /* * \brief It waits on a connected socket and it manages to receive data. * * This function basically calls the recv() socket function and it checks that no * error occurred. If that happens, it writes the error message into 'errbuf'. * * This function changes its behavior according to the 'receiveall' flag: if we * want to receive exactly 'size' byte, it loops on the recv() until all the requested * data is arrived. Otherwise, it returns the data currently available. * * In case the socket does not have enough data available, it cycles on the recv() * until the requested data (of size 'size') is arrived. * In this case, it blocks until the number of bytes read is equal to 'size'. * * \param sock: the connected socket currently opened. * * \param buffer: a char pointer to a user-allocated buffer in which data has to be stored * * \param size: size of the allocated buffer. WARNING: this indicates the number of bytes * that we are expecting to be read. * * \param flags: * * SOCK_RECEIVALL_XXX: * - * if SOCK_RECEIVEALL_NO, return as soon as some data is ready + * if SOCK_RECEIVEALL_NO, return as soon as some data is ready * if SOCK_RECEIVALL_YES, wait until 'size' data has been * received (in case the socket does not have enough data available). * * SOCK_EOF_XXX: * * if SOCK_EOF_ISNT_ERROR, if the first read returns 0, just return 0, * and return an error on any subsequent read that returns 0; * if SOCK_EOF_IS_ERROR, if any read returns 0, return an error. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return the number of bytes read if everything is fine, '-1' if some errors occurred. * The error message is returned in the 'errbuf' variable. */ int sock_recv(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size, int flags, char *errbuf, int errbuflen) { int recv_flags = 0; char *bufp = buffer; int remaining; ssize_t nread; if (size == 0) { return 0; } if (size > INT_MAX) { if (errbuf) { snprintf(errbuf, errbuflen, "Can't read more than %u bytes with sock_recv", INT_MAX); } return -1; } if (flags & SOCK_MSG_PEEK) recv_flags |= MSG_PEEK; bufp = (char *) buffer; remaining = (int) size; /* * We don't use MSG_WAITALL because it's not supported in * Win32. */ for (;;) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION nread = fuzz_recv(bufp, remaining); #elif defined(HAVE_OPENSSL) if (ssl) { /* * XXX - what about MSG_PEEK? */ nread = ssl_recv(ssl, bufp, remaining, errbuf, errbuflen); if (nread == -2) return -1; } else nread = recv(sock, bufp, remaining, recv_flags); #else nread = recv(sock, bufp, remaining, recv_flags); #endif if (nread == -1) { #ifndef _WIN32 if (errno == EINTR) return -3; #endif sock_geterrmsg(errbuf, errbuflen, "recv() failed"); return -1; } if (nread == 0) { if ((flags & SOCK_EOF_IS_ERROR) || (remaining != (int) size)) { /* * Either we've already read some data, * or we're always supposed to return * an error on EOF. */ if (errbuf) { snprintf(errbuf, errbuflen, "The other host terminated the connection."); } return -1; } else return 0; } /* * Do we want to read the amount requested, or just return * what we got? */ if (!(flags & SOCK_RECEIVEALL_YES)) { /* * Just return what we got. */ return (int) nread; } bufp += nread; remaining -= nread; if (remaining == 0) return (int) size; } } /* * Receives a datagram from a socket. * * Returns the size of the datagram on success or -1 on error. */ int sock_recv_dgram(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size, char *errbuf, int errbuflen) { ssize_t nread; #ifndef _WIN32 struct msghdr message; struct iovec iov; #endif if (size == 0) { return 0; } if (size > INT_MAX) { if (errbuf) { snprintf(errbuf, errbuflen, "Can't read more than %u bytes with sock_recv_dgram", INT_MAX); } return -1; } #ifdef HAVE_OPENSSL // TODO: DTLS if (ssl) { snprintf(errbuf, errbuflen, "DTLS not implemented yet"); return -1; } #endif /* * This should be a datagram socket, so we should get the * entire datagram in one recv() or recvmsg() call, and * don't need to loop. */ #ifdef _WIN32 nread = recv(sock, buffer, (int)size, 0); if (nread == SOCKET_ERROR) { /* * To quote the MSDN documentation for recv(), * "If the datagram or message is larger than * the buffer specified, the buffer is filled * with the first part of the datagram, and recv * generates the error WSAEMSGSIZE. For unreliable * protocols (for example, UDP) the excess data is * lost..." * * So if the message is bigger than the buffer * supplied to us, the excess data is discarded, * and we'll report an error. */ sock_fmterrmsg(errbuf, errbuflen, sock_geterrcode(), "recv() failed"); return -1; } #else /* _WIN32 */ /* * The Single UNIX Specification says that a recv() on * a socket for a message-oriented protocol will discard * the excess data. It does *not* indicate that the * receive will fail with, for example, EMSGSIZE. * * Therefore, we use recvmsg(), which appears to be * the only way to get a "message truncated" indication * when receiving a message for a message-oriented * protocol. */ message.msg_name = NULL; /* we don't care who it's from */ message.msg_namelen = 0; iov.iov_base = buffer; iov.iov_len = size; message.msg_iov = &iov; message.msg_iovlen = 1; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL message.msg_control = NULL; /* we don't care about control information */ message.msg_controllen = 0; #endif #ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS message.msg_flags = 0; #endif #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION nread = fuzz_recv(buffer, size); #else nread = recvmsg(sock, &message, 0); #endif if (nread == -1) { if (errno == EINTR) return -3; sock_geterrmsg(errbuf, errbuflen, "recv() failed"); return -1; } #ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS /* * XXX - Solaris supports this, but only if you ask for the * X/Open version of recvmsg(); should we use that, or will * that cause other problems? */ if (message.msg_flags & MSG_TRUNC) { /* * Message was bigger than the specified buffer size. * * Report this as an error, as the Microsoft documentation * implies we'd do in a similar case on Windows. */ snprintf(errbuf, errbuflen, "recv(): Message too long"); return -1; } #endif /* HAVE_STRUCT_MSGHDR_MSG_FLAGS */ #endif /* _WIN32 */ /* * The size we're reading fits in an int, so the return value * will fit in an int. */ return (int)nread; } /* * \brief It discards N bytes that are currently waiting to be read on the current socket. * * This function is useful in case we receive a message we cannot understand (e.g. * wrong version number when receiving a network packet), so that we have to discard all * data before reading a new message. * * This function will read 'size' bytes from the socket and discard them. * It defines an internal buffer in which data will be copied; however, in case * this buffer is not large enough, it will cycle in order to read everything as well. * * \param sock: the connected socket currently opened. * * \param size: number of bytes that have to be discarded. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '0' if everything is fine, '-1' if some errors occurred. * The error message is returned in the 'errbuf' variable. */ int sock_discard(SOCKET sock, SSL *ssl, int size, char *errbuf, int errbuflen) { #define TEMP_BUF_SIZE 32768 char buffer[TEMP_BUF_SIZE]; /* network buffer, to be used when the message is discarded */ /* * A static allocation avoids the need of a 'malloc()' each time we want to discard a message * Our feeling is that a buffer if 32KB is enough for most of the application; * in case this is not enough, the "while" loop discards the message by calling the * sockrecv() several times. * We do not want to create a bigger variable because this causes the program to exit on * some platforms (e.g. BSD) */ while (size > TEMP_BUF_SIZE) { if (sock_recv(sock, ssl, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1) return -1; size -= TEMP_BUF_SIZE; } /* * If there is still data to be discarded * In this case, the data can fit into the temporary buffer */ if (size) { if (sock_recv(sock, ssl, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1) return -1; } return 0; } /* * \brief Checks that one host (identified by the sockaddr_storage structure) belongs to an 'allowed list'. * * This function is useful after an accept() call in order to check if the connecting * host is allowed to connect to me. To do that, we have a buffer that keeps the list of the * allowed host; this function checks the sockaddr_storage structure of the connecting host * against this host list, and it returns '0' is the host is included in this list. * * \param hostlist: pointer to a string that contains the list of the allowed host. * * \param sep: a string that keeps the separators used between the hosts (for example the * space character) in the host list. * * \param from: a sockaddr_storage structure, as it is returned by the accept() call. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return It returns: * - '1' if the host list is empty * - '0' if the host belongs to the host list (and therefore it is allowed to connect) * - '-1' in case the host does not belong to the host list (and therefore it is not allowed to connect * - '-2' in case or error. The error message is returned in the 'errbuf' variable. */ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen) { /* checks if the connecting host is among the ones allowed */ if ((hostlist) && (hostlist[0])) { char *token; /* temp, needed to separate items into the hostlist */ struct addrinfo *addrinfo, *ai_next; char *temphostlist; char *lasts; int getaddrinfo_failed = 0; /* * The problem is that strtok modifies the original variable by putting '0' at the end of each token * So, we have to create a new temporary string in which the original content is kept */ temphostlist = strdup(hostlist); if (temphostlist == NULL) { sock_geterrmsg(errbuf, errbuflen, "sock_check_hostlist(), malloc() failed"); return -2; } token = pcap_strtok_r(temphostlist, sep, &lasts); /* it avoids a warning in the compilation ('addrinfo used but not initialized') */ addrinfo = NULL; while (token != NULL) { struct addrinfo hints; int retval; addrinfo = NULL; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; retval = getaddrinfo(token, NULL, &hints, &addrinfo); if (retval != 0) { if (errbuf) get_gai_errstring(errbuf, errbuflen, "Allowed host list error: ", retval, token, NULL); /* * Note that at least one call to getaddrinfo() * failed. */ getaddrinfo_failed = 1; /* Get next token */ token = pcap_strtok_r(NULL, sep, &lasts); continue; } /* ai_next is required to preserve the content of addrinfo, in order to deallocate it properly */ ai_next = addrinfo; while (ai_next) { if (sock_cmpaddr(from, (struct sockaddr_storage *) ai_next->ai_addr) == 0) { free(temphostlist); freeaddrinfo(addrinfo); return 0; } /* * If we are here, it means that the current address does not matches * Let's try with the next one in the header chain */ ai_next = ai_next->ai_next; } freeaddrinfo(addrinfo); addrinfo = NULL; /* Get next token */ token = pcap_strtok_r(NULL, sep, &lasts); } if (addrinfo) { freeaddrinfo(addrinfo); addrinfo = NULL; } free(temphostlist); if (getaddrinfo_failed) { /* * At least one getaddrinfo() call failed; * treat that as an error, so rpcapd knows * that it should log it locally as well * as telling the client about it. */ return -2; } else { /* * All getaddrinfo() calls succeeded, but * the host wasn't in the list. */ if (errbuf) snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused."); return -1; } } /* No hostlist, so we have to return 'empty list' */ return 1; } /* * \brief Compares two addresses contained into two sockaddr_storage structures. * * This function is useful to compare two addresses, given their internal representation, * i.e. an sockaddr_storage structure. * * The two structures do not need to be sockaddr_storage; you can have both 'sockaddr_in' and * sockaddr_in6, properly acsted in order to be compliant to the function interface. * * This function will return '0' if the two addresses matches, '-1' if not. * * \param first: a sockaddr_storage structure, (for example the one that is returned by an * accept() call), containing the first address to compare. * * \param second: a sockaddr_storage structure containing the second address to compare. * * \return '0' if the addresses are equal, '-1' if they are different. */ int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second) { if (first->ss_family == second->ss_family) { if (first->ss_family == AF_INET) { if (memcmp(&(((struct sockaddr_in *) first)->sin_addr), &(((struct sockaddr_in *) second)->sin_addr), sizeof(struct in_addr)) == 0) return 0; } else /* address family is AF_INET6 */ { if (memcmp(&(((struct sockaddr_in6 *) first)->sin6_addr), &(((struct sockaddr_in6 *) second)->sin6_addr), sizeof(struct in6_addr)) == 0) return 0; } } return -1; } /* * \brief It gets the address/port the system picked for this socket (on connected sockets). * * It is used to return the address and port the server picked for our socket on the local machine. * It works only on: * - connected sockets * - server sockets * * On unconnected client sockets it does not work because the system dynamically chooses a port * only when the socket calls a send() call. * * \param sock: the connected socket currently opened. * * \param address: it contains the address that will be returned by the function. This buffer * must be properly allocated by the user. The address can be either literal or numeric depending * on the value of 'Flags'. * * \param addrlen: the length of the 'address' buffer. * * \param port: it contains the port that will be returned by the function. This buffer * must be properly allocated by the user. * * \param portlen: the length of the 'port' buffer. * * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function) * that determine if the resulting address must be in numeric / literal form, and so on. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return It returns '-1' if this function succeeds, '0' otherwise. * The address and port corresponding are returned back in the buffers 'address' and 'port'. * In any case, the returned strings are '0' terminated. * * \warning If the socket is using a connectionless protocol, the address may not be available * until I/O occurs on the socket. */ int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) { struct sockaddr_storage mysockaddr; socklen_t sockaddrlen; sockaddrlen = sizeof(struct sockaddr_storage); if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1) { sock_geterrmsg(errbuf, errbuflen, "getsockname() failed"); return 0; } /* Returns the numeric address of the host that triggered the error */ return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen); } /* * \brief It retrieves two strings containing the address and the port of a given 'sockaddr' variable. * * This function is basically an extended version of the inet_ntop(), which does not exist in * Winsock because the same result can be obtained by using the getnameinfo(). * However, differently from inet_ntop(), this function is able to return also literal names * (e.g. 'localhost') dependently from the 'Flags' parameter. * * The function accepts a sockaddr_storage variable (which can be returned by several functions * like bind(), connect(), accept(), and more) and it transforms its content into a 'human' * form. So, for instance, it is able to translate an hex address (stored in binary form) into * a standard IPv6 address like "::1". * * The behavior of this function depends on the parameters we have in the 'Flags' variable, which * are the ones allowed in the standard getnameinfo() socket function. * * \param sockaddr: a 'sockaddr_in' or 'sockaddr_in6' structure containing the address that * need to be translated from network form into the presentation form. This structure must be * zero-ed prior using it, and the address family field must be filled with the proper value. * The user must cast any 'sockaddr_in' or 'sockaddr_in6' structures to 'sockaddr_storage' before * calling this function. * * \param address: it contains the address that will be returned by the function. This buffer * must be properly allocated by the user. The address can be either literal or numeric depending * on the value of 'Flags'. * * \param addrlen: the length of the 'address' buffer. * * \param port: it contains the port that will be returned by the function. This buffer * must be properly allocated by the user. * * \param portlen: the length of the 'port' buffer. * * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function) * that determine if the resulting address must be in numeric / literal form, and so on. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return It returns '-1' if this function succeeds, '0' otherwise. * The address and port corresponding to the given SockAddr are returned back in the buffers 'address' * and 'port'. * In any case, the returned strings are '0' terminated. */ int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, size_t errbuflen) { socklen_t sockaddrlen; int retval; /* Variable that keeps the return value; */ retval = -1; #ifdef _WIN32 if (sockaddr->ss_family == AF_INET) sockaddrlen = sizeof(struct sockaddr_in); else sockaddrlen = sizeof(struct sockaddr_in6); #else sockaddrlen = sizeof(struct sockaddr_storage); #endif if ((flags & NI_NUMERICHOST) == 0) /* Check that we want literal names */ { if ((sockaddr->ss_family == AF_INET6) && (memcmp(&((struct sockaddr_in6 *) sockaddr)->sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(struct in6_addr)) == 0)) { if (address) pcap_strlcpy(address, SOCKET_NAME_NULL_DAD, addrlen); return retval; } } if (getnameinfo((struct sockaddr *) sockaddr, sockaddrlen, address, addrlen, port, portlen, flags) != 0) { /* If the user wants to receive an error message */ if (errbuf) { sock_geterrmsg(errbuf, errbuflen, "getnameinfo() failed"); errbuf[errbuflen - 1] = 0; } if (address) { pcap_strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen); address[addrlen - 1] = 0; } if (port) { pcap_strlcpy(port, SOCKET_NO_PORT_AVAILABLE, portlen); port[portlen - 1] = 0; } retval = 0; } return retval; } /* * \brief It translates an address from the 'presentation' form into the 'network' form. * * This function basically replaces inet_pton(), which does not exist in Winsock because * the same result can be obtained by using the getaddrinfo(). * An additional advantage is that 'Address' can be both a numeric address (e.g. '127.0.0.1', * like in inet_pton() ) and a literal name (e.g. 'localhost'). * * This function does the reverse job of sock_getascii_addrport(). * * \param address: a zero-terminated string which contains the name you have to * translate. The name can be either literal (e.g. 'localhost') or numeric (e.g. '::1'). * * \param sockaddr: a user-allocated sockaddr_storage structure which will contains the * 'network' form of the requested address. * * \param addr_family: a constant which can assume the following values: * - 'AF_INET' if we want to ping an IPv4 host * - 'AF_INET6' if we want to ping an IPv6 host * - 'AF_UNSPEC' if we do not have preferences about the protocol used to ping the host * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. * It can be NULL; in this case the error cannot be printed. * * \param errbuflen: length of the buffer that will contains the error. The error message cannot be * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. * * \return '-1' if the translation succeeded, '-2' if there was some non critical error, '0' * otherwise. In case it fails, the content of the SockAddr variable remains unchanged. * A 'non critical error' can occur in case the 'Address' is a literal name, which can be mapped * to several network addresses (e.g. 'foo.bar.com' => '10.2.2.2' and '10.2.2.3'). In this case * the content of the SockAddr parameter will be the address corresponding to the first mapping. * * \warning The sockaddr_storage structure MUST be allocated by the user. */ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen) { int retval; struct addrinfo *addrinfo; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = addr_family; if ((retval = sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen)) == -1) return 0; if (addrinfo->ai_family == PF_INET) memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in)); else memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in6)); if (addrinfo->ai_next != NULL) { freeaddrinfo(addrinfo); if (errbuf) snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned"); return -2; } freeaddrinfo(addrinfo); return -1; } diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in index f195693713f9..d3fd328ce9a8 100644 --- a/testprogs/Makefile.in +++ b/testprogs/Makefile.in @@ -1,172 +1,172 @@ # Copyright (c) 1993, 1994, 1995, 1996 -# The Regents of the University of California. All rights reserved. +# The Regents of the University of California. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that: (1) source code distributions # retain the above copyright notice and this paragraph in its entirety, (2) # distributions including binary code include the above copyright notice and # this paragraph in its entirety in the documentation or other materials # provided with the distribution, and (3) all advertising materials mentioning # features or use of this software display the following acknowledgement: # ``This product includes software developed by the University of California, # Lawrence Berkeley Laboratory and its contributors.'' Neither the name of # the University nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior # written permission. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # Various configurable paths (remember to edit Makefile.in, not Makefile) # # Top level hierarchy prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ # Pathname of directory to install the configure program bindir = @bindir@ # Pathname of directory to install the rpcapd daemon sbindir = @sbindir@ # Pathname of directory to install the include files includedir = @includedir@ # Pathname of directory to install the library libdir = @libdir@ # Pathname of directory to install the man pages mandir = @mandir@ # VPATH srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ # # You shouldn't need to edit anything below. # LD = /usr/bin/ld CC = @CC@ AR = @AR@ LN_S = @LN_S@ MKDEP = @MKDEP@ CCOPT = @V_CCOPT@ INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ DEFS = @DEFS@ @V_DEFS@ ADDLOBJS = @ADDLOBJS@ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ LIBS = @LIBS@ PTHREAD_LIBS = @PTHREAD_LIBS@ CROSSFLAGS= CFLAGS = @CFLAGS@ ${CROSSFLAGS} LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} DYEXT = @DYEXT@ V_RPATH_OPT = @V_RPATH_OPT@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ # Standard CFLAGS for building test programs FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ # Explicitly define compilation rule since SunOS 4's make doesn't like gcc. # Also, gcc does not remove the .o before forking 'as', which can be a # problem if you don't own the file but can write to the directory. .c.o: @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c SRC = @VALGRINDTEST_SRC@ \ can_set_rfmon_test.c \ capturetest.c \ filtertest.c \ findalldevstest-perf.c \ findalldevstest.c \ opentest.c \ nonblocktest.c \ reactivatetest.c \ selpolltest.c \ threadsignaltest.c \ writecaptest.c TESTS = $(SRC:.c=) TAGFILES = \ $(SRC) $(HDR) CLEANFILES = $(OBJ) $(TESTS) all: $(TESTS) capturetest: $(srcdir)/capturetest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/capturetest.c \ ../libpcap.a $(LIBS) can_set_rfmon_test: $(srcdir)/can_set_rfmon_test.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o can_set_rfmon_test \ $(srcdir)/can_set_rfmon_test.c \ ../libpcap.a $(LIBS) filtertest: $(srcdir)/filtertest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/filtertest.c \ ../libpcap.a $(LIBS) findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest \ $(srcdir)/findalldevstest.c \ ../libpcap.a $(LIBS) findalldevstest-perf: $(srcdir)/findalldevstest-perf.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest-perf \ $(srcdir)/findalldevstest-perf.c \ ../libpcap.a $(LIBS) opentest: $(srcdir)/opentest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c \ ../libpcap.a $(LIBS) nonblocktest: $(srcdir)/nonblocktest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o nonblocktest $(srcdir)/nonblocktest.c \ ../libpcap.a $(LIBS) reactivatetest: $(srcdir)/reactivatetest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o reactivatetest \ $(srcdir)/reactivatetest.c ../libpcap.a $(LIBS) selpolltest: $(srcdir)/selpolltest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/selpolltest.c \ ../libpcap.a $(LIBS) threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o threadsignaltest \ $(srcdir)/threadsignaltest.c \ ../libpcap.a $(LIBS) $(PTHREAD_LIBS) valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c \ ../libpcap.a $(LIBS) writecaptest: $(srcdir)/writecaptest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o writecaptest $(srcdir)/writecaptest.c \ ../libpcap.a $(LIBS) clean: rm -f $(CLEANFILES) rm -rf *.dSYM distclean: clean rm -f Makefile config.cache config.log config.status \ config.h stamp-h stamp-h.in rm -rf autom4te.cache install: uninstall: tags: $(TAGFILES) ctags -wtd $(TAGFILES) depend: $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)