From 97a9217a80442061add4f20a612a3a5dd2cdb0d4 Mon Sep 17 00:00:00 2001 From: Antonio Huete Jimenez Date: Sat, 17 Mar 2018 08:21:54 -0700 Subject: [PATCH] Import libpcap-1.8.1. See CHANGES for the details. --- contrib/libpcap/CHANGES | 169 +- contrib/libpcap/LICENSE | 6 +- contrib/libpcap/README | 23 +- contrib/libpcap/README.DELETED | 20 + contrib/libpcap/VERSION | 2 +- contrib/libpcap/arcnet.h | 2 - contrib/libpcap/atmuni31.h | 2 - contrib/libpcap/bpf/net/bpf_filter.c | 148 +- contrib/libpcap/bpf_dump.c | 9 +- contrib/libpcap/bpf_image.c | 37 +- contrib/libpcap/etherent.c | 11 +- contrib/libpcap/ethertype.h | 5 +- contrib/libpcap/extract.h | 221 + contrib/libpcap/fad-getad.c | 138 +- contrib/libpcap/{inet.c => fad-helpers.c} | 907 ++- contrib/libpcap/gencode.c | 5790 +++++++++-------- contrib/libpcap/gencode.h | 172 +- contrib/libpcap/grammar.y | 295 +- contrib/libpcap/inet.c | 744 +-- contrib/libpcap/llc.h | 37 +- contrib/libpcap/nametoaddr.c | 80 +- .../libpcap/{pcap-namedb.h => nametoaddr.h} | 20 +- contrib/libpcap/nlpid.h | 2 - contrib/libpcap/optimize.c | 891 +-- contrib/libpcap/pcap-bpf.c | 931 ++- contrib/libpcap/pcap-bpf.h | 4 +- contrib/libpcap/pcap-common.c | 411 +- contrib/libpcap/pcap-common.h | 4 +- contrib/libpcap/pcap-filter.manmisc.in | 126 +- contrib/libpcap/pcap-int.h | 402 +- contrib/libpcap/pcap-linktype.manmisc.in | 4 +- contrib/libpcap/pcap-namedb.h | 2 - contrib/libpcap/pcap-savefile.manfile.in | 40 +- contrib/libpcap/pcap-tstamp.manmisc.in | 53 +- contrib/libpcap/pcap.3pcap.in | 94 +- contrib/libpcap/pcap.c | 1182 +++- contrib/libpcap/pcap.h | 2 - contrib/libpcap/pcap/bluetooth.h | 23 +- contrib/libpcap/pcap/bpf.h | 1191 +--- .../{pcap-bpf.h => pcap/can_socketcan.h} | 23 +- contrib/libpcap/pcap/{bpf.h => dlt.h} | 449 +- contrib/libpcap/pcap/export-defs.h | 108 + contrib/libpcap/pcap/namedb.h | 34 +- contrib/libpcap/pcap/nflog.h | 92 + contrib/libpcap/pcap/pcap.h | 311 +- contrib/libpcap/pcap/sll.h | 4 +- contrib/libpcap/pcap/usb.h | 14 +- contrib/libpcap/pcap/vlan.h | 2 - contrib/libpcap/pcap_activate.3pcap | 75 +- contrib/libpcap/pcap_breakloop.3pcap | 6 +- contrib/libpcap/pcap_can_set_rfmon.3pcap | 36 +- contrib/libpcap/pcap_close.3pcap | 4 +- contrib/libpcap/pcap_compile.3pcap.in | 4 +- contrib/libpcap/pcap_create.3pcap | 4 +- contrib/libpcap/pcap_datalink.3pcap.in | 33 +- .../libpcap/pcap_datalink_name_to_val.3pcap | 7 +- .../libpcap/pcap_datalink_val_to_name.3pcap | 20 +- contrib/libpcap/pcap_dump.3pcap | 8 +- contrib/libpcap/pcap_dump_close.3pcap | 4 +- contrib/libpcap/pcap_dump_file.3pcap | 4 +- contrib/libpcap/pcap_dump_flush.3pcap | 4 +- contrib/libpcap/pcap_dump_ftell.3pcap | 4 +- contrib/libpcap/pcap_dump_open.3pcap.in | 19 +- contrib/libpcap/pcap_file.3pcap | 4 +- contrib/libpcap/pcap_fileno.3pcap | 4 +- contrib/libpcap/pcap_findalldevs.3pcap | 12 +- contrib/libpcap/pcap_freecode.3pcap | 4 +- contrib/libpcap/pcap_get_selectable_fd.3pcap | 16 +- .../pcap_get_tstamp_precision.3pcap.in | 52 + contrib/libpcap/pcap_geterr.3pcap | 6 +- contrib/libpcap/pcap_inject.3pcap | 4 +- contrib/libpcap/pcap_is_swapped.3pcap | 19 +- contrib/libpcap/pcap_lib_version.3pcap | 4 +- contrib/libpcap/pcap_list_datalinks.3pcap.in | 23 +- .../libpcap/pcap_list_tstamp_types.3pcap.in | 2 +- contrib/libpcap/pcap_lookupdev.3pcap | 4 +- contrib/libpcap/pcap_lookupnet.3pcap | 4 +- contrib/libpcap/pcap_loop.3pcap | 49 +- contrib/libpcap/pcap_major_version.3pcap | 4 +- contrib/libpcap/pcap_next_ex.3pcap | 46 +- contrib/libpcap/pcap_offline_filter.3pcap | 4 +- contrib/libpcap/pcap_open_dead.3pcap.in | 43 +- contrib/libpcap/pcap_open_live.3pcap | 4 +- contrib/libpcap/pcap_open_offline.3pcap.in | 43 +- contrib/libpcap/pcap_set_buffer_size.3pcap | 4 +- contrib/libpcap/pcap_set_datalink.3pcap | 4 +- ...en.3pcap => pcap_set_immediate_mode.3pcap} | 21 +- contrib/libpcap/pcap_set_promisc.3pcap | 4 +- contrib/libpcap/pcap_set_rfmon.3pcap | 4 +- contrib/libpcap/pcap_set_snaplen.3pcap | 4 +- contrib/libpcap/pcap_set_timeout.3pcap | 11 +- .../pcap_set_tstamp_precision.3pcap.in | 61 + contrib/libpcap/pcap_set_tstamp_type.3pcap.in | 4 +- contrib/libpcap/pcap_setdirection.3pcap | 6 +- contrib/libpcap/pcap_setfilter.3pcap | 4 +- contrib/libpcap/pcap_setnonblock.3pcap | 12 +- contrib/libpcap/pcap_snapshot.3pcap | 14 +- contrib/libpcap/pcap_stats.3pcap | 4 +- contrib/libpcap/pcap_statustostr.3pcap | 4 +- contrib/libpcap/pcap_strerror.3pcap | 4 +- .../pcap_tstamp_type_name_to_val.3pcap | 4 +- .../pcap_tstamp_type_val_to_name.3pcap | 10 +- contrib/libpcap/portability.h | 216 + contrib/libpcap/ppp.h | 1 - contrib/libpcap/savefile.c | 268 +- contrib/libpcap/scanner.l | 258 +- contrib/libpcap/sf-pcap-ng.c | 647 +- contrib/libpcap/sf-pcap-ng.h | 3 +- contrib/libpcap/sf-pcap.c | 540 +- contrib/libpcap/sf-pcap.h | 3 +- contrib/libpcap/sockutils.c | 1230 ++++ contrib/libpcap/sockutils.h | 241 + contrib/libpcap/sunatmpos.h | 2 - 113 files changed, 11788 insertions(+), 7620 deletions(-) create mode 100644 contrib/libpcap/extract.h copy contrib/libpcap/{inet.c => fad-helpers.c} (59%) copy contrib/libpcap/{pcap-namedb.h => nametoaddr.h} (84%) copy contrib/libpcap/{pcap-bpf.h => pcap/can_socketcan.h} (87%) copy contrib/libpcap/pcap/{bpf.h => dlt.h} (79%) create mode 100644 contrib/libpcap/pcap/export-defs.h create mode 100644 contrib/libpcap/pcap/nflog.h create mode 100644 contrib/libpcap/pcap_get_tstamp_precision.3pcap.in copy contrib/libpcap/{pcap_set_snaplen.3pcap => pcap_set_immediate_mode.3pcap} (76%) create mode 100644 contrib/libpcap/pcap_set_tstamp_precision.3pcap.in create mode 100644 contrib/libpcap/portability.h create mode 100644 contrib/libpcap/sockutils.c create mode 100644 contrib/libpcap/sockutils.h diff --git a/contrib/libpcap/CHANGES b/contrib/libpcap/CHANGES index 0dcf957eca..1784096593 100644 --- a/contrib/libpcap/CHANGES +++ b/contrib/libpcap/CHANGES @@ -1,9 +1,141 @@ -Monday March 18, 2013 guy@alum.mit.edu +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 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. - Checks added for malloc()/realloc()/etc. failures. Fix pcap-config to include -lpthread if canusb support is present Try to fix "pcap_parse not defined" problems when --without-flex @@ -29,6 +161,7 @@ Summary for 1.4.0 libpcap release 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 @@ -208,7 +341,7 @@ Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap rele DLT: Add JUNIPER_ST 802.15.4 support Variable length 802.11 header support - X2E data type 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 @@ -220,7 +353,7 @@ Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap rele 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 + 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 @@ -233,14 +366,14 @@ Mon. September 10, 2007. ken@xelerance.com. Summary for 0.9.8 libpcap relea 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 + 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 + files at the top-level directory to include those headers, for backwards compatibility. Add Bluetooth support Add USB capturing support on Linux @@ -248,30 +381,30 @@ Wed. April 25, 2007. ken@xelerance.com. Summary for 0.9.6 libpcap release 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 + 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) + 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 + 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 + 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 + 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 + 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. + was not checked. Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release @@ -283,19 +416,19 @@ Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release 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 + Fix allocation of buffer for list of link-layer types Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communcation 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 + 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 + 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 + 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 diff --git a/contrib/libpcap/LICENSE b/contrib/libpcap/LICENSE index dea5f7d54d..a10474d54a 100644 --- a/contrib/libpcap/LICENSE +++ b/contrib/libpcap/LICENSE @@ -1,9 +1,9 @@ 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 @@ -13,7 +13,7 @@ are met: 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. diff --git a/contrib/libpcap/README b/contrib/libpcap/README index 8cac0af1d2..9f65948d4e 100644 --- a/contrib/libpcap/README +++ b/contrib/libpcap/README @@ -1,5 +1,3 @@ -@(#) $Header: /tcpdump/master/libpcap/README,v 1.34 2008-12-14 19:44:14 guy Exp $ (LBL) - LIBPCAP 1.x.y www.tcpdump.org @@ -10,18 +8,15 @@ Please send inquiries/comments/reports to: Anonymous Git is available via: git clone git://bpf.tcpdump.org/libpcap -Version 1.x.y of LIBPCAP can be retrieved with the CVS tag "libpcap_1_{x}rel{y}": - cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout -r libpcap_1_{x}rel{y} libpcap - Please submit patches by forking the branch on GitHub at - http://github.com/mcr/libpcap/tree/master + http://github.com/the-tcpdump-group/libpcap/tree/master and issuing a pull request. formerly from Lawrence Berkeley National Laboratory Network Research Group - ftp://ftp.ee.lbl.gov/libpcap.tar.Z (0.4) + ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z This directory contains source code for libpcap, a system-independent interface for user-level packet capture. libpcap provides a portable @@ -81,15 +76,15 @@ information on configuring that option. 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 +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 +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 +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. Problems, bugs, questions, desirable enhancements, etc. should be sent @@ -97,12 +92,12 @@ to the address "tcpdump-workers@lists.tcpdump.org". Bugs, support requests, and feature requests may also be submitted on the GitHub issue tracker for libpcap at - https://github.com/mcr/libpcap/issues + https://github.com/the-tcpdump-group/libpcap/issues Source code contributions, etc. should be sent to the email address above or submitted by forking the branch on GitHub at - http://github.com/mcr/libpcap/tree/master + http://github.com/the-tcpdump-group/libpcap/tree/master and issuing a pull request. diff --git a/contrib/libpcap/README.DELETED b/contrib/libpcap/README.DELETED index d084061b3e..afa061dfed 100644 --- a/contrib/libpcap/README.DELETED +++ b/contrib/libpcap/README.DELETED @@ -1,4 +1,24 @@ +pcap-new.c +pcap-rpcap.c +pcap-rpcap.h +remote-ext.h +CMakeLists.txt +GenVersion.bat +Makefile-devel-adds +cmake/ +cmakeconfig.h.in +config/ +configure.ac CREDITS +gen_version_c.sh +gen_version_header.sh +pcap-bt-monitor-linux.c +pcap-bt-monitor-linux.h +pcap-dbus.c +pcap-dbus.h +pcap-tc.c +pcap-tc.h +pcap_version.h.in ChmodBPF/ INSTALL.txt Makefile.in diff --git a/contrib/libpcap/VERSION b/contrib/libpcap/VERSION index 88c5fb891d..a8fdfda1c7 100644 --- a/contrib/libpcap/VERSION +++ b/contrib/libpcap/VERSION @@ -1 +1 @@ -1.4.0 +1.8.1 diff --git a/contrib/libpcap/arcnet.h b/contrib/libpcap/arcnet.h index 4f86043e61..58690985cb 100644 --- a/contrib/libpcap/arcnet.h +++ b/contrib/libpcap/arcnet.h @@ -30,8 +30,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Id: arcnet.h,v 1.2 2001-04-24 02:17:52 guy Exp $ (LBL) - * * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp */ diff --git a/contrib/libpcap/atmuni31.h b/contrib/libpcap/atmuni31.h index 880cc1a8a4..0f85430098 100644 --- a/contrib/libpcap/atmuni31.h +++ b/contrib/libpcap/atmuni31.h @@ -28,8 +28,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/atmuni31.h,v 1.3 2007-10-22 19:28:58 guy Exp $ (LBL) */ /* Based on UNI3.1 standard by ATM Forum */ diff --git a/contrib/libpcap/bpf/net/bpf_filter.c b/contrib/libpcap/bpf/net/bpf_filter.c index 0c4fb00616..01a1b64e71 100644 --- a/contrib/libpcap/bpf/net/bpf_filter.c +++ b/contrib/libpcap/bpf/net/bpf_filter.c @@ -38,20 +38,15 @@ * @(#)bpf.c 7.5 (Berkeley) 7/15/91 */ -#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL)) -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/bpf/net/bpf_filter.c,v 1.46 2008-01-02 04:16:46 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include @@ -78,7 +73,7 @@ static const char rcsid[] _U_ = # define MLEN(m) ((m)->m_len) #endif /* defined(__hpux) || SOLARIS */ -#endif /* WIN32 */ +#endif /* _WIN32 */ #include @@ -104,7 +99,7 @@ static const char rcsid[] _U_ = #endif #ifndef LBL_ALIGN -#ifndef WIN32 +#ifndef _WIN32 #include #endif @@ -200,23 +195,41 @@ m_xhalf(m, k, err) } #endif +#ifdef __linux__ +#include +#include +#include +#endif + +enum { + BPF_S_ANC_NONE, + BPF_S_ANC_VLAN_TAG, + BPF_S_ANC_VLAN_TAG_PRESENT, +}; + /* * Execute the filter program starting at pc on the packet p * wirelen is the length of the original packet * buflen is the amount of data present + * aux_data is auxiliary data, currently used only when interpreting + * filters intended for the Linux kernel in cases where the kernel + * rejects the filter; it contains VLAN tag information * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, * in all other cases, p is a pointer to a buffer and buflen is its size. + * + * Thanks to Ani Sinha for providing initial implementation */ u_int -bpf_filter(pc, p, wirelen, buflen) +bpf_filter_with_aux_data(pc, p, wirelen, buflen, aux_data) register const struct bpf_insn *pc; register const u_char *p; u_int wirelen; register u_int buflen; + register const struct bpf_aux_data *aux_data; { register u_int32 A, X; - register int k; - int32 mem[BPF_MEMWORDS]; + register bpf_u_int32 k; + u_int32 mem[BPF_MEMWORDS]; #if defined(KERNEL) || defined(_KERNEL) struct mbuf *m, *n; int merr, len; @@ -255,7 +268,7 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_W|BPF_ABS: k = pc->k; - if (k + sizeof(int32) > buflen) { + if (k > buflen || sizeof(int32_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; @@ -272,7 +285,7 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_H|BPF_ABS: k = pc->k; - if (k + sizeof(short) > buflen) { + if (k > buflen || sizeof(int16_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; @@ -288,22 +301,50 @@ bpf_filter(pc, p, wirelen, buflen) continue; case BPF_LD|BPF_B|BPF_ABS: - k = pc->k; - if (k >= buflen) { + { +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) + int code = BPF_S_ANC_NONE; +#define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ + code = BPF_S_ANC_##CODE; \ + if (!aux_data) \ + return 0; \ + break; + + switch (pc->k) { + ANCILLARY(VLAN_TAG); + ANCILLARY(VLAN_TAG_PRESENT); + default : +#endif + k = pc->k; + if (k >= buflen) { #if defined(KERNEL) || defined(_KERNEL) - if (m == NULL) - return 0; - n = m; - MINDEX(len, n, k); - A = mtod(n, u_char *)[k]; - continue; + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = mtod(n, u_char *)[k]; + continue; #else - return 0; + return 0; +#endif + } + A = p[k]; +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) + } + switch (code) { + case BPF_S_ANC_VLAN_TAG: + if (aux_data) + A = aux_data->vlan_tag; + break; + + case BPF_S_ANC_VLAN_TAG_PRESENT: + if (aux_data) + A = aux_data->vlan_tag_present; + break; + } #endif + continue; } - A = p[k]; - continue; - case BPF_LD|BPF_W|BPF_LEN: A = wirelen; continue; @@ -314,7 +355,8 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_W|BPF_IND: k = X + pc->k; - if (k + sizeof(int32) > buflen) { + if (pc->k > buflen || X > buflen - pc->k || + sizeof(int32_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; @@ -331,7 +373,8 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_H|BPF_IND: k = X + pc->k; - if (k + sizeof(short) > buflen) { + if (X > buflen || pc->k > buflen - X || + sizeof(int16_t) > buflen - k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; @@ -348,7 +391,7 @@ bpf_filter(pc, p, wirelen, buflen) case BPF_LD|BPF_B|BPF_IND: k = X + pc->k; - if (k >= buflen) { + if (pc->k >= buflen || X >= buflen - pc->k) { #if defined(KERNEL) || defined(_KERNEL) if (m == NULL) return 0; @@ -469,6 +512,12 @@ bpf_filter(pc, p, wirelen, buflen) A /= X; continue; + case BPF_ALU|BPF_MOD|BPF_X: + if (X == 0) + return 0; + A %= X; + continue; + case BPF_ALU|BPF_AND|BPF_X: A &= X; continue; @@ -477,6 +526,10 @@ bpf_filter(pc, p, wirelen, buflen) A |= X; continue; + case BPF_ALU|BPF_XOR|BPF_X: + A ^= X; + continue; + case BPF_ALU|BPF_LSH|BPF_X: A <<= X; continue; @@ -501,6 +554,10 @@ bpf_filter(pc, p, wirelen, buflen) A /= pc->k; continue; + case BPF_ALU|BPF_MOD|BPF_K: + A %= pc->k; + continue; + case BPF_ALU|BPF_AND|BPF_K: A &= pc->k; continue; @@ -509,6 +566,10 @@ bpf_filter(pc, p, wirelen, buflen) A |= pc->k; continue; + case BPF_ALU|BPF_XOR|BPF_K: + A ^= pc->k; + continue; + case BPF_ALU|BPF_LSH|BPF_K: A <<= pc->k; continue; @@ -518,7 +579,12 @@ bpf_filter(pc, p, wirelen, buflen) continue; case BPF_ALU|BPF_NEG: - A = -A; + /* + * Most BPF arithmetic is unsigned, but negation + * can't be unsigned; throw some casts to + * specify what we're trying to do. + */ + A = (u_int32)(-(int32)A); continue; case BPF_MISC|BPF_TAX: @@ -532,6 +598,17 @@ bpf_filter(pc, p, wirelen, buflen) } } +u_int +bpf_filter(pc, p, wirelen, buflen) + register const struct bpf_insn *pc; + register const u_char *p; + u_int wirelen; + register u_int buflen; +{ + return bpf_filter_with_aux_data(pc, p, wirelen, buflen, NULL); +} + + /* * Return true if the 'fcode' is a valid filter program. * The constraints are that each jump be forward and to a valid @@ -561,7 +638,7 @@ bpf_validate(f, len) return 0; #endif - for (i = 0; i < len; ++i) { + for (i = 0; i < (u_int)len; ++i) { p = &f[i]; switch (BPF_CLASS(p->code)) { /* @@ -611,13 +688,16 @@ bpf_validate(f, len) case BPF_MUL: case BPF_OR: case BPF_AND: + case BPF_XOR: case BPF_LSH: case BPF_RSH: case BPF_NEG: break; case BPF_DIV: + case BPF_MOD: /* - * Check for constant division by 0. + * Check for constant division or modulus + * by 0. */ if (BPF_SRC(p->code) == BPF_K && p->k == 0) return 0; @@ -659,7 +739,7 @@ bpf_validate(f, len) #if defined(KERNEL) || defined(_KERNEL) if (from + p->k < from || from + p->k >= len) #else - if (from + p->k >= len) + if (from + p->k >= (u_int)len) #endif return 0; break; @@ -667,7 +747,7 @@ bpf_validate(f, len) case BPF_JGT: case BPF_JGE: case BPF_JSET: - if (from + p->jt >= len || from + p->jf >= len) + if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)len) return 0; break; default: diff --git a/contrib/libpcap/bpf_dump.c b/contrib/libpcap/bpf_dump.c index e4ff4a2392..d5ab61e5e8 100644 --- a/contrib/libpcap/bpf_dump.c +++ b/contrib/libpcap/bpf_dump.c @@ -18,10 +18,6 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/bpf_dump.c,v 1.15 2008-01-02 04:16:46 guy Exp $ (LBL)"; -#endif #ifdef HAVE_CONFIG_H #include "config.h" @@ -55,7 +51,10 @@ bpf_dump(const struct bpf_program *p, int option) for (i = 0; i < n; ++insn, ++i) { #ifdef BDEBUG extern int bids[]; - printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1); + if (bids[i] > 0) + printf("[%02d]", bids[i] - 1); + else + printf(" -- "); #endif puts(bpf_image(insn, i)); } diff --git a/contrib/libpcap/bpf_image.c b/contrib/libpcap/bpf_image.c index e6c0f62617..01ec536dfd 100644 --- a/contrib/libpcap/bpf_image.c +++ b/contrib/libpcap/bpf_image.c @@ -19,18 +19,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/bpf_image.c,v 1.28 2008-01-02 04:16:46 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -40,7 +35,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -216,6 +211,11 @@ bpf_image(p, n) fmt = "x"; break; + case BPF_ALU|BPF_MOD|BPF_X: + op = "mod"; + fmt = "x"; + break; + case BPF_ALU|BPF_AND|BPF_X: op = "and"; fmt = "x"; @@ -226,6 +226,11 @@ bpf_image(p, n) fmt = "x"; break; + case BPF_ALU|BPF_XOR|BPF_X: + op = "xor"; + fmt = "x"; + break; + case BPF_ALU|BPF_LSH|BPF_X: op = "lsh"; fmt = "x"; @@ -256,6 +261,11 @@ bpf_image(p, n) fmt = "#%d"; break; + case BPF_ALU|BPF_MOD|BPF_K: + op = "mod"; + fmt = "#%d"; + break; + case BPF_ALU|BPF_AND|BPF_K: op = "and"; fmt = "#0x%x"; @@ -266,6 +276,11 @@ bpf_image(p, n) fmt = "#0x%x"; break; + case BPF_ALU|BPF_XOR|BPF_K: + op = "xor"; + fmt = "#0x%x"; + break; + case BPF_ALU|BPF_LSH|BPF_K: op = "lsh"; fmt = "#%d"; @@ -291,13 +306,13 @@ bpf_image(p, n) fmt = ""; break; } - (void)snprintf(operand, sizeof operand, fmt, v); + (void)pcap_snprintf(operand, sizeof operand, fmt, v); if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) { - (void)snprintf(image, sizeof image, + (void)pcap_snprintf(image, sizeof image, "(%03d) %-8s %-16s jt %d\tjf %d", n, op, operand, n + 1 + p->jt, n + 1 + p->jf); } else { - (void)snprintf(image, sizeof image, + (void)pcap_snprintf(image, sizeof image, "(%03d) %-8s %s", n, op, operand); } diff --git a/contrib/libpcap/etherent.c b/contrib/libpcap/etherent.c index d9de11467e..5cfd1b4c3b 100644 --- a/contrib/libpcap/etherent.c +++ b/contrib/libpcap/etherent.c @@ -19,18 +19,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/etherent.c,v 1.23 2006-10-04 18:09:22 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -40,7 +35,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include diff --git a/contrib/libpcap/ethertype.h b/contrib/libpcap/ethertype.h index 2d6bbebddd..51f63083f8 100644 --- a/contrib/libpcap/ethertype.h +++ b/contrib/libpcap/ethertype.h @@ -17,8 +17,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/ethertype.h,v 1.14 2005-09-05 09:06:58 guy Exp $ (LBL) */ /* @@ -114,6 +112,9 @@ #ifndef ETHERTYPE_PPPOES #define ETHERTYPE_PPPOES 0x8864 #endif +#ifndef ETHERTYPE_8021AD +#define ETHERTYPE_8021AD 0x88a8 +#endif #ifndef ETHERTYPE_LOOPBACK #define ETHERTYPE_LOOPBACK 0x9000 #endif diff --git a/contrib/libpcap/extract.h b/contrib/libpcap/extract.h new file mode 100644 index 0000000000..face5b7e94 --- /dev/null +++ b/contrib/libpcap/extract.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1992, 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. + */ + +#ifndef _WIN32 +#include +#endif + +/* + * Macros to extract possibly-unaligned big-endian integral values. + */ +#ifdef LBL_ALIGN +/* + * The processor doesn't natively handle unaligned loads. + */ +#if defined(__GNUC__) && defined(HAVE___ATTRIBUTE__) && \ + (defined(__alpha) || defined(__alpha__) || \ + defined(__mips) || defined(__mips__)) + +/* + * This is a GCC-compatible compiler and we have __attribute__, which + * we assume that mean we have __attribute__((packed)), and this is + * MIPS or Alpha, which has instructions that can help when doing + * unaligned loads. + * + * Declare packed structures containing a uint16_t and a uint32_t, + * cast the pointer to point to one of those, and fetch through it; + * the GCC manual doesn't appear to explicitly say that + * __attribute__((packed)) causes the compiler to generate unaligned-safe + * code, but it apppears to do so. + * + * We do this in case the compiler can generate code using those + * instructions to do an unaligned load and pass stuff to "ntohs()" or + * "ntohl()", which might be better than than the code to fetch the + * bytes one at a time and assemble them. (That might not be the + * case on a little-endian platform, such as DEC's MIPS machines and + * Alpha machines, where "ntohs()" and "ntohl()" might not be done + * inline.) + * + * We do this only for specific architectures because, for example, + * at least some versions of GCC, when compiling for 64-bit SPARC, + * generate code that assumes alignment if we do this. + * + * XXX - add other architectures and compilers as possible and + * appropriate. + * + * HP's C compiler, indicated by __HP_cc being defined, supports + * "#pragma unaligned N" in version A.05.50 and later, where "N" + * specifies a number of bytes at which the typedef on the next + * line is aligned, e.g. + * + * #pragma unalign 1 + * typedef uint16_t unaligned_uint16_t; + * + * to define unaligned_uint16_t as a 16-bit unaligned data type. + * This could be presumably used, in sufficiently recent versions of + * the compiler, with macros similar to those below. This would be + * useful only if that compiler could generate better code for PA-RISC + * or Itanium than would be generated by a bunch of shifts-and-ORs. + * + * DEC C, indicated by __DECC being defined, has, at least on Alpha, + * an __unaligned qualifier that can be applied to pointers to get the + * compiler to generate code that does unaligned loads and stores when + * dereferencing the pointer in question. + * + * XXX - what if the native C compiler doesn't support + * __attribute__((packed))? How can we get it to generate unaligned + * accesses for *specific* items? + */ +typedef struct { + uint16_t val; +} __attribute__((packed)) unaligned_uint16_t; + +typedef struct { + uint32_t val; +} __attribute__((packed)) unaligned_uint32_t; + +static inline uint16_t +EXTRACT_16BITS(const void *p) +{ + return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val)); +} + +static inline uint32_t +EXTRACT_32BITS(const void *p) +{ + return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val)); +} + +static inline uint64_t +EXTRACT_64BITS(const void *p) +{ + return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \ + ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0)); +} + +#else /* have to do it a byte at a time */ +/* + * This isn't a GCC-compatible compiler, we don't have __attribute__, + * or we do but we don't know of any better way with this instruction + * set to do unaligned loads, so do unaligned loads of big-endian + * quantities the hard way - fetch the bytes one at a time and + * assemble them. + */ +#define EXTRACT_16BITS(p) \ + ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0))) +#define EXTRACT_32BITS(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0))) +#define EXTRACT_64BITS(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0))) +#endif /* must special-case unaligned accesses */ +#else /* LBL_ALIGN */ +/* + * The processor natively handles unaligned loads, so we can just + * cast the pointer and fetch through it. + */ +static inline uint16_t +EXTRACT_16BITS(const void *p) +{ + return ((uint16_t)ntohs(*(const uint16_t *)(p))); +} + +static inline uint32_t +EXTRACT_32BITS(const void *p) +{ + return ((uint32_t)ntohl(*(const uint32_t *)(p))); +} + +static inline uint64_t +EXTRACT_64BITS(const void *p) +{ + return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \ + ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0)); + +} + +#endif /* LBL_ALIGN */ + +#define EXTRACT_24BITS(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) + +#define EXTRACT_40BITS(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) + +#define EXTRACT_48BITS(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) + +#define EXTRACT_56BITS(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) + +/* + * Macros to extract possibly-unaligned little-endian integral values. + * XXX - do loads on little-endian machines that support unaligned loads? + */ +#define EXTRACT_LE_8BITS(p) (*(p)) +#define EXTRACT_LE_16BITS(p) \ + ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_32BITS(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_24BITS(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_64BITS(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0))) diff --git a/contrib/libpcap/fad-getad.c b/contrib/libpcap/fad-getad.c index f4d5869c2d..b67b5cdcd4 100644 --- a/contrib/libpcap/fad-getad.c +++ b/contrib/libpcap/fad-getad.c @@ -32,11 +32,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/fad-getad.c,v 1.12 2007-09-14 00:44:55 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -60,9 +55,15 @@ static const char rcsid[] _U_ = #include "os-proto.h" #endif -#ifdef AF_PACKET +/* + * We don't do this on Solaris 11 and later, as it appears there aren't + * any AF_PACKET addresses on interfaces, so we don't need this, and + * we end up including both the OS's and our , + * and their definitions of some data structures collide. + */ +#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) # ifdef HAVE_NETPACKET_PACKET_H -/* Solaris 11 and later, Linux distributions with newer glibc */ +/* Linux distributions with newer glibc */ # include # else /* HAVE_NETPACKET_PACKET_H */ /* LynxOS, Linux distributions with older glibc */ @@ -75,7 +76,7 @@ static const char rcsid[] _U_ = # include # endif /* __Lynx__ */ # endif /* HAVE_NETPACKET_PACKET_H */ -#endif /* AF_PACKET */ +#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */ /* * This is fun. @@ -120,7 +121,7 @@ get_sa_len(struct sockaddr *addr) return (sizeof (struct sockaddr_in6)); #endif -#ifdef AF_PACKET +#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) case AF_PACKET: return (sizeof (struct sockaddr_ll)); #endif @@ -140,10 +141,11 @@ get_sa_len(struct sockaddr *addr) * Get a list of all interfaces that are up and that we can open. * Returns -1 on error, 0 otherwise. * The list, as returned through "alldevsp", may be null if no interfaces - * were up and could be opened. + * could be opened. */ int -pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) +pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf, + int (*check_usable)(const char *)) { pcap_if_t *devlist = NULL; struct ifaddrs *ifap, *ifa; @@ -156,10 +158,10 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) * Get the list of interface addresses. * * Note: this won't return information about interfaces - * with no addresses; are there any such interfaces - * that would be capable of receiving packets? - * (Interfaces incapable of receiving packets aren't - * very interesting from libpcap's point of view.) + * with no addresses, so, if a platform has interfaces + * with no interfaces on which traffic can be captured, + * we must check for those interfaces as well (see, for + * example, what's done on Linux). * * LAN interfaces will probably have link-layer * addresses; I don't know whether all implementations @@ -167,40 +169,56 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) * those. */ if (getifaddrs(&ifap) != 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getifaddrs: %s", pcap_strerror(errno)); return (-1); } for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { /* - * Is this interface up? + * If this entry has a colon followed by a number at + * the end, we assume it's a logical interface. Those + * are just the way you assign multiple IP addresses to + * a real interface on Linux, so an entry for a logical + * interface should be treated like the entry for the + * real interface; we do that by stripping off the ":" + * and the number. + * + * XXX - should we do this only on Linux? */ - if (!(ifa->ifa_flags & IFF_UP)) { + p = strchr(ifa->ifa_name, ':'); + if (p != NULL) { /* - * No, so don't add it to the list. + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (isdigit((unsigned char)*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } + + /* + * Can we capture on this device? + */ + if (!(*check_usable)(ifa->ifa_name)) { + /* + * No. */ continue; } /* * "ifa_addr" was apparently null on at least one - * interface on some system. - * - * "ifa_broadaddr" may be non-null even on - * non-broadcast interfaces, and was null on - * at least one OpenBSD 3.4 system on at least - * one interface with IFF_BROADCAST set. - * - * "ifa_dstaddr" was, on at least one FreeBSD 4.1 - * system, non-null on a non-point-to-point - * interface. - * - * Therefore, we supply the address and netmask only - * if "ifa_addr" is non-null (if there's no address, - * there's obviously no netmask), and supply the - * broadcast and destination addresses if the appropriate - * flag is set *and* the appropriate "ifa_" entry doesn't - * evaluate to a null pointer. + * interface on some system. Therefore, we supply + * the address and netmask only if "ifa_addr" is + * non-null (if there's no address, there's obviously + * no netmask). */ if (ifa->ifa_addr != NULL) { addr = ifa->ifa_addr; @@ -211,6 +229,22 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) addr_size = 0; netmask = NULL; } + + /* + * Note that, on some platforms, ifa_broadaddr and + * ifa_dstaddr could be the same field (true on at + * least some versions of *BSD and OS X), so we + * can't just check whether the broadcast address + * is null and add it if so and check whether the + * destination address is null and add it if so. + * + * Therefore, we must also check the IFF_BROADCAST + * flag, and only add a broadcast address if it's + * set, and check the IFF_POINTTOPOINT flag, and + * only add a destination address if it's set (as + * per man page recommendations on some of those + * platforms). + */ if (ifa->ifa_flags & IFF_BROADCAST && ifa->ifa_broadaddr != NULL) { broadaddr = ifa->ifa_broadaddr; @@ -228,40 +262,12 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) dstaddr_size = 0; } - /* - * If this entry has a colon followed by a number at - * the end, we assume it's a logical interface. Those - * are just the way you assign multiple IP addresses to - * a real interface on Linux, so an entry for a logical - * interface should be treated like the entry for the - * real interface; we do that by stripping off the ":" - * and the number. - * - * XXX - should we do this only on Linux? - */ - p = strchr(ifa->ifa_name, ':'); - if (p != NULL) { - /* - * We have a ":"; is it followed by a number? - */ - q = p + 1; - while (isdigit((unsigned char)*q)) - q++; - if (*q == '\0') { - /* - * All digits after the ":" until the end. - * Strip off the ":" and everything after - * it. - */ - *p = '\0'; - } - } - /* * Add information for this address to the list. */ if (add_addr_to_iflist(&devlist, ifa->ifa_name, - ifa->ifa_flags, addr, addr_size, netmask, addr_size, + if_flags_to_pcap_flags(ifa->ifa_name, ifa->ifa_flags), + addr, addr_size, netmask, addr_size, broadaddr, broadaddr_size, dstaddr, dstaddr_size, errbuf) < 0) { ret = -1; diff --git a/contrib/libpcap/inet.c b/contrib/libpcap/fad-helpers.c similarity index 59% copy from contrib/libpcap/inet.c copy to contrib/libpcap/fad-helpers.c index 6ae46ef876..4860bc55ca 100644 --- a/contrib/libpcap/inet.c +++ b/contrib/libpcap/fad-helpers.c @@ -32,18 +32,13 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.79 2008-04-20 18:19:02 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #include #ifndef MSDOS @@ -59,7 +54,7 @@ struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -67,9 +62,9 @@ struct rtentry; /* declarations in */ #include #include #include -#if !defined(WIN32) && !defined(__BORLANDC__) +#if !defined(_WIN32) && !defined(__BORLANDC__) #include -#endif /* !WIN32 && !__BORLANDC__ */ +#endif /* !_WIN32 && !__BORLANDC__ */ #ifdef HAVE_LIMITS_H #include #else @@ -82,6 +77,7 @@ struct rtentry; /* declarations in */ #include "os-proto.h" #endif +#ifndef _WIN32 /* Not all systems have IFF_LOOPBACK */ #ifdef IFF_LOOPBACK #define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK) @@ -90,7 +86,38 @@ struct rtentry; /* declarations in */ (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0')) #endif -struct sockaddr * +#ifdef IFF_UP +#define ISUP(flags) ((flags) & IFF_UP) +#else +#define ISUP(flags) 0 +#endif + +#ifdef IFF_RUNNING +#define ISRUNNING(flags) ((flags) & IFF_RUNNING) +#else +#define ISRUNNING(flags) 0 +#endif + +/* + * Map UN*X-style interface flags to libpcap flags. + */ +bpf_u_int32 +if_flags_to_pcap_flags(const char *name _U_, u_int if_flags) +{ + bpf_u_int32 pcap_flags; + + pcap_flags = 0; + if (ISLOOPBACK(name, if_flags)) + pcap_flags |= PCAP_IF_LOOPBACK; + if (ISUP(if_flags)) + pcap_flags |= PCAP_IF_UP; + if (ISRUNNING(if_flags)) + pcap_flags |= PCAP_IF_RUNNING; + return (pcap_flags); +} +#endif + +static struct sockaddr * dup_sockaddr(struct sockaddr *sa, size_t sa_length) { struct sockaddr *newsa; @@ -100,40 +127,259 @@ dup_sockaddr(struct sockaddr *sa, size_t sa_length) return (memcpy(newsa, sa, sa_length)); } -static int -get_instance(const char *name) +/* + * Construct a "figure of merit" for an interface, for use when sorting + * the list of interfaces, in which interfaces that are up are superior + * to interfaces that aren't up, interfaces that are up and running are + * superior to interfaces that are up but not running, and non-loopback + * interfaces that are up and running are superior to loopback interfaces, + * and interfaces with the same flags have a figure of merit that's higher + * the lower the instance number. + * + * The goal is to try to put the interfaces most likely to be useful for + * capture at the beginning of the list. + * + * The figure of merit, which is lower the "better" the interface is, + * has the uppermost bit set if the interface isn't running, the bit + * below that set if the interface isn't up, the bit below that set + * if the interface is a loopback interface, and the interface index + * in the 29 bits below that. (Yes, we assume u_int is 32 bits.) + */ +static u_int +get_figure_of_merit(pcap_if_t *dev) { - const char *cp, *endcp; - int n; + const char *cp; + u_int n; - if (strcmp(name, "any") == 0) { + if (strcmp(dev->name, "any") == 0) { /* * Give the "any" device an artificially high instance * number, so it shows up after all other non-loopback * interfaces. */ - return INT_MAX; + n = 0x1FFFFFFF; /* 29 all-1 bits */ + } else { + /* + * A number at the end of the device name string is + * assumed to be a unit number. + */ + cp = dev->name + strlen(dev->name) - 1; + while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9') + cp--; + if (*cp >= '0' && *cp <= '9') + n = atoi(cp); + else + n = 0; } + if (!(dev->flags & PCAP_IF_RUNNING)) + n |= 0x80000000; + if (!(dev->flags & PCAP_IF_UP)) + n |= 0x40000000; + if (dev->flags & PCAP_IF_LOOPBACK) + n |= 0x20000000; + return (n); +} - endcp = name + strlen(name); - for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp) - continue; +/* + * Try to get a description for a given device. + * Returns a mallocated description if it could and NULL if it couldn't. + * + * XXX - on FreeBSDs that support it, should it get the sysctl named + * "dev.{adapter family name}.{adapter unit}.%desc" to get a description + * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" + * with my Cisco 350 card, so the name isn't entirely descriptive. The + * "dev.an.0.%pnpinfo" has a better description, although one might argue + * that the problem is really a driver bug - if it can find out that it's + * a Cisco 340 or 350, rather than an old Aironet card, it should use + * that in the description. + * + * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD + * and OpenBSD let you get a description, but it's not generated by the OS, + * it's set with another ioctl that ifconfig supports; we use that to get + * a description in FreeBSD and OpenBSD, but if there is no such + * description available, it still might be nice to get some description + * string based on the device type or something such as that. + * + * In OS X, the System Configuration framework can apparently return + * names in 10.4 and later. + * + * It also appears that freedesktop.org's HAL offers an "info.product" + * string, but the HAL specification says it "should not be used in any + * UI" and "subsystem/capability specific properties" should be used + * instead and, in any case, I think HAL is being deprecated in + * favor of other stuff such as DeviceKit. DeviceKit doesn't appear + * to have any obvious product information for devices, but maybe + * I haven't looked hard enough. + * + * Using the System Configuration framework, or HAL, or DeviceKit, or + * whatever, would require that libpcap applications be linked with + * the frameworks/libraries in question. That shouldn't be a problem + * for programs linking with the shared version of libpcap (unless + * you're running on AIX - which I think is the only UN*X that doesn't + * support linking a shared library with other libraries on which it + * depends, and having an executable linked only with the first shared + * library automatically pick up the other libraries when started - + * and using HAL or whatever). Programs linked with the static + * version of libpcap would have to use pcap-config with the --static + * flag in order to get the right linker flags in order to pick up + * the additional libraries/frameworks; those programs need that anyway + * for libpcap 1.1 and beyond on Linux, as, by default, it requires + * -lnl. + * + * Do any other UN*Xes, or desktop environments support getting a + * description? + */ +static char * +get_if_description(const char *name) +{ +#ifdef SIOCGIFDESCR + char *description = NULL; + int s; + struct ifreq ifrdesc; +#ifndef IFDESCRSIZE + size_t descrlen = 64; +#else + size_t descrlen = IFDESCRSIZE; +#endif /* IFDESCRSIZE */ - if (isdigit((unsigned char)*cp)) - n = atoi(cp); - else - n = 0; - return (n); + /* + * Get the description for the interface. + */ + memset(&ifrdesc, 0, sizeof ifrdesc); + strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s >= 0) { +#ifdef __FreeBSD__ + /* + * On FreeBSD, if the buffer isn't big enough for the + * description, the ioctl succeeds, but the description + * isn't copied, ifr_buffer.length is set to the description + * length, and ifr_buffer.buffer is set to NULL. + */ + for (;;) { + free(description); + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_buffer.buffer = description; + ifrdesc.ifr_buffer.length = descrlen; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { + if (ifrdesc.ifr_buffer.buffer == + description) + break; + else + descrlen = ifrdesc.ifr_buffer.length; + } else { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + break; + } + } else + break; + } +#else /* __FreeBSD__ */ + /* + * The only other OS that currently supports + * SIOCGIFDESCR is OpenBSD, and it has no way + * to get the description length - it's clamped + * to a maximum of IFDESCRSIZE. + */ + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_data = (caddr_t)description; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + } + } +#endif /* __FreeBSD__ */ + close(s); + if (description != NULL && strlen(description) == 0) { + /* + * Description is empty, so discard it. + */ + free(description); + description = NULL; + } + } + +#ifdef __FreeBSD__ + /* + * For FreeBSD, if we didn't get a description, and this is + * a device with a name of the form usbusN, label it as a USB + * bus. + */ + if (description == NULL) { + if (strncmp(name, "usbus", 5) == 0) { + /* + * OK, it begins with "usbus". + */ + long busnum; + char *p; + + errno = 0; + busnum = strtol(name + 5, &p, 10); + if (errno == 0 && p != name + 5 && *p == '\0' && + busnum >= 0 && busnum <= INT_MAX) { + /* + * OK, it's a valid number that's not + * bigger than INT_MAX. Construct + * a description from it. + */ + static const char descr_prefix[] = "USB bus number "; + size_t descr_size; + + /* + * Allow enough room for a 32-bit bus number. + * sizeof (descr_prefix) includes the + * terminating NUL. + */ + descr_size = sizeof (descr_prefix) + 10; + description = malloc(descr_size); + if (description != NULL) { + pcap_snprintf(description, descr_size, + "%s%ld", descr_prefix, busnum); + } + } + } + } +#endif + return (description); +#else /* SIOCGIFDESCR */ + return (NULL); +#endif /* SIOCGIFDESCR */ } +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0 and set *curdev_ret to point to it. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. If we + * weren't given a description, try to get one. + */ int add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, - u_int flags, const char *description, char *errbuf) + bpf_u_int32 flags, const char *description, char *errbuf) { pcap_t *p; pcap_if_t *curdev, *prevdev, *nextdev; - int this_instance; + u_int this_figure_of_merit, nextdev_figure_of_merit; char open_errbuf[PCAP_ERRBUF_SIZE]; + int ret; /* * Is there already an entry in the list for this interface? @@ -187,34 +433,83 @@ add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, en_name_len = strlen(name) - 1; en_name = malloc(en_name_len + 1); if (en_name == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } strcpy(en_name, "en"); strcat(en_name, name + 3); - p = pcap_open_live(en_name, 68, 0, 0, open_errbuf); + p = pcap_create(en_name, open_errbuf); free(en_name); } else #endif /* __APPLE */ - p = pcap_open_live(name, 68, 0, 0, open_errbuf); + p = pcap_create(name, open_errbuf); if (p == NULL) { /* - * No. Don't bother including it. - * Don't treat this as an error, though. + * The attempt to create the pcap_t failed; + * that's probably an indication that we're + * out of memory. + * + * Don't bother including this interface, + * but don't treat it as an error. */ *curdev_ret = NULL; return (0); } + /* Small snaplen, so we don't try to allocate much memory. */ + pcap_set_snaplen(p, 68); + ret = pcap_activate(p); pcap_close(p); + switch (ret) { + + case PCAP_ERROR_NO_SUCH_DEVICE: + case PCAP_ERROR_IFACE_NOT_UP: + /* + * We expect these two errors - they're the + * reason we try to open the device. + * + * PCAP_ERROR_NO_SUCH_DEVICE typically means + * "there's no such device *known to the + * OS's capture mechanism*", so, even though + * it might be a valid network interface, you + * can't capture on it (e.g., the loopback + * device in Solaris up to Solaris 10, or + * the vmnet devices in OS X with VMware + * Fusion). We don't include those devices + * in our list of devices, as there's no + * point in doing so - they're not available + * for capture. + * + * PCAP_ERROR_IFACE_NOT_UP means that the + * OS's capture mechanism doesn't work on + * interfaces not marked as up; some capture + * mechanisms *do* support that, so we no + * longer reject those interfaces out of hand, + * but we *do* want to reject them if they + * can't be opened for capture. + */ + *curdev_ret = NULL; + return (0); + } /* - * Yes, we can open it. + * Yes, we can open it, or we can't, for some other + * reason. + * + * If we can open it, we want to offer it for + * capture, as you can capture on it. If we can't, + * we want to offer it for capture, so that, if + * the user tries to capture on it, they'll get + * an error and they'll know why they can't + * capture on it (e.g., insufficient permissions) + * or they'll report it as a problem (and then + * have the error message to provide as information). + * * Allocate a new entry. */ curdev = malloc(sizeof(pcap_if_t)); if (curdev == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } @@ -225,47 +520,45 @@ add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, curdev->next = NULL; curdev->name = strdup(name); if (curdev->name == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev); return (-1); } - if (description != NULL) { + if (description == NULL) { /* - * We have a description for this interface. + * We weren't handed a description for the + * interface, so see if we can generate one + * ourselves. + */ + curdev->description = get_if_description(name); + } else { + /* + * We were handed a description; make a copy. */ curdev->description = strdup(description); if (curdev->description == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev->name); free(curdev); return (-1); } - } else { - /* - * We don't. - */ - curdev->description = NULL; } curdev->addresses = NULL; /* list starts out as empty */ - curdev->flags = 0; - if (ISLOOPBACK(name, flags)) - curdev->flags |= PCAP_IF_LOOPBACK; + curdev->flags = flags; /* * Add it to the list, in the appropriate location. - * First, get the instance number of this interface. + * First, get the "figure of merit" for this + * interface. */ - this_instance = get_instance(name); + this_figure_of_merit = get_figure_of_merit(curdev); /* - * Now look for the last interface with an instance number - * less than or equal to the new interface's instance - * number - except that non-loopback interfaces are - * arbitrarily treated as having interface numbers less - * than those of loopback interfaces, so the loopback - * interfaces are put at the end of the list. + * Now look for the last interface with an figure of merit + * less than or equal to the new interface's figure of + * merit. * * We start with "prevdev" being NULL, meaning we're before * the first element in the list. @@ -295,34 +588,13 @@ add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, } /* - * Is the new interface a non-loopback interface - * and the next interface a loopback interface? + * Is the new interface's figure of merit less + * than the next interface's figure of merit, + * meaning that the new interface is better + * than the next interface? */ - if (!(curdev->flags & PCAP_IF_LOOPBACK) && - (nextdev->flags & PCAP_IF_LOOPBACK)) { - /* - * Yes, we should put the new entry - * before "nextdev", i.e. after "prevdev". - */ - break; - } - - /* - * Is the new interface's instance number less - * than the next interface's instance number, - * and is it the case that the new interface is a - * non-loopback interface or the next interface is - * a loopback interface? - * - * (The goal of both loopback tests is to make - * sure that we never put a loopback interface - * before any non-loopback interface and that we - * always put a non-loopback interface before all - * loopback interfaces.) - */ - if (this_instance < get_instance(nextdev->name) && - (!(curdev->flags & PCAP_IF_LOOPBACK) || - (nextdev->flags & PCAP_IF_LOOPBACK))) { + nextdev_figure_of_merit = get_figure_of_merit(nextdev); + if (this_figure_of_merit < nextdev_figure_of_merit) { /* * Yes - we should put the new entry * before "nextdev", i.e. after "prevdev". @@ -358,53 +630,34 @@ add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, } /* - * XXX - on FreeBSDs that support it, should it get the sysctl named - * "dev.{adapter family name}.{adapter unit}.%desc" to get a description - * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" - * with my Cisco 350 card, so the name isn't entirely descriptive. The - * "dev.an.0.%pnpinfo" has a better description, although one might argue - * that the problem is really a driver bug - if it can find out that it's - * a Cisco 340 or 350, rather than an old Aironet card, it should use - * that in the description. + * Try to get a description for a given device, and then look for that + * device in the specified list of devices. * - * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD - * and OpenBSD let you get a description, but it's not generated by the OS, - * it's set with another ioctl that ifconfig supports; we use that to get - * a description in FreeBSD and OpenBSD, but if there is no such - * description available, it still might be nice to get some description - * string based on the device type or something such as that. + * If we find it, then, if the specified address isn't null, add it to + * the list of addresses for the device and return 0. * - * In OS X, the System Configuration framework can apparently return - * names in 10.4 and later. + * If we don't find it, check whether we can open it: * - * It also appears that freedesktop.org's HAL offers an "info.product" - * string, but the HAL specification says it "should not be used in any - * UI" and "subsystem/capability specific properties" should be used - * instead and, in any case, I think HAL is being deprecated in - * favor of other stuff such as DeviceKit. DeviceKit doesn't appear - * to have any obvious product information for devices, but maybe - * I haven't looked hard enough. + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. * - * Using the System Configuration framework, or HAL, or DeviceKit, or - * whatever, would require that libpcap applications be linked with - * the frameworks/libraries in question. That shouldn't be a problem - * for programs linking with the shared version of libpcap (unless - * you're running on AIX - which I think is the only UN*X that doesn't - * support linking a shared library with other libraries on which it - * depends, and having an executable linked only with the first shared - * library automatically pick up the other libraries when started - - * and using HAL or whatever). Programs linked with the static - * version of libpcap would have to use pcap-config with the --static - * flag in order to get the right linker flags in order to pick up - * the additional libraries/frameworks; those programs need that anyway - * for libpcap 1.1 and beyond on Linux, as, by default, it requires - * -lnl. + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags, and, if that succeeds, add the specified address + * to its list of addresses if that address is non-null, set + * *curdev_ret to point to the new entry, and return 0, otherwise + * return PCAP_ERROR and set errbuf to an error message. * - * Do any other UN*Xes, or desktop environments support getting a - * description? + * (We can get called with a null address because we might get a list + * of interface name/address combinations from the underlying OS, with + * the address being absent in some cases, rather than a list of + * interfaces with each interface having a list of addresses, so this + * call may be the only call made to add to the list, and we want to + * add interfaces even if they have no addresses.) */ int -add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, +add_addr_to_iflist(pcap_if_t **alldevs, const char *name, bpf_u_int32 flags, struct sockaddr *addr, size_t addr_size, struct sockaddr *netmask, size_t netmask_size, struct sockaddr *broadaddr, size_t broadaddr_size, @@ -412,90 +665,13 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, char *errbuf) { pcap_if_t *curdev; - char *description = NULL; - pcap_addr_t *curaddr, *prevaddr, *nextaddr; -#ifdef SIOCGIFDESCR - int s; - struct ifreq ifrdesc; -#ifndef IFDESCRSIZE - size_t descrlen = 64; -#else - size_t descrlen = IFDESCRSIZE; -#endif /* IFDESCRSIZE */ -#endif /* SIOCGIFDESCR */ -#ifdef SIOCGIFDESCR - /* - * Get the description for the interface. - */ - memset(&ifrdesc, 0, sizeof ifrdesc); - strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s >= 0) { -#ifdef __FreeBSD__ - /* - * On FreeBSD, if the buffer isn't big enough for the - * description, the ioctl succeeds, but the description - * isn't copied, ifr_buffer.length is set to the description - * length, and ifr_buffer.buffer is set to NULL. - */ - for (;;) { - free(description); - if ((description = malloc(descrlen)) != NULL) { - ifrdesc.ifr_buffer.buffer = description; - ifrdesc.ifr_buffer.length = descrlen; - if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { - if (ifrdesc.ifr_buffer.buffer == - description) - break; - else - descrlen = ifrdesc.ifr_buffer.length; - } else { - /* - * Failed to get interface description. - */ - free(description); - description = NULL; - break; - } - } else - break; - } -#else /* __FreeBSD__ */ - /* - * The only other OS that currently supports - * SIOCGIFDESCR is OpenBSD, and it has no way - * to get the description length - it's clamped - * to a maximum of IFDESCRSIZE. - */ - if ((description = malloc(descrlen)) != NULL) { - ifrdesc.ifr_data = (caddr_t)description; - if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { - /* - * Failed to get interface description. - */ - free(description); - description = NULL; - } - } -#endif /* __FreeBSD__ */ - close(s); - if (description != NULL && strlen(description) == 0) { - free(description); - description = NULL; - } - } -#endif /* SIOCGIFDESCR */ - - if (add_or_find_if(&curdev, alldevs, name, flags, description, - errbuf) == -1) { - free(description); + if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) { /* * Error - give up. */ return (-1); } - free(description); if (curdev == NULL) { /* * Device wasn't added because it can't be opened. @@ -504,15 +680,45 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, return (0); } + if (addr == NULL) { + /* + * There's no address to add; this entry just meant + * "here's a new interface". + */ + return (0); + } + /* - * "curdev" is an entry for this interface; add an entry for this - * address to its list of addresses. + * "curdev" is an entry for this interface, and we have an + * address for it; add an entry for that address to the + * interface's list of addresses. * * Allocate the new entry and fill it in. */ + return (add_addr_to_dev(curdev, addr, addr_size, netmask, + netmask_size, broadaddr, broadaddr_size, dstaddr, + dstaddr_size, errbuf)); +} + +/* + * Add an entry to the list of addresses for an interface. + * "curdev" is the entry for that interface. + * If this is the first IP address added to the interface, move it + * in the list as appropriate. + */ +int +add_addr_to_dev(pcap_if_t *curdev, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_addr_t *curaddr, *prevaddr, *nextaddr; + curaddr = malloc(sizeof(pcap_addr_t)); if (curaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } @@ -521,7 +727,7 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, if (addr != NULL) { curaddr->addr = dup_sockaddr(addr, addr_size); if (curaddr->addr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); @@ -532,7 +738,7 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, if (netmask != NULL) { curaddr->netmask = dup_sockaddr(netmask, netmask_size); if (curaddr->netmask == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->addr != NULL) free(curaddr->addr); @@ -545,7 +751,7 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, if (broadaddr != NULL) { curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); if (curaddr->broadaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->netmask != NULL) free(curaddr->netmask); @@ -560,7 +766,7 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, if (dstaddr != NULL) { curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); if (curaddr->dstaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->broadaddr != NULL) free(curaddr->broadaddr); @@ -603,6 +809,23 @@ add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, return (0); } +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. + */ int pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags, const char *description, char *errbuf) @@ -659,275 +882,3 @@ pcap_freealldevs(pcap_if_t *alldevs) free(curdev); } } - -#if !defined(WIN32) && !defined(MSDOS) - -/* - * 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. - */ -char * -pcap_lookupdev(errbuf) - register char *errbuf; -{ - pcap_if_t *alldevs; -/* for old BSD systems, including bsdi3 */ -#ifndef IF_NAMESIZE -#define IF_NAMESIZE IFNAMSIZ -#endif - static char device[IF_NAMESIZE + 1]; - char *ret; - - if (pcap_findalldevs(&alldevs, errbuf) == -1) - return (NULL); - - if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) { - /* - * There are no devices on the list, or the first device - * on the list is a loopback device, which means there - * are no non-loopback devices on the list. This means - * we can't return any device. - * - * XXX - why not return a loopback device? If we can't - * capture on it, it won't be on the list, and if it's - * on the list, there aren't any non-loopback devices, - * so why not just supply it as the default device? - */ - (void)strlcpy(errbuf, "no suitable device found", - PCAP_ERRBUF_SIZE); - ret = NULL; - } else { - /* - * Return the name of the first device on the list. - */ - (void)strlcpy(device, alldevs->name, sizeof(device)); - ret = device; - } - - pcap_freealldevs(alldevs); - return (ret); -} - -int -pcap_lookupnet(device, netp, maskp, errbuf) - register const char *device; - register bpf_u_int32 *netp, *maskp; - register char *errbuf; -{ - register int fd; - register struct sockaddr_in *sin4; - struct ifreq ifr; - - /* - * The pseudo-device "any" listens on all interfaces and therefore - * has the network address and -mask "0.0.0.0" therefore catching - * all traffic. Using NULL for the interface is the same as "any". - */ - if (!device || strcmp(device, "any") == 0 -#ifdef HAVE_DAG_API - || strstr(device, "dag") != NULL -#endif -#ifdef HAVE_SEPTEL_API - || strstr(device, "septel") != NULL -#endif -#ifdef PCAP_SUPPORT_BT - || strstr(device, "bluetooth") != NULL -#endif -#ifdef PCAP_SUPPORT_USB - || strstr(device, "usbmon") != NULL -#endif -#ifdef HAVE_SNF_API - || strstr(device, "snf") != NULL -#endif - ) { - *netp = *maskp = 0; - return 0; - } - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", - pcap_strerror(errno)); - return (-1); - } - memset(&ifr, 0, sizeof(ifr)); -#ifdef linux - /* XXX Work around Linux kernel bug */ - ifr.ifr_addr.sa_family = AF_INET; -#endif - (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { - if (errno == EADDRNOTAVAIL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "%s: no IPv4 address assigned", device); - } else { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFADDR: %s: %s", - device, pcap_strerror(errno)); - } - (void)close(fd); - return (-1); - } - sin4 = (struct sockaddr_in *)&ifr.ifr_addr; - *netp = sin4->sin_addr.s_addr; - memset(&ifr, 0, sizeof(ifr)); -#ifdef linux - /* XXX Work around Linux kernel bug */ - ifr.ifr_addr.sa_family = AF_INET; -#endif - (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); - (void)close(fd); - return (-1); - } - (void)close(fd); - *maskp = sin4->sin_addr.s_addr; - if (*maskp == 0) { - if (IN_CLASSA(*netp)) - *maskp = IN_CLASSA_NET; - else if (IN_CLASSB(*netp)) - *maskp = IN_CLASSB_NET; - else if (IN_CLASSC(*netp)) - *maskp = IN_CLASSC_NET; - else { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "inet class for 0x%x unknown", *netp); - return (-1); - } - } - *netp &= *maskp; - return (0); -} - -#elif defined(WIN32) - -/* - * 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. - */ -char * -pcap_lookupdev(errbuf) - register char *errbuf; -{ - DWORD dwVersion; - DWORD dwWindowsMajorVersion; - dwVersion = GetVersion(); /* get the OS version */ - dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - - if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { - /* - * Windows 95, 98, ME. - */ - ULONG NameLength = 8192; - static char AdaptersName[8192]; - - if (PacketGetAdapterNames(AdaptersName,&NameLength) ) - return (AdaptersName); - else - return NULL; - } else { - /* - * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility - */ - ULONG NameLength = 8192; - static WCHAR AdaptersName[8192]; - char *tAstr; - WCHAR *tUstr; - WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR)); - int NAdapts = 0; - - if(TAdaptersName == NULL) - { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); - return NULL; - } - - if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) - { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", - pcap_win32strerror()); - free(TAdaptersName); - return NULL; - } - - - tAstr = (char*)TAdaptersName; - tUstr = (WCHAR*)AdaptersName; - - /* - * Convert and copy the device names - */ - while(sscanf(tAstr, "%S", tUstr) > 0) - { - tAstr += strlen(tAstr) + 1; - tUstr += wcslen(tUstr) + 1; - NAdapts ++; - } - - tAstr++; - *tUstr = 0; - tUstr++; - - /* - * Copy the descriptions - */ - while(NAdapts--) - { - char* tmp = (char*)tUstr; - strcpy(tmp, tAstr); - tmp += strlen(tAstr) + 1; - tUstr = (WCHAR*)tmp; - tAstr += strlen(tAstr) + 1; - } - - free(TAdaptersName); - return (char *)(AdaptersName); - } -} - - -int -pcap_lookupnet(device, netp, maskp, errbuf) - register const char *device; - register bpf_u_int32 *netp, *maskp; - register 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 = 1; - struct sockaddr_in *t_addr; - unsigned int i; - - if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { - *netp = *maskp = 0; - return (0); - } - - for(i=0; isin_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); -} - -#endif /* !WIN32 && !MSDOS */ diff --git a/contrib/libpcap/gencode.c b/contrib/libpcap/gencode.c index cdb0d34e9f..a887f2730f 100644 --- a/contrib/libpcap/gencode.c +++ b/contrib/libpcap/gencode.c @@ -19,18 +19,14 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.309 2008-12-23 20:13:29 guy Exp $ (LBL)"; -#endif #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -41,16 +37,9 @@ static const char rcsid[] _U_ = #endif #include #include -#endif /* WIN32 */ - -/* - * XXX - why was this included even on UNIX? - */ -#ifdef __MINGW32__ -#include "ip6_misc.h" -#endif +#endif /* _WIN32 */ -#ifndef WIN32 +#ifndef _WIN32 #ifdef __NetBSD__ #include @@ -59,7 +48,7 @@ static const char rcsid[] _U_ = #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -84,29 +73,86 @@ static const char rcsid[] _U_ = #include "pcap/sll.h" #include "pcap/ipnet.h" #include "arcnet.h" -#if defined(PF_PACKET) && defined(SO_ATTACH_FILTER) + +#include "grammar.h" +#include "scanner.h" + +#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) #include #include #include #endif + #ifdef HAVE_NET_PFVAR_H #include #include #include #include #endif + #ifndef offsetof #define offsetof(s, e) ((size_t)&((s *)0)->e) #endif + #ifdef INET6 -#ifndef WIN32 +#ifdef _WIN32 +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_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_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_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) */ +#else /* _WIN32 */ #include /* for "struct addrinfo" */ -#endif /* WIN32 */ -#endif /*INET6*/ +#endif /* _WIN32 */ +#endif /* INET6 */ #include +#include "nametoaddr.h" + #define ETHERMTU 1500 +#ifndef ETHERTYPE_TEB +#define ETHERTYPE_TEB 0x6558 +#endif + #ifndef IPPROTO_HOPOPTS #define IPPROTO_HOPOPTS 0 #endif @@ -123,76 +169,75 @@ static const char rcsid[] _U_ = #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) -/* Locals */ -static jmp_buf top_ctx; -static pcap_t *bpf_pcap; - -/* Hack for updating VLAN, MPLS, and PPPoE offsets. */ -#ifdef WIN32 -static u_int orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1; -#else -static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U; -#endif - -/* XXX */ -#ifdef PCAP_FDDIPAD -static int pcap_fddipad; -#endif - -/* VARARGS */ -void -bpf_error(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (bpf_pcap != NULL) - (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, - fmt, ap); - va_end(ap); - longjmp(top_ctx, 1); - /* NOTREACHED */ +/* + * "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; \ } -static void init_linktype(pcap_t *); - -static void init_regs(void); -static int alloc_reg(void); -static void free_reg(int); +/* + * Offset "not set" value. + */ +#define OFFSET_NOT_SET 0xffffffffU -static struct block *root; +/* + * 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. + * is relative to the beginning of. */ enum e_offrel { - OR_PACKET, /* relative to the beginning of the packet */ - OR_LINK, /* relative to the beginning of the link-layer header */ - OR_MACPL, /* relative to the end of the MAC-layer header */ - OR_NET, /* relative to the network-layer header */ - OR_NET_NOSNAP, /* relative to the network-layer header, with no SNAP header at the link layer */ - OR_TRAN_IPV4, /* relative to the transport-layer header, with IPv4 network layer */ - OR_TRAN_IPV6 /* relative to the transport-layer header, with IPv6 network layer */ + 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 */ }; -#ifdef INET6 -/* - * 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. - */ -static struct addrinfo *ai; -#endif - /* * 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 @@ -204,100 +249,324 @@ static struct addrinfo *ai; #define NCHUNKS 16 #define CHUNK0SIZE 1024 struct chunk { - u_int n_left; + size_t n_left; void *m; }; -static struct chunk chunks[NCHUNKS]; -static int cur_chunk; +/* Code generator state */ + +struct _compiler_state { + jmp_buf top_ctx; + pcap_t *bpf_pcap; + + struct icode ic; + + int snaplen; + + int linktype; + int prevlinktype; + int outermostlinktype; + + bpf_u_int32 netmask; + int no_optimize; -static void *newchunk(u_int); -static void freechunks(void); -static inline struct block *new_block(int); -static inline struct slist *new_stmt(int); -static struct block *gen_retblk(int); -static inline void syntax(void); + /* Hack for handling VLAN and MPLS stacks. */ + u_int label_stack_depth; + u_int vlan_stack_depth; + + /* XXX */ + u_int pcap_fddipad; + +#ifdef INET6 + /* + * 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; +#endif + + /* + * 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; + + /* + * 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; +}; + +void +bpf_syntax_error(compiler_state_t *cstate, const char *msg) +{ + bpf_error(cstate, "syntax error in filter expression: %s", msg); + /* NOTREACHED */ +} + +/* VARARGS */ +void +bpf_error(compiler_state_t *cstate, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (cstate->bpf_pcap != NULL) + (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap), + PCAP_ERRBUF_SIZE, fmt, ap); + va_end(ap); + longjmp(cstate->top_ctx, 1); + /* NOTREACHED */ +} + +static void 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(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(enum e_offrel, u_int, u_int, bpf_int32); -static struct block *gen_cmp_gt(enum e_offrel, u_int, u_int, bpf_int32); -static struct block *gen_cmp_ge(enum e_offrel, u_int, u_int, bpf_int32); -static struct block *gen_cmp_lt(enum e_offrel, u_int, u_int, bpf_int32); -static struct block *gen_cmp_le(enum e_offrel, u_int, u_int, bpf_int32); -static struct block *gen_mcmp(enum e_offrel, u_int, u_int, bpf_int32, - bpf_u_int32); -static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *); -static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32, - bpf_u_int32, bpf_u_int32, int, bpf_int32); -static struct slist *gen_load_llrel(u_int, u_int); -static struct slist *gen_load_macplrel(u_int, u_int); -static struct slist *gen_load_a(enum e_offrel, u_int, u_int); -static struct slist *gen_loadx_iphdrlen(void); -static struct block *gen_uncond(int); -static inline struct block *gen_true(void); -static inline struct block *gen_false(void); -static struct block *gen_ether_linktype(int); -static struct block *gen_ipnet_linktype(int); -static struct block *gen_linux_sll_linktype(int); -static struct slist *gen_load_prism_llprefixlen(void); -static struct slist *gen_load_avs_llprefixlen(void); -static struct slist *gen_load_radiotap_llprefixlen(void); -static struct slist *gen_load_ppi_llprefixlen(void); -static void insert_compute_vloffsets(struct block *); -static struct slist *gen_llprefixlen(void); -static struct slist *gen_off_macpl(void); +static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_int32); +static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_int32); +static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_int32); +static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_int32); +static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_int32); +static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_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, bpf_u_int32, + bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_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 *, int); +static struct block *gen_ipnet_linktype(compiler_state_t *, int); +static struct block *gen_linux_sll_linktype(compiler_state_t *, int); +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 int ethertype_to_ppptype(int); -static struct block *gen_linktype(int); -static struct block *gen_snap(bpf_u_int32, bpf_u_int32); -static struct block *gen_llc_linktype(int); -static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); +static struct block *gen_linktype(compiler_state_t *, int); +static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32); +static struct block *gen_llc_linktype(compiler_state_t *, int); +static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32, + int, int, u_int, u_int); #ifdef INET6 -static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); +static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *, + struct in6_addr *, int, int, u_int, u_int); #endif -static struct block *gen_ahostop(const u_char *, int); -static struct block *gen_ehostop(const u_char *, int); -static struct block *gen_fhostop(const u_char *, int); -static struct block *gen_thostop(const u_char *, int); -static struct block *gen_wlanhostop(const u_char *, int); -static struct block *gen_ipfchostop(const u_char *, int); -static struct block *gen_dnhostop(bpf_u_int32, int); -static struct block *gen_mpls_linktype(int); -static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int); +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 *, int); +static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32, + int, int, int); #ifdef INET6 -static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int); +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(const u_char *, bpf_u_int32 **, int, int); #endif -static struct block *gen_ipfrag(void); -static struct block *gen_portatom(int, bpf_int32); -static struct block *gen_portrangeatom(int, bpf_int32, bpf_int32); -static struct block *gen_portatom6(int, bpf_int32); -static struct block *gen_portrangeatom6(int, bpf_int32, bpf_int32); -struct block *gen_portop(int, int, int); -static struct block *gen_port(int, int, int); -struct block *gen_portrangeop(int, int, int, int); -static struct block *gen_portrange(int, int, int, int); -struct block *gen_portop6(int, int, int); -static struct block *gen_port6(int, int, int); -struct block *gen_portrangeop6(int, int, int, int); -static struct block *gen_portrange6(int, int, int, int); -static int lookup_proto(const char *, int); -static struct block *gen_protochain(int, int, int); -static struct block *gen_proto(int, int, int); -static struct slist *xfer_to_x(struct arth *); -static struct slist *xfer_to_a(struct arth *); -static struct block *gen_mac_multicast(int); -static struct block *gen_len(int, int); -static struct block *gen_check_802_11_data_frame(void); - -static struct block *gen_ppi_dlt_check(void); -static struct block *gen_msg_abbrev(int type); +static struct block *gen_ipfrag(compiler_state_t *); +static struct block *gen_portatom(compiler_state_t *, int, bpf_int32); +static struct block *gen_portrangeatom(compiler_state_t *, int, bpf_int32, + bpf_int32); +static struct block *gen_portatom6(compiler_state_t *, int, bpf_int32); +static struct block *gen_portrangeatom6(compiler_state_t *, int, bpf_int32, + bpf_int32); +struct block *gen_portop(compiler_state_t *, int, int, int); +static struct block *gen_port(compiler_state_t *, int, int, int); +struct block *gen_portrangeop(compiler_state_t *, int, int, int, int); +static struct block *gen_portrange(compiler_state_t *, int, int, int, int); +struct block *gen_portop6(compiler_state_t *, int, int, int); +static struct block *gen_port6(compiler_state_t *, int, int, int); +struct block *gen_portrangeop6(compiler_state_t *, int, int, int, int); +static struct block *gen_portrange6(compiler_state_t *, int, int, int, int); +static int lookup_proto(compiler_state_t *, const char *, int); +static struct block *gen_protochain(compiler_state_t *, int, int, int); +static struct block *gen_proto(compiler_state_t *, int, 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_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(n) - u_int n; +newchunk(compiler_state_t *cstate, size_t n) { struct chunk *cp; int k; @@ -311,58 +580,53 @@ newchunk(n) n = ALIGN(n); #endif - cp = &chunks[cur_chunk]; + cp = &cstate->chunks[cstate->cur_chunk]; if (n > cp->n_left) { - ++cp, k = ++cur_chunk; + ++cp, k = ++cstate->cur_chunk; if (k >= NCHUNKS) - bpf_error("out of memory"); + bpf_error(cstate, "out of memory"); size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); if (cp->m == NULL) - bpf_error("out of memory"); + bpf_error(cstate, "out of memory"); memset((char *)cp->m, 0, size); cp->n_left = size; if (n > size) - bpf_error("out of memory"); + bpf_error(cstate, "out of memory"); } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left); } static void -freechunks() +freechunks(compiler_state_t *cstate) { int i; - cur_chunk = 0; for (i = 0; i < NCHUNKS; ++i) - if (chunks[i].m != NULL) { - free(chunks[i].m); - chunks[i].m = NULL; - } + if (cstate->chunks[i].m != NULL) + free(cstate->chunks[i].m); } /* * A strdup whose allocations are freed after code generation is over. */ char * -sdup(s) - register const char *s; +sdup(compiler_state_t *cstate, const char *s) { - int n = strlen(s) + 1; - char *cp = newchunk(n); + size_t n = strlen(s) + 1; + char *cp = newchunk(cstate, n); strlcpy(cp, s, n); return (cp); } static inline struct block * -new_block(code) - int code; +new_block(compiler_state_t *cstate, int code) { struct block *p; - p = (struct block *)newchunk(sizeof(*p)); + p = (struct block *)newchunk(cstate, sizeof(*p)); p->s.code = code; p->head = p; @@ -370,126 +634,129 @@ new_block(code) } static inline struct slist * -new_stmt(code) - int code; +new_stmt(compiler_state_t *cstate, int code) { struct slist *p; - p = (struct slist *)newchunk(sizeof(*p)); + p = (struct slist *)newchunk(cstate, sizeof(*p)); p->s.code = code; return p; } static struct block * -gen_retblk(v) - int v; +gen_retblk(compiler_state_t *cstate, int v) { - struct block *b = new_block(BPF_RET|BPF_K); + struct block *b = new_block(cstate, BPF_RET|BPF_K); b->s.k = v; return b; } static inline void -syntax() -{ - bpf_error("syntax error in filter expression"); -} - -static bpf_u_int32 netmask; -static int snaplen; -int no_optimize; -#ifdef WIN32 -static int -pcap_compile_unsafe(pcap_t *p, struct bpf_program *program, - const char *buf, int optimize, bpf_u_int32 mask); - -int -pcap_compile(pcap_t *p, struct bpf_program *program, - const char *buf, int optimize, bpf_u_int32 mask) +syntax(compiler_state_t *cstate) { - int result; - - EnterCriticalSection(&g_PcapCompileCriticalSection); - - result = pcap_compile_unsafe(p, program, buf, optimize, mask); - - LeaveCriticalSection(&g_PcapCompileCriticalSection); - - return result; + bpf_error(cstate, "syntax error in filter expression"); } -static int -pcap_compile_unsafe(pcap_t *p, struct bpf_program *program, - const char *buf, int optimize, bpf_u_int32 mask) -#else /* WIN32 */ int pcap_compile(pcap_t *p, struct bpf_program *program, const char *buf, int optimize, bpf_u_int32 mask) -#endif /* WIN32 */ { - extern int n_errors; + compiler_state_t cstate; const char * volatile xbuf = buf; + yyscan_t scanner = NULL; + YY_BUFFER_STATE in_buffer = NULL; u_int len; + int rc; + +#ifdef _WIN32 + static int done = 0; + + if (!done) + pcap_wsockinit(); + done = 1; +#endif /* * 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, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "not-yet-activated pcap_t passed to pcap_compile"); - return (-1); + rc = -1; + goto quit; } - no_optimize = 0; - n_errors = 0; - root = NULL; - bpf_pcap = p; - init_regs(); - if (setjmp(top_ctx)) { + initchunks(&cstate); + cstate.no_optimize = 0; + cstate.ai = NULL; + cstate.ic.root = NULL; + cstate.ic.cur_mark = 0; + cstate.bpf_pcap = p; + init_regs(&cstate); + + if (setjmp(cstate.top_ctx)) { #ifdef INET6 - if (ai != NULL) { - freeaddrinfo(ai); - ai = NULL; - } + if (cstate.ai != NULL) + freeaddrinfo(cstate.ai); #endif - lex_cleanup(); - freechunks(); - return (-1); + rc = -1; + goto quit; } - netmask = mask; + cstate.netmask = mask; - snaplen = pcap_snapshot(p); - if (snaplen == 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + cstate.snaplen = pcap_snapshot(p); + if (cstate.snaplen == 0) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snaplen of 0 rejects all packets"); - return -1; + rc = -1; + goto quit; } - lex_init(xbuf ? xbuf : ""); - init_linktype(p); - (void)pcap_parse(); + if (pcap_lex_init(&scanner) != 0) + bpf_error(&cstate, "can't initialize scanner: %s", pcap_strerror(errno)); + in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); + + /* + * Associate the compiler state with the lexical analyzer + * state. + */ + pcap_set_extra(&cstate, scanner); - if (n_errors) - syntax(); + init_linktype(&cstate, p); + (void)pcap_parse(scanner, &cstate); - if (root == NULL) - root = gen_retblk(snaplen); + if (cstate.ic.root == NULL) + cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); - if (optimize && !no_optimize) { - bpf_optimize(&root); - if (root == NULL || - (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) - bpf_error("expression rejects all packets"); + if (optimize && !cstate.no_optimize) { + bpf_optimize(&cstate, &cstate.ic); + if (cstate.ic.root == NULL || + (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) + bpf_error(&cstate, "expression rejects all packets"); } - program->bf_insns = icode_to_fcode(root, &len); + program->bf_insns = icode_to_fcode(&cstate, &cstate.ic, cstate.ic.root, &len); program->bf_len = len; - lex_cleanup(); - freechunks(); - return (0); + 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); } /* @@ -569,8 +836,7 @@ merge(b0, b1) } void -finish_parse(p) - struct block *p; +finish_parse(compiler_state_t *cstate, struct block *p) { struct block *ppi_dlt_check; @@ -593,20 +859,29 @@ finish_parse(p) * for tests that fail early, and it's not clear that's * worth the effort. */ - insert_compute_vloffsets(p->head); - + 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(); + ppi_dlt_check = gen_ppi_dlt_check(cstate); if (ppi_dlt_check != NULL) gen_and(ppi_dlt_check, p); - backpatch(p, gen_retblk(snaplen)); + backpatch(p, gen_retblk(cstate, cstate->snaplen)); p->sense = !p->sense; - backpatch(p, gen_retblk(0)); - root = p->head; + backpatch(p, gen_retblk(cstate, 0)); + cstate->ic.root = p->head; } void @@ -640,65 +915,50 @@ gen_not(b) } static struct block * -gen_cmp(offrel, offset, size, v) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; +gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v) { - return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); } static struct block * -gen_cmp_gt(offrel, offset, size, v) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; +gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v) { - return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); } static struct block * -gen_cmp_ge(offrel, offset, size, v) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; +gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v) { - return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); } static struct block * -gen_cmp_lt(offrel, offset, size, v) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; +gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v) { - return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); } static struct block * -gen_cmp_le(offrel, offset, size, v) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; +gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v) { - return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); } static struct block * -gen_mcmp(offrel, offset, size, v, mask) - enum e_offrel offrel; - u_int offset, size; - bpf_int32 v; - bpf_u_int32 mask; +gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_int32 v, bpf_u_int32 mask) { - return gen_ncmp(offrel, offset, size, mask, BPF_JEQ, 0, v); + return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v); } static struct block * -gen_bcmp(offrel, offset, size, v) - enum e_offrel offrel; - register u_int offset, size; - register const u_char *v; +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; @@ -708,7 +968,7 @@ gen_bcmp(offrel, offset, size, v) bpf_int32 w = ((bpf_int32)p[0] << 24) | ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; - tmp = gen_cmp(offrel, offset + size - 4, BPF_W, w); + tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, w); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -718,14 +978,14 @@ gen_bcmp(offrel, offset, size, v) register const u_char *p = &v[size - 2]; bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; - tmp = gen_cmp(offrel, offset + size - 2, BPF_H, w); + tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, w); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 2; } if (size > 0) { - tmp = gen_cmp(offrel, offset, BPF_B, (bpf_int32)v[0]); + tmp = gen_cmp(cstate, offrel, offset, BPF_B, (bpf_int32)v[0]); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -740,24 +1000,22 @@ gen_bcmp(offrel, offset, size, v) * should test the opposite of "jtype". */ static struct block * -gen_ncmp(offrel, offset, size, mask, jtype, reverse, v) - enum e_offrel offrel; - bpf_int32 v; - bpf_u_int32 offset, size, mask, jtype; - int reverse; +gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset, + bpf_u_int32 size, bpf_u_int32 mask, bpf_u_int32 jtype, int reverse, + bpf_int32 v) { struct slist *s, *s2; struct block *b; - s = gen_load_a(offrel, offset, size); + s = gen_load_a(cstate, offrel, offset, size); if (mask != 0xffffffff) { - s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = mask; sappend(s, s2); } - b = new_block(JMP(jtype)); + b = new_block(cstate, JMP(jtype)); b->stmts = s; b->s.k = v; if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) @@ -765,294 +1023,152 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v) return b; } -/* - * Various code constructs need to know the layout of the data link - * layer. These variables give the necessary offsets from the beginning - * of the packet data. - */ - -/* - * This is the offset of the beginning of the link-layer header from - * the beginning of the raw packet data. - * - * It's usually 0, except for 802.11 with a fixed-length radio header. - * (For 802.11 with a variable-length radio header, we have to generate - * code to compute that offset; off_ll is 0 in that case.) - */ -static u_int off_ll; - -/* - * If there's a variable-length header preceding the link-layer header, - * "reg_off_ll" is the register number for a register containing the - * length of that header, and therefore the offset of the link-layer - * header from the beginning of the raw packet data. Otherwise, - * "reg_off_ll" is -1. - */ -static int reg_off_ll; - -/* - * This is the offset of the beginning of the MAC-layer header from - * the beginning of the link-layer header. - * It's usually 0, except for ATM LANE, where it's the offset, relative - * to the beginning of the raw packet data, of the Ethernet header, and - * for Ethernet with various additional information. - */ -static u_int off_mac; - -/* - * This is the offset of the beginning of the MAC-layer payload, - * from the beginning of the raw packet data. - * - * I.e., it's the sum of the length of the link-layer header (without, - * for example, any 802.2 LLC header, so it's the MAC-layer - * portion of that header), plus any prefix preceding the - * link-layer header. - */ -static u_int off_macpl; - -/* - * This is 1 if the offset of the beginning of the MAC-layer payload - * from the beginning of the link-layer header is variable-length. - */ -static int off_macpl_is_variable; - -/* - * If the link layer has variable_length headers, "reg_off_macpl" - * is the register number for a register containing the length of the - * link-layer header plus the length of any variable-length header - * preceding the link-layer header. Otherwise, "reg_off_macpl" - * is -1. - */ -static int reg_off_macpl; - -/* - * "off_linktype" is the offset to information in the link-layer header - * giving the packet type. This offset is relative to the beginning - * of the link-layer header (i.e., it doesn't include off_ll). - * - * For Ethernet, it's the offset of the Ethernet type field. - * - * For link-layer types that always use 802.2 headers, it's the - * offset of the LLC header. - * - * 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. - * - * It's set to -1 for no encapsulation, in which case, IP is assumed. - */ -static u_int off_linktype; - -/* - * TRUE if "pppoes" appeared in the filter; it causes link-layer type - * checks to check the PPP header, assumed to follow a LAN-style link- - * layer header and a PPPoE session header. - */ -static int is_pppoes = 0; - -/* - * TRUE if the link layer includes an ATM pseudo-header. - */ -static int is_atm = 0; - -/* - * TRUE if "lane" appeared in the filter; it causes us to generate - * code that assumes LANE rather than LLC-encapsulated traffic in SunATM. - */ -static int is_lane = 0; - -/* - * These are offsets for the ATM pseudo-header. - */ -static u_int off_vpi; -static u_int off_vci; -static u_int off_proto; - -/* - * These are offsets for the MTP2 fields. - */ -static u_int off_li; +static void +init_linktype(compiler_state_t *cstate, pcap_t *p) +{ + cstate->pcap_fddipad = p->fddipad; -/* - * These are offsets for the MTP3 fields. - */ -static u_int off_sio; -static u_int off_opc; -static u_int off_dpc; -static u_int off_sls; + /* + * 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; -/* - * This is the offset of the first byte after the ATM pseudo_header, - * or -1 if there is no ATM pseudo-header. - */ -static u_int off_payload; + cstate->prevlinktype = cstate->outermostlinktype; + cstate->off_prevlinkhdr.constant_part = 0; + cstate->off_prevlinkhdr.is_variable = 0; + cstate->off_prevlinkhdr.reg = -1; -/* - * These are offsets to the beginning of the network-layer header. - * They are relative to the beginning of the MAC-layer payload (i.e., - * they don't include off_ll or off_macpl). - * - * 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. - */ -static u_int off_nl; -static u_int off_nl_nosnap; + cstate->linktype = cstate->outermostlinktype; + cstate->off_linkhdr.constant_part = 0; + cstate->off_linkhdr.is_variable = 0; + cstate->off_linkhdr.reg = -1; -static int linktype; + /* + * XXX + */ + cstate->off_linkpl.constant_part = 0; + cstate->off_linkpl.is_variable = 0; + cstate->off_linkpl.reg = -1; -static void -init_linktype(p) - pcap_t *p; -{ - linktype = pcap_datalink(p); -#ifdef PCAP_FDDIPAD - pcap_fddipad = p->fddipad; -#endif + 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. */ - off_mac = 0; - is_atm = 0; - is_lane = 0; - off_vpi = -1; - off_vci = -1; - off_proto = -1; - off_payload = -1; + cstate->is_atm = 0; + cstate->off_vpi = -1; + cstate->off_vci = -1; + cstate->off_proto = -1; + cstate->off_payload = -1; /* - * And that we're not doing PPPoE. + * And not Geneve. */ - is_pppoes = 0; + cstate->is_geneve = 0; /* * And assume we're not doing SS7. */ - off_li = -1; - off_sio = -1; - off_opc = -1; - off_dpc = -1; - off_sls = -1; - - /* - * Also assume it's not 802.11. - */ - off_ll = 0; - off_macpl = 0; - off_macpl_is_variable = 0; + cstate->off_li = -1; + cstate->off_li_hsl = -1; + cstate->off_sio = -1; + cstate->off_opc = -1; + cstate->off_dpc = -1; + cstate->off_sls = -1; - orig_linktype = -1; - orig_nl = -1; - label_stack_depth = 0; + cstate->label_stack_depth = 0; + cstate->vlan_stack_depth = 0; - reg_off_ll = -1; - reg_off_macpl = -1; - - switch (linktype) { + switch (cstate->linktype) { case DLT_ARCNET: - off_linktype = 2; - off_macpl = 6; - off_nl = 0; /* XXX in reality, variable! */ - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 4; - off_macpl = 8; - off_nl = 0; /* XXX in reality, variable! */ - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 12; - off_macpl = 14; /* Ethernet header length */ - off_nl = 0; /* Ethernet II */ - off_nl_nosnap = 3; /* 802.3+802.2 */ - return; + 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. */ - off_linktype = -1; - off_macpl = 16; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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 */ - off_linktype = -1; + cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* XXX end */ - off_macpl = 24; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 0; - off_macpl = 4; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 0; - off_macpl = 12; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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_PPP_SERIAL: /* NetBSD sync/async serial PPP */ - off_linktype = 2; - off_macpl = 4; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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. */ - off_linktype = 6; - off_macpl = 8; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 5; - off_macpl = 24; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: /* @@ -1063,17 +1179,13 @@ init_linktype(p) * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? */ - off_linktype = 13; -#ifdef PCAP_FDDIPAD - off_linktype += pcap_fddipad; -#endif - off_macpl = 13; /* FDDI MAC header length */ -#ifdef PCAP_FDDIPAD - off_macpl += pcap_fddipad; -#endif - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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: /* @@ -1099,19 +1211,24 @@ init_linktype(p) * the 16-bit value at an offset of 14 (shifted right * 8 - figure out which byte that is). */ - off_linktype = 14; - off_macpl = 14; /* Token Ring MAC header length */ - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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_IEEE802_11: 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. */ + + case DLT_IEEE802_11: /* * 802.11 doesn't really have a link-level type field. - * We set "off_linktype" to the offset of the LLC header. + * 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. @@ -1126,15 +1243,15 @@ init_linktype(p) * header or an AVS header, so, in practice, it's * variable-length. */ - off_linktype = 24; - off_macpl = 0; /* link-layer header is variable-length */ - off_macpl_is_variable = 1; - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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 @@ -1143,12 +1260,13 @@ init_linktype(p) * the encapsulated DLT should be DLT_IEEE802_11) we * generate code to check for this too. */ - off_linktype = 24; - off_macpl = 0; /* link-layer header is variable-length */ - off_macpl_is_variable = 1; - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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 */ @@ -1163,44 +1281,43 @@ init_linktype(p) * or "pppoa and tcp port 80" and have it check for * PPPo{A,E} and a PPP protocol of IP and.... */ - off_linktype = 0; - off_macpl = 0; /* packet begins with LLC header */ - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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. */ - is_atm = 1; - off_vpi = SUNATM_VPI_POS; - off_vci = SUNATM_VCI_POS; - off_proto = PROTO_POS; - off_mac = -1; /* assume LLC-encapsulated, so no MAC-layer header */ - off_payload = SUNATM_PKT_BEGIN_POS; - off_linktype = off_payload; - off_macpl = off_payload; /* if LLC-encapsulated */ - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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: - off_linktype = -1; - off_macpl = 0; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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 */ - off_linktype = 14; - off_macpl = 16; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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_LTALK: /* @@ -1208,11 +1325,11 @@ init_linktype(p) * but really it just indicates whether there is a "short" or * "long" DDP packet following. */ - off_linktype = -1; - off_macpl = 0; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: /* @@ -1225,22 +1342,22 @@ init_linktype(p) * XXX - should we generate code to check for SNAP? RFC * 2625 says SNAP should be used. */ - off_linktype = 16; - off_macpl = 16; - off_nl = 8; /* 802.2+SNAP */ - off_nl_nosnap = 3; /* 802.2 */ - return; + 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). */ - off_linktype = -1; - off_macpl = 0; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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; @@ -1248,33 +1365,33 @@ init_linktype(p) * so lets start with offset 4 for now and increments later on (FIXME); */ case DLT_MFR: - off_linktype = -1; - off_macpl = 0; - off_nl = 4; - off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ - return; + 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: - off_linktype = 16; - off_macpl = 18; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + 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: - off_linktype = 6; - off_macpl = 44; - off_nl = 0; /* Ethernet II */ - off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ - return; + 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; #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: - off_linktype = 0; - off_macpl = PFLOG_HDRLEN; - off_nl = 0; - off_nl_nosnap = 0; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = PFLOG_HDRLEN; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; #endif case DLT_JUNIPER_MFR: @@ -1283,279 +1400,244 @@ init_linktype(p) case DLT_JUNIPER_PPP: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_FRELAY: - off_linktype = 4; - off_macpl = 4; - off_nl = 0; - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 4; + cstate->off_linkpl.constant_part = 4; + cstate->off_nl = 0; + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_JUNIPER_ATM1: - off_linktype = 4; /* in reality variable between 4-8 */ - off_macpl = 4; /* in reality variable between 4-8 */ - off_nl = 0; - off_nl_nosnap = 10; - return; + 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: - off_linktype = 8; /* in reality variable between 8-12 */ - off_macpl = 8; /* in reality variable between 8-12 */ - off_nl = 0; - off_nl_nosnap = 10; - return; + 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: - off_macpl = 14; - off_linktype = 16; - off_nl = 18; /* Ethernet II */ - off_nl_nosnap = 21; /* 802.3+802.2 */ - return; + 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: - off_linktype = 4; - off_macpl = 6; - off_nl = 0; - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 4; + cstate->off_linkpl.constant_part = 6; + cstate->off_nl = 0; + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_JUNIPER_GGSN: - off_linktype = 6; - off_macpl = 12; - off_nl = 0; - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 6; + cstate->off_linkpl.constant_part = 12; + cstate->off_nl = 0; + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_JUNIPER_ES: - off_linktype = 6; - off_macpl = -1; /* not really a network layer but raw IP addresses */ - off_nl = -1; /* not really a network layer but raw IP addresses */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + 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 = -1; /* not really a network layer but raw IP addresses */ + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_JUNIPER_MONITOR: - off_linktype = 12; - off_macpl = 12; - off_nl = 0; /* raw IP/IP6 header */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 12; + cstate->off_linkpl.constant_part = 12; + cstate->off_nl = 0; /* raw IP/IP6 header */ + cstate->off_nl_nosnap = -1; /* 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 = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_JUNIPER_SERVICES: - off_linktype = 12; - off_macpl = -1; /* L3 proto location dep. on cookie type */ - off_nl = -1; /* L3 proto location dep. on cookie type */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + cstate->off_linktype.constant_part = 12; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ + cstate->off_nl = -1; /* L3 proto location dep. on cookie type */ + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_JUNIPER_VP: - off_linktype = 18; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + cstate->off_linktype.constant_part = 18; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_JUNIPER_ST: - off_linktype = 18; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + cstate->off_linktype.constant_part = 18; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_JUNIPER_ISM: - off_linktype = 8; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + cstate->off_linktype.constant_part = 8; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_JUNIPER_VS: case DLT_JUNIPER_SRX_E2E: case DLT_JUNIPER_FIBRECHANNEL: case DLT_JUNIPER_ATM_CEMIC: - off_linktype = 8; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + cstate->off_linktype.constant_part = 8; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_MTP2: - off_li = 2; - off_sio = 3; - off_opc = 4; - off_dpc = 4; - off_sls = 7; - off_linktype = -1; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + 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 = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_MTP2_WITH_PHDR: - off_li = 6; - off_sio = 7; - off_opc = 8; - off_dpc = 8; - off_sls = 11; - off_linktype = -1; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + 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 = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_ERF: - off_li = 22; - off_sio = 23; - off_opc = 24; - off_dpc = 24; - off_sls = 27; - off_linktype = -1; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + 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 = -1; + cstate->off_nl_nosnap = -1; + break; case DLT_PFSYNC: - off_linktype = -1; - off_macpl = 4; - off_nl = 0; - off_nl_nosnap = 0; - return; + 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. */ - off_linktype = -1; /* variable, min 15, max 71 steps of 7 */ - off_macpl = -1; - off_nl = -1; /* variable, min 16, max 71 steps of 7 */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - off_mac = 1; /* step over the kiss length byte */ - return; + 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 = -1; /* variable, min 16, max 71 steps of 7 */ + cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + break; case DLT_IPNET: - off_linktype = 1; - off_macpl = 24; /* ipnet header length */ - off_nl = 0; - off_nl_nosnap = -1; - return; + cstate->off_linktype.constant_part = 1; + cstate->off_linkpl.constant_part = 24; /* ipnet header length */ + cstate->off_nl = 0; + cstate->off_nl_nosnap = -1; + break; case DLT_NETANALYZER: - off_mac = 4; /* MAC header is past 4-byte pseudo-header */ - off_linktype = 16; /* includes 4-byte pseudo-header */ - off_macpl = 18; /* pseudo-header+Ethernet header length */ - off_nl = 0; /* Ethernet II */ - off_nl_nosnap = 3; /* 802.3+802.2 */ - return; + 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: - off_mac = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */ - off_linktype = 24; /* includes 4-byte pseudo-header+preamble+SFD */ - off_macpl = 26; /* pseudo-header+preamble+SFD+Ethernet header length */ - off_nl = 0; /* Ethernet II */ - off_nl_nosnap = 3; /* 802.3+802.2 */ - return; + 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 (linktype >= DLT_MATCHING_MIN && - linktype <= DLT_MATCHING_MAX) { - off_linktype = -1; - off_macpl = -1; - off_nl = -1; - off_nl_nosnap = -1; - return; + 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 = -1; + cstate->off_nl_nosnap = -1; + } else { + bpf_error(cstate, "unknown data link type %d", cstate->linktype); } - + break; } - bpf_error("unknown data link type %d", linktype); - /* NOTREACHED */ -} -/* - * Load a value relative to the beginning of the link-layer header. - * 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_llrel(offset, size) - u_int offset, size; -{ - struct slist *s, *s2; - - s = gen_llprefixlen(); - - /* - * 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_ll". - */ - if (s != NULL) { - /* - * There's a variable-length prefix preceding the - * link-layer header. "s" points to a list of statements - * that put the length of that prefix into the X register. - * do an indirect load, to use the X register as an offset. - */ - s2 = new_stmt(BPF_LD|BPF_IND|size); - s2->s.k = offset; - sappend(s, s2); - } else { - /* - * There is no variable-length header preceding the - * link-layer header; add in off_ll, which, if there's - * a fixed-length header preceding the link-layer header, - * is the length of that header. - */ - s = new_stmt(BPF_LD|BPF_ABS|size); - s->s.k = offset + off_ll; - } - return s; + cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr; } /* - * Load a value relative to the beginning of the MAC-layer payload. + * Load a value relative to the specified absolute offset. */ static struct slist * -gen_load_macplrel(offset, size) - u_int offset, size; +gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset, + u_int offset, u_int size) { struct slist *s, *s2; - s = gen_off_macpl(); + s = gen_abs_offset_varpart(cstate, abs_offset); /* - * If s is non-null, the offset of the MAC-layer payload is - * variable, and s points to a list of instructions that - * arrange that the X register contains that 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, the offset of the MAC-layer payload is constant, - * and is in off_macpl. + * Otherwise, we can do an absolute load with an offset of + * abs_offset->constant_part + offset. */ if (s != NULL) { /* - * The offset of the MAC-layer payload is in the X - * register. Do an indirect load, to use the X register - * as an offset. + * "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(BPF_LD|BPF_IND|size); - s2->s.k = offset; + s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); + s2->s.k = abs_offset->constant_part + offset; sappend(s, s2); } else { /* - * The offset of the MAC-layer payload is constant, - * and is in off_macpl; load the value at that offset - * plus the specified offset. + * There is no variable part of the absolute offset, so + * just do an absolute load. */ - s = new_stmt(BPF_LD|BPF_ABS|size); - s->s.k = off_macpl + offset; + s = new_stmt(cstate, BPF_LD|BPF_ABS|size); + s->s.k = abs_offset->constant_part + offset; } return s; } @@ -1564,33 +1646,44 @@ gen_load_macplrel(offset, size) * Load a value relative to the beginning of the specified header. */ static struct slist * -gen_load_a(offrel, offset, size) - enum e_offrel offrel; - u_int offset, size; +gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size) { struct slist *s, *s2; switch (offrel) { case OR_PACKET: - s = new_stmt(BPF_LD|BPF_ABS|size); + s = new_stmt(cstate, BPF_LD|BPF_ABS|size); s->s.k = offset; break; - case OR_LINK: - s = gen_load_llrel(offset, size); + case OR_LINKHDR: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size); break; - case OR_MACPL: - s = gen_load_macplrel(offset, size); + case OR_PREVLINKHDR: + s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size); break; - case OR_NET: - s = gen_load_macplrel(off_nl + offset, size); + case OR_LLC: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size); break; - case OR_NET_NOSNAP: - s = gen_load_macplrel(off_nl_nosnap + offset, size); + 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: @@ -1600,25 +1693,26 @@ gen_load_a(offrel, offset, size) * preceded by a variable-length header such as a radio * header), in bytes. */ - s = gen_loadx_iphdrlen(); + s = gen_loadx_iphdrlen(cstate); /* - * Load the item at {offset of the MAC-layer payload} + - * {offset, relative to the start of the MAC-layer + * 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 MAC-layer payload is variable, - * it's included in the value in the X register, and - * off_macpl is 0.) + * 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(BPF_LD|BPF_IND|size); - s2->s.k = off_macpl + off_nl + offset; + 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_macplrel(off_nl + 40 + offset, size); + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size); break; default: @@ -1630,87 +1724,87 @@ gen_load_a(offrel, offset, size) /* * Generate code to load into the X register the sum of the length of - * the IPv4 header and any variable-length header preceding the link-layer - * header. + * the IPv4 header and the variable part of the offset of the link-layer + * payload. */ static struct slist * -gen_loadx_iphdrlen() +gen_loadx_iphdrlen(compiler_state_t *cstate) { struct slist *s, *s2; - s = gen_off_macpl(); + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); if (s != NULL) { /* - * There's a variable-length prefix preceding the - * link-layer header, or the link-layer header is itself - * variable-length. "s" points to a list of statements - * that put the offset of the MAC-layer payload into - * the X register. + * 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(BPF_LD|BPF_IND|BPF_B); - s2->s.k = off_nl; + 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(BPF_ALU|BPF_AND|BPF_K); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xf; sappend(s, s2); - s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + 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 offset of - * the MAC-layer payload, which is still in the X + * 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(BPF_ALU|BPF_ADD|BPF_X)); - sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); } else { /* - * There is no variable-length header preceding the - * link-layer header, and the link-layer header is - * fixed-length; load the length of the IPv4 header, - * which is at an offset of off_nl from the beginning - * of the MAC-layer payload, and thus at an offset - * of off_mac_pl + off_nl from the beginning of the - * raw packet data. - */ - s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); - s->s.k = off_macpl + off_nl; + * 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(rsense) - int rsense; +gen_uncond(compiler_state_t *cstate, int rsense) { struct block *b; struct slist *s; - s = new_stmt(BPF_LD|BPF_IMM); + s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = !rsense; - b = new_block(JMP(BPF_JEQ)); + b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; return b; } static inline struct block * -gen_true() +gen_true(compiler_state_t *cstate) { - return gen_uncond(1); + return gen_uncond(cstate, 1); } static inline struct block * -gen_false() +gen_false(compiler_state_t *cstate) { - return gen_uncond(0); + return gen_uncond(cstate, 0); } /* @@ -1731,8 +1825,7 @@ gen_false() * the appropriate test. */ static struct block * -gen_ether_linktype(proto) - register int proto; +gen_ether_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; @@ -1753,9 +1846,9 @@ gen_ether_linktype(proto) * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ - b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); - b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32) + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; @@ -1793,22 +1886,22 @@ gen_ether_linktype(proto) * This generates code to check both for the * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. */ - b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX); - b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)0xFFFF); + b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF); gen_or(b0, b1); /* * Now we add code to check for SNAP frames with * ETHERTYPE_IPX, i.e. Ethernet_SNAP. */ - b0 = gen_snap(0x000000, ETHERTYPE_IPX); + 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(OR_LINK, off_linktype, BPF_H, ETHERMTU); + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* @@ -1824,8 +1917,7 @@ gen_ether_linktype(proto) * do that before checking for the other frame * types. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)ETHERTYPE_IPX); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); gen_or(b0, b1); return b1; @@ -1841,7 +1933,7 @@ gen_ether_linktype(proto) * we check for an Ethernet type field less than * 1500, which means it's an 802.3 length field. */ - b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); /* @@ -1856,9 +1948,9 @@ gen_ether_linktype(proto) * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) - b1 = gen_snap(0x080007, ETHERTYPE_ATALK); + b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ - b1 = gen_snap(0x000000, ETHERTYPE_AARP); + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* @@ -1866,7 +1958,7 @@ gen_ether_linktype(proto) * phase 1?); we just check for the Ethernet * protocol type. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); gen_or(b0, b1); return b1; @@ -1881,10 +1973,9 @@ gen_ether_linktype(proto) * a length field, <= ETHERMTU) and * then check the DSAP. */ - b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); gen_not(b0); - b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B, - (bpf_int32)proto); + b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto); gen_and(b0, b1); return b1; } else { @@ -1897,29 +1988,62 @@ gen_ether_linktype(proto) * will fail and the frame won't match, * which is what we want). */ - return gen_cmp(OR_LINK, off_linktype, BPF_H, + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } } } +static struct block * +gen_loopback_linktype(compiler_state_t *cstate, int 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) + proto = SWAPLONG(proto); + proto = htonl(proto); + } + return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)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(proto) - register int proto; +gen_ipnet_linktype(compiler_state_t *cstate, int proto) { switch (proto) { case ETHERTYPE_IP: - return gen_cmp(OR_LINK, off_linktype, BPF_B, - (bpf_int32)IPH_AF_INET); + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET); /* NOTREACHED */ case ETHERTYPE_IPV6: - return gen_cmp(OR_LINK, off_linktype, BPF_B, + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET6); /* NOTREACHED */ @@ -1927,7 +2051,7 @@ gen_ipnet_linktype(proto) break; } - return gen_false(); + return gen_false(cstate); } /* @@ -1939,8 +2063,7 @@ gen_ipnet_linktype(proto) * LINUX_SLL_P_802_2 value and then do the appropriate test. */ static struct block * -gen_linux_sll_linktype(proto) - register int proto; +gen_linux_sll_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; @@ -1961,8 +2084,8 @@ gen_linux_sll_linktype(proto) * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); - b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32) + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; @@ -1993,17 +2116,17 @@ gen_linux_sll_linktype(proto) * then put a check for LINUX_SLL_P_802_2 frames * before it. */ - b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX); - b1 = gen_snap(0x000000, ETHERTYPE_IPX); + b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); gen_or(b0, b1); - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); + 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(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_3); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3); gen_or(b0, b1); /* @@ -2011,8 +2134,7 @@ gen_linux_sll_linktype(proto) * do that before checking for the other frame * types. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)ETHERTYPE_IPX); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX); gen_or(b0, b1); return b1; @@ -2028,7 +2150,7 @@ gen_linux_sll_linktype(proto) * we check for the 802.2 protocol type in the * "Ethernet type" field. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); /* * 802.2-encapsulated ETHERTYPE_ATALK packets are @@ -2042,9 +2164,9 @@ gen_linux_sll_linktype(proto) * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) - b1 = gen_snap(0x080007, ETHERTYPE_ATALK); + b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ - b1 = gen_snap(0x000000, ETHERTYPE_AARP); + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* @@ -2052,7 +2174,7 @@ gen_linux_sll_linktype(proto) * phase 1?); we just check for the Ethernet * protocol type. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); gen_or(b0, b1); return b1; @@ -2066,9 +2188,8 @@ gen_linux_sll_linktype(proto) * in the "Ethernet type" field, and * then check the DSAP. */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, - LINUX_SLL_P_802_2); - b1 = gen_cmp(OR_LINK, off_macpl, BPF_B, + 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, (bpf_int32)proto); gen_and(b0, b1); return b1; @@ -2082,14 +2203,13 @@ gen_linux_sll_linktype(proto) * will fail and the frame won't match, * which is what we want). */ - return gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)proto); + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } } } static struct slist * -gen_load_prism_llprefixlen() +gen_load_prism_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; struct slist *sjeq_avs_cookie; @@ -2100,7 +2220,7 @@ gen_load_prism_llprefixlen() * we are generating jmp instructions within a normal * slist of instructions */ - no_optimize = 1; + cstate->no_optimize = 1; /* * Generate code to load the length of the radio header into @@ -2121,24 +2241,24 @@ gen_load_prism_llprefixlen() * but no known software generates headers that aren't 144 * bytes long. */ - if (reg_off_ll != -1) { + if (cstate->off_linkhdr.reg != -1) { /* * Load the cookie. */ - s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s1->s.k = 0; /* * AND it with 0xFFFFF000. */ - s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); + 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(JMP(BPF_JEQ)); + sjeq_avs_cookie = new_stmt(cstate, JMP(BPF_JEQ)); sjeq_avs_cookie->s.k = 0x80211000; sappend(s1, sjeq_avs_cookie); @@ -2149,7 +2269,7 @@ gen_load_prism_llprefixlen() * the AVS header are the length of the AVS header. * That field is big-endian. */ - s2 = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s2->s.k = 4; sappend(s1, s2); sjeq_avs_cookie->s.jt = s2; @@ -2162,7 +2282,7 @@ gen_load_prism_llprefixlen() * it's added to the PC, so, as we're jumping * over a single instruction, it should be 1.) */ - sjcommon = new_stmt(JMP(BPF_JA)); + sjcommon = new_stmt(cstate, JMP(BPF_JA)); sjcommon->s.k = 1; sappend(s1, sjcommon); @@ -2172,7 +2292,7 @@ gen_load_prism_llprefixlen() * into the A register. Have the test for an AVS * header branch here if we don't have an AVS header. */ - s2 = new_stmt(BPF_LD|BPF_W|BPF_IMM); + s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); s2->s.k = 144; sappend(s1, s2); sjeq_avs_cookie->s.jf = s2; @@ -2182,15 +2302,15 @@ gen_load_prism_llprefixlen() * it. The code for the AVS header will jump here after * loading the length of the AVS header. */ - s2 = new_stmt(BPF_ST); - s2->s.k = reg_off_ll; + 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(BPF_MISC|BPF_TAX); + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); @@ -2199,7 +2319,7 @@ gen_load_prism_llprefixlen() } static struct slist * -gen_load_avs_llprefixlen() +gen_load_avs_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; @@ -2210,27 +2330,27 @@ gen_load_avs_llprefixlen() * generated uses that prefix, so we don't need to generate any * code to load it.) */ - if (reg_off_ll != -1) { + 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(BPF_LD|BPF_W|BPF_ABS); + 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(BPF_ST); - s2->s.k = reg_off_ll; + 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(BPF_MISC|BPF_TAX); + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); @@ -2239,7 +2359,7 @@ gen_load_avs_llprefixlen() } static struct slist * -gen_load_radiotap_llprefixlen() +gen_load_radiotap_llprefixlen(compiler_state_t *cstate) { struct slist *s1, *s2; @@ -2250,7 +2370,7 @@ gen_load_radiotap_llprefixlen() * generated uses that prefix, so we don't need to generate any * code to load it.) */ - if (reg_off_ll != -1) { + 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 @@ -2262,36 +2382,36 @@ gen_load_radiotap_llprefixlen() * 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(BPF_LD|BPF_B|BPF_ABS); + s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; - s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; - s2 = new_stmt(BPF_MISC|BPF_TAX); + 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(BPF_LD|BPF_B|BPF_ABS); + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; - s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X); + 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(BPF_ST); - s2->s.k = reg_off_ll; + 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(BPF_MISC|BPF_TAX); + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); @@ -2299,7 +2419,7 @@ gen_load_radiotap_llprefixlen() 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. @@ -2309,16 +2429,16 @@ gen_load_radiotap_llprefixlen() * that's done in finish_parse(). */ static struct slist * -gen_load_ppi_llprefixlen() +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 (reg_off_ll != -1) { + 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 @@ -2330,36 +2450,36 @@ gen_load_ppi_llprefixlen() * 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(BPF_LD|BPF_B|BPF_ABS); + s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); s1->s.k = 3; - s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); + s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); sappend(s1, s2); s2->s.k = 8; - s2 = new_stmt(BPF_MISC|BPF_TAX); + 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(BPF_LD|BPF_B|BPF_ABS); + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); sappend(s1, s2); s2->s.k = 2; - s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X); + 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(BPF_ST); - s2->s.k = reg_off_ll; + 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(BPF_MISC|BPF_TAX); + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); sappend(s1, s2); return (s1); @@ -2375,21 +2495,22 @@ gen_load_ppi_llprefixlen() * radio information. */ static struct slist * -gen_load_802_11_header_len(struct slist *s, struct slist *snext) +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; - struct slist *sjset_radiotap_tsft; + 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 (reg_off_macpl == -1) { + if (cstate->off_linkpl.reg == -1) { /* * No register has been assigned to the offset of - * the MAC-layer payload, which means nobody needs + * the link-layer payload, which means nobody needs * it; don't bother computing it - just return * what we already have. */ @@ -2401,15 +2522,15 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * we are generating jmp instructions within a normal * slist of instructions */ - no_optimize = 1; - + 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_ll". + * header is "off_outermostlinkhdr.constant_part". */ if (s == NULL) { /* @@ -2418,30 +2539,30 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * * Load the length of the fixed-length prefix preceding * the link-layer header (if any) into the X register, - * and store it in the reg_off_macpl register. - * That length is off_ll. + * and store it in the cstate->off_linkpl.reg register. + * That length is off_outermostlinkhdr.constant_part. */ - s = new_stmt(BPF_LDX|BPF_IMM); - s->s.k = off_ll; + 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 reg_off_macpl, and then load the Frame Control field, + * 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(BPF_MISC|BPF_TXA); + s2 = new_stmt(cstate, BPF_MISC|BPF_TXA); sappend(s, s2); - s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s2->s.k = 24; sappend(s, s2); - s2 = new_stmt(BPF_ST); - s2->s.k = reg_off_macpl; + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); - s2 = new_stmt(BPF_LD|BPF_IND|BPF_B); + s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); s2->s.k = 0; sappend(s, s2); @@ -2450,15 +2571,15 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * a data frame has the 0x08 bit (b3) in that field set and the * 0x04 bit (b2) clear. */ - sjset_data_frame_1 = new_stmt(JMP(BPF_JSET)); + 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(JMP(BPF_JSET)); + 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; @@ -2469,24 +2590,24 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * program. */ sjset_data_frame_2->s.jt = snext; - sjset_data_frame_2->s.jf = sjset_qos = new_stmt(JMP(BPF_JSET)); + 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 reg_off_macpl, to skip the 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(BPF_LD|BPF_MEM); - s2->s.k = reg_off_macpl; + 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(BPF_ALU|BPF_ADD|BPF_IMM); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 2; sappend(s, s2); - s2 = new_stmt(BPF_ST); - s2->s.k = reg_off_macpl; + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); /* @@ -2498,32 +2619,54 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * 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 (linktype == DLT_IEEE802_11_RADIO) { + if (cstate->linktype == DLT_IEEE802_11_RADIO) { /* * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set - * in the presence flag? + * in the first presence flag word? */ - sjset_qos->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_W); + sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W); s2->s.k = 4; sappend(s, s2); - sjset_radiotap_flags = new_stmt(JMP(BPF_JSET)); - sjset_radiotap_flags->s.k = SWAPLONG(0x00000002); - sappend(s, sjset_radiotap_flags); + 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->s.jf = snext; + 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 = sjset_radiotap_flags->s.jt = - new_stmt(JMP(BPF_JSET)); - sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001); - sappend(s, sjset_radiotap_tsft); + 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 @@ -2534,11 +2677,12 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ - sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + 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(JMP(BPF_JSET)); + sjset_tsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_tsft_datapad->s.k = 0x20; sappend(s, sjset_tsft_datapad); @@ -2550,11 +2694,12 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) * is set. */ - sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + 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(JMP(BPF_JSET)); + sjset_notsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); sjset_notsft_datapad->s.k = 0x20; sappend(s, sjset_notsft_datapad); @@ -2565,17 +2710,17 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) * dividing by and multiplying by 4, which we do by * ANDing with ~3. */ - s_roundup = new_stmt(BPF_LD|BPF_MEM); - s_roundup->s.k = reg_off_macpl; + s_roundup = new_stmt(cstate, BPF_LD|BPF_MEM); + s_roundup->s.k = cstate->off_linkpl.reg; sappend(s, s_roundup); - s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); s2->s.k = 3; sappend(s, s2); - s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM); s2->s.k = ~3; sappend(s, s2); - s2 = new_stmt(BPF_ST); - s2->s.k = reg_off_macpl; + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; sappend(s, s2); sjset_tsft_datapad->s.jt = s_roundup; @@ -2589,33 +2734,46 @@ gen_load_802_11_header_len(struct slist *s, struct slist *snext) } static void -insert_compute_vloffsets(b) - struct block *b; +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 (linktype) { + switch (cstate->outermostlinktype) { case DLT_PRISM_HEADER: - s = gen_load_prism_llprefixlen(); + s = gen_load_prism_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO_AVS: - s = gen_load_avs_llprefixlen(); + s = gen_load_avs_llprefixlen(cstate); break; case DLT_IEEE802_11_RADIO: - s = gen_load_radiotap_llprefixlen(); + s = gen_load_radiotap_llprefixlen(cstate); break; case DLT_PPI: - s = gen_load_ppi_llprefixlen(); + s = gen_load_ppi_llprefixlen(cstate); break; default: @@ -2625,17 +2783,17 @@ insert_compute_vloffsets(b) /* * For link-layer types that have a variable-length link-layer - * header, generate code to load the offset of the MAC-layer + * header, generate code to load the offset of the link-layer * payload into the register assigned to that offset, if any. */ - switch (linktype) { + 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(s, b->stmts); + s = gen_load_802_11_header_len(cstate, s, b->stmts); break; } @@ -2652,19 +2810,19 @@ insert_compute_vloffsets(b) } static struct block * -gen_ppi_dlt_check(void) +gen_ppi_dlt_check(compiler_state_t *cstate) { struct slist *s_load_dlt; struct block *b; - if (linktype == DLT_PPI) + if (cstate->linktype == DLT_PPI) { /* Create the statements that check for the DLT */ - s_load_dlt = new_stmt(BPF_LD|BPF_W|BPF_ABS); + s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); s_load_dlt->s.k = 4; - b = new_block(JMP(BPF_JEQ)); + b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s_load_dlt; b->s.k = SWAPLONG(DLT_IEEE802_11); @@ -2673,164 +2831,49 @@ gen_ppi_dlt_check(void) { b = NULL; } - - return b; -} - -static struct slist * -gen_prism_llprefixlen(void) -{ - struct slist *s; - - if (reg_off_ll == -1) { - /* - * We haven't yet assigned a register for the length - * of the radio header; allocate one. - */ - reg_off_ll = alloc_reg(); - } - - /* - * Load the register containing the radio length - * into the X register. - */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_off_ll; - return s; -} - -static struct slist * -gen_avs_llprefixlen(void) -{ - struct slist *s; - - if (reg_off_ll == -1) { - /* - * We haven't yet assigned a register for the length - * of the AVS header; allocate one. - */ - reg_off_ll = alloc_reg(); - } - - /* - * Load the register containing the AVS length - * into the X register. - */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_off_ll; - return s; -} - -static struct slist * -gen_radiotap_llprefixlen(void) -{ - struct slist *s; - - if (reg_off_ll == -1) { - /* - * We haven't yet assigned a register for the length - * of the radiotap header; allocate one. - */ - reg_off_ll = alloc_reg(); - } - - /* - * Load the register containing the radiotap length - * into the X register. - */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_off_ll; - return s; -} - -/* - * 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. - */ -static struct slist * -gen_ppi_llprefixlen(void) -{ - struct slist *s; - - if (reg_off_ll == -1) { - /* - * We haven't yet assigned a register for the length - * of the radiotap header; allocate one. - */ - reg_off_ll = alloc_reg(); - } - - /* - * Load the register containing the PPI length - * into the X register. - */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_off_ll; - return s; -} - -/* - * Generate code to compute the link-layer header length, if necessary, - * putting it into the X register, and to return either a pointer to a - * "struct slist" for the list of statements in that code, or NULL if - * no code is necessary. - */ -static struct slist * -gen_llprefixlen(void) -{ - switch (linktype) { - - case DLT_PRISM_HEADER: - return gen_prism_llprefixlen(); - - case DLT_IEEE802_11_RADIO_AVS: - return gen_avs_llprefixlen(); - - case DLT_IEEE802_11_RADIO: - return gen_radiotap_llprefixlen(); - - case DLT_PPI: - return gen_ppi_llprefixlen(); - - default: - return NULL; - } + + return b; } /* - * Generate code to load the register containing the offset of the - * MAC-layer payload into the X register; if no register for that offset - * has been allocated, allocate it first. + * 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_off_macpl(void) +gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off) { struct slist *s; - if (off_macpl_is_variable) { - if (reg_off_macpl == -1) { + if (off->is_variable) { + if (off->reg == -1) { /* - * We haven't yet assigned a register for the offset - * of the MAC-layer payload; allocate one. + * We haven't yet assigned a register for the + * variable part of the offset of the link-layer + * header; allocate one. */ - reg_off_macpl = alloc_reg(); + off->reg = alloc_reg(cstate); } /* - * Load the register containing the offset of the MAC-layer - * payload into the X register. + * Load the register containing the variable part of the + * offset of the link-layer header into the X register. */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_off_macpl; + s = new_stmt(cstate, BPF_LDX|BPF_MEM); + s->s.k = off->reg; return s; } else { /* - * That offset isn't variable, so we don't need to - * generate any code. + * That offset isn't variable, there's no variable part, + * so we don't need to generate any code. */ return NULL; } @@ -2885,6 +2928,51 @@ ethertype_to_ppptype(proto) return (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 /* OS X, 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. @@ -2893,55 +2981,46 @@ ethertype_to_ppptype(proto) * value, if <= ETHERMTU. */ static struct block * -gen_linktype(proto) - register int proto; +gen_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1, *b2; + const char *description; /* are we checking MPLS-encapsulated packets? */ - if (label_stack_depth > 0) { + if (cstate->label_stack_depth > 0) { switch (proto) { case ETHERTYPE_IP: case PPP_IP: /* FIXME add other L3 proto IDs */ - return gen_mpls_linktype(Q_IP); + return gen_mpls_linktype(cstate, Q_IP); case ETHERTYPE_IPV6: case PPP_IPV6: /* FIXME add other L3 proto IDs */ - return gen_mpls_linktype(Q_IPV6); + return gen_mpls_linktype(cstate, Q_IPV6); default: - bpf_error("unsupported protocol over mpls"); + bpf_error(cstate, "unsupported protocol over mpls"); /* NOTREACHED */ } } - /* - * Are we testing PPPoE packets? - */ - if (is_pppoes) { - /* - * The PPPoE session header is part of the - * MAC-layer payload, so all references - * should be relative to the beginning of - * that payload. - */ - - /* - * We use Ethernet protocol types inside libpcap; - * map them to the corresponding PPP protocol types. - */ - proto = ethertype_to_ppptype(proto); - return gen_cmp(OR_MACPL, off_linktype, BPF_H, (bpf_int32)proto); - } - - switch (linktype) { + switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - return gen_ether_linktype(proto); + /* 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, proto); + if (b0 != NULL) + gen_and(b0, b1); + return b1; /*NOTREACHED*/ break; @@ -2953,8 +3032,7 @@ gen_linktype(proto) /* fall through */ default: - return gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)proto); + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ break; } @@ -2968,12 +3046,12 @@ gen_linktype(proto) /* * Check that we have a data frame. */ - b0 = gen_check_802_11_data_frame(); + b0 = gen_check_802_11_data_frame(cstate); /* * Now check for the specified link-layer type. */ - b1 = gen_llc_linktype(proto); + b1 = gen_llc_linktype(cstate, proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ @@ -2981,9 +3059,9 @@ gen_linktype(proto) case DLT_FDDI: /* - * XXX - check for asynchronous frames, as per RFC 1103. + * XXX - check for LLC frames. */ - return gen_llc_linktype(proto); + return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; @@ -2991,56 +3069,34 @@ gen_linktype(proto) /* * XXX - check for LLC PDUs, as per IEEE 802.5. */ - return gen_llc_linktype(proto); + return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_ATM_RFC1483: case DLT_ATM_CLIP: case DLT_IP_OVER_FC: - return gen_llc_linktype(proto); + return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ break; case DLT_SUNATM: /* - * If "is_lane" is set, check for a LANE-encapsulated - * version of this protocol, otherwise check for an - * LLC-encapsulated version of this protocol. + * Check for an LLC-encapsulated version of this protocol; + * if we were checking for LANE, linktype would no longer + * be DLT_SUNATM. * - * We assume LANE means Ethernet, not Token Ring. + * Check for LLC encapsulation and then check the protocol. */ - if (is_lane) { - /* - * Check that the packet doesn't begin with an - * LE Control marker. (We've already generated - * a test for LANE.) - */ - b0 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H, - 0xFF00); - gen_not(b0); - - /* - * Now generate an Ethernet test. - */ - b1 = gen_ether_linktype(proto); - gen_and(b0, b1); - return b1; - } else { - /* - * Check for LLC encapsulation and then check the - * protocol. - */ - b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); - b1 = gen_llc_linktype(proto); - gen_and(b0, b1); - return b1; - } + b0 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + b1 = gen_llc_linktype(cstate, proto); + gen_and(b0, b1); + return b1; /*NOTREACHED*/ break; case DLT_LINUX_SLL: - return gen_linux_sll_linktype(proto); + return gen_linux_sll_linktype(cstate, proto); /*NOTREACHED*/ break; @@ -3058,14 +3114,14 @@ gen_linktype(proto) case ETHERTYPE_IP: /* Check for a version number of 4. */ - return gen_mcmp(OR_LINK, 0, BPF_B, 0x40, 0xF0); + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0); case ETHERTYPE_IPV6: /* Check for a version number of 6. */ - return gen_mcmp(OR_LINK, 0, BPF_B, 0x60, 0xF0); + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0); default: - return gen_false(); /* always false */ + return gen_false(cstate); /* always false */ } /*NOTREACHED*/ break; @@ -3075,10 +3131,10 @@ gen_linktype(proto) * Raw IPv4, so no type field. */ if (proto == ETHERTYPE_IP) - return gen_true(); /* always true */ + return gen_true(cstate); /* always true */ /* Checking for something other than IPv4; always false */ - return gen_false(); + return gen_false(cstate); /*NOTREACHED*/ break; @@ -3087,10 +3143,10 @@ gen_linktype(proto) * Raw IPv6, so no type field. */ if (proto == ETHERTYPE_IPV6) - return gen_true(); /* always true */ + return gen_true(cstate); /* always true */ /* Checking for something other than IPv6; always false */ - return gen_false(); + return gen_false(cstate); /*NOTREACHED*/ break; @@ -3103,7 +3159,7 @@ gen_linktype(proto) * map them to the corresponding PPP protocol types. */ proto = ethertype_to_ppptype(proto); - return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ break; @@ -3119,16 +3175,16 @@ gen_linktype(proto) * Also check for Van Jacobson-compressed IP. * XXX - do this for other forms of PPP? */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_IP); - b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJC); + 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(OR_LINK, off_linktype, BPF_H, PPP_VJNC); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC); gen_or(b1, b0); return b0; default: proto = ethertype_to_ppptype(proto); - return gen_cmp(OR_LINK, off_linktype, BPF_H, + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); } /*NOTREACHED*/ @@ -3137,39 +3193,71 @@ gen_linktype(proto) case DLT_NULL: case DLT_LOOP: case DLT_ENC: - /* - * 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 work 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. - * - * XXX - AF_ values may, unfortunately, be platform- - * dependent; for example, FreeBSD's AF_INET6 is 24 - * whilst NetBSD's and OpenBSD's is 26. - * - * This means that, when reading a capture file, just - * checking for our AF_INET6 value won't work if the - * capture file came from another OS. - */ switch (proto) { case ETHERTYPE_IP: - proto = AF_INET; - break; + return (gen_loopback_linktype(cstate, AF_INET)); -#ifdef INET6 case ETHERTYPE_IPV6: - proto = AF_INET6; - break; -#endif + /* + * 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: /* @@ -3177,28 +3265,8 @@ gen_linktype(proto) * XXX - support those that have AF_ values * #defined on this platform, at least? */ - return gen_false(); - } - - if (linktype == DLT_NULL || 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 (bpf_pcap->sf.rfile != NULL && - bpf_pcap->sf.swapped) - proto = SWAPLONG(proto); - proto = htonl(proto); + return gen_false(cstate); } - return (gen_cmp(OR_LINK, 0, BPF_W, (bpf_int32)proto)); #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: @@ -3207,13 +3275,13 @@ gen_linktype(proto) * the packet. */ if (proto == ETHERTYPE_IP) - return (gen_cmp(OR_LINK, offsetof(struct pfloghdr, af), + return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, (bpf_int32)AF_INET)); else if (proto == ETHERTYPE_IPV6) - return (gen_cmp(OR_LINK, offsetof(struct pfloghdr, af), + return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), BPF_B, (bpf_int32)AF_INET6)); else - return gen_false(); + return gen_false(cstate); /*NOTREACHED*/ break; #endif /* HAVE_NET_PFVAR_H */ @@ -3227,34 +3295,34 @@ gen_linktype(proto) switch (proto) { default: - return gen_false(); + return gen_false(cstate); case ETHERTYPE_IPV6: - return (gen_cmp(OR_LINK, off_linktype, BPF_B, + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_INET6)); case ETHERTYPE_IP: - b0 = gen_cmp(OR_LINK, off_linktype, BPF_B, + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_IP); - b1 = gen_cmp(OR_LINK, off_linktype, BPF_B, + b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_IP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_ARP: - b0 = gen_cmp(OR_LINK, off_linktype, BPF_B, + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ARP); - b1 = gen_cmp(OR_LINK, off_linktype, BPF_B, + b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ARP_OLD); gen_or(b0, b1); return (b1); case ETHERTYPE_REVARP: - return (gen_cmp(OR_LINK, off_linktype, BPF_B, + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_REVARP)); case ETHERTYPE_ATALK: - return (gen_cmp(OR_LINK, off_linktype, BPF_B, + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)ARCTYPE_ATALK)); } /*NOTREACHED*/ @@ -3263,9 +3331,9 @@ gen_linktype(proto) case DLT_LTALK: switch (proto) { case ETHERTYPE_ATALK: - return gen_true(); + return gen_true(cstate); default: - return gen_false(); + return gen_false(cstate); } /*NOTREACHED*/ break; @@ -3281,13 +3349,13 @@ gen_linktype(proto) /* * Check for the special NLPID for IP. */ - return gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | 0xcc); + 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(OR_LINK, 2, BPF_H, (0x03<<8) | 0x8e); + return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e); case LLCSAP_ISONS: /* @@ -3301,21 +3369,21 @@ gen_linktype(proto) * control field of UI, i.e. 0x03 followed * by the NLPID. */ - b0 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO8473_CLNP); - b1 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO9542_ESIS); - b2 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO10589_ISIS); + 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(); + return gen_false(cstate); } /*NOTREACHED*/ break; case DLT_MFR: - bpf_error("Multi-link Frame Relay link-layer type filtering not implemented"); + bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented"); case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: @@ -3347,83 +3415,104 @@ gen_linktype(proto) * * FIXME encapsulation specific BPF_ filters */ - return gen_mcmp(OR_LINK, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */ + 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(proto); + return gen_ipnet_linktype(cstate, proto); case DLT_LINUX_IRDA: - bpf_error("IrDA link-layer type filtering not implemented"); + bpf_error(cstate, "IrDA link-layer type filtering not implemented"); case DLT_DOCSIS: - bpf_error("DOCSIS link-layer type filtering not implemented"); + bpf_error(cstate, "DOCSIS link-layer type filtering not implemented"); case DLT_MTP2: case DLT_MTP2_WITH_PHDR: - bpf_error("MTP2 link-layer type filtering not implemented"); + bpf_error(cstate, "MTP2 link-layer type filtering not implemented"); case DLT_ERF: - bpf_error("ERF link-layer type filtering not implemented"); + bpf_error(cstate, "ERF link-layer type filtering not implemented"); case DLT_PFSYNC: - bpf_error("PFSYNC link-layer type filtering not implemented"); + bpf_error(cstate, "PFSYNC link-layer type filtering not implemented"); case DLT_LINUX_LAPD: - bpf_error("LAPD link-layer type filtering not implemented"); + bpf_error(cstate, "LAPD link-layer type filtering not implemented"); - case DLT_USB: + case DLT_USB_FREEBSD: case DLT_USB_LINUX: case DLT_USB_LINUX_MMAPPED: - bpf_error("USB link-layer type filtering not implemented"); + 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("Bluetooth link-layer type filtering not implemented"); + bpf_error(cstate, "Bluetooth link-layer type filtering not implemented"); case DLT_CAN20B: case DLT_CAN_SOCKETCAN: - bpf_error("CAN link-layer type filtering not implemented"); + 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: - bpf_error("IEEE 802.15.4 link-layer type filtering not implemented"); + bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented"); case DLT_IEEE802_16_MAC_CPS_RADIO: - bpf_error("IEEE 802.16 link-layer type filtering not implemented"); + bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented"); case DLT_SITA: - bpf_error("SITA link-layer type filtering not implemented"); + bpf_error(cstate, "SITA link-layer type filtering not implemented"); case DLT_RAIF1: - bpf_error("RAIF1 link-layer type filtering not implemented"); + bpf_error(cstate, "RAIF1 link-layer type filtering not implemented"); case DLT_IPMB: - bpf_error("IPMB link-layer type filtering not implemented"); + bpf_error(cstate, "IPMB link-layer type filtering not implemented"); case DLT_AX25_KISS: - bpf_error("AX.25 link-layer type filtering not implemented"); - } + bpf_error(cstate, "AX.25 link-layer type filtering not implemented"); - /* - * All the types that have no encapsulation should either be - * handled as DLT_SLIP, DLT_SLIP_BSDOS, and DLT_RAW are, if - * all packets are IP packets, or should be handled in some - * special case, if none of them are (if some are and some - * aren't, the lack of encapsulation is a problem, as we'd - * have to find some other way of determining the packet type). - * - * Therefore, if "off_linktype" is -1, there's an error. - */ - if (off_linktype == (u_int)-1) - abort(); + 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"); - /* - * Any type not handled above should always have an Ethernet - * type at an offset of "off_linktype". - */ - return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); + 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, (bpf_int32)proto); + } else { + /* + * No; report an error. + */ + description = pcap_datalink_val_to_description(cstate->linktype); + if (description != NULL) { + bpf_error(cstate, "%s link-layer type filtering not implemented", + description); + } else { + bpf_error(cstate, "DLT %u link-layer type filtering not implemented", + cstate->linktype); + } + } + break; + } } /* @@ -3434,9 +3523,7 @@ gen_linktype(proto) * code and protocol type in the SNAP header. */ static struct block * -gen_snap(orgcode, ptype) - bpf_u_int32 orgcode; - bpf_u_int32 ptype; +gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) { u_char snapblock[8]; @@ -3448,7 +3535,179 @@ gen_snap(orgcode, ptype) snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ - return gen_bcmp(OR_MACPL, 0, 8, snapblock); + return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock); +} + +/* + * Generate code to match frames with an LLC header. + */ +struct block * +gen_llc(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, (bpf_int32)0xFFFF); + gen_not(b1); + gen_and(b0, b1); + return b1; + + case DLT_SUNATM: + /* + * We check for LLC traffic. + */ + b0 = gen_atmtype_abbrev(cstate, A_LLC); + 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 linktype %d", cstate->linktype); + /* NOTREACHED */ + } +} + +struct block * +gen_llc_i(compiler_state_t *cstate) +{ + struct block *b0, *b1; + struct slist *s; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(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; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(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; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(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; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(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; + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc(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; } /* @@ -3464,8 +3723,7 @@ gen_snap(orgcode, ptype) * protocol ID in a SNAP header. */ static struct block * -gen_llc_linktype(proto) - int proto; +gen_llc_linktype(compiler_state_t *cstate, int proto) { /* * XXX - handle token-ring variable-length header. @@ -3478,10 +3736,9 @@ gen_llc_linktype(proto) /* * 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)? + * DSAP, as we do for other SAP values? */ - return gen_cmp(OR_MACPL, 0, BPF_H, (bpf_u_int32) + return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32) ((proto << 8) | proto)); case LLCSAP_IPX: @@ -3489,7 +3746,7 @@ gen_llc_linktype(proto) * XXX - are there ever SNAP frames for IPX on * non-Ethernet 802.x networks? */ - return gen_cmp(OR_MACPL, 0, BPF_B, + return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX); case ETHERTYPE_ATALK: @@ -3502,7 +3759,7 @@ gen_llc_linktype(proto) * XXX - check for an organization code of * encapsulated Ethernet as well? */ - return gen_snap(0x080007, ETHERTYPE_ATALK); + return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); default: /* @@ -3514,7 +3771,7 @@ gen_llc_linktype(proto) * This is an LLC SAP value, so check * the DSAP. */ - return gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)proto); + return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)proto); } else { /* * This is an Ethernet type; we assume that it's @@ -3529,23 +3786,20 @@ gen_llc_linktype(proto) * organization code of 0x000000 (encapsulated * Ethernet), we'd do * - * return gen_snap(0x000000, proto); + * return gen_snap(cstate, 0x000000, 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(OR_MACPL, 6, BPF_H, (bpf_int32)proto); + return gen_cmp(cstate, OR_LLC, 6, BPF_H, (bpf_int32)proto); } } } static struct block * -gen_hostop(addr, mask, dir, proto, src_off, dst_off) - bpf_u_int32 addr; - bpf_u_int32 mask; - int dir, proto; - u_int src_off, dst_off; +gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, + int dir, int proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; @@ -3561,34 +3815,31 @@ gen_hostop(addr, mask, dir, proto, src_off, dst_off) break; case Q_AND: - b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); - b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: - b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); - b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; default: abort(); } - b0 = gen_linktype(proto); - b1 = gen_mcmp(OR_NET, offset, BPF_W, (bpf_int32)addr, mask); + b0 = gen_linktype(cstate, proto); + b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask); gen_and(b0, b1); return b1; } #ifdef INET6 static struct block * -gen_hostop6(addr, mask, dir, proto, src_off, dst_off) - struct in6_addr *addr; - struct in6_addr *mask; - int dir, proto; - u_int src_off, dst_off; +gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, + struct in6_addr *mask, int dir, int proto, u_int src_off, u_int dst_off) { struct block *b0, *b1; u_int offset; @@ -3605,15 +3856,15 @@ gen_hostop6(addr, mask, dir, proto, src_off, dst_off) break; case Q_AND: - b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); - b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); + b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: - b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); - b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); + b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; @@ -3623,68 +3874,66 @@ gen_hostop6(addr, mask, dir, proto, src_off, dst_off) /* this order is important */ a = (u_int32_t *)addr; m = (u_int32_t *)mask; - b1 = gen_mcmp(OR_NET, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); - b0 = gen_mcmp(OR_NET, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); + 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(OR_NET, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); + b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); gen_and(b0, b1); - b0 = gen_mcmp(OR_NET, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); + b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); gen_and(b0, b1); - b0 = gen_linktype(proto); + b0 = gen_linktype(cstate, proto); gen_and(b0, b1); return b1; } #endif static struct block * -gen_ehostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +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(OR_LINK, off_mac + 6, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr); case Q_DST: - return gen_bcmp(OR_LINK, off_mac + 0, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr); case Q_AND: - b0 = gen_ehostop(eaddr, Q_SRC); - b1 = gen_ehostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_ehostop(eaddr, Q_DST); + 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("'addr1' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr1' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR2: - bpf_error("'addr2' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr2' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR3: - bpf_error("'addr3' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr3' is only supported on 802.11 with 802.11 headers"); break; case Q_ADDR4: - bpf_error("'addr4' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr4' is only supported on 802.11 with 802.11 headers"); break; case Q_RA: - bpf_error("'ra' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers"); break; case Q_TA: - bpf_error("'ta' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers"); break; } abort(); @@ -3695,62 +3944,52 @@ gen_ehostop(eaddr, dir) * Like gen_ehostop, but for DLT_FDDI */ static struct block * -gen_fhostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { struct block *b0, *b1; switch (dir) { case Q_SRC: -#ifdef PCAP_FDDIPAD - return gen_bcmp(OR_LINK, 6 + 1 + pcap_fddipad, 6, eaddr); -#else - return gen_bcmp(OR_LINK, 6 + 1, 6, eaddr); -#endif + return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_DST: -#ifdef PCAP_FDDIPAD - return gen_bcmp(OR_LINK, 0 + 1 + pcap_fddipad, 6, eaddr); -#else - return gen_bcmp(OR_LINK, 0 + 1, 6, eaddr); -#endif + return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr); case Q_AND: - b0 = gen_fhostop(eaddr, Q_SRC); - b1 = gen_fhostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_fhostop(eaddr, Q_DST); + 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("'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: - bpf_error("'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: - bpf_error("'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: - bpf_error("'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: - bpf_error("'ra' is only supported on 802.11"); + bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: - bpf_error("'ta' is only supported on 802.11"); + bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); @@ -3761,54 +4000,52 @@ gen_fhostop(eaddr, dir) * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) */ static struct block * -gen_thostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +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(OR_LINK, 8, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr); case Q_DST: - return gen_bcmp(OR_LINK, 2, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: - b0 = gen_thostop(eaddr, Q_SRC); - b1 = gen_thostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_thostop(eaddr, Q_DST); + 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("'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: - bpf_error("'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: - bpf_error("'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: - bpf_error("'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: - bpf_error("'ra' is only supported on 802.11"); + bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: - bpf_error("'ta' is only supported on 802.11"); + bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); @@ -3820,9 +4057,7 @@ gen_thostop(eaddr, dir) * various 802.11 + radio headers. */ static struct block * -gen_wlanhostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) { register struct block *b0, *b1, *b2; register struct slist *s; @@ -3834,7 +4069,7 @@ gen_wlanhostop(eaddr, dir) * and wipes out some LD instructions generated by the below * code to validate the Frame Control bits */ - no_optimize = 1; + cstate->no_optimize = 1; #endif /* ENABLE_WLAN_FILTERING_PATCH */ switch (dir) { @@ -3864,23 +4099,23 @@ gen_wlanhostop(eaddr, dir) * * First, check for To DS set, i.e. check "link[1] & 0x01". */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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(OR_LINK, 24, 6, eaddr); + 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(OR_LINK, 1, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -3888,7 +4123,7 @@ gen_wlanhostop(eaddr, dir) /* * If To DS is not set, the SA is at 16. */ - b1 = gen_bcmp(OR_LINK, 16, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b2, b1); /* @@ -3902,8 +4137,8 @@ gen_wlanhostop(eaddr, dir) * Now check for From DS being set, and AND that with * the ORed-together checks. */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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); @@ -3911,8 +4146,8 @@ gen_wlanhostop(eaddr, dir) /* * Now check for data frames with From DS not set. */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -3920,7 +4155,7 @@ gen_wlanhostop(eaddr, dir) /* * If From DS isn't set, the SA is at 10. */ - b1 = gen_bcmp(OR_LINK, 10, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* @@ -3934,8 +4169,8 @@ gen_wlanhostop(eaddr, dir) * Now check for a data frame. * I.e, check "link[0] & 0x08". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; @@ -3949,8 +4184,8 @@ gen_wlanhostop(eaddr, dir) * is a management frame. * I.e, check "!(link[0] & 0x08)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -3958,7 +4193,7 @@ gen_wlanhostop(eaddr, dir) /* * For management frames, the SA is at 10. */ - b1 = gen_bcmp(OR_LINK, 10, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); /* @@ -3976,8 +4211,8 @@ gen_wlanhostop(eaddr, dir) * * I.e., check "!(link[0] & 0x04)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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); @@ -4011,23 +4246,23 @@ gen_wlanhostop(eaddr, dir) * * First, check for To DS set, i.e. "link[1] & 0x01". */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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(OR_LINK, 16, 6, eaddr); + 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(OR_LINK, 1, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -4035,7 +4270,7 @@ gen_wlanhostop(eaddr, dir) /* * If To DS is not set, the DA is at 4. */ - b1 = gen_bcmp(OR_LINK, 4, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* @@ -4048,8 +4283,8 @@ gen_wlanhostop(eaddr, dir) * Now check for a data frame. * I.e, check "link[0] & 0x08". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; @@ -4063,8 +4298,8 @@ gen_wlanhostop(eaddr, dir) * is a management frame. * I.e, check "!(link[0] & 0x08)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -4072,7 +4307,7 @@ gen_wlanhostop(eaddr, dir) /* * For management frames, the DA is at 4. */ - b1 = gen_bcmp(OR_LINK, 4, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); gen_and(b2, b1); /* @@ -4090,8 +4325,8 @@ gen_wlanhostop(eaddr, dir) * * I.e., check "!(link[0] & 0x04)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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); @@ -4114,15 +4349,15 @@ gen_wlanhostop(eaddr, dir) * is a management frame. * I.e, check "(link[0] & 0x08)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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(OR_LINK, 4, 6, eaddr); + b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); /* * AND that with the check of addr1. @@ -4139,13 +4374,13 @@ gen_wlanhostop(eaddr, dir) /* * Not present in CTS or ACK control frames. */ - b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); - b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); - b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b2); gen_and(b1, b2); @@ -4156,8 +4391,8 @@ gen_wlanhostop(eaddr, dir) * is a management frame. * I.e, check "(link[0] & 0x08)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; @@ -4170,7 +4405,7 @@ gen_wlanhostop(eaddr, dir) /* * Check addr2. */ - b1 = gen_bcmp(OR_LINK, 10, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; @@ -4178,24 +4413,24 @@ gen_wlanhostop(eaddr, dir) * XXX - add BSSID keyword? */ case Q_ADDR1: - return (gen_bcmp(OR_LINK, 4, 6, eaddr)); + return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); case Q_ADDR2: /* * Not present in CTS or ACK control frames. */ - b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); - b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, IEEE80211_FC0_SUBTYPE_MASK); gen_not(b1); - b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + 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(OR_LINK, 10, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; @@ -4203,10 +4438,10 @@ gen_wlanhostop(eaddr, dir) /* * Not present in control frames. */ - b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_TYPE_MASK); gen_not(b0); - b1 = gen_bcmp(OR_LINK, 16, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); gen_and(b0, b1); return b1; @@ -4217,22 +4452,22 @@ gen_wlanhostop(eaddr, dir) * frames should have both of those set, so we don't * check the frame type. */ - b0 = gen_mcmp(OR_LINK, 1, BPF_B, + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); - b1 = gen_bcmp(OR_LINK, 24, 6, eaddr); + b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); gen_and(b0, b1); return b1; case Q_AND: - b0 = gen_wlanhostop(eaddr, Q_SRC); - b1 = gen_wlanhostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_wlanhostop(eaddr, Q_DST); + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); gen_or(b0, b1); return b1; } @@ -4246,54 +4481,52 @@ gen_wlanhostop(eaddr, dir) * as the RFC states.) */ static struct block * -gen_ipfchostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +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(OR_LINK, 10, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); case Q_DST: - return gen_bcmp(OR_LINK, 2, 6, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); case Q_AND: - b0 = gen_ipfchostop(eaddr, Q_SRC); - b1 = gen_ipfchostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_ipfchostop(eaddr, Q_DST); + 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("'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: - bpf_error("'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: - bpf_error("'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: - bpf_error("'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: - bpf_error("'ra' is only supported on 802.11"); + bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: - bpf_error("'ta' is only supported on 802.11"); + bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); @@ -4319,9 +4552,7 @@ gen_ipfchostop(eaddr, dir) * and not generate masking instructions if the mask is 0xFFFF. */ static struct block * -gen_dnhostop(addr, dir) - bpf_u_int32 addr; - int dir; +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 */ @@ -4341,50 +4572,50 @@ gen_dnhostop(addr, dir) case Q_AND: /* Inefficient because we do our Calvinball dance twice */ - b0 = gen_dnhostop(addr, Q_SRC); - b1 = gen_dnhostop(addr, Q_DST); + b0 = gen_dnhostop(cstate, addr, Q_SRC); + b1 = gen_dnhostop(cstate, addr, Q_DST); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: /* Inefficient because we do our Calvinball dance twice */ - b0 = gen_dnhostop(addr, Q_SRC); - b1 = gen_dnhostop(addr, Q_DST); + b0 = gen_dnhostop(cstate, addr, Q_SRC); + b1 = gen_dnhostop(cstate, addr, Q_DST); gen_or(b0, b1); return b1; case Q_ISO: - bpf_error("ISO host filtering not implemented"); + bpf_error(cstate, "ISO host filtering not implemented"); default: abort(); } - b0 = gen_linktype(ETHERTYPE_DN); + b0 = gen_linktype(cstate, ETHERTYPE_DN); /* Check for pad = 1, long header case */ - tmp = gen_mcmp(OR_NET, 2, BPF_H, + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); - b1 = gen_cmp(OR_NET, 2 + 1 + offset_lh, + b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b1); /* Check for pad = 0, long header case */ - tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); - b2 = gen_cmp(OR_NET, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 1, short header case */ - tmp = gen_mcmp(OR_NET, 2, BPF_H, + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); - b2 = gen_cmp(OR_NET, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); /* Check for pad = 0, short header case */ - tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); - b2 = gen_cmp(OR_NET, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); - /* Combine with test for linktype */ + /* Combine with test for cstate->linktype */ gen_and(b0, b1); return b1; } @@ -4395,8 +4626,7 @@ gen_dnhostop(addr, dir) * field in the IP header. */ static struct block * -gen_mpls_linktype(proto) - int proto; +gen_mpls_linktype(compiler_state_t *cstate, int proto) { struct block *b0, *b1; @@ -4404,32 +4634,28 @@ gen_mpls_linktype(proto) case Q_IP: /* match the bottom-of-stack bit */ - b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01); + b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ - b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x40, 0xf0); + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0); gen_and(b0, b1); return b1; - + case Q_IPV6: /* match the bottom-of-stack bit */ - b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01); + b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ - b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x60, 0xf0); + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0); gen_and(b0, b1); return b1; - + default: abort(); } } static struct block * -gen_host(addr, mask, proto, dir, type) - bpf_u_int32 addr; - bpf_u_int32 mask; - int proto; - int dir; - int type; +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; @@ -4442,111 +4668,111 @@ gen_host(addr, mask, proto, dir, type) switch (proto) { case Q_DEFAULT: - b0 = gen_host(addr, mask, Q_IP, dir, type); + 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 (label_stack_depth == 0) { - b1 = gen_host(addr, mask, Q_ARP, dir, type); + if (cstate->label_stack_depth == 0) { + b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type); gen_or(b0, b1); - b0 = gen_host(addr, mask, Q_RARP, dir, type); + b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type); gen_or(b1, b0); } return b0; case Q_IP: - return gen_hostop(addr, mask, dir, ETHERTYPE_IP, 12, 16); + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); case Q_RARP: - return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, 14, 24); + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24); case Q_ARP: - return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, 14, 24); + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); case Q_TCP: - bpf_error("'tcp' modifier applied to %s", typestr); + bpf_error(cstate, "'tcp' modifier applied to %s", typestr); case Q_SCTP: - bpf_error("'sctp' modifier applied to %s", typestr); + bpf_error(cstate, "'sctp' modifier applied to %s", typestr); case Q_UDP: - bpf_error("'udp' modifier applied to %s", typestr); + bpf_error(cstate, "'udp' modifier applied to %s", typestr); case Q_ICMP: - bpf_error("'icmp' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp' modifier applied to %s", typestr); case Q_IGMP: - bpf_error("'igmp' modifier applied to %s", typestr); + bpf_error(cstate, "'igmp' modifier applied to %s", typestr); case Q_IGRP: - bpf_error("'igrp' modifier applied to %s", typestr); + bpf_error(cstate, "'igrp' modifier applied to %s", typestr); case Q_PIM: - bpf_error("'pim' modifier applied to %s", typestr); + bpf_error(cstate, "'pim' modifier applied to %s", typestr); case Q_VRRP: - bpf_error("'vrrp' modifier applied to %s", typestr); + bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); case Q_CARP: - bpf_error("'carp' modifier applied to %s", typestr); + bpf_error(cstate, "'carp' modifier applied to %s", typestr); case Q_ATALK: - bpf_error("ATALK host filtering not implemented"); + bpf_error(cstate, "ATALK host filtering not implemented"); case Q_AARP: - bpf_error("AARP host filtering not implemented"); + bpf_error(cstate, "AARP host filtering not implemented"); case Q_DECNET: - return gen_dnhostop(addr, dir); + return gen_dnhostop(cstate, addr, dir); case Q_SCA: - bpf_error("SCA host filtering not implemented"); + bpf_error(cstate, "SCA host filtering not implemented"); case Q_LAT: - bpf_error("LAT host filtering not implemented"); + bpf_error(cstate, "LAT host filtering not implemented"); case Q_MOPDL: - bpf_error("MOPDL host filtering not implemented"); + bpf_error(cstate, "MOPDL host filtering not implemented"); case Q_MOPRC: - bpf_error("MOPRC host filtering not implemented"); + bpf_error(cstate, "MOPRC host filtering not implemented"); case Q_IPV6: - bpf_error("'ip6' modifier applied to ip host"); + bpf_error(cstate, "'ip6' modifier applied to ip host"); case Q_ICMPV6: - bpf_error("'icmp6' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); case Q_AH: - bpf_error("'ah' modifier applied to %s", typestr); + bpf_error(cstate, "'ah' modifier applied to %s", typestr); case Q_ESP: - bpf_error("'esp' modifier applied to %s", typestr); + bpf_error(cstate, "'esp' modifier applied to %s", typestr); case Q_ISO: - bpf_error("ISO host filtering not implemented"); + bpf_error(cstate, "ISO host filtering not implemented"); case Q_ESIS: - bpf_error("'esis' modifier applied to %s", typestr); + bpf_error(cstate, "'esis' modifier applied to %s", typestr); case Q_ISIS: - bpf_error("'isis' modifier applied to %s", typestr); + bpf_error(cstate, "'isis' modifier applied to %s", typestr); case Q_CLNP: - bpf_error("'clnp' modifier applied to %s", typestr); + bpf_error(cstate, "'clnp' modifier applied to %s", typestr); case Q_STP: - bpf_error("'stp' modifier applied to %s", typestr); + bpf_error(cstate, "'stp' modifier applied to %s", typestr); case Q_IPX: - bpf_error("IPX host filtering not implemented"); + bpf_error(cstate, "IPX host filtering not implemented"); case Q_NETBEUI: - bpf_error("'netbeui' modifier applied to %s", typestr); + bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); case Q_RADIO: - bpf_error("'radio' modifier applied to %s", typestr); + bpf_error(cstate, "'radio' modifier applied to %s", typestr); default: abort(); @@ -4556,12 +4782,8 @@ gen_host(addr, mask, proto, dir, type) #ifdef INET6 static struct block * -gen_host6(addr, mask, proto, dir, type) - struct in6_addr *addr; - struct in6_addr *mask; - int proto; - int dir; - int type; +gen_host6(compiler_state_t *cstate, struct in6_addr *addr, + struct in6_addr *mask, int proto, int dir, int type) { const char *typestr; @@ -4573,100 +4795,103 @@ gen_host6(addr, mask, proto, dir, type) switch (proto) { case Q_DEFAULT: - return gen_host6(addr, mask, Q_IPV6, dir, type); + 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("'ip' modifier applied to ip6 %s", typestr); + bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr); case Q_RARP: - bpf_error("'rarp' modifier applied to ip6 %s", typestr); + bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr); case Q_ARP: - bpf_error("'arp' modifier applied to ip6 %s", typestr); + bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: - bpf_error("'sctp' modifier applied to %s", typestr); + bpf_error(cstate, "'sctp' modifier applied to %s", typestr); case Q_TCP: - bpf_error("'tcp' modifier applied to %s", typestr); + bpf_error(cstate, "'tcp' modifier applied to %s", typestr); case Q_UDP: - bpf_error("'udp' modifier applied to %s", typestr); + bpf_error(cstate, "'udp' modifier applied to %s", typestr); case Q_ICMP: - bpf_error("'icmp' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp' modifier applied to %s", typestr); case Q_IGMP: - bpf_error("'igmp' modifier applied to %s", typestr); + bpf_error(cstate, "'igmp' modifier applied to %s", typestr); case Q_IGRP: - bpf_error("'igrp' modifier applied to %s", typestr); + bpf_error(cstate, "'igrp' modifier applied to %s", typestr); case Q_PIM: - bpf_error("'pim' modifier applied to %s", typestr); + bpf_error(cstate, "'pim' modifier applied to %s", typestr); case Q_VRRP: - bpf_error("'vrrp' modifier applied to %s", typestr); + bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); case Q_CARP: - bpf_error("'carp' modifier applied to %s", typestr); + bpf_error(cstate, "'carp' modifier applied to %s", typestr); case Q_ATALK: - bpf_error("ATALK host filtering not implemented"); + bpf_error(cstate, "ATALK host filtering not implemented"); case Q_AARP: - bpf_error("AARP host filtering not implemented"); + bpf_error(cstate, "AARP host filtering not implemented"); case Q_DECNET: - bpf_error("'decnet' modifier applied to ip6 %s", typestr); + bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); case Q_SCA: - bpf_error("SCA host filtering not implemented"); + bpf_error(cstate, "SCA host filtering not implemented"); case Q_LAT: - bpf_error("LAT host filtering not implemented"); + bpf_error(cstate, "LAT host filtering not implemented"); case Q_MOPDL: - bpf_error("MOPDL host filtering not implemented"); + bpf_error(cstate, "MOPDL host filtering not implemented"); case Q_MOPRC: - bpf_error("MOPRC host filtering not implemented"); + bpf_error(cstate, "MOPRC host filtering not implemented"); case Q_IPV6: - return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, 8, 24); + return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: - bpf_error("'icmp6' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); case Q_AH: - bpf_error("'ah' modifier applied to %s", typestr); + bpf_error(cstate, "'ah' modifier applied to %s", typestr); case Q_ESP: - bpf_error("'esp' modifier applied to %s", typestr); + bpf_error(cstate, "'esp' modifier applied to %s", typestr); case Q_ISO: - bpf_error("ISO host filtering not implemented"); + bpf_error(cstate, "ISO host filtering not implemented"); case Q_ESIS: - bpf_error("'esis' modifier applied to %s", typestr); + bpf_error(cstate, "'esis' modifier applied to %s", typestr); case Q_ISIS: - bpf_error("'isis' modifier applied to %s", typestr); + bpf_error(cstate, "'isis' modifier applied to %s", typestr); case Q_CLNP: - bpf_error("'clnp' modifier applied to %s", typestr); + bpf_error(cstate, "'clnp' modifier applied to %s", typestr); case Q_STP: - bpf_error("'stp' modifier applied to %s", typestr); + bpf_error(cstate, "'stp' modifier applied to %s", typestr); case Q_IPX: - bpf_error("IPX host filtering not implemented"); + bpf_error(cstate, "IPX host filtering not implemented"); case Q_NETBEUI: - bpf_error("'netbeui' modifier applied to %s", typestr); + bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); case Q_RADIO: - bpf_error("'radio' modifier applied to %s", typestr); + bpf_error(cstate, "'radio' modifier applied to %s", typestr); default: abort(); @@ -4686,61 +4911,54 @@ gen_gateway(eaddr, alist, proto, dir) struct block *b0, *b1, *tmp; if (dir != 0) - bpf_error("direction applied to 'gateway'"); + bpf_error(cstate, "direction applied to 'gateway'"); switch (proto) { case Q_DEFAULT: case Q_IP: case Q_ARP: case Q_RARP: - switch (linktype) { + switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - b0 = gen_ehostop(eaddr, Q_OR); + 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(eaddr, Q_OR); + b0 = gen_fhostop(cstate, eaddr, Q_OR); break; case DLT_IEEE802: - b0 = gen_thostop(eaddr, Q_OR); + 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(eaddr, Q_OR); + b0 = gen_wlanhostop(cstate, eaddr, Q_OR); break; case DLT_SUNATM: - if (!is_lane) - bpf_error( - "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); - /* - * Check that the packet doesn't begin with an - * LE Control marker. (We've already generated - * a test for LANE.) - */ - b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, - BPF_H, 0xFF00); - gen_not(b1); - /* - * Now check the MAC address. + * This is LLC-multiplexed traffic; if it were + * LANE, cstate->linktype would have been set to + * DLT_EN10MB. */ - b0 = gen_ehostop(eaddr, Q_OR); - gen_and(b1, b0); + 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(eaddr, Q_OR); + b0 = gen_ipfchostop(cstate, eaddr, Q_OR); break; default: - bpf_error( + bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); } - b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST); + b1 = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST); while (*alist) { - tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR, + tmp = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST); gen_or(b1, tmp); b1 = tmp; @@ -4749,14 +4967,13 @@ gen_gateway(eaddr, alist, proto, dir) gen_and(b0, b1); return b1; } - bpf_error("illegal modifier of 'gateway'"); + bpf_error(cstate, "illegal modifier of 'gateway'"); /* NOTREACHED */ } #endif struct block * -gen_proto_abbrev(proto) - int proto; +gen_proto_abbrev(compiler_state_t *cstate, int proto) { struct block *b0; struct block *b1; @@ -4764,25 +4981,25 @@ gen_proto_abbrev(proto) switch (proto) { case Q_SCTP: - b1 = gen_proto(IPPROTO_SCTP, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_TCP: - b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_TCP, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_TCP, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_TCP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_UDP: - b1 = gen_proto(IPPROTO_UDP, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_UDP, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_UDP, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_UDP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_ICMP: - b1 = gen_proto(IPPROTO_ICMP, Q_IP, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_IGMP @@ -4790,14 +5007,14 @@ gen_proto_abbrev(proto) #endif case Q_IGMP: - b1 = gen_proto(IPPROTO_IGMP, Q_IP, Q_DEFAULT); + 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(IPPROTO_IGRP, Q_IP, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_PIM @@ -4805,8 +5022,8 @@ gen_proto_abbrev(proto) #endif case Q_PIM: - b1 = gen_proto(IPPROTO_PIM, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_PIM, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_PIM, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; @@ -4815,7 +5032,7 @@ gen_proto_abbrev(proto) #endif case Q_VRRP: - b1 = gen_proto(IPPROTO_VRRP, Q_IP, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT); break; #ifndef IPPROTO_CARP @@ -4823,69 +5040,69 @@ gen_proto_abbrev(proto) #endif case Q_CARP: - b1 = gen_proto(IPPROTO_CARP, Q_IP, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT); break; case Q_IP: - b1 = gen_linktype(ETHERTYPE_IP); + b1 = gen_linktype(cstate, ETHERTYPE_IP); break; case Q_ARP: - b1 = gen_linktype(ETHERTYPE_ARP); + b1 = gen_linktype(cstate, ETHERTYPE_ARP); break; case Q_RARP: - b1 = gen_linktype(ETHERTYPE_REVARP); + b1 = gen_linktype(cstate, ETHERTYPE_REVARP); break; case Q_LINK: - bpf_error("link layer applied in wrong context"); + bpf_error(cstate, "link layer applied in wrong context"); case Q_ATALK: - b1 = gen_linktype(ETHERTYPE_ATALK); + b1 = gen_linktype(cstate, ETHERTYPE_ATALK); break; case Q_AARP: - b1 = gen_linktype(ETHERTYPE_AARP); + b1 = gen_linktype(cstate, ETHERTYPE_AARP); break; case Q_DECNET: - b1 = gen_linktype(ETHERTYPE_DN); + b1 = gen_linktype(cstate, ETHERTYPE_DN); break; case Q_SCA: - b1 = gen_linktype(ETHERTYPE_SCA); + b1 = gen_linktype(cstate, ETHERTYPE_SCA); break; case Q_LAT: - b1 = gen_linktype(ETHERTYPE_LAT); + b1 = gen_linktype(cstate, ETHERTYPE_LAT); break; case Q_MOPDL: - b1 = gen_linktype(ETHERTYPE_MOPDL); + b1 = gen_linktype(cstate, ETHERTYPE_MOPDL); break; case Q_MOPRC: - b1 = gen_linktype(ETHERTYPE_MOPRC); + b1 = gen_linktype(cstate, ETHERTYPE_MOPRC); break; case Q_IPV6: - b1 = gen_linktype(ETHERTYPE_IPV6); + b1 = gen_linktype(cstate, ETHERTYPE_IPV6); break; #ifndef IPPROTO_ICMPV6 #define IPPROTO_ICMPV6 58 #endif case Q_ICMPV6: - b1 = gen_proto(IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); + 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(IPPROTO_AH, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_AH, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_AH, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; @@ -4893,101 +5110,101 @@ gen_proto_abbrev(proto) #define IPPROTO_ESP 50 #endif case Q_ESP: - b1 = gen_proto(IPPROTO_ESP, Q_IP, Q_DEFAULT); - b0 = gen_proto(IPPROTO_ESP, Q_IPV6, Q_DEFAULT); + b1 = gen_proto(cstate, IPPROTO_ESP, Q_IP, Q_DEFAULT); + b0 = gen_proto(cstate, IPPROTO_ESP, Q_IPV6, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISO: - b1 = gen_linktype(LLCSAP_ISONS); + b1 = gen_linktype(cstate, LLCSAP_ISONS); break; case Q_ESIS: - b1 = gen_proto(ISO9542_ESIS, Q_ISO, Q_DEFAULT); + b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS: - b1 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); break; case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ - b0 = gen_proto(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + 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(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); - b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); - b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + 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(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + 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(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); - b0 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); - b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + 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(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + 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(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_LSP: - b0 = gen_proto(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + 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(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + 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(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); - b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); gen_or(b0, b1); break; case Q_ISIS_CSNP: - b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + 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(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); - b1 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + 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(ISO8473_CLNP, Q_ISO, Q_DEFAULT); + b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT); break; case Q_STP: - b1 = gen_linktype(LLCSAP_8021D); + b1 = gen_linktype(cstate, LLCSAP_8021D); break; case Q_IPX: - b1 = gen_linktype(LLCSAP_IPX); + b1 = gen_linktype(cstate, LLCSAP_IPX); break; case Q_NETBEUI: - b1 = gen_linktype(LLCSAP_NETBEUI); + b1 = gen_linktype(cstate, LLCSAP_NETBEUI); break; case Q_RADIO: - bpf_error("'radio' is not a valid protocol type"); + bpf_error(cstate, "'radio' is not a valid protocol type"); default: abort(); @@ -4996,14 +5213,14 @@ gen_proto_abbrev(proto) } static struct block * -gen_ipfrag() +gen_ipfrag(compiler_state_t *cstate) { struct slist *s; struct block *b; /* not IPv4 frag other than the first frag */ - s = gen_load_a(OR_NET, 6, BPF_H); - b = new_block(JMP(BPF_JSET)); + 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); @@ -5021,51 +5238,46 @@ gen_ipfrag() * headers). */ static struct block * -gen_portatom(off, v) - int off; - bpf_int32 v; +gen_portatom(compiler_state_t *cstate, int off, bpf_int32 v) { - return gen_cmp(OR_TRAN_IPV4, off, BPF_H, v); + return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v); } static struct block * -gen_portatom6(off, v) - int off; - bpf_int32 v; +gen_portatom6(compiler_state_t *cstate, int off, bpf_int32 v) { - return gen_cmp(OR_TRAN_IPV6, off, BPF_H, v); + return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v); } struct block * -gen_portop(port, proto, dir) - int port, proto, dir; +gen_portop(compiler_state_t *cstate, int port, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ - tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto); - b0 = gen_ipfrag(); + tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto); + b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: - b1 = gen_portatom(0, (bpf_int32)port); + b1 = gen_portatom(cstate, 0, (bpf_int32)port); break; case Q_DST: - b1 = gen_portatom(2, (bpf_int32)port); + b1 = gen_portatom(cstate, 2, (bpf_int32)port); break; case Q_OR: case Q_DEFAULT: - tmp = gen_portatom(0, (bpf_int32)port); - b1 = gen_portatom(2, (bpf_int32)port); + tmp = gen_portatom(cstate, 0, (bpf_int32)port); + b1 = gen_portatom(cstate, 2, (bpf_int32)port); gen_or(tmp, b1); break; case Q_AND: - tmp = gen_portatom(0, (bpf_int32)port); - b1 = gen_portatom(2, (bpf_int32)port); + tmp = gen_portatom(cstate, 0, (bpf_int32)port); + b1 = gen_portatom(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; @@ -5078,10 +5290,7 @@ gen_portop(port, proto, dir) } static struct block * -gen_port(port, ip_proto, dir) - int port; - int ip_proto; - int dir; +gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; @@ -5102,20 +5311,20 @@ gen_port(port, ip_proto, dir) * * So we always check for ETHERTYPE_IP. */ - b0 = gen_linktype(ETHERTYPE_IP); + b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - b1 = gen_portop(port, ip_proto, dir); + b1 = gen_portop(cstate, port, ip_proto, dir); break; case PROTO_UNDEF: - tmp = gen_portop(port, IPPROTO_TCP, dir); - b1 = gen_portop(port, IPPROTO_UDP, dir); + tmp = gen_portop(cstate, port, IPPROTO_TCP, dir); + b1 = gen_portop(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); - tmp = gen_portop(port, IPPROTO_SCTP, dir); + tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; @@ -5127,34 +5336,33 @@ gen_port(port, ip_proto, dir) } struct block * -gen_portop6(port, proto, dir) - int port, proto, dir; +gen_portop6(compiler_state_t *cstate, int port, int proto, int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ - b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto); + b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto); switch (dir) { case Q_SRC: - b1 = gen_portatom6(0, (bpf_int32)port); + b1 = gen_portatom6(cstate, 0, (bpf_int32)port); break; case Q_DST: - b1 = gen_portatom6(2, (bpf_int32)port); + b1 = gen_portatom6(cstate, 2, (bpf_int32)port); break; case Q_OR: case Q_DEFAULT: - tmp = gen_portatom6(0, (bpf_int32)port); - b1 = gen_portatom6(2, (bpf_int32)port); + tmp = gen_portatom6(cstate, 0, (bpf_int32)port); + b1 = gen_portatom6(cstate, 2, (bpf_int32)port); gen_or(tmp, b1); break; case Q_AND: - tmp = gen_portatom6(0, (bpf_int32)port); - b1 = gen_portatom6(2, (bpf_int32)port); + tmp = gen_portatom6(cstate, 0, (bpf_int32)port); + b1 = gen_portatom6(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; @@ -5167,28 +5375,25 @@ gen_portop6(port, proto, dir) } static struct block * -gen_port6(port, ip_proto, dir) - int port; - int ip_proto; - int dir; +gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ - b0 = gen_linktype(ETHERTYPE_IPV6); + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - b1 = gen_portop6(port, ip_proto, dir); + b1 = gen_portop6(cstate, port, ip_proto, dir); break; case PROTO_UNDEF: - tmp = gen_portop6(port, IPPROTO_TCP, dir); - b1 = gen_portop6(port, IPPROTO_UDP, dir); + tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir); + b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir); gen_or(tmp, b1); - tmp = gen_portop6(port, IPPROTO_SCTP, dir); + tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; @@ -5201,9 +5406,8 @@ gen_port6(port, ip_proto, dir) /* gen_portrange code */ static struct block * -gen_portrangeatom(off, v1, v2) - int off; - bpf_int32 v1, v2; +gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1, + bpf_int32 v2) { struct block *b1, *b2; @@ -5218,46 +5422,44 @@ gen_portrangeatom(off, v1, v2) v2 = vtemp; } - b1 = gen_cmp_ge(OR_TRAN_IPV4, off, BPF_H, v1); - b2 = gen_cmp_le(OR_TRAN_IPV4, off, BPF_H, v2); + 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); + gen_and(b1, b2); return b2; } struct block * -gen_portrangeop(port1, port2, proto, dir) - int port1, port2; - int proto; - int dir; +gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto, + int dir) { struct block *b0, *b1, *tmp; /* ip proto 'proto' and not a fragment other than the first fragment */ - tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto); - b0 = gen_ipfrag(); + tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto); + b0 = gen_ipfrag(cstate); gen_and(tmp, b0); switch (dir) { case Q_SRC: - b1 = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); break; case Q_DST: - b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; case Q_OR: case Q_DEFAULT: - tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_or(tmp, b1); break; case Q_AND: - tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2); + tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; @@ -5270,28 +5472,26 @@ gen_portrangeop(port1, port2, proto, dir) } static struct block * -gen_portrange(port1, port2, ip_proto, dir) - int port1, port2; - int ip_proto; - int dir; +gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto, + int dir) { struct block *b0, *b1, *tmp; /* link proto ip */ - b0 = gen_linktype(ETHERTYPE_IP); + b0 = gen_linktype(cstate, ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - b1 = gen_portrangeop(port1, port2, ip_proto, dir); + b1 = gen_portrangeop(cstate, port1, port2, ip_proto, dir); break; case PROTO_UNDEF: - tmp = gen_portrangeop(port1, port2, IPPROTO_TCP, dir); - b1 = gen_portrangeop(port1, port2, IPPROTO_UDP, dir); + 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(port1, port2, IPPROTO_SCTP, dir); + tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; @@ -5303,9 +5503,8 @@ gen_portrange(port1, port2, ip_proto, dir) } static struct block * -gen_portrangeatom6(off, v1, v2) - int off; - bpf_int32 v1, v2; +gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1, + bpf_int32 v2) { struct block *b1, *b2; @@ -5320,45 +5519,43 @@ gen_portrangeatom6(off, v1, v2) v2 = vtemp; } - b1 = gen_cmp_ge(OR_TRAN_IPV6, off, BPF_H, v1); - b2 = gen_cmp_le(OR_TRAN_IPV6, off, BPF_H, v2); + 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); + gen_and(b1, b2); return b2; } struct block * -gen_portrangeop6(port1, port2, proto, dir) - int port1, port2; - int proto; - int dir; +gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto, + int dir) { struct block *b0, *b1, *tmp; /* ip6 proto 'proto' */ /* XXX - catch the first fragment of a fragmented packet? */ - b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto); + b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto); switch (dir) { case Q_SRC: - b1 = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); break; case Q_DST: - b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; case Q_OR: case Q_DEFAULT: - tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_or(tmp, b1); break; case Q_AND: - tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2); + tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; @@ -5371,28 +5568,26 @@ gen_portrangeop6(port1, port2, proto, dir) } static struct block * -gen_portrange6(port1, port2, ip_proto, dir) - int port1, port2; - int ip_proto; - int dir; +gen_portrange6(compiler_state_t *cstate, int port1, int port2, int ip_proto, + int dir) { struct block *b0, *b1, *tmp; /* link proto ip6 */ - b0 = gen_linktype(ETHERTYPE_IPV6); + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - b1 = gen_portrangeop6(port1, port2, ip_proto, dir); + b1 = gen_portrangeop6(cstate, port1, port2, ip_proto, dir); break; case PROTO_UNDEF: - tmp = gen_portrangeop6(port1, port2, IPPROTO_TCP, dir); - b1 = gen_portrangeop6(port1, port2, IPPROTO_UDP, dir); + 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(port1, port2, IPPROTO_SCTP, dir); + tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir); gen_or(tmp, b1); break; @@ -5404,9 +5599,7 @@ gen_portrange6(port1, port2, ip_proto, dir) } static int -lookup_proto(name, proto) - register const char *name; - register int proto; +lookup_proto(compiler_state_t *cstate, const char *name, int proto) { register int v; @@ -5417,16 +5610,16 @@ lookup_proto(name, proto) case Q_IPV6: v = pcap_nametoproto(name); if (v == PROTO_UNDEF) - bpf_error("unknown ip proto '%s'", name); + bpf_error(cstate, "unknown ip proto '%s'", name); break; case Q_LINK: - /* XXX should look up h/w protocol type based on linktype */ + /* 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("unknown ether proto '%s'", name); + bpf_error(cstate, "unknown ether proto '%s'", name); } break; @@ -5438,7 +5631,7 @@ lookup_proto(name, proto) else if (strcmp(name, "clnp") == 0) v = ISO8473_CLNP; else - bpf_error("unknown osi proto '%s'", name); + bpf_error(cstate, "unknown osi proto '%s'", name); break; default: @@ -5459,35 +5652,32 @@ gen_joinsp(s, n) #endif static struct block * -gen_protochain(v, proto, dir) - int v; - int proto; - int dir; +gen_protochain(compiler_state_t *cstate, int v, int proto, int dir) { #ifdef NO_PROTOCHAIN - return gen_proto(v, proto, dir); + return gen_proto(cstate, v, proto, dir); #else struct block *b0, *b; struct slist *s[100]; int fix2, fix3, fix4, fix5; int ahcheck, again, end; int i, max; - int reg2 = alloc_reg(); + int reg2 = alloc_reg(cstate); memset(s, 0, sizeof(s)); - fix2 = fix3 = fix4 = fix5 = 0; + fix3 = fix4 = fix5 = 0; switch (proto) { case Q_IP: case Q_IPV6: break; case Q_DEFAULT: - b0 = gen_protochain(v, Q_IP, dir); - b = gen_protochain(v, Q_IPV6, dir); + b0 = gen_protochain(cstate, v, Q_IP, dir); + b = gen_protochain(cstate, v, Q_IPV6, dir); gen_or(b0, b); return b; default: - bpf_error("bad protocol applied for 'protochain'"); + bpf_error(cstate, "bad protocol applied for 'protochain'"); /*NOTREACHED*/ } @@ -5502,17 +5692,10 @@ gen_protochain(v, proto, dir) * branches, and backward branch support is unlikely to appear * in kernel BPF engines.) */ - switch (linktype) { - - case DLT_IEEE802_11: - case DLT_PRISM_HEADER: - case DLT_IEEE802_11_RADIO_AVS: - case DLT_IEEE802_11_RADIO: - case DLT_PPI: - bpf_error("'protochain' not supported with 802.11"); - } + if (cstate->off_linkpl.is_variable) + bpf_error(cstate, "'protochain' not supported with variable length headers"); - no_optimize = 1; /*this code is not compatible with optimzer yet */ + cstate->no_optimize = 1; /*this code is not compatible with optimzer yet */ /* * s[0] is a dummy entry to protect other BPF insn from damage @@ -5520,44 +5703,44 @@ gen_protochain(v, proto, dir) * hard to find interdependency made by jump table fixup. */ i = 0; - s[i] = new_stmt(0); /*dummy*/ + s[i] = new_stmt(cstate, 0); /*dummy*/ i++; switch (proto) { case Q_IP: - b0 = gen_linktype(ETHERTYPE_IP); + b0 = gen_linktype(cstate, ETHERTYPE_IP); /* A = ip->ip_p */ - s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); - s[i]->s.k = off_macpl + off_nl + 9; + 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(BPF_LDX|BPF_MSH|BPF_B); - s[i]->s.k = off_macpl + off_nl; + 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(ETHERTYPE_IPV6); + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); /* A = ip6->ip_nxt */ - s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); - s[i]->s.k = off_macpl + off_nl + 6; + 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(BPF_LDX|BPF_IMM); + s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM); s[i]->s.k = 40; i++; break; default: - bpf_error("unsupported proto to gen_protochain"); + bpf_error(cstate, "unsupported proto to gen_protochain"); /*NOTREACHED*/ } /* again: if (A == v) goto end; else fall through; */ again = i; - s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + 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*/ @@ -5568,7 +5751,7 @@ gen_protochain(v, proto, dir) #define IPPROTO_NONE 59 #endif /* if (A == IPPROTO_NONE) goto end */ - s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + 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; @@ -5581,26 +5764,26 @@ gen_protochain(v, proto, dir) v6start = i; /* if (A == IPPROTO_HOPOPTS) goto v6advance */ - s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + 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(BPF_JMP|BPF_JEQ|BPF_K); + 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(BPF_JMP|BPF_JEQ|BPF_K); + 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(BPF_JMP|BPF_JEQ|BPF_K); + 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; @@ -5617,39 +5800,39 @@ gen_protochain(v, proto, dir) * X = X + (P[X + packet head + 1] + 1) * 8; */ /* A = P[X + packet head] */ - s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_macpl + off_nl; + 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(BPF_ST); + s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = P[X + packet head + 1]; */ - s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_macpl + off_nl + 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(BPF_ALU|BPF_ADD|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* A *= 8 */ - s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 8; i++; /* A += X */ - s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_X); + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); s[i]->s.k = 0; i++; /* X = A; */ - s[i] = new_stmt(BPF_MISC|BPF_TAX); + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ - s[i] = new_stmt(BPF_LD|BPF_MEM); + 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(BPF_JMP|BPF_JA); + s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); s[i]->s.k = again - i - 1; s[i - 1]->s.jf = s[i]; i++; @@ -5659,7 +5842,7 @@ gen_protochain(v, proto, dir) s[j]->s.jt = s[v6advance]; } else { /* nop */ - s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; s[fix2]->s.jf = s[i]; i++; @@ -5668,7 +5851,7 @@ gen_protochain(v, proto, dir) /* ahcheck: */ ahcheck = i; /* if (A == IPPROTO_AH) then fall through; else goto end; */ - s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); + 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; @@ -5683,54 +5866,54 @@ gen_protochain(v, proto, dir) * X = X + (P[X + 1] + 2) * 4; */ /* A = X */ - s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); + s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A = P[X + packet head]; */ - s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_macpl + off_nl; + 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(BPF_ST); + s[i] = new_stmt(cstate, BPF_ST); s[i]->s.k = reg2; i++; /* A = X */ - s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); + s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); i++; /* A += 1 */ - s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; i++; /* X = A */ - s[i] = new_stmt(BPF_MISC|BPF_TAX); + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = P[X + packet head] */ - s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_macpl + off_nl; + 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(BPF_ALU|BPF_ADD|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 2; i++; /* A *= 4 */ - s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); + s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); s[i]->s.k = 4; i++; /* X = A; */ - s[i] = new_stmt(BPF_MISC|BPF_TAX); + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); i++; /* A = MEM[reg2] */ - s[i] = new_stmt(BPF_LD|BPF_MEM); + 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(BPF_JMP|BPF_JA); + 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(BPF_ALU|BPF_ADD|BPF_K); + 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]; @@ -5748,11 +5931,11 @@ gen_protochain(v, proto, dir) /* * emit final check */ - b = new_block(JMP(BPF_JEQ)); + b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s[1]; /*remember, s[0] is dummy*/ b->s.k = v; - free_reg(reg2); + free_reg(cstate, reg2); gen_and(b0, b); return b; @@ -5760,7 +5943,7 @@ gen_protochain(v, proto, dir) } static struct block * -gen_check_802_11_data_frame() +gen_check_802_11_data_frame(compiler_state_t *cstate) { struct slist *s; struct block *b0, *b1; @@ -5769,13 +5952,13 @@ gen_check_802_11_data_frame() * A data frame has the 0x08 bit (b3) in the frame control field set * and the 0x04 bit (b2) clear. */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b0 = new_block(JMP(BPF_JSET)); + 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(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + + 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); @@ -5795,10 +5978,7 @@ gen_check_802_11_data_frame() * against Q_IP and Q_IPV6. */ static struct block * -gen_proto(v, proto, dir) - int v; - int proto; - int dir; +gen_proto(compiler_state_t *cstate, int v, int proto, int dir) { struct block *b0, *b1; #ifndef CHASE_CHAIN @@ -5806,12 +5986,12 @@ gen_proto(v, proto, dir) #endif if (dir != Q_DEFAULT) - bpf_error("direction applied to 'proto'"); + bpf_error(cstate, "direction applied to 'proto'"); switch (proto) { case Q_DEFAULT: - b0 = gen_proto(v, Q_IP, dir); - b1 = gen_proto(v, Q_IPV6, dir); + b0 = gen_proto(cstate, v, Q_IP, dir); + b1 = gen_proto(cstate, v, Q_IPV6, dir); gen_or(b0, b1); return b1; @@ -5831,22 +6011,22 @@ gen_proto(v, proto, dir) * * So we always check for ETHERTYPE_IP. */ - b0 = gen_linktype(ETHERTYPE_IP); + b0 = gen_linktype(cstate, ETHERTYPE_IP); #ifndef CHASE_CHAIN - b1 = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)v); + b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)v); #else - b1 = gen_protochain(v, Q_IP); + b1 = gen_protochain(cstate, v, Q_IP); #endif gen_and(b0, b1); return b1; case Q_ISO: - switch (linktype) { + switch (cstate->linktype) { case DLT_FRELAY: /* * Frame Relay packets typically have an OSI - * NLPID at the beginning; "gen_linktype(LLCSAP_ISONS)" + * 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 @@ -5862,7 +6042,7 @@ gen_proto(v, proto, dir) * * XXX - what about SNAP-encapsulated frames? */ - return gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | v); + return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); /*NOTREACHED*/ break; @@ -5871,138 +6051,138 @@ gen_proto(v, proto, dir) * Cisco uses an Ethertype lookalike - for OSI, * it's 0xfefe. */ - b0 = gen_linktype(LLCSAP_ISONS<<8 | LLCSAP_ISONS); + b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS); /* OSI in C-HDLC is stuffed with a fudge byte */ - b1 = gen_cmp(OR_NET_NOSNAP, 1, BPF_B, (long)v); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v); gen_and(b0, b1); return b1; default: - b0 = gen_linktype(LLCSAP_ISONS); - b1 = gen_cmp(OR_NET_NOSNAP, 0, BPF_B, (long)v); + b0 = gen_linktype(cstate, LLCSAP_ISONS); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v); gen_and(b0, b1); return b1; } case Q_ISIS: - b0 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + 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(OR_NET_NOSNAP, 4, BPF_B, (long)v); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (long)v); gen_and(b0, b1); return b1; case Q_ARP: - bpf_error("arp does not encapsulate another protocol"); + bpf_error(cstate, "arp does not encapsulate another protocol"); /* NOTREACHED */ case Q_RARP: - bpf_error("rarp does not encapsulate another protocol"); + bpf_error(cstate, "rarp does not encapsulate another protocol"); /* NOTREACHED */ case Q_ATALK: - bpf_error("atalk encapsulation is not specifiable"); + bpf_error(cstate, "atalk encapsulation is not specifiable"); /* NOTREACHED */ case Q_DECNET: - bpf_error("decnet encapsulation is not specifiable"); + bpf_error(cstate, "decnet encapsulation is not specifiable"); /* NOTREACHED */ case Q_SCA: - bpf_error("sca does not encapsulate another protocol"); + bpf_error(cstate, "sca does not encapsulate another protocol"); /* NOTREACHED */ case Q_LAT: - bpf_error("lat does not encapsulate another protocol"); + bpf_error(cstate, "lat does not encapsulate another protocol"); /* NOTREACHED */ case Q_MOPRC: - bpf_error("moprc does not encapsulate another protocol"); + bpf_error(cstate, "moprc does not encapsulate another protocol"); /* NOTREACHED */ case Q_MOPDL: - bpf_error("mopdl does not encapsulate another protocol"); + bpf_error(cstate, "mopdl does not encapsulate another protocol"); /* NOTREACHED */ case Q_LINK: - return gen_linktype(v); + return gen_linktype(cstate, v); case Q_UDP: - bpf_error("'udp proto' is bogus"); + bpf_error(cstate, "'udp proto' is bogus"); /* NOTREACHED */ case Q_TCP: - bpf_error("'tcp proto' is bogus"); + bpf_error(cstate, "'tcp proto' is bogus"); /* NOTREACHED */ case Q_SCTP: - bpf_error("'sctp proto' is bogus"); + bpf_error(cstate, "'sctp proto' is bogus"); /* NOTREACHED */ case Q_ICMP: - bpf_error("'icmp proto' is bogus"); + bpf_error(cstate, "'icmp proto' is bogus"); /* NOTREACHED */ case Q_IGMP: - bpf_error("'igmp proto' is bogus"); + bpf_error(cstate, "'igmp proto' is bogus"); /* NOTREACHED */ case Q_IGRP: - bpf_error("'igrp proto' is bogus"); + bpf_error(cstate, "'igrp proto' is bogus"); /* NOTREACHED */ case Q_PIM: - bpf_error("'pim proto' is bogus"); + bpf_error(cstate, "'pim proto' is bogus"); /* NOTREACHED */ case Q_VRRP: - bpf_error("'vrrp proto' is bogus"); + bpf_error(cstate, "'vrrp proto' is bogus"); /* NOTREACHED */ case Q_CARP: - bpf_error("'carp proto' is bogus"); + bpf_error(cstate, "'carp proto' is bogus"); /* NOTREACHED */ case Q_IPV6: - b0 = gen_linktype(ETHERTYPE_IPV6); + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); #ifndef CHASE_CHAIN /* * Also check for a fragment header before the final * header. */ - b2 = gen_cmp(OR_NET, 6, BPF_B, IPPROTO_FRAGMENT); - b1 = gen_cmp(OR_NET, 40, BPF_B, (bpf_int32)v); + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); + b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v); gen_and(b2, b1); - b2 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)v); + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v); gen_or(b2, b1); #else - b1 = gen_protochain(v, Q_IPV6); + b1 = gen_protochain(cstate, v, Q_IPV6); #endif gen_and(b0, b1); return b1; case Q_ICMPV6: - bpf_error("'icmp6 proto' is bogus"); + bpf_error(cstate, "'icmp6 proto' is bogus"); case Q_AH: - bpf_error("'ah proto' is bogus"); + bpf_error(cstate, "'ah proto' is bogus"); case Q_ESP: - bpf_error("'ah proto' is bogus"); + bpf_error(cstate, "'ah proto' is bogus"); case Q_STP: - bpf_error("'stp proto' is bogus"); + bpf_error(cstate, "'stp proto' is bogus"); case Q_IPX: - bpf_error("'ipx proto' is bogus"); + bpf_error(cstate, "'ipx proto' is bogus"); case Q_NETBEUI: - bpf_error("'netbeui proto' is bogus"); + bpf_error(cstate, "'netbeui proto' is bogus"); case Q_RADIO: - bpf_error("'radio proto' is bogus"); + bpf_error(cstate, "'radio proto' is bogus"); default: abort(); @@ -6012,9 +6192,7 @@ gen_proto(v, proto, dir) } struct block * -gen_scode(name, q) - register const char *name; - struct qual q; +gen_scode(compiler_state_t *cstate, const char *name, struct qual q) { int proto = q.proto; int dir = q.dir; @@ -6039,46 +6217,49 @@ gen_scode(name, q) case Q_NET: addr = pcap_nametonetaddr(name); if (addr == 0) - bpf_error("unknown network '%s'", name); + 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(addr, mask, proto, dir, q.addr); + return gen_host(cstate, addr, mask, proto, dir, q.addr); case Q_DEFAULT: case Q_HOST: if (proto == Q_LINK) { - switch (linktype) { + switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) - bpf_error( + bpf_error(cstate, "unknown ether host '%s'", name); - b = gen_ehostop(eaddr, dir); + 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( + bpf_error(cstate, "unknown FDDI host '%s'", name); - b = gen_fhostop(eaddr, dir); + b = gen_fhostop(cstate, eaddr, dir); free(eaddr); return b; case DLT_IEEE802: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) - bpf_error( + bpf_error(cstate, "unknown token ring host '%s'", name); - b = gen_thostop(eaddr, dir); + b = gen_thostop(cstate, eaddr, dir); free(eaddr); return b; @@ -6089,63 +6270,51 @@ gen_scode(name, q) case DLT_PPI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) - bpf_error( + bpf_error(cstate, "unknown 802.11 host '%s'", name); - b = gen_wlanhostop(eaddr, dir); + 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( + bpf_error(cstate, "unknown Fibre Channel host '%s'", name); - b = gen_ipfchostop(eaddr, dir); - free(eaddr); - return b; - - case DLT_SUNATM: - if (!is_lane) - break; - - /* - * Check that the packet doesn't begin - * with an LE Control marker. (We've - * already generated a test for LANE.) - */ - tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, - BPF_H, 0xFF00); - gen_not(tmp); - - eaddr = pcap_ether_hostton(name); - if (eaddr == NULL) - bpf_error( - "unknown ether host '%s'", name); - b = gen_ehostop(eaddr, dir); - gen_and(tmp, b); + b = gen_ipfchostop(cstate, eaddr, dir); free(eaddr); return b; } - bpf_error("only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); + 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 = __pcap_nametodnaddr(name); + 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(dn_addr, 0, proto, dir, q.addr)); + return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr)); } else { #ifndef INET6 alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) - bpf_error("unknown host '%s'", name); + bpf_error(cstate, "unknown host '%s'", name); tproto = proto; - if (off_linktype == (u_int)-1 && tproto == Q_DEFAULT) + if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && + tproto == Q_DEFAULT) tproto = Q_IP; - b = gen_host(**alist++, 0xffffffff, tproto, dir, q.addr); + b = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr); while (*alist) { - tmp = gen_host(**alist++, 0xffffffff, + tmp = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr); gen_or(b, tmp); b = tmp; @@ -6155,11 +6324,12 @@ gen_scode(name, q) memset(&mask128, 0xff, sizeof(mask128)); res0 = res = pcap_nametoaddrinfo(name); if (res == NULL) - bpf_error("unknown host '%s'", name); - ai = res; + bpf_error(cstate, "unknown host '%s'", name); + cstate->ai = res; b = tmp = NULL; tproto = tproto6 = proto; - if (off_linktype == -1 && tproto == Q_DEFAULT) { + if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && + tproto == Q_DEFAULT) { tproto = Q_IP; tproto6 = Q_IPV6; } @@ -6171,7 +6341,7 @@ gen_scode(name, q) sin4 = (struct sockaddr_in *) res->ai_addr; - tmp = gen_host(ntohl(sin4->sin_addr.s_addr), + tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr), 0xffffffff, tproto, dir, q.addr); break; case AF_INET6: @@ -6180,7 +6350,7 @@ gen_scode(name, q) sin6 = (struct sockaddr_in6 *) res->ai_addr; - tmp = gen_host6(&sin6->sin6_addr, + tmp = gen_host6(cstate, &sin6->sin6_addr, &mask128, tproto6, dir, q.addr); break; default: @@ -6190,10 +6360,10 @@ gen_scode(name, q) gen_or(b, tmp); b = tmp; } - ai = NULL; + cstate->ai = NULL; freeaddrinfo(res0); if (b == NULL) { - bpf_error("unknown host '%s'%s", name, + bpf_error(cstate, "unknown host '%s'%s", name, (proto == Q_DEFAULT) ? "" : " for specified address family"); @@ -6205,124 +6375,124 @@ gen_scode(name, q) case Q_PORT: if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) - bpf_error("illegal qualifier of 'port'"); + bpf_error(cstate, "illegal qualifier of 'port'"); if (pcap_nametoport(name, &port, &real_proto) == 0) - bpf_error("unknown port '%s'", name); + bpf_error(cstate, "unknown port '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) - bpf_error("port '%s' is tcp", name); + bpf_error(cstate, "port '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) - bpf_error("port '%s' is sctp", name); + 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("port '%s' is udp", name); + bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) - bpf_error("port '%s' is sctp", name); + 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("port '%s' is udp", name); + bpf_error(cstate, "port '%s' is udp", name); else if (real_proto == IPPROTO_TCP) - bpf_error("port '%s' is tcp", name); + bpf_error(cstate, "port '%s' is tcp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_SCTP; } if (port < 0) - bpf_error("illegal port number %d < 0", port); + bpf_error(cstate, "illegal port number %d < 0", port); if (port > 65535) - bpf_error("illegal port number %d > 65535", port); - b = gen_port(port, real_proto, dir); - gen_or(gen_port6(port, real_proto, dir), b); + 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("illegal qualifier of 'portrange'"); - if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0) - bpf_error("unknown port in range '%s'", name); + 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("port in range '%s' is tcp", name); + bpf_error(cstate, "port in range '%s' is tcp", name); else if (real_proto == IPPROTO_SCTP) - bpf_error("port in range '%s' is sctp", name); + 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("port in range '%s' is udp", name); + bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_SCTP) - bpf_error("port in range '%s' is sctp", name); + 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("port in range '%s' is udp", name); + bpf_error(cstate, "port in range '%s' is udp", name); else if (real_proto == IPPROTO_TCP) - bpf_error("port in range '%s' is tcp", name); + bpf_error(cstate, "port in range '%s' is tcp", name); else /* override PROTO_UNDEF */ - real_proto = IPPROTO_SCTP; + real_proto = IPPROTO_SCTP; } if (port1 < 0) - bpf_error("illegal port number %d < 0", port1); + bpf_error(cstate, "illegal port number %d < 0", port1); if (port1 > 65535) - bpf_error("illegal port number %d > 65535", port1); + bpf_error(cstate, "illegal port number %d > 65535", port1); if (port2 < 0) - bpf_error("illegal port number %d < 0", port2); + bpf_error(cstate, "illegal port number %d < 0", port2); if (port2 > 65535) - bpf_error("illegal port number %d > 65535", port2); + bpf_error(cstate, "illegal port number %d > 65535", port2); - b = gen_portrange(port1, port2, real_proto, dir); - gen_or(gen_portrange6(port1, port2, real_proto, dir), b); + 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("unknown ether host: %s", name); + bpf_error(cstate, "unknown ether host: %s", name); alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) - bpf_error("unknown host '%s'", name); + bpf_error(cstate, "unknown host '%s'", name); b = gen_gateway(eaddr, alist, proto, dir); free(eaddr); return b; #else - bpf_error("'gateway' not supported in this configuration"); + bpf_error(cstate, "'gateway' not supported in this configuration"); #endif /*INET6*/ case Q_PROTO: - real_proto = lookup_proto(name, proto); + real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) - return gen_proto(real_proto, proto, dir); + return gen_proto(cstate, real_proto, proto, dir); else - bpf_error("unknown protocol: %s", name); + bpf_error(cstate, "unknown protocol: %s", name); case Q_PROTOCHAIN: - real_proto = lookup_proto(name, proto); + real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) - return gen_protochain(real_proto, proto, dir); + return gen_protochain(cstate, real_proto, proto, dir); else - bpf_error("unknown protocol: %s", name); + bpf_error(cstate, "unknown protocol: %s", name); case Q_UNDEF: - syntax(); + syntax(cstate); /* NOTREACHED */ } abort(); @@ -6330,10 +6500,8 @@ gen_scode(name, q) } struct block * -gen_mcode(s1, s2, masklen, q) - register const char *s1, *s2; - register int masklen; - struct qual q; +gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, + unsigned int masklen, struct qual q) { register int nlen, mlen; bpf_u_int32 n, m; @@ -6347,12 +6515,12 @@ gen_mcode(s1, s2, masklen, q) /* Promote short ipaddr */ m <<= 32 - mlen; if ((n & ~m) != 0) - bpf_error("non-network bits set in \"%s mask %s\"", + bpf_error(cstate, "non-network bits set in \"%s mask %s\"", s1, s2); } else { /* Convert mask len to mask */ if (masklen > 32) - bpf_error("mask length must be <= 32"); + bpf_error(cstate, "mask length must be <= 32"); if (masklen == 0) { /* * X << 32 is not guaranteed by C to be 0; it's @@ -6362,17 +6530,17 @@ gen_mcode(s1, s2, masklen, q) } else m = 0xffffffff << (32 - masklen); if ((n & ~m) != 0) - bpf_error("non-network bits set in \"%s/%d\"", + bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { case Q_NET: - return gen_host(n, m, q.proto, q.dir, q.addr); + return gen_host(cstate, n, m, q.proto, q.dir, q.addr); default: - bpf_error("Mask syntax for networks only"); + bpf_error(cstate, "Mask syntax for networks only"); /* NOTREACHED */ } /* NOTREACHED */ @@ -6380,10 +6548,7 @@ gen_mcode(s1, s2, masklen, q) } struct block * -gen_ncode(s, v, q) - register const char *s; - bpf_u_int32 v; - struct qual q; +gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) { bpf_u_int32 mask; int proto = q.proto; @@ -6392,9 +6557,11 @@ gen_ncode(s, v, q) if (s == NULL) vlen = 32; - else if (q.proto == Q_DECNET) + else if (q.proto == Q_DECNET) { vlen = __pcap_atodn(s, &v); - else + if (vlen == 0) + bpf_error(cstate, "malformed decnet address '%s'", s); + } else vlen = __pcap_atoin(s, &v); switch (q.addr) { @@ -6403,9 +6570,9 @@ gen_ncode(s, v, q) case Q_HOST: case Q_NET: if (proto == Q_DECNET) - return gen_host(v, 0, proto, dir, q.addr); + return gen_host(cstate, v, 0, proto, dir, q.addr); else if (proto == Q_LINK) { - bpf_error("illegal link layer address"); + bpf_error(cstate, "illegal link layer address"); } else { mask = 0xffffffff; if (s == NULL && q.addr == Q_NET) { @@ -6417,9 +6584,9 @@ gen_ncode(s, v, q) } else { /* Promote short ipaddr */ v <<= 32 - vlen; - mask <<= 32 - vlen; + mask <<= 32 - vlen ; } - return gen_host(v, mask, proto, dir, q.addr); + return gen_host(cstate, v, mask, proto, dir, q.addr); } case Q_PORT: @@ -6432,15 +6599,15 @@ gen_ncode(s, v, q) else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else - bpf_error("illegal qualifier of 'port'"); + bpf_error(cstate, "illegal qualifier of 'port'"); if (v > 65535) - bpf_error("illegal port number %u > 65535", v); + bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; - b = gen_port((int)v, proto, dir); - gen_or(gen_port6((int)v, proto, dir), b); + b = gen_port(cstate, (int)v, proto, dir); + gen_or(gen_port6(cstate, (int)v, proto, dir), b); return b; } @@ -6454,30 +6621,30 @@ gen_ncode(s, v, q) else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else - bpf_error("illegal qualifier of 'portrange'"); + bpf_error(cstate, "illegal qualifier of 'portrange'"); if (v > 65535) - bpf_error("illegal port number %u > 65535", v); + bpf_error(cstate, "illegal port number %u > 65535", v); { struct block *b; - b = gen_portrange((int)v, (int)v, proto, dir); - gen_or(gen_portrange6((int)v, (int)v, proto, dir), b); + b = gen_portrange(cstate, (int)v, (int)v, proto, dir); + gen_or(gen_portrange6(cstate, (int)v, (int)v, proto, dir), b); return b; } case Q_GATEWAY: - bpf_error("'gateway' requires a name"); + bpf_error(cstate, "'gateway' requires a name"); /* NOTREACHED */ case Q_PROTO: - return gen_proto((int)v, proto, dir); + return gen_proto(cstate, (int)v, proto, dir); case Q_PROTOCHAIN: - return gen_protochain((int)v, proto, dir); + return gen_protochain(cstate, (int)v, proto, dir); case Q_UNDEF: - syntax(); + syntax(cstate); /* NOTREACHED */ default: @@ -6489,10 +6656,8 @@ gen_ncode(s, v, q) #ifdef INET6 struct block * -gen_mcode6(s1, s2, masklen, q) - register const char *s1, *s2; - register int masklen; - struct qual q; +gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, + unsigned int masklen, struct qual q) { struct addrinfo *res; struct in6_addr *addr; @@ -6501,18 +6666,18 @@ gen_mcode6(s1, s2, masklen, q) u_int32_t *a, *m; if (s2) - bpf_error("no mask %s supported", s2); + bpf_error(cstate, "no mask %s supported", s2); res = pcap_nametoaddrinfo(s1); if (!res) - bpf_error("invalid ip6 address %s", s1); - ai = res; + bpf_error(cstate, "invalid ip6 address %s", s1); + cstate->ai = res; if (res->ai_next) - bpf_error("%s resolved to multiple address", s1); + bpf_error(cstate, "%s resolved to multiple address", s1); addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; if (sizeof(mask) * 8 < masklen) - bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); + bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); memset(&mask, 0, sizeof(mask)); memset(&mask, 0xff, masklen / 8); if (masklen % 8) { @@ -6524,7 +6689,7 @@ gen_mcode6(s1, s2, masklen, q) m = (u_int32_t *)&mask; if ((a[0] & ~m[0]) || (a[1] & ~m[1]) || (a[2] & ~m[2]) || (a[3] & ~m[3])) { - bpf_error("non-network bits set in \"%s/%d\"", s1, masklen); + bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); } switch (q.addr) { @@ -6532,17 +6697,17 @@ gen_mcode6(s1, s2, masklen, q) case Q_DEFAULT: case Q_HOST: if (masklen != 128) - bpf_error("Mask syntax for networks only"); + bpf_error(cstate, "Mask syntax for networks only"); /* FALLTHROUGH */ case Q_NET: - b = gen_host6(addr, &mask, q.proto, q.dir, q.addr); - ai = NULL; + b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr); + cstate->ai = NULL; freeaddrinfo(res); return b; default: - bpf_error("invalid qualifier against IPv6 address"); + bpf_error(cstate, "invalid qualifier against IPv6 address"); /* NOTREACHED */ } return NULL; @@ -6550,55 +6715,38 @@ gen_mcode6(s1, s2, masklen, q) #endif /*INET6*/ struct block * -gen_ecode(eaddr, q) - register const u_char *eaddr; - struct qual q; +gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) { struct block *b, *tmp; if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { - switch (linktype) { + switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - return gen_ehostop(eaddr, (int)q.dir); + tmp = gen_prevlinkhdr_check(cstate); + b = gen_ehostop(cstate, eaddr, (int)q.dir); + if (tmp != NULL) + gen_and(tmp, b); + return b; case DLT_FDDI: - return gen_fhostop(eaddr, (int)q.dir); + return gen_fhostop(cstate, eaddr, (int)q.dir); case DLT_IEEE802: - return gen_thostop(eaddr, (int)q.dir); + return gen_thostop(cstate, eaddr, (int)q.dir); 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(eaddr, (int)q.dir); - case DLT_SUNATM: - if (is_lane) { - /* - * Check that the packet doesn't begin with an - * LE Control marker. (We've already generated - * a test for LANE.) - */ - tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H, - 0xFF00); - gen_not(tmp); - - /* - * Now check the MAC address. - */ - b = gen_ehostop(eaddr, (int)q.dir); - gen_and(tmp, b); - return b; - } - break; + return gen_wlanhostop(cstate, eaddr, (int)q.dir); case DLT_IP_OVER_FC: - return gen_ipfchostop(eaddr, (int)q.dir); + return gen_ipfchostop(cstate, eaddr, (int)q.dir); default: - bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); break; } } - bpf_error("ethernet address used in non-ether expression"); + bpf_error(cstate, "ethernet address used in non-ether expression"); /* NOTREACHED */ return NULL; } @@ -6617,23 +6765,21 @@ sappend(s0, s1) } static struct slist * -xfer_to_x(a) - struct arth *a; +xfer_to_x(compiler_state_t *cstate, struct arth *a) { struct slist *s; - s = new_stmt(BPF_LDX|BPF_MEM); + s = new_stmt(cstate, BPF_LDX|BPF_MEM); s->s.k = a->regno; return s; } static struct slist * -xfer_to_a(a) - struct arth *a; +xfer_to_a(compiler_state_t *cstate, struct arth *a) { struct slist *s; - s = new_stmt(BPF_LD|BPF_MEM); + s = new_stmt(cstate, BPF_LD|BPF_MEM); s->s.k = a->regno; return s; } @@ -6646,20 +6792,17 @@ xfer_to_a(a) * for "index". */ struct arth * -gen_load(proto, inst, size) - int proto; - struct arth *inst; - int size; +gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) { struct slist *s, *tmp; struct block *b; - int regno = alloc_reg(); + int regno = alloc_reg(cstate); - free_reg(inst->regno); + free_reg(cstate, inst->regno); switch (size) { default: - bpf_error("data size must be 1, 2, or 4"); + bpf_error(cstate, "data size must be 1, 2, or 4"); case 1: size = BPF_B; @@ -6675,7 +6818,7 @@ gen_load(proto, inst, size) } switch (proto) { default: - bpf_error("unsupported index operation"); + bpf_error(cstate, "unsupported index operation"); case Q_RADIO: /* @@ -6683,21 +6826,21 @@ gen_load(proto, inst, size) * data, if we have a radio header. (If we don't, this * is an error.) */ - if (linktype != DLT_IEEE802_11_RADIO_AVS && - linktype != DLT_IEEE802_11_RADIO && - linktype != DLT_PRISM_HEADER) - bpf_error("radio information not present in capture"); + 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(inst); + s = xfer_to_x(cstate, inst); /* * Load the item at that offset. */ - tmp = new_stmt(BPF_LD|BPF_IND|size); + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); sappend(s, tmp); sappend(inst->s, s); break; @@ -6714,7 +6857,7 @@ gen_load(proto, inst, size) * frame, so that 0 refers, for Ethernet LANE, to * the beginning of the destination address? */ - s = gen_llprefixlen(); + s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr); /* * If "s" is non-null, it has code to arrange that the @@ -6726,11 +6869,11 @@ gen_load(proto, inst, size) * by "index". */ if (s != NULL) { - sappend(s, xfer_to_a(inst)); - sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); - sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + 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(inst); + s = xfer_to_x(cstate, inst); /* * Load the item at the sum of the offset we've put in the @@ -6739,8 +6882,8 @@ gen_load(proto, inst, size) * variable-length; that header length is what we put * into the X register and then added to the index). */ - tmp = new_stmt(BPF_LD|BPF_IND|size); - tmp->s.k = off_ll; + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); + tmp->s.k = cstate->off_linkhdr.constant_part; sappend(s, tmp); sappend(inst->s, s); break; @@ -6759,40 +6902,35 @@ gen_load(proto, inst, size) * The offset is relative to the beginning of * the network-layer header. * XXX - are there any cases where we want - * off_nl_nosnap? + * cstate->off_nl_nosnap? */ - s = gen_off_macpl(); + 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 offset of the MAC-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". + * 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(inst)); - sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); - sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + 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(inst); + 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 MAC-layer - * payload, and the purported offset of the start of the - * MAC-layer payload (which might be 0 if there's a - * variable-length prefix before the link-layer header - * or the link-layer header itself is variable-length; - * the variable-length offset of the start of the - * MAC-layer payload is what we put into the X register - * and then added to the index). - */ - tmp = new_stmt(BPF_LD|BPF_IND|size); - tmp->s.k = off_macpl + off_nl; + * 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); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(s, tmp); sappend(inst->s, s); @@ -6800,7 +6938,7 @@ gen_load(proto, inst, size) * Do the computation only if the packet contains * the protocol in question. */ - b = gen_proto_abbrev(proto); + b = gen_proto_abbrev(cstate, proto); if (inst->b) gen_and(inst->b, b); inst->b = b; @@ -6824,34 +6962,32 @@ gen_load(proto, inst, size) * a variable-length header), in bytes. * * XXX - are there any cases where we want - * off_nl_nosnap? + * 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(); + s = gen_loadx_iphdrlen(cstate); /* - * The X register now contains the sum of the length - * of any variable-length header preceding the link-layer - * header, any variable-length link-layer header, and the + * 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 offset of the network - * layer header relative to the beginning of - * the MAC-layer payload plus the fixed-length - * portion of the offset of the MAC-layer payload - * from the beginning of the raw packet data. - */ - sappend(s, xfer_to_a(inst)); - sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); - sappend(s, new_stmt(BPF_MISC|BPF_TAX)); - sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); - tmp->s.k = off_macpl + off_nl; + * 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)); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; sappend(inst->s, s); /* @@ -6860,18 +6996,18 @@ gen_load(proto, inst, size) * if this is an IP datagram and is the first or * only fragment of that datagram. */ - gen_and(gen_proto_abbrev(proto), b = gen_ipfrag()); + gen_and(gen_proto_abbrev(cstate, proto), b = gen_ipfrag(cstate)); if (inst->b) gen_and(inst->b, b); - gen_and(gen_proto_abbrev(Q_IP), b); + gen_and(gen_proto_abbrev(cstate, Q_IP), b); inst->b = b; break; case Q_ICMPV6: - bpf_error("IPv6 upper-layer protocol is not supported by proto[x]"); + bpf_error(cstate, "IPv6 upper-layer protocol is not supported by proto[x]"); /*NOTREACHED*/ } inst->regno = regno; - s = new_stmt(BPF_ST); + s = new_stmt(cstate, BPF_ST); s->s.k = regno; sappend(inst->s, s); @@ -6879,23 +7015,21 @@ gen_load(proto, inst, size) } struct block * -gen_relation(code, a0, a1, reversed) - int code; - struct arth *a0, *a1; - int reversed; +gen_relation(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(a1); - s1 = xfer_to_a(a0); + s0 = xfer_to_x(cstate, a1); + s1 = xfer_to_a(cstate, a0); if (code == BPF_JEQ) { - s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X); - b = new_block(JMP(code)); + s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X); + b = new_block(cstate, JMP(code)); sappend(s1, s2); } else - b = new_block(BPF_JMP|code|BPF_X); + b = new_block(cstate, BPF_JMP|code|BPF_X); if (reversed) gen_not(b); @@ -6905,8 +7039,8 @@ gen_relation(code, a0, a1, reversed) b->stmts = a0->s; - free_reg(a0->regno); - free_reg(a1->regno); + free_reg(cstate, a0->regno); + free_reg(cstate, a1->regno); /* 'and' together protocol checks */ if (a0->b) { @@ -6925,14 +7059,14 @@ gen_relation(code, a0, a1, reversed) } struct arth * -gen_loadlen() +gen_loadlen(compiler_state_t *cstate) { - int regno = alloc_reg(); - struct arth *a = (struct arth *)newchunk(sizeof(*a)); + int regno = alloc_reg(cstate); + struct arth *a = (struct arth *)newchunk(cstate, sizeof(*a)); struct slist *s; - s = new_stmt(BPF_LD|BPF_LEN); - s->next = new_stmt(BPF_ST); + 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; @@ -6941,20 +7075,19 @@ gen_loadlen() } struct arth * -gen_loadi(val) - int val; +gen_loadi(compiler_state_t *cstate, int val) { struct arth *a; struct slist *s; int reg; - a = (struct arth *)newchunk(sizeof(*a)); + a = (struct arth *)newchunk(cstate, sizeof(*a)); - reg = alloc_reg(); + reg = alloc_reg(cstate); - s = new_stmt(BPF_LD|BPF_IMM); + s = new_stmt(cstate, BPF_LD|BPF_IMM); s->s.k = val; - s->next = new_stmt(BPF_ST); + s->next = new_stmt(cstate, BPF_ST); s->next->s.k = reg; a->s = s; a->regno = reg; @@ -6963,17 +7096,16 @@ gen_loadi(val) } struct arth * -gen_neg(a) - struct arth *a; +gen_neg(compiler_state_t *cstate, struct arth *a) { struct slist *s; - s = xfer_to_a(a); + s = xfer_to_a(cstate, a); sappend(a->s, s); - s = new_stmt(BPF_ALU|BPF_NEG); + s = new_stmt(cstate, BPF_ALU|BPF_NEG); s->s.k = 0; sappend(a->s, s); - s = new_stmt(BPF_ST); + s = new_stmt(cstate, BPF_ST); s->s.k = a->regno; sappend(a->s, s); @@ -6981,65 +7113,68 @@ gen_neg(a) } struct arth * -gen_arth(code, a0, a1) - int code; - struct arth *a0, *a1; +gen_arth(compiler_state_t *cstate, int code, struct arth *a0, + struct arth *a1) { struct slist *s0, *s1, *s2; - s0 = xfer_to_x(a1); - s1 = xfer_to_a(a0); - s2 = new_stmt(BPF_ALU|BPF_X|code); + /* + * Disallow division by, or modulus by, zero; we do this here + * so that it gets done even if the optimizer is disabled. + */ + 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"); + } + 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(a0->regno); - free_reg(a1->regno); + free_reg(cstate, a0->regno); + free_reg(cstate, a1->regno); - s0 = new_stmt(BPF_ST); - a0->regno = s0->s.k = alloc_reg(); + s0 = new_stmt(cstate, BPF_ST); + a0->regno = s0->s.k = alloc_reg(cstate); sappend(a0->s, s0); return a0; } -/* - * Here we handle simple allocation of the scratch registers. - * If too many registers are alloc'd, the allocator punts. - */ -static int regused[BPF_MEMWORDS]; -static int curreg; - /* * Initialize the table of used registers and the current register. */ static void -init_regs() +init_regs(compiler_state_t *cstate) { - curreg = 0; - memset(regused, 0, sizeof regused); + cstate->curreg = 0; + memset(cstate->regused, 0, sizeof cstate->regused); } /* * Return the next free register. */ static int -alloc_reg() +alloc_reg(compiler_state_t *cstate) { int n = BPF_MEMWORDS; while (--n >= 0) { - if (regused[curreg]) - curreg = (curreg + 1) % BPF_MEMWORDS; + if (cstate->regused[cstate->curreg]) + cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS; else { - regused[curreg] = 1; - return curreg; + cstate->regused[cstate->curreg] = 1; + return cstate->curreg; } } - bpf_error("too many registers needed to evaluate expression"); + bpf_error(cstate, "too many registers needed to evaluate expression"); /* NOTREACHED */ return 0; } @@ -7049,21 +7184,19 @@ alloc_reg() * be used later. */ static void -free_reg(n) - int n; +free_reg(compiler_state_t *cstate, int n) { - regused[n] = 0; + cstate->regused[n] = 0; } static struct block * -gen_len(jmp, n) - int jmp, n; +gen_len(compiler_state_t *cstate, int jmp, int n) { struct slist *s; struct block *b; - s = new_stmt(BPF_LD|BPF_LEN); - b = new_block(JMP(jmp)); + s = new_stmt(cstate, BPF_LD|BPF_LEN); + b = new_block(cstate, JMP(jmp)); b->stmts = s; b->s.k = n; @@ -7071,22 +7204,20 @@ gen_len(jmp, n) } struct block * -gen_greater(n) - int n; +gen_greater(compiler_state_t *cstate, int n) { - return gen_len(BPF_JGE, n); + return gen_len(cstate, BPF_JGE, n); } /* * Actually, this is less than or equal. */ struct block * -gen_less(n) - int n; +gen_less(compiler_state_t *cstate, int n) { struct block *b; - b = gen_len(BPF_JGT, n); + b = gen_len(cstate, BPF_JGT, n); gen_not(b); return b; @@ -7103,8 +7234,7 @@ gen_less(n) * would generate code appropriate to the radio header in question. */ struct block * -gen_byteop(op, idx, val) - int op, idx, val; +gen_byteop(compiler_state_t *cstate, int op, int idx, int val) { struct block *b; struct slist *s; @@ -7114,87 +7244,71 @@ gen_byteop(op, idx, val) abort(); case '=': - return gen_cmp(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val); + return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); case '<': - b = gen_cmp_lt(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val); + b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); return b; case '>': - b = gen_cmp_gt(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val); + b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val); return b; case '|': - s = new_stmt(BPF_ALU|BPF_OR|BPF_K); + s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K); break; case '&': - s = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); break; } s->s.k = val; - b = new_block(JMP(BPF_JEQ)); + b = new_block(cstate, JMP(BPF_JEQ)); b->stmts = s; gen_not(b); return b; } -static u_char abroadcast[] = { 0x0 }; +static const u_char abroadcast[] = { 0x0 }; struct block * -gen_broadcast(proto) - int proto; +gen_broadcast(compiler_state_t *cstate, int proto) { bpf_u_int32 hostmask; struct block *b0, *b1, *b2; - static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; switch (proto) { case Q_DEFAULT: case Q_LINK: - switch (linktype) { + switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: - return gen_ahostop(abroadcast, Q_DST); + return gen_ahostop(cstate, abroadcast, Q_DST); case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - return gen_ehostop(ebroadcast, Q_DST); + 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(ebroadcast, Q_DST); + return gen_fhostop(cstate, ebroadcast, Q_DST); case DLT_IEEE802: - return gen_thostop(ebroadcast, Q_DST); + 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(ebroadcast, Q_DST); + return gen_wlanhostop(cstate, ebroadcast, Q_DST); case DLT_IP_OVER_FC: - return gen_ipfchostop(ebroadcast, Q_DST); - case DLT_SUNATM: - if (is_lane) { - /* - * Check that the packet doesn't begin with an - * LE Control marker. (We've already generated - * a test for LANE.) - */ - b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, - BPF_H, 0xFF00); - gen_not(b1); - - /* - * Now check the MAC address. - */ - b0 = gen_ehostop(ebroadcast, Q_DST); - gen_and(b1, b0); - return b0; - } - break; + return gen_ipfchostop(cstate, ebroadcast, Q_DST); default: - bpf_error("not a broadcast link"); + bpf_error(cstate, "not a broadcast link"); } break; @@ -7204,18 +7318,18 @@ gen_broadcast(proto) * as an indication that we don't know the netmask, and fail * in that case. */ - if (netmask == PCAP_NETMASK_UNKNOWN) - bpf_error("netmask not known, so 'ip broadcast' not supported"); - b0 = gen_linktype(ETHERTYPE_IP); - hostmask = ~netmask; - b1 = gen_mcmp(OR_NET, 16, BPF_W, (bpf_int32)0, hostmask); - b2 = gen_mcmp(OR_NET, 16, BPF_W, + 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, (bpf_int32)0, hostmask); + b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)(~0 & hostmask), hostmask); gen_or(b1, b2); gen_and(b0, b2); return b2; } - bpf_error("only link-layer/IP broadcast filters supported"); + bpf_error(cstate, "only link-layer/IP broadcast filters supported"); /* NOTREACHED */ return NULL; } @@ -7225,23 +7339,21 @@ gen_broadcast(proto) * the bottom bit of the *first* byte). */ static struct block * -gen_mac_multicast(offset) - int offset; +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(OR_LINK, offset, BPF_B); - b0 = new_block(JMP(BPF_JSET)); + 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(proto) - int proto; +gen_multicast(compiler_state_t *cstate, int proto) { register struct block *b0, *b1, *b2; register struct slist *s; @@ -7250,16 +7362,20 @@ gen_multicast(proto) case Q_DEFAULT: case Q_LINK: - switch (linktype) { + switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: /* all ARCnet multicasts use the same address */ - return gen_ahostop(abroadcast, Q_DST); + 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 */ - return gen_mac_multicast(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 @@ -7267,10 +7383,10 @@ gen_multicast(proto) * XXX - was that referring to bit-order issues? */ /* fddi[1] & 1 != 0 */ - return gen_mac_multicast(1); + return gen_mac_multicast(cstate, 1); case DLT_IEEE802: /* tr[2] & 1 != 0 */ - return gen_mac_multicast(2); + return gen_mac_multicast(cstate, 2); case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: @@ -7297,23 +7413,23 @@ gen_multicast(proto) * * First, check for To DS set, i.e. "link[1] & 0x01". */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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(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(OR_LINK, 1, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -7321,7 +7437,7 @@ gen_multicast(proto) /* * If To DS is not set, the DA is at 4. */ - b1 = gen_mac_multicast(4); + b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* @@ -7334,8 +7450,8 @@ gen_multicast(proto) * Now check for a data frame. * I.e, check "link[0] & 0x08". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; @@ -7349,8 +7465,8 @@ gen_multicast(proto) * is a management frame. * I.e, check "!(link[0] & 0x08)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b2 = new_block(JMP(BPF_JSET)); + 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); @@ -7358,7 +7474,7 @@ gen_multicast(proto) /* * For management frames, the DA is at 4. */ - b1 = gen_mac_multicast(4); + b1 = gen_mac_multicast(cstate, 4); gen_and(b2, b1); /* @@ -7376,8 +7492,8 @@ gen_multicast(proto) * * I.e., check "!(link[0] & 0x04)". */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); + 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); @@ -7389,25 +7505,8 @@ gen_multicast(proto) gen_and(b1, b0); return b0; case DLT_IP_OVER_FC: - b0 = gen_mac_multicast(2); + b0 = gen_mac_multicast(cstate, 2); return b0; - case DLT_SUNATM: - if (is_lane) { - /* - * Check that the packet doesn't begin with an - * LE Control marker. (We've already generated - * a test for LANE.) - */ - b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, - BPF_H, 0xFF00); - gen_not(b1); - - /* ether[off_mac] & 1 != 0 */ - b0 = gen_mac_multicast(off_mac); - gen_and(b1, b0); - return b0; - } - break; default: break; } @@ -7415,18 +7514,18 @@ gen_multicast(proto) break; case Q_IP: - b0 = gen_linktype(ETHERTYPE_IP); - b1 = gen_cmp_ge(OR_NET, 16, BPF_B, (bpf_int32)224); + b0 = gen_linktype(cstate, ETHERTYPE_IP); + b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, (bpf_int32)224); gen_and(b0, b1); return b1; case Q_IPV6: - b0 = gen_linktype(ETHERTYPE_IPV6); - b1 = gen_cmp(OR_NET, 24, BPF_B, (bpf_int32)255); + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, (bpf_int32)255); gen_and(b0, b1); return b1; } - bpf_error("link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); + bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); /* NOTREACHED */ return NULL; } @@ -7441,35 +7540,34 @@ gen_multicast(proto) * better accomplished using a higher-layer filter. */ struct block * -gen_inbound(dir) - int dir; +gen_inbound(compiler_state_t *cstate, int dir) { register struct block *b0; /* * Only some data link types support inbound/outbound qualifiers. */ - switch (linktype) { + switch (cstate->linktype) { case DLT_SLIP: - b0 = gen_relation(BPF_JEQ, - gen_load(Q_LINK, gen_loadi(0), 1), - gen_loadi(0), + b0 = gen_relation(cstate, BPF_JEQ, + gen_load(cstate, Q_LINK, gen_loadi(cstate, 0), 1), + gen_loadi(cstate, 0), dir); break; case DLT_IPNET: if (dir) { /* match outgoing packets */ - b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_OUTBOUND); + b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND); } else { /* match incoming packets */ - b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_INBOUND); + b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND); } break; case DLT_LINUX_SLL: /* match outgoing packets */ - b0 = gen_cmp(OR_LINK, 0, BPF_H, LINUX_SLL_OUTGOING); + 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); @@ -7478,7 +7576,7 @@ gen_inbound(dir) #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: - b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, dir), BPF_B, + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, (bpf_int32)((dir == 0) ? PF_IN : PF_OUT)); break; #endif @@ -7486,10 +7584,10 @@ gen_inbound(dir) case DLT_PPP_PPPD: if (dir) { /* match outgoing packets */ - b0 = gen_cmp(OR_LINK, 0, BPF_B, PPP_PPPD_OUT); + b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT); } else { /* match incoming packets */ - b0 = gen_cmp(OR_LINK, 0, BPF_B, PPP_PPPD_IN); + b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN); } break; @@ -7520,10 +7618,10 @@ gen_inbound(dir) * the byte after the 3-byte magic number */ if (dir) { /* match outgoing packets */ - b0 = gen_mcmp(OR_LINK, 3, BPF_B, 0, 0x01); + b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01); } else { /* match incoming packets */ - b0 = gen_mcmp(OR_LINK, 3, BPF_B, 1, 0x01); + b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01); } break; @@ -7533,33 +7631,33 @@ gen_inbound(dir) * check it, otherwise give up as this link-layer type * has nothing in the packet data. */ -#if defined(PF_PACKET) && defined(SO_ATTACH_FILTER) +#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) /* - * We infer that this is Linux with PF_PACKET support. + * This is Linux with 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 (bpf_pcap->sf.rfile != NULL) { + if (cstate->bpf_pcap->rfile != NULL) { /* We have a FILE *, so this is a savefile */ - bpf_error("inbound/outbound not supported on linktype %d when reading savefiles", - linktype); + bpf_error(cstate, "inbound/outbound not supported on linktype %d when reading savefiles", + cstate->linktype); b0 = NULL; /* NOTREACHED */ } /* match outgoing packets */ - b0 = gen_cmp(OR_LINK, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, + 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(PF_PACKET) && defined(SO_ATTACH_FILTER) */ - bpf_error("inbound/outbound not supported on linktype %d", - linktype); +#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ + bpf_error(cstate, "inbound/outbound not supported on linktype %d", + cstate->linktype); b0 = NULL; /* NOTREACHED */ -#endif /* defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ +#endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ } return (b0); } @@ -7567,156 +7665,156 @@ gen_inbound(dir) #ifdef HAVE_NET_PFVAR_H /* PF firewall log matched interface */ struct block * -gen_pf_ifname(const char *ifname) +gen_pf_ifname(compiler_state_t *cstate, const char *ifname) { struct block *b0; u_int len, off; - if (linktype != DLT_PFLOG) { - bpf_error("ifname supported only on PF linktype"); + 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("ifname interface names can only be %d characters", + bpf_error(cstate, "ifname interface names can only be %d characters", len-1); /* NOTREACHED */ } - b0 = gen_bcmp(OR_LINK, off, strlen(ifname), (const u_char *)ifname); + b0 = gen_bcmp(cstate, OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname); return (b0); } /* PF firewall log ruleset name */ struct block * -gen_pf_ruleset(char *ruleset) +gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { struct block *b0; - if (linktype != DLT_PFLOG) { - bpf_error("ruleset supported only on PF linktype"); + 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("ruleset names can only be %ld characters", + bpf_error(cstate, "ruleset names can only be %ld characters", (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); /* NOTREACHED */ } - b0 = gen_bcmp(OR_LINK, offsetof(struct pfloghdr, ruleset), + b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset), strlen(ruleset), (const u_char *)ruleset); return (b0); } /* PF firewall log rule number */ struct block * -gen_pf_rnr(int rnr) +gen_pf_rnr(compiler_state_t *cstate, int rnr) { struct block *b0; - if (linktype != DLT_PFLOG) { - bpf_error("rnr supported only on PF linktype"); + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "rnr supported only on PF linktype"); /* NOTREACHED */ } - b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W, + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, (bpf_int32)rnr); return (b0); } /* PF firewall log sub-rule number */ struct block * -gen_pf_srnr(int srnr) +gen_pf_srnr(compiler_state_t *cstate, int srnr) { struct block *b0; - if (linktype != DLT_PFLOG) { - bpf_error("srnr supported only on PF linktype"); + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "srnr supported only on PF linktype"); /* NOTREACHED */ } - b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, subrulenr), BPF_W, + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, (bpf_int32)srnr); return (b0); } /* PF firewall log reason code */ struct block * -gen_pf_reason(int reason) +gen_pf_reason(compiler_state_t *cstate, int reason) { struct block *b0; - if (linktype != DLT_PFLOG) { - bpf_error("reason supported only on PF linktype"); + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "reason supported only on PF linktype"); /* NOTREACHED */ } - b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B, + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, (bpf_int32)reason); return (b0); } /* PF firewall log action */ struct block * -gen_pf_action(int action) +gen_pf_action(compiler_state_t *cstate, int action) { struct block *b0; - if (linktype != DLT_PFLOG) { - bpf_error("action supported only on PF linktype"); + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "action supported only on PF linktype"); /* NOTREACHED */ } - b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B, + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, (bpf_int32)action); return (b0); } #else /* !HAVE_NET_PFVAR_H */ struct block * -gen_pf_ifname(const char *ifname) +gen_pf_ifname(compiler_state_t *cstate, const char *ifname) { - bpf_error("libpcap was compiled without pf support"); + bpf_error(cstate, "libpcap was compiled without pf support"); /* NOTREACHED */ return (NULL); } struct block * -gen_pf_ruleset(char *ruleset) +gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * -gen_pf_rnr(int rnr) +gen_pf_rnr(compiler_state_t *cstate, int rnr) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * -gen_pf_srnr(int srnr) +gen_pf_srnr(compiler_state_t *cstate, int srnr) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * -gen_pf_reason(int reason) +gen_pf_reason(compiler_state_t *cstate, int reason) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } struct block * -gen_pf_action(int action) +gen_pf_action(compiler_state_t *cstate, int action) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ return (NULL); } @@ -7724,22 +7822,22 @@ gen_pf_action(int action) /* IEEE 802.11 wireless header */ struct block * -gen_p80211_type(int type, int mask) +gen_p80211_type(compiler_state_t *cstate, int type, int mask) { struct block *b0; - switch (linktype) { + 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(OR_LINK, 0, BPF_B, (bpf_int32)type, + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, (bpf_int32)type, (bpf_int32)mask); break; default: - bpf_error("802.11 link-layer types supported only on 802.11"); + bpf_error(cstate, "802.11 link-layer types supported only on 802.11"); /* NOTREACHED */ } @@ -7747,11 +7845,11 @@ gen_p80211_type(int type, int mask) } struct block * -gen_p80211_fcdir(int fcdir) +gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) { struct block *b0; - switch (linktype) { + switch (cstate->linktype) { case DLT_IEEE802_11: case DLT_PRISM_HEADER: @@ -7760,111 +7858,175 @@ gen_p80211_fcdir(int fcdir) break; default: - bpf_error("frame direction supported only with 802.11 headers"); + bpf_error(cstate, "frame direction supported only with 802.11 headers"); /* NOTREACHED */ } - b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir, + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir, (bpf_u_int32)IEEE80211_FC1_DIR_MASK); return (b0); } struct block * -gen_acode(eaddr, q) - register const u_char *eaddr; - struct qual q; +gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) { - switch (linktype) { + switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) - return (gen_ahostop(eaddr, (int)q.dir)); + return (gen_ahostop(cstate, eaddr, (int)q.dir)); else { - bpf_error("ARCnet address used in non-arc expression"); + bpf_error(cstate, "ARCnet address used in non-arc expression"); /* NOTREACHED */ } break; default: - bpf_error("aid supported only on ARCnet"); + bpf_error(cstate, "aid supported only on ARCnet"); /* NOTREACHED */ } - bpf_error("ARCnet address used in non-arc expression"); + bpf_error(cstate, "ARCnet address used in non-arc expression"); /* NOTREACHED */ return NULL; } static struct block * -gen_ahostop(eaddr, dir) - register const u_char *eaddr; - register int dir; +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(OR_LINK, 0, 1, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr); case Q_DST: - return gen_bcmp(OR_LINK, 1, 1, eaddr); + return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr); case Q_AND: - b0 = gen_ahostop(eaddr, Q_SRC); - b1 = gen_ahostop(eaddr, Q_DST); + 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(eaddr, Q_SRC); - b1 = gen_ahostop(eaddr, Q_DST); + 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("'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' is only supported on 802.11"); break; case Q_ADDR2: - bpf_error("'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' is only supported on 802.11"); break; case Q_ADDR3: - bpf_error("'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' is only supported on 802.11"); break; case Q_ADDR4: - bpf_error("'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' is only supported on 802.11"); break; case Q_RA: - bpf_error("'ra' is only supported on 802.11"); + bpf_error(cstate, "'ra' is only supported on 802.11"); break; case Q_TA: - bpf_error("'ta' is only supported on 802.11"); + bpf_error(cstate, "'ta' is only supported on 802.11"); break; } abort(); /* NOTREACHED */ } +#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) +static struct block * +gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) +{ + struct block *b0, *b1; + 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; + + if (vlan_num >= 0) { + s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; + + b1 = new_block(cstate, JMP(BPF_JEQ)); + b1->stmts = s; + b1->s.k = (bpf_int32) vlan_num; + + gen_and(b0,b1); + b0 = b1; + } + + return b0; +} +#endif + +static struct block * +gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num) +{ + struct block *b0, *b1; + + /* check for VLAN, including 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); + b0 = b1; + + /* If a specific VLAN is requested, check VLAN id */ + if (vlan_num >= 0) { + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, + (bpf_int32)vlan_num, 0x0fff); + gen_and(b0, b1); + b0 = b1; + } + + /* + * The payload follows the full header, including the + * VLAN tags, so skip past this VLAN tag. + */ + cstate->off_linkpl.constant_part += 4; + + /* + * The link-layer type information follows the VLAN tags, so + * skip past this VLAN tag. + */ + cstate->off_linktype.constant_part += 4; + + return b0; +} + /* * support IEEE 802.1Q VLAN trunk over ethernet */ struct block * -gen_vlan(vlan_num) - int vlan_num; +gen_vlan(compiler_state_t *cstate, int vlan_num) { - struct block *b0, *b1; + struct block *b0; /* can't check for VLAN-encapsulated packets inside MPLS */ - if (label_stack_depth > 0) - bpf_error("no VLAN match after 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 @@ -7897,43 +8059,44 @@ gen_vlan(vlan_num) * be done assuming a VLAN, even though the "or" could be viewed * as meaning "or, if this isn't a VLAN packet...". */ - orig_nl = off_nl; - - switch (linktype) { + switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - /* check for VLAN, including QinQ */ - b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)ETHERTYPE_8021Q); - b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, - (bpf_int32)ETHERTYPE_8021QINQ); - gen_or(b0,b1); - b0 = b1; - - /* If a specific VLAN is requested, check VLAN id */ - if (vlan_num >= 0) { - b1 = gen_mcmp(OR_MACPL, 0, BPF_H, - (bpf_int32)vlan_num, 0x0fff); - gen_and(b0, b1); - b0 = b1; - } - - off_macpl += 4; - off_linktype += 4; -#if 0 - off_nl_nosnap += 4; - off_nl += 4; +#if defined(SKF_AD_VLAN_TAG) && 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); + else + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); + } else #endif + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); + 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); break; default: - bpf_error("no VLAN support for data link type %d", - linktype); + bpf_error(cstate, "no VLAN support for data link type %d", + cstate->linktype); /*NOTREACHED*/ } + cstate->vlan_stack_depth++; + return (b0); } @@ -7941,52 +8104,38 @@ gen_vlan(vlan_num) * support for MPLS */ struct block * -gen_mpls(label_num) - int label_num; +gen_mpls(compiler_state_t *cstate, int label_num) { - struct block *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. - * - * XXX - this is a bit of a kludge. See comments in gen_vlan(). - */ - orig_nl = off_nl; + struct block *b0, *b1; - if (label_stack_depth > 0) { + if (cstate->label_stack_depth > 0) { /* just match the bottom-of-stack bit clear */ - b0 = gen_mcmp(OR_MACPL, orig_nl-2, BPF_B, 0, 0x01); + b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); } else { /* - * Indicate 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. + * We're not in an MPLS stack yet, so check the link-layer + * type against MPLS. */ - switch (linktype) { - + switch (cstate->linktype) { + case DLT_C_HDLC: /* fall through */ case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: - b0 = gen_linktype(ETHERTYPE_MPLS); + b0 = gen_linktype(cstate, ETHERTYPE_MPLS); break; - + case DLT_PPP: - b0 = gen_linktype(PPP_MPLS_UCAST); + 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("no MPLS support for data link type %d", - linktype); + bpf_error(cstate, "no MPLS support for data link type %d", + cstate->linktype); b0 = NULL; /*NOTREACHED*/ break; @@ -7996,15 +8145,29 @@ gen_mpls(label_num) /* If a specific MPLS label is requested, check it */ if (label_num >= 0) { label_num = label_num << 12; /* label is shifted 12 bits on the wire */ - b1 = gen_mcmp(OR_MACPL, orig_nl, BPF_W, (bpf_int32)label_num, + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ gen_and(b0, b1); b0 = b1; } - off_nl_nosnap += 4; - off_nl += 4; - label_stack_depth++; + /* + * 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); } @@ -8012,21 +8175,29 @@ gen_mpls(label_num) * Support PPPOE discovery and session. */ struct block * -gen_pppoed() +gen_pppoed(compiler_state_t *cstate) { /* check for PPPoE discovery */ - return gen_linktype((bpf_int32)ETHERTYPE_PPPOED); + return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED); } struct block * -gen_pppoes() +gen_pppoes(compiler_state_t *cstate, int sess_num) { - struct block *b0; + struct block *b0, *b1; /* * Test against the PPPoE session link-layer type. */ - b0 = gen_linktype((bpf_int32)ETHERTYPE_PPPOES); + b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES); + + /* If a specific session is requested, check PPPoE session id */ + if (sess_num >= 0) { + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, + (bpf_int32)sess_num, 0x0000ffff); + gen_and(b0, b1); + b0 = b1; + } /* * Change the offsets to point to the type and data fields within @@ -8056,12 +8227,7 @@ gen_pppoes() * as all the "or ..." tests would be done assuming PPPoE, even * though the "or" could be viewed as meaning "or, if this isn't * a PPPoE packet...". - */ - orig_linktype = off_linktype; /* save original values */ - orig_nl = off_nl; - is_pppoes = 1; - - /* + * * The "network-layer" protocol is PPPoE, which has a 6-byte * PPPoE header, followed by a PPP packet. * @@ -8070,70 +8236,362 @@ gen_pppoes() * 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 off_nl. + * it's 6 bytes past cstate->off_nl. */ - off_linktype = off_nl + 6; + 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); - /* - * The network-layer offsets are relative to the beginning - * of the MAC-layer payload; that's past the 6-byte - * PPPoE header and the 2-byte PPP header. - */ - off_nl = 6+2; - off_nl_nosnap = 6+2; + 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 *, int, int, int), + enum e_offrel offrel, int 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, (bpf_int32)0, 0xc0); + gen_and(b0, b1); + b0 = b1; + + if (vni >= 0) { + vni <<= 8; /* VNI is in the upper 3 bytes */ + b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)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, int vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, 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, int vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, 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, int vni) +{ + struct block *b0, *b1; + struct slist *s; + + b0 = gen_geneve4(cstate, vni); + b1 = gen_geneve6(cstate, 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; } struct block * -gen_atmfield_code(atmfield, jvalue, jtype, reverse) - int atmfield; - bpf_int32 jvalue; - bpf_u_int32 jtype; - int reverse; +gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, + bpf_u_int32 jtype, int reverse) { struct block *b0; switch (atmfield) { case A_VPI: - if (!is_atm) - bpf_error("'vpi' supported only on raw ATM"); - if (off_vpi == (u_int)-1) + if (!cstate->is_atm) + bpf_error(cstate, "'vpi' supported only on raw ATM"); + if (cstate->off_vpi == (u_int)-1) abort(); - b0 = gen_ncmp(OR_LINK, off_vpi, BPF_B, 0xffffffff, jtype, + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; case A_VCI: - if (!is_atm) - bpf_error("'vci' supported only on raw ATM"); - if (off_vci == (u_int)-1) + if (!cstate->is_atm) + bpf_error(cstate, "'vci' supported only on raw ATM"); + if (cstate->off_vci == (u_int)-1) abort(); - b0 = gen_ncmp(OR_LINK, off_vci, BPF_H, 0xffffffff, jtype, + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype, reverse, jvalue); break; case A_PROTOTYPE: - if (off_proto == (u_int)-1) + if (cstate->off_proto == (u_int)-1) abort(); /* XXX - this isn't on FreeBSD */ - b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0x0f, jtype, + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype, reverse, jvalue); break; case A_MSGTYPE: - if (off_payload == (u_int)-1) + if (cstate->off_payload == (u_int)-1) abort(); - b0 = gen_ncmp(OR_LINK, off_payload + MSG_TYPE_POS, BPF_B, + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; case A_CALLREFTYPE: - if (!is_atm) - bpf_error("'callref' supported only on raw ATM"); - if (off_proto == (u_int)-1) + if (!cstate->is_atm) + bpf_error(cstate, "'callref' supported only on raw ATM"); + if (cstate->off_proto == (u_int)-1) abort(); - b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0xffffffff, + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff, jtype, reverse, jvalue); break; @@ -8144,8 +8602,7 @@ gen_atmfield_code(atmfield, jvalue, jtype, reverse) } struct block * -gen_atmtype_abbrev(type) - int type; +gen_atmtype_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; @@ -8153,63 +8610,63 @@ gen_atmtype_abbrev(type) case A_METAC: /* Get all packets in Meta signalling Circuit */ - if (!is_atm) - bpf_error("'metac' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 1, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'metac' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 1, BPF_JEQ, 0); gen_and(b0, b1); break; case A_BCC: /* Get all packets in Broadcast Circuit*/ - if (!is_atm) - bpf_error("'bcc' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 2, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'bcc' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 2, BPF_JEQ, 0); gen_and(b0, b1); break; case A_OAMF4SC: /* Get all cells in Segment OAM F4 circuit*/ - if (!is_atm) - bpf_error("'oam4sc' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'oam4sc' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(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 (!is_atm) - bpf_error("'oam4ec' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'oam4ec' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); gen_and(b0, b1); break; case A_SC: /* Get all packets in connection Signalling Circuit */ - if (!is_atm) - bpf_error("'sc' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 5, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'sc' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 5, BPF_JEQ, 0); gen_and(b0, b1); break; case A_ILMIC: /* Get all packets in ILMI Circuit */ - if (!is_atm) - bpf_error("'ilmic' supported only on raw ATM"); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 16, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'ilmic' supported only on raw ATM"); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 16, BPF_JEQ, 0); gen_and(b0, b1); break; case A_LANE: /* Get all LANE packets */ - if (!is_atm) - bpf_error("'lane' supported only on raw ATM"); - b1 = gen_atmfield_code(A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); + if (!cstate->is_atm) + bpf_error(cstate, "'lane' supported only on raw ATM"); + b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); /* * Arrange that all subsequent tests assume LANE @@ -8217,26 +8674,23 @@ gen_atmtype_abbrev(type) * the offsets appropriately for LANE-encapsulated * Ethernet. * - * "off_mac" is the offset of the Ethernet header, - * which is 2 bytes past the ATM pseudo-header - * (skipping the pseudo-header and 2-byte LE Client - * field). The other offsets are Ethernet offsets - * relative to "off_mac". + * We assume LANE means Ethernet, not Token Ring. */ - is_lane = 1; - off_mac = off_payload + 2; /* MAC header */ - off_linktype = off_mac + 12; - off_macpl = off_mac + 14; /* Ethernet */ - off_nl = 0; /* Ethernet II */ - off_nl_nosnap = 3; /* 802.3+802.2 */ + 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 (!is_atm) - bpf_error("'llc' supported only on raw ATM"); - b1 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); - is_lane = 0; + if (!cstate->is_atm) + bpf_error(cstate, "'llc' supported only on raw ATM"); + b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + cstate->linktype = cstate->prevlinktype; break; default: @@ -8245,45 +8699,72 @@ gen_atmtype_abbrev(type) 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(type) - int type; +gen_mtp2type_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; switch (type) { case M_FISU: - if ( (linktype != DLT_MTP2) && - (linktype != DLT_ERF) && - (linktype != DLT_MTP2_WITH_PHDR) ) - bpf_error("'fisu' supported only on MTP2"); - /* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */ - b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0); + 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, 0x3f, BPF_JEQ, 0, 0); break; case M_LSSU: - if ( (linktype != DLT_MTP2) && - (linktype != DLT_ERF) && - (linktype != DLT_MTP2_WITH_PHDR) ) - bpf_error("'lssu' supported only on MTP2"); - b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 1, 2); - b1 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 0); + 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, 0x3f, BPF_JGT, 1, 2); + b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 0); gen_and(b1, b0); break; case M_MSU: - if ( (linktype != DLT_MTP2) && - (linktype != DLT_ERF) && - (linktype != DLT_MTP2_WITH_PHDR) ) - bpf_error("'msu' supported only on MTP2"); - b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 2); + 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, 0x3f, BPF_JGT, 0, 2); + 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, 0xff80, BPF_JEQ, 0, 0); + 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, 0xff80, BPF_JGT, 1, 0x0100); + b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0); + 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, 0xff80, BPF_JGT, 0, 0x0100); break; default: @@ -8293,34 +8774,41 @@ gen_mtp2type_abbrev(type) } struct block * -gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) - int mtp3field; - bpf_u_int32 jvalue; - bpf_u_int32 jtype; - int reverse; +gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, + bpf_u_int32 jtype, int reverse) { struct block *b0; bpf_u_int32 val1 , val2 , val3; + u_int newoff_sio = cstate->off_sio; + u_int newoff_opc = cstate->off_opc; + u_int newoff_dpc = cstate->off_dpc; + u_int newoff_sls = cstate->off_sls; switch (mtp3field) { + case MH_SIO: + newoff_sio += 3; /* offset for MTP2_HSL */ + /* FALLTHROUGH */ + case M_SIO: - if (off_sio == (u_int)-1) - bpf_error("'sio' supported only on SS7"); + if (cstate->off_sio == (u_int)-1) + bpf_error(cstate, "'sio' supported only on SS7"); /* sio coded on 1 byte so max value 255 */ if(jvalue > 255) - bpf_error("sio value %u too big; max value = 255", + bpf_error(cstate, "sio value %u too big; max value = 255", jvalue); - b0 = gen_ncmp(OR_PACKET, off_sio, BPF_B, 0xffffffff, + b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffff, (u_int)jtype, reverse, (u_int)jvalue); break; + case MH_OPC: + newoff_opc+=3; case M_OPC: - if (off_opc == (u_int)-1) - bpf_error("'opc' supported only on SS7"); + if (cstate->off_opc == (u_int)-1) + bpf_error(cstate, "'opc' supported only on SS7"); /* opc coded on 14 bits so max value 16383 */ if (jvalue > 16383) - bpf_error("opc value %u too big; max value = 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*/ @@ -8331,16 +8819,20 @@ gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) val3 = jvalue & 0x00000003; val3 = val3 <<22; jvalue = val1 + val2 + val3; - b0 = gen_ncmp(OR_PACKET, off_opc, BPF_W, 0x00c0ff0f, + b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f, (u_int)jtype, reverse, (u_int)jvalue); break; + case MH_DPC: + newoff_dpc += 3; + /* FALLTHROUGH */ + case M_DPC: - if (off_dpc == (u_int)-1) - bpf_error("'dpc' supported only on SS7"); + if (cstate->off_dpc == (u_int)-1) + bpf_error(cstate, "'dpc' supported only on SS7"); /* dpc coded on 14 bits so max value 16383 */ if (jvalue > 16383) - bpf_error("dpc value %u too big; max value = 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*/ @@ -8349,21 +8841,23 @@ gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) val2 = jvalue & 0x00003f00; val2 = val2 << 8; jvalue = val1 + val2; - b0 = gen_ncmp(OR_PACKET, off_dpc, BPF_W, 0xff3f0000, + b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000, (u_int)jtype, reverse, (u_int)jvalue); break; + case MH_SLS: + newoff_sls+=3; case M_SLS: - if (off_sls == (u_int)-1) - bpf_error("'sls' supported only on SS7"); + if (cstate->off_sls == (u_int)-1) + bpf_error(cstate, "'sls' supported only on SS7"); /* sls coded on 4 bits so max value 15 */ if (jvalue > 15) - bpf_error("sls value %u too big; max value = 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(OR_PACKET, off_sls, BPF_B, 0xf0, + b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0, (u_int)jtype,reverse, (u_int)jvalue); break; @@ -8374,8 +8868,7 @@ gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) } static struct block * -gen_msg_abbrev(type) - int type; +gen_msg_abbrev(compiler_state_t *cstate, int type) { struct block *b1; @@ -8386,27 +8879,27 @@ gen_msg_abbrev(type) switch (type) { case A_SETUP: - b1 = gen_atmfield_code(A_MSGTYPE, SETUP, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); break; case A_CALLPROCEED: - b1 = gen_atmfield_code(A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); break; case A_CONNECT: - b1 = gen_atmfield_code(A_MSGTYPE, CONNECT, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); break; case A_CONNECTACK: - b1 = gen_atmfield_code(A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); break; case A_RELEASE: - b1 = gen_atmfield_code(A_MSGTYPE, RELEASE, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); break; case A_RELEASE_DONE: - b1 = gen_atmfield_code(A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); break; default: @@ -8416,27 +8909,26 @@ gen_msg_abbrev(type) } struct block * -gen_atmmulti_abbrev(type) - int type; +gen_atmmulti_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; switch (type) { case A_OAM: - if (!is_atm) - bpf_error("'oam' supported only on raw ATM"); - b1 = gen_atmmulti_abbrev(A_OAMF4); + if (!cstate->is_atm) + bpf_error(cstate, "'oam' supported only on raw ATM"); + b1 = gen_atmmulti_abbrev(cstate, A_OAMF4); break; case A_OAMF4: - if (!is_atm) - bpf_error("'oamf4' supported only on raw ATM"); + if (!cstate->is_atm) + bpf_error(cstate, "'oamf4' supported only on raw ATM"); /* OAM F4 type */ - b0 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); - b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + b0 = gen_atmfield_code(cstate, A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); gen_or(b0, b1); - b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -8445,36 +8937,36 @@ gen_atmmulti_abbrev(type) * Get Q.2931 signalling messages for switched * virtual connection */ - if (!is_atm) - bpf_error("'connectmsg' supported only on raw ATM"); - b0 = gen_msg_abbrev(A_SETUP); - b1 = gen_msg_abbrev(A_CALLPROCEED); + 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(A_CONNECT); + b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); - b0 = gen_msg_abbrev(A_CONNECTACK); + b0 = gen_msg_abbrev(cstate, A_CONNECTACK); gen_or(b0, b1); - b0 = gen_msg_abbrev(A_RELEASE); + b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); - b0 = gen_msg_abbrev(A_RELEASE_DONE); + b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); - b0 = gen_atmtype_abbrev(A_SC); + b0 = gen_atmtype_abbrev(cstate, A_SC); gen_and(b0, b1); break; case A_METACONNECT: - if (!is_atm) - bpf_error("'metaconnect' supported only on raw ATM"); - b0 = gen_msg_abbrev(A_SETUP); - b1 = gen_msg_abbrev(A_CALLPROCEED); + 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(A_CONNECT); + b0 = gen_msg_abbrev(cstate, A_CONNECT); gen_or(b0, b1); - b0 = gen_msg_abbrev(A_RELEASE); + b0 = gen_msg_abbrev(cstate, A_RELEASE); gen_or(b0, b1); - b0 = gen_msg_abbrev(A_RELEASE_DONE); + b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); - b0 = gen_atmtype_abbrev(A_METAC); + b0 = gen_atmtype_abbrev(cstate, A_METAC); gen_and(b0, b1); break; diff --git a/contrib/libpcap/gencode.h b/contrib/libpcap/gencode.h index 29d2d10f26..2b089d21d5 100644 --- a/contrib/libpcap/gencode.h +++ b/contrib/libpcap/gencode.h @@ -17,8 +17,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/gencode.h,v 1.71 2007-11-18 02:03:52 guy Exp $ (LBL) */ /* @@ -163,7 +161,7 @@ #define A_CONNECTACK 44 /* Connect Ack message */ #define A_RELEASE 45 /* Release message */ #define A_RELEASE_DONE 46 /* Release message */ - + /* ATM field types */ #define A_VPI 51 #define A_VCI 52 @@ -186,12 +184,23 @@ #define M_LSSU 23 /* LSSU */ #define M_MSU 24 /* MSU */ +/* MTP2 HSL types */ +#define MH_FISU 25 /* FISU for HSL */ +#define MH_LSSU 26 /* LSSU */ +#define MH_MSU 27 /* MSU */ + /* MTP3 field types */ #define M_SIO 1 #define M_OPC 2 #define M_DPC 3 #define M_SLS 4 +/* MTP3 field types in case of MTP2 HSL */ +#define MH_SIO 5 +#define MH_OPC 6 +#define MH_DPC 7 +#define MH_SLS 8 + struct slist; @@ -272,72 +281,115 @@ struct qual { unsigned char pad; }; -struct arth *gen_loadi(int); -struct arth *gen_load(int, struct arth *, int); -struct arth *gen_loadlen(void); -struct arth *gen_neg(struct arth *); -struct arth *gen_arth(int, struct arth *, struct arth *); +struct _compiler_state; + +typedef struct _compiler_state compiler_state_t; + +struct arth *gen_loadi(compiler_state_t *, int); +struct arth *gen_load(compiler_state_t *, int, struct arth *, int); +struct arth *gen_loadlen(compiler_state_t *); +struct arth *gen_neg(compiler_state_t *, struct arth *); +struct arth *gen_arth(compiler_state_t *, int, struct arth *, struct arth *); void gen_and(struct block *, struct block *); void gen_or(struct block *, struct block *); void gen_not(struct block *); -struct block *gen_scode(const char *, struct qual); -struct block *gen_ecode(const u_char *, struct qual); -struct block *gen_acode(const u_char *, struct qual); -struct block *gen_mcode(const char *, const char *, int, struct qual); +struct block *gen_scode(compiler_state_t *, const char *, struct qual); +struct block *gen_ecode(compiler_state_t *, const u_char *, struct qual); +struct block *gen_acode(compiler_state_t *, const u_char *, struct qual); +struct block *gen_mcode(compiler_state_t *, const char *, const char *, + unsigned int, struct qual); #ifdef INET6 -struct block *gen_mcode6(const char *, const char *, int, struct qual); +struct block *gen_mcode6(compiler_state_t *, const char *, const char *, + unsigned int, struct qual); #endif -struct block *gen_ncode(const char *, bpf_u_int32, struct qual); -struct block *gen_proto_abbrev(int); -struct block *gen_relation(int, struct arth *, struct arth *, int); -struct block *gen_less(int); -struct block *gen_greater(int); -struct block *gen_byteop(int, int, int); -struct block *gen_broadcast(int); -struct block *gen_multicast(int); -struct block *gen_inbound(int); - -struct block *gen_vlan(int); -struct block *gen_mpls(int); - -struct block *gen_pppoed(void); -struct block *gen_pppoes(void); - -struct block *gen_atmfield_code(int atmfield, bpf_int32 jvalue, bpf_u_int32 jtype, int reverse); -struct block *gen_atmtype_abbrev(int type); -struct block *gen_atmmulti_abbrev(int type); - -struct block *gen_mtp2type_abbrev(int type); -struct block *gen_mtp3field_code(int mtp3field, bpf_u_int32 jvalue, bpf_u_int32 jtype, int reverse); - -struct block *gen_pf_ifname(const char *); -struct block *gen_pf_rnr(int); -struct block *gen_pf_srnr(int); -struct block *gen_pf_ruleset(char *); -struct block *gen_pf_reason(int); -struct block *gen_pf_action(int); -struct block *gen_pf_dir(int); - -struct block *gen_p80211_type(int, int); -struct block *gen_p80211_fcdir(int); - -void bpf_optimize(struct block **); -void bpf_error(const char *, ...) - __attribute__((noreturn, format (printf, 1, 2))); - -void finish_parse(struct block *); -char *sdup(const char *); - -struct bpf_insn *icode_to_fcode(struct block *, u_int *); -int pcap_parse(void); -void lex_init(const char *); -void lex_cleanup(void); +struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32, + struct qual); +struct block *gen_proto_abbrev(compiler_state_t *, int); +struct block *gen_relation(compiler_state_t *, int, struct arth *, + struct arth *, int); +struct block *gen_less(compiler_state_t *, int); +struct block *gen_greater(compiler_state_t *, int); +struct block *gen_byteop(compiler_state_t *, int, int, int); +struct block *gen_broadcast(compiler_state_t *, int); +struct block *gen_multicast(compiler_state_t *, int); +struct block *gen_inbound(compiler_state_t *, int); + +struct block *gen_llc(compiler_state_t *); +struct block *gen_llc_i(compiler_state_t *); +struct block *gen_llc_s(compiler_state_t *); +struct block *gen_llc_u(compiler_state_t *); +struct block *gen_llc_s_subtype(compiler_state_t *, bpf_u_int32); +struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32); + +struct block *gen_vlan(compiler_state_t *, int); +struct block *gen_mpls(compiler_state_t *, int); + +struct block *gen_pppoed(compiler_state_t *); +struct block *gen_pppoes(compiler_state_t *, int); + +struct block *gen_geneve(compiler_state_t *, int); + +struct block *gen_atmfield_code(compiler_state_t *, int, bpf_int32, + bpf_u_int32, int); +struct block *gen_atmtype_abbrev(compiler_state_t *, int type); +struct block *gen_atmmulti_abbrev(compiler_state_t *, int type); + +struct block *gen_mtp2type_abbrev(compiler_state_t *, int type); +struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32, + bpf_u_int32, int); + +struct block *gen_pf_ifname(compiler_state_t *, const char *); +struct block *gen_pf_rnr(compiler_state_t *, int); +struct block *gen_pf_srnr(compiler_state_t *, int); +struct block *gen_pf_ruleset(compiler_state_t *, char *); +struct block *gen_pf_reason(compiler_state_t *, int); +struct block *gen_pf_action(compiler_state_t *, int); + +struct block *gen_p80211_type(compiler_state_t *, int, int); +struct block *gen_p80211_fcdir(compiler_state_t *, int); + +/* + * Representation of a program as a tree of blocks, plus current mark. + * A block is marked if only if its mark equals the current mark. + * Rather than traverse the code array, marking each item, 'cur_mark' + * is incremented. This automatically makes each element unmarked. + */ +#define isMarked(icp, p) ((p)->mark == (icp)->cur_mark) +#define unMarkAll(icp) (icp)->cur_mark += 1 +#define Mark(icp, p) ((p)->mark = (icp)->cur_mark) + +struct icode { + struct block *root; + int cur_mark; +}; + +void bpf_optimize(compiler_state_t *, struct icode *ic); +void bpf_syntax_error(compiler_state_t *, const char *); +void bpf_error(compiler_state_t *, const char *, ...) + __attribute__((noreturn)) +#ifdef __ATTRIBUTE___FORMAT_OK + __attribute__((format (printf, 2, 3))) +#endif /* __ATTRIBUTE___FORMAT_OK */ + ; + +void finish_parse(compiler_state_t *, struct block *); +char *sdup(compiler_state_t *, const char *); + +struct _opt_state; +typedef struct _opt_state opt_state_t; + +struct bpf_insn *icode_to_fcode(compiler_state_t *, struct icode *, + struct block *, u_int *); void sappend(struct slist *, struct slist *); +/* + * Older versions of Bison don't put this declaration in + * grammar.h. + */ +int pcap_parse(void *, compiler_state_t *); + /* XXX */ #define JT(b) ((b)->et.succ) #define JF(b) ((b)->ef.succ) - -extern int no_optimize; diff --git a/contrib/libpcap/grammar.y b/contrib/libpcap/grammar.y index f92e90dd73..8e1d40a7ce 100644 --- a/contrib/libpcap/grammar.y +++ b/contrib/libpcap/grammar.y @@ -1,3 +1,28 @@ +/* + * We want a reentrant parser. + */ +%pure-parser + +/* + * We also want a reentrant scanner, so we have to pass the + * handle for the reentrant scanner to the parser, and the + * parser has to pass it to the lexical analyzer. + * + * We use void * rather than yyscan_t because, at least with some + * versions of Flex and Bison, if you use yyscan_t in %parse-param and + * %lex-param, you have to include scanner.h before grammar.h to get + * yyscan_t declared, and you have to include grammar.h before scanner.h + * to get YYSTYPE declared. Using void * breaks the cycle; the Flex + * documentation says yyscan_t is just a void *. + */ +%parse-param {void *yyscanner} +%lex-param {void *yyscanner} + +/* + * And we need to pass the compiler state to the scanner. + */ +%parse-param {compiler_state_t *cstate} + %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 @@ -20,25 +45,21 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/grammar.y,v 1.101 2007-11-18 02:03:52 guy Exp $ (LBL)"; -#endif #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include -#ifndef WIN32 +#ifndef _WIN32 #if __STDC__ struct mbuf; struct rtentry; @@ -46,18 +67,22 @@ struct rtentry; #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include "pcap-int.h" #include "gencode.h" +#include "grammar.h" +#include "scanner.h" + #ifdef HAVE_NET_PFVAR_H #include #include #include #endif +#include "llc.h" #include "ieee80211.h" #include @@ -132,6 +157,23 @@ static const struct tok ieee80211_data_subtypes[] = { { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" }, { 0, NULL } }; +static const struct tok llc_s_subtypes[] = { + { LLC_RR, "rr" }, + { LLC_RNR, "rnr" }, + { LLC_REJ, "rej" }, + { 0, NULL } +}; +static const struct tok llc_u_subtypes[] = { + { LLC_UI, "ui" }, + { LLC_UA, "ua" }, + { LLC_DISC, "disc" }, + { LLC_DM, "dm" }, + { LLC_SABME, "sabme" }, + { LLC_TEST, "test" }, + { LLC_XID, "xid" }, + { LLC_FRMR, "frmr" }, + { 0, NULL } +}; struct type2tok { int type; const struct tok *tok; @@ -155,31 +197,18 @@ str2tok(const char *str, const struct tok *toks) return (-1); } -int n_errors = 0; - static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; static void -yyerror(const char *msg) +yyerror(void *yyscanner, compiler_state_t *cstate, const char *msg) { - ++n_errors; - bpf_error("%s", msg); + bpf_syntax_error(cstate, msg); /* NOTREACHED */ } -#ifdef NEED_YYPARSE_WRAPPER -int yyparse(void); - -int -pcap_parse() -{ - return (yyparse()); -} -#endif - #ifdef HAVE_NET_PFVAR_H static int -pfreason_to_num(const char *reason) +pfreason_to_num(compiler_state_t *cstate, const char *reason) { const char *reasons[] = PFRES_NAMES; int i; @@ -188,12 +217,12 @@ pfreason_to_num(const char *reason) if (pcap_strcasecmp(reason, reasons[i]) == 0) return (i); } - bpf_error("unknown PF reason"); + bpf_error(cstate, "unknown PF reason"); /*NOTREACHED*/ } static int -pfaction_to_num(const char *action) +pfaction_to_num(compiler_state_t *cstate, const char *action) { if (pcap_strcasecmp(action, "pass") == 0 || pcap_strcasecmp(action, "accept") == 0) @@ -212,15 +241,15 @@ pfaction_to_num(const char *action) return (PF_NORDR); #endif else { - bpf_error("unknown PF action"); + bpf_error(cstate, "unknown PF action"); /*NOTREACHED*/ } } #else /* !HAVE_NET_PFVAR_H */ static int -pfreason_to_num(const char *reason) +pfreason_to_num(compiler_state_t *cstate, const char *reason) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /*NOTREACHED*/ /* this is to make the VC compiler happy */ @@ -228,9 +257,9 @@ pfreason_to_num(const char *reason) } static int -pfaction_to_num(const char *action) +pfaction_to_num(compiler_state_t *cstate, const char *action) { - bpf_error("libpcap was compiled on a machine without pf support"); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /*NOTREACHED*/ /* this is to make the VC compiler happy */ @@ -261,7 +290,7 @@ pfaction_to_num(const char *action) %type arth narth %type byteop pname pnum relop irelop %type and or paren not null prog -%type other pfvar p80211 +%type other pfvar p80211 pllc %type atmtype atmmultitype %type atmfield %type atmfieldvalue atmvalue atmlistvalue @@ -285,8 +314,8 @@ pfaction_to_num(const char *action) %token LEN %token IPV6 ICMPV6 AH ESP %token VLAN MPLS -%token PPPOED PPPOES -%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP +%token PPPOED PPPOES GENEVE +%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP %token STP %token IPX %token NETBEUI @@ -294,8 +323,9 @@ pfaction_to_num(const char *action) %token OAM OAMF4 CONNECTMSG METACONNECT %token VPI VCI %token RADIO -%token FISU LSSU MSU -%token SIO OPC DPC SLS +%token FISU LSSU MSU HFISU HLSSU HMSU +%token SIO OPC DPC SLS HSIO HOPC HDPC HSLS + %type ID %type EID @@ -314,7 +344,7 @@ pfaction_to_num(const char *action) %% prog: null expr { - finish_parse($2.b); + finish_parse(cstate, $2.b); } | null ; @@ -331,48 +361,48 @@ and: AND { $$ = $0; } or: OR { $$ = $0; } ; id: nid - | pnum { $$.b = gen_ncode(NULL, (bpf_u_int32)$1, + | pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, $$.q = $0.q); } | paren pid ')' { $$ = $2; } ; -nid: ID { $$.b = gen_scode($1, $$.q = $0.q); } - | HID '/' NUM { $$.b = gen_mcode($1, NULL, $3, +nid: ID { $$.b = gen_scode(cstate, $1, $$.q = $0.q); } + | HID '/' NUM { $$.b = gen_mcode(cstate, $1, NULL, $3, $$.q = $0.q); } - | HID NETMASK HID { $$.b = gen_mcode($1, $3, 0, + | HID NETMASK HID { $$.b = gen_mcode(cstate, $1, $3, 0, $$.q = $0.q); } | HID { /* Decide how to parse HID based on proto */ $$.q = $0.q; if ($$.q.addr == Q_PORT) - bpf_error("'port' modifier applied to ip host"); + bpf_error(cstate, "'port' modifier applied to ip host"); else if ($$.q.addr == Q_PORTRANGE) - bpf_error("'portrange' modifier applied to ip host"); + bpf_error(cstate, "'portrange' modifier applied to ip host"); else if ($$.q.addr == Q_PROTO) - bpf_error("'proto' modifier applied to ip host"); + bpf_error(cstate, "'proto' modifier applied to ip host"); else if ($$.q.addr == Q_PROTOCHAIN) - bpf_error("'protochain' modifier applied to ip host"); - $$.b = gen_ncode($1, 0, $$.q); + bpf_error(cstate, "'protochain' modifier applied to ip host"); + $$.b = gen_ncode(cstate, $1, 0, $$.q); } | HID6 '/' NUM { #ifdef INET6 - $$.b = gen_mcode6($1, NULL, $3, + $$.b = gen_mcode6(cstate, $1, NULL, $3, $$.q = $0.q); #else - bpf_error("'ip6addr/prefixlen' not supported " + bpf_error(cstate, "'ip6addr/prefixlen' not supported " "in this configuration"); #endif /*INET6*/ } | HID6 { #ifdef INET6 - $$.b = gen_mcode6($1, 0, 128, + $$.b = gen_mcode6(cstate, $1, 0, 128, $$.q = $0.q); #else - bpf_error("'ip6addr' not supported " + bpf_error(cstate, "'ip6addr' not supported " "in this configuration"); #endif /*INET6*/ } - | EID { - $$.b = gen_ecode($1, $$.q = $0.q); + | EID { + $$.b = gen_ecode(cstate, $1, $$.q = $0.q); /* * $1 was allocated by "pcap_ether_aton()", * so we must free it now that we're done @@ -381,7 +411,7 @@ nid: ID { $$.b = gen_scode($1, $$.q = $0.q); } free($1); } | AID { - $$.b = gen_acode($1, $$.q = $0.q); + $$.b = gen_acode(cstate, $1, $$.q = $0.q); /* * $1 was allocated by "pcap_ether_aton()", * so we must free it now that we're done @@ -399,7 +429,7 @@ pid: nid | qid and id { gen_and($1.b, $3.b); $$ = $3; } | qid or id { gen_or($1.b, $3.b); $$ = $3; } ; -qid: pnum { $$.b = gen_ncode(NULL, (bpf_u_int32)$1, +qid: pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, $$.q = $0.q); } | pid ; @@ -415,16 +445,16 @@ head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } ; rterm: head id { $$ = $2; } | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } - | pname { $$.b = gen_proto_abbrev($1); $$.q = qerr; } - | arth relop arth { $$.b = gen_relation($2, $1, $3, 0); + | pname { $$.b = gen_proto_abbrev(cstate, $1); $$.q = qerr; } + | arth relop arth { $$.b = gen_relation(cstate, $2, $1, $3, 0); $$.q = qerr; } - | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1); + | arth irelop arth { $$.b = gen_relation(cstate, $2, $1, $3, 1); $$.q = qerr; } | other { $$.b = $1; $$.q = qerr; } - | atmtype { $$.b = gen_atmtype_abbrev($1); $$.q = qerr; } - | atmmultitype { $$.b = gen_atmmulti_abbrev($1); $$.q = qerr; } + | atmtype { $$.b = gen_atmtype_abbrev(cstate, $1); $$.q = qerr; } + | atmmultitype { $$.b = gen_atmmulti_abbrev(cstate, $1); $$.q = qerr; } | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } - | mtp2type { $$.b = gen_mtp2type_abbrev($1); $$.q = qerr; } + | mtp2type { $$.b = gen_mtp2type_abbrev(cstate, $1); $$.q = qerr; } | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; } ; /* protocol level qualifiers */ @@ -494,50 +524,54 @@ pname: LINK { $$ = Q_LINK; } | NETBEUI { $$ = Q_NETBEUI; } | RADIO { $$ = Q_RADIO; } ; -other: pqual TK_BROADCAST { $$ = gen_broadcast($1); } - | pqual TK_MULTICAST { $$ = gen_multicast($1); } - | LESS NUM { $$ = gen_less($2); } - | GREATER NUM { $$ = gen_greater($2); } - | CBYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); } - | INBOUND { $$ = gen_inbound(0); } - | OUTBOUND { $$ = gen_inbound(1); } - | VLAN pnum { $$ = gen_vlan($2); } - | VLAN { $$ = gen_vlan(-1); } - | MPLS pnum { $$ = gen_mpls($2); } - | MPLS { $$ = gen_mpls(-1); } - | PPPOED { $$ = gen_pppoed(); } - | PPPOES { $$ = gen_pppoes(); } +other: pqual TK_BROADCAST { $$ = gen_broadcast(cstate, $1); } + | pqual TK_MULTICAST { $$ = gen_multicast(cstate, $1); } + | LESS NUM { $$ = gen_less(cstate, $2); } + | GREATER NUM { $$ = gen_greater(cstate, $2); } + | CBYTE NUM byteop NUM { $$ = gen_byteop(cstate, $3, $2, $4); } + | INBOUND { $$ = gen_inbound(cstate, 0); } + | OUTBOUND { $$ = gen_inbound(cstate, 1); } + | VLAN pnum { $$ = gen_vlan(cstate, $2); } + | VLAN { $$ = gen_vlan(cstate, -1); } + | MPLS pnum { $$ = gen_mpls(cstate, $2); } + | MPLS { $$ = gen_mpls(cstate, -1); } + | PPPOED { $$ = gen_pppoed(cstate); } + | PPPOES pnum { $$ = gen_pppoes(cstate, $2); } + | PPPOES { $$ = gen_pppoes(cstate, -1); } + | GENEVE pnum { $$ = gen_geneve(cstate, $2); } + | GENEVE { $$ = gen_geneve(cstate, -1); } | pfvar { $$ = $1; } | pqual p80211 { $$ = $2; } + | pllc { $$ = $1; } ; -pfvar: PF_IFNAME ID { $$ = gen_pf_ifname($2); } - | PF_RSET ID { $$ = gen_pf_ruleset($2); } - | PF_RNR NUM { $$ = gen_pf_rnr($2); } - | PF_SRNR NUM { $$ = gen_pf_srnr($2); } - | PF_REASON reason { $$ = gen_pf_reason($2); } - | PF_ACTION action { $$ = gen_pf_action($2); } +pfvar: PF_IFNAME ID { $$ = gen_pf_ifname(cstate, $2); } + | PF_RSET ID { $$ = gen_pf_ruleset(cstate, $2); } + | PF_RNR NUM { $$ = gen_pf_rnr(cstate, $2); } + | PF_SRNR NUM { $$ = gen_pf_srnr(cstate, $2); } + | PF_REASON reason { $$ = gen_pf_reason(cstate, $2); } + | PF_ACTION action { $$ = gen_pf_action(cstate, $2); } ; p80211: TYPE type SUBTYPE subtype - { $$ = gen_p80211_type($2 | $4, + { $$ = gen_p80211_type(cstate, $2 | $4, IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK); } - | TYPE type { $$ = gen_p80211_type($2, + | TYPE type { $$ = gen_p80211_type(cstate, $2, IEEE80211_FC0_TYPE_MASK); } - | SUBTYPE type_subtype { $$ = gen_p80211_type($2, + | SUBTYPE type_subtype { $$ = gen_p80211_type(cstate, $2, IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK); } - | DIR dir { $$ = gen_p80211_fcdir($2); } + | DIR dir { $$ = gen_p80211_fcdir(cstate, $2); } ; type: NUM | ID { $$ = str2tok($1, ieee80211_types); if ($$ == -1) - bpf_error("unknown 802.11 type name"); + bpf_error(cstate, "unknown 802.11 type name"); } ; @@ -547,7 +581,7 @@ subtype: NUM for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ - bpf_error("unknown 802.11 type"); + bpf_error(cstate, "unknown 802.11 type"); break; } if ($-1 == ieee80211_type_subtypes[i].type) { @@ -558,7 +592,7 @@ subtype: NUM $$ = str2tok($1, types); if ($$ == -1) - bpf_error("unknown 802.11 subtype name"); + bpf_error(cstate, "unknown 802.11 subtype name"); } ; @@ -566,7 +600,7 @@ type_subtype: ID { int i; for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ - bpf_error("unknown 802.11 type name"); + bpf_error(cstate, "unknown 802.11 type name"); break; } $$ = str2tok($1, ieee80211_type_subtypes[i].tok); @@ -578,6 +612,31 @@ type_subtype: ID { int i; } ; +pllc: LLC { $$ = gen_llc(cstate); } + | LLC ID { if (pcap_strcasecmp($2, "i") == 0) + $$ = gen_llc_i(cstate); + else if (pcap_strcasecmp($2, "s") == 0) + $$ = gen_llc_s(cstate); + else if (pcap_strcasecmp($2, "u") == 0) + $$ = gen_llc_u(cstate); + else { + int subtype; + + subtype = str2tok($2, llc_s_subtypes); + if (subtype != -1) + $$ = gen_llc_s_subtype(cstate, subtype); + else { + subtype = str2tok($2, llc_u_subtypes); + if (subtype == -1) + bpf_error(cstate, "unknown LLC type name \"%s\"", $2); + $$ = gen_llc_u_subtype(cstate, subtype); + } + } + } + /* sigh, "rnr" is already a keyword for PF */ + | LLC PF_RNR { $$ = gen_llc_s_subtype(cstate, LLC_RNR); } + ; + dir: NUM | ID { if (pcap_strcasecmp($1, "nods") == 0) $$ = IEEE80211_FC1_DIR_NODS; @@ -588,15 +647,15 @@ dir: NUM else if (pcap_strcasecmp($1, "dstods") == 0) $$ = IEEE80211_FC1_DIR_DSTODS; else - bpf_error("unknown 802.11 direction"); + bpf_error(cstate, "unknown 802.11 direction"); } ; reason: NUM { $$ = $1; } - | ID { $$ = pfreason_to_num($1); } + | ID { $$ = pfreason_to_num(cstate, $1); } ; -action: ID { $$ = pfaction_to_num($1); } +action: ID { $$ = pfaction_to_num(cstate, $1); } ; relop: '>' { $$ = BPF_JGT; } @@ -607,22 +666,24 @@ irelop: LEQ { $$ = BPF_JGT; } | '<' { $$ = BPF_JGE; } | NEQ { $$ = BPF_JEQ; } ; -arth: pnum { $$ = gen_loadi($1); } +arth: pnum { $$ = gen_loadi(cstate, $1); } | narth ; -narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); } - | pname '[' arth ':' NUM ']' { $$ = gen_load($1, $3, $5); } - | arth '+' arth { $$ = gen_arth(BPF_ADD, $1, $3); } - | arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); } - | arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); } - | arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); } - | arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); } - | arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); } - | arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); } - | arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); } - | '-' arth %prec UMINUS { $$ = gen_neg($2); } +narth: pname '[' arth ']' { $$ = gen_load(cstate, $1, $3, 1); } + | pname '[' arth ':' NUM ']' { $$ = gen_load(cstate, $1, $3, $5); } + | arth '+' arth { $$ = gen_arth(cstate, BPF_ADD, $1, $3); } + | arth '-' arth { $$ = gen_arth(cstate, BPF_SUB, $1, $3); } + | arth '*' arth { $$ = gen_arth(cstate, BPF_MUL, $1, $3); } + | arth '/' arth { $$ = gen_arth(cstate, BPF_DIV, $1, $3); } + | arth '%' arth { $$ = gen_arth(cstate, BPF_MOD, $1, $3); } + | arth '&' arth { $$ = gen_arth(cstate, BPF_AND, $1, $3); } + | arth '|' arth { $$ = gen_arth(cstate, BPF_OR, $1, $3); } + | arth '^' arth { $$ = gen_arth(cstate, BPF_XOR, $1, $3); } + | arth LSH arth { $$ = gen_arth(cstate, BPF_LSH, $1, $3); } + | arth RSH arth { $$ = gen_arth(cstate, BPF_RSH, $1, $3); } + | '-' arth %prec UMINUS { $$ = gen_neg(cstate, $2); } | paren narth ')' { $$ = $2; } - | LEN { $$ = gen_loadlen(); } + | LEN { $$ = gen_loadlen(cstate); } ; byteop: '&' { $$ = '&'; } | '|' { $$ = '|'; } @@ -634,7 +695,6 @@ pnum: NUM | paren pnum ')' { $$ = $2; } ; atmtype: LANE { $$ = A_LANE; } - | LLC { $$ = A_LLC; } | METAC { $$ = A_METAC; } | BCC { $$ = A_BCC; } | OAMF4EC { $$ = A_OAMF4EC; } @@ -652,15 +712,15 @@ atmfield: VPI { $$.atmfieldtype = A_VPI; } | VCI { $$.atmfieldtype = A_VCI; } ; atmvalue: atmfieldvalue - | relop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0); } - | irelop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1); } + | relop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0); } + | irelop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1); } | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } ; atmfieldvalue: NUM { $$.atmfieldtype = $0.atmfieldtype; if ($$.atmfieldtype == A_VPI || $$.atmfieldtype == A_VCI) - $$.b = gen_atmfield_code($$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0); + $$.b = gen_atmfield_code(cstate, $$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0); } ; atmlistvalue: atmfieldvalue @@ -670,16 +730,23 @@ atmlistvalue: atmfieldvalue mtp2type: FISU { $$ = M_FISU; } | LSSU { $$ = M_LSSU; } | MSU { $$ = M_MSU; } + | HFISU { $$ = MH_FISU; } + | HLSSU { $$ = MH_LSSU; } + | HMSU { $$ = MH_MSU; } ; /* MTP3 field types quantifier */ mtp3field: SIO { $$.mtp3fieldtype = M_SIO; } | OPC { $$.mtp3fieldtype = M_OPC; } | DPC { $$.mtp3fieldtype = M_DPC; } | SLS { $$.mtp3fieldtype = M_SLS; } + | HSIO { $$.mtp3fieldtype = MH_SIO; } + | HOPC { $$.mtp3fieldtype = MH_OPC; } + | HDPC { $$.mtp3fieldtype = MH_DPC; } + | HSLS { $$.mtp3fieldtype = MH_SLS; } ; mtp3value: mtp3fieldvalue - | relop NUM { $$.b = gen_mtp3field_code($0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0); } - | irelop NUM { $$.b = gen_mtp3field_code($0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1); } + | relop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0); } + | irelop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1); } | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; } ; mtp3fieldvalue: NUM { @@ -687,8 +754,12 @@ mtp3fieldvalue: NUM { if ($$.mtp3fieldtype == M_SIO || $$.mtp3fieldtype == M_OPC || $$.mtp3fieldtype == M_DPC || - $$.mtp3fieldtype == M_SLS ) - $$.b = gen_mtp3field_code($$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0); + $$.mtp3fieldtype == M_SLS || + $$.mtp3fieldtype == MH_SIO || + $$.mtp3fieldtype == MH_OPC || + $$.mtp3fieldtype == MH_DPC || + $$.mtp3fieldtype == MH_SLS) + $$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0); } ; mtp3listvalue: mtp3fieldvalue diff --git a/contrib/libpcap/inet.c b/contrib/libpcap/inet.c index 6ae46ef876..16a483d496 100644 --- a/contrib/libpcap/inet.c +++ b/contrib/libpcap/inet.c @@ -32,18 +32,13 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.79 2008-04-20 18:19:02 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #include #ifndef MSDOS @@ -59,22 +54,16 @@ struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ -#include #include #include #include #include #include -#if !defined(WIN32) && !defined(__BORLANDC__) +#if !defined(_WIN32) && !defined(__BORLANDC__) #include -#endif /* !WIN32 && !__BORLANDC__ */ -#ifdef HAVE_LIMITS_H -#include -#else -#define INT_MAX 2147483647 -#endif +#endif /* !_WIN32 && !__BORLANDC__ */ #include "pcap-int.h" @@ -82,585 +71,7 @@ struct rtentry; /* declarations in */ #include "os-proto.h" #endif -/* Not all systems have IFF_LOOPBACK */ -#ifdef IFF_LOOPBACK -#define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK) -#else -#define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \ - (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0')) -#endif - -struct sockaddr * -dup_sockaddr(struct sockaddr *sa, size_t sa_length) -{ - struct sockaddr *newsa; - - if ((newsa = malloc(sa_length)) == NULL) - return (NULL); - return (memcpy(newsa, sa, sa_length)); -} - -static int -get_instance(const char *name) -{ - const char *cp, *endcp; - int n; - - if (strcmp(name, "any") == 0) { - /* - * Give the "any" device an artificially high instance - * number, so it shows up after all other non-loopback - * interfaces. - */ - return INT_MAX; - } - - endcp = name + strlen(name); - for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp) - continue; - - if (isdigit((unsigned char)*cp)) - n = atoi(cp); - else - n = 0; - return (n); -} - -int -add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, - u_int flags, const char *description, char *errbuf) -{ - pcap_t *p; - pcap_if_t *curdev, *prevdev, *nextdev; - int this_instance; - char open_errbuf[PCAP_ERRBUF_SIZE]; - - /* - * Is there already an entry in the list for this interface? - */ - for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { - if (strcmp(name, curdev->name) == 0) - break; /* yes, we found it */ - } - - if (curdev == NULL) { - /* - * No, we didn't find it. - * - * Can we open this interface for live capture? - * - * We do this check so that interfaces that are - * supplied by the interface enumeration mechanism - * we're using but that don't support packet capture - * aren't included in the list. Loopback interfaces - * on Solaris are an example of this; we don't just - * omit loopback interfaces on all platforms because - * you *can* capture on loopback interfaces on some - * OSes. - * - * On OS X, we don't do this check if the device - * name begins with "wlt"; at least some versions - * of OS X offer monitor mode capturing by having - * a separate "monitor mode" device for each wireless - * adapter, rather than by implementing the ioctls - * that {Free,Net,Open,DragonFly}BSD provide. - * Opening that device puts the adapter into monitor - * mode, which, at least for some adapters, causes - * them to deassociate from the network with which - * they're associated. - * - * Instead, we try to open the corresponding "en" - * device (so that we don't end up with, for users - * without sufficient privilege to open capture - * devices, a list of adapters that only includes - * the wlt devices). - */ -#ifdef __APPLE__ - if (strncmp(name, "wlt", 3) == 0) { - char *en_name; - size_t en_name_len; - - /* - * Try to allocate a buffer for the "en" - * device's name. - */ - en_name_len = strlen(name) - 1; - en_name = malloc(en_name_len + 1); - if (en_name == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - return (-1); - } - strcpy(en_name, "en"); - strcat(en_name, name + 3); - p = pcap_open_live(en_name, 68, 0, 0, open_errbuf); - free(en_name); - } else -#endif /* __APPLE */ - p = pcap_open_live(name, 68, 0, 0, open_errbuf); - if (p == NULL) { - /* - * No. Don't bother including it. - * Don't treat this as an error, though. - */ - *curdev_ret = NULL; - return (0); - } - pcap_close(p); - - /* - * Yes, we can open it. - * Allocate a new entry. - */ - curdev = malloc(sizeof(pcap_if_t)); - if (curdev == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - return (-1); - } - - /* - * Fill in the entry. - */ - curdev->next = NULL; - curdev->name = strdup(name); - if (curdev->name == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - free(curdev); - return (-1); - } - if (description != NULL) { - /* - * We have a description for this interface. - */ - curdev->description = strdup(description); - if (curdev->description == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - free(curdev->name); - free(curdev); - return (-1); - } - } else { - /* - * We don't. - */ - curdev->description = NULL; - } - curdev->addresses = NULL; /* list starts out as empty */ - curdev->flags = 0; - if (ISLOOPBACK(name, flags)) - curdev->flags |= PCAP_IF_LOOPBACK; - - /* - * Add it to the list, in the appropriate location. - * First, get the instance number of this interface. - */ - this_instance = get_instance(name); - - /* - * Now look for the last interface with an instance number - * less than or equal to the new interface's instance - * number - except that non-loopback interfaces are - * arbitrarily treated as having interface numbers less - * than those of loopback interfaces, so the loopback - * interfaces are put at the end of the list. - * - * We start with "prevdev" being NULL, meaning we're before - * the first element in the list. - */ - prevdev = NULL; - for (;;) { - /* - * Get the interface after this one. - */ - if (prevdev == NULL) { - /* - * The next element is the first element. - */ - nextdev = *alldevs; - } else - nextdev = prevdev->next; - - /* - * Are we at the end of the list? - */ - if (nextdev == NULL) { - /* - * Yes - we have to put the new entry - * after "prevdev". - */ - break; - } - - /* - * Is the new interface a non-loopback interface - * and the next interface a loopback interface? - */ - if (!(curdev->flags & PCAP_IF_LOOPBACK) && - (nextdev->flags & PCAP_IF_LOOPBACK)) { - /* - * Yes, we should put the new entry - * before "nextdev", i.e. after "prevdev". - */ - break; - } - - /* - * Is the new interface's instance number less - * than the next interface's instance number, - * and is it the case that the new interface is a - * non-loopback interface or the next interface is - * a loopback interface? - * - * (The goal of both loopback tests is to make - * sure that we never put a loopback interface - * before any non-loopback interface and that we - * always put a non-loopback interface before all - * loopback interfaces.) - */ - if (this_instance < get_instance(nextdev->name) && - (!(curdev->flags & PCAP_IF_LOOPBACK) || - (nextdev->flags & PCAP_IF_LOOPBACK))) { - /* - * Yes - we should put the new entry - * before "nextdev", i.e. after "prevdev". - */ - break; - } - - prevdev = nextdev; - } - - /* - * Insert before "nextdev". - */ - curdev->next = nextdev; - - /* - * Insert after "prevdev" - unless "prevdev" is null, - * in which case this is the first interface. - */ - if (prevdev == NULL) { - /* - * This is the first interface. Pass back a - * pointer to it, and put "curdev" before - * "nextdev". - */ - *alldevs = curdev; - } else - prevdev->next = curdev; - } - - *curdev_ret = curdev; - return (0); -} - -/* - * XXX - on FreeBSDs that support it, should it get the sysctl named - * "dev.{adapter family name}.{adapter unit}.%desc" to get a description - * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" - * with my Cisco 350 card, so the name isn't entirely descriptive. The - * "dev.an.0.%pnpinfo" has a better description, although one might argue - * that the problem is really a driver bug - if it can find out that it's - * a Cisco 340 or 350, rather than an old Aironet card, it should use - * that in the description. - * - * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD - * and OpenBSD let you get a description, but it's not generated by the OS, - * it's set with another ioctl that ifconfig supports; we use that to get - * a description in FreeBSD and OpenBSD, but if there is no such - * description available, it still might be nice to get some description - * string based on the device type or something such as that. - * - * In OS X, the System Configuration framework can apparently return - * names in 10.4 and later. - * - * It also appears that freedesktop.org's HAL offers an "info.product" - * string, but the HAL specification says it "should not be used in any - * UI" and "subsystem/capability specific properties" should be used - * instead and, in any case, I think HAL is being deprecated in - * favor of other stuff such as DeviceKit. DeviceKit doesn't appear - * to have any obvious product information for devices, but maybe - * I haven't looked hard enough. - * - * Using the System Configuration framework, or HAL, or DeviceKit, or - * whatever, would require that libpcap applications be linked with - * the frameworks/libraries in question. That shouldn't be a problem - * for programs linking with the shared version of libpcap (unless - * you're running on AIX - which I think is the only UN*X that doesn't - * support linking a shared library with other libraries on which it - * depends, and having an executable linked only with the first shared - * library automatically pick up the other libraries when started - - * and using HAL or whatever). Programs linked with the static - * version of libpcap would have to use pcap-config with the --static - * flag in order to get the right linker flags in order to pick up - * the additional libraries/frameworks; those programs need that anyway - * for libpcap 1.1 and beyond on Linux, as, by default, it requires - * -lnl. - * - * Do any other UN*Xes, or desktop environments support getting a - * description? - */ -int -add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, - struct sockaddr *addr, size_t addr_size, - struct sockaddr *netmask, size_t netmask_size, - struct sockaddr *broadaddr, size_t broadaddr_size, - struct sockaddr *dstaddr, size_t dstaddr_size, - char *errbuf) -{ - pcap_if_t *curdev; - char *description = NULL; - pcap_addr_t *curaddr, *prevaddr, *nextaddr; -#ifdef SIOCGIFDESCR - int s; - struct ifreq ifrdesc; -#ifndef IFDESCRSIZE - size_t descrlen = 64; -#else - size_t descrlen = IFDESCRSIZE; -#endif /* IFDESCRSIZE */ -#endif /* SIOCGIFDESCR */ - -#ifdef SIOCGIFDESCR - /* - * Get the description for the interface. - */ - memset(&ifrdesc, 0, sizeof ifrdesc); - strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s >= 0) { -#ifdef __FreeBSD__ - /* - * On FreeBSD, if the buffer isn't big enough for the - * description, the ioctl succeeds, but the description - * isn't copied, ifr_buffer.length is set to the description - * length, and ifr_buffer.buffer is set to NULL. - */ - for (;;) { - free(description); - if ((description = malloc(descrlen)) != NULL) { - ifrdesc.ifr_buffer.buffer = description; - ifrdesc.ifr_buffer.length = descrlen; - if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { - if (ifrdesc.ifr_buffer.buffer == - description) - break; - else - descrlen = ifrdesc.ifr_buffer.length; - } else { - /* - * Failed to get interface description. - */ - free(description); - description = NULL; - break; - } - } else - break; - } -#else /* __FreeBSD__ */ - /* - * The only other OS that currently supports - * SIOCGIFDESCR is OpenBSD, and it has no way - * to get the description length - it's clamped - * to a maximum of IFDESCRSIZE. - */ - if ((description = malloc(descrlen)) != NULL) { - ifrdesc.ifr_data = (caddr_t)description; - if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { - /* - * Failed to get interface description. - */ - free(description); - description = NULL; - } - } -#endif /* __FreeBSD__ */ - close(s); - if (description != NULL && strlen(description) == 0) { - free(description); - description = NULL; - } - } -#endif /* SIOCGIFDESCR */ - - if (add_or_find_if(&curdev, alldevs, name, flags, description, - errbuf) == -1) { - free(description); - /* - * Error - give up. - */ - return (-1); - } - free(description); - if (curdev == NULL) { - /* - * Device wasn't added because it can't be opened. - * Not a fatal error. - */ - return (0); - } - - /* - * "curdev" is an entry for this interface; add an entry for this - * address to its list of addresses. - * - * Allocate the new entry and fill it in. - */ - curaddr = malloc(sizeof(pcap_addr_t)); - if (curaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - return (-1); - } - - curaddr->next = NULL; - if (addr != NULL) { - curaddr->addr = dup_sockaddr(addr, addr_size); - if (curaddr->addr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - free(curaddr); - return (-1); - } - } else - curaddr->addr = NULL; - - if (netmask != NULL) { - curaddr->netmask = dup_sockaddr(netmask, netmask_size); - if (curaddr->netmask == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - if (curaddr->addr != NULL) - free(curaddr->addr); - free(curaddr); - return (-1); - } - } else - curaddr->netmask = NULL; - - if (broadaddr != NULL) { - curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); - if (curaddr->broadaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - if (curaddr->netmask != NULL) - free(curaddr->netmask); - if (curaddr->addr != NULL) - free(curaddr->addr); - free(curaddr); - return (-1); - } - } else - curaddr->broadaddr = NULL; - - if (dstaddr != NULL) { - curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); - if (curaddr->dstaddr == NULL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "malloc: %s", pcap_strerror(errno)); - if (curaddr->broadaddr != NULL) - free(curaddr->broadaddr); - if (curaddr->netmask != NULL) - free(curaddr->netmask); - if (curaddr->addr != NULL) - free(curaddr->addr); - free(curaddr); - return (-1); - } - } else - curaddr->dstaddr = NULL; - - /* - * Find the end of the list of addresses. - */ - for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { - nextaddr = prevaddr->next; - if (nextaddr == NULL) { - /* - * This is the end of the list. - */ - break; - } - } - - if (prevaddr == NULL) { - /* - * The list was empty; this is the first member. - */ - curdev->addresses = curaddr; - } else { - /* - * "prevaddr" is the last member of the list; append - * this member to it. - */ - prevaddr->next = curaddr; - } - - return (0); -} - -int -pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags, - const char *description, char *errbuf) -{ - pcap_if_t *curdev; - - return (add_or_find_if(&curdev, devlist, name, flags, description, - errbuf)); -} - - -/* - * Free a list of interfaces. - */ -void -pcap_freealldevs(pcap_if_t *alldevs) -{ - pcap_if_t *curdev, *nextdev; - pcap_addr_t *curaddr, *nextaddr; - - for (curdev = alldevs; curdev != NULL; curdev = nextdev) { - nextdev = curdev->next; - - /* - * Free all addresses. - */ - for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) { - nextaddr = curaddr->next; - if (curaddr->addr) - free(curaddr->addr); - if (curaddr->netmask) - free(curaddr->netmask); - if (curaddr->broadaddr) - free(curaddr->broadaddr); - if (curaddr->dstaddr) - free(curaddr->dstaddr); - free(curaddr); - } - - /* - * Free the name string. - */ - free(curdev->name); - - /* - * Free the description string, if any. - */ - if (curdev->description != NULL) - free(curdev->description); - - /* - * Free the interface. - */ - free(curdev); - } -} - -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) /* * Return the name of a network interface attached to the system, or NULL @@ -747,7 +158,7 @@ pcap_lookupnet(device, netp, maskp, errbuf) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (-1); } @@ -756,13 +167,13 @@ pcap_lookupnet(device, netp, maskp, errbuf) /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif - (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { if (errno == EADDRNOTAVAIL) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: no IPv4 address assigned", device); } else { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFADDR: %s: %s", device, pcap_strerror(errno)); } @@ -776,9 +187,9 @@ pcap_lookupnet(device, netp, maskp, errbuf) /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif - (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); (void)close(fd); return (-1); @@ -793,7 +204,7 @@ pcap_lookupnet(device, netp, maskp, errbuf) else if (IN_CLASSC(*netp)) *maskp = IN_CLASSC_NET; else { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%x unknown", *netp); return (-1); } @@ -802,92 +213,151 @@ pcap_lookupnet(device, netp, maskp, errbuf) return (0); } -#elif defined(WIN32) +#elif defined(_WIN32) /* * 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(errbuf) register char *errbuf; { DWORD dwVersion; DWORD dwWindowsMajorVersion; + char our_errbuf[PCAP_ERRBUF_SIZE+1]; + +#pragma warning (push) +#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */ dwVersion = GetVersion(); /* get the OS version */ +#pragma warning (pop) dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - + if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { /* * Windows 95, 98, ME. */ - ULONG NameLength = 8192; - static char AdaptersName[8192]; - + ULONG NameLength = ADAPTERSNAME_LEN; + static char AdaptersName[ADAPTERSNAME_LEN]; + if (PacketGetAdapterNames(AdaptersName,&NameLength) ) return (AdaptersName); else return NULL; } else { /* - * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility + * Windows NT (NT 4.0 and later). + * Convert the names to Unicode for backward compatibility. */ - ULONG NameLength = 8192; - static WCHAR AdaptersName[8192]; + ULONG NameLength = ADAPTERSNAME_LEN; + static WCHAR AdaptersName[ADAPTERSNAME_LEN]; + size_t BufferSpaceLeft; char *tAstr; - WCHAR *tUstr; - WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR)); + 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"); + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); return NULL; } if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", - pcap_win32strerror()); + pcap_win32_err_to_str(GetLastError(), our_errbuf); + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "PacketGetAdapterNames: %s", our_errbuf); free(TAdaptersName); return NULL; } + BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR); tAstr = (char*)TAdaptersName; - tUstr = (WCHAR*)AdaptersName; + Unameptr = AdaptersName; /* - * Convert and copy the device names + * Convert the device names to Unicode into AdapterName. */ - while(sscanf(tAstr, "%S", tUstr) > 0) - { - tAstr += strlen(tAstr) + 1; - tUstr += wcslen(tUstr) + 1; - NAdapts ++; - } + 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); - tAstr++; - *tUstr = 0; - tUstr++; + /* + * 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 + * Copy the descriptions, but don't convert them from + * ASCII to Unicode. */ + Adescptr = (char *)Unameptr; while(NAdapts--) { - char* tmp = (char*)tUstr; - strcpy(tmp, tAstr); - tmp += strlen(tAstr) + 1; - tUstr = (WCHAR*)tmp; - tAstr += strlen(tAstr) + 1; + 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); - } + } } @@ -897,7 +367,7 @@ pcap_lookupnet(device, netp, maskp, errbuf) register bpf_u_int32 *netp, *maskp; register 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) */ @@ -923,11 +393,11 @@ pcap_lookupnet(device, netp, maskp, errbuf) *netp &= *maskp; return (0); } - + } *netp = *maskp = 0; return (0); } -#endif /* !WIN32 && !MSDOS */ +#endif /* !_WIN32 && !MSDOS */ diff --git a/contrib/libpcap/llc.h b/contrib/libpcap/llc.h index b8c221fa0b..b0cf881ca1 100644 --- a/contrib/libpcap/llc.h +++ b/contrib/libpcap/llc.h @@ -17,10 +17,39 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/llc.h,v 1.2 2001-01-28 09:44:50 guy Exp $ (LBL) */ +/* + * Definitions for information in the LLC header. + */ + +#define LLC_U_FMT 3 +#define LLC_GSAP 1 +#define LLC_IG 1 /* Individual / Group */ +#define LLC_S_FMT 1 + +#define LLC_U_POLL 0x10 +#define LLC_IS_POLL 0x0100 +#define LLC_XID_FI 0x81 + +#define LLC_U_CMD_MASK 0xef +#define LLC_UI 0x03 +#define LLC_UA 0x63 +#define LLC_DISC 0x43 +#define LLC_DM 0x0f +#define LLC_SABME 0x6f +#define LLC_TEST 0xe3 +#define LLC_XID 0xaf +#define LLC_FRMR 0x87 + +#define LLC_S_CMD_MASK 0x0f +#define LLC_RR 0x0001 +#define LLC_RNR 0x0005 +#define LLC_REJ 0x0009 + +#define LLC_IS_NR(is) (((is) >> 9) & 0x7f) +#define LLC_I_NS(is) (((is) >> 1) & 0x7f) + /* * 802.2 LLC SAP values. */ @@ -31,10 +60,10 @@ #ifndef LLCSAP_GLOBAL #define LLCSAP_GLOBAL 0xff #endif -#ifndef LLCSAP_8021B +#ifndef LLCSAP_8021B_I #define LLCSAP_8021B_I 0x02 #endif -#ifndef LLCSAP_8021B +#ifndef LLCSAP_8021B_G #define LLCSAP_8021B_G 0x03 #endif #ifndef LLCSAP_IP diff --git a/contrib/libpcap/nametoaddr.c b/contrib/libpcap/nametoaddr.c index c0e86f43ab..71280b31c4 100644 --- a/contrib/libpcap/nametoaddr.c +++ b/contrib/libpcap/nametoaddr.c @@ -22,11 +22,6 @@ * These functions are not time critical. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.83 2008-02-06 10:21:30 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,10 +31,36 @@ static const char rcsid[] _U_ = #include #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#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. pcap-stdinc.h + * includes Ws2tcpip.h, so we don't need to include it ourselves. + */ +#include +#endif + +#else /* _WIN32 */ #include #include /* concession to AIX */ @@ -47,9 +68,9 @@ static const char rcsid[] _U_ = #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ -#ifndef WIN32 +#ifndef _WIN32 #ifdef HAVE_ETHER_HOSTTON /* * XXX - do we need any of this if doesn't declare @@ -67,7 +88,7 @@ struct rtentry; /* declarations in */ #endif /* HAVE_ETHER_HOSTTON */ #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -79,6 +100,7 @@ struct rtentry; /* declarations in */ #include "gencode.h" #include +#include "nametoaddr.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -145,7 +167,7 @@ pcap_nametoaddrinfo(const char *name) bpf_u_int32 pcap_nametonetaddr(const char *name) { -#ifndef WIN32 +#ifndef _WIN32 struct netent *np; if ((np = getnetbyname(name)) != NULL) @@ -155,6 +177,15 @@ pcap_nametonetaddr(const char *name) #else /* * 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; #endif @@ -279,8 +310,14 @@ struct eproto { u_short p; }; -/* Static data base of ether protocol types. */ -struct eproto eproto_db[] = { +/* + * 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.) + */ +PCAP_API_DEF struct eproto eproto_db[] = { { "pup", ETHERTYPE_PUP }, { "xns", ETHERTYPE_NS }, { "ip", ETHERTYPE_IP }, @@ -388,7 +425,7 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr) u_int node, area; if (sscanf(s, "%d.%d", &area, &node) != 2) - bpf_error("malformed decnet address '%s'", s); + return(0); *addr = (area << AREASHIFT) & AREAMASK; *addr |= (node & NODEMASK); @@ -415,6 +452,8 @@ pcap_ether_aton(const char *s) register u_int d; e = ep = (u_char *)malloc(6); + if (e == NULL) + return (NULL); while (*s) { if (*s == ':' || *s == '.' || *s == '-') @@ -490,23 +529,20 @@ pcap_ether_hostton(const char *name) } #endif -u_short -__pcap_nametodnaddr(const char *name) +int +__pcap_nametodnaddr(const char *name, u_short *res) { #ifdef DECNETLIB struct nodeent *getnodebyname(); struct nodeent *nep; - unsigned short res; nep = getnodebyname(name); if (nep == ((struct nodeent *)0)) - bpf_error("unknown decnet host name '%s'\n", name); + return(0); - memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short)); - return(res); + memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); + return(1); #else - bpf_error("decnet name support not included, '%s' cannot be translated\n", - name); return(0); #endif } diff --git a/contrib/libpcap/pcap-namedb.h b/contrib/libpcap/nametoaddr.h similarity index 84% copy from contrib/libpcap/pcap-namedb.h copy to contrib/libpcap/nametoaddr.h index d0b2231082..fd6b7e1016 100644 --- a/contrib/libpcap/pcap-namedb.h +++ b/contrib/libpcap/nametoaddr.h @@ -29,14 +29,20 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006-10-04 18:13:32 guy Exp $ (LBL) */ +#ifdef __cplusplus +extern "C" { +#endif + /* - * For backwards compatibility. - * - * Note to OS vendors: do NOT get rid of this file! Some applications - * might expect to be able to include . + * Routines used for name-or-address-string-to-address resolution + * that are *not* exported to code using libpcap. */ -#include +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +int __pcap_nametodnaddr(const char *, u_short *); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/libpcap/nlpid.h b/contrib/libpcap/nlpid.h index 5327a362b4..9dfa752b85 100644 --- a/contrib/libpcap/nlpid.h +++ b/contrib/libpcap/nlpid.h @@ -14,8 +14,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/nlpid.h,v 1.2 2002-12-06 00:01:34 hannes Exp $ (Juniper) */ /* Types missing from some systems */ diff --git a/contrib/libpcap/optimize.c b/contrib/libpcap/optimize.c index dcb104ec2a..19980dc81d 100644 --- a/contrib/libpcap/optimize.c +++ b/contrib/libpcap/optimize.c @@ -20,18 +20,14 @@ * * Optimization module for tcpdump intermediate representation. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.91 2008-01-02 04:16:46 guy Exp $ (LBL)"; -#endif #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -41,7 +37,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -59,7 +55,7 @@ static const char rcsid[] _U_ = #endif #ifdef BDEBUG -extern int dflag; +int pcap_optimizer_debug; #endif #if defined(MSDOS) && !defined(__DJGPP__) @@ -67,8 +63,26 @@ extern int _w32_ffs (int mask); #define ffs _w32_ffs #endif -#if defined(WIN32) && defined (_MSC_VER) -int ffs(int mask); +/* + * So is the check for _MSC_VER done because MinGW has this? + */ +#if defined(_WIN32) && defined (_MSC_VER) +/* + * ffs -- vax ffs instruction + * + * XXX - with versions of VS that have it, use _BitScanForward()? + */ +static int +ffs(int mask) +{ + int bit; + + if (mask == 0) + return(0); + for (bit = 1; !(mask & 1); bit++) + mask >>= 1; + return(bit); +} #endif /* @@ -93,45 +107,48 @@ int ffs(int mask); #define AX_ATOM N_ATOMS /* - * A flag to indicate that further optimization is needed. - * Iterative passes are continued until a given pass yields no - * branch movement. + * 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. */ -static int done; +struct valnode { + int code; + int v0, v1; + int val; + struct valnode *next; +}; -/* - * A block is marked if only if its mark equals the current mark. - * Rather than traverse the code array, marking each item, 'cur_mark' is - * incremented. This automatically makes each element unmarked. - */ -static int cur_mark; -#define isMarked(p) ((p)->mark == cur_mark) -#define unMarkAll() cur_mark += 1 -#define Mark(p) ((p)->mark = cur_mark) +/* Integer constants mapped with the load immediate opcode. */ +#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0L) -static void opt_init(struct block *); -static void opt_cleanup(void); +struct vmapinfo { + int is_const; + bpf_int32 const_val; +}; -static void intern_blocks(struct block *); +struct _opt_state { + /* + * A flag to indicate that further optimization is needed. + * Iterative passes are continued until a given pass yields no + * branch movement. + */ + int done; -static void find_inedges(struct block *); -#ifdef BDEBUG -static void opt_dump(struct block *); -#endif + int n_blocks; + struct block **blocks; + int n_edges; + struct edge **edges; -static int n_blocks; -struct block **blocks; -static int n_edges; -struct edge **edges; + /* + * A bit vector set representation of the dominators. + * We round up the set size to the next power of two. + */ + int nodewords; + int edgewords; + struct block **levels; + bpf_u_int32 *space; -/* - * A bit vector set representation of the dominators. - * We round up the set size to the next power of two. - */ -static int nodewords; -static int edgewords; -struct block **levels; -bpf_u_int32 *space; #define BITS_PER_WORD (8*sizeof(bpf_u_int32)) /* * True if a is in uset {p} @@ -181,48 +198,79 @@ bpf_u_int32 *space; while (--_n >= 0) *_x++ |= *_y++;\ } -static uset all_dom_sets; -static uset all_closure_sets; -static uset all_edge_sets; + uset all_dom_sets; + uset all_closure_sets; + uset all_edge_sets; + +#define MODULUS 213 + struct valnode *hashtbl[MODULUS]; + int curval; + int maxval; + + struct vmapinfo *vmap; + struct valnode *vnode_base; + struct valnode *next_vnode; +}; + +typedef struct { + /* + * 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(compiler_state_t *, opt_state_t *, struct icode *); +static void opt_cleanup(opt_state_t *); + +static void intern_blocks(opt_state_t *, struct icode *); + +static void find_inedges(opt_state_t *, struct block *); +#ifdef BDEBUG +static void opt_dump(compiler_state_t *, struct icode *); +#endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif static void -find_levels_r(struct block *b) +find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b) { int level; - if (isMarked(b)) + if (isMarked(ic, b)) return; - Mark(b); + Mark(ic, b); b->link = 0; if (JT(b)) { - find_levels_r(JT(b)); - find_levels_r(JF(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 = levels[level]; - levels[level] = b; + 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 levels[] array points to the + * 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(struct block *root) +find_levels(opt_state_t *opt_state, struct icode *ic) { - memset((char *)levels, 0, n_blocks * sizeof(*levels)); - unMarkAll(); - find_levels_r(root); + memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels)); + unMarkAll(ic); + find_levels_r(opt_state, ic, ic->root); } /* @@ -230,7 +278,7 @@ find_levels(struct block *root) * Assumes graph has been leveled. */ static void -find_dom(struct block *root) +find_dom(opt_state_t *opt_state, struct block *root) { int i; struct block *b; @@ -239,33 +287,33 @@ find_dom(struct block *root) /* * Initialize sets to contain all nodes. */ - x = all_dom_sets; - i = n_blocks * nodewords; + x = opt_state->all_dom_sets; + i = opt_state->n_blocks * opt_state->nodewords; while (--i >= 0) *x++ = ~0; /* Root starts off empty. */ - for (i = nodewords; --i >= 0;) + for (i = opt_state->nodewords; --i >= 0;) root->dom[i] = 0; /* root->level is the highest level no found. */ for (i = root->level; i >= 0; --i) { - for (b = levels[i]; b; b = b->link) { + for (b = opt_state->levels[i]; b; b = b->link) { SET_INSERT(b->dom, b->id); if (JT(b) == 0) continue; - SET_INTERSECT(JT(b)->dom, b->dom, nodewords); - SET_INTERSECT(JF(b)->dom, b->dom, nodewords); + SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords); + SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords); } } } static void -propedom(struct edge *ep) +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, edgewords); - SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords); + SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords); + SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords); } } @@ -274,23 +322,23 @@ propedom(struct edge *ep) * Assumes graph has been leveled and predecessors established. */ static void -find_edom(struct block *root) +find_edom(opt_state_t *opt_state, struct block *root) { int i; uset x; struct block *b; - x = all_edge_sets; - for (i = n_edges * edgewords; --i >= 0; ) + x = opt_state->all_edge_sets; + for (i = opt_state->n_edges * opt_state->edgewords; --i >= 0; ) x[i] = ~0; /* root->level is the highest level no found. */ - memset(root->et.edom, 0, edgewords * sizeof(*(uset)0)); - memset(root->ef.edom, 0, edgewords * sizeof(*(uset)0)); + memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); + memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); for (i = root->level; i >= 0; --i) { - for (b = levels[i]; b != 0; b = b->link) { - propedom(&b->et); - propedom(&b->ef); + for (b = opt_state->levels[i]; b != 0; b = b->link) { + propedom(opt_state, &b->et); + propedom(opt_state, &b->ef); } } } @@ -303,7 +351,7 @@ find_edom(struct block *root) * Assumes graph has been leveled. */ static void -find_closure(struct block *root) +find_closure(opt_state_t *opt_state, struct block *root) { int i; struct block *b; @@ -311,17 +359,17 @@ find_closure(struct block *root) /* * Initialize sets to contain no nodes. */ - memset((char *)all_closure_sets, 0, - n_blocks * nodewords * sizeof(*all_closure_sets)); + 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 (i = root->level; i >= 0; --i) { - for (b = levels[i]; b; b = b->link) { + for (b = opt_state->levels[i]; b; b = b->link) { SET_INSERT(b->closure, b->id); if (JT(b) == 0) continue; - SET_UNION(JT(b)->closure, b->closure, nodewords); - SET_UNION(JF(b)->closure, b->closure, nodewords); + SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords); + SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords); } } } @@ -417,7 +465,7 @@ static void compute_local_ud(struct block *b) { struct slist *s; - atomset def = 0, use = 0, kill = 0; + atomset def = 0, use = 0, killed = 0; int atom; for (s = b->stmts; s; s = s->next) { @@ -441,7 +489,7 @@ compute_local_ud(struct block *b) atom = atomdef(&s->s); if (atom >= 0) { if (!ATOMELEM(use, atom)) - kill |= ATOMMASK(atom); + killed |= ATOMMASK(atom); def |= ATOMMASK(atom); } } @@ -467,7 +515,7 @@ compute_local_ud(struct block *b) } b->def = def; - b->kill = kill; + b->kill = killed; b->in_use = use; } @@ -475,7 +523,7 @@ compute_local_ud(struct block *b) * Assume graph is already leveled. */ static void -find_ud(struct block *root) +find_ud(opt_state_t *opt_state, struct block *root) { int i, maxlevel; struct block *p; @@ -486,61 +534,30 @@ find_ud(struct block *root) */ maxlevel = root->level; for (i = maxlevel; i >= 0; --i) - for (p = levels[i]; p; p = p->link) { + 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 = levels[i]; p; p = p->link) { + 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; } } } - -/* - * 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; - int v0, v1; - int val; - struct valnode *next; -}; - -#define MODULUS 213 -static struct valnode *hashtbl[MODULUS]; -static int curval; -static int maxval; - -/* Integer constants mapped with the load immediate opcode. */ -#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L) - -struct vmapinfo { - int is_const; - bpf_int32 const_val; -}; - -struct vmapinfo *vmap; -struct valnode *vnode_base; -struct valnode *next_vnode; - static void -init_val(void) +init_val(opt_state_t *opt_state) { - curval = 0; - next_vnode = vnode_base; - memset((char *)vmap, 0, maxval * sizeof(*vmap)); - memset((char *)hashtbl, 0, sizeof hashtbl); + 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. */ static int -F(int code, int v0, int v1) +F(opt_state_t *opt_state, int code, int v0, int v1) { u_int hash; int val; @@ -549,23 +566,23 @@ F(int code, int v0, int v1) hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); hash %= MODULUS; - for (p = hashtbl[hash]; p; p = p->next) + for (p = opt_state->hashtbl[hash]; p; p = p->next) if (p->code == code && p->v0 == v0 && p->v1 == v1) return p->val; - val = ++curval; + val = ++opt_state->curval; if (BPF_MODE(code) == BPF_IMM && (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) { - vmap[val].const_val = v0; - vmap[val].is_const = 1; + opt_state->vmap[val].const_val = v0; + opt_state->vmap[val].is_const = 1; } - p = next_vnode++; + p = opt_state->next_vnode++; p->val = val; p->code = code; p->v0 = v0; p->v1 = v1; - p->next = hashtbl[hash]; - hashtbl[hash] = p; + p->next = opt_state->hashtbl[hash]; + opt_state->hashtbl[hash] = p; return val; } @@ -579,13 +596,18 @@ vstore(struct stmt *s, int *valp, int newval, int alter) *valp = newval; } +/* + * Do constant-folding on binary operators. + * (Unary operators are handled elsewhere.) + */ static void -fold_op(struct stmt *s, int v0, int v1) +fold_op(compiler_state_t *cstate, struct icode *ic, opt_state_t *opt_state, + struct stmt *s, int v0, int v1) { bpf_u_int32 a, b; - a = vmap[v0].const_val; - b = vmap[v1].const_val; + a = opt_state->vmap[v0].const_val; + b = opt_state->vmap[v1].const_val; switch (BPF_OP(s->code)) { case BPF_ADD: @@ -602,10 +624,16 @@ fold_op(struct stmt *s, int v0, int v1) case BPF_DIV: if (b == 0) - bpf_error("division by zero"); + bpf_error(cstate, "division by zero"); a /= b; break; + case BPF_MOD: + if (b == 0) + bpf_error(cstate, "modulus by zero"); + a %= b; + break; + case BPF_AND: a &= b; break; @@ -614,6 +642,10 @@ fold_op(struct stmt *s, int v0, int v1) a |= b; break; + case BPF_XOR: + a ^= b; + break; + case BPF_LSH: a <<= b; break; @@ -622,16 +654,12 @@ fold_op(struct stmt *s, int v0, int v1) a >>= b; break; - case BPF_NEG: - a = -a; - break; - default: abort(); } s->k = a; s->code = BPF_LD|BPF_IMM; - done = 0; + opt_state->done = 0; } static inline struct slist * @@ -652,7 +680,7 @@ opt_not(struct block *b) } static void -opt_peep(struct block *b) +opt_peep(opt_state_t *opt_state, struct block *b) { struct slist *s; struct slist *next, *last; @@ -687,7 +715,7 @@ opt_peep(struct block *b) if (s->s.code == BPF_ST && next->s.code == (BPF_LDX|BPF_MEM) && s->s.k == next->s.k) { - done = 0; + opt_state->done = 0; next->s.code = BPF_MISC|BPF_TAX; } /* @@ -698,7 +726,7 @@ opt_peep(struct block *b) next->s.code == (BPF_MISC|BPF_TAX)) { s->s.code = BPF_LDX|BPF_IMM; next->s.code = BPF_MISC|BPF_TXA; - done = 0; + opt_state->done = 0; } /* * This is an ugly special case, but it happens @@ -777,7 +805,7 @@ opt_peep(struct block *b) s->s.code = NOP; add->s.code = NOP; tax->s.code = NOP; - done = 0; + opt_state->done = 0; } } /* @@ -795,7 +823,7 @@ opt_peep(struct block *b) */ if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) { val = b->val[X_ATOM]; - if (vmap[val].is_const) { + if (opt_state->vmap[val].is_const) { /* * If we have a subtract to do a comparison, * and the X register is a known constant, @@ -805,9 +833,9 @@ opt_peep(struct block *b) * sub x -> nop * jeq #y jeq #(x+y) */ - b->s.k += vmap[val].const_val; + b->s.k += opt_state->vmap[val].const_val; last->s.code = NOP; - done = 0; + opt_state->done = 0; } else if (b->s.k == 0) { /* * If the X register isn't a constant, @@ -820,7 +848,7 @@ opt_peep(struct block *b) */ last->s.code = NOP; b->s.code = BPF_JMP|BPF_JEQ|BPF_X; - done = 0; + opt_state->done = 0; } } /* @@ -832,7 +860,7 @@ opt_peep(struct block *b) else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) { last->s.code = NOP; b->s.k += last->s.k; - done = 0; + opt_state->done = 0; } /* * And, similarly, a constant AND can be simplified @@ -846,7 +874,7 @@ opt_peep(struct block *b) b->s.k = last->s.k; b->s.code = BPF_JMP|BPF_K|BPF_JSET; last->s.code = NOP; - done = 0; + opt_state->done = 0; opt_not(b); } } @@ -857,7 +885,7 @@ opt_peep(struct block *b) if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) { if (b->s.k == 0) JT(b) = JF(b); - if (b->s.k == 0xffffffff) + if ((u_int)b->s.k == 0xffffffffU) JF(b) = JT(b); } /* @@ -866,8 +894,8 @@ opt_peep(struct block *b) * constant. */ val = b->val[X_ATOM]; - if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) { - bpf_int32 v = vmap[val].const_val; + if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) { + bpf_int32 v = opt_state->vmap[val].const_val; b->s.code &= ~BPF_X; b->s.k = v; } @@ -876,8 +904,8 @@ opt_peep(struct block *b) * comparison result. */ val = b->val[A_ATOM]; - if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { - bpf_int32 v = vmap[val].const_val; + if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { + bpf_int32 v = opt_state->vmap[val].const_val; switch (BPF_OP(b->s.code)) { case BPF_JEQ: @@ -885,11 +913,11 @@ opt_peep(struct block *b) break; case BPF_JGT: - v = (unsigned)v > b->s.k; + v = (unsigned)v > (unsigned)b->s.k; break; case BPF_JGE: - v = (unsigned)v >= b->s.k; + v = (unsigned)v >= (unsigned)b->s.k; break; case BPF_JSET: @@ -900,7 +928,7 @@ opt_peep(struct block *b) abort(); } if (JF(b) != JT(b)) - done = 0; + opt_state->done = 0; if (v) JF(b) = JT(b); else @@ -915,7 +943,8 @@ opt_peep(struct block *b) * evaluation and code transformations weren't folded together. */ static void -opt_stmt(struct stmt *s, int val[], int alter) +opt_stmt(compiler_state_t *cstate, struct icode *ic, opt_state_t *opt_state, + struct stmt *s, int val[], int alter) { int op; int v; @@ -925,7 +954,7 @@ opt_stmt(struct stmt *s, int val[], int alter) case BPF_LD|BPF_ABS|BPF_W: case BPF_LD|BPF_ABS|BPF_H: case BPF_LD|BPF_ABS|BPF_B: - v = F(s->code, s->k, 0L); + v = F(opt_state, s->code, s->k, 0L); vstore(s, &val[A_ATOM], v, alter); break; @@ -933,19 +962,19 @@ opt_stmt(struct stmt *s, int val[], int alter) case BPF_LD|BPF_IND|BPF_H: case BPF_LD|BPF_IND|BPF_B: v = val[X_ATOM]; - if (alter && vmap[v].is_const) { + if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code); - s->k += vmap[v].const_val; - v = F(s->code, s->k, 0L); - done = 0; + s->k += opt_state->vmap[v].const_val; + v = F(opt_state, s->code, s->k, 0L); + opt_state->done = 0; } else - v = F(s->code, s->k, v); + v = F(opt_state, s->code, s->k, v); vstore(s, &val[A_ATOM], v, alter); break; case BPF_LD|BPF_LEN: - v = F(s->code, 0L, 0L); + v = F(opt_state, s->code, 0L, 0L); vstore(s, &val[A_ATOM], v, alter); break; @@ -960,26 +989,28 @@ opt_stmt(struct stmt *s, int val[], int alter) break; case BPF_LDX|BPF_MSH|BPF_B: - v = F(s->code, s->k, 0L); + v = F(opt_state, s->code, s->k, 0L); vstore(s, &val[X_ATOM], v, alter); break; case BPF_ALU|BPF_NEG: - if (alter && vmap[val[A_ATOM]].is_const) { + if (alter && opt_state->vmap[val[A_ATOM]].is_const) { s->code = BPF_LD|BPF_IMM; - s->k = -vmap[val[A_ATOM]].const_val; + s->k = -opt_state->vmap[val[A_ATOM]].const_val; val[A_ATOM] = K(s->k); } else - val[A_ATOM] = F(s->code, val[A_ATOM], 0L); + 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); @@ -990,7 +1021,7 @@ opt_stmt(struct stmt *s, int val[], int alter) * fixup the generated math code */ if (op == BPF_ADD || op == BPF_LSH || op == BPF_RSH || - op == BPF_OR) { + op == BPF_OR || op == BPF_XOR) { s->code = NOP; break; } @@ -1000,35 +1031,37 @@ opt_stmt(struct stmt *s, int val[], int alter) break; } } - if (vmap[val[A_ATOM]].is_const) { - fold_op(s, val[A_ATOM], K(s->k)); + if (opt_state->vmap[val[A_ATOM]].is_const) { + fold_op(cstate, ic, opt_state, s, val[A_ATOM], K(s->k)); val[A_ATOM] = K(s->k); break; } } - val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k)); + 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 && vmap[val[X_ATOM]].is_const) { - if (vmap[val[A_ATOM]].is_const) { - fold_op(s, val[A_ATOM], val[X_ATOM]); + if (alter && opt_state->vmap[val[X_ATOM]].is_const) { + if (opt_state->vmap[val[A_ATOM]].is_const) { + fold_op(cstate, ic, 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 = vmap[val[X_ATOM]].const_val; - done = 0; + s->k = opt_state->vmap[val[X_ATOM]].const_val; + opt_state->done = 0; val[A_ATOM] = - F(s->code, val[A_ATOM], K(s->k)); + F(opt_state, s->code, val[A_ATOM], K(s->k)); } break; } @@ -1039,14 +1072,14 @@ opt_stmt(struct stmt *s, int val[], int alter) * optimizations. * XXX We could also check for mul by 1, etc. */ - if (alter && vmap[val[A_ATOM]].is_const - && vmap[val[A_ATOM]].const_val == 0) { - if (op == BPF_ADD || op == BPF_OR) { + 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 || + 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; @@ -1058,7 +1091,7 @@ opt_stmt(struct stmt *s, int val[], int alter) break; } } - val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]); + val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]); break; case BPF_MISC|BPF_TXA: @@ -1067,10 +1100,10 @@ opt_stmt(struct stmt *s, int val[], int alter) case BPF_LD|BPF_MEM: v = val[s->k]; - if (alter && vmap[v].is_const) { + if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LD|BPF_IMM; - s->k = vmap[v].const_val; - done = 0; + s->k = opt_state->vmap[v].const_val; + opt_state->done = 0; } vstore(s, &val[A_ATOM], v, alter); break; @@ -1081,10 +1114,10 @@ opt_stmt(struct stmt *s, int val[], int alter) case BPF_LDX|BPF_MEM: v = val[s->k]; - if (alter && vmap[v].is_const) { + if (alter && opt_state->vmap[v].is_const) { s->code = BPF_LDX|BPF_IMM; - s->k = vmap[v].const_val; - done = 0; + s->k = opt_state->vmap[v].const_val; + opt_state->done = 0; } vstore(s, &val[X_ATOM], v, alter); break; @@ -1100,7 +1133,7 @@ opt_stmt(struct stmt *s, int val[], int alter) } static void -deadstmt(register struct stmt *s, register struct stmt *last[]) +deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[]) { register int atom; @@ -1116,7 +1149,7 @@ deadstmt(register struct stmt *s, register struct stmt *last[]) atom = atomdef(s); if (atom >= 0) { if (last[atom]) { - done = 0; + opt_state->done = 0; last[atom]->code = NOP; } last[atom] = s; @@ -1124,7 +1157,7 @@ deadstmt(register struct stmt *s, register struct stmt *last[]) } static void -opt_deadstores(register struct block *b) +opt_deadstores(opt_state_t *opt_state, register struct block *b) { register struct slist *s; register int atom; @@ -1133,18 +1166,19 @@ opt_deadstores(register struct block *b) memset((char *)last, 0, sizeof last); for (s = b->stmts; s != 0; s = s->next) - deadstmt(&s->s, last); - deadstmt(&b->s, last); + 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; - done = 0; + opt_state->done = 0; } } static void -opt_blk(struct block *b, int do_stmts) +opt_blk(compiler_state_t *cstate, struct icode *ic, opt_state_t *opt_state, + struct block *b, int do_stmts) { struct slist *s; struct edge *p; @@ -1194,7 +1228,7 @@ opt_blk(struct block *b, int do_stmts) aval = b->val[A_ATOM]; xval = b->val[X_ATOM]; for (s = b->stmts; s; s = s->next) - opt_stmt(&s->s, b->val, do_stmts); + opt_stmt(cstate, ic, opt_state, &s->s, b->val, do_stmts); /* * This is a special case: if we don't use anything from this @@ -1225,11 +1259,11 @@ opt_blk(struct block *b, int do_stmts) BPF_CLASS(b->s.code) == BPF_RET)) { if (b->stmts != 0) { b->stmts = 0; - done = 0; + opt_state->done = 0; } } else { - opt_peep(b); - opt_deadstores(b); + opt_peep(opt_state, b); + opt_deadstores(opt_state, b); } /* * Set up values for branch optimizer. @@ -1316,7 +1350,7 @@ fold_edge(struct block *child, struct edge *ep) } static void -opt_j(struct edge *ep) +opt_j(opt_state_t *opt_state, struct edge *ep) { register int i, k; register struct block *target; @@ -1330,7 +1364,7 @@ opt_j(struct edge *ep) * there is no data dependency. */ if (!use_conflict(ep->pred, ep->succ->et.succ)) { - done = 0; + opt_state->done = 0; ep->succ = JT(ep->succ); } } @@ -1342,7 +1376,7 @@ opt_j(struct edge *ep) * efficient loop. */ top: - for (i = 0; i < edgewords; ++i) { + for (i = 0; i < opt_state->edgewords; ++i) { register bpf_u_int32 x = ep->edom[i]; while (x != 0) { @@ -1350,13 +1384,13 @@ opt_j(struct edge *ep) x &=~ (1 << k); k += i * BITS_PER_WORD; - target = fold_edge(ep->succ, edges[k]); + target = fold_edge(ep->succ, opt_state->edges[k]); /* * Check that there is no data dependency between * nodes that will be violated if we move the edge. */ if (target != 0 && !use_conflict(ep->pred, target)) { - done = 0; + opt_state->done = 0; ep->succ = target; if (JT(target) != 0) /* @@ -1371,7 +1405,7 @@ opt_j(struct edge *ep) static void -or_pullup(struct block *b) +or_pullup(opt_state_t *opt_state, struct block *b) { int val, at_top; struct block *pull; @@ -1459,11 +1493,11 @@ or_pullup(struct block *b) else *diffp = pull; - done = 0; + opt_state->done = 0; } static void -and_pullup(struct block *b) +and_pullup(opt_state_t *opt_state, struct block *b) { int val, at_top; struct block *pull; @@ -1550,22 +1584,23 @@ and_pullup(struct block *b) else *diffp = pull; - done = 0; + opt_state->done = 0; } static void -opt_blks(struct block *root, int do_stmts) +opt_blks(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, + int do_stmts) { int i, maxlevel; struct block *p; - init_val(); - maxlevel = root->level; + init_val(opt_state); + maxlevel = ic->root->level; - find_inedges(root); + find_inedges(opt_state, ic->root); for (i = maxlevel; i >= 0; --i) - for (p = levels[i]; p; p = p->link) - opt_blk(p, do_stmts); + for (p = opt_state->levels[i]; p; p = p->link) + opt_blk(cstate, ic, opt_state, p, do_stmts); if (do_stmts) /* @@ -1575,17 +1610,17 @@ opt_blks(struct block *root, int do_stmts) return; for (i = 1; i <= maxlevel; ++i) { - for (p = levels[i]; p; p = p->link) { - opt_j(&p->et); - opt_j(&p->ef); + for (p = opt_state->levels[i]; p; p = p->link) { + opt_j(opt_state, &p->et); + opt_j(opt_state, &p->ef); } } - find_inedges(root); + find_inedges(opt_state, ic->root); for (i = 1; i <= maxlevel; ++i) { - for (p = levels[i]; p; p = p->link) { - or_pullup(p); - and_pullup(p); + for (p = opt_state->levels[i]; p; p = p->link) { + or_pullup(opt_state, p); + and_pullup(opt_state, p); } } } @@ -1598,20 +1633,20 @@ link_inedge(struct edge *parent, struct block *child) } static void -find_inedges(struct block *root) +find_inedges(opt_state_t *opt_state, struct block *root) { int i; struct block *b; - for (i = 0; i < n_blocks; ++i) - blocks[i]->in_edges = 0; + 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 (i = root->level; i > 0; --i) { - for (b = levels[i]; b != 0; b = b->link) { + for (b = opt_state->levels[i]; b != 0; b = b->link) { link_inedge(&b->et, JT(b)); link_inedge(&b->ef, JF(b)); } @@ -1643,83 +1678,82 @@ opt_root(struct block **b) } static void -opt_loop(struct block *root, int do_stmts) +opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, + int do_stmts) { #ifdef BDEBUG - if (dflag > 1) { + if (pcap_optimizer_debug > 1) { printf("opt_loop(root, %d) begin\n", do_stmts); - opt_dump(root); + opt_dump(cstate, ic); } #endif do { - done = 1; - find_levels(root); - find_dom(root); - find_closure(root); - find_ud(root); - find_edom(root); - opt_blks(root, do_stmts); + opt_state->done = 1; + 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(cstate, opt_state, ic, do_stmts); #ifdef BDEBUG - if (dflag > 1) { - printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, done); - opt_dump(root); + if (pcap_optimizer_debug > 1) { + printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done); + opt_dump(cstate, ic); } #endif - } while (!done); + } while (!opt_state->done); } /* * Optimize the filter code in its dag representation. */ void -bpf_optimize(struct block **rootp) +bpf_optimize(compiler_state_t *cstate, struct icode *ic) { - struct block *root; + opt_state_t opt_state; - root = *rootp; - - opt_init(root); - opt_loop(root, 0); - opt_loop(root, 1); - intern_blocks(root); + opt_init(cstate, &opt_state, ic); + opt_loop(cstate, &opt_state, ic, 0); + opt_loop(cstate, &opt_state, ic, 1); + intern_blocks(&opt_state, ic); #ifdef BDEBUG - if (dflag > 1) { + if (pcap_optimizer_debug > 1) { printf("after intern_blocks()\n"); - opt_dump(root); + opt_dump(cstate, ic); } #endif - opt_root(rootp); + opt_root(&ic->root); #ifdef BDEBUG - if (dflag > 1) { + if (pcap_optimizer_debug > 1) { printf("after opt_root()\n"); - opt_dump(root); + opt_dump(cstate, ic); } #endif - opt_cleanup(); + opt_cleanup(&opt_state); } static void -make_marks(struct block *p) +make_marks(struct icode *ic, struct block *p) { - if (!isMarked(p)) { - Mark(p); + if (!isMarked(ic, p)) { + Mark(ic, p); if (BPF_CLASS(p->s.code) != BPF_RET) { - make_marks(JT(p)); - make_marks(JF(p)); + make_marks(ic, JT(p)); + make_marks(ic, JF(p)); } } } /* - * Mark code array such that isMarked(i) is true + * Mark code array such that isMarked(ic->cur_mark, i) is true * only for nodes that are alive. */ static void -mark_code(struct block *p) +mark_code(struct icode *ic) { - cur_mark += 1; - make_marks(p); + ic->cur_mark += 1; + make_marks(ic, ic->root); } /* @@ -1757,33 +1791,33 @@ eq_blk(struct block *b0, struct block *b1) } static void -intern_blocks(struct block *root) +intern_blocks(opt_state_t *opt_state, struct icode *ic) { struct block *p; int i, j; int done1; /* don't shadow global */ top: done1 = 1; - for (i = 0; i < n_blocks; ++i) - blocks[i]->link = 0; + for (i = 0; i < opt_state->n_blocks; ++i) + opt_state->blocks[i]->link = 0; - mark_code(root); + mark_code(ic); - for (i = n_blocks - 1; --i >= 0; ) { - if (!isMarked(blocks[i])) + for (i = opt_state->n_blocks - 1; --i >= 0; ) { + if (!isMarked(ic, opt_state->blocks[i])) continue; - for (j = i + 1; j < n_blocks; ++j) { - if (!isMarked(blocks[j])) + for (j = i + 1; j < opt_state->n_blocks; ++j) { + if (!isMarked(ic, opt_state->blocks[j])) continue; - if (eq_blk(blocks[i], blocks[j])) { - blocks[i]->link = blocks[j]->link ? - blocks[j]->link : blocks[j]; + 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 < n_blocks; ++i) { - p = blocks[i]; + for (i = 0; i < opt_state->n_blocks; ++i) { + p = opt_state->blocks[i]; if (JT(p) == 0) continue; if (JT(p)->link) { @@ -1800,14 +1834,14 @@ intern_blocks(struct block *root) } static void -opt_cleanup(void) +opt_cleanup(opt_state_t *opt_state) { - free((void *)vnode_base); - free((void *)vmap); - free((void *)edges); - free((void *)space); - free((void *)levels); - free((void *)blocks); + 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); } /* @@ -1829,12 +1863,12 @@ slength(struct slist *s) * All nodes should be initially unmarked. */ static int -count_blocks(struct block *p) +count_blocks(struct icode *ic, struct block *p) { - if (p == 0 || isMarked(p)) + if (p == 0 || isMarked(ic, p)) return 0; - Mark(p); - return count_blocks(JT(p)) + count_blocks(JF(p)) + 1; + Mark(ic, p); + return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1; } /* @@ -1842,20 +1876,20 @@ count_blocks(struct block *p) * the basic blocks, and entering them into the 'blocks' array.` */ static void -number_blks_r(struct block *p) +number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p) { int n; - if (p == 0 || isMarked(p)) + if (p == 0 || isMarked(ic, p)) return; - Mark(p); - n = n_blocks++; + Mark(ic, p); + n = opt_state->n_blocks++; p->id = n; - blocks[n] = p; + opt_state->blocks[n] = p; - number_blks_r(JT(p)); - number_blks_r(JF(p)); + number_blks_r(opt_state, ic, JT(p)); + number_blks_r(opt_state, ic, JF(p)); } /* @@ -1877,14 +1911,14 @@ number_blks_r(struct block *p) * an extra long jump if the false branch requires it (p->longjf). */ static u_int -count_stmts(struct block *p) +count_stmts(struct icode *ic, struct block *p) { u_int n; - if (p == 0 || isMarked(p)) + if (p == 0 || isMarked(ic, p)) return 0; - Mark(p); - n = count_stmts(JT(p)) + count_stmts(JF(p)); + Mark(ic, p); + n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p)); return slength(p->stmts) + n + 1 + p->longjt + p->longjf; } @@ -1894,7 +1928,7 @@ count_stmts(struct block *p) * from the total number of blocks and/or statements. */ static void -opt_init(struct block *root) +opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) { bpf_u_int32 *p; int i, n, max_stmts; @@ -1903,84 +1937,81 @@ opt_init(struct block *root) * First, count the blocks, so we can malloc an array to map * block number to block. Then, put the blocks into the array. */ - unMarkAll(); - n = count_blocks(root); - blocks = (struct block **)calloc(n, sizeof(*blocks)); - if (blocks == NULL) - bpf_error("malloc"); - unMarkAll(); - n_blocks = 0; - number_blks_r(root); - - n_edges = 2 * n_blocks; - edges = (struct edge **)calloc(n_edges, sizeof(*edges)); - if (edges == NULL) - bpf_error("malloc"); + unMarkAll(ic); + n = count_blocks(ic, ic->root); + opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks)); + if (opt_state->blocks == NULL) + bpf_error(cstate, "malloc"); + unMarkAll(ic); + opt_state->n_blocks = 0; + number_blks_r(opt_state, ic, ic->root); + + opt_state->n_edges = 2 * opt_state->n_blocks; + opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges)); + if (opt_state->edges == NULL) + bpf_error(cstate, "malloc"); /* * The number of levels is bounded by the number of nodes. */ - levels = (struct block **)calloc(n_blocks, sizeof(*levels)); - if (levels == NULL) - bpf_error("malloc"); + opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels)); + if (opt_state->levels == NULL) + bpf_error(cstate, "malloc"); - edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1; - nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1; + opt_state->edgewords = opt_state->n_edges / (8 * sizeof(bpf_u_int32)) + 1; + opt_state->nodewords = opt_state->n_blocks / (8 * sizeof(bpf_u_int32)) + 1; /* XXX */ - space = (bpf_u_int32 *)malloc(2 * n_blocks * nodewords * sizeof(*space) - + n_edges * edgewords * sizeof(*space)); - if (space == NULL) - bpf_error("malloc"); - p = space; - all_dom_sets = p; + opt_state->space = (bpf_u_int32 *)malloc(2 * opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->space) + + opt_state->n_edges * opt_state->edgewords * sizeof(*opt_state->space)); + if (opt_state->space == NULL) + bpf_error(cstate, "malloc"); + p = opt_state->space; + opt_state->all_dom_sets = p; for (i = 0; i < n; ++i) { - blocks[i]->dom = p; - p += nodewords; + opt_state->blocks[i]->dom = p; + p += opt_state->nodewords; } - all_closure_sets = p; + opt_state->all_closure_sets = p; for (i = 0; i < n; ++i) { - blocks[i]->closure = p; - p += nodewords; + opt_state->blocks[i]->closure = p; + p += opt_state->nodewords; } - all_edge_sets = p; + opt_state->all_edge_sets = p; for (i = 0; i < n; ++i) { - register struct block *b = blocks[i]; + register struct block *b = opt_state->blocks[i]; b->et.edom = p; - p += edgewords; + p += opt_state->edgewords; b->ef.edom = p; - p += edgewords; + p += opt_state->edgewords; b->et.id = i; - edges[i] = &b->et; - b->ef.id = n_blocks + i; - edges[n_blocks + i] = &b->ef; + 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(blocks[i]->stmts) + 1; + 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. */ - maxval = 3 * max_stmts; - vmap = (struct vmapinfo *)calloc(maxval, sizeof(*vmap)); - vnode_base = (struct valnode *)calloc(maxval, sizeof(*vnode_base)); - if (vmap == NULL || vnode_base == NULL) - bpf_error("malloc"); + opt_state->maxval = 3 * max_stmts; + opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap)); + opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base)); + if (opt_state->vmap == NULL || opt_state->vnode_base == NULL) + bpf_error(cstate, "malloc"); } /* - * 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. + * 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. */ -static struct bpf_insn *fstart; -static struct bpf_insn *ftail; - #ifdef BDEBUG int bids[1000]; #endif @@ -1992,35 +2023,36 @@ int bids[1000]; * properly. */ static int -convert_code_r(struct block *p) +convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, + struct icode *ic, struct block *p) { struct bpf_insn *dst; struct slist *src; - int slen; + u_int slen; u_int off; int extrajmps; /* number of extra jumps inserted */ struct slist **offset = NULL; - if (p == 0 || isMarked(p)) + if (p == 0 || isMarked(ic, p)) return (1); - Mark(p); + Mark(ic, p); - if (convert_code_r(JF(p)) == 0) + if (convert_code_r(cstate, conv_state, ic, JF(p)) == 0) return (0); - if (convert_code_r(JT(p)) == 0) + if (convert_code_r(cstate, conv_state, ic, JT(p)) == 0) return (0); slen = slength(p->stmts); - dst = ftail -= (slen + 1 + p->longjt + p->longjf); + dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf); /* inflate length by any extra jumps */ - p->offset = dst - fstart; + p->offset = (int)(dst - conv_state->fstart); /* generate offset[] for convenience */ if (slen) { offset = (struct slist **)calloc(slen, sizeof(struct slist *)); if (!offset) { - bpf_error("not enough core"); + bpf_error(cstate, "not enough core"); /*NOTREACHED*/ } } @@ -2044,7 +2076,7 @@ convert_code_r(struct block *p) if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) { #if 0 if (src->s.jt || src->s.jf) { - bpf_error("illegal jmp destination"); + bpf_error(cstate, "illegal jmp destination"); /*NOTREACHED*/ } #endif @@ -2054,7 +2086,7 @@ convert_code_r(struct block *p) goto filled; { - int i; + u_int i; int jt, jf; const char *ljerr = "%s for block-local relative jump: off=%d"; @@ -2064,7 +2096,7 @@ convert_code_r(struct block *p) #endif if (!src->s.jt || !src->s.jf) { - bpf_error(ljerr, "no jmp destination", off); + bpf_error(cstate, ljerr, "no jmp destination", off); /*NOTREACHED*/ } @@ -2072,7 +2104,7 @@ convert_code_r(struct block *p) for (i = 0; i < slen; i++) { if (offset[i] == src->s.jt) { if (jt) { - bpf_error(ljerr, "multiple matches", off); + bpf_error(cstate, ljerr, "multiple matches", off); /*NOTREACHED*/ } @@ -2081,7 +2113,7 @@ convert_code_r(struct block *p) } if (offset[i] == src->s.jf) { if (jf) { - bpf_error(ljerr, "multiple matches", off); + bpf_error(cstate, ljerr, "multiple matches", off); /*NOTREACHED*/ } dst->jf = i - off - 1; @@ -2089,7 +2121,7 @@ convert_code_r(struct block *p) } } if (!jt || !jf) { - bpf_error(ljerr, "no destination found", off); + bpf_error(cstate, ljerr, "no destination found", off); /*NOTREACHED*/ } } @@ -2101,7 +2133,7 @@ filled: free(offset); #ifdef BDEBUG - bids[dst - fstart] = p->id + 1; + bids[dst - conv_state->fstart] = p->id + 1; #endif dst->code = (u_short)p->s.code; dst->k = p->s.k; @@ -2164,28 +2196,30 @@ filled: * done with the filter program. See the pcap man page. */ struct bpf_insn * -icode_to_fcode(struct block *root, u_int *lenp) +icode_to_fcode(compiler_state_t *cstate, struct icode *ic, + struct block *root, u_int *lenp) { u_int n; struct bpf_insn *fp; + conv_state_t conv_state; /* * Loop doing convert_code_r() until no branches remain * with too-large offsets. */ while (1) { - unMarkAll(); - n = *lenp = count_stmts(root); + unMarkAll(ic); + n = *lenp = count_stmts(ic, root); fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); if (fp == NULL) - bpf_error("malloc"); + bpf_error(cstate, "malloc"); memset((char *)fp, 0, sizeof(*fp) * n); - fstart = fp; - ftail = fp + n; + conv_state.fstart = fp; + conv_state.ftail = fp + n; - unMarkAll(); - if (convert_code_r(root)) + unMarkAll(ic); + if (convert_code_r(cstate, &conv_state, ic, root)) break; free(fp); } @@ -2210,7 +2244,7 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp) * Validate the program. */ if (!bpf_validate(fp->bf_insns, fp->bf_len)) { - snprintf(p->errbuf, sizeof(p->errbuf), + pcap_snprintf(p->errbuf, sizeof(p->errbuf), "BPF program is not valid"); return (-1); } @@ -2224,7 +2258,7 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp) p->fcode.bf_len = fp->bf_len; p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); if (p->fcode.bf_insns == NULL) { - snprintf(p->errbuf, sizeof(p->errbuf), + pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } @@ -2234,14 +2268,117 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp) #ifdef BDEBUG static void -opt_dump(struct block *root) +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%d [shape=ellipse, id=\"block-%d\" label=\"BLOCK%d\\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] != 0) + 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%d\":se -> \"block%d\":n [label=\"T\"]; \n", + block->id, JT(block)->id); + fprintf(out, "\t\"block%d\":sw -> \"block%d\":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"]; + } + * + * After install graphviz on http://www.graphviz.org/, save it as bpf.dot + * and run `dot -Tpng -O bpf.dot' to draw the graph. + */ +static void +dot_dump(compiler_state_t *cstate, struct icode *ic) { struct bpf_program f; + FILE *out = stdout; memset(bids, 0, sizeof bids); - f.bf_insns = icode_to_fcode(root, &f.bf_len); + f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len); + + fprintf(out, "digraph BPF {\n"); + ic->cur_mark = 0; + unMarkAll(ic); + dot_dump_node(ic, ic->root, &f, out); + ic->cur_mark = 0; + unMarkAll(ic); + dot_dump_edge(ic, ic->root, out); + fprintf(out, "}\n"); + + free((char *)f.bf_insns); +} + +static void +plain_dump(compiler_state_t *cstate, struct icode *ic) +{ + struct bpf_program f; + + memset(bids, 0, sizeof bids); + f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len); bpf_dump(&f, 1); putchar('\n'); free((char *)f.bf_insns); } + +static void +opt_dump(compiler_state_t *cstate, struct icode *ic) +{ + /* if optimizer debugging is enabled, output DOT graph + * `pcap_optimizer_debug=4' is equivalent to -dddd to follow -d/-dd/-ddd + * convention in tcpdump command line + */ + if (pcap_optimizer_debug > 3) + dot_dump(cstate, ic); + else + plain_dump(cstate, ic); +} #endif diff --git a/contrib/libpcap/pcap-bpf.c b/contrib/libpcap/pcap-bpf.c index 9e739dc6a4..b765904d7c 100644 --- a/contrib/libpcap/pcap-bpf.c +++ b/contrib/libpcap/pcap-bpf.c @@ -18,10 +18,6 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.116 2008-09-16 18:42:29 guy Exp $ (LBL)"; -#endif #ifdef HAVE_CONFIG_H #include "config.h" @@ -52,6 +48,15 @@ static const char rcsid[] _U_ = #endif #include +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) +/* + * Add support for capturing on FreeBSD usbusN interfaces. + */ +static const char usbus_prefix[] = "usbus"; +#define USBUS_PREFIX_LEN (sizeof(usbus_prefix) - 1) +#include +#endif + #ifdef HAVE_ZEROCOPY_BPF #include #endif @@ -126,9 +131,68 @@ static int bpf_load(char *errbuf); #include "os-proto.h" #endif +/* + * Later versions of NetBSD stick padding in front of FDDI frames + * to align the IP header on a 4-byte boundary. + */ +#if defined(__NetBSD__) && __NetBSD_Version__ > 106000000 +#define PCAP_FDDIPAD 3 +#endif + +/* + * Private data for capturing on BPF devices. + */ +struct pcap_bpf { +#ifdef HAVE_ZEROCOPY_BPF + /* + * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will + * alternative between these two actual mmap'd buffers as required. + * As there is a header on the front size of the mmap'd buffer, only + * some of the buffer is exposed to libpcap as a whole via bufsize; + * zbufsize is the true size. zbuffer tracks the current zbuf + * assocated with buffer so that it can be used to decide which the + * next buffer to read will be. + */ + u_char *zbuf1, *zbuf2, *zbuffer; + u_int zbufsize; + u_int zerocopy; + u_int interrupted; + struct timespec firstsel; + /* + * If there's currently a buffer being actively processed, then it is + * referenced here; 'buffer' is also pointed at it, but offset by the + * size of the header. + */ + struct bpf_zbuf_header *bzh; + int nonblock; /* true if in nonblocking mode */ +#endif /* HAVE_ZEROCOPY_BPF */ + + char *device; /* device name */ + int filtering_in_kernel; /* using kernel filter */ + int must_do_on_close; /* stuff we must do when we close */ +}; + +/* + * Stuff to do when we close. + */ +#define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ +#define MUST_DESTROY_USBUS 0x00000002 /* destroy usbusN interface */ + #ifdef BIOCGDLTLIST # if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__) #define HAVE_BSD_IEEE80211 + +/* + * The ifm_ulist member of a struct ifmediareq is an int * on most systems, + * but it's a uint64_t on newer versions of OpenBSD. + * + * We check this by checking whether IFM_GMASK is defined and > 2^32-1. + */ +# if defined(IFM_GMASK) && IFM_GMASK > 0xFFFFFFFF +# define IFM_ULIST_TYPE uint64_t +# else +# define IFM_ULIST_TYPE int +# endif # endif # if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) @@ -184,49 +248,29 @@ static int pcap_set_datalink_bpf(pcap_t *p, int dlt); /* * For zerocopy bpf, the setnonblock/getnonblock routines need to modify - * p->md.timeout so we don't call select(2) if the pcap handle is in non- - * blocking mode. We preserve the timeout supplied by pcap_open functions - * to make sure it does not get clobbered if the pcap handle moves between - * blocking and non-blocking mode. + * pb->nonblock so we don't call select(2) if the pcap handle is in non- + * blocking mode. */ static int pcap_getnonblock_bpf(pcap_t *p, char *errbuf) -{ +{ #ifdef HAVE_ZEROCOPY_BPF - if (p->md.zerocopy) { - /* - * Use a negative value for the timeout to represent that the - * pcap handle is in non-blocking mode. - */ - return (p->md.timeout < 0); - } + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) + return (pb->nonblock); #endif return (pcap_getnonblock_fd(p, errbuf)); } static int pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) -{ +{ #ifdef HAVE_ZEROCOPY_BPF - if (p->md.zerocopy) { - /* - * Map each value to their corresponding negation to - * preserve the timeout value provided with pcap_set_timeout. - * (from pcap-linux.c). - */ - if (nonblock) { - if (p->md.timeout >= 0) { - /* - * Indicate that we're switching to - * non-blocking mode. - */ - p->md.timeout = ~p->md.timeout; - } - } else { - if (p->md.timeout < 0) { - p->md.timeout = ~p->md.timeout; - } - } + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) { + pb->nonblock = nonblock; return (0); } #endif @@ -246,25 +290,26 @@ pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) static int pcap_next_zbuf_shm(pcap_t *p, int *cc) { + struct pcap_bpf *pb = p->priv; struct bpf_zbuf_header *bzh; - if (p->md.zbuffer == p->md.zbuf2 || p->md.zbuffer == NULL) { - bzh = (struct bpf_zbuf_header *)p->md.zbuf1; + if (pb->zbuffer == pb->zbuf2 || pb->zbuffer == NULL) { + bzh = (struct bpf_zbuf_header *)pb->zbuf1; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { - p->md.bzh = bzh; - p->md.zbuffer = (u_char *)p->md.zbuf1; - p->buffer = p->md.zbuffer + sizeof(*bzh); + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf1; + p->buffer = pb->zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } - } else if (p->md.zbuffer == p->md.zbuf1) { - bzh = (struct bpf_zbuf_header *)p->md.zbuf2; + } else if (pb->zbuffer == pb->zbuf1) { + bzh = (struct bpf_zbuf_header *)pb->zbuf2; if (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)) { - p->md.bzh = bzh; - p->md.zbuffer = (u_char *)p->md.zbuf2; - p->buffer = p->md.zbuffer + sizeof(*bzh); + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf2; + p->buffer = pb->zbuffer + sizeof(*bzh); *cc = bzh->bzh_kernel_len; return (1); } @@ -283,6 +328,7 @@ pcap_next_zbuf_shm(pcap_t *p, int *cc) static int pcap_next_zbuf(pcap_t *p, int *cc) { + struct pcap_bpf *pb = p->priv; struct bpf_zbuf bz; struct timeval tv; struct timespec cur; @@ -306,20 +352,20 @@ pcap_next_zbuf(pcap_t *p, int *cc) * our timeout is less then or equal to zero, handle it like a * regular timeout. */ - tmout = p->md.timeout; + tmout = p->opt.timeout; if (tmout) (void) clock_gettime(CLOCK_MONOTONIC, &cur); - if (p->md.interrupted && p->md.timeout) { - expire = TSTOMILLI(&p->md.firstsel) + p->md.timeout; + if (pb->interrupted && p->opt.timeout) { + expire = TSTOMILLI(&pb->firstsel) + p->opt.timeout; tmout = expire - TSTOMILLI(&cur); #undef TSTOMILLI if (tmout <= 0) { - p->md.interrupted = 0; + pb->interrupted = 0; data = pcap_next_zbuf_shm(p, cc); if (data) return (data); if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { - (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } @@ -331,7 +377,7 @@ pcap_next_zbuf(pcap_t *p, int *cc) * the next timeout. Note that we only call select if the handle * is in blocking mode. */ - if (p->md.timeout >= 0) { + if (!pb->nonblock) { FD_ZERO(&r_set); FD_SET(p->fd, &r_set); if (tmout != 0) { @@ -339,20 +385,20 @@ pcap_next_zbuf(pcap_t *p, int *cc) tv.tv_usec = (tmout * 1000) % 1000000; } r = select(p->fd + 1, &r_set, NULL, NULL, - p->md.timeout != 0 ? &tv : NULL); + p->opt.timeout != 0 ? &tv : NULL); if (r < 0 && errno == EINTR) { - if (!p->md.interrupted && p->md.timeout) { - p->md.interrupted = 1; - p->md.firstsel = cur; + if (!pb->interrupted && p->opt.timeout) { + pb->interrupted = 1; + pb->firstsel = cur; } return (0); } else if (r < 0) { - (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "select: %s", strerror(errno)); return (PCAP_ERROR); } } - p->md.interrupted = 0; + pb->interrupted = 0; /* * Check again for data, which may exist now that we've either been * woken up as a result of data or timed out. Try the "there's data" @@ -366,7 +412,7 @@ pcap_next_zbuf(pcap_t *p, int *cc) * data. */ if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { - (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCROTZBUF: %s", strerror(errno)); return (PCAP_ERROR); } @@ -380,26 +426,43 @@ pcap_next_zbuf(pcap_t *p, int *cc) static int pcap_ack_zbuf(pcap_t *p) { + struct pcap_bpf *pb = p->priv; - atomic_store_rel_int(&p->md.bzh->bzh_user_gen, - p->md.bzh->bzh_kernel_gen); - p->md.bzh = NULL; + atomic_store_rel_int(&pb->bzh->bzh_user_gen, + pb->bzh->bzh_kernel_gen); + pb->bzh = NULL; p->buffer = NULL; return (0); } #endif /* HAVE_ZEROCOPY_BPF */ pcap_t * -pcap_create_interface(const char *device, char *ebuf) +pcap_create_interface(const char *device _U_, char *ebuf) { pcap_t *p; - p = pcap_create_common(device, ebuf); + p = pcap_create_common(ebuf, sizeof (struct pcap_bpf)); if (p == NULL) return (NULL); p->activate_op = pcap_activate_bpf; p->can_set_rfmon_op = pcap_can_set_rfmon_bpf; +#ifdef BIOCSTSTAMP + /* + * We claim that we support microsecond and nanosecond time + * stamps. + */ + p->tstamp_precision_count = 2; + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; +#endif /* BIOCSTSTAMP */ return (p); } @@ -408,7 +471,7 @@ pcap_create_interface(const char *device, char *ebuf) * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf. */ static int -bpf_open(pcap_t *p) +bpf_open(char *errbuf) { int fd; #ifdef HAVE_CLONING_BPF @@ -424,7 +487,7 @@ bpf_open(pcap_t *p) * and create the BPF device entries, if they don't * already exist. */ - if (bpf_load(p->errbuf) == PCAP_ERROR) + if (bpf_load(errbuf) == PCAP_ERROR) return (PCAP_ERROR); #endif @@ -435,7 +498,7 @@ bpf_open(pcap_t *p) fd = PCAP_ERROR_PERM_DENIED; else fd = PCAP_ERROR; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open device) %s: %s", device, pcap_strerror(errno)); } #else @@ -443,7 +506,7 @@ bpf_open(pcap_t *p) * Go through all the minors and find one that isn't in use. */ do { - (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); + (void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++); /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission @@ -477,7 +540,7 @@ bpf_open(pcap_t *p) * means we probably have no BPF * devices. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(there are no BPF devices)"); } else { /* @@ -486,7 +549,7 @@ bpf_open(pcap_t *p) * devices, but all the ones * that exist are busy. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(all BPF devices are busy)"); } break; @@ -498,7 +561,7 @@ bpf_open(pcap_t *p) * if any. */ fd = PCAP_ERROR_PERM_DENIED; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; @@ -508,7 +571,7 @@ bpf_open(pcap_t *p) * Some other problem. */ fd = PCAP_ERROR; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "(cannot open BPF device) %s: %s", device, pcap_strerror(errno)); break; @@ -519,6 +582,66 @@ bpf_open(pcap_t *p) return (fd); } +/* + * Open and bind to a device; used if we're not actually going to use + * the device, but are just testing whether it can be opened, or opening + * it to get information about it. + * + * Returns an error code on failure (always negative), and an FD for + * the now-bound BPF device on success (always non-negative). + */ +static int +bpf_open_and_bind(const char *name, char *errbuf) +{ + int fd; + struct ifreq ifr; + + /* + * First, open a BPF device. + */ + fd = bpf_open(errbuf); + if (fd < 0) + return (fd); /* fd is the appropriate error code */ + + /* + * Now bind to the device. + */ + (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { + switch (errno) { + + case ENXIO: + /* + * There's no such device. + */ + close(fd); + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case 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. + */ + close(fd); + return (PCAP_ERROR_IFACE_NOT_UP); + + default: + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "BIOCSETIF: %s: %s", name, pcap_strerror(errno)); + close(fd); + return (PCAP_ERROR); + } + } + + /* + * Success. + */ + return (fd); +} + #ifdef BIOCGDLTLIST static int get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) @@ -530,13 +653,13 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); if (bdlp->bfl_list == NULL) { - (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { - (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); free(bdlp->bfl_list); return (PCAP_ERROR); @@ -591,7 +714,7 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) * this device"; don't treat it as an error. */ if (errno != EINVAL) { - (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); return (PCAP_ERROR); } @@ -650,7 +773,7 @@ pcap_can_set_rfmon_bpf(pcap_t *p) * 10.4 (Darwin 8.x). s/en/wlt/, and check * whether the device exists. */ - if (strncmp(p->opt.source, "en", 2) != 0) { + if (strncmp(p->opt.device, "en", 2) != 0) { /* * Not an enN device; no monitor mode. */ @@ -658,12 +781,12 @@ pcap_can_set_rfmon_bpf(pcap_t *p) } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); - strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name)); + strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * No such device? @@ -683,14 +806,14 @@ pcap_can_set_rfmon_bpf(pcap_t *p) * * First, open a BPF device. */ - fd = bpf_open(p); + fd = bpf_open(p->errbuf); if (fd < 0) return (fd); /* fd is the appropriate error code */ /* * Now bind to the device. */ - (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); + (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { switch (errno) { @@ -713,9 +836,9 @@ pcap_can_set_rfmon_bpf(pcap_t *p) return (PCAP_ERROR_IFACE_NOT_UP); default: - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - p->opt.source, pcap_strerror(errno)); + p->opt.device, pcap_strerror(errno)); close(fd); return (PCAP_ERROR); } @@ -741,6 +864,7 @@ pcap_can_set_rfmon_bpf(pcap_t *p) return (1); } free(bdl.bfl_list); + close(fd); #endif /* BIOCGDLTLIST */ return (0); #elif defined(HAVE_BSD_IEEE80211) @@ -776,7 +900,7 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) * by libpcap, and thus not yet seen by the application. */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", pcap_strerror(errno)); return (PCAP_ERROR); } @@ -790,12 +914,13 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) static int pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { + struct pcap_bpf *pb = p->priv; int cc; int n = 0; register u_char *bp, *ep; u_char *datap; #ifdef PCAP_FDDIPAD - register int pad; + register u_int pad; #endif #ifdef HAVE_ZEROCOPY_BPF int i; @@ -825,7 +950,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * buffer. */ #ifdef HAVE_ZEROCOPY_BPF - if (p->md.zerocopy) { + if (pb->zerocopy) { if (p->buffer != NULL) pcap_ack_zbuf(p); i = pcap_next_zbuf(p, &cc); @@ -836,7 +961,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } else #endif { - cc = read(p->fd, (char *)p->buffer, p->bufsize); + cc = read(p->fd, p->buffer, p->bufsize); } if (cc < 0) { /* Don't choke when we get ptraced */ @@ -884,7 +1009,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * pcap_dispatch() etc. aren't * defined to retur that. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The interface went down"); return (PCAP_ERROR); @@ -903,24 +1028,28 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* fall through */ #endif } - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", pcap_strerror(errno)); return (PCAP_ERROR); } - bp = p->buffer; + bp = (u_char *)p->buffer; } else bp = p->bp; /* * Loop through each packet. */ +#ifdef BIOCSTSTAMP +#define bhp ((struct bpf_xhdr *)bp) +#else #define bhp ((struct bpf_hdr *)bp) +#endif ep = bp + cc; #ifdef PCAP_FDDIPAD pad = p->fddipad; #endif while (bp < ep) { - register int caplen, hdrlen; + register u_int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? @@ -973,10 +1102,28 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * skipping that padding. #endif */ - if (p->md.use_bpf || + if (pb->filtering_in_kernel || bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { struct pcap_pkthdr pkthdr; +#ifdef BIOCSTSTAMP + struct bintime bt; + bt.sec = bhp->bh_tstamp.bt_sec; + bt.frac = bhp->bh_tstamp.bt_frac; + if (p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { + struct timespec ts; + + bintime2timespec(&bt, &ts); + pkthdr.ts.tv_sec = ts.tv_sec; + pkthdr.ts.tv_usec = ts.tv_nsec; + } else { + struct timeval tv; + + bintime2timeval(&bt, &tv); + pkthdr.ts.tv_sec = tv.tv_sec; + pkthdr.ts.tv_usec = tv.tv_usec; + } +#else pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec; #ifdef _AIX /* @@ -987,6 +1134,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) #else pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec; #endif +#endif /* BIOCSTSTAMP */ #ifdef PCAP_FDDIPAD if (caplen > pad) pkthdr.caplen = caplen - pad; @@ -1003,7 +1151,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) #endif (*callback)(user, &pkthdr, datap); bp += BPF_WORDALIGN(caplen + hdrlen); - if (++n >= cnt && cnt > 0) { + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { p->bp = bp; p->cc = ep - bp; /* @@ -1054,7 +1202,7 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) u_int spoof_eth_src = 0; if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: can't turn off BIOCSHDRCMPLT: %s", pcap_strerror(errno)); return (PCAP_ERROR); @@ -1067,7 +1215,7 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) } #endif /* __APPLE__ */ if (ret == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (PCAP_ERROR); } @@ -1083,7 +1231,7 @@ bpf_odminit(char *errbuf) if (odm_initialize() == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_initialize failed: %s", errstr); return (PCAP_ERROR); @@ -1092,7 +1240,7 @@ bpf_odminit(char *errbuf) if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", errstr); (void)odm_terminate(); @@ -1111,7 +1259,7 @@ bpf_odmcleanup(char *errbuf) if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_unlock failed: %s", errstr); } @@ -1122,7 +1270,7 @@ bpf_odmcleanup(char *errbuf) if (errbuf != NULL) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_terminate failed: %s", errstr); } @@ -1156,7 +1304,7 @@ bpf_load(char *errbuf) major = genmajor(BPF_NAME); if (major == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genmajor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); @@ -1166,7 +1314,7 @@ bpf_load(char *errbuf) if (!minors) { minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); if (!minors) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: genminor failed: %s", pcap_strerror(errno)); (void)bpf_odmcleanup(NULL); @@ -1179,7 +1327,7 @@ bpf_load(char *errbuf) rc = stat(BPF_NODE "0", &sbuf); if (rc == -1 && errno != ENOENT) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't stat %s: %s", BPF_NODE "0", pcap_strerror(errno)); return (PCAP_ERROR); @@ -1190,7 +1338,7 @@ bpf_load(char *errbuf) sprintf(buf, "%s%d", BPF_NODE, i); unlink(buf); if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: can't mknod %s: %s", buf, pcap_strerror(errno)); return (PCAP_ERROR); @@ -1206,7 +1354,7 @@ bpf_load(char *errbuf) (cfg_ld.kmid == 0)) { /* Driver isn't loaded, load it now */ if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not load driver: %s", strerror(errno)); return (PCAP_ERROR); @@ -1221,7 +1369,7 @@ bpf_load(char *errbuf) for (i = 0; i < BPF_MINORS; i++) { cfg_bpf.devno = domakedev(major, i); if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: could not configure driver: %s", strerror(errno)); return (PCAP_ERROR); @@ -1235,24 +1383,25 @@ bpf_load(char *errbuf) #endif /* - * Turn off rfmon mode if necessary. + * Undo any operations done when opening the device when necessary. */ static void pcap_cleanup_bpf(pcap_t *p) { + struct pcap_bpf *pb = p->priv; #ifdef HAVE_BSD_IEEE80211 int sock; struct ifmediareq req; struct ifreq ifr; #endif - if (p->md.must_do_on_close != 0) { + if (pb->must_do_on_close != 0) { /* * There's something we have to do when closing this * pcap_t. */ #ifdef HAVE_BSD_IEEE80211 - if (p->md.must_do_on_close & MUST_CLEAR_RFMON) { + if (pb->must_do_on_close & MUST_CLEAR_RFMON) { /* * We put the interface into rfmon mode; * take it out of rfmon mode. @@ -1269,7 +1418,7 @@ pcap_cleanup_bpf(pcap_t *p) strerror(errno)); } else { memset(&req, 0, sizeof(req)); - strncpy(req.ifm_name, p->md.device, + strncpy(req.ifm_name, pb->device, sizeof(req.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { fprintf(stderr, @@ -1284,7 +1433,7 @@ pcap_cleanup_bpf(pcap_t *p) */ memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, - p->md.device, + pb->device, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current & ~IFM_IEEE80211_MONITOR; @@ -1302,16 +1451,34 @@ pcap_cleanup_bpf(pcap_t *p) } #endif /* HAVE_BSD_IEEE80211 */ +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + /* + * Attempt to destroy the usbusN interface that we created. + */ + if (pb->must_do_on_close & MUST_DESTROY_USBUS) { + if (if_nametoindex(pb->device) > 0) { + int s; + + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s >= 0) { + strlcpy(ifr.ifr_name, pb->device, + sizeof(ifr.ifr_name)); + ioctl(s, SIOCIFDESTROY, &ifr); + close(s); + } + } + } +#endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ /* * 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(p); - p->md.must_do_on_close = 0; + pb->must_do_on_close = 0; } #ifdef HAVE_ZEROCOPY_BPF - if (p->md.zerocopy) { + if (pb->zerocopy) { /* * Delete the mappings. Note that p->buffer gets * initialized to one of the mmapped regions in @@ -1319,16 +1486,16 @@ pcap_cleanup_bpf(pcap_t *p) * null it out so that pcap_cleanup_live_common() * doesn't try to free it. */ - if (p->md.zbuf1 != MAP_FAILED && p->md.zbuf1 != NULL) - (void) munmap(p->md.zbuf1, p->md.zbufsize); - if (p->md.zbuf2 != MAP_FAILED && p->md.zbuf2 != NULL) - (void) munmap(p->md.zbuf2, p->md.zbufsize); + if (pb->zbuf1 != MAP_FAILED && pb->zbuf1 != NULL) + (void) munmap(pb->zbuf1, pb->zbufsize); + if (pb->zbuf2 != MAP_FAILED && pb->zbuf2 != NULL) + (void) munmap(pb->zbuf2, pb->zbufsize); p->buffer = NULL; } #endif - if (p->md.device != NULL) { - free(p->md.device); - p->md.device = NULL; + if (pb->device != NULL) { + free(pb->device); + pb->device = NULL; } pcap_cleanup_live_common(p); } @@ -1347,7 +1514,7 @@ check_setif_failure(pcap_t *p, int error) * No such device exists. */ #ifdef __APPLE__ - if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) { + if (p->opt.rfmon && strncmp(p->opt.device, "wlt", 3) == 0) { /* * Monitor mode was requested, and we're trying * to open a "wltN" device. Assume that this @@ -1359,7 +1526,7 @@ check_setif_failure(pcap_t *p, int error) if (fd != -1) { strlcpy(ifr.ifr_name, "en", sizeof(ifr.ifr_name)); - strlcat(ifr.ifr_name, p->opt.source + 3, + strlcat(ifr.ifr_name, p->opt.device + 3, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* @@ -1368,7 +1535,7 @@ check_setif_failure(pcap_t *p, int error) * exist. */ err = PCAP_ERROR_NO_SUCH_DEVICE; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS on %s failed: %s", ifr.ifr_name, pcap_strerror(errno)); } else { @@ -1392,7 +1559,7 @@ check_setif_failure(pcap_t *p, int error) * just report "no such device". */ err = PCAP_ERROR_NO_SUCH_DEVICE; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } @@ -1402,7 +1569,7 @@ check_setif_failure(pcap_t *p, int error) /* * No such device. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", pcap_strerror(errno)); return (PCAP_ERROR_NO_SUCH_DEVICE); } else if (errno == ENETDOWN) { @@ -1419,8 +1586,8 @@ check_setif_failure(pcap_t *p, int error) * Some other error; fill in the error string, and * return PCAP_ERROR. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - p->opt.source, pcap_strerror(errno)); + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", + p->opt.device, pcap_strerror(errno)); return (PCAP_ERROR); } } @@ -1443,7 +1610,11 @@ check_setif_failure(pcap_t *p, int error) static int pcap_activate_bpf(pcap_t *p) { + struct pcap_bpf *pb = p->priv; int status = 0; +#ifdef HAVE_BSD_IEEE80211 + int retv; +#endif int fd; #ifdef LIFNAMSIZ char *zonesep; @@ -1479,7 +1650,7 @@ pcap_activate_bpf(pcap_t *p) u_int bufmode, zbufmax; #endif - fd = bpf_open(p); + fd = bpf_open(p->errbuf); if (fd < 0) { status = fd; goto bad; @@ -1488,14 +1659,14 @@ pcap_activate_bpf(pcap_t *p) p->fd = fd; if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "kernel bpf filter out of date"); status = PCAP_ERROR; goto bad; @@ -1503,30 +1674,57 @@ pcap_activate_bpf(pcap_t *p) #if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid) /* - * Check if the given source network device has a '/' separated - * zonename prefix string. The zonename prefixed source device - * can be used by libpcap consumers to capture network traffic - * in non-global zones from the global zone on Solaris 11 and - * above. If the zonename prefix is present then we strip the - * prefix and pass the zone ID as part of lifr_zoneid. + * Retrieve the zoneid of the zone we are currently executing in. */ - if ((zonesep = strchr(p->opt.source, '/')) != NULL) { - char zonename[ZONENAME_MAX]; + if ((ifr.lifr_zoneid = getzoneid()) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "getzoneid(): %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + /* + * Check if the given source datalink name has a '/' separated + * zonename prefix string. The zonename prefixed source datalink can + * be used by pcap consumers in the Solaris global zone to capture + * traffic on datalinks in non-global zones. Non-global zones + * do not have access to datalinks outside of their own namespace. + */ + if ((zonesep = strchr(p->opt.device, '/')) != NULL) { + char path_zname[ZONENAME_MAX]; int znamelen; char *lnamep; - znamelen = zonesep - p->opt.source; - (void) strlcpy(zonename, p->opt.source, znamelen + 1); + if (ifr.lifr_zoneid != GLOBAL_ZONEID) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "zonename/linkname only valid in global zone."); + status = PCAP_ERROR; + goto bad; + } + znamelen = zonesep - p->opt.device; + (void) strlcpy(path_zname, p->opt.device, znamelen + 1); + ifr.lifr_zoneid = getzoneidbyname(path_zname); + if (ifr.lifr_zoneid == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "getzoneidbyname(%s): %s", path_zname, + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } lnamep = strdup(zonesep + 1); - ifr.lifr_zoneid = getzoneidbyname(zonename); - free(p->opt.source); - p->opt.source = lnamep; + if (lnamep == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + free(p->opt.device); + p->opt.device = lnamep; } #endif - p->md.device = strdup(p->opt.source); - if (p->md.device == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", + pb->device = strdup(p->opt.device); + if (pb->device == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -1562,7 +1760,7 @@ pcap_activate_bpf(pcap_t *p) /* * 10.4 (Darwin 8.x). s/en/wlt/ */ - if (strncmp(p->opt.source, "en", 2) != 0) { + if (strncmp(p->opt.device, "en", 2) != 0) { /* * Not an enN device; check * whether the device even exists. @@ -1570,7 +1768,7 @@ pcap_activate_bpf(pcap_t *p) sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd != -1) { strlcpy(ifrname, - p->opt.source, ifnamsiz); + p->opt.device, ifnamsiz); if (ioctl(sockfd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* @@ -1581,7 +1779,7 @@ pcap_activate_bpf(pcap_t *p) * exist. */ status = PCAP_ERROR_NO_SUCH_DEVICE; - snprintf(p->errbuf, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFFLAGS failed: %s", pcap_strerror(errno)); @@ -1595,25 +1793,25 @@ pcap_activate_bpf(pcap_t *p) * report "no such device". */ status = PCAP_ERROR_NO_SUCH_DEVICE; - snprintf(p->errbuf, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "socket() failed: %s", pcap_strerror(errno)); } goto bad; } - wltdev = malloc(strlen(p->opt.source) + 2); + wltdev = malloc(strlen(p->opt.device) + 2); if (wltdev == NULL) { - (void)snprintf(p->errbuf, + (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } strcpy(wltdev, "wlt"); - strcat(wltdev, p->opt.source + 2); - free(p->opt.source); - p->opt.source = wltdev; + strcat(wltdev, p->opt.device + 2); + free(p->opt.device); + p->opt.device = wltdev; } /* * Everything else is 10.5 or later; for those, @@ -1622,6 +1820,85 @@ pcap_activate_bpf(pcap_t *p) } } #endif /* __APPLE__ */ + + /* + * If this is FreeBSD, and the device name begins with "usbus", + * try to create the interface if it's not available. + */ +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + if (strncmp(p->opt.device, usbus_prefix, USBUS_PREFIX_LEN) == 0) { + /* + * Do we already have an interface with that name? + */ + if (if_nametoindex(p->opt.device) == 0) { + /* + * No. We need to create it, and, if we + * succeed, remember that we should destroy + * it when the pcap_t is closed. + */ + int s; + + /* + * Open a socket to use for ioctls to + * create the interface. + */ + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s < 0) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Can't open socket: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcap_do_addexit(p)) { + /* + * "atexit()" failed; don't create the + * interface, just give up. + */ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "atexit failed"); + close(s); + status = PCAP_ERROR; + goto bad; + } + + /* + * Create the interface. + */ + strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) { + if (errno == EINVAL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Invalid USB bus interface %s", + p->opt.device); + } else { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Can't create interface for %s: %s", + p->opt.device, pcap_strerror(errno)); + } + close(s); + status = PCAP_ERROR; + goto bad; + } + + /* + * Make sure we clean this up when we close. + */ + pb->must_do_on_close |= MUST_DESTROY_USBUS; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcap_add_to_pcaps_to_close(p); + } + } +#endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ + #ifdef HAVE_ZEROCOPY_BPF /* * If the BPF extension to set buffer mode is present, try setting @@ -1633,7 +1910,7 @@ pcap_activate_bpf(pcap_t *p) /* * We have zerocopy BPF; use it. */ - p->md.zerocopy = 1; + pb->zerocopy = 1; /* * How to pick a buffer size: first, query the maximum buffer @@ -1645,8 +1922,9 @@ pcap_activate_bpf(pcap_t *p) * size. */ if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", pcap_strerror(errno)); + status = PCAP_ERROR; goto bad; } @@ -1663,34 +1941,37 @@ pcap_activate_bpf(pcap_t *p) #ifndef roundup #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ #endif - p->md.zbufsize = roundup(v, getpagesize()); - if (p->md.zbufsize > zbufmax) - p->md.zbufsize = zbufmax; - p->md.zbuf1 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE, + pb->zbufsize = roundup(v, getpagesize()); + if (pb->zbufsize > zbufmax) + pb->zbufsize = zbufmax; + pb->zbuf1 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); - p->md.zbuf2 = mmap(NULL, p->md.zbufsize, PROT_READ | PROT_WRITE, + pb->zbuf2 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); - if (p->md.zbuf1 == MAP_FAILED || p->md.zbuf2 == MAP_FAILED) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", + if (pb->zbuf1 == MAP_FAILED || pb->zbuf2 == MAP_FAILED) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", pcap_strerror(errno)); + status = PCAP_ERROR; goto bad; } memset(&bz, 0, sizeof(bz)); /* bzero() deprecated, replaced with memset() */ - bz.bz_bufa = p->md.zbuf1; - bz.bz_bufb = p->md.zbuf2; - bz.bz_buflen = p->md.zbufsize; + bz.bz_bufa = pb->zbuf1; + bz.bz_bufb = pb->zbuf2; + bz.bz_buflen = pb->zbufsize; if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", pcap_strerror(errno)); + status = PCAP_ERROR; goto bad; } - (void)strncpy(ifrname, p->opt.source, ifnamsiz); + (void)strncpy(ifrname, p->opt.device, ifnamsiz); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - p->opt.source, pcap_strerror(errno)); + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", + p->opt.device, pcap_strerror(errno)); + status = PCAP_ERROR; goto bad; } - v = p->md.zbufsize - sizeof(struct bpf_zbuf_header); + v = pb->zbufsize - sizeof(struct bpf_zbuf_header); } else #endif { @@ -1704,8 +1985,8 @@ pcap_activate_bpf(pcap_t *p) */ if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSBLEN: %s: %s", p->opt.source, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSBLEN: %s: %s", p->opt.device, pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -1714,7 +1995,7 @@ pcap_activate_bpf(pcap_t *p) /* * Now bind to the device. */ - (void)strncpy(ifrname, p->opt.source, ifnamsiz); + (void)strncpy(ifrname, p->opt.device, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0) #else @@ -1747,7 +2028,7 @@ pcap_activate_bpf(pcap_t *p) */ (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); - (void)strncpy(ifrname, p->opt.source, ifnamsiz); + (void)strncpy(ifrname, p->opt.device, ifnamsiz); #ifdef BIOCSETLIF if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0) #else @@ -1762,9 +2043,9 @@ pcap_activate_bpf(pcap_t *p) } if (v == 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: No buffer size worked", - p->opt.source); + p->opt.device); status = PCAP_ERROR; goto bad; } @@ -1773,7 +2054,7 @@ pcap_activate_bpf(pcap_t *p) /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -1806,7 +2087,7 @@ pcap_activate_bpf(pcap_t *p) /* * We don't know what to map this to yet. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", v); status = PCAP_ERROR; goto bad; @@ -1894,7 +2175,7 @@ pcap_activate_bpf(pcap_t *p) * the default mode, attempt to * select the new mode. */ - if (new_dlt != v) { + if ((u_int)new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* @@ -1941,11 +2222,12 @@ pcap_activate_bpf(pcap_t *p) /* * Try to put the interface into monitor mode. */ - status = monitor_mode(p, 1); - if (status != 0) { + retv = monitor_mode(p, 1); + if (retv != 0) { /* * We failed. */ + status = retv; goto bad; } @@ -1965,7 +2247,7 @@ pcap_activate_bpf(pcap_t *p) * If the new mode we want isn't the default mode, * attempt to select the new mode. */ - if (new_dlt != v) { + if ((u_int)new_dlt != v) { if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { /* * We succeeded; make this the @@ -2002,8 +2284,8 @@ pcap_activate_bpf(pcap_t *p) if (v == DLT_FDDI) p->fddipad = PCAP_FDDIPAD; else - p->fddipad = 0; #endif + p->fddipad = 0; p->linktype = v; #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) @@ -2017,7 +2299,7 @@ pcap_activate_bpf(pcap_t *p) * BSDs - check CVS log for "bpf.c"? */ if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSHDRCMPLT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -2025,9 +2307,14 @@ pcap_activate_bpf(pcap_t *p) #endif /* set timeout */ #ifdef HAVE_ZEROCOPY_BPF - if (p->md.timeout != 0 && !p->md.zerocopy) { + /* + * In zero-copy mode, we just use the timeout in select(). + * XXX - what if we're in non-blocking mode and the *application* + * is using select() or poll() or kqueues or....? + */ + if (p->opt.timeout && !pb->zerocopy) { #else - if (p->md.timeout) { + if (p->opt.timeout) { #endif /* * XXX - is this seconds/nanoseconds in AIX? @@ -2051,20 +2338,20 @@ pcap_activate_bpf(pcap_t *p) struct BPF_TIMEVAL bpf_to; if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) { - bpf_to.tv_sec = p->md.timeout / 1000; - bpf_to.tv_usec = (p->md.timeout * 1000) % 1000000; + bpf_to.tv_sec = p->opt.timeout / 1000; + bpf_to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } } else { #endif - to.tv_sec = p->md.timeout / 1000; - to.tv_usec = (p->md.timeout * 1000) % 1000000; + to.tv_sec = p->opt.timeout / 1000; + to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -2074,7 +2361,6 @@ pcap_activate_bpf(pcap_t *p) #endif } -#ifdef _AIX #ifdef BIOCIMMEDIATE /* * Darren Reed notes that @@ -2086,74 +2372,71 @@ pcap_activate_bpf(pcap_t *p) * is reducing things to only a few packets (i.e. one every * second or so). * - * so we turn BIOCIMMEDIATE mode on if this is AIX. + * so we always turn BIOCIMMEDIATE mode on if this is AIX. * - * We don't turn it on for other platforms, as that means we - * get woken up for every packet, which may not be what we want; - * in the Winter 1993 USENIX paper on BPF, they say: + * For other platforms, we don't turn immediate mode on by default, + * as that would mean we get woken up for every packet, which + * probably isn't what you want for a packet sniffer. * - * Since a process might want to look at every packet on a - * network and the time between packets can be only a few - * microseconds, it is not possible to do a read system call - * per packet and BPF must collect the data from several - * packets and return it as a unit when the monitoring - * application does a read. - * - * which I infer is the reason for the timeout - it means we - * wait that amount of time, in the hopes that more packets - * will arrive and we'll get them all with one read. - * - * Setting BIOCIMMEDIATE mode on FreeBSD (and probably other - * BSDs) causes the timeout to be ignored. - * - * On the other hand, some platforms (e.g., Linux) don't support - * timeouts, they just hand stuff to you as soon as it arrives; - * if that doesn't cause a problem on those platforms, it may - * be OK to have BIOCIMMEDIATE mode on BSD as well. - * - * (Note, though, that applications may depend on the read - * completing, even if no packets have arrived, when the timeout - * expires, e.g. GUI applications that have to check for input - * while waiting for packets to arrive; a non-zero timeout - * prevents "select()" from working right on FreeBSD and - * possibly other BSDs, as the timer doesn't start until a - * "read()" is done, so the timer isn't in effect if the - * application is blocked on a "select()", and the "select()" - * doesn't get woken up for a BPF device until the buffer - * fills up.) + * We set immediate mode if the caller requested it by calling + * pcap_set_immediate() before calling pcap_activate(). */ - v = 1; - if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s", - pcap_strerror(errno)); +#ifndef _AIX + if (p->opt.immediate) { +#endif /* _AIX */ + v = 1; + if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCIMMEDIATE: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#ifndef _AIX + } +#endif /* _AIX */ +#else /* BIOCIMMEDIATE */ + if (p->opt.immediate) { + /* + * We don't support immediate mode. Fail. + */ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported"); status = PCAP_ERROR; goto bad; } -#endif /* BIOCIMMEDIATE */ -#endif /* _AIX */ +#endif /* BIOCIMMEDIATE */ if (p->opt.promisc) { /* set promiscuous mode, just warn if it fails */ if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", pcap_strerror(errno)); status = PCAP_WARNING_PROMISC_NOTSUP; } } +#ifdef BIOCSTSTAMP + v = BPF_T_BINTIME; + if (ioctl(p->fd, BIOCSTSTAMP, &v) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTSTAMP: %s", + pcap_strerror(errno)); + status = PCAP_ERROR; + goto bad; + } +#endif /* BIOCSTSTAMP */ + if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; } p->bufsize = v; #ifdef HAVE_ZEROCOPY_BPF - if (!p->md.zerocopy) { + if (!pb->zerocopy) { #endif - p->buffer = (u_char *)malloc(p->bufsize); + p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -2184,7 +2467,7 @@ pcap_activate_bpf(pcap_t *p) total_prog.bf_len = 1; total_prog.bf_insns = &total_insn; if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); status = PCAP_ERROR; goto bad; @@ -2250,13 +2533,140 @@ pcap_activate_bpf(pcap_t *p) return (status); bad: - pcap_cleanup_bpf(p); + pcap_cleanup_bpf(p); return (status); } +/* + * Not all interfaces can be bound to by BPF, so try to bind to + * the specified interface; return 0 if we fail with + * PCAP_ERROR_NO_SUCH_DEVICE (which means we got an ENXIO when we tried + * to bind, which means this interface isn't in the list of interfaces + * attached to BPF) and 1 otherwise. + */ +static int +check_bpf_bindable(const char *name) +{ + int fd; + char errbuf[PCAP_ERRBUF_SIZE]; + + fd = bpf_open_and_bind(name, errbuf); + if (fd < 0) { + /* + * Error - was it PCAP_ERROR_NO_SUCH_DEVICE? + */ + if (fd == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * Yes, so we can't bind to this because it's + * not something supported by BPF. + */ + return (0); + } + /* + * No, so we don't know whether it's supported or not; + * say it is, so that the user can at least try to + * open it and report the error (which is probably + * "you don't have permission to open BPF devices"; + * reporting those interfaces means users will ask + * "why am I getting a permissions error when I try + * to capture" rather than "why am I not seeing any + * interfaces", making the underlying problem clearer). + */ + return (1); + } + + /* + * Success. + */ + close(fd); + return (1); +} + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) +static int +finddevs_usb(pcap_if_t **alldevsp, char *errbuf) +{ + DIR *usbdir; + struct dirent *usbitem; + size_t name_max; + char *name; + + /* + * We might have USB sniffing support, so try looking for USB + * interfaces. + * + * We want to report a usbusN device for each USB bus, but + * usbusN interfaces might, or might not, exist for them - + * we create one if there isn't already one. + * + * So, instead, we look in /dev/usb for all buses and create + * a "usbusN" device for each one. + */ + usbdir = opendir("/dev/usb"); + if (usbdir == NULL) { + /* + * Just punt. + */ + return (0); + } + + /* + * Leave enough room for a 32-bit (10-digit) bus number. + * Yes, that's overkill, but we won't be using + * the buffer very long. + */ + name_max = USBUS_PREFIX_LEN + 10 + 1; + name = malloc(name_max); + if (name == NULL) { + closedir(usbdir); + return (0); + } + while ((usbitem = readdir(usbdir)) != NULL) { + char *p; + size_t busnumlen; + int err; + + if (strcmp(usbitem->d_name, ".") == 0 || + strcmp(usbitem->d_name, "..") == 0) { + /* + * Ignore these. + */ + continue; + } + p = strchr(usbitem->d_name, '.'); + if (p == NULL) + continue; + busnumlen = p - usbitem->d_name; + memcpy(name, usbus_prefix, USBUS_PREFIX_LEN); + memcpy(name + USBUS_PREFIX_LEN, usbitem->d_name, busnumlen); + *(name + USBUS_PREFIX_LEN + busnumlen) = '\0'; + err = pcap_add_if(alldevsp, name, PCAP_IF_UP, NULL, errbuf); + if (err != 0) { + free(name); + closedir(usbdir); + return (err); + } + } + free(name); + closedir(usbdir); + return (0); +} +#endif + int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { + /* + * Get the list of regular interfaces first. + */ + if (pcap_findalldevs_interfaces(alldevsp, errbuf, check_bpf_bindable) == -1) + return (-1); /* failure */ + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + if (finddevs_usb(alldevsp, errbuf) == -1) + return (-1); +#endif + return (0); } @@ -2264,22 +2674,23 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) static int monitor_mode(pcap_t *p, int set) { + struct pcap_bpf *pb = p->priv; int sock; struct ifmediareq req; - int *media_list; + IFM_ULIST_TYPE *media_list; int i; int can_do; struct ifreq ifr; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", pcap_strerror(errno)); return (PCAP_ERROR); } memset(&req, 0, sizeof req); - strncpy(req.ifm_name, p->opt.source, sizeof req.ifm_name); + strncpy(req.ifm_name, p->opt.device, sizeof req.ifm_name); /* * Find out how many media types we have. @@ -2305,7 +2716,7 @@ monitor_mode(pcap_t *p, int set) return (PCAP_ERROR_RFMON_NOTSUP); default: - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA 1: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); @@ -2323,16 +2734,16 @@ monitor_mode(pcap_t *p, int set) * Allocate a buffer to hold all the media types, and * get the media types. */ - media_list = malloc(req.ifm_count * sizeof(int)); + media_list = malloc(req.ifm_count * sizeof(*media_list)); if (media_list == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } req.ifm_ulist = media_list; if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", pcap_strerror(errno)); free(media_list); close(sock); @@ -2385,23 +2796,21 @@ monitor_mode(pcap_t *p, int set) * "atexit()" failed; don't put the interface * in monitor mode, just give up. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "atexit failed"); close(sock); return (PCAP_ERROR); } memset(&ifr, 0, sizeof(ifr)); - (void)strncpy(ifr.ifr_name, p->opt.source, + (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSIFMEDIA: %s", pcap_strerror(errno)); close(sock); return (PCAP_ERROR); } - p->md.must_do_on_close |= MUST_CLEAR_RFMON; + pb->must_do_on_close |= MUST_CLEAR_RFMON; /* * Add this to the list of pcaps to close when we exit. @@ -2428,7 +2837,7 @@ static int find_802_11(struct bpf_dltlist *bdlp) { int new_dlt; - int i; + u_int i; /* * Scan the list of DLT_ values, looking for 802.11 values, @@ -2578,6 +2987,8 @@ remove_802_11(pcap_t *p) static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) { + struct pcap_bpf *pb = p->priv; + /* * Free any user-mode filter we might happen to have installed. */ @@ -2590,7 +3001,7 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) /* * It worked. */ - p->md.use_bpf = 1; /* filtering in the kernel */ + pb->filtering_in_kernel = 1; /* filtering in the kernel */ /* * Discard any previously-received packets, as they might @@ -2618,7 +3029,7 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) * some kernels. */ if (errno != EINVAL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } @@ -2630,7 +3041,7 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) */ if (install_bpf_program(p, fp) < 0) return (-1); - p->md.use_bpf = 0; /* filtering in userland */ + pb->filtering_in_kernel = 0; /* filtering in userland */ return (0); } @@ -2647,7 +3058,7 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) direction = (d == PCAP_D_IN) ? BPF_D_IN : ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT); if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_IN) ? "PCAP_D_IN" : ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"), @@ -2662,14 +3073,14 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) * We don't support PCAP_D_OUT. */ if (d == PCAP_D_OUT) { - snprintf(p->errbuf, sizeof(p->errbuf), + pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Setting direction to PCAP_D_OUT is not supported on BPF"); return -1; } seesent = (d == PCAP_D_INOUT); if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set direction to %s: %s", (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN", strerror(errno)); @@ -2677,7 +3088,7 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) } return (0); #else - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "This system doesn't support BIOCSSEESENT, so the direction can't be set"); return (-1); #endif @@ -2688,7 +3099,7 @@ pcap_set_datalink_bpf(pcap_t *p, int dlt) { #ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set DLT %d: %s", dlt, strerror(errno)); return (-1); } diff --git a/contrib/libpcap/pcap-bpf.h b/contrib/libpcap/pcap-bpf.h index 7b7e90a53a..ebb64c3f96 100644 --- a/contrib/libpcap/pcap-bpf.h +++ b/contrib/libpcap/pcap-bpf.h @@ -4,7 +4,7 @@ * * 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 + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -34,8 +34,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007-04-01 21:43:55 guy Exp $ (LBL) */ /* diff --git a/contrib/libpcap/pcap-common.c b/contrib/libpcap/pcap-common.c index bd18c64acb..84368f6cef 100644 --- a/contrib/libpcap/pcap-common.c +++ b/contrib/libpcap/pcap-common.c @@ -25,9 +25,9 @@ #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -37,10 +37,14 @@ #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include "pcap-int.h" +#include "extract.h" +#include "pcap/sll.h" #include "pcap/usb.h" +#include "pcap/nflog.h" +#include "pcap/can_socketcan.h" #include "pcap-common.h" @@ -350,7 +354,7 @@ #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-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 @@ -385,7 +389,7 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The Link Types are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames @@ -402,7 +406,7 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ @@ -425,10 +429,17 @@ #define LINKTYPE_A653_ICM 185 /* - * USB packets, beginning with a USB setup header; requested by - * Paolo Abeni . + * 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 186 +#define LINKTYPE_USB_FREEBSD 186 /* * Bluetooth HCI UART transport layer (part H:4); requested by @@ -477,7 +488,7 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ @@ -518,7 +529,7 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define LINKTYPE_JUNIPER_ST 200 @@ -610,11 +621,11 @@ */ #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. + * Linux kernel to display systems, such as Xorg. */ #define LINKTYPE_LINUX_EVDEV 216 @@ -735,8 +746,10 @@ /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied - * by Linux SocketCAN. See Documentation/networking/can.txt in the Linux - * source. + * 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 . */ @@ -776,7 +789,7 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . */ #define LINKTYPE_JUNIPER_VS 232 #define LINKTYPE_JUNIPER_SRX_E2E 233 @@ -808,12 +821,12 @@ /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . */ #define LINKTYPE_JUNIPER_ATM_CEMIC 238 /* - * NetFilter LOG messages + * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki @@ -897,7 +910,125 @@ */ #define LINKTYPE_SCTP 248 -#define LINKTYPE_MATCHING_MAX 248 /* highest value in the "matching" range */ +/* + * 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 DLT_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 stored with each + * packet: + * EXP_PDU_TAG_LINKTYPE the link type (LINKTYPE_ value) of the + * original packet. + * + * EXP_PDU_TAG_PROTO_NAME the name of the wireshark 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 OS X*; 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 + +#define LINKTYPE_MATCHING_MAX 265 /* highest value in the "matching" range */ static struct linktype_map { int dlt; @@ -970,13 +1101,20 @@ dlt_to_linktype(int dlt) int i; /* - * Map DLT_PFSYNC, whatever it might be, to LINKTYPE_PFSYNC. + * 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); /* - * Map the values in the matching range. + * 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); @@ -990,9 +1128,9 @@ dlt_to_linktype(int dlt) } /* - * If we don't have a mapping for this DLT_ code, return an + * If we don't have a mapping for this DLT, return an * error; that means that this is a value with no corresponding - * LINKTYPE_ code, and we need to assign one. + * LINKTYPE, and we need to assign one. */ return (-1); } @@ -1003,16 +1141,19 @@ linktype_to_dlt(int linktype) int i; /* - * Map LINKTYPE_PFSYNC to DLT_PFSYNC, whatever it might be. - * LINKTYPE_PFSYNC is in the matching range, to make sure - * it's as safe from reuse as we can arrange, so we do - * this test first. + * 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); /* - * Map the values in the matching range. + * For all other values in the matching range, the LINKTYPE + * value is the same as the DLT value. */ if (linktype >= LINKTYPE_MATCHING_MIN && linktype <= LINKTYPE_MATCHING_MAX) @@ -1027,30 +1168,70 @@ linktype_to_dlt(int linktype) } /* - * If we don't have an entry for this link type, return - * the link type value; it may be a DLT_ value from an - * older version of libpcap. + * If we don't have an entry for this LINKTYPE, return + * the link type value; it may be a DLT from an older + * version of libpcap. */ return linktype; } +#define EXTRACT_ + +/* + * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or + * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload, + * with the CAN ID being in host byte order. + * + * When reading a DLT_LINUX_SLL capture file, we need to check for those + * packets and convert the CAN ID from the byte order of the host that + * wrote the file to this host's byte order. + */ +static void +swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + struct sll_header *shdr = (struct sll_header *)buf; + u_int16_t protocol; + pcap_can_socketcan_hdr *chdr; + + if (caplen < (u_int) sizeof(struct sll_header) || + length < (u_int) sizeof(struct sll_header)) { + /* Not enough data to have the protocol field */ + return; + } + + protocol = EXTRACT_16BITS(&shdr->sll_protocol); + if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD) + return; + + /* + * SocketCAN packet; fix up the packet's header. + */ + chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header)); + if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) || + length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) { + /* Not enough data to have the CAN ID */ + return; + } + chdr->can_id = SWAPLONG(chdr->can_id); +} + /* * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host * byte order when capturing (it's supplied directly from a * memory-mapped buffer shared by the kernel). * * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED capture file, - * we need to convert it from the capturing host's byte order to - * the reading host's byte order. + * we need to convert it from the byte order of the host that wrote + * the file to this host's byte order. */ -void +static void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, int header_len_64_bytes) { pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; bpf_u_int32 offset = 0; - usb_isodesc *pisodesc; - int32_t numdesc, i; /* * "offset" is the offset *past* the field we're swapping; @@ -1059,7 +1240,7 @@ swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, */ /* - * The URB id is a totally opaque value; do we really need to + * The URB id is a totally opaque value; do we really need to * convert it to the reading host's byte order??? */ offset += 8; /* skip past id */ @@ -1114,6 +1295,17 @@ swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, } else offset += 8; /* skip USB setup header */ + /* + * With the old header, there are no isochronous descriptors + * after the header. + * + * With the new header, the actual number of descriptors in + * the header is not s.iso.numdesc, it's ndesc - only the + * first N descriptors, for some value of N, are put into + * the header, and ndesc is set to the actual number copied. + * In addition, if s.iso.numdesc is negative, no descriptors + * are captured, and ndesc is set to 0. + */ if (header_len_64_bytes) { /* * This is either the "version 1" header, with @@ -1142,31 +1334,128 @@ swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, if (hdr->caplen < offset) return; uhdr->ndesc = SWAPLONG(uhdr->ndesc); - } - if (uhdr->transfer_type == URB_ISOCHRONOUS) { - /* swap the values in struct linux_usb_isodesc */ - pisodesc = (usb_isodesc *)(void *)(buf+offset); - numdesc = uhdr->s.iso.numdesc; - for (i = 0; i < numdesc; i++) { - offset += 4; /* skip past status */ - if (hdr->caplen < offset) - return; - pisodesc->status = SWAPLONG(pisodesc->status); - - offset += 4; /* skip past offset */ - if (hdr->caplen < offset) - return; - pisodesc->offset = SWAPLONG(pisodesc->offset); - - offset += 4; /* skip past len */ - if (hdr->caplen < offset) - return; - pisodesc->len = SWAPLONG(pisodesc->len); - - offset += 4; /* skip past padding */ - - pisodesc++; + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + /* swap the values in struct linux_usb_isodesc */ + usb_isodesc *pisodesc; + u_int32_t i; + + pisodesc = (usb_isodesc *)(void *)(buf+offset); + for (i = 0; i < uhdr->ndesc; i++) { + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + pisodesc->status = SWAPLONG(pisodesc->status); + + offset += 4; /* skip past offset */ + if (hdr->caplen < offset) + return; + pisodesc->offset = SWAPLONG(pisodesc->offset); + + offset += 4; /* skip past len */ + if (hdr->caplen < offset) + return; + pisodesc->len = SWAPLONG(pisodesc->len); + + offset += 4; /* skip past padding */ + + pisodesc++; + } } } } + +/* + * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order + * data. They begin with a fixed-length header with big-endian fields, + * followed by a set of TLVs, where the type and length are in host + * byte order but the values are either big-endian or are a raw byte + * sequence that's the same regardless of the host's byte order. + * + * When reading a DLT_NFLOG capture file, we need to convert the type + * and length values from the byte order of the host that wrote the + * file to the byte order of this host. + */ +static void +swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_char *p = buf; + nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf; + nflog_tlv_t *tlv; + u_int caplen = hdr->caplen; + u_int length = hdr->len; + u_int16_t size; + + if (caplen < (u_int) sizeof(nflog_hdr_t) || + length < (u_int) sizeof(nflog_hdr_t)) { + /* Not enough data to have any TLVs. */ + return; + } + + if (nfhdr->nflog_version != 0) { + /* Unknown NFLOG version */ + return; + } + + length -= sizeof(nflog_hdr_t); + caplen -= sizeof(nflog_hdr_t); + p += sizeof(nflog_hdr_t); + + while (caplen >= sizeof(nflog_tlv_t)) { + tlv = (nflog_tlv_t *) p; + + /* Swap the type and length. */ + tlv->tlv_type = SWAPSHORT(tlv->tlv_type); + tlv->tlv_length = SWAPSHORT(tlv->tlv_length); + + /* Get the length of the TLV. */ + size = tlv->tlv_length; + if (size % 4 != 0) + size += 4 - size % 4; + + /* Is the TLV's length less than the minimum? */ + if (size < sizeof(nflog_tlv_t)) { + /* Yes. Give up now. */ + return; + } + + /* Do we have enough data for the full TLV? */ + if (caplen < size || length < size) { + /* No. */ + return; + } + + /* Skip over the TLV. */ + length -= size; + caplen -= size; + p += size; + } +} + +void +swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) +{ + /* + * Convert pseudo-headers from the byte order of + * the host on which the file was saved to our + * byte order, as necessary. + */ + switch (linktype) { + + case DLT_LINUX_SLL: + swap_linux_sll_header(hdr, data); + break; + + case DLT_USB_LINUX: + swap_linux_usb_header(hdr, data, 0); + break; + + case DLT_USB_LINUX_MMAPPED: + swap_linux_usb_header(hdr, data, 1); + break; + + case DLT_NFLOG: + swap_nflog_header(hdr, data); + break; + } +} diff --git a/contrib/libpcap/pcap-common.h b/contrib/libpcap/pcap-common.h index 0c80ba3267..6ac5bcd264 100644 --- a/contrib/libpcap/pcap-common.h +++ b/contrib/libpcap/pcap-common.h @@ -21,5 +21,5 @@ extern int dlt_to_linktype(int dlt); extern int linktype_to_dlt(int linktype); -extern void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, - int header_len_64_bytes); +extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, + u_char *data); diff --git a/contrib/libpcap/pcap-filter.manmisc.in b/contrib/libpcap/pcap-filter.manmisc.in index 6019a8097b..9d3f34bfee 100644 --- a/contrib/libpcap/pcap-filter.manmisc.in +++ b/contrib/libpcap/pcap-filter.manmisc.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap-filter.manmisc.in,v 1.1 2008-10-21 07:33:01 guy Exp $ (LBL) -.\" .\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" All rights reserved. @@ -20,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP-FILTER @MAN_MISC_INFO@ "6 January 2008" +.TH PCAP-FILTER @MAN_MISC_INFO@ "3 August 2015" .SH NAME pcap-filter \- packet filter syntax .br @@ -300,7 +298,7 @@ of protocol type \fIprotocol\fP. \fBicmp\fP, \fBicmp6\fP, \fBigmp\fP, \fBigrp\fP, \fBpim\fP, \fBah\fP, \fBesp\fP, \fBvrrp\fP, \fBudp\fP, or \fBtcp\fP. Note that the identifiers \fBtcp\fP, \fBudp\fP, and \fBicmp\fP are also -keywords and must be escaped via backslash (\\), which is \\\\ in the C-shell. +keywords and must be escaped via backslash (\\). Note that this primitive does not chase the protocol header chain. .IP "\fBip6 proto \fIprotocol\fR" True if the packet is an IPv6 packet of protocol type \fIprotocol\fP. @@ -332,8 +330,9 @@ The packet may contain, for example, authentication header, routing header, or hop-by-hop option header, between IPv6 header and TCP header. The BPF code emitted by this primitive is complex and -cannot be optimized by the BPF optimizer code, so this can be somewhat -slow. +cannot be optimized by the BPF optimizer code, and is not supported by +filter engines in the kernel, so this can be somewhat slow, and may +cause more packets to be dropped. .IP "\fBip protochain \fIprotocol\fR" Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4. .IP "\fBprotochain \fIprotocol\fR" @@ -373,9 +372,9 @@ True if the packet is of ether type \fIprotocol\fR. Note these identifiers are also keywords and must be escaped via backslash (\\). .IP -[In the case of FDDI (e.g., `\fBfddi protocol arp\fR'), Token Ring -(e.g., `\fBtr protocol arp\fR'), and IEEE 802.11 wireless LANS (e.g., -`\fBwlan protocol arp\fR'), for most of those protocols, the +[In the case of FDDI (e.g., `\fBfddi proto arp\fR'), Token Ring +(e.g., `\fBtr proto arp\fR'), and IEEE 802.11 wireless LANS (e.g., +`\fBwlan proto arp\fR'), for most of those protocols, the protocol identification comes from the 802.2 Logical Link Control (LLC) header, which is usually layered on top of the FDDI, Token Ring, or 802.11 header. @@ -453,6 +452,67 @@ True if the DECNET destination address is .IP "\fBdecnet host \fIhost\fR" True if either the DECNET source or destination address is .IR host . +.IP \fBllc\fP +True if the packet has an 802.2 LLC header. This includes: +.IP +Ethernet packets with a length field rather than a type field that +aren't raw NetWare-over-802.3 packets; +.IP +IEEE 802.11 data packets; +.IP +Token Ring packets (no check is done for LLC frames); +.IP +FDDI packets (no check is done for LLC frames); +.IP +LLC-encapsulated ATM packets, for SunATM on Solaris. +.IP + +.IP "\fBllc\fP \Fitype\fR" +True if the packet has an 802.2 LLC header and has the specified +.IR type . +.I type +can be one of: +.RS +.TP +\fBi\fR +Information (I) PDUs +.TP +\fBs\fR +Supervisory (S) PDUs +.TP +\fBu\fR +Unnumbered (U) PDUs +.TP +\fBrr\fR +Receiver Ready (RR) S PDUs +.TP +\fBrnr\fR +Receiver Not Ready (RNR) S PDUs +.TP +\fBrej\fR +Reject (REJ) S PDUs +.TP +\fBui\fR +Unnumbered Information (UI) U PDUs +.TP +\fBua\fR +Unnumbered Acknowledgment (UA) U PDUs +.TP +\fBdisc\fR +Disconnect (DISC) U PDUs +.TP +\fBsabme\fR +Set Asynchronous Balanced Mode Extended (SABME) U PDUs +.TP +\fBtest\fR +Test (TEST) U PDUs +.TP +\fBxid\fR +Exchange Identification (XID) U PDUs +.TP +\fBfrmr\fR +Frame Reject (FRMR) U PDUs +.RE .IP "\fBifname \fIinterface\fR" True if the packet was logged as coming from the specified interface (applies only to packets logged by OpenBSD's or FreeBSD's @@ -487,7 +547,7 @@ name of an anchored ruleset (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBruleset \fIname\fR" -Synonomous with the +Synonymous with the .B rset modifier. .IP "\fBsrnr \fInum\fR" @@ -496,7 +556,7 @@ of an anchored ruleset (applies only to packets logged by OpenBSD's or FreeBSD's .BR pf (4)). .IP "\fBsubrulenum \fInum\fR" -Synonomous with the +Synonymous with the .B srnr modifier. .IP "\fBaction \fIact\fR" @@ -637,7 +697,7 @@ changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a MPLS-encapsulated IP packet. The \fBmpls \fI[label_num]\fR expression may be used more than once, to filter on MPLS hierarchies. Each use of that expression increments the -filter offsets by 4. +filter offsets by 4. .IP For example: .in +.5i @@ -657,9 +717,11 @@ any outer label. .IP \fBpppoed\fP True if the packet is a PPP-over-Ethernet Discovery packet (Ethernet type 0x8863). -.IP \fBpppoes\fP +.IP "\fBpppoes \fI[session_id]\fR" True if the packet is a PPP-over-Ethernet Session packet (Ethernet type 0x8864). +If \fI[session_id]\fR is specified, only true if the packet has the specified +\fIsession_id\fR. Note that the first \fBpppoes\fR keyword encountered in \fIexpression\fR changes the decoding offsets for the remainder of \fIexpression\fR on the assumption that the packet is a PPPoE session packet. @@ -667,10 +729,26 @@ the assumption that the packet is a PPPoE session packet. For example: .in +.5i .nf -\fBpppoes && ip\fR +\fBpppoes 0x27 && ip\fR +.fi +.in -.5i +filters IPv4 protocols encapsulated in PPPoE session id 0x27. +.IP "\fBgeneve \fI[vni]\fR" +True if the packet is a Geneve packet (UDP port 6081). If \fI[vni]\fR +is specified, only true if the packet has the specified \fIvni\fR. +Note that when the \fBgeneve\fR keyword is encountered in +\fIexpression\fR, it changes the decoding offsets for the remainder of +\fIexpression\fR on the assumption that the packet is a Geneve packet. +.IP +For example: +.in +.5i +.nf +\fBgeneve 0xb && ip\fR .fi .in -.5i -filters IPv4 protocols encapsulated in PPPoE. +filters IPv4 protocols encapsulated in Geneve with VNI 0xb. This will +match both IP directly encapsulated in Geneve as well as IP contained +inside an Ethernet frame. .IP "\fBiso proto \fIprotocol\fR" True if the packet is an OSI packet of protocol type \fIprotocol\fP. \fIProtocol\fP can be a number or one of the names @@ -702,9 +780,6 @@ on the assumption that the packet is either a LANE emulated Ethernet packet or a LANE LE Control packet. If \fBlane\fR isn't specified, the tests are done under the assumption that the packet is an LLC-encapsulated packet. -.IP \fBllc\fP -True if the packet is an ATM packet, for SunATM on Solaris, and is -an LLC-encapsulated packet. .IP \fBoamf4s\fP True if the packet is an ATM packet, for SunATM on Solaris, and is a segment OAM F4 flow cell (VPI=0 & VCI=3). @@ -741,11 +816,17 @@ Release, or Release Done message. True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=, and \fIexpr\fR is an arithmetic expression composed of integer constants (expressed in standard C syntax), the normal binary operators -[+, -, *, /, &, |, <<, >>], a length operator, and special packet data +[+, -, *, /, %, &, |, ^, <<, >>], a length operator, and special packet data accessors. Note that all comparisons are unsigned, so that, for example, 0x80000000 and 0xffffffff are > 0. -To access -data inside the packet, use the following syntax: +.IP +The % and ^ operators are currently only supported for filtering in the +kernel on Linux with 3.7 and later kernels; on all other systems, if +those operators are used, filtering will be done in user mode, which +will increase the overhead of capturing packets and may cause more +packets to be dropped. +.IP +To access data inside the packet, use the following syntax: .in +.5i .nf \fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR @@ -798,8 +879,7 @@ The following TCP flags field values are available: \fBtcp-fin\fP, .LP Primitives may be combined using: .IP -A parenthesized group of primitives and operators -(parentheses are special to the Shell and must be escaped). +A parenthesized group of primitives and operators. .IP Negation (`\fB!\fP' or `\fBnot\fP'). .IP diff --git a/contrib/libpcap/pcap-int.h b/contrib/libpcap/pcap-int.h index b3ce82d6a6..7db7ff5e68 100644 --- a/contrib/libpcap/pcap-int.h +++ b/contrib/libpcap/pcap-int.h @@ -29,8 +29,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.94 2008-09-16 00:20:23 guy Exp $ (LBL) */ #ifndef pcap_int_h @@ -42,22 +40,16 @@ extern "C" { #endif -#ifdef HAVE_LIBDLPI -#include -#endif - -#ifdef WIN32 -#include -extern CRITICAL_SECTION g_PcapCompileCriticalSection; -#endif /* WIN32 */ - -#ifdef MSDOS -#include -#include -#endif - -#ifdef HAVE_SNF_API -#include +#if defined(_WIN32) + /* + * Make sure Packet32.h doesn't define BPF structures that we've + * probably already defined as a result of including . + */ + #define BPF_MAJOR_VERSION + #include +#elif defined(MSDOS) + #include + #include #endif #if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/ @@ -93,139 +85,39 @@ extern CRITICAL_SECTION g_PcapCompileCriticalSection; #endif /* _MSC_VER */ /* - * Savefile - */ -typedef enum { - NOT_SWAPPED, - SWAPPED, - MAYBE_SWAPPED -} swapped_type_t; - -/* - * Used when reading a savefile. - */ -struct pcap_sf { - FILE *rfile; - int (*next_packet_op)(pcap_t *, struct pcap_pkthdr *, u_char **); - int swapped; - size_t hdrsize; - swapped_type_t lengths_swapped; - int version_major; - int version_minor; - bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ - u_int tsresol; /* time stamp resolution */ - u_int tsscale; /* scaling factor for resolution -> microseconds */ - u_int64_t tsoffset; /* time stamp offset */ -}; - -/* - * Used when doing a live capture. - */ -struct pcap_md { - struct pcap_stat stat; - /*XXX*/ - int use_bpf; /* using kernel filter */ - u_long TotPkts; /* can't oflow for 79 hrs on ether */ - u_long TotAccepted; /* count accepted by filter */ - u_long TotDrops; /* count of dropped packets */ - long TotMissed; /* missed by i/f during this run */ - long OrigMissed; /* missed by i/f before this run */ - char *device; /* device name */ - int timeout; /* timeout for buffering */ - int must_do_on_close; /* stuff we must do when we close */ - struct pcap *next; /* list of open pcaps that need stuff cleared on close */ -#ifdef linux - int sock_packet; /* using Linux 2.0 compatible interface */ - 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 */ - u_int packets_read; /* count of packets read with recvfrom() */ - 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 */ - long proc_dropped; /* packets reported dropped by /proc/net/dev */ -#endif /* linux */ - -#ifdef HAVE_DAG_API -#ifdef HAVE_DAG_STREAMS_API - u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ - u_char *dag_mem_top; /* DAG card current memory top pointer */ -#else /* HAVE_DAG_STREAMS_API */ - void *dag_mem_base; /* DAG card memory base address */ - u_int dag_mem_bottom; /* DAG card current memory bottom offset */ - u_int dag_mem_top; /* DAG card current memory top offset */ -#endif /* HAVE_DAG_STREAMS_API */ - int dag_fcs_bits; /* Number of checksum bits from link layer */ - int dag_offset_flags; /* Flags to pass to dag_offset(). */ - int dag_stream; /* DAG stream number */ - int dag_timeout; /* timeout specified to pcap_open_live. - * Same as in linux above, introduce - * generally? */ -#endif /* HAVE_DAG_API */ -#ifdef HAVE_SNF_API - snf_handle_t snf_handle; /* opaque device handle */ - snf_ring_t snf_ring; /* opaque device ring handle */ - int snf_timeout; - int snf_boardnum; -#endif /*HAVE_SNF_API*/ - -#ifdef HAVE_ZEROCOPY_BPF - /* - * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will - * alternative between these two actual mmap'd buffers as required. - * As there is a header on the front size of the mmap'd buffer, only - * some of the buffer is exposed to libpcap as a whole via bufsize; - * zbufsize is the true size. zbuffer tracks the current zbuf - * assocated with buffer so that it can be used to decide which the - * next buffer to read will be. - */ - u_char *zbuf1, *zbuf2, *zbuffer; - u_int zbufsize; - u_int zerocopy; - u_int interrupted; - struct timespec firstsel; - /* - * If there's currently a buffer being actively processed, then it is - * referenced here; 'buffer' is also pointed at it, but offset by the - * size of the header. - */ - struct bpf_zbuf_header *bzh; -#endif /* HAVE_ZEROCOPY_BPF */ -}; - -/* - * Stuff to do when we close. + * Maximum snapshot length. + * + * Somewhat arbitrary, but chosen to be: + * + * 1) big enough for maximum-size Linux loopback packets (65549) + * and some USB packets captured with USBPcap: + * + * http://desowin.org/usbpcap/ + * + * (> 131072, < 262144) + * + * and + * + * 2) small enough not to cause attempts to allocate huge amounts of + * memory; some applications might use the snapshot length in a + * savefile header to control the size of the buffer they allocate, + * so a size of, say, 2^31-1 might not work well. + * + * We don't enforce this in pcap_set_snaplen(), but we use it internally. */ -#define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */ -#define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */ -#define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */ +#define MAXIMUM_SNAPLEN 262144 struct pcap_opt { - int buffer_size; - char *source; + char *device; + int timeout; /* timeout for buffering */ + u_int buffer_size; int promisc; - int rfmon; + int rfmon; /* monitor mode */ + int immediate; /* immediate mode - deliver packets as soon as they arrive */ int tstamp_type; + int tstamp_precision; }; -/* - * Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H - * Tru64 UNIX, and some versions of NetBSD pad FDDI packets to make everything - * line up on a nice boundary. - */ -#ifdef __NetBSD__ -#include /* needed to declare __NetBSD_Version__ */ -#endif - -#if defined(ultrix) || defined(__osf__) || (defined(__NetBSD__) && __NetBSD_Version__ > 106000000) -#define PCAP_FDDIPAD 3 -#endif - typedef int (*activate_op_t)(pcap_t *); typedef int (*can_set_rfmon_op_t)(pcap_t *); typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *); @@ -236,27 +128,70 @@ typedef int (*set_datalink_op_t)(pcap_t *, int); typedef int (*getnonblock_op_t)(pcap_t *, char *); typedef int (*setnonblock_op_t)(pcap_t *, int, char *); typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); -#ifdef WIN32 +#ifdef _WIN32 +typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *); typedef int (*setbuff_op_t)(pcap_t *, int); typedef int (*setmode_op_t)(pcap_t *, int); typedef int (*setmintocopy_op_t)(pcap_t *, int); +typedef HANDLE (*getevent_op_t)(pcap_t *); +typedef int (*oid_get_request_op_t)(pcap_t *, bpf_u_int32, void *, size_t *); +typedef int (*oid_set_request_op_t)(pcap_t *, bpf_u_int32, const void *, size_t *); +typedef u_int (*sendqueue_transmit_op_t)(pcap_t *, pcap_send_queue *, int); +typedef int (*setuserbuffer_op_t)(pcap_t *, int); +typedef int (*live_dump_op_t)(pcap_t *, char *, int, int); +typedef int (*live_dump_ended_op_t)(pcap_t *, int); +typedef PAirpcapHandle (*get_airpcap_handle_op_t)(pcap_t *); #endif typedef void (*cleanup_op_t)(pcap_t *); +/* + * We put all the stuff used in the read code path at the beginning, + * to try to keep it together in the same cache line or lines. + */ struct pcap { -#ifdef WIN32 + /* + * Method to call to read packets on a live capture. + */ + read_op_t read_op; + + /* + * Method to call to read packets from a savefile. + */ + int (*next_packet_op)(pcap_t *, struct pcap_pkthdr *, u_char **); + +#ifdef _WIN32 ADAPTER *adapter; - LPPACKET Packet; - int nonblock; #else int fd; int selectable_fd; - int send_fd; -#endif /* WIN32 */ +#endif /* _WIN32 */ + + /* + * Read buffer. + */ + u_int bufsize; + void *buffer; + u_char *bp; + int cc; + + int break_loop; /* flag set to force break from packet-reading loop */ + + void *priv; /* private data for methods */ + + int swapped; + FILE *rfile; /* null if live capture, non-null if savefile */ + u_int fddipad; + struct pcap *next; /* list of open pcaps that need stuff cleared on close */ + + /* + * File version number; meaningful only for a savefile, but we + * keep it here so that apps that (mistakenly) ask for the + * version numbers will get the same zero values that they + * always did. + */ + int version_major; + int version_minor; -#ifdef HAVE_LIBDLPI - dlpi_handle_t dlpi_hd; -#endif int snapshot; int linktype; /* Network linktype */ int linktype_ext; /* Extended information stored in the linktype field of a file */ @@ -265,42 +200,45 @@ struct pcap { int activated; /* true if the capture is really started */ int oldstyle; /* if we're opening with pcap_open_live() */ - int break_loop; /* flag set to force break from packet-reading loop */ + struct pcap_opt opt; -#ifdef PCAP_FDDIPAD - int fddipad; -#endif + /* + * Place holder for pcap_next(). + */ + u_char *pkt; -#ifdef MSDOS - void (*wait_proc)(void); /* call proc while waiting */ +#ifdef _WIN32 + struct pcap_stat stat; /* used for pcap_stats_ex() */ #endif - struct pcap_sf sf; - struct pcap_md md; - struct pcap_opt opt; + /* We're accepting only packets in this direction/these directions. */ + pcap_direction_t direction; /* - * Read buffer. + * Flags to affect BPF code generation. */ - int bufsize; - u_char *buffer; - u_char *bp; - int cc; + int bpf_codegen_flags; /* - * Place holder for pcap_next(). + * Placeholder for filter code if bpf not in kernel. */ - u_char *pkt; + struct bpf_program fcode; - /* We're accepting only packets in this direction/these directions. */ - pcap_direction_t direction; + char errbuf[PCAP_ERRBUF_SIZE + 1]; + int dlt_count; + u_int *dlt_list; + int tstamp_type_count; + u_int *tstamp_type_list; + int tstamp_precision_count; + u_int *tstamp_precision_list; + + struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ /* - * Methods. + * More methods. */ activate_op_t activate_op; can_set_rfmon_op_t can_set_rfmon_op; - read_op_t read_op; inject_op_t inject_op; setfilter_op_t setfilter_op; setdirection_op_t setdirection_op; @@ -314,31 +252,32 @@ struct pcap { */ pcap_handler oneshot_callback; -#ifdef WIN32 +#ifdef _WIN32 /* * These are, at least currently, specific to the Win32 NPF * driver. */ + stats_ex_op_t stats_ex_op; setbuff_op_t setbuff_op; setmode_op_t setmode_op; setmintocopy_op_t setmintocopy_op; + getevent_op_t getevent_op; + oid_get_request_op_t oid_get_request_op; + oid_set_request_op_t oid_set_request_op; + sendqueue_transmit_op_t sendqueue_transmit_op; + setuserbuffer_op_t setuserbuffer_op; + live_dump_op_t live_dump_op; + live_dump_ended_op_t live_dump_ended_op; + get_airpcap_handle_op_t get_airpcap_handle_op; #endif cleanup_op_t cleanup_op; - - /* - * Placeholder for filter code if bpf not in kernel. - */ - struct bpf_program fcode; - - char errbuf[PCAP_ERRBUF_SIZE + 1]; - int dlt_count; - u_int *dlt_list; - int tstamp_type_count; - u_int *tstamp_type_list; - - struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ }; +/* + * BPF code generation flags. + */ +#define BPF_SPECIAL_VLAN_HANDLING 0x00000001 /* special VLAN handling for Linux */ + /* * This is a timeval as stored in a savefile. * It has to use the same types everywhere, independent of the actual @@ -377,7 +316,7 @@ struct pcap_timeval { * * Then supply the changes by forking the branch at * - * https://github.com/mcr/libpcap/issues + * https://github.com/the-tcpdump-group/libpcap/issues * * 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 @@ -419,39 +358,26 @@ struct oneshot_userdata { pcap_t *pd; }; -int yylex(void); - #ifndef min #define min(a, b) ((a) > (b) ? (b) : (a)) #endif -/* XXX should these be in pcap.h? */ int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); -int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); - -#ifndef HAVE_STRLCPY -#define strlcpy(x, y, z) \ - (strncpy((x), (y), (z)), \ - ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ - strlen((y))) -#endif #include -#if !defined(HAVE_SNPRINTF) -#define snprintf pcap_snprintf -extern int snprintf (char *, size_t, const char *, ...); -#endif +#include "portability.h" -#if !defined(HAVE_VSNPRINTF) -#define vsnprintf pcap_vsnprintf -extern int vsnprintf (char *, size_t, const char *, va_list ap); -#endif +/* + * Does the packet count argument to a module's read routine say + * "supply packets until you run out of packets"? + */ +#define PACKET_COUNT_IS_UNLIMITED(count) ((count) <= 0) /* * Routines that most pcap implementations can use for non-blocking mode. */ -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *, char *); int pcap_setnonblock_fd(pcap_t *p, int, char *); #endif @@ -468,38 +394,68 @@ int pcap_setnonblock_fd(pcap_t *p, int, char *); * by pcap_create routines. */ pcap_t *pcap_create_interface(const char *, char *); -pcap_t *pcap_create_common(const char *, char *); +pcap_t *pcap_create_common(char *, size_t); int pcap_do_addexit(pcap_t *); void pcap_add_to_pcaps_to_close(pcap_t *); void pcap_remove_from_pcaps_to_close(pcap_t *); void pcap_cleanup_live_common(pcap_t *); -int pcap_not_initialized(pcap_t *); int pcap_check_activated(pcap_t *); /* * Internal interfaces for "pcap_findalldevs()". * - * "pcap_findalldevs_interfaces()" finds interfaces using the - * "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). - * * "pcap_platform_finddevs()" is a platform-dependent routine to - * add devices not found by the "standard" mechanisms. + * find local network interfaces. + * + * "pcap_findalldevs_interfaces()" is a helper to find those interfaces + * using the "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). * * "pcap_add_if()" adds an interface to the list of interfaces, for * use by various "find interfaces" routines. */ -int pcap_findalldevs_interfaces(pcap_if_t **, char *); int pcap_platform_finddevs(pcap_if_t **, char *); -int add_addr_to_iflist(pcap_if_t **, const char *, u_int, struct sockaddr *, - size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, - struct sockaddr *, size_t, char *); -int pcap_add_if(pcap_if_t **, const char *, u_int, const char *, char *); -struct sockaddr *dup_sockaddr(struct sockaddr *, size_t); -int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int, +#if !defined(_WIN32) && !defined(MSDOS) +int pcap_findalldevs_interfaces(pcap_if_t **, char *, + int (*)(const char *)); +#endif +int add_addr_to_iflist(pcap_if_t **, const char *, bpf_u_int32, + struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *, size_t, struct sockaddr *, size_t, char *); +int add_addr_to_dev(pcap_if_t *, struct sockaddr *, size_t, + struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *dstaddr, size_t, char *errbuf); +int pcap_add_if(pcap_if_t **, const char *, bpf_u_int32, const char *, + char *); +int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, bpf_u_int32, const char *, char *); +#ifndef _WIN32 +bpf_u_int32 if_flags_to_pcap_flags(const char *, u_int); +#endif + +/* + * Internal interfaces for "pcap_open_offline()". + * + * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use + * by pcap_open_offline routines. + * + * "sf_cleanup()" closes the file handle associated with a pcap_t, if + * appropriate, and frees all data common to all modules for handling + * savefile types. + */ +pcap_t *pcap_open_offline_common(char *ebuf, size_t size); +void sf_cleanup(pcap_t *p); + +/* + * Internal interfaces for both "pcap_create()" and routines that + * open savefiles. + * + * "pcap_oneshot()" is the standard one-shot callback for "pcap_next()" + * and "pcap_next_ex()". + */ +void pcap_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *); -#ifdef WIN32 -char *pcap_win32strerror(void); +#ifdef _WIN32 +void pcap_win32_err_to_str(DWORD, char *); #endif int install_bpf_program(pcap_t *, struct bpf_program *); diff --git a/contrib/libpcap/pcap-linktype.manmisc.in b/contrib/libpcap/pcap-linktype.manmisc.in index 890438728a..7634a96290 100644 --- a/contrib/libpcap/pcap-linktype.manmisc.in +++ b/contrib/libpcap/pcap-linktype.manmisc.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap-linktype.manmisc.in,v 1.3 2008-10-27 22:52:30 guy Exp $ -.\" .\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" All rights reserved. @@ -20,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "23 October 2008" +.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "7 April 2014" .SH NAME pcap-linktype \- link-layer header types supported by libpcap .SH DESCRIPTION diff --git a/contrib/libpcap/pcap-namedb.h b/contrib/libpcap/pcap-namedb.h index d0b2231082..d5908c9208 100644 --- a/contrib/libpcap/pcap-namedb.h +++ b/contrib/libpcap/pcap-namedb.h @@ -29,8 +29,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006-10-04 18:13:32 guy Exp $ (LBL) */ /* diff --git a/contrib/libpcap/pcap-savefile.manfile.in b/contrib/libpcap/pcap-savefile.manfile.in index 907559ccb5..451dd90b7e 100644 --- a/contrib/libpcap/pcap-savefile.manfile.in +++ b/contrib/libpcap/pcap-savefile.manfile.in @@ -1,6 +1,3 @@ -'\" t -.\" @(#) $Header: /tcpdump/master/libpcap/pcap-savefile.manfile.in,v 1.2 2008-10-24 07:33:50 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -20,12 +17,12 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "21 October 2008" +.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "8 March 2015" .SH NAME pcap-savefile \- libpcap savefile format .SH DESCRIPTION NOTE: applications and libraries should, if possible, use libpcap to -read savefiles, rather than having their own code to read savefiles. +read savefiles, rather than having their own code to read savefiles. If, in the future, a new file format is supported by libpcap, applications and libraries using libpcap to read savefiles will be able to read the new format of savefiles, but applications and libraries @@ -55,16 +52,24 @@ Link-layer header type .RE .PP All fields in the per-file header are in the byte order of the host -writing the file. The first field in the per-file header is a 4-byte -magic number, with the value 0xa1b2c3d4. The magic number, when read by -a host with the same byte order as the host that wrote the file, will -have the value 0xa1b2c3d4, and, when read by a host with the opposite -byte order as the host that wrote the file, will have the value +writing the file. Normally, the first field in the per-file header is a +4-byte magic number, with the value 0xa1b2c3d4. The magic number, when +read by a host with the same byte order as the host that wrote the file, +will have the value 0xa1b2c3d4, and, when read by a host with the +opposite byte order as the host that wrote the file, will have the value 0xd4c3b2a1. That allows software reading the file to determine whether the byte order of the host that wrote the file is the same as the byte order of the host on which the file is being read, and thus whether the values in the per-file and per-packet headers need to be byte-swapped. .PP +If the magic number has the value 0xa1b23c4d (with the two nibbles of +the two lower-order bytes of the magic number swapped), which would be +read as 0xa1b23c4d by a host with the same byte order as the host that +wrote the file and as 0x4d3cb2a1 by a host with the opposite byte order +as the host that wrote the file, the file format is the same as for +regular files, except that the time stamps for packets are given in +seconds and nanoseconds rather than seconds and microseconds. +.PP Following this are: .IP A 2-byte file format major version number; the current version number is @@ -104,7 +109,7 @@ box; c. Time stamp, seconds value _ -Time stamp, microseconds value +Time stamp, microseconds or nanoseconds value _ Length of captured packet data _ @@ -117,11 +122,12 @@ writing the file. The per-packet header begins with a time stamp giving the approximate time the packet was captured; the time stamp consists of a 4-byte value, giving the time in seconds since January 1, 1970, 00:00:00 UTC, followed by a 4-byte value, giving the time in -microseconds since that second. Following that are a 4-byte value -giving the number of bytes of captured data that follow the per-packet -header and a 4-byte value giving the number of bytes that would have -been present had the packet not been truncated by the snapshot length. -The two lengths will be equal if the number of bytes of packet data are -less than or equal to the snapshot length. +microseconds or nanoseconds since that second, depending on the magic +number in the file header. Following that are a 4-byte value giving the +number of bytes of captured data that follow the per-packet header and a +4-byte value giving the number of bytes that would have been present had +the packet not been truncated by the snapshot length. The two lengths +will be equal if the number of bytes of packet data are less than or +equal to the snapshot length. .SH SEE ALSO pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) diff --git a/contrib/libpcap/pcap-tstamp.manmisc.in b/contrib/libpcap/pcap-tstamp.manmisc.in index 2cd32c6213..2e1ef61d1f 100644 --- a/contrib/libpcap/pcap-tstamp.manmisc.in +++ b/contrib/libpcap/pcap-tstamp.manmisc.in @@ -19,7 +19,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP-TSTAMP @MAN_MISC_INFO@ "22 August 2010" +.TH PCAP-TSTAMP @MAN_MISC_INFO@ "8 March 2015" .SH NAME pcap-tstamp \- packet time stamps in libpcap .SH DESCRIPTION @@ -95,7 +95,7 @@ The time stamp types are listed here; the first value is the #define to use in code, the second value is the value returned by .B pcap_tstamp_type_val_to_name() and accepted by -.BR pcap_tstamp_name_to_val() . +.BR pcap_tstamp_type_name_to_val() . .RS 5 .TP 5 .BR PCAP_TSTAMP_HOST " - " host @@ -104,12 +104,12 @@ precision of this time stamp is unspecified; it might or might not be synchronized with the host operating system's clock. .TP 5 .BR PCAP_TSTAMP_HOST_LOWPREC " - " host_lowprec -Time stamp provided by the host on which the capture is being done. +Time stamp provided by the host on which the capture is being done. This is a low-precision time stamp, synchronized with the host operating system's clock. .TP 5 .BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec -Time stamp provided by the host on which the capture is being done. +Time stamp provided by the host on which the capture is being done. This is a high-precision time stamp; it might or might not be synchronized with the host operating system's clock. It might be more expensive to fetch than @@ -125,8 +125,51 @@ Time stamp provided by the network adapter on which the capture is being done. This is a high-precision time stamp; it is not synchronized with the host operating system's clock. .RE +.LP +By default, when performing a live capture or reading from a savefile, +time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC, +and microseconds since that seconds value, even if higher-resolution +time stamps are available from the capture device or in the savefile. +If, when reading a savefile, the time stamps in the file have a higher +resolution than one microsecond, the additional digits of resolution are +discarded. +.LP +The +.BR pcap_set_tstamp_precision (3PCAP) +routine can be used after a +.B pcap_create() +call and after a +.B pcap_activate() +call to specify the resolution of the time stamps to get for the device. +If the hardware or software cannot supply a higher-resolution time +stamp, the +.B pcap_set_tstamp_precision() +call will fail, and the time stamps supplied after the +.B pcap_activate() +call will have microsecond resolution. +.LP +When opening a savefile, the +.BR pcap_open_offline_with_tstamp_precision (3PCAP) +and +.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +routines can be used to specify the resolution of time stamps to be read +from the file; if the time stamps in the file have a lower resolution, +the fraction-of-a-second portion of the time stamps will be scaled to +the specified resolution. +.LP +The +.BR pcap_get_tstamp_precision (3PCAP) +routine returns the resolution of time stamps that will be supplied; +when capturing packets, this does not reflect the actual precision of +the time stamp supplied by the hardware or operating system and, when +reading a savefile, this does not indicate the actual precision of time +stamps in the file. .SH SEE ALSO pcap_set_tstamp_type(3PCAP), pcap_list_tstamp_types(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), -pcap_tstamp_name_to_val(3PCAP) +pcap_tstamp_type_name_to_val(3PCAP), +pcap_set_tstamp_precision(3PCAP), +pcap_open_offline_with_tstamp_precision(3PCAP), +pcap_fopen_offline_with_tstamp_precision(3PCAP), +pcap_get_tstamp_precision(3PCAP) diff --git a/contrib/libpcap/pcap.3pcap.in b/contrib/libpcap/pcap.3pcap.in index 6f99cc519d..93478f1cd3 100644 --- a/contrib/libpcap/pcap.3pcap.in +++ b/contrib/libpcap/pcap.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap.3pcap.in,v 1.1 2008-10-21 07:33:01 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP 3PCAP "4 April 2008" +.TH PCAP 3PCAP "8 March 2015" .SH NAME pcap \- Packet Capture library .SH SYNOPSIS @@ -309,6 +307,19 @@ handle, call lists the values it returns and describes the packet formats that correspond to those values. .PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.PP To obtain the .B "FILE\ *" corresponding to a @@ -343,12 +354,25 @@ open a .B pcap_t for a ``savefile'', given a pathname .TP +.BR pcap_open_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a pathname, and specify the precision to +provide for packet time stamps +.TP .BR pcap_fopen_offline (3PCAP) open a .B pcap_t for a ``savefile'', given a .B "FILE\ *" .TP +.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a +.BR "FILE\ *" , +and specify the precision to provide for packet time stamps +.TP .BR pcap_open_dead (3PCAP) create a ``fake'' .B pcap_t @@ -410,9 +434,19 @@ get name for a time stamp type .BR pcap_tstamp_type_val_to_description (3PCAP) get description for a time stamp type .TP -.BR pcap_tstamp_name_to_val (3PCAP) +.BR pcap_tstamp_type_name_to_val (3PCAP) get time stamp type corresponding to a name .TP +.BR pcap_set_tstamp_precision (3PCAP) +set time stamp precision for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_get_tstamp_precision (3PCAP) +get the time stamp precision of a +.B pcap_t +for live capture +.TP .BR pcap_datalink (3PCAP) get link-layer header type for a .B pcap_t @@ -510,20 +544,13 @@ number of bytes available from the capture, if the length of the packet is larger than the maximum number of bytes to capture). .RE .PP -.BR pcap_next_ex () -supplies that pointer through a pointer argument. -.BR pcap_next () -is passed an argument that points to a -.I struct pcap_pkthdr -structure, and fills it in. -.PP The callback is also supplied a .I const u_char pointer to the first .B caplen (as given in the .I struct pcap_pkthdr -a pointer to which is passed to the callback routine) +mentioned above) bytes of data from the packet. This won't necessarily be the entire packet; to capture the entire packet, you will have to provide a value for @@ -534,10 +561,28 @@ that is sufficiently large to get all of the packet's data - a value of 65535 should be sufficient on most if not all networks). When reading from a ``savefile'', the snapshot length specified when the capture was performed will limit the amount of packet data available. +.PP .BR pcap_next () -returns that pointer; +is passed an argument that points to a +.I struct pcap_pkthdr +structure, and fills it in with the time stamp and length values for the +packet. It returns a +.I const u_char +to the first +.B caplen +bytes of the packet on success, and NULL on error. +.PP .BR pcap_next_ex () -supplies that pointer through a pointer argument. +is passed two pointer arguments, one of which points to a +.IR struct pcap_pkthdr * +and one of which points to a +.IR "const u_char" *. +It sets the first pointer to point to a +.I struct pcap_pkthdr +structure with the time stamp and length values for the packet, and sets +the second pointer to point to the first +.B caplen +bytes of the packet. .PP To force the loop in .BR pcap_dispatch () @@ -558,7 +603,9 @@ for packets to become available. On some, but all, platforms, if a read timeout was specified, the wait will terminate after the read timeout expires; applications should be prepared for this, as it happens on some platforms, but should not rely on it, as it -does not happen on other platforms. +does not happen on other platforms. Note that the wait might, or might +not, terminate even if no packets are available; applications should be +prepared for this to happen, but must not rely on it happening. .PP A handle can be put into ``non-blocking mode'', so that those routines will, rather than blocking, return an indication that no packets are @@ -574,8 +621,8 @@ Non-blocking mode is often combined with routines such as .BR select (2) or .BR poll (2) -or other routines a platform offers to wait for the availability of data -on any of a set of descriptors. To obtain, for a handle, a descriptor +or other routines a platform offers to wait for any of a set of +descriptors to be ready to read. To obtain, for a handle, a descriptor that can be used in those routines, call .BR pcap_get_selectable_fd (). Not all handles have such a descriptor available; @@ -584,7 +631,14 @@ will return \-1 if no such descriptor exists. In addition, for various reasons, one or more of those routines will not work properly with the descriptor; the documentation for .BR pcap_get_selectable_fd () -gives details. +gives details. Note that, just as an attempt to read packets from a +.B pcap_t +may not return any packets if the read timeout expires, a +.BR select (), +.BR poll (), +or other such call may, if the read timeout expires, indicate that a +descriptor is ready to read even if there are no packets available to +read. .TP .B Routines .RS @@ -821,12 +875,12 @@ get a string for an error or warning status code .RE .SS Getting library version information To get a string giving version information about libpcap, call -.BR pcap_library_version (). +.BR pcap_lib_version (). .TP .B Routines .RS .TP -.BR pcap_library_version (3PCAP) +.BR pcap_lib_version (3PCAP) get library version string .RE .SH BACKWARDS COMPATIBILITY diff --git a/contrib/libpcap/pcap.c b/contrib/libpcap/pcap.c index 9ce43183c8..77a709f8f2 100644 --- a/contrib/libpcap/pcap.c +++ b/contrib/libpcap/pcap.c @@ -31,18 +31,13 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.128 2008-12-23 20:13:29 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -52,7 +47,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -85,6 +80,10 @@ static const char rcsid[] _U_ = #include "pcap-snf.h" #endif /* HAVE_SNF_API */ +#ifdef HAVE_TC_API +#include "pcap-tc.h" +#endif /* HAVE_TC_API */ + #ifdef PCAP_SUPPORT_USB #include "pcap-usb-linux.h" #endif @@ -93,25 +92,62 @@ static const char rcsid[] _U_ = #include "pcap-bt-linux.h" #endif -#ifdef PCAP_SUPPORT_CAN -#include "pcap-can-linux.h" -#endif - -#ifdef PCAP_SUPPORT_CANUSB -#include "pcap-canusb-linux.h" +#ifdef PCAP_SUPPORT_BT_MONITOR +#include "pcap-bt-monitor-linux.h" #endif #ifdef PCAP_SUPPORT_NETFILTER #include "pcap-netfilter-linux.h" #endif -int +#ifdef PCAP_SUPPORT_DBUS +#include "pcap-dbus.h" +#endif + +static int pcap_not_initialized(pcap_t *pcap) { + /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); /* this means 'not initialized' */ return (PCAP_ERROR_NOT_ACTIVATED); } +#ifdef _WIN32 +static void * +pcap_not_initialized_ptr(pcap_t *pcap) +{ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); + return (NULL); +} + +static HANDLE +pcap_getevent_not_initialized(pcap_t *pcap) +{ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); + return (INVALID_HANDLE_VALUE); +} + +static u_int +pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync) +{ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); + return (0); +} + +static PAirpcapHandle +pcap_get_airpcap_handle_not_initialized(pcap_t *pcap) +{ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); + return (NULL); +} +#endif + /* * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't, * a PCAP_ERROR value on an error. @@ -154,7 +190,7 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp), p->tstamp_type_count); if (*tstamp_typesp == NULL) { - (void)snprintf(p->errbuf, sizeof(p->errbuf), + (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (PCAP_ERROR); } @@ -186,7 +222,7 @@ pcap_free_tstamp_types(int *tstamp_type_list) * packet data cannot be guaranteed to be available after the callback * returns, so that a copy must be made. */ -static void +void pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) { struct oneshot_userdata *sp = (struct oneshot_userdata *)user; @@ -209,7 +245,7 @@ pcap_next(pcap_t *p, struct pcap_pkthdr *h) return (pkt); } -int +int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data) { @@ -222,7 +258,7 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, /* Saves a pointer to the packet headers */ *pkt_header= &p->pcap_header; - if (p->sf.rfile != NULL) { + if (p->rfile != NULL) { int status; /* We are on an offline capture */ @@ -259,44 +295,7 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); } -#if defined(DAG_ONLY) -int -pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) -{ - return (dag_findalldevs(alldevsp, errbuf)); -} - -pcap_t * -pcap_create(const char *source, char *errbuf) -{ - return (dag_create(source, errbuf)); -} -#elif defined(SEPTEL_ONLY) -int -pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) -{ - return (septel_findalldevs(alldevsp, errbuf)); -} - -pcap_t * -pcap_create(const char *source, char *errbuf) -{ - return (septel_create(source, errbuf)); -} -#elif defined(SNF_ONLY) -int -pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) -{ - return (snf_findalldevs(alldevsp, errbuf)); -} - -pcap_t * -pcap_create(const char *source, char *errbuf) -{ - return (snf_create(source, errbuf)); -} -#else /* regular pcap */ -struct capture_source_type { +static struct capture_source_type { int (*findalldevs_op)(pcap_if_t **, char *); pcap_t *(*create_op)(const char *, char *, int *); } capture_source_types[] = { @@ -309,20 +308,23 @@ struct capture_source_type { #ifdef HAVE_SNF_API { snf_findalldevs, snf_create }, #endif +#ifdef HAVE_TC_API + { TcFindAllDevs, TcCreate }, +#endif #ifdef PCAP_SUPPORT_BT { bt_findalldevs, bt_create }, #endif -#if PCAP_SUPPORT_CANUSB - { canusb_findalldevs, canusb_create }, -#endif -#ifdef PCAP_SUPPORT_CAN - { can_findalldevs, can_create }, +#ifdef PCAP_SUPPORT_BT_MONITOR + { bt_monitor_findalldevs, bt_monitor_create }, #endif #ifdef PCAP_SUPPORT_USB { usb_findalldevs, usb_create }, #endif #ifdef PCAP_SUPPORT_NETFILTER { netfilter_findalldevs, netfilter_create }, +#endif +#ifdef PCAP_SUPPORT_DBUS + { dbus_findalldevs, dbus_create }, #endif { NULL, NULL } }; @@ -339,26 +341,11 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) size_t i; /* - * Get the list of regular interfaces first. - */ - if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1) - return (-1); /* failure */ - - /* - * Add any interfaces that need a platform-specific mechanism - * to find. + * Find all the local network interfaces on which we + * can capture. */ - if (pcap_platform_finddevs(alldevsp, errbuf) == -1) { - /* - * We had an error; free the list we've been - * constructing. - */ - if (*alldevsp != NULL) { - pcap_freealldevs(*alldevsp); - *alldevsp = NULL; - } + if (pcap_platform_finddevs(alldevsp, errbuf) == -1) return (-1); - } /* * Ask each of the non-local-network-interface capture @@ -377,25 +364,58 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) return (-1); } } + return (0); } pcap_t * -pcap_create(const char *source, char *errbuf) +pcap_create(const char *device, char *errbuf) { size_t i; int is_theirs; pcap_t *p; + char *device_str; /* - * A null source name is equivalent to the "any" device - + * A null device name is equivalent to the "any" device - * which might not be supported on this platform, but * this means that you'll get a "not supported" error * rather than, say, a crash when we try to dereference * the null pointer. */ - if (source == NULL) - source = "any"; + if (device == NULL) + device_str = strdup("any"); + else { +#ifdef _WIN32 + /* + * If the string appears to be little-endian UCS-2/UTF-16, + * convert it to ASCII. + * + * XXX - to UTF-8 instead? Or report an error if any + * character isn't ASCII? + */ + if (device[0] != '\0' && device[1] == '\0') { + size_t length; + + length = wcslen((wchar_t *)device); + device_str = (char *)malloc(length + 1); + if (device_str == NULL) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (NULL); + } + + pcap_snprintf(device_str, length + 1, "%ws", + (const wchar_t *)device); + } else +#endif + device_str = strdup(device); + } + if (device_str == NULL) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (NULL); + } /* * Try each of the non-local-network-interface capture @@ -404,7 +424,8 @@ pcap_create(const char *source, char *errbuf) */ for (i = 0; capture_source_types[i].create_op != NULL; i++) { is_theirs = 0; - p = capture_source_types[i].create_op(source, errbuf, &is_theirs); + p = capture_source_types[i].create_op(device_str, errbuf, + &is_theirs); if (is_theirs) { /* * The device name refers to a device of the @@ -415,6 +436,14 @@ pcap_create(const char *source, char *errbuf) * should return that to report the failure * to create. */ + if (p == NULL) { + /* + * We assume the caller filled in errbuf. + */ + free(device_str); + return (NULL); + } + p->opt.device = device_str; return (p); } } @@ -422,9 +451,17 @@ pcap_create(const char *source, char *errbuf) /* * OK, try it as a regular network interface. */ - return (pcap_create_interface(source, errbuf)); + p = pcap_create_interface(device_str, errbuf); + if (p == NULL) { + /* + * We assume the caller filled in errbuf. + */ + free(device_str); + return (NULL); + } + p->opt.device = device_str; + return (p); } -#endif static void initialize_ops(pcap_t *p) @@ -442,10 +479,19 @@ initialize_ops(pcap_t *p) p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized; p->stats_op = (stats_op_t)pcap_not_initialized; -#ifdef WIN32 +#ifdef _WIN32 + p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr; p->setbuff_op = (setbuff_op_t)pcap_not_initialized; p->setmode_op = (setmode_op_t)pcap_not_initialized; p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; + p->getevent_op = pcap_getevent_not_initialized; + p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized; + p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized; + p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized; + p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized; + p->live_dump_op = (live_dump_op_t)pcap_not_initialized; + p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized; + p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized; #endif /* @@ -456,38 +502,65 @@ initialize_ops(pcap_t *p) p->cleanup_op = pcap_cleanup_live_common; /* - * In most cases, the standard one-short callback can + * In most cases, the standard one-shot callback can * be used for pcap_next()/pcap_next_ex(). */ p->oneshot_callback = pcap_oneshot; } -pcap_t * -pcap_create_common(const char *source, char *ebuf) +static pcap_t * +pcap_alloc_pcap_t(char *ebuf, size_t size) { + char *chunk; pcap_t *p; - p = malloc(sizeof(*p)); - if (p == NULL) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + /* + * Allocate a chunk of memory big enough for a pcap_t + * plus a structure following it of size "size". The + * structure following it is a private data structure + * for the routines that handle this pcap_t. + */ + chunk = malloc(sizeof (pcap_t) + size); + if (chunk == NULL) { + pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } - memset(p, 0, sizeof(*p)); -#ifndef WIN32 + memset(chunk, 0, sizeof (pcap_t) + size); + + /* + * Get a pointer to the pcap_t at the beginning. + */ + p = (pcap_t *)chunk; + +#ifndef _WIN32 p->fd = -1; /* not opened yet */ p->selectable_fd = -1; - p->send_fd = -1; -#endif +#endif - p->opt.source = strdup(source); - if (p->opt.source == NULL) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); - free(p); - return (NULL); + if (size == 0) { + /* No private data was requested. */ + p->priv = NULL; + } else { + /* + * Set the pointer to the private data; that's the structure + * of size "size" following the pcap_t. + */ + p->priv = (void *)(chunk + sizeof (pcap_t)); } + return (p); +} + +pcap_t * +pcap_create_common(char *ebuf, size_t size) +{ + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + /* * Default to "can't set rfmon mode"; if it's supported by * a platform, the create routine that called us can set @@ -499,11 +572,20 @@ pcap_create_common(const char *source, char *ebuf) initialize_ops(p); /* put in some defaults*/ - pcap_set_timeout(p, 0); - pcap_set_snaplen(p, 65535); /* max packet size */ + p->snapshot = MAXIMUM_SNAPLEN; /* max packet size */ + p->opt.timeout = 0; /* no timeout specified */ + p->opt.buffer_size = 0; /* use the platform's default */ p->opt.promisc = 0; - p->opt.buffer_size = 0; + p->opt.rfmon = 0; + p->opt.immediate = 0; p->opt.tstamp_type = -1; /* default to not setting time stamp type */ + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + + /* + * Start out with no BPF code generation flags set. + */ + p->bpf_codegen_flags = 0; + return (p); } @@ -511,7 +593,7 @@ int pcap_check_activated(pcap_t *p) { if (p->activated) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " " operation on activated capture"); return (-1); } @@ -523,6 +605,16 @@ pcap_set_snaplen(pcap_t *p, int snaplen) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); + + /* + * Turn invalid values, or excessively large values, into + * the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN) + snaplen = MAXIMUM_SNAPLEN; p->snapshot = snaplen; return (0); } @@ -550,7 +642,7 @@ pcap_set_timeout(pcap_t *p, int timeout_ms) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); - p->md.timeout = timeout_ms; + p->opt.timeout = timeout_ms; return (0); } @@ -563,41 +655,121 @@ pcap_set_tstamp_type(pcap_t *p, int tstamp_type) return (PCAP_ERROR_ACTIVATED); /* - * If p->tstamp_type_count is 0, we don't support setting - * the time stamp type at all. + * The argument should have been u_int, but that's too late + * to change now - it's an API. */ - if (p->tstamp_type_count == 0) - return (PCAP_ERROR_CANTSET_TSTAMP_TYPE); + if (tstamp_type < 0) + return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); /* - * Check whether we claim to support this type of time stamp. + * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST; + * the default time stamp type is PCAP_TSTAMP_HOST. */ - for (i = 0; i < p->tstamp_type_count; i++) { - if (p->tstamp_type_list[i] == tstamp_type) { - /* - * Yes. - */ + if (p->tstamp_type_count == 0) { + if (tstamp_type == PCAP_TSTAMP_HOST) { p->opt.tstamp_type = tstamp_type; return (0); } + } else { + /* + * Check whether we claim to support this type of time stamp. + */ + for (i = 0; i < p->tstamp_type_count; i++) { + if (p->tstamp_type_list[i] == (u_int)tstamp_type) { + /* + * Yes. + */ + p->opt.tstamp_type = tstamp_type; + return (0); + } + } } /* - * No. We support setting the time stamp type, but not to this - * particular value. + * We don't support this type of time stamp. */ return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); } +int +pcap_set_immediate_mode(pcap_t *p, int immediate) +{ + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.immediate = immediate; + return (0); +} + int pcap_set_buffer_size(pcap_t *p, int buffer_size) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); + if (buffer_size <= 0) { + /* + * Silently ignore invalid values. + */ + return (0); + } p->opt.buffer_size = buffer_size; return (0); } +int +pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) +{ + int i; + + if (pcap_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + + /* + * The argument should have been u_int, but that's too late + * to change now - it's an API. + */ + if (tstamp_precision < 0) + return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); + + /* + * If p->tstamp_precision_count is 0, we only support setting + * the time stamp precision to microsecond precision; every + * pcap module *MUST* support microsecond precision, even if + * it does so by converting the native precision to + * microseconds. + */ + if (p->tstamp_precision_count == 0) { + if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) { + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } else { + /* + * Check whether we claim to support this precision of + * time stamp. + */ + for (i = 0; i < p->tstamp_precision_count; i++) { + if (p->tstamp_precision_list[i] == (u_int)tstamp_precision) { + /* + * Yes. + */ + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } + } + + /* + * We don't support this time stamp precision. + */ + return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); +} + +int +pcap_get_tstamp_precision(pcap_t *p) +{ + return (p->opt.tstamp_precision); +} + int pcap_activate(pcap_t *p) { @@ -623,7 +795,7 @@ pcap_activate(pcap_t *p) * handle errors other than PCAP_ERROR, return the * error message corresponding to the status. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_statustostr(status)); } @@ -637,12 +809,12 @@ pcap_activate(pcap_t *p) } pcap_t * -pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf) +pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) { pcap_t *p; int status; - p = pcap_create(source, errbuf); + p = pcap_create(device, errbuf); if (p == NULL) return (NULL); status = pcap_set_snaplen(p, snaplen); @@ -671,33 +843,37 @@ pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *er return (p); fail: if (status == PCAP_ERROR) - snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, p->errbuf); else if (status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED || status == PCAP_ERROR_PROMISC_PERM_DENIED) - snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", source, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", device, pcap_statustostr(status), p->errbuf); else - snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, pcap_statustostr(status)); pcap_close(p); return (NULL); } -int -pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +pcap_t * +pcap_open_offline_common(char *ebuf, size_t size) { - return (p->read_op(p, cnt, callback, user)); + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + + return (p); } -/* - * XXX - is this necessary? - */ int -pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - return (p->read_op(p, cnt, callback, user)); } @@ -707,7 +883,7 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) register int n; for (;;) { - if (p->sf.rfile != NULL) { + if (p->rfile != NULL) { /* * 0 means EOF, so don't loop if we get 0. */ @@ -723,7 +899,7 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } if (n <= 0) return (n); - if (cnt > 0) { + if (!PACKET_COUNT_IS_UNLIMITED(cnt)) { cnt -= n; if (cnt <= 0) return (0); @@ -743,18 +919,24 @@ pcap_breakloop(pcap_t *p) int pcap_datalink(pcap_t *p) { + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); return (p->linktype); } int pcap_datalink_ext(pcap_t *p) { + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); return (p->linktype_ext); } int pcap_list_datalinks(pcap_t *p, int **dlt_buffer) { + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); if (p->dlt_count == 0) { /* * We couldn't fetch the list of DLTs, which means @@ -764,18 +946,18 @@ pcap_list_datalinks(pcap_t *p, int **dlt_buffer) */ *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); if (*dlt_buffer == NULL) { - (void)snprintf(p->errbuf, sizeof(p->errbuf), + (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); - return (-1); + return (PCAP_ERROR); } **dlt_buffer = p->linktype; return (1); } else { *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count); if (*dlt_buffer == NULL) { - (void)snprintf(p->errbuf, sizeof(p->errbuf), + (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); - return (-1); + return (PCAP_ERROR); } (void)memcpy(*dlt_buffer, p->dlt_list, sizeof(**dlt_buffer) * p->dlt_count); @@ -806,6 +988,9 @@ pcap_set_datalink(pcap_t *p, int dlt) int i; const char *dlt_name; + if (dlt < 0) + goto unsupported; + if (p->dlt_count == 0 || p->set_datalink_op == NULL) { /* * We couldn't fetch the list of DLTs, or we don't @@ -823,7 +1008,7 @@ pcap_set_datalink(pcap_t *p, int dlt) return (0); } for (i = 0; i < p->dlt_count; i++) - if (p->dlt_list[i] == dlt) + if (p->dlt_list[i] == (u_int)dlt) break; if (i >= p->dlt_count) goto unsupported; @@ -851,11 +1036,11 @@ pcap_set_datalink(pcap_t *p, int dlt) unsupported: dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name != NULL) { - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "%s is not one of the DLTs supported by this device", dlt_name); } else { - (void) snprintf(p->errbuf, sizeof(p->errbuf), + (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "DLT %d is not one of the DLTs supported by this device", dlt); } @@ -953,113 +1138,139 @@ struct dlt_choice { int dlt; }; -#define DLT_CHOICE(code, description) { #code, description, code } +#define DLT_CHOICE(code, description) { #code, description, DLT_ ## code } #define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } static struct dlt_choice dlt_choices[] = { - DLT_CHOICE(DLT_NULL, "BSD loopback"), - DLT_CHOICE(DLT_EN10MB, "Ethernet"), - DLT_CHOICE(DLT_IEEE802, "Token ring"), - DLT_CHOICE(DLT_ARCNET, "BSD ARCNET"), - DLT_CHOICE(DLT_SLIP, "SLIP"), - DLT_CHOICE(DLT_PPP, "PPP"), - DLT_CHOICE(DLT_FDDI, "FDDI"), - DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), - DLT_CHOICE(DLT_RAW, "Raw IP"), - DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"), - DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"), - DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"), - DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"), - DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"), - DLT_CHOICE(DLT_SYMANTEC_FIREWALL, "Symantec Firewall"), - DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"), - DLT_CHOICE(DLT_IEEE802_11, "802.11"), - DLT_CHOICE(DLT_FRELAY, "Frame Relay"), - DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"), - DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"), - DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"), - DLT_CHOICE(DLT_LTALK, "Localtalk"), - DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"), - DLT_CHOICE(DLT_PFSYNC, "Packet filter state syncing"), - DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"), - DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), - DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"), - DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus radiotap header"), - DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"), - DLT_CHOICE(DLT_JUNIPER_MLPPP, "Juniper Multi-Link PPP"), - DLT_CHOICE(DLT_JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), - DLT_CHOICE(DLT_JUNIPER_ES, "Juniper Encryption Services PIC"), - DLT_CHOICE(DLT_JUNIPER_GGSN, "Juniper GGSN PIC"), - DLT_CHOICE(DLT_JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), - DLT_CHOICE(DLT_JUNIPER_ATM2, "Juniper ATM2 PIC"), - DLT_CHOICE(DLT_JUNIPER_SERVICES, "Juniper Advanced Services PIC"), - DLT_CHOICE(DLT_JUNIPER_ATM1, "Juniper ATM1 PIC"), - DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), - DLT_CHOICE(DLT_MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), - DLT_CHOICE(DLT_MTP2, "SS7 MTP2"), - DLT_CHOICE(DLT_MTP3, "SS7 MTP3"), - DLT_CHOICE(DLT_SCCP, "SS7 SCCP"), - DLT_CHOICE(DLT_DOCSIS, "DOCSIS"), - DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"), - DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), - DLT_CHOICE(DLT_JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), - DLT_CHOICE(DLT_PPP_PPPD, "PPP for pppd, with direction flag"), - DLT_CHOICE(DLT_JUNIPER_PPPOE, "Juniper PPPoE"), - DLT_CHOICE(DLT_JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), - DLT_CHOICE(DLT_GPRS_LLC, "GPRS LLC"), - DLT_CHOICE(DLT_GPF_T, "GPF-T"), - DLT_CHOICE(DLT_GPF_F, "GPF-F"), - DLT_CHOICE(DLT_JUNIPER_PIC_PEER, "Juniper PIC Peer"), - DLT_CHOICE(DLT_ERF_ETH, "Ethernet with Endace ERF header"), - DLT_CHOICE(DLT_ERF_POS, "Packet-over-SONET with Endace ERF header"), - DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"), - DLT_CHOICE(DLT_JUNIPER_ETHER, "Juniper Ethernet"), - DLT_CHOICE(DLT_JUNIPER_PPP, "Juniper PPP"), - DLT_CHOICE(DLT_JUNIPER_FRELAY, "Juniper Frame Relay"), - DLT_CHOICE(DLT_JUNIPER_CHDLC, "Juniper C-HDLC"), - DLT_CHOICE(DLT_MFR, "FRF.16 Frame Relay"), - DLT_CHOICE(DLT_JUNIPER_VP, "Juniper Voice PIC"), - DLT_CHOICE(DLT_A429, "Arinc 429"), - DLT_CHOICE(DLT_A653_ICM, "Arinc 653 Interpartition Communication"), - DLT_CHOICE(DLT_USB, "USB"), - DLT_CHOICE(DLT_BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), - DLT_CHOICE(DLT_IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), - DLT_CHOICE(DLT_USB_LINUX, "USB with Linux header"), - DLT_CHOICE(DLT_CAN20B, "Controller Area Network (CAN) v. 2.0B"), - DLT_CHOICE(DLT_IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), - DLT_CHOICE(DLT_PPI, "Per-Packet Information"), - DLT_CHOICE(DLT_IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), - DLT_CHOICE(DLT_JUNIPER_ISM, "Juniper Integrated Service Module"), - DLT_CHOICE(DLT_IEEE802_15_4, "IEEE 802.15.4 with FCS"), - DLT_CHOICE(DLT_SITA, "SITA pseudo-header"), - DLT_CHOICE(DLT_ERF, "Endace ERF header"), - DLT_CHOICE(DLT_RAIF1, "Ethernet with u10 Networks pseudo-header"), - DLT_CHOICE(DLT_IPMB, "IPMB"), - DLT_CHOICE(DLT_JUNIPER_ST, "Juniper Secure Tunnel"), - DLT_CHOICE(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), - DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"), - DLT_CHOICE(DLT_IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), - DLT_CHOICE(DLT_MPLS, "MPLS with label as link-layer header"), - DLT_CHOICE(DLT_USB_LINUX_MMAPPED, "USB with padded Linux header"), - DLT_CHOICE(DLT_DECT, "DECT"), - DLT_CHOICE(DLT_AOS, "AOS Space Data Link protocol"), - DLT_CHOICE(DLT_WIHART, "Wireless HART"), - DLT_CHOICE(DLT_FC_2, "Fibre Channel FC-2"), - DLT_CHOICE(DLT_FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), - DLT_CHOICE(DLT_IPNET, "Solaris ipnet"), - DLT_CHOICE(DLT_CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), - DLT_CHOICE(DLT_IPV4, "Raw IPv4"), - DLT_CHOICE(DLT_IPV6, "Raw IPv6"), - DLT_CHOICE(DLT_IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), - DLT_CHOICE(DLT_JUNIPER_VS, "Juniper Virtual Server"), - DLT_CHOICE(DLT_JUNIPER_SRX_E2E, "Juniper SRX E2E"), - DLT_CHOICE(DLT_JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), - DLT_CHOICE(DLT_DVB_CI, "DVB-CI"), - DLT_CHOICE(DLT_JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), - DLT_CHOICE(DLT_NFLOG, "Linux netfilter log messages"), - DLT_CHOICE(DLT_NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), - DLT_CHOICE(DLT_NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), - DLT_CHOICE(DLT_IPOIB, "RFC 4391 IP-over-Infiniband"), + DLT_CHOICE(NULL, "BSD loopback"), + DLT_CHOICE(EN10MB, "Ethernet"), + DLT_CHOICE(IEEE802, "Token ring"), + DLT_CHOICE(ARCNET, "BSD ARCNET"), + DLT_CHOICE(SLIP, "SLIP"), + DLT_CHOICE(PPP, "PPP"), + DLT_CHOICE(FDDI, "FDDI"), + DLT_CHOICE(ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), + DLT_CHOICE(RAW, "Raw IP"), + DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"), + DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"), + DLT_CHOICE(ATM_CLIP, "Linux Classical IP-over-ATM"), + DLT_CHOICE(PPP_SERIAL, "PPP over serial"), + DLT_CHOICE(PPP_ETHER, "PPPoE"), + DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"), + DLT_CHOICE(C_HDLC, "Cisco HDLC"), + DLT_CHOICE(IEEE802_11, "802.11"), + DLT_CHOICE(FRELAY, "Frame Relay"), + DLT_CHOICE(LOOP, "OpenBSD loopback"), + DLT_CHOICE(ENC, "OpenBSD encapsulated IP"), + DLT_CHOICE(LINUX_SLL, "Linux cooked"), + DLT_CHOICE(LTALK, "Localtalk"), + DLT_CHOICE(PFLOG, "OpenBSD pflog file"), + DLT_CHOICE(PFSYNC, "Packet filter state syncing"), + DLT_CHOICE(PRISM_HEADER, "802.11 plus Prism header"), + DLT_CHOICE(IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), + DLT_CHOICE(SUNATM, "Sun raw ATM"), + DLT_CHOICE(IEEE802_11_RADIO, "802.11 plus radiotap header"), + DLT_CHOICE(ARCNET_LINUX, "Linux ARCNET"), + DLT_CHOICE(JUNIPER_MLPPP, "Juniper Multi-Link PPP"), + DLT_CHOICE(JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), + DLT_CHOICE(JUNIPER_ES, "Juniper Encryption Services PIC"), + DLT_CHOICE(JUNIPER_GGSN, "Juniper GGSN PIC"), + DLT_CHOICE(JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), + DLT_CHOICE(JUNIPER_ATM2, "Juniper ATM2 PIC"), + DLT_CHOICE(JUNIPER_SERVICES, "Juniper Advanced Services PIC"), + DLT_CHOICE(JUNIPER_ATM1, "Juniper ATM1 PIC"), + DLT_CHOICE(APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), + DLT_CHOICE(MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), + DLT_CHOICE(MTP2, "SS7 MTP2"), + DLT_CHOICE(MTP3, "SS7 MTP3"), + DLT_CHOICE(SCCP, "SS7 SCCP"), + DLT_CHOICE(DOCSIS, "DOCSIS"), + DLT_CHOICE(LINUX_IRDA, "Linux IrDA"), + DLT_CHOICE(IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), + DLT_CHOICE(JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), + DLT_CHOICE(BACNET_MS_TP, "BACnet MS/TP"), + DLT_CHOICE(PPP_PPPD, "PPP for pppd, with direction flag"), + DLT_CHOICE(JUNIPER_PPPOE, "Juniper PPPoE"), + DLT_CHOICE(JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), + DLT_CHOICE(GPRS_LLC, "GPRS LLC"), + DLT_CHOICE(GPF_T, "GPF-T"), + DLT_CHOICE(GPF_F, "GPF-F"), + DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"), + DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"), + DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"), + DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"), + DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"), + DLT_CHOICE(JUNIPER_PPP, "Juniper PPP"), + DLT_CHOICE(JUNIPER_FRELAY, "Juniper Frame Relay"), + DLT_CHOICE(JUNIPER_CHDLC, "Juniper C-HDLC"), + DLT_CHOICE(MFR, "FRF.16 Frame Relay"), + DLT_CHOICE(JUNIPER_VP, "Juniper Voice PIC"), + DLT_CHOICE(A429, "Arinc 429"), + DLT_CHOICE(A653_ICM, "Arinc 653 Interpartition Communication"), + DLT_CHOICE(USB_FREEBSD, "USB with FreeBSD header"), + DLT_CHOICE(BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), + DLT_CHOICE(IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), + DLT_CHOICE(USB_LINUX, "USB with Linux header"), + DLT_CHOICE(CAN20B, "Controller Area Network (CAN) v. 2.0B"), + DLT_CHOICE(IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), + DLT_CHOICE(PPI, "Per-Packet Information"), + DLT_CHOICE(IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), + DLT_CHOICE(JUNIPER_ISM, "Juniper Integrated Service Module"), + DLT_CHOICE(IEEE802_15_4, "IEEE 802.15.4 with FCS"), + DLT_CHOICE(SITA, "SITA pseudo-header"), + DLT_CHOICE(ERF, "Endace ERF header"), + DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"), + DLT_CHOICE(IPMB, "IPMB"), + DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"), + DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), + DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"), + DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), + DLT_CHOICE(MPLS, "MPLS with label as link-layer header"), + DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"), + DLT_CHOICE(USB_LINUX_MMAPPED, "USB with padded Linux header"), + DLT_CHOICE(DECT, "DECT"), + DLT_CHOICE(AOS, "AOS Space Data Link protocol"), + DLT_CHOICE(WIHART, "Wireless HART"), + DLT_CHOICE(FC_2, "Fibre Channel FC-2"), + DLT_CHOICE(FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), + DLT_CHOICE(IPNET, "Solaris ipnet"), + DLT_CHOICE(CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), + DLT_CHOICE(IPV4, "Raw IPv4"), + DLT_CHOICE(IPV6, "Raw IPv6"), + DLT_CHOICE(IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), + DLT_CHOICE(DBUS, "D-Bus"), + DLT_CHOICE(JUNIPER_VS, "Juniper Virtual Server"), + DLT_CHOICE(JUNIPER_SRX_E2E, "Juniper SRX E2E"), + DLT_CHOICE(JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), + DLT_CHOICE(DVB_CI, "DVB-CI"), + DLT_CHOICE(MUX27010, "MUX27010"), + DLT_CHOICE(STANAG_5066_D_PDU, "STANAG 5066 D_PDUs"), + DLT_CHOICE(JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), + DLT_CHOICE(NFLOG, "Linux netfilter log messages"), + DLT_CHOICE(NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), + DLT_CHOICE(NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), + DLT_CHOICE(IPOIB, "RFC 4391 IP-over-Infiniband"), + DLT_CHOICE(MPEG_2_TS, "MPEG-2 transport stream"), + DLT_CHOICE(NG40, "ng40 protocol tester Iub/Iur"), + DLT_CHOICE(NFC_LLCP, "NFC LLCP PDUs with pseudo-header"), + DLT_CHOICE(INFINIBAND, "InfiniBand"), + DLT_CHOICE(SCTP, "SCTP"), + DLT_CHOICE(USBPCAP, "USB with USBPcap header"), + DLT_CHOICE(RTAC_SERIAL, "Schweitzer Engineering Laboratories RTAC packets"), + DLT_CHOICE(BLUETOOTH_LE_LL, "Bluetooth Low Energy air interface"), + DLT_CHOICE(NETLINK, "Linux netlink"), + DLT_CHOICE(BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"), + DLT_CHOICE(BLUETOOTH_BREDR_BB, "Bluetooth Basic Rate/Enhanced Data Rate baseband packets"), + DLT_CHOICE(BLUETOOTH_LE_LL_WITH_PHDR, "Bluetooth Low Energy air interface with pseudo-header"), + DLT_CHOICE(PROFIBUS_DL, "PROFIBUS data link layer"), + DLT_CHOICE(PKTAP, "Apple DLT_PKTAP"), + DLT_CHOICE(EPON, "Ethernet with 802.3 Clause 65 EPON preamble"), + DLT_CHOICE(IPMI_HPM_2, "IPMI trace packets"), + DLT_CHOICE(ZWAVE_R1_R2, "Z-Wave RF profile R1 and R2 packets"), + DLT_CHOICE(ZWAVE_R3, "Z-Wave RF profile R3 packets"), + DLT_CHOICE(WATTSTOPPER_DLM, "WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol"), + DLT_CHOICE(ISO_14443, "ISO 14443 messages"), + DLT_CHOICE(RDS, "IEC 62106 Radio Data System groups"), DLT_CHOICE_SENTINEL }; @@ -1069,8 +1280,7 @@ pcap_datalink_name_to_val(const char *name) int i; for (i = 0; dlt_choices[i].name != NULL; i++) { - if (pcap_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1, - name) == 0) + if (pcap_strcasecmp(dlt_choices[i].name, name) == 0) return (dlt_choices[i].dlt); } return (-1); @@ -1083,7 +1293,7 @@ pcap_datalink_val_to_name(int dlt) for (i = 0; dlt_choices[i].name != NULL; i++) { if (dlt_choices[i].dlt == dlt) - return (dlt_choices[i].name + sizeof("DLT_") - 1); + return (dlt_choices[i].name); } return (NULL); } @@ -1154,47 +1364,55 @@ pcap_tstamp_type_val_to_description(int tstamp_type) int pcap_snapshot(pcap_t *p) { + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); return (p->snapshot); } int pcap_is_swapped(pcap_t *p) { - return (p->sf.swapped); + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->swapped); } int pcap_major_version(pcap_t *p) { - return (p->sf.version_major); + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_major); } int pcap_minor_version(pcap_t *p) { - return (p->sf.version_minor); + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_minor); } FILE * pcap_file(pcap_t *p) { - return (p->sf.rfile); + return (p->rfile); } int pcap_fileno(pcap_t *p) { -#ifndef WIN32 +#ifndef _WIN32 return (p->fd); #else if (p->adapter != NULL) return ((int)(DWORD)p->adapter->hFile); else - return (-1); + return (PCAP_ERROR); #endif } -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) int pcap_get_selectable_fd(pcap_t *p) { @@ -1203,7 +1421,7 @@ pcap_get_selectable_fd(pcap_t *p) #endif void -pcap_perror(pcap_t *p, char *prefix) +pcap_perror(pcap_t *p, const char *prefix) { fprintf(stderr, "%s: %s\n", prefix, p->errbuf); } @@ -1234,11 +1452,8 @@ pcap_getnonblock(pcap_t *p, char *errbuf) /* * Get the current non-blocking mode setting, under the assumption that * it's just the standard POSIX non-blocking flag. - * - * We don't look at "p->nonblock", in case somebody tweaked the FD - * directly. */ -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) int pcap_getnonblock_fd(pcap_t *p, char *errbuf) { @@ -1246,7 +1461,7 @@ pcap_getnonblock_fd(pcap_t *p, char *errbuf) fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } @@ -1274,7 +1489,7 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) return (ret); } -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) /* * Set non-blocking mode, under the assumption that it's just the * standard POSIX non-blocking flag. (This can be called by the @@ -1288,7 +1503,7 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) fdflags = fcntl(p->fd, F_GETFL, 0); if (fdflags == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", pcap_strerror(errno)); return (-1); } @@ -1297,7 +1512,7 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) else fdflags &= ~O_NONBLOCK; if (fcntl(p->fd, F_SETFL, fdflags) == -1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", pcap_strerror(errno)); return (-1); } @@ -1305,21 +1520,18 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) } #endif -#ifdef WIN32 +#ifdef _WIN32 /* - * Generate a string for the last Win32-specific error (i.e. an error generated when + * Generate a string for a Win32-specific error (i.e. an error generated when * calling a Win32 API). * For errors occurred during standard C calls, we still use pcap_strerror() */ -char * -pcap_win32strerror(void) +void +pcap_win32_err_to_str(DWORD error, char *errbuf) { - DWORD error; - static char errbuf[PCAP_ERRBUF_SIZE+1]; - int errlen; + size_t errlen; char *p; - error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, PCAP_ERRBUF_SIZE, NULL); @@ -1333,8 +1545,7 @@ pcap_win32strerror(void) errbuf[errlen - 2] = '\0'; } p = strchr(errbuf, '\0'); - snprintf (p, sizeof(errbuf)-(p-errbuf), " (%lu)", error); - return (errbuf); + pcap_snprintf (p, PCAP_ERRBUF_SIZE+1-(p-errbuf), " (%lu)", error); } #endif @@ -1389,8 +1600,11 @@ pcap_statustostr(int errnum) case PCAP_ERROR_PROMISC_PERM_DENIED: return ("You don't have permission to capture in promiscuous mode on that device"); + + case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP: + return ("That device doesn't support that time stamp precision"); } - (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); + (void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); return(ebuf); } @@ -1401,16 +1615,25 @@ const char * pcap_strerror(int errnum) { #ifdef HAVE_STRERROR +#ifdef _WIN32 + static char errbuf[PCAP_ERRBUF_SIZE]; + errno_t errno; + errno = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum); + if (errno != 0) /* errno = 0 if successful */ + strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE); + return (errbuf); +#else return (strerror(errnum)); +#endif /* _WIN32 */ #else extern int sys_nerr; extern const char *const sys_errlist[]; - static char ebuf[15+10+1]; + static char errbuf[PCAP_ERRBUF_SIZE]; if ((unsigned int)errnum < sys_nerr) return ((char *)sys_errlist[errnum]); - (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); - return(ebuf); + (void)pcap_snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum); + return (errbuf); #endif } @@ -1430,7 +1653,7 @@ int pcap_setdirection(pcap_t *p, pcap_direction_t d) { if (p->setdirection_op == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Setting direction is not implemented on this platform"); return (-1); } else @@ -1446,12 +1669,18 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps) static int pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from a pcap_open_dead pcap_t"); return (-1); } -#ifdef WIN32 +#ifdef _WIN32 +struct pcap_stat * +pcap_stats_ex(pcap_t *p, int *pcap_stat_size) +{ + return (p->stats_ex_op(p, pcap_stat_size)); +} + int pcap_setbuff(pcap_t *p, int dim) { @@ -1461,7 +1690,7 @@ pcap_setbuff(pcap_t *p, int dim) static int pcap_setbuff_dead(pcap_t *p, int dim) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set on a pcap_open_dead pcap_t"); return (-1); } @@ -1475,7 +1704,7 @@ pcap_setmode(pcap_t *p, int mode) static int pcap_setmode_dead(pcap_t *p, int mode) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode on a pcap_open_dead pcap_t"); return (-1); } @@ -1489,10 +1718,178 @@ pcap_setmintocopy(pcap_t *p, int size) static int pcap_setmintocopy_dead(pcap_t *p, int size) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t"); return (-1); } + +HANDLE +pcap_getevent(pcap_t *p) +{ + return (p->getevent_op(p)); +} + +static HANDLE +pcap_getevent_dead(pcap_t *p) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A pcap_open_dead pcap_t has no event handle"); + return (INVALID_HANDLE_VALUE); +} + +int +pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) +{ + return (p->oid_get_request_op(p, oid, data, lenp)); +} + +static int +pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, + size_t *lenp _U_) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID get request cannot be performed on a pcap_open_dead pcap_t"); + return (PCAP_ERROR); +} + +int +pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp) +{ + return (p->oid_set_request_op(p, oid, data, lenp)); +} + +static int +pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID set request cannot be performed on a pcap_open_dead pcap_t"); + return (PCAP_ERROR); +} + +pcap_send_queue * +pcap_sendqueue_alloc(u_int memsize) +{ + pcap_send_queue *tqueue; + + /* Allocate the queue */ + tqueue = (pcap_send_queue *)malloc(sizeof(pcap_send_queue)); + if (tqueue == NULL){ + return (NULL); + } + + /* Allocate the buffer */ + tqueue->buffer = (char *)malloc(memsize); + if (tqueue->buffer == NULL) { + free(tqueue); + return (NULL); + } + + tqueue->maxlen = memsize; + tqueue->len = 0; + + return (tqueue); +} + +void +pcap_sendqueue_destroy(pcap_send_queue *queue) +{ + free(queue->buffer); + free(queue); +} + +int +pcap_sendqueue_queue(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) +{ + if (queue->len + sizeof(struct pcap_pkthdr) + pkt_header->caplen > queue->maxlen){ + return (-1); + } + + /* Copy the pcap_pkthdr header*/ + memcpy(queue->buffer + queue->len, pkt_header, sizeof(struct pcap_pkthdr)); + queue->len += sizeof(struct pcap_pkthdr); + + /* copy the packet */ + memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen); + queue->len += pkt_header->caplen; + + return (0); +} + +u_int +pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) +{ + return (p->sendqueue_transmit_op(p, queue, sync)); +} + +static u_int +pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packets cannot be transmitted on a pcap_open_dead pcap_t"); + return (0); +} + +int +pcap_setuserbuffer(pcap_t *p, int size) +{ + return (p->setuserbuffer_op(p, size)); +} + +static int +pcap_setuserbuffer_dead(pcap_t *p, int size) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The user buffer cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +int +pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) +{ + return (p->live_dump_op(p, filename, maxsize, maxpacks)); +} + +static int +pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +int +pcap_live_dump_ended(pcap_t *p, int sync) +{ + return (p->live_dump_ended_op(p, sync)); +} + +static int +pcap_live_dump_ended_dead(pcap_t *p, int sync) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +PAirpcapHandle +pcap_get_airpcap_handle(pcap_t *p) +{ + PAirpcapHandle handle; + + handle = p->get_airpcap_handle_op(p); + if (handle == NULL) { + (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf), + "This isn't an AirPcap device"); + } + return (handle); +} + +static PAirpcapHandle +pcap_get_airpcap_handle_dead(pcap_t *p) +{ + return (NULL); +} #endif /* @@ -1537,12 +1934,11 @@ pcap_do_addexit(pcap_t *p) * "pcap_close_all()" called when we exit. */ if (!did_atexit) { - if (atexit(pcap_close_all) == -1) { + if (atexit(pcap_close_all) != 0) { /* * "atexit()" failed; let our caller know. */ - strncpy(p->errbuf, "atexit failed", - PCAP_ERRBUF_SIZE); + strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); return (0); } did_atexit = 1; @@ -1553,7 +1949,7 @@ pcap_do_addexit(pcap_t *p) void pcap_add_to_pcaps_to_close(pcap_t *p) { - p->md.next = pcaps_to_close; + p->next = pcaps_to_close; pcaps_to_close = p; } @@ -1563,7 +1959,7 @@ pcap_remove_from_pcaps_to_close(pcap_t *p) pcap_t *pc, *prevpc; for (pc = pcaps_to_close, prevpc = NULL; pc != NULL; - prevpc = pc, pc = pc->md.next) { + prevpc = pc, pc = pc->next) { if (pc == p) { /* * Found it. Remove it from the list. @@ -1572,12 +1968,12 @@ pcap_remove_from_pcaps_to_close(pcap_t *p) /* * It was at the head of the list. */ - pcaps_to_close = pc->md.next; + pcaps_to_close = pc->next; } else { /* * It was in the middle of the list. */ - prevpc->md.next = pc->md.next; + prevpc->next = pc->next; } break; } @@ -1601,14 +1997,18 @@ pcap_cleanup_live_common(pcap_t *p) p->tstamp_type_list = NULL; p->tstamp_type_count = 0; } + if (p->tstamp_precision_list != NULL) { + free(p->tstamp_precision_list); + p->tstamp_precision_list = NULL; + p->tstamp_precision_count = 0; + } pcap_freecode(&p->fcode); -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) if (p->fd >= 0) { close(p->fd); p->fd = -1; } p->selectable_fd = -1; - p->send_fd = -1; #endif } @@ -1619,27 +2019,59 @@ pcap_cleanup_dead(pcap_t *p _U_) } pcap_t * -pcap_open_dead(int linktype, int snaplen) +pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision) { pcap_t *p; + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + case PCAP_TSTAMP_PRECISION_NANO: + break; + + default: + return NULL; + } p = malloc(sizeof(*p)); if (p == NULL) return NULL; memset (p, 0, sizeof(*p)); p->snapshot = snaplen; p->linktype = linktype; + p->opt.tstamp_precision = precision; p->stats_op = pcap_stats_dead; -#ifdef WIN32 +#ifdef _WIN32 + p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr; p->setbuff_op = pcap_setbuff_dead; p->setmode_op = pcap_setmode_dead; p->setmintocopy_op = pcap_setmintocopy_dead; + p->getevent_op = pcap_getevent_dead; + p->oid_get_request_op = pcap_oid_get_request_dead; + p->oid_set_request_op = pcap_oid_set_request_dead; + p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead; + p->setuserbuffer_op = pcap_setuserbuffer_dead; + p->live_dump_op = pcap_live_dump_dead; + p->live_dump_ended_op = pcap_live_dump_ended_dead; + p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead; #endif p->cleanup_op = pcap_cleanup_dead; + + /* + * A "dead" pcap_t never requires special BPF code generation. + */ + p->bpf_codegen_flags = 0; + p->activated = 1; return (p); } +pcap_t * +pcap_open_dead(int linktype, int snaplen) +{ + return (pcap_open_dead_with_tstamp_precision(linktype, snaplen, + PCAP_TSTAMP_PRECISION_MICRO)); +} + /* * API compatible with WinPcap's "send a packet" routine - returns -1 * on error, 0 otherwise. @@ -1667,8 +2099,8 @@ pcap_inject(pcap_t *p, const void *buf, size_t size) void pcap_close(pcap_t *p) { - if (p->opt.source != NULL) - free(p->opt.source); + if (p->opt.device != NULL) + free(p->opt.device); p->cleanup_op(p); free(p); } @@ -1685,42 +2117,35 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, { const struct bpf_insn *fcode = fp->bf_insns; - if (fcode != NULL) + if (fcode != NULL) return (bpf_filter(fcode, pkt, h->len, h->caplen)); else return (0); } -/* - * We make the version string static, and return a pointer to it, rather - * than exporting the version string directly. On at least some UNIXes, - * if you import data from a shared library into an 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). - */ -#ifdef HAVE_VERSION_H -#include "version.h" -#else -static const char pcap_version_string[] = "libpcap version 1.x.y"; -#endif +#include "pcap_version.h" -#ifdef WIN32 +#ifdef _WIN32 + +static char *full_pcap_version_string; + +#ifdef HAVE_VERSION_H /* - * XXX - it'd be nice if we could somehow generate the WinPcap and libpcap - * version numbers when building WinPcap. (It'd be nice to do so for - * the packet.dll version number as well.) + * 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 version number + * when building WinPcap. (It'd be nice to do so for the packet.dll version + * number as well.) */ -static const char wpcap_version_string[] = "4.0"; +#include "../../version.h" + +static const char wpcap_version_string[] = WINPCAP_VER_STRING; static const char pcap_version_string_fmt[] = - "WinPcap version %s, based on %s"; + WINPCAP_PRODUCT_NAME " version %s, based on %s"; static const char pcap_version_string_packet_dll_fmt[] = - "WinPcap version %s (packet.dll version %s), based on %s"; -static char *full_pcap_version_string; + WINPCAP_PRODUCT_NAME " version %s (packet.dll version %s), based on %s"; const char * pcap_lib_version(void) @@ -1745,8 +2170,12 @@ pcap_lib_version(void) strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); - sprintf(full_pcap_version_string, - pcap_version_string_fmt, wpcap_version_string, + if (full_pcap_version_string == NULL) + return (NULL); + pcap_snprintf(full_pcap_version_string, + full_pcap_version_string_len, + pcap_version_string_fmt, + wpcap_version_string, pcap_version_string); } else { /* @@ -1762,16 +2191,57 @@ pcap_lib_version(void) strlen(packet_version_string) + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); - - sprintf(full_pcap_version_string, + if (full_pcap_version_string == NULL) + return (NULL); + pcap_snprintf(full_pcap_version_string, + full_pcap_version_string_len, pcap_version_string_packet_dll_fmt, - wpcap_version_string, packet_version_string, + wpcap_version_string, + packet_version_string, pcap_version_string); } } return (full_pcap_version_string); } +#else /* HAVE_VERSION_H */ + +/* + * libpcap being built for Windows, not as part of a WinPcap/Npcap source + * tree. + */ +static const char pcap_version_string_packet_dll_fmt[] = + "%s (packet.dll version %s)"; +const char * +pcap_lib_version(void) +{ + char *packet_version_string; + size_t full_pcap_version_string_len; + + if (full_pcap_version_string == NULL) { + /* + * Generate the version string. Report the packet.dll + * version. + */ + packet_version_string = PacketGetVersion(); + full_pcap_version_string_len = + (sizeof pcap_version_string_packet_dll_fmt - 4) + + strlen(pcap_version_string) + + strlen(packet_version_string); + full_pcap_version_string = malloc(full_pcap_version_string_len); + if (full_pcap_version_string == NULL) + return (NULL); + pcap_snprintf(full_pcap_version_string, + full_pcap_version_string_len, + pcap_version_string_packet_dll_fmt, + pcap_version_string, + packet_version_string); + } + return (full_pcap_version_string); +} + +#endif /* HAVE_VERSION_H */ + #elif defined(MSDOS) static char *full_pcap_version_string; @@ -1791,6 +2261,8 @@ pcap_lib_version (void) sizeof dospfx + strlen(pcap_version_string); full_pcap_version_string = malloc(full_pcap_version_string_len); + if (full_pcap_version_string == NULL) + return (NULL); strcpy(full_pcap_version_string, dospfx); strcat(full_pcap_version_string, pcap_version_string); } @@ -1805,3 +2277,51 @@ pcap_lib_version(void) return (pcap_version_string); } #endif + +#ifdef YYDEBUG +/* + * Set the internal "debug printout" flag for the filter expression parser. + * The code to print that stuff is present only if YYDEBUG is defined, so + * the flag, and the routine to set it, are defined only if YYDEBUG is + * defined. + * + * 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_parser_debug(int value); + +PCAP_API_DEF void +pcap_set_parser_debug(int value) +{ + extern int pcap_debug; + + pcap_debug = value; +} +#endif + +#ifdef BDEBUG +/* + * Set 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. + * + * 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) +{ + extern int pcap_optimizer_debug; + + pcap_optimizer_debug = value; +} +#endif diff --git a/contrib/libpcap/pcap.h b/contrib/libpcap/pcap.h index 490a4bfb43..174e32d25f 100644 --- a/contrib/libpcap/pcap.h +++ b/contrib/libpcap/pcap.h @@ -29,8 +29,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006-10-04 18:09:22 guy Exp $ (LBL) */ /* diff --git a/contrib/libpcap/pcap/bluetooth.h b/contrib/libpcap/pcap/bluetooth.h index 813bea347d..c5f378abbe 100644 --- a/contrib/libpcap/pcap/bluetooth.h +++ b/contrib/libpcap/pcap/bluetooth.h @@ -11,8 +11,8 @@ * 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 + * 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 @@ -29,20 +29,27 @@ * * bluetooth data struct * By Paolo Abeni - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007-09-22 02:10:17 guy Exp $ */ - -#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ -#define _PCAP_BLUETOOTH_STRUCTS_H__ + +#ifndef lib_pcap_bluetooth_h +#define lib_pcap_bluetooth_h /* - * Header prepended libpcap to each bluetooth h:4 frame. + * Header prepended libpcap to each bluetooth h4 frame, * fields are in network byte order */ typedef struct _pcap_bluetooth_h4_header { u_int32_t direction; /* if first bit is set direction is incoming */ } pcap_bluetooth_h4_header; +/* + * Header prepended libpcap to each bluetooth linux monitor frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_linux_monitor_header { + u_int16_t adapter_id; + u_int16_t opcode; +} pcap_bluetooth_linux_monitor_header; + #endif diff --git a/contrib/libpcap/pcap/bpf.h b/contrib/libpcap/pcap/bpf.h index 8576bbdbd0..78ad8905d0 100644 --- a/contrib/libpcap/pcap/bpf.h +++ b/contrib/libpcap/pcap/bpf.h @@ -4,7 +4,7 @@ * * 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 + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -36,8 +36,6 @@ * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.32 2008-12-23 20:13:29 guy Exp $ (LBL) */ /* @@ -61,7 +59,8 @@ * 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). + * I don't have earlier versions available to check), or QNX-style + * multiple-include protection (as per GitHub pull request #394). * * We do not check for BPF_MAJOR_VERSION, as that's defined by * , which is directly or indirectly included in some @@ -70,9 +69,11 @@ * * This also provides our own multiple-include protection. */ -#if !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) +#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 + #ifdef __cplusplus extern "C" { #endif @@ -89,7 +90,7 @@ typedef u_int bpf_u_int32; #endif /* - * Alignment macros. BPF_WORDALIGN rounds up to the next + * 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. @@ -108,1112 +109,22 @@ struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; - -/* - * 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 - * - * http://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 - -/* - * 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 - * Mac OS X; 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. - */ -#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. - */ -#ifdef __OpenBSD__ -#define DLT_ENC 13 -#else -#define DLT_ENC 109 -#endif - -/* - * Values between 110 and 112 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. - */ - -/* - * This is for 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. - * - * This 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. Its libpcap does DLT_ <-> LINKTYPE_ - * mapping, so it probably supports capturing on the pfsync device - * but not saving the captured data to a pcap file. - * - * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC; - * their libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would - * use 18 in pcap files as well. - * - * NetBSD and DragonFly BSD also use 18 for DLT_PFSYNC; their - * libpcaps do DLT_ <-> LINKTYPE_ mapping, and neither has an entry - * for DLT_PFSYNC, so it might not be able to write out dump files - * with 18 as the link-layer header type. (Earlier versions might - * not have done mapping, in which case they'd work the same way - * OpenBSD does.) - * - * Mac OS X defines it as 18, but doesn't appear to use it as of - * Mac OS X 10.7.3. Its libpcap does DLT_ <-> LINKTYPE_ mapping. - * - * We'll define DLT_PFSYNC as 121 on FreeBSD and define it as 18 on - * all other platforms. 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 18, *even on FreeBSD*, and map - * it, so that savefiles won't use 121 for PFSYNC - they'll all - * use 18. 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; code that doesn't, such as the code in Wireshark, - * will be able to distinguish between them. - */ -#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 http://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 dependant on the direction of the packet (incomming 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 accomodate - * 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 - * http://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 +#include /* - * 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 - * http://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 - -/* - * USB packets, beginning with a USB setup header; requested by - * Paolo Abeni . - */ -#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. - */ -#define DLT_IEEE802_15_4 195 - -/* - * Various link-layer types, with a pseudo-header, for SITA - * (http://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 the I2C slave address, followed - * by the netFn and LUN, etc.. Requested by Chanthy Toeung - * . - */ -#define DLT_IPMB 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 - -/* - * Variants of various link-layer headers, 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_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ -#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ -#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ -#define DLT_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 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 - http://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 { - * u_int8_t dli_version; - * u_int8_t dli_family; - * u_int16_t dli_htype; - * u_int32_t dli_pktlen; - * u_int32_t dli_ifindex; - * u_int32_t dli_grifindex; - * u_int32_t dli_zsrc; - * u_int32_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. 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: - * - * http://www.freedesktop.org/wiki/Software/dbus - * - * messages: - * - * http://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: - * - * http://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 - * - * http://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 - -/* - * 245 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 245. - */ -#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). + * The instruction encodings. * - * Requested by Michael Tuexen . + * 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). */ -#define DLT_SCTP 248 - -#define DLT_MATCHING_MAX 248 /* 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. + * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000. */ -#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) - -/* - * The instruction encodings. - */ /* instruction classes */ #define BPF_CLASS(code) ((code) & 0x07) #define BPF_LD 0x00 @@ -1230,6 +141,7 @@ struct bpf_program { #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_ABS 0x20 @@ -1237,6 +149,8 @@ struct bpf_program { #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) @@ -1249,11 +163,30 @@ struct bpf_program { #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 @@ -1261,11 +194,43 @@ struct bpf_program { /* 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. @@ -1277,6 +242,16 @@ struct bpf_insn { bpf_u_int32 k; }; +/* + * Auxiliary data, for use when interpreting a filter intended for the + * Linux kernel when the kernel rejects the filter (requiring us to + * run it in userland). It contains VLAN tag information. + */ +struct bpf_aux_data { + u_short vlan_tag_present; + u_short vlan_tag; +}; + /* * Macros for insn array initializers. */ @@ -1284,11 +259,13 @@ struct bpf_insn { #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } #if __STDC__ || defined(__cplusplus) -extern int bpf_validate(const struct bpf_insn *, int); -extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +PCAP_API int bpf_validate(const struct bpf_insn *, int); +PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +extern u_int bpf_filter_with_aux_data(const struct bpf_insn *, const u_char *, u_int, u_int, const struct bpf_aux_data *); #else -extern int bpf_validate(); -extern u_int bpf_filter(); +PCAP_API int bpf_validate(); +PCAP_API u_int bpf_filter(); +extern u_int bpf_filter_with_aux_data(); #endif /* diff --git a/contrib/libpcap/pcap-bpf.h b/contrib/libpcap/pcap/can_socketcan.h similarity index 87% copy from contrib/libpcap/pcap-bpf.h copy to contrib/libpcap/pcap/can_socketcan.h index 7b7e90a53a..68d2a131c8 100644 --- a/contrib/libpcap/pcap-bpf.h +++ b/contrib/libpcap/pcap/can_socketcan.h @@ -4,7 +4,7 @@ * * 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 + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -34,14 +34,21 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007-04-01 21:43:55 guy Exp $ (LBL) */ +#ifndef lib_pcap_can_socketcan_h +#define lib_pcap_can_socketcan_h + /* - * For backwards compatibility. - * - * Note to OS vendors: do NOT get rid of this file! Some applications - * might expect to be able to include . + * SocketCAN header, as per Documentation/networking/can.txt in the + * Linux source. */ -#include +typedef struct { + u_int32_t can_id; + u_int8_t payload_length; + u_int8_t pad; + u_int8_t reserved1; + u_int8_t reserved2; +} pcap_can_socketcan_hdr; + +#endif diff --git a/contrib/libpcap/pcap/bpf.h b/contrib/libpcap/pcap/dlt.h similarity index 79% copy from contrib/libpcap/pcap/bpf.h copy to contrib/libpcap/pcap/dlt.h index 8576bbdbd0..2d74713e8a 100644 --- a/contrib/libpcap/pcap/bpf.h +++ b/contrib/libpcap/pcap/dlt.h @@ -4,7 +4,7 @@ * * 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 + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without @@ -36,79 +36,11 @@ * SUCH DAMAGE. * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.32 2008-12-23 20:13:29 guy Exp $ (LBL) - */ - -/* - * 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). - * - * 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. - * - * This also provides our own multiple-include protection. - */ -#if !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) -#define lib_pcap_bpf_h - -#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)) +#ifndef lib_pcap_dlt_h +#define lib_pcap_dlt_h -/* - * Structure for "pcap_compile()", "pcap_setfilter()", etc.. - */ -struct bpf_program { - u_int bf_len; - struct bpf_insn *bf_insns; -}; - /* * Link-layer header type codes. * @@ -363,40 +295,62 @@ struct bpf_program { /* * Sigh. * - * This was reserved for Siemens HiPath HDLC on 2002-01-25, as + * 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. Its libpcap does DLT_ <-> LINKTYPE_ - * mapping, so it probably supports capturing on the pfsync device - * but not saving the captured data to a pcap file. + * 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; - * their libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would - * use 18 in pcap files as well. - * - * NetBSD and DragonFly BSD also use 18 for DLT_PFSYNC; their - * libpcaps do DLT_ <-> LINKTYPE_ mapping, and neither has an entry - * for DLT_PFSYNC, so it might not be able to write out dump files - * with 18 as the link-layer header type. (Earlier versions might - * not have done mapping, in which case they'd work the same way - * OpenBSD does.) - * - * Mac OS X defines it as 18, but doesn't appear to use it as of - * Mac OS X 10.7.3. Its libpcap does DLT_ <-> LINKTYPE_ mapping. - * - * We'll define DLT_PFSYNC as 121 on FreeBSD and define it as 18 on - * all other platforms. 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 18, *even on FreeBSD*, and map - * it, so that savefiles won't use 121 for PFSYNC - they'll all - * use 18. 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; code that doesn't, such as the code in Wireshark, - * will be able to distinguish between them. + * 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 OS X - 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 @@ -430,7 +384,7 @@ struct bpf_program { */ #define DLT_SUNATM 123 /* Solaris+SunATM */ -/* +/* * Reserved as per request from Kent Dahlgren * for private use. */ @@ -673,7 +627,7 @@ struct bpf_program { /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ are used for prepending meta-information * like interface index, interface name * before standard Ethernet, PPP, Frelay & C-HDLC Frames @@ -690,7 +644,7 @@ struct bpf_program { /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for internal communication with a * voice Adapter Card (PIC) */ @@ -713,9 +667,23 @@ struct bpf_program { #define DLT_A653_ICM 185 /* - * USB packets, beginning with a USB setup header; requested by - * Paolo Abeni . + * 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 /* @@ -765,7 +733,7 @@ struct bpf_program { /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for internal communication with a * integrated service module (ISM). */ @@ -808,7 +776,7 @@ struct bpf_program { /* * Juniper-private data link type, as per request from - * Hannes Gredler . + * Hannes Gredler . * The DLT_ is used for capturing data on a secure tunnel interface. */ #define DLT_JUNIPER_ST 200 @@ -900,11 +868,11 @@ struct bpf_program { */ #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. + * Linux kernel to display systems, such as Xorg. */ #define DLT_LINUX_EVDEV 216 @@ -1025,8 +993,10 @@ struct bpf_program { /* * CAN (Controller Area Network) frames, with a pseudo-header as supplied - * by Linux SocketCAN. See Documentation/networking/can.txt in the Linux - * source. + * 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 . */ @@ -1104,7 +1074,7 @@ struct bpf_program { #define DLT_JUNIPER_ATM_CEMIC 238 /* - * NetFilter LOG messages + * NetFilter LOG messages * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) * * Requested by Jakub Zawadzki @@ -1165,11 +1135,11 @@ struct bpf_program { #define DLT_NFC_LLCP 245 /* - * 245 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. + * 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 245. + * don't already define it, define it as 246. */ #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) #define DLT_PFSYNC 246 @@ -1189,7 +1159,164 @@ struct bpf_program { */ #define DLT_SCTP 248 -#define DLT_MATCHING_MAX 248 /* highest value in the "matching" range */ +/* + * 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 stored with each + * packet: + * EXP_PDU_TAG_LINKTYPE the link type (LINKTYPE_ value) of the + * original packet. + * + * EXP_PDU_TAG_PROTO_NAME the name of the wireshark 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 OS X*; 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 OS X, you can't do so with + * this version of libpcap, just as you can't with Apple's libpcap - + * on OS X, 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 + +/* + * 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 265 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and @@ -1210,94 +1337,4 @@ struct bpf_program { #define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) #define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) - -/* - * The instruction encodings. - */ -/* 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 -#define BPF_MODE(code) ((code) & 0xe0) -#define BPF_IMM 0x00 -#define BPF_ABS 0x20 -#define BPF_IND 0x40 -#define BPF_MEM 0x60 -#define BPF_LEN 0x80 -#define BPF_MSH 0xa0 - -/* 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_JA 0x00 -#define BPF_JEQ 0x10 -#define BPF_JGT 0x20 -#define BPF_JGE 0x30 -#define BPF_JSET 0x40 -#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 - -/* misc */ -#define BPF_MISCOP(code) ((code) & 0xf8) -#define BPF_TAX 0x00 -#define BPF_TXA 0x80 - -/* - * The instruction data structure. - */ -struct bpf_insn { - u_short code; - u_char jt; - u_char jf; - bpf_u_int32 k; -}; - -/* - * Macros for insn array initializers. - */ -#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } -#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } - -#if __STDC__ || defined(__cplusplus) -extern int bpf_validate(const struct bpf_insn *, int); -extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); -#else -extern int bpf_validate(); -extern u_int bpf_filter(); -#endif - -/* - * 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) */ +#endif /* !defined(lib_pcap_dlt_h) */ diff --git a/contrib/libpcap/pcap/export-defs.h b/contrib/libpcap/pcap/export-defs.h new file mode 100644 index 0000000000..a2350579dc --- /dev/null +++ b/contrib/libpcap/pcap/export-defs.h @@ -0,0 +1,108 @@ +/* -*- 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. + */ + +#ifndef lib_pcap_export_defs_h +#define lib_pcap_export_defs_h + +/* + * PCAP_API_DEF must be used when defining *data* exported from + * libpcap. It can be used when defining *functions* exported + * from libpcap, but it doesn't have to be used there. It + * should not be used in declarations in headers. + * + * PCAP_API must be used when *declaring* data or functions + * exported from libpcap; PCAP_API_DEF won't work on all platforms. + */ + +/* + * Check whether this is GCC major.minor or a later release, or some + * compiler that claims to be "just like GCC" of that version or a + * later release. + */ +#define IS_AT_LEAST_GNUC_VERSION(major, minor) \ + (defined(__GNUC__) && \ + (__GNUC__ > (major) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) + +#if defined(_WIN32) + #ifdef BUILDING_PCAP + /* + * We're compiling libpcap, so we should export functions in our + * API. + */ + #define PCAP_API_DEF __declspec(dllexport) + #else + #define PCAP_API_DEF __declspec(dllimport) + #endif +#elif defined(MSDOS) + /* XXX - does this need special treatment? */ + #define PCAP_API_DEF +#else /* UN*X */ + #ifdef BUILDING_PCAP + /* + * We're compiling libpcap, so we should export functions in our API. + * The compiler might be configured not to export functions from a + * shared library by default, so we might have to explicitly mark + * functions as exported. + */ + #if IS_AT_LEAST_GNUC_VERSION(3, 4) + /* + * GCC 3.4 or later, or some compiler asserting compatibility with + * GCC 3.4 or later, so we have __attribute__((visibility()). + */ + #define PCAP_API_DEF __attribute__((visibility("default"))) + #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) + /* + * Sun C 5.5 or later, so we have __global. + * (Sun C 5.9 and later also have __attribute__((visibility()), + * but there's no reason to prefer it with Sun C.) + */ + #define PCAP_API_DEF __global + #else + /* + * We don't have anything to say. + */ + #define PCAP_API_DEF + #endif + #else + /* + * We're not building libpcap. + */ + #define PCAP_API_DEF + #endif +#endif /* _WIN32/MSDOS/UN*X */ + +#define PCAP_API PCAP_API_DEF extern + +#endif /* lib_pcap_export_defs_h */ diff --git a/contrib/libpcap/pcap/namedb.h b/contrib/libpcap/pcap/namedb.h index e31455791f..73fb40a4cf 100644 --- a/contrib/libpcap/pcap/namedb.h +++ b/contrib/libpcap/pcap/namedb.h @@ -29,8 +29,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006-10-04 18:09:22 guy Exp $ (LBL) */ #ifndef lib_pcap_namedb_h @@ -45,7 +43,10 @@ extern "C" { * XXX this stuff doesn't belong in this interface, but this * library already must do name to address translation, so * on systems that don't have support for /etc/ethers, we - * export these hooks since they'll + * export these hooks since they're already being used by + * some applications (such as tcpdump) and already being + * marked as exported in some OSes offering libpcap (such + * as Debian). */ struct pcap_etherent { u_char addr[6]; @@ -54,21 +55,21 @@ struct pcap_etherent { #ifndef PCAP_ETHERS_FILE #define PCAP_ETHERS_FILE "/etc/ethers" #endif -struct pcap_etherent *pcap_next_etherent(FILE *); -u_char *pcap_ether_hostton(const char*); -u_char *pcap_ether_aton(const char *); +PCAP_API struct pcap_etherent *pcap_next_etherent(FILE *); +PCAP_API u_char *pcap_ether_hostton(const char*); +PCAP_API u_char *pcap_ether_aton(const char *); -bpf_u_int32 **pcap_nametoaddr(const char *); +PCAP_API bpf_u_int32 **pcap_nametoaddr(const char *); #ifdef INET6 -struct addrinfo *pcap_nametoaddrinfo(const char *); +PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *); #endif -bpf_u_int32 pcap_nametonetaddr(const char *); +PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *); -int pcap_nametoport(const char *, int *, int *); -int pcap_nametoportrange(const char *, int *, int *, int *); -int pcap_nametoproto(const char *); -int pcap_nametoeproto(const char *); -int pcap_nametollc(const char *); +PCAP_API int pcap_nametoport(const char *, int *, int *); +PCAP_API int pcap_nametoportrange(const char *, int *, int *, int *); +PCAP_API int pcap_nametoproto(const char *); +PCAP_API int pcap_nametoeproto(const char *); +PCAP_API int pcap_nametollc(const char *); /* * If a protocol is unknown, PROTO_UNDEF is returned. * Also, pcap_nametoport() returns the protocol along with the port number. @@ -77,11 +78,6 @@ int pcap_nametollc(const char *); */ #define PROTO_UNDEF -1 -/* XXX move these to pcap-int.h? */ -int __pcap_atodn(const char *, bpf_u_int32 *); -int __pcap_atoin(const char *, bpf_u_int32 *); -u_short __pcap_nametodnaddr(const char *); - #ifdef __cplusplus } #endif diff --git a/contrib/libpcap/pcap/nflog.h b/contrib/libpcap/pcap/nflog.h new file mode 100644 index 0000000000..a3867cdd6c --- /dev/null +++ b/contrib/libpcap/pcap/nflog.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, Petar Alilovic, + * Faculty of Electrical Engineering and Computing, University of Zagreb + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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_nflog_h +#define lib_pcap_nflog_h + +/* + * Structure of an NFLOG header and TLV parts, as described at + * http://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html + * + * The NFLOG header is big-endian. + * + * The TLV length and type are in host byte order. The value is either + * big-endian or is an array of bytes in some externally-specified byte + * order (text string, link-layer address, link-layer header, packet + * data, etc.). + */ +typedef struct nflog_hdr { + u_int8_t nflog_family; /* address family */ + u_int8_t nflog_version; /* version */ + u_int16_t nflog_rid; /* resource ID */ +} nflog_hdr_t; + +typedef struct nflog_tlv { + u_int16_t tlv_length; /* tlv length */ + u_int16_t tlv_type; /* tlv type */ + /* value follows this */ +} nflog_tlv_t; + +typedef struct nflog_packet_hdr { + u_int16_t hw_protocol; /* hw protocol */ + u_int8_t hook; /* netfilter hook */ + u_int8_t pad; /* padding to 32 bits */ +} nflog_packet_hdr_t; + +typedef struct nflog_hwaddr { + u_int16_t hw_addrlen; /* address length */ + u_int16_t pad; /* padding to 32-bit boundary */ + u_int8_t hw_addr[8]; /* address, up to 8 bytes */ +} nflog_hwaddr_t; + +typedef struct nflog_timestamp { + u_int64_t sec; + u_int64_t usec; +} nflog_timestamp_t; + +/* + * TLV types. + */ +#define NFULA_PACKET_HDR 1 /* nflog_packet_hdr_t */ +#define NFULA_MARK 2 /* packet mark from skbuff */ +#define NFULA_TIMESTAMP 3 /* nflog_timestamp_t for skbuff's time stamp */ +#define NFULA_IFINDEX_INDEV 4 /* ifindex of device on which packet received (possibly bridge group) */ +#define NFULA_IFINDEX_OUTDEV 5 /* ifindex of device on which packet transmitted (possibly bridge group) */ +#define NFULA_IFINDEX_PHYSINDEV 6 /* ifindex of physical device on which packet received (not bridge group) */ +#define NFULA_IFINDEX_PHYSOUTDEV 7 /* ifindex of physical device on which packet transmitted (not bridge group) */ +#define NFULA_HWADDR 8 /* nflog_hwaddr_t for hardware address */ +#define NFULA_PAYLOAD 9 /* packet payload */ +#define NFULA_PREFIX 10 /* text string - null-terminated, count includes NUL */ +#define NFULA_UID 11 /* UID owning socket on which packet was sent/received */ +#define NFULA_SEQ 12 /* sequence number of packets on this NFLOG socket */ +#define NFULA_SEQ_GLOBAL 13 /* sequence number of pakets on all NFLOG sockets */ +#define NFULA_GID 14 /* GID owning socket on which packet was sent/received */ +#define NFULA_HWTYPE 15 /* ARPHRD_ type of skbuff's device */ +#define NFULA_HWHEADER 16 /* skbuff's MAC-layer header */ +#define NFULA_HWLEN 17 /* length of skbuff's MAC-layer header */ + +#endif diff --git a/contrib/libpcap/pcap/pcap.h b/contrib/libpcap/pcap/pcap.h index 7be36b1718..7f92a379f7 100644 --- a/contrib/libpcap/pcap/pcap.h +++ b/contrib/libpcap/pcap/pcap.h @@ -30,14 +30,14 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.15 2008-10-06 15:27:32 gianluca Exp $ (LBL) */ #ifndef lib_pcap_pcap_h #define lib_pcap_pcap_h -#if defined(WIN32) +#include + +#if defined(_WIN32) #include #elif defined(MSDOS) #include @@ -45,7 +45,7 @@ #else /* UN*X */ #include #include -#endif /* WIN32/MSDOS/UN*X */ +#endif /* _WIN32/MSDOS/UN*X */ #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H #include @@ -115,7 +115,7 @@ typedef struct pcap_addr pcap_addr_t; * * Then supply the changes by forking the branch at * - * https://github.com/mcr/libpcap/issues + * https://github.com/the-tcpdump-group/libpcap/issues * * 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 @@ -133,7 +133,7 @@ struct pcap_file_header { /* * 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. */ @@ -172,9 +172,11 @@ 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 bs_capt; /* number of packets that reach the application */ -#endif /* WIN32 */ +#if defined(_WIN32) && defined(HAVE_REMOTE) + 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 && HAVE_REMOTE */ }; #ifdef MSDOS @@ -222,6 +224,8 @@ struct pcap_if { }; #define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ +#define PCAP_IF_UP 0x00000002 /* interface is up */ +#define PCAP_IF_RUNNING 0x00000004 /* interface is running */ /* * Representation of an interface address. @@ -254,6 +258,7 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, #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. @@ -270,24 +275,27 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, */ #define PCAP_NETMASK_UNKNOWN 0xffffffff -char *pcap_lookupdev(char *); -int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); - -pcap_t *pcap_create(const char *, char *); -int pcap_set_snaplen(pcap_t *, int); -int pcap_set_promisc(pcap_t *, int); -int pcap_can_set_rfmon(pcap_t *); -int pcap_set_rfmon(pcap_t *, int); -int pcap_set_timeout(pcap_t *, int); -int pcap_set_tstamp_type(pcap_t *, int); -int pcap_set_buffer_size(pcap_t *, int); -int pcap_activate(pcap_t *); - -int pcap_list_tstamp_types(pcap_t *, int **); -void pcap_free_tstamp_types(int *); -int pcap_tstamp_type_name_to_val(const char *); -const char *pcap_tstamp_type_val_to_name(int); -const char *pcap_tstamp_type_val_to_description(int); +PCAP_API char *pcap_lookupdev(char *); +PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +PCAP_API pcap_t *pcap_create(const char *, char *); +PCAP_API int pcap_set_snaplen(pcap_t *, int); +PCAP_API int pcap_set_promisc(pcap_t *, int); +PCAP_API int pcap_can_set_rfmon(pcap_t *); +PCAP_API int pcap_set_rfmon(pcap_t *, int); +PCAP_API int pcap_set_timeout(pcap_t *, int); +PCAP_API int pcap_set_tstamp_type(pcap_t *, int); +PCAP_API int pcap_set_immediate_mode(pcap_t *, int); +PCAP_API int pcap_set_buffer_size(pcap_t *, int); +PCAP_API int pcap_set_tstamp_precision(pcap_t *, int); +PCAP_API int pcap_get_tstamp_precision(pcap_t *); +PCAP_API int pcap_activate(pcap_t *); + +PCAP_API int pcap_list_tstamp_types(pcap_t *, int **); +PCAP_API void pcap_free_tstamp_types(int *); +PCAP_API int pcap_tstamp_type_name_to_val(const char *); +PCAP_API const char *pcap_tstamp_type_val_to_name(int); +PCAP_API const char *pcap_tstamp_type_val_to_description(int); /* * Time stamp types. @@ -333,128 +341,195 @@ const char *pcap_tstamp_type_val_to_description(int); #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 */ -pcap_t *pcap_open_live(const char *, int, int, int, char *); -pcap_t *pcap_open_dead(int, int); -pcap_t *pcap_open_offline(const char *, char *); -#if defined(WIN32) -pcap_t *pcap_hopen_offline(intptr_t, char *); -#if !defined(LIBPCAP_EXPORTS) -#define pcap_fopen_offline(f,b) \ +/* + * 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_API pcap_t *pcap_open_live(const char *, int, int, int, char *); +PCAP_API pcap_t *pcap_open_dead(int, int); +PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int); +PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *); +PCAP_API pcap_t *pcap_open_offline(const char *, char *); +#ifdef _WIN32 + 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 mustn't define them as macros. + */ + #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) -#else /*LIBPCAP_EXPORTS*/ -static pcap_t *pcap_fopen_offline(FILE *, char *); -#endif -#else /*WIN32*/ -pcap_t *pcap_fopen_offline(FILE *, char *); -#endif /*WIN32*/ - -void pcap_close(pcap_t *); -int pcap_loop(pcap_t *, int, pcap_handler, u_char *); -int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); -const u_char* - pcap_next(pcap_t *, struct pcap_pkthdr *); -int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); -void pcap_breakloop(pcap_t *); -int pcap_stats(pcap_t *, struct pcap_stat *); -int pcap_setfilter(pcap_t *, struct bpf_program *); -int pcap_setdirection(pcap_t *, pcap_direction_t); -int pcap_getnonblock(pcap_t *, char *); -int pcap_setnonblock(pcap_t *, int, char *); -int pcap_inject(pcap_t *, const void *, size_t); -int pcap_sendpacket(pcap_t *, const u_char *, int); -const char *pcap_statustostr(int); -const char *pcap_strerror(int); -char *pcap_geterr(pcap_t *); -void pcap_perror(pcap_t *, char *); -int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + #endif +#else /*_WIN32*/ + PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); + PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*_WIN32*/ + +PCAP_API void pcap_close(pcap_t *); +PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *); +PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +PCAP_API void pcap_breakloop(pcap_t *); +PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *); +PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *); +PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t); +PCAP_API int pcap_getnonblock(pcap_t *, char *); +PCAP_API int pcap_setnonblock(pcap_t *, int, char *); +PCAP_API int pcap_inject(pcap_t *, const void *, size_t); +PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int); +PCAP_API const char *pcap_statustostr(int); +PCAP_API const char *pcap_strerror(int); +PCAP_API char *pcap_geterr(pcap_t *); +PCAP_API void pcap_perror(pcap_t *, const char *); +PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32); -int pcap_compile_nopcap(int, int, struct bpf_program *, +PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *, const char *, int, bpf_u_int32); -void pcap_freecode(struct bpf_program *); -int pcap_offline_filter(const struct bpf_program *, +PCAP_API void pcap_freecode(struct bpf_program *); +PCAP_API int pcap_offline_filter(const struct bpf_program *, const struct pcap_pkthdr *, const u_char *); -int pcap_datalink(pcap_t *); -int pcap_datalink_ext(pcap_t *); -int pcap_list_datalinks(pcap_t *, int **); -int pcap_set_datalink(pcap_t *, int); -void pcap_free_datalinks(int *); -int pcap_datalink_name_to_val(const char *); -const char *pcap_datalink_val_to_name(int); -const char *pcap_datalink_val_to_description(int); -int pcap_snapshot(pcap_t *); -int pcap_is_swapped(pcap_t *); -int pcap_major_version(pcap_t *); -int pcap_minor_version(pcap_t *); +PCAP_API int pcap_datalink(pcap_t *); +PCAP_API int pcap_datalink_ext(pcap_t *); +PCAP_API int pcap_list_datalinks(pcap_t *, int **); +PCAP_API int pcap_set_datalink(pcap_t *, int); +PCAP_API void pcap_free_datalinks(int *); +PCAP_API int pcap_datalink_name_to_val(const char *); +PCAP_API const char *pcap_datalink_val_to_name(int); +PCAP_API const char *pcap_datalink_val_to_description(int); +PCAP_API int pcap_snapshot(pcap_t *); +PCAP_API int pcap_is_swapped(pcap_t *); +PCAP_API int pcap_major_version(pcap_t *); +PCAP_API int pcap_minor_version(pcap_t *); /* XXX */ -FILE *pcap_file(pcap_t *); -int pcap_fileno(pcap_t *); +PCAP_API FILE *pcap_file(pcap_t *); +PCAP_API int pcap_fileno(pcap_t *); + +#ifdef _WIN32 + PCAP_API int pcap_wsockinit(void); +#endif -pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); -pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); -FILE *pcap_dump_file(pcap_dumper_t *); -long pcap_dump_ftell(pcap_dumper_t *); -int pcap_dump_flush(pcap_dumper_t *); -void pcap_dump_close(pcap_dumper_t *); -void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); +PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); +PCAP_API FILE *pcap_dump_file(pcap_dumper_t *); +PCAP_API long pcap_dump_ftell(pcap_dumper_t *); +PCAP_API int pcap_dump_flush(pcap_dumper_t *); +PCAP_API void pcap_dump_close(pcap_dumper_t *); +PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); -int pcap_findalldevs(pcap_if_t **, char *); -void pcap_freealldevs(pcap_if_t *); +PCAP_API int pcap_findalldevs(pcap_if_t **, char *); +PCAP_API void pcap_freealldevs(pcap_if_t *); -const char *pcap_lib_version(void); +PCAP_API const char *pcap_lib_version(void); /* - * On at least some versions of NetBSD, we don't want to declare + * On at least some versions of NetBSD and QNX, we don't want to declare * bpf_filter() here, as it's also be declared in , with a * different signature, but, on other BSD-flavored UN*Xes, it's not * declared in , so we *do* want to declare it here, so it's * declared when we build pcap-bpf.c. */ -#ifndef __NetBSD__ -u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#if !defined(__NetBSD__) && !defined(__QNX__) + PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); #endif -int bpf_validate(const struct bpf_insn *f, int len); -char *bpf_image(const struct bpf_insn *, int); -void bpf_dump(const struct bpf_program *, int); +PCAP_API int bpf_validate(const struct bpf_insn *f, int len); +PCAP_API char *bpf_image(const struct bpf_insn *, int); +PCAP_API void bpf_dump(const struct bpf_program *, int); -#if defined(WIN32) +#if defined(_WIN32) -/* - * Win32 definitions - */ + /* + * 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 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); -int pcap_setbuff(pcap_t *p, int dim); -int pcap_setmode(pcap_t *p, int mode); -int pcap_setmintocopy(pcap_t *p, int size); + PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *); + PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *); -#ifdef WPCAP -/* Include file with the wpcap-specific extensions */ -#include -#endif /* WPCAP */ + PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); -#define MODE_CAPT 0 -#define MODE_STAT 1 -#define MODE_MON 2 + 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 - */ + /* + * MS-DOS definitions + */ -int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); -void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); -u_long pcap_mac_packets (void); + 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 - */ + /* + * UN*X definitions + */ + + PCAP_API int pcap_get_selectable_fd(pcap_t *); -int pcap_get_selectable_fd(pcap_t *); +#endif /* _WIN32/MSDOS/UN*X */ -#endif /* WIN32/MSDOS/UN*X */ +#ifdef HAVE_REMOTE + /* Includes most of the public stuff that is needed for the remote capture */ + #include +#endif /* HAVE_REMOTE */ #ifdef __cplusplus } diff --git a/contrib/libpcap/pcap/sll.h b/contrib/libpcap/pcap/sll.h index 7ad811d7c2..b46d15f25d 100644 --- a/contrib/libpcap/pcap/sll.h +++ b/contrib/libpcap/pcap/sll.h @@ -34,8 +34,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.3 2008-05-30 01:35:33 guy Exp $ (LBL) */ /* @@ -125,5 +123,7 @@ struct sll_header { */ #define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ #define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_CAN 0x000C /* CAN frames, with SocketCAN pseudo-headers */ +#define LINUX_SLL_P_CANFD 0x000D /* CAN FD frames, with SocketCAN pseudo-headers */ #endif diff --git a/contrib/libpcap/pcap/usb.h b/contrib/libpcap/pcap/usb.h index aa35122586..26a9046b44 100644 --- a/contrib/libpcap/pcap/usb.h +++ b/contrib/libpcap/pcap/usb.h @@ -11,8 +11,8 @@ * 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 + * 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 @@ -29,14 +29,12 @@ * * Basic USB data struct * By Paolo Abeni - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.9 2008-12-23 20:13:29 guy Exp $ */ - -#ifndef _PCAP_USB_STRUCTS_H__ -#define _PCAP_USB_STRUCTS_H__ -/* +#ifndef lib_pcap_usb_h +#define lib_pcap_usb_h + +/* * possible transfer mode */ #define URB_TRANSFER_IN 0x80 diff --git a/contrib/libpcap/pcap/vlan.h b/contrib/libpcap/pcap/vlan.h index 41aa8c7862..021f612907 100644 --- a/contrib/libpcap/pcap/vlan.h +++ b/contrib/libpcap/pcap/vlan.h @@ -29,8 +29,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1 2008-08-06 07:45:00 guy Exp $ */ #ifndef lib_pcap_vlan_h diff --git a/contrib/libpcap/pcap_activate.3pcap b/contrib/libpcap/pcap_activate.3pcap index f963d35e51..8c89939fdd 100644 --- a/contrib/libpcap/pcap_activate.3pcap +++ b/contrib/libpcap/pcap_activate.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_activate.3pcap,v 1.5 2008-07-01 08:02:33 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_ACTIVATE 3PCAP "5 April 2008" +.TH PCAP_ACTIVATE 3PCAP "7 April 2014" .SH NAME pcap_activate \- activate a capture handle .SH SYNOPSIS @@ -39,46 +37,65 @@ at packets on the network, with the options that were set on the handle being in effect. .SH RETURN VALUE .B pcap_activate() -returns 0 on success without warnings, +returns 0 on success without warnings, a non-zero positive value on +success with warnings, and a negative value on error. +A non-zero return value indicates what warning or error condition +occurred. +.LP +The possible warning values are: +.TP .B PCAP_WARNING_PROMISC_NOTSUP -on success on a device that doesn't support promiscuous mode if -promiscuous mode was requested, +Promiscuous mode was requested, but the capture source doesn't support +promiscuous mode. +.TP .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP -on success if the time stamp type specified in a previous +The time stamp type specified in a previous .B pcap_set_tstamp_type() call isn't supported by the capture source (the time stamp type is left as the default), +.TP .B PCAP_WARNING -on success with any other warning, +Another warning condition occurred; +.B pcap_geterr() +or +.B pcap_perror() +may be called with +.I p +as an argument to fetch or display a message describing the warning +condition. +.LP +The possible error values are: +.TP .B PCAP_ERROR_ACTIVATED -if the handle has already been activated, +The handle has already been activated. +.TP .B PCAP_ERROR_NO_SUCH_DEVICE -if the capture source specified when the handle was created doesn't -exist, +The capture source specified when the handle was created doesn't +exist. +.TP .B PCAP_ERROR_PERM_DENIED -if the process doesn't have permission to open the capture source, +The process doesn't have permission to open the capture source. +.TP .B PCAP_ERROR_PROMISC_PERM_DENIED -if the process has permission to open the capture source but doesn't -have permission to put it into promiscuous mode, +The process has permission to open the capture source but doesn't +have permission to put it into promiscuous mode. +.TP .B PCAP_ERROR_RFMON_NOTSUP -if monitor mode was specified but the capture source doesn't support -monitor mode, +Monitor mode was specified but the capture source doesn't support +monitor mode. +.TP .B PCAP_ERROR_IFACE_NOT_UP -if the capture source is not up, and +The capture source device is not up. +.TP .B PCAP_ERROR -if another error occurred. -If -.B PCAP_WARNING -or -.B PCAP_ERROR -is returned, +Another error occurred. .B pcap_geterr() or .B pcap_perror() may be called with .I p -as an argument to fetch or display a message describing the warning or -error. +as an argument to fetch or display a message describing the error. +.LP If .BR PCAP_WARNING_PROMISC_NOTSUP , .BR PCAP_ERROR_NO_SUCH_DEVICE , @@ -93,5 +110,13 @@ may be called with as an argument to fetch or display an message giving additional details about the problem that might be useful for debugging the problem if it's unexpected. +.LP +Additional warning and error codes may be added in the future; a program +should check for positive, negative, and zero return codes, and treat +all positive return codes as warnings and all negative return +codes as errors. +.B pcap_statustostr() +can be called, with a warning or error code as an argument, to fetch a +message describing the warning or error code. .SH SEE ALSO pcap(3PCAP) diff --git a/contrib/libpcap/pcap_breakloop.3pcap b/contrib/libpcap/pcap_breakloop.3pcap index e437af8a8e..3f9327b198 100644 --- a/contrib/libpcap/pcap_breakloop.3pcap +++ b/contrib/libpcap/pcap_breakloop.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_breakloop.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_BREAKLOOP 3PCAP "5 April 2008" +.TH PCAP_BREAKLOOP 3PCAP "8 March 2015" .SH NAME pcap_breakloop \- force a pcap_dispatch() or pcap_loop() call to return .SH SYNOPSIS @@ -93,7 +91,7 @@ If \-2 is returned from .B pcap_dispatch() or .BR pcap_loop() , -the flag is cleared, so a subsequent call will resume reading packets. +the flag is cleared, so a subsequent call will resume reading packets. If a positive number is returned, the flag is not cleared, so a subsequent call will return \-2 and clear the flag. .SH SEE ALSO diff --git a/contrib/libpcap/pcap_can_set_rfmon.3pcap b/contrib/libpcap/pcap_can_set_rfmon.3pcap index 00b92a4034..389e50ddaa 100644 --- a/contrib/libpcap/pcap_can_set_rfmon.3pcap +++ b/contrib/libpcap/pcap_can_set_rfmon.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_can_set_rfmon.3pcap,v 1.1 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_CAN_SET_RFMON 3PCAP "18 May 2010" +.TH PCAP_CAN_SET_RFMON 3PCAP "3 January 2014" .SH NAME pcap_can_set_rfmon \- check whether monitor mode can be set for a not-yet-activated capture handle @@ -39,26 +37,36 @@ the handle is activated. .SH RETURN VALUE .B pcap_can_set_rfmon() returns 0 if monitor mode could not be set, -1 if monitor mode could be set, +1 if monitor mode could be set, and a negative value on error. +A negative return value indicates what error condition occurred. +The possible error values are: +.TP .B PCAP_ERROR_NO_SUCH_DEVICE -if the capture source specified when the handle was created doesn't -exist, +The capture source specified when the handle was created doesn't +exist. +.TP .B PCAP_ERROR_PERM_DENIED -if the process doesn't have permission to check whether monitor mode -could be supported, +The process doesn't have permission to check whether monitor mode +could be supported. +.TP .B PCAP_ERROR_ACTIVATED -if called on a capture handle that has been activated, or -.B PCAP_ERROR -if an error occurred. -If +The capture handle has already been activated. +.TP .B PCAP_ERROR -is returned, +Another error occurred. .B pcap_geterr() or .B pcap_perror() may be called with .I p -as an argument to fetch or display the error text. +as an argument to fetch or display a message describing the error. +.LP +Additional error codes may be added in the future; a program should +check for 0, 1, and negative, return codes, and treat all negative +return codes as errors. +.B pcap_statustostr() +can be called, with a warning or error code as an argument, to fetch a +message describing the warning or error code. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), pcap_set_rfmon(3PCAP) diff --git a/contrib/libpcap/pcap_close.3pcap b/contrib/libpcap/pcap_close.3pcap index 810664dbd7..e2316a417d 100644 --- a/contrib/libpcap/pcap_close.3pcap +++ b/contrib/libpcap/pcap_close.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_close.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_CLOSE 3PCAP "5 April 2008" +.TH PCAP_CLOSE 3PCAP "3 January 2014" .SH NAME pcap_close \- close a capture device or savefile .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_compile.3pcap.in b/contrib/libpcap/pcap_compile.3pcap.in index 7dbdad5a1c..2bd0eb4694 100644 --- a/contrib/libpcap/pcap_compile.3pcap.in +++ b/contrib/libpcap/pcap_compile.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_compile.3pcap.in,v 1.1 2008-10-21 07:33:02 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_COMPILE 3PCAP "5 April 2008" +.TH PCAP_COMPILE 3PCAP "7 April 2014" .SH NAME pcap_compile \- compile a filter expression .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_create.3pcap b/contrib/libpcap/pcap_create.3pcap index 153f9fd696..3040b3b200 100644 --- a/contrib/libpcap/pcap_create.3pcap +++ b/contrib/libpcap/pcap_create.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_create.3pcap,v 1.1 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_CREATE 3PCAP "5 April 2008" +.TH PCAP_CREATE 3PCAP "3 January 2014" .SH NAME pcap_create \- create a live capture handle .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_datalink.3pcap.in b/contrib/libpcap/pcap_datalink.3pcap.in index 3d4ace1d79..be50a649ee 100644 --- a/contrib/libpcap/pcap_datalink.3pcap.in +++ b/contrib/libpcap/pcap_datalink.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_datalink.3pcap.in,v 1.1 2008-10-21 07:33:02 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DATALINK 3PCAP "22 August 2010" +.TH PCAP_DATALINK 3PCAP "7 April 2014" .SH NAME pcap_datalink \- get the link-layer header type .SH SYNOPSIS @@ -37,5 +35,34 @@ int pcap_datalink(pcap_t *p); returns the link-layer header type for the live capture or ``savefile'' specified by .IR p . +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.PP +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.B pcap_datalink() +returns the link-layer header type on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) diff --git a/contrib/libpcap/pcap_datalink_name_to_val.3pcap b/contrib/libpcap/pcap_datalink_name_to_val.3pcap index 9c8e18a3c4..8a6905a2c5 100644 --- a/contrib/libpcap/pcap_datalink_name_to_val.3pcap +++ b/contrib/libpcap/pcap_datalink_name_to_val.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_datalink_name_to_val.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "22 August 2010" +.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "5 December 2014" .SH NAME pcap_datalink_name_to_val \- get the link-layer header type value corresponding to a header type name @@ -43,6 +41,7 @@ removed, to the corresponding link-layer header type value. The translation is case-insensitive. .SH RETURN VALUE .B pcap_datalink_name_to_val() -returns 0 on success and \-1 on failure. +returns the type value on success and \-1 if the name is not a known +type name.. .SH SEE ALSO pcap(3PCAP) diff --git a/contrib/libpcap/pcap_datalink_val_to_name.3pcap b/contrib/libpcap/pcap_datalink_val_to_name.3pcap index 26397faf91..aa3e89a6e0 100644 --- a/contrib/libpcap/pcap_datalink_val_to_name.3pcap +++ b/contrib/libpcap/pcap_datalink_val_to_name.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_datalink_val_to_name.3pcap,v 1.3 2008-12-24 21:45:25 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "22 August 2010" +.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "3 January 2014" .SH NAME pcap_datalink_val_to_name, pcap_datalink_val_to_description \- get a name or description for a link-layer header type value @@ -37,8 +35,20 @@ const char *pcap_datalink_val_to_description(int dlt); .SH DESCRIPTION .B pcap_datalink_val_to_name() translates a link-layer header type value to the corresponding -link-layer header type name. NULL is returned on failure. +link-layer header type name, which is the +.B DLT_ +name for the link-layer header type value with the +.B DLT_ +removed. +.B NULL +is returned if the type value does not correspond to a known +.B DLT_ +value. .PP .B pcap_datalink_val_to_description() translates a link-layer header type value to a short description of that -link-layer header type. NULL is returned on failure. +link-layer header type. +.B NULL +is returned if the type value does not correspond to a known +.B DLT_ +value. diff --git a/contrib/libpcap/pcap_dump.3pcap b/contrib/libpcap/pcap_dump.3pcap index 1ccd82a6f5..6402b4b451 100644 --- a/contrib/libpcap/pcap_dump.3pcap +++ b/contrib/libpcap/pcap_dump.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP 3PCAP "5 April 2008" +.TH PCAP_DUMP 3PCAP "8 March 2015" .SH NAME pcap_dump \- write a packet to a capture file .SH SYNOPSIS @@ -42,9 +40,9 @@ Note that its calling arguments are suitable for use with .B pcap_dispatch() or .BR pcap_loop() . -If called directly, the +If called directly, the .I user -parameter is of type +parameter is of type .B pcap_dumper_t as returned by .BR pcap_dump_open() . diff --git a/contrib/libpcap/pcap_dump_close.3pcap b/contrib/libpcap/pcap_dump_close.3pcap index 4ed820b037..bd95a52b29 100644 --- a/contrib/libpcap/pcap_dump_close.3pcap +++ b/contrib/libpcap/pcap_dump_close.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump_close.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_CLOSE 3PCAP "5 April 2008" +.TH PCAP_DUMP_CLOSE 3PCAP "3 January 2014" .SH NAME pcap_dump_close \- close a savefile being written to .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_dump_file.3pcap b/contrib/libpcap/pcap_dump_file.3pcap index 9e51a2a989..8fea610a4f 100644 --- a/contrib/libpcap/pcap_dump_file.3pcap +++ b/contrib/libpcap/pcap_dump_file.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump_file.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_FILE 3PCAP "5 April 2008" +.TH PCAP_DUMP_FILE 3PCAP "3 January 2014" .SH NAME pcap_dump_file \- get the standard I/O stream for a savefile being written .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_dump_flush.3pcap b/contrib/libpcap/pcap_dump_flush.3pcap index b553883aa1..c8f110bb6f 100644 --- a/contrib/libpcap/pcap_dump_flush.3pcap +++ b/contrib/libpcap/pcap_dump_flush.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump_flush.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_FLUSH 3PCAP "5 April 2008" +.TH PCAP_DUMP_FLUSH 3PCAP "3 January 2014" .SH NAME pcap_dump_flush \- flush to a savefile packets dumped .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_dump_ftell.3pcap b/contrib/libpcap/pcap_dump_ftell.3pcap index 1d0f96f35d..757e9482ba 100644 --- a/contrib/libpcap/pcap_dump_ftell.3pcap +++ b/contrib/libpcap/pcap_dump_ftell.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump_ftell.3pcap,v 1.3 2008-04-06 02:53:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_FTELL 3PCAP "5 April 2008" +.TH PCAP_DUMP_FTELL 3PCAP "3 January 2014" .SH NAME pcap_dump_ftell \- get the current file offset for a savefile being written .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_dump_open.3pcap.in b/contrib/libpcap/pcap_dump_open.3pcap.in index 2a5dc9de17..3f91d13bf8 100644 --- a/contrib/libpcap/pcap_dump_open.3pcap.in +++ b/contrib/libpcap/pcap_dump_open.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_dump_open.3pcap.in,v 1.1 2008-10-23 05:56:59 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_OPEN 3PCAP "5 April 2008" +.TH PCAP_DUMP_OPEN 3PCAP "16 February 2015" .SH NAME pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets .SH SYNOPSIS @@ -31,6 +29,7 @@ pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets .LP .ft B pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname); +pcap_dumper_t *pcap_dump_open_append(pcap_t *p, const char *fname); pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *fp); .ft .fi @@ -43,7 +42,7 @@ the same format as those used by .BR tcpdump (1) and .BR tcpslice (1). -The name "-" in a synonym +The name "-" is a synonym for .BR stdout . .PP @@ -62,9 +61,19 @@ or returned by an earlier call to .BR pcap_open_live() , or .BR pcap_open_dead() . -The link-layer type and snapshot length from +The time stamp precision, link-layer type, and snapshot length from .I p are used as the link-layer type and snapshot length of the output file. +.PP +.B pcap_dump_open_append() +is like +.B pcap_dump_open +but does not create the file if it does not exist and, if it does +already exist, and is a pcap file with the same byte order as the host +opening the file, and has the same time stamp precision, link-layer +header type, and snapshot length as +.IR p , +it will write new packets at the end of the file. .SH RETURN VALUES A pointer to a .B pcap_dumper_t diff --git a/contrib/libpcap/pcap_file.3pcap b/contrib/libpcap/pcap_file.3pcap index 1471ab63c8..cd6b06bb8a 100644 --- a/contrib/libpcap/pcap_file.3pcap +++ b/contrib/libpcap/pcap_file.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_file.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FILE 3PCAP "5 April 2008" +.TH PCAP_FILE 3PCAP "3 January 2014" .SH NAME pcap_file \- get the standard I/O stream for a savefile being read .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_fileno.3pcap b/contrib/libpcap/pcap_fileno.3pcap index 723733e73d..7aeb06947b 100644 --- a/contrib/libpcap/pcap_fileno.3pcap +++ b/contrib/libpcap/pcap_fileno.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_fileno.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FILENO 3PCAP "5 April 2008" +.TH PCAP_FILENO 3PCAP "7 April 2014" .SH NAME pcap_fileno \- get the file descriptor for a live capture .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_findalldevs.3pcap b/contrib/libpcap/pcap_findalldevs.3pcap index 2e56d09165..2dd3e59b9c 100644 --- a/contrib/libpcap/pcap_findalldevs.3pcap +++ b/contrib/libpcap/pcap_findalldevs.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_findalldevs.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FINDALLDEVS 3PCAP "22 August 2010" +.TH PCAP_FINDALLDEVS 3PCAP "7 April 2014" .SH NAME pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and free that list @@ -94,6 +92,12 @@ device flags: .TP .B PCAP_IF_LOOPBACK set if the device is a loopback interface +.TP +.B PCAP_IF_UP +set if the device is up +.TP +.B PCAP_IF_RUNNING +set if the device is running .RE .RE .PP @@ -167,7 +171,7 @@ for IPv6 addresses, it can be interpreted as if it pointed to a .PP The list of devices must be freed with .BR pcap_freealldevs() , -whch frees the list pointed to by +which frees the list pointed to by .IR alldevs . .SH RETURN VALUE .B pcap_findalldevs() diff --git a/contrib/libpcap/pcap_freecode.3pcap b/contrib/libpcap/pcap_freecode.3pcap index 31b4f89711..fac4b3df2a 100644 --- a/contrib/libpcap/pcap_freecode.3pcap +++ b/contrib/libpcap/pcap_freecode.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_freecode.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FREECODE 3PCAP "5 April 2008" +.TH PCAP_FREECODE 3PCAP "3 January 2014" .SH NAME pcap_freecode \- free a BPF program .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_get_selectable_fd.3pcap b/contrib/libpcap/pcap_get_selectable_fd.3pcap index ae33dbb2e4..86b0c2683f 100644 --- a/contrib/libpcap/pcap_get_selectable_fd.3pcap +++ b/contrib/libpcap/pcap_get_selectable_fd.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_get_selectable_fd.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_GET_SELECTABLE_FD 3PCAP "5 April 2008" +.TH PCAP_GET_SELECTABLE_FD 3PCAP "18 October 2014" .SH NAME pcap_get_selectable_fd \- get a file descriptor on which a select() can be done for a live capture @@ -38,9 +36,9 @@ int pcap_get_selectable_fd(pcap_t *p); returns, on UNIX, a file descriptor number for a file descriptor on which one can do a -.B select() -or -.B poll() +.BR select() , +.BR poll() , +or other such call to wait for it to be possible to read packets without blocking, if such a descriptor exists, or \-1, if no such descriptor exists. Some network devices opened with @@ -56,6 +54,12 @@ or (for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace DAG devices), so \-1 is returned for those devices. .PP +Note that a descriptor on which a read can be done without blocking may, +on some platforms, not have any packets to read if the read timeout has +expired. A call to +.B pcap_dispatch() +will return 0 in this case, but will not block. +.PP Note that in: .IP FreeBSD prior to FreeBSD 4.6; diff --git a/contrib/libpcap/pcap_get_tstamp_precision.3pcap.in b/contrib/libpcap/pcap_get_tstamp_precision.3pcap.in new file mode 100644 index 0000000000..285e77095e --- /dev/null +++ b/contrib/libpcap/pcap_get_tstamp_precision.3pcap.in @@ -0,0 +1,52 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"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 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. + +.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "18 December 2013" +.SH NAME +pcap_get_tstamp_precision \- get the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_get_tstamp_precision(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.B pcap_get_tstamp_precision() +returns the precision of the time stamp returned in packet captures on the pcap +descriptor. +.SH RETURN VALUE +.B pcap_get_tstamp_precision() +returns +.B PCAP_TSTAMP_PRECISION_MICRO +or +.BR PCAP_TSTAMP_PRECISION_NANO , +which indicates +that pcap captures contains time stamps in microseconds or nanoseconds +respectively. +.SH SEE ALSO +pcap(3PCAP), +pcap_set_tstamp_precision(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/contrib/libpcap/pcap_geterr.3pcap b/contrib/libpcap/pcap_geterr.3pcap index 1a4ea3476b..2e99c37de3 100644 --- a/contrib/libpcap/pcap_geterr.3pcap +++ b/contrib/libpcap/pcap_geterr.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_geterr.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_GETERR 3PCAP "5 April 2008" +.TH PCAP_GETERR 3PCAP "3 January 2014" .SH NAME pcap_geterr, pcap_perror \- get or print libpcap error message text .SH SYNOPSIS @@ -30,7 +28,7 @@ pcap_geterr, pcap_perror \- get or print libpcap error message text .LP .ft B char *pcap_geterr(pcap_t *p); -void pcap_perror(pcap_t *p, char *prefix); +void pcap_perror(pcap_t *p, const char *prefix); .ft .fi .SH DESCRIPTION diff --git a/contrib/libpcap/pcap_inject.3pcap b/contrib/libpcap/pcap_inject.3pcap index 79a3eea6da..ff9792d209 100644 --- a/contrib/libpcap/pcap_inject.3pcap +++ b/contrib/libpcap/pcap_inject.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_inject.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_INJECT 3PCAP "5 April 2008" +.TH PCAP_INJECT 3PCAP "3 January 2014" .SH NAME pcap_inject, pcap_sendpacket \- transmit a packet .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_is_swapped.3pcap b/contrib/libpcap/pcap_is_swapped.3pcap index 4d26b3be9e..c4e62ae547 100644 --- a/contrib/libpcap/pcap_is_swapped.3pcap +++ b/contrib/libpcap/pcap_is_swapped.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_is_swapped.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_IS_SWAPPED 3PCAP "5 April 2008" +.TH PCAP_IS_SWAPPED 3PCAP "7 April 2014" .SH NAME pcap_is_swapped \- find out whether a savefile has the native byte order .SH SYNOPSIS @@ -34,9 +32,20 @@ int pcap_is_swapped(pcap_t *p); .fi .SH DESCRIPTION .B pcap_is_swapped() -returns true if +returns true (1) if .I p refers to a ``savefile'' that uses a different byte order -than the current system. For a live capture, it always returns false. +than the current system. For a live capture, it always returns false +(0). +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.SH RETURN VALUE +.B pcap_datalink() +returns true (1) or false (0) on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP) diff --git a/contrib/libpcap/pcap_lib_version.3pcap b/contrib/libpcap/pcap_lib_version.3pcap index 7b39be1810..4b86b2d577 100644 --- a/contrib/libpcap/pcap_lib_version.3pcap +++ b/contrib/libpcap/pcap_lib_version.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_lib_version.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LIB_VERSION 3PCAP "5 April 2008" +.TH PCAP_LIB_VERSION 3PCAP "3 January 2014" .SH NAME pcap_lib_version \- get the version information for libpcap .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_list_datalinks.3pcap.in b/contrib/libpcap/pcap_list_datalinks.3pcap.in index 632757642b..9f52b63bb9 100644 --- a/contrib/libpcap/pcap_list_datalinks.3pcap.in +++ b/contrib/libpcap/pcap_list_datalinks.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_list_datalinks.3pcap.in,v 1.1 2008-10-21 07:33:02 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LIST_DATALINKS 3PCAP "22 August 2010" +.TH PCAP_LIST_DATALINKS 3PCAP "8 March 2015" .SH NAME pcap_list_datalinks, pcap_free_datalinks \- get a list of link-layer header types supported by a capture device, and free that list @@ -40,18 +38,29 @@ is used to get a list of the supported link-layer header types of the interface associated with the pcap descriptor. .B pcap_list_datalinks() allocates an array to hold the list and sets -.IR *dlt_buf +.IR *dlt_buf to point to that array. .LP The caller is responsible for freeing the array with .BR pcap_free_datalinks() , which frees the list of link-layer header types pointed to by .IR dlt_list . +.LP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . .SH RETURN VALUE .B pcap_list_datalinks() -returns the number of link-layer header types in the array on success -and \-1 on failure. -If \-1 is returned, +returns the number of link-layer header types in the array on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +and +.B PCAP_ERROR +(\-1) on other errors. +If +.B PCAP_ERROR +is returned, .B pcap_geterr() or .B pcap_perror() diff --git a/contrib/libpcap/pcap_list_tstamp_types.3pcap.in b/contrib/libpcap/pcap_list_tstamp_types.3pcap.in index 66d3d66793..a139324f31 100644 --- a/contrib/libpcap/pcap_list_tstamp_types.3pcap.in +++ b/contrib/libpcap/pcap_list_tstamp_types.3pcap.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "21 August 2010" +.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2010" .SH NAME pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time stamp types supported by a capture device, and free that list diff --git a/contrib/libpcap/pcap_lookupdev.3pcap b/contrib/libpcap/pcap_lookupdev.3pcap index 8b23cb8704..aaa3a2013a 100644 --- a/contrib/libpcap/pcap_lookupdev.3pcap +++ b/contrib/libpcap/pcap_lookupdev.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_lookupdev.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOKUPDEV 3PCAP "5 April 2008" +.TH PCAP_LOOKUPDEV 3PCAP "3 January 2014" .SH NAME pcap_lookupdev \- find the default device on which to capture .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_lookupnet.3pcap b/contrib/libpcap/pcap_lookupnet.3pcap index 75c82cfc76..c38ff3a8e3 100644 --- a/contrib/libpcap/pcap_lookupnet.3pcap +++ b/contrib/libpcap/pcap_lookupnet.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_lookupnet.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOKUPNET 3PCAP "5 April 2008" +.TH PCAP_LOOKUPNET 3PCAP "3 January 2014" .SH NAME pcap_lookupnet \- find the IPv4 network number and netmask for a device .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_loop.3pcap b/contrib/libpcap/pcap_loop.3pcap index 7e0b582bac..0eaf6e5e59 100644 --- a/contrib/libpcap/pcap_loop.3pcap +++ b/contrib/libpcap/pcap_loop.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_loop.3pcap,v 1.4 2008-12-25 02:01:32 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOP 3PCAP "24 December 2008" +.TH PCAP_LOOP 3PCAP "18 October 2014" .SH NAME pcap_loop, pcap_dispatch \- process packets from a live capture or savefile .SH SYNOPSIS @@ -79,6 +77,13 @@ causes all the packets received in one buffer to be processed when reading a live capture, and causes all the packets in the file to be processed when reading a ``savefile''. .PP +Note that, when doing a live capture on some platforms, if the read +timeout expires when there are no packets available, +.B pcap_dispatch() +will return 0, even when not in non-blocking mode, as there are no +packets to process. Applications should be prepared for this to happen, +but must not rely on it happening. +.PP .ft B (In older versions of libpcap, the behavior when \fIcnt\fP @@ -115,6 +120,41 @@ and the packet data are not to be freed by the callback routine, and are not guaranteed to be valid after the callback routine returns; if the code needs them to be valid after the callback, it must make a copy of them. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.B pcap_datalink() +routine when handed the +.B pcap_t +value also passed to +.B pcap_loop() +or +.BR pcap_dispatch() . +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.B pcap_set_datalink() +is called; after a successful call to +.BR pcap_set_datalink() , +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink() . +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. .SH RETURN VALUE .B pcap_loop() returns 0 if @@ -155,4 +195,5 @@ may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), pcap_breakloop(3PCAP) +pcap(3PCAP), pcap_geterr(3PCAP), pcap_breakloop(3PCAP), +pcap_datalink(3PCAP) diff --git a/contrib/libpcap/pcap_major_version.3pcap b/contrib/libpcap/pcap_major_version.3pcap index 31903dcfd0..8334e16c34 100644 --- a/contrib/libpcap/pcap_major_version.3pcap +++ b/contrib/libpcap/pcap_major_version.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_major_version.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_MAJOR_VERSION 3PCAP "5 April 2008" +.TH PCAP_MAJOR_VERSION 3PCAP "7 April 2014" .SH NAME pcap_major_version, pcap_minor_version \- get the version number of a savefile .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_next_ex.3pcap b/contrib/libpcap/pcap_next_ex.3pcap index 737383604b..d69e7283d8 100644 --- a/contrib/libpcap/pcap_next_ex.3pcap +++ b/contrib/libpcap/pcap_next_ex.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_next_ex.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_NEXT_EX 3PCAP "5 April 2008" +.TH PCAP_NEXT_EX 3PCAP "7 April 2014" .SH NAME pcap_next_ex, pcap_next \- read the next packet from a pcap_t .SH SYNOPSIS @@ -77,12 +75,47 @@ The structure pointed to by .I h is filled in with the appropriate values for the packet. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.B pcap_datalink() +routine when handed the +.B pcap_t +value also passed to +.B pcap_loop() +or +.BR pcap_dispatch() . +.I http://www.tcpdump.org/linktypes.html +lists the values +.B pcap_datalink() +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.B pcap_set_datalink() +is called; after a successful call to +.BR pcap_set_datalink() , +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink() . +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. .SH RETURN VALUE .B pcap_next_ex() returns 1 if the packet was read without problems, 0 -if packets are being read from a live capture, and the timeout expired, +if packets are being read from a live capture and the timeout expired, \-1 if an error occurred while reading the packet, and \-2 if -packets are being read from a ``savefile'', and there are no more +packets are being read from a ``savefile'' and there are no more packets to read from the savefile. If \-1 is returned, .B pcap_geterr() @@ -104,4 +137,5 @@ non-blocking mode and no packets were available to be read), or if no more packets are available in a ``savefile.'' Unfortunately, there is no way to determine whether an error occurred or not. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), pcap_dispatch(3PCAP) +pcap(3PCAP), pcap_geterr(3PCAP), pcap_dispatch(3PCAP), +pcap_datalink(3PCAP) diff --git a/contrib/libpcap/pcap_offline_filter.3pcap b/contrib/libpcap/pcap_offline_filter.3pcap index 3f11022d5a..08c0b66b33 100644 --- a/contrib/libpcap/pcap_offline_filter.3pcap +++ b/contrib/libpcap/pcap_offline_filter.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_offline_filter.3pcap,v 1.1 2008-05-13 15:19:56 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OFFLINE_FILTER 3PCAP "13 May 2008" +.TH PCAP_OFFLINE_FILTER 3PCAP "7 April 2014" .SH NAME pcap_offline_filter \- check whether a filter matches a packet .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_open_dead.3pcap.in b/contrib/libpcap/pcap_open_dead.3pcap.in index 00df786680..a3dc592107 100644 --- a/contrib/libpcap/pcap_open_dead.3pcap.in +++ b/contrib/libpcap/pcap_open_dead.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_open_dead.3pcap.in,v 1.1 2008-10-21 07:33:02 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,10 +17,10 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OPEN_DEAD 3PCAP "5 April 2008" +.TH PCAP_OPEN_DEAD 3PCAP "3 January 2014" .SH NAME -pcap_open_dead \- open a fake pcap_t for compiling filters or opening a -capture for output +pcap_open_dead, pcap_open_dead_with_tstamp_precision \- open a fake +pcap_t for compiling filters or opening a capture for output .SH SYNOPSIS .nf .ft B @@ -31,15 +29,27 @@ capture for output .LP .ft B pcap_t *pcap_open_dead(int linktype, int snaplen); +pcap_t *pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, + u_int precision); .ft .fi .SH DESCRIPTION .PP .B pcap_open_dead() -is used for creating a +and +.B pcap_open_dead_with_tstamp_precision() +are used for creating a .B pcap_t structure to use when calling the other functions in libpcap. It is -typically used when just using libpcap for compiling BPF code. +typically used when just using libpcap for compiling BPF code; it can +also be used if using +.BR pcap_dump_open() , +.BR pcap_dump() , +and +.B pcap_dump_close() +to write a savefile if there is no +.B pcap_t +that supplies the packets to be written. .PP .I linktype specifies the link-layer type for the @@ -48,5 +58,22 @@ specifies the link-layer type for the .I snaplen specifies the snapshot length for the .BR pcap_t . +.PP +When +.BR pcap_open_dead_with_tstamp_precision() , +is used to create a +.B pcap_t +for use with +.BR pcap_dump_open() , +.I precision +specifies the time stamp precision for packets; +.B PCAP_TSTAMP_PRECISION_MICRO +should be specified if the packets to be written have time stamps in +seconds and microseconds, and +.B PCAP_TSTAMP_PRECISION_NANO +should be specified if the packets to be written have time stamps in +seconds and nanoseconds. Its value does not affect +.BR pcap_compile() . .SH SEE ALSO -pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) +pcap(3PCAP), pcap_compile(3PCAP), pcap_dump_open(3PCAP), +pcap-linktype(@MAN_MISC_INFO@) diff --git a/contrib/libpcap/pcap_open_live.3pcap b/contrib/libpcap/pcap_open_live.3pcap index 0889a2a258..8c5d47469b 100644 --- a/contrib/libpcap/pcap_open_live.3pcap +++ b/contrib/libpcap/pcap_open_live.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_open_live.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OPEN_LIVE 3PCAP "5 April 2008" +.TH PCAP_OPEN_LIVE 3PCAP "3 January 2014" .SH NAME pcap_open_live \- open a device for capturing .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_open_offline.3pcap.in b/contrib/libpcap/pcap_open_offline.3pcap.in index 3f9f5a2711..7fe551eefa 100644 --- a/contrib/libpcap/pcap_open_offline.3pcap.in +++ b/contrib/libpcap/pcap_open_offline.3pcap.in @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_open_offline.3pcap.in,v 1.1 2008-10-23 05:56:59 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,9 +17,10 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OPEN_OFFLINE 3PCAP "5 April 2008" +.TH PCAP_OPEN_OFFLINE 3PCAP "3 January 2014" .SH NAME -pcap_open_offline, pcap_fopen_offline \- open a saved capture file for reading +pcap_open_offline, pcap_open_offline_with_tstamp_precision, +pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading .SH SYNOPSIS .nf .ft B @@ -35,12 +34,18 @@ char errbuf[PCAP_ERRBUF_SIZE]; .LP .ft B pcap_t *pcap_open_offline(const char *fname, char *errbuf); +pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, + u_int precision, char *errbuf); pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf); +pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, + u_int precision, char *errbuf); .ft .fi .SH DESCRIPTION .B pcap_open_offline() -is called to open a ``savefile'' for reading. +and +.B pcap_open_offline_with_tstamp_precision() +are called to open a ``savefile'' for reading. .PP .I fname specifies the name of the file to open. The file can have the pcap file @@ -52,18 +57,40 @@ and .BR tcpslice (1), or can have the pcap-ng file format, although not all pcap-ng files can be read. -The name "-" in a synonym for +The name "-" is a synonym for .BR stdin . .PP +.B pcap_open_offline_with_tstamp_precision() +takes an additional +.I precision +argument specifying the time stamp precision desired; +if +.B PCAP_TSTAMP_PRECISION_MICRO +is specified, packet time stamps will be supplied in seconds and +microseconds, +and if +.B PCAP_TSTAMP_PRECISION_NANO +is specified, packet time stamps will be supplied in seconds and +nanoseconds. If the time stamps in the file do not have the same +precision as the requested precision, they will be scaled up or down as +necessary before being supplied. +.PP Alternatively, you may call .B pcap_fopen_offline() +or +.B pcap_fopen_offline_with_tstamp_precision() to read dumped data from an existing open stream .IR fp . +.B pcap_fopen_offline_with_tstamp_precision() takes an additional +.I precision +argument as described above. Note that on Windows, that stream should be opened in binary mode. .SH RETURN VALUE -.B pcap_open_offline() +.BR pcap_open_offline() , +.BR pcap_open_offline_with_tstamp_precision() , +.BR pcap_fopen_offline() , and -.B pcap_fopen_offline() +.B pcap_fopen_offline_with_tstamp_precision() return a .I pcap_t * on success and diff --git a/contrib/libpcap/pcap_set_buffer_size.3pcap b/contrib/libpcap/pcap_set_buffer_size.3pcap index 060e923e8c..684f739cc6 100644 --- a/contrib/libpcap/pcap_set_buffer_size.3pcap +++ b/contrib/libpcap/pcap_set_buffer_size.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_buffer_size.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_BUFFER_SIZE 3PCAP "5 April 2008" +.TH PCAP_SET_BUFFER_SIZE 3PCAP "3 January 2014" .SH NAME pcap_set_buffer_size \- set the buffer size for a not-yet-activated capture handle diff --git a/contrib/libpcap/pcap_set_datalink.3pcap b/contrib/libpcap/pcap_set_datalink.3pcap index 9af32d0696..24d57a541c 100644 --- a/contrib/libpcap/pcap_set_datalink.3pcap +++ b/contrib/libpcap/pcap_set_datalink.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_datalink.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_DATALINK 3PCAP "22 August 2010" +.TH PCAP_SET_DATALINK 3PCAP "3 January 2014" .SH NAME pcap_set_datalink \- set the link-layer header type to be used by a capture device diff --git a/contrib/libpcap/pcap_set_snaplen.3pcap b/contrib/libpcap/pcap_set_immediate_mode.3pcap similarity index 76% copy from contrib/libpcap/pcap_set_snaplen.3pcap copy to contrib/libpcap/pcap_set_immediate_mode.3pcap index 74195d9367..b3ad243151 100644 --- a/contrib/libpcap/pcap_set_snaplen.3pcap +++ b/contrib/libpcap/pcap_set_immediate_mode.3pcap @@ -1,4 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_snaplen.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ .\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. @@ -19,26 +18,28 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_SNAPLEN 3PCAP "5 April 2008" +.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "5 December 2013" .SH NAME -pcap_set_snaplen \- set the snapshot length for a not-yet-activated -capture handle +pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture +handle .SH SYNOPSIS .nf .ft B #include .LP .ft B -int pcap_set_snaplen(pcap_t *p, int snaplen); +int pcap_set_immediate_mode(pcap_t *p, int immediate_mode); .ft .fi .SH DESCRIPTION -.B pcap_set_snaplen() -sets the snapshot length to be used on a capture handle when the handle -is activated to -.IR snaplen . +.B pcap_set_immediate_mode() +sets whether immediate mode should be set on a capture handle when +the handle is activated. +If +.I immediate_mode +is non-zero, immediate mode will be set, otherwise it will not be set. .SH RETURN VALUE -.B pcap_set_snaplen() +.B pcap_set_immediate_mode() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. diff --git a/contrib/libpcap/pcap_set_promisc.3pcap b/contrib/libpcap/pcap_set_promisc.3pcap index 382260c743..fcd797a34c 100644 --- a/contrib/libpcap/pcap_set_promisc.3pcap +++ b/contrib/libpcap/pcap_set_promisc.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_promisc.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_PROMISC 3PCAP "5 April 2008" +.TH PCAP_SET_PROMISC 3PCAP "3 January 2014" .SH NAME pcap_set_promisc \- set promiscuous mode for a not-yet-activated capture handle diff --git a/contrib/libpcap/pcap_set_rfmon.3pcap b/contrib/libpcap/pcap_set_rfmon.3pcap index ee73556862..691518a5b2 100644 --- a/contrib/libpcap/pcap_set_rfmon.3pcap +++ b/contrib/libpcap/pcap_set_rfmon.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_rfmon.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_RFMON 3PCAP "5 April 2008" +.TH PCAP_SET_RFMON 3PCAP "3 January 2014" .SH NAME pcap_set_rfmon \- set monitor mode for a not-yet-activated capture handle diff --git a/contrib/libpcap/pcap_set_snaplen.3pcap b/contrib/libpcap/pcap_set_snaplen.3pcap index 74195d9367..44eb15488a 100644 --- a/contrib/libpcap/pcap_set_snaplen.3pcap +++ b/contrib/libpcap/pcap_set_snaplen.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_snaplen.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_SNAPLEN 3PCAP "5 April 2008" +.TH PCAP_SET_SNAPLEN 3PCAP "3 January 2014" .SH NAME pcap_set_snaplen \- set the snapshot length for a not-yet-activated capture handle diff --git a/contrib/libpcap/pcap_set_timeout.3pcap b/contrib/libpcap/pcap_set_timeout.3pcap index c361b7da62..a89327f2eb 100644 --- a/contrib/libpcap/pcap_set_timeout.3pcap +++ b/contrib/libpcap/pcap_set_timeout.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_set_timeout.3pcap,v 1.1 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_TIMEOUT 3PCAP "5 April 2008" +.TH PCAP_SET_TIMEOUT 3PCAP "1 December 2015" .SH NAME pcap_set_timeout \- set the read timeout for a not-yet-activated capture handle @@ -38,10 +36,15 @@ sets the read timeout that will be used on a capture handle when the handle is activated to .IR to_ms , which is in units of milliseconds. +.LP +The behavior, if the timeout isn't specified, is undefined. We +recommend always setting the timeout to a non-zero value unless +immediate mode is set, in which case the timeout has no effect. .SH RETURN VALUE .B pcap_set_timeout() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_set_immediate_mode(3PCAP) diff --git a/contrib/libpcap/pcap_set_tstamp_precision.3pcap.in b/contrib/libpcap/pcap_set_tstamp_precision.3pcap.in new file mode 100644 index 0000000000..57c4ea301c --- /dev/null +++ b/contrib/libpcap/pcap_set_tstamp_precision.3pcap.in @@ -0,0 +1,61 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"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 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. + +.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "5 February 2015" +.SH NAME +pcap_set_tstamp_precision \- set the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision); +.ft +.fi +.SH DESCRIPTION +.B pcap_set_tstamp_precision() +sets the precision of the time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_precision . +It must be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +Two time stamp precisions are supported, microseconds and nanoseconds. One can +use options +.B PCAP_TSTAMP_PRECISION_MICRO and +.B PCAP_TSTAMP_PRECISION_NANO +to request desired precision. By default, time stamps are in microseconds. +.SH RETURN VALUE +.B pcap_set_tstamp_precision() +returns 0 on success if the specified time stamp precision is expected to be +supported by the operating system, +.B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP +if operating system does not support requested time stamp precision, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +pcap(3PCAP), +pcap_get_tstamp_precision(3PCAP), +pcap-tstamp(@MAN_MISC_INFO@) diff --git a/contrib/libpcap/pcap_set_tstamp_type.3pcap.in b/contrib/libpcap/pcap_set_tstamp_type.3pcap.in index 261c315200..e58cdd4b0d 100644 --- a/contrib/libpcap/pcap_set_tstamp_type.3pcap.in +++ b/contrib/libpcap/pcap_set_tstamp_type.3pcap.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_TSTAMP_TYPE 3PCAP "21 August 2010" +.TH PCAP_SET_TSTAMP_TYPE 3PCAP "5 December 2014" .SH NAME pcap_set_tstamp_type \- set the time stamp type to be used by a capture device @@ -52,7 +52,7 @@ for a list of all the time stamp types. returns 0 on success if the specified time stamp type is expected to be supported by the capture device, .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP -on success if the specified time stamp type is not supported by the +if the specified time stamp type is not supported by the capture device, .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated, and diff --git a/contrib/libpcap/pcap_setdirection.3pcap b/contrib/libpcap/pcap_setdirection.3pcap index bd0fb253e5..11945f5421 100644 --- a/contrib/libpcap/pcap_setdirection.3pcap +++ b/contrib/libpcap/pcap_setdirection.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_setdirection.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETDIRECTION 3PCAP "5 April 2008" +.TH PCAP_SETDIRECTION 3PCAP "8 March 2015" .SH NAME pcap_setdirection \- set the direction for which packets will be captured .SH SYNOPSIS @@ -39,7 +37,7 @@ is used to specify a direction that packets will be captured. is one of the constants .BR PCAP_D_IN , .B PCAP_D_OUT -or +or .BR PCAP_D_INOUT . .B PCAP_D_IN will only capture packets received by the device, diff --git a/contrib/libpcap/pcap_setfilter.3pcap b/contrib/libpcap/pcap_setfilter.3pcap index 89d5da7f7d..6efd253982 100644 --- a/contrib/libpcap/pcap_setfilter.3pcap +++ b/contrib/libpcap/pcap_setfilter.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_setfilter.3pcap,v 1.4 2008-05-13 15:19:56 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETFILTER 3PCAP "5 April 2008" +.TH PCAP_SETFILTER 3PCAP "7 April 2014" .SH NAME pcap_setfilter \- set the filter .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_setnonblock.3pcap b/contrib/libpcap/pcap_setnonblock.3pcap index b00fce100c..695912701f 100644 --- a/contrib/libpcap/pcap_setnonblock.3pcap +++ b/contrib/libpcap/pcap_setnonblock.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_setnonblock.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETNONBLOCK 3PCAP "5 April 2008" +.TH PCAP_SETNONBLOCK 3PCAP "18 October 2014" .SH NAME pcap_setnonblock, pcap_getnonblock \- set or get the state of non-blocking mode on a capture device @@ -59,6 +57,14 @@ immediately rather than blocking waiting for packets to arrive. and .B pcap_next() will not work in ``non-blocking'' mode. +.PP +When first activated with +.B pcap_activate() +or opened with +.B pcap_open_live() , +a capture handle is not in ``non-blocking mode''; a call to +.B pcap_setnonblock() +is required in order to put it into ``non-blocking'' mode. .SH RETURN VALUE .B pcap_getnonblock() returns the current ``non-blocking'' state of the capture descriptor; it diff --git a/contrib/libpcap/pcap_snapshot.3pcap b/contrib/libpcap/pcap_snapshot.3pcap index 3025312fb5..7af8c33dc4 100644 --- a/contrib/libpcap/pcap_snapshot.3pcap +++ b/contrib/libpcap/pcap_snapshot.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_snapshot.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SNAPSHOT 3PCAP "5 April 2008" +.TH PCAP_SNAPSHOT 3PCAP "7 April 2014" .SH NAME pcap_snapshot \- get the snapshot length .SH SYNOPSIS @@ -40,5 +38,15 @@ or .B pcap_open_live() was called, for a live capture, or the snapshot length from the capture file, for a ``savefile''. +.PP +It must not be called on a pcap descriptor created by +.B pcap_create() +that has not yet been activated by +.BR pcap_activate() . +.SH RETURN VALUE +.B pcap_snapshot() +returns the snapshot length on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. .SH SEE ALSO pcap(3PCAP) diff --git a/contrib/libpcap/pcap_stats.3pcap b/contrib/libpcap/pcap_stats.3pcap index a953e211d5..2dce4b501c 100644 --- a/contrib/libpcap/pcap_stats.3pcap +++ b/contrib/libpcap/pcap_stats.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_stats.3pcap,v 1.3 2008-04-06 02:53:22 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_STATS 3PCAP "7 September 2009" +.TH PCAP_STATS 3PCAP "3 January 2014" .SH NAME pcap_stats \- get capture statistics .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_statustostr.3pcap b/contrib/libpcap/pcap_statustostr.3pcap index da18f69122..9c2057ae4f 100644 --- a/contrib/libpcap/pcap_statustostr.3pcap +++ b/contrib/libpcap/pcap_statustostr.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_statustostr.3pcap,v 1.1 2008-04-09 21:39:21 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_STATUSTOSTR 3PCAP "9 April 2008" +.TH PCAP_STATUSTOSTR 3PCAP "3 January 2014" .SH NAME pcap_statustostr \- convert a PCAP_ERROR_ or PCAP_WARNING_ value to a string .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_strerror.3pcap b/contrib/libpcap/pcap_strerror.3pcap index 8e6319bbfa..7c7d53f5a9 100644 --- a/contrib/libpcap/pcap_strerror.3pcap +++ b/contrib/libpcap/pcap_strerror.3pcap @@ -1,5 +1,3 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/pcap_strerror.3pcap,v 1.2 2008-04-05 20:26:56 guy Exp $ -.\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. .\" @@ -19,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_STRERROR 3PCAP "4 April 2008" +.TH PCAP_STRERROR 3PCAP "3 January 2014" .SH NAME pcap_strerror \- convert an errno value to a string .SH SYNOPSIS diff --git a/contrib/libpcap/pcap_tstamp_type_name_to_val.3pcap b/contrib/libpcap/pcap_tstamp_type_name_to_val.3pcap index 8fcc4d75c0..ac2e35dd76 100644 --- a/contrib/libpcap/pcap_tstamp_type_name_to_val.3pcap +++ b/contrib/libpcap/pcap_tstamp_type_name_to_val.3pcap @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "21 August 2010" +.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "5 December 2014" .SH NAME pcap_tstamp_type_name_to_val \- get the time stamp type value corresponding to a time stamp type name @@ -38,7 +38,7 @@ translates a time stamp type name to the corresponding time stamp type value. The translation is case-insensitive. .SH RETURN VALUE .B pcap_tstamp_type_name_to_val() -returns 0 on success and +returns time stamp type value on success and .B PCAP_ERROR on failure. .SH SEE ALSO diff --git a/contrib/libpcap/pcap_tstamp_type_val_to_name.3pcap b/contrib/libpcap/pcap_tstamp_type_val_to_name.3pcap index 5d8d75405c..261554ec79 100644 --- a/contrib/libpcap/pcap_tstamp_type_val_to_name.3pcap +++ b/contrib/libpcap/pcap_tstamp_type_val_to_name.3pcap @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "21 August 2010" +.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "12 December 2013" .SH NAME pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get a name or description for a time stamp type value @@ -36,10 +36,14 @@ const char *pcap_tstamp_type_val_to_description(int tstamp_type); .SH DESCRIPTION .B pcap_tstamp_type_val_to_name() translates a time stamp type value to the corresponding time stamp type -name. NULL is returned on failure. +name. +.B NULL +is returned on failure. .PP .B pcap_tstamp_type_val_to_description() translates a time stamp type value to a short description of that time -stamp type. NULL is returned on failure. +stamp type. +.B NULL +is returned on failure. .SH SEE ALSO pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP) diff --git a/contrib/libpcap/portability.h b/contrib/libpcap/portability.h new file mode 100644 index 0000000000..8a6bf40e8b --- /dev/null +++ b/contrib/libpcap/portability.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 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 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. + */ + +#ifndef portability_h +#define portability_h + +/* + * Helpers for portability between Windows and UN*X and between different + * flavors of UN*X. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_STRLCPY + /* + * Macro that does the same thing as strlcpy(). + */ + #ifdef _MSC_VER + /* + * strncpy_s() is supported at least back to Visual + * Studio 2005. + */ + #define strlcpy(x, y, z) \ + strncpy_s((x), (z), (y), _TRUNCATE) + + #else + #define strlcpy(x, y, z) \ + (strncpy((x), (y), (z)), \ + ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ + (void) strlen((y))) + #endif +#endif + +/* + * For flagging arguments as format strings in MSVC. + */ +#if _MSC_VER >= 1400 + #include + #if _MSC_VER > 1400 + #define FORMAT_STRING(p) _Printf_format_string_ p + #else + #define FORMAT_STRING(p) __format_string p + #endif +#else + #define FORMAT_STRING(p) p +#endif + +#ifdef _MSC_VER + #define strdup _strdup + #define sscanf sscanf_s + #define setbuf(x, y) \ + setvbuf((x), (y), _IONBF, 0) + #define fopen(x, y) \ + fopen_safe((x), (y)) + FILE *fopen_safe(const char *filename, const char* mode); +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) + #define strlcat(x, y, z) \ + strncat_s((x), (z), (y), _TRUNCATE) +#endif + +#ifdef _MSC_VER + /* + * MSVC. + */ + #if _MSC_VER >= 1900 + /* + * VS 2015 or newer; we have snprintf() function. + */ + #define HAVE_SNPRINTF + #endif +#endif + +/* + * On Windows, snprintf(), with that name and with C99 behavior - i.e., + * guaranteeing that the formatted string is null-terminated - didn't + * appear until Visual Studio 2015. Prior to that, the C runtime had + * only _snprintf(), which *doesn't* guarantee that the string is + * null-terminated if it is truncated due to the buffer being too + * small. We therefore can't just define snprintf to be _snprintf + * and define vsnprintf to be _vsnprintf, as we're relying on null- + * termination of strings in all cases. + * + * We also want to allow this to be built with versions of Visual Studio + * prior to VS 2015, so we can't rely on snprintf() being present. + * + * And we want to make sure that, if we support plugins in the future, + * a routine with C99 snprintf() behavior will be available to them. + * We also don't want it to collide with the C library snprintf() if + * there is one. + * + * So we make pcap_snprintf() and pcap_vsnprintf() available, either by + * #defining them to be snprintf or vsnprintf, respectively, or by + * defining our own versions and exporting them. + */ +#ifdef HAVE_SNPRINTF +#define pcap_snprintf snprintf +#else +extern int pcap_snprintf(char *, size_t, FORMAT_STRING(const char *), ...) +#ifdef __ATTRIBUTE___FORMAT_OK + __attribute__((format (printf, 3, 4))) +#endif /* __ATTRIBUTE___FORMAT_OK */ + ; +#endif + +#ifdef HAVE_VSNPRINTF +#define pcap_vsnprintf vsnprintf +#else +extern int pcap_vsnprintf(char *, size_t, const char *, va_list ap); +#endif + +#ifdef HAVE_STRTOK_R + #define pcap_strtok_r strtok_r +#else + #ifdef _MSC_VER + /* + * Microsoft gives it a different name. + */ + #define pcap_strtok_r strtok_s + #else + /* + * Define it ourselves. + */ + #define NEED_STRTOK_R + extern int pcap_strtok_r(char *, const char *, char **); + #endif +#endif /* HAVE_STRTOK_R */ + +#ifdef _WIN32 + /* + * These may be defined by . + * + * XXX - for MSVC, we always want the _MSC_EXTENSIONS versions. + * What about other compilers? If, as the MinGW Web site says MinGW + * does, the other compilers just use Microsoft's run-time library, + * then they should probably use the _MSC_EXTENSIONS even if the + * compiler doesn't define _MSC_EXTENSIONS. + * + * XXX - we currently aren't using any of these, but this allows + * their use in the future. + */ + #ifndef PRId64 + #ifdef _MSC_EXTENSIONS + #define PRId64 "I64d" + #else + #define PRId64 "lld" + #endif + #endif /* PRId64 */ + + #ifndef PRIo64 + #ifdef _MSC_EXTENSIONS + #define PRIo64 "I64o" + #else + #define PRIo64 "llo" + #endif + #endif /* PRIo64 */ + + #ifndef PRIx64 + #ifdef _MSC_EXTENSIONS + #define PRIx64 "I64x" + #else + #define PRIx64 "llx" + #endif + #endif + + #ifndef PRIu64 + #ifdef _MSC_EXTENSIONS + #define PRIu64 "I64u" + #else + #define PRIu64 "llu" + #endif + #endif + + #if !defined(__cplusplus) + #define inline __inline + #endif +#endif /* _WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libpcap/ppp.h b/contrib/libpcap/ppp.h index 4e1d08de1c..d6e70c151d 100644 --- a/contrib/libpcap/ppp.h +++ b/contrib/libpcap/ppp.h @@ -1,4 +1,3 @@ -/* @(#) $Header: /tcpdump/master/libpcap/ppp.h,v 1.12 2005-02-08 19:52:19 guy Exp $ (LBL) */ /* * Point to Point Protocol (PPP) RFC1331 * diff --git a/contrib/libpcap/savefile.c b/contrib/libpcap/savefile.c index 8115749b13..247338c5b8 100644 --- a/contrib/libpcap/savefile.c +++ b/contrib/libpcap/savefile.c @@ -28,18 +28,13 @@ * dependent values so we can print the dump file on any architecture. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp $ (LBL)"; -#endif - #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -49,7 +44,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -58,7 +53,6 @@ static const char rcsid[] _U_ = #include #include "pcap-int.h" -#include "pcap/usb.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -67,10 +61,27 @@ static const char rcsid[] _U_ = #include "sf-pcap.h" #include "sf-pcap-ng.h" +#ifdef _WIN32 +/* + * These aren't exported on Windows, because they would only work if both + * WinPcap and the code using it were to use the Universal CRT; otherwise, + * a FILE structure in WinPcap and a FILE structure in the code using it + * could be different if they're using different versions of the C runtime. + * + * Instead, pcap/pcap.h defines them as macros that wrap the hopen versions, + * with the wrappers calling _fileno() and _get_osfhandle() themselves, + * so that they convert the appropriate CRT version's FILE structure to + * a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32 + * and Win64 ABIs). + */ +static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif + /* * Setting O_BINARY on DOS/Windows is a bit tricky */ -#if defined(WIN32) +#if defined(_WIN32) #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #elif defined(MSDOS) #if defined(__HIGHC__) @@ -101,7 +112,7 @@ sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) * as it would have to handle reading partial packets and * keeping the state of the read.) */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Savefiles cannot be put into non-blocking mode"); return (-1); } @@ -109,16 +120,24 @@ sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) static int sf_stats(pcap_t *p, struct pcap_stat *ps) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Statistics aren't available from savefiles"); return (-1); } -#ifdef WIN32 +#ifdef _WIN32 +static struct pcap_stat * +sf_stats_ex(pcap_t *p, int *size) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from savefiles"); + return (NULL); +} + static int sf_setbuff(pcap_t *p, int dim) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file"); return (-1); } @@ -126,7 +145,7 @@ sf_setbuff(pcap_t *p, int dim) static int sf_setmode(pcap_t *p, int mode) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file"); return (-1); } @@ -134,10 +153,74 @@ sf_setmode(pcap_t *p, int mode) static int sf_setmintocopy(pcap_t *p, int size) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The mintocopy parameter cannot be set while reading from a file"); return (-1); } + +static HANDLE +sf_getevent(pcap_t *pcap) +{ + (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "The read event cannot be retrieved while reading from a file"); + return (INVALID_HANDLE_VALUE); +} + +static int +sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, + size_t *lenp _U_) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID get request cannot be performed on a file"); + return (PCAP_ERROR); +} + +static int +sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID set request cannot be performed on a file"); + return (PCAP_ERROR); +} + +static u_int +sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) +{ + strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + PCAP_ERRBUF_SIZE); + return (0); +} + +static int +sf_setuserbuffer(pcap_t *p, int size) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The user buffer cannot be set when reading from a file"); + return (-1); +} + +static int +sf_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed when reading from a file"); + return (-1); +} + +static int +sf_live_dump_ended(pcap_t *p, int sync) +{ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +static PAirpcapHandle +sf_get_airpcap_handle(pcap_t *pcap) +{ + return (NULL); +} #endif static int @@ -155,31 +238,53 @@ sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) static int sf_setdirection(pcap_t *p, pcap_direction_t d) { - snprintf(p->errbuf, sizeof(p->errbuf), + pcap_snprintf(p->errbuf, sizeof(p->errbuf), "Setting direction is not supported on savefiles"); return (-1); } -static void +void sf_cleanup(pcap_t *p) { - if (p->sf.rfile != stdin) - (void)fclose(p->sf.rfile); + if (p->rfile != stdin) + (void)fclose(p->rfile); if (p->buffer != NULL) free(p->buffer); pcap_freecode(&p->fcode); } +/* +* fopen's safe version on Windows. +*/ +#ifdef _MSC_VER +FILE *fopen_safe(const char *filename, const char* mode) +{ + FILE *fp = NULL; + errno_t errno; + errno = fopen_s(&fp, filename, mode); + if (errno == 0) + return fp; + else + return NULL; +} +#endif + pcap_t * -pcap_open_offline(const char *fname, char *errbuf) +pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, + char *errbuf) { FILE *fp; pcap_t *p; + if (fname == NULL) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return (NULL); + } if (fname[0] == '-' && fname[1] == '\0') { fp = stdin; -#if defined(WIN32) || defined(MSDOS) +#if defined(_WIN32) || defined(MSDOS) /* * We're reading from the standard input, so put it in binary * mode, as savefiles are binary files. @@ -188,18 +293,18 @@ pcap_open_offline(const char *fname, char *errbuf) #endif } else { -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) fp = fopen(fname, "r"); #else fp = fopen(fname, "rb"); #endif if (fp == NULL) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } } - p = pcap_fopen_offline(fp, errbuf); + p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf); if (p == NULL) { if (fp != stdin) fclose(fp); @@ -207,51 +312,64 @@ pcap_open_offline(const char *fname, char *errbuf) return (p); } -#ifdef WIN32 -pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) +pcap_t * +pcap_open_offline(const char *fname, char *errbuf) +{ + return (pcap_open_offline_with_tstamp_precision(fname, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); +} + +#ifdef _WIN32 +pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, + char *errbuf) { int fd; FILE *file; fd = _open_osfhandle(osfd, _O_RDONLY); - if ( fd < 0 ) + if ( fd < 0 ) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); return NULL; } file = _fdopen(fd, "rb"); - if ( file == NULL ) + if ( file == NULL ) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); return NULL; } - return pcap_fopen_offline(file, errbuf); + return pcap_fopen_offline_with_tstamp_precision(file, precision, + errbuf); +} + +pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) +{ + return pcap_hopen_offline_with_tstamp_precision(osfd, + PCAP_TSTAMP_PRECISION_MICRO, errbuf); } #endif -static int (*check_headers[])(pcap_t *, bpf_u_int32, FILE *, char *) = { +static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = { pcap_check_header, pcap_ng_check_header }; #define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) -#ifdef WIN32 +#ifdef _WIN32 static #endif pcap_t * -pcap_fopen_offline(FILE *fp, char *errbuf) +pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, + char *errbuf) { register pcap_t *p; bpf_u_int32 magic; size_t amt_read; u_int i; - - p = pcap_create_common("(savefile)", errbuf); - if (p == NULL) - return (NULL); + int err; /* * Read the first 4 bytes of the file; the network analyzer dump @@ -263,53 +381,48 @@ pcap_fopen_offline(FILE *fp, char *errbuf) amt_read = fread((char *)&magic, 1, sizeof(magic), fp); if (amt_read != sizeof(magic)) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu file header bytes, only got %lu", (unsigned long)sizeof(magic), (unsigned long)amt_read); } - goto bad; + return (NULL); } /* * Try all file types. */ for (i = 0; i < N_FILE_TYPES; i++) { - switch ((*check_headers[i])(p, magic, fp, errbuf)) { - - case -1: + p = (*check_headers[i])(magic, fp, precision, errbuf, &err); + if (p != NULL) { + /* Yup, that's it. */ + goto found; + } + if (err) { /* * Error trying to read the header. */ - goto bad; - - case 1: - /* - * Yup, that's it. - */ - goto found; + return (NULL); } } /* * Well, who knows what this mess is.... */ - snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); - goto bad; + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); + return (NULL); found: - p->sf.rfile = fp; + p->rfile = fp; -#ifdef PCAP_FDDIPAD /* Padding only needed for live capture fcode */ p->fddipad = 0; -#endif -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) /* * You can do "select()" and "poll()" on plain files on most * platforms, and should be able to do so on pipes. @@ -328,18 +441,45 @@ found: p->getnonblock_op = sf_getnonblock; p->setnonblock_op = sf_setnonblock; p->stats_op = sf_stats; -#ifdef WIN32 +#ifdef _WIN32 + p->stats_ex_op = sf_stats_ex; p->setbuff_op = sf_setbuff; p->setmode_op = sf_setmode; p->setmintocopy_op = sf_setmintocopy; + p->getevent_op = sf_getevent; + p->oid_get_request_op = sf_oid_get_request; + p->oid_set_request_op = sf_oid_set_request; + p->sendqueue_transmit_op = sf_sendqueue_transmit; + p->setuserbuffer_op = sf_setuserbuffer; + p->live_dump_op = sf_live_dump; + p->live_dump_ended_op = sf_live_dump_ended; + p->get_airpcap_handle_op = sf_get_airpcap_handle; #endif - p->cleanup_op = sf_cleanup; + + /* + * For offline captures, the standard one-shot callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcap_oneshot; + + /* + * Savefiles never require special BPF code generation. + */ + p->bpf_codegen_flags = 0; + p->activated = 1; return (p); - bad: - free(p); - return (NULL); +} + +#ifdef _WIN32 +static +#endif +pcap_t * +pcap_fopen_offline(FILE *fp, char *errbuf) +{ + return (pcap_fopen_offline_with_tstamp_precision(fp, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); } /* @@ -375,7 +515,7 @@ pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) return (n); } - status = p->sf.next_packet_op(p, &h, &data); + status = p->next_packet_op(p, &h, &data); if (status) { if (status == 1) return (0); diff --git a/contrib/libpcap/scanner.l b/contrib/libpcap/scanner.l index 10ffbcd567..1000b7a3c9 100644 --- a/contrib/libpcap/scanner.l +++ b/contrib/libpcap/scanner.l @@ -1,3 +1,46 @@ +%top { +/* Must come first for _LARGE_FILE_API on AIX. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +} + +/* + * We want a reentrant scanner. + */ +%option reentrant + +/* + * And we need to pass the compiler state to the scanner. + */ +%option extra-type="compiler_state_t *" + +/* + * We don't use input, so don't generate code for it. + */ +%option noinput + +/* + * We don't use unput, so don't generate code for it. + */ +%option nounput + +/* + * We don't read from the terminal. + */ +%option never-interactive + +/* + * We want to stop processing when we get to the end of the input. + */ +%option noyywrap + +/* + * We want to generate code that can be used by a reentrant parser + * generated by Bison or Berkeley YACC. + */ +%option bison-bridge + %{ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 @@ -20,28 +63,19 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/scanner.l,v 1.112 2008-02-06 10:21:30 guy Exp $ (LBL)"; -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#include -#else /* WIN32 */ -#if HAVE_INTTYPES_H -#include -#elif HAVE_STDINT_H -#include -#endif -#ifdef HAVE_SYS_BITYPES_H -#include +#ifdef _WIN32 + #include +#else + #if HAVE_INTTYPES_H + #include + #elif HAVE_STDINT_H + #include + #endif + #ifdef HAVE_SYS_BITYPES_H + #include + #endif + #include #endif -#include -#endif /* WIN32 */ #include #include @@ -49,25 +83,56 @@ static const char rcsid[] _U_ = #include "pcap-int.h" #include "gencode.h" + +#include "grammar.h" + +/* + * Earlier versions of Flex don't declare these, so we declare them + * ourselves to squelch warnings. + */ +int pcap_get_column(yyscan_t); +void pcap_set_column(int, yyscan_t); + #ifdef INET6 -#ifdef WIN32 -#include -#ifdef __MINGW32__ -#include "ip6_misc.h" -#endif -#else /* WIN32 */ +#ifdef _WIN32 +/* + * 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. pcap-stdinc.h + * includes Ws2tcpip.h, so we don't need to include it ourselves. + */ +#include +#else /* _WIN32 */ #include /* for "struct sockaddr" in "struct addrinfo" */ #include /* for "struct addrinfo" */ -#endif /* WIN32 */ +#endif /* _WIN32 */ /* Workaround for AIX 4.3 */ #if !defined(AI_NUMERICHOST) #define AI_NUMERICHOST 0x04 #endif + #endif /*INET6*/ + #include -#include "tokdefs.h" +#include "grammar.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -76,20 +141,6 @@ static const char rcsid[] _U_ = static int stoi(char *); static inline int xdtoi(int); -#ifdef FLEX_SCANNER -#define YY_NO_INPUT -#define YY_NO_UNPUT -static YY_BUFFER_STATE in_buffer; -#else -static const char *in_buffer; - -#undef getc -#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) -#endif - -#define yylval pcap_lval -extern YYSTYPE yylval; - %} N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) @@ -248,7 +299,7 @@ portrange return PORTRANGE; proto return PROTO; protochain { #ifdef NO_PROTOCHAIN - bpf_error("%s not supported", yytext); + bpf_error(yyextra, "%s not supported", yytext); #else return PROTOCHAIN; #endif @@ -284,6 +335,7 @@ vlan return VLAN; mpls return MPLS; pppoed return PPPOED; pppoes return PPPOES; +geneve return GENEVE; lane return LANE; llc return LLC; @@ -311,26 +363,37 @@ fisu return FISU; lssu return LSSU; lsu return LSSU; msu return MSU; +hfisu return HFISU; +hlssu return HLSSU; +hmsu return HMSU; sio return SIO; opc return OPC; dpc return DPC; sls return SLS; +hsio return HSIO; +hopc return HOPC; +hdpc return HDPC; +hsls return HSLS; [ \r\n\t] ; -[+\-*/:\[\]!<>()&|=] return yytext[0]; +[+\-*/%:\[\]!<>()&|\^=] return yytext[0]; ">=" return GEQ; "<=" return LEQ; "!=" return NEQ; "==" return '='; "<<" return LSH; ">>" return RSH; -${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); +${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1); + if (yylval->e == NULL) + bpf_error(yyextra, "malloc"); return AID; } -{MAC} { yylval.e = pcap_ether_aton((char *)yytext); +{MAC} { yylval->e = pcap_ether_aton((char *)yytext); + if (yylval->e == NULL) + bpf_error(yyextra, "malloc"); return EID; } -{N} { yylval.i = stoi((char *)yytext); return NUM; } +{N} { yylval->i = stoi((char *)yytext); return NUM; } ({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { - yylval.s = sdup((char *)yytext); return HID; } + yylval->s = sdup(yyextra, (char *)yytext); return HID; } {V6} { #ifdef INET6 struct addrinfo hints, *res; @@ -338,80 +401,47 @@ ${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); hints.ai_family = AF_INET6; hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo(yytext, NULL, &hints, &res)) - bpf_error("bogus IPv6 address %s", yytext); + bpf_error(yyextra, "bogus IPv6 address %s", yytext); else { freeaddrinfo(res); - yylval.s = sdup((char *)yytext); return HID6; + yylval->s = sdup(yyextra, (char *)yytext); return HID6; } #else - bpf_error("IPv6 address %s not supported", yytext); + bpf_error(yyextra, "IPv6 address %s not supported", yytext); #endif /*INET6*/ } -{B}:+({B}:+)+ { bpf_error("bogus ethernet address %s", yytext); } -icmptype { yylval.i = 0; return NUM; } -icmpcode { yylval.i = 1; return NUM; } -icmp-echoreply { yylval.i = 0; return NUM; } -icmp-unreach { yylval.i = 3; return NUM; } -icmp-sourcequench { yylval.i = 4; return NUM; } -icmp-redirect { yylval.i = 5; return NUM; } -icmp-echo { yylval.i = 8; return NUM; } -icmp-routeradvert { yylval.i = 9; return NUM; } -icmp-routersolicit { yylval.i = 10; return NUM; } -icmp-timxceed { yylval.i = 11; return NUM; } -icmp-paramprob { yylval.i = 12; return NUM; } -icmp-tstamp { yylval.i = 13; return NUM; } -icmp-tstampreply { yylval.i = 14; return NUM; } -icmp-ireq { yylval.i = 15; return NUM; } -icmp-ireqreply { yylval.i = 16; return NUM; } -icmp-maskreq { yylval.i = 17; return NUM; } -icmp-maskreply { yylval.i = 18; return NUM; } -tcpflags { yylval.i = 13; return NUM; } -tcp-fin { yylval.i = 0x01; return NUM; } -tcp-syn { yylval.i = 0x02; return NUM; } -tcp-rst { yylval.i = 0x04; return NUM; } -tcp-push { yylval.i = 0x08; return NUM; } -tcp-ack { yylval.i = 0x10; return NUM; } -tcp-urg { yylval.i = 0x20; return NUM; } +{B}:+({B}:+)+ { bpf_error(yyextra, "bogus ethernet address %s", yytext); } +icmptype { yylval->i = 0; return NUM; } +icmpcode { yylval->i = 1; return NUM; } +icmp-echoreply { yylval->i = 0; return NUM; } +icmp-unreach { yylval->i = 3; return NUM; } +icmp-sourcequench { yylval->i = 4; return NUM; } +icmp-redirect { yylval->i = 5; return NUM; } +icmp-echo { yylval->i = 8; return NUM; } +icmp-routeradvert { yylval->i = 9; return NUM; } +icmp-routersolicit { yylval->i = 10; return NUM; } +icmp-timxceed { yylval->i = 11; return NUM; } +icmp-paramprob { yylval->i = 12; return NUM; } +icmp-tstamp { yylval->i = 13; return NUM; } +icmp-tstampreply { yylval->i = 14; return NUM; } +icmp-ireq { yylval->i = 15; return NUM; } +icmp-ireqreply { yylval->i = 16; return NUM; } +icmp-maskreq { yylval->i = 17; return NUM; } +icmp-maskreply { yylval->i = 18; return NUM; } +tcpflags { yylval->i = 13; return NUM; } +tcp-fin { yylval->i = 0x01; return NUM; } +tcp-syn { yylval->i = 0x02; return NUM; } +tcp-rst { yylval->i = 0x04; return NUM; } +tcp-push { yylval->i = 0x08; return NUM; } +tcp-ack { yylval->i = 0x10; return NUM; } +tcp-urg { yylval->i = 0x20; return NUM; } [A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { - yylval.s = sdup((char *)yytext); return ID; } -"\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; } + yylval->s = sdup(yyextra, (char *)yytext); return ID; } +"\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; } [^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { - bpf_error("illegal token: %s", yytext); } -. { bpf_error("illegal char '%c'", *yytext); } + bpf_error(yyextra, "illegal token: %s", yytext); } +. { bpf_error(yyextra, "illegal char '%c'", *yytext); } %% -void -lex_init(buf) - const char *buf; -{ -#ifdef FLEX_SCANNER - in_buffer = yy_scan_string(buf); -#else - in_buffer = buf; -#endif -} - -/* - * Do any cleanup necessary after parsing. - */ -void -lex_cleanup() -{ -#ifdef FLEX_SCANNER - if (in_buffer != NULL) - yy_delete_buffer(in_buffer); - in_buffer = NULL; -#endif -} - -/* - * Also define a yywrap. Note that if we're using flex, it will - * define a macro to map this identifier to pcap_wrap. - */ -int -yywrap() -{ - return 1; -} /* Hex digit to integer. */ static inline int diff --git a/contrib/libpcap/sf-pcap-ng.c b/contrib/libpcap/sf-pcap-ng.c index 7eb6db7649..0c02829e71 100644 --- a/contrib/libpcap/sf-pcap-ng.c +++ b/contrib/libpcap/sf-pcap-ng.c @@ -30,9 +30,9 @@ static const char rcsid[] _U_ = #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -42,7 +42,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -121,6 +121,7 @@ struct section_header_block { * that means that this code can't read the file. */ #define PCAP_NG_VERSION_MAJOR 1 +#define PCAP_NG_VERSION_MINOR 0 /* * Interface Description Block. @@ -201,6 +202,32 @@ struct block_cursor { bpf_u_int32 block_type; }; +typedef enum { + PASS_THROUGH, + SCALE_UP_DEC, + SCALE_DOWN_DEC, + SCALE_UP_BIN, + SCALE_DOWN_BIN +} tstamp_scale_type_t; + +/* + * Per-interface information. + */ +struct pcap_ng_if { + u_int tsresol; /* time stamp resolution */ + tstamp_scale_type_t scale_type; /* how to scale */ + u_int scale_factor; /* time stamp scale factor for power-of-10 tsresol */ + u_int64_t tsoffset; /* time stamp offset */ +}; + +struct pcap_ng_sf { + u_int user_tsresol; /* time stamp resolution requested by the user */ + bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ + bpf_u_int32 ifaces_size; /* size of array below */ + struct pcap_ng_if *ifaces; /* array of interface information */ +}; + +static void pcap_ng_cleanup(pcap_t *p); static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data); @@ -213,13 +240,13 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, amt_read = fread(buf, 1, bytes_to_read, fp); if (amt_read != bytes_to_read) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { if (amt_read == 0 && !fail_on_eof) return (0); /* EOF */ - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu bytes, only got %lu", (unsigned long)bytes_to_read, (unsigned long)amt_read); @@ -234,12 +261,14 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) { int status; struct block_header bhdr; + u_char *bdata; + size_t data_remaining; status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf); if (status <= 0) return (status); /* error or EOF */ - if (p->sf.swapped) { + if (p->swapped) { bhdr.block_type = SWAPLONG(bhdr.block_type); bhdr.total_length = SWAPLONG(bhdr.total_length); } @@ -252,7 +281,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) * memory if we read a malformed file. */ if (bhdr.total_length > 16*1024*1024) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap-ng block size %u > maximum %u", bhdr.total_length, 16*1024*1024); return (-1); @@ -264,7 +293,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) */ if (bhdr.total_length < sizeof(struct block_header) + sizeof(struct block_trailer)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block in pcap-ng dump file has a length of %u < %lu", bhdr.total_length, (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); @@ -278,11 +307,14 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) /* * No - make it big enough. */ - p->buffer = realloc(p->buffer, bhdr.total_length); - if (p->buffer == NULL) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + void *bigger_buffer; + + bigger_buffer = realloc(p->buffer, bhdr.total_length); + if (bigger_buffer == NULL) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); return (-1); } + p->buffer = bigger_buffer; } /* @@ -290,16 +322,16 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) * of the block. */ memcpy(p->buffer, &bhdr, sizeof(bhdr)); - if (read_bytes(fp, p->buffer + sizeof(bhdr), - bhdr.total_length - sizeof(bhdr), 1, errbuf) == -1) + bdata = (u_char *)p->buffer + sizeof(bhdr); + data_remaining = bhdr.total_length - sizeof(bhdr); + if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1) return (-1); /* * Initialize the cursor. */ - cursor->data = p->buffer + sizeof(bhdr); - cursor->data_remaining = bhdr.total_length - sizeof(bhdr) - - sizeof(struct block_trailer); + cursor->data = bdata; + cursor->data_remaining = data_remaining - sizeof(struct block_trailer); cursor->block_type = bhdr.block_type; return (1); } @@ -315,7 +347,7 @@ get_from_block_data(struct block_cursor *cursor, size_t chunk_size, * the block data. */ if (cursor->data_remaining < chunk_size) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block of type %u in pcap-ng dump file is too short", cursor->block_type); return (NULL); @@ -346,7 +378,7 @@ get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { opthdr->option_code = SWAPSHORT(opthdr->option_code); opthdr->option_length = SWAPSHORT(opthdr->option_length); } @@ -378,7 +410,7 @@ get_optvalue_from_block_data(struct block_cursor *cursor, static int process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, - u_int64_t *tsoffset, char *errbuf) + u_int64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; @@ -416,7 +448,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, case OPT_ENDOFOPT: if (opthdr->option_length != 0) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); @@ -425,27 +457,29 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, case IF_TSRESOL: if (opthdr->option_length != 1) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr->option_length); return (-1); } if (saw_tsresol) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; - tsresol_opt = *(u_int *)optvalue; + memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ + *is_binary = 1; *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ + *is_binary = 0; *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; @@ -455,11 +489,11 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, * Resolution is too high. */ if (tsresol_opt & 0x80) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_opt & 0x7F); } else { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } @@ -469,19 +503,19 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, case IF_TSOFFSET: if (opthdr->option_length != 8) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr->option_length); return (-1); } if (saw_tsoffset) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); - if (p->sf.swapped) + if (p->swapped) *tsoffset = SWAPLL(*tsoffset); break; @@ -494,25 +528,204 @@ done: return (0); } +static int +add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + struct pcap_ng_sf *ps; + u_int tsresol; + u_int64_t tsoffset; + int is_binary; + + ps = p->priv; + + /* + * Count this interface. + */ + ps->ifcount++; + + /* + * Grow the array of per-interface information as necessary. + */ + if (ps->ifcount > ps->ifaces_size) { + /* + * We need to grow the array. + */ + bpf_u_int32 new_ifaces_size; + struct pcap_ng_if *new_ifaces; + + if (ps->ifaces_size == 0) { + /* + * It's currently empty. + * + * (The Clang static analyzer doesn't do enough, + * err, umm, dataflow *analysis* to realize that + * ps->ifaces_size == 0 if ps->ifaces == NULL, + * and so complains about a possible zero argument + * to realloc(), so we check for the former + * condition to shut it up. + * + * However, it doesn't complain that one of the + * multiplications below could overflow, which is + * a real, albeit extremely unlikely, problem (you'd + * need a pcap-ng file with tens of millions of + * interfaces).) + */ + new_ifaces_size = 1; + new_ifaces = malloc(sizeof (struct pcap_ng_if)); + } else { + /* + * It's not currently empty; double its size. + * (Perhaps overkill once we have a lot of interfaces.) + * + * Check for overflow if we double it. + */ + if (ps->ifaces_size * 2 < ps->ifaces_size) { + /* + * The maximum number of interfaces before + * ps->ifaces_size overflows is the largest + * possible 32-bit power of 2, as we do + * size doubling. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "more than %u interfaces in the file", + 0x80000000U); + return (0); + } + + /* + * ps->ifaces_size * 2 doesn't overflow, so it's + * safe to multiply. + */ + new_ifaces_size = ps->ifaces_size * 2; + + /* + * Now make sure that's not so big that it overflows + * if we multiply by sizeof (struct pcap_ng_if). + * + * That can happen on 32-bit platforms, with a 32-bit + * size_t; it shouldn't happen on 64-bit platforms, + * with a 64-bit size_t, as new_ifaces_size is + * 32 bits. + */ + if (new_ifaces_size * sizeof (struct pcap_ng_if) < new_ifaces_size) { + /* + * As this fails only with 32-bit size_t, + * the multiplication was 32x32->32, and + * the largest 32-bit value that can safely + * be multiplied by sizeof (struct pcap_ng_if) + * without overflow is the largest 32-bit + * (unsigned) value divided by + * sizeof (struct pcap_ng_if). + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "more than %u interfaces in the file", + 0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if))); + return (0); + } + new_ifaces = realloc(ps->ifaces, new_ifaces_size * sizeof (struct pcap_ng_if)); + } + if (new_ifaces == NULL) { + /* + * We ran out of memory. + * Give up. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "out of memory for per-interface information (%u interfaces)", + ps->ifcount); + return (0); + } + ps->ifaces_size = new_ifaces_size; + ps->ifaces = new_ifaces; + } + + /* + * Set the default time stamp resolution and offset. + */ + tsresol = 1000000; /* microsecond resolution */ + is_binary = 0; /* which is a power of 10 */ + tsoffset = 0; /* absolute timestamps */ + + /* + * Now look for various time stamp options, so we know + * how to interpret the time stamps for this interface. + */ + if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary, + errbuf) == -1) + return (0); + + ps->ifaces[ps->ifcount - 1].tsresol = tsresol; + ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; + + /* + * Determine whether we're scaling up or down or not + * at all for this interface. + */ + if (tsresol == ps->user_tsresol) { + /* + * The resolution is the resolution the user wants, + * so we don't have to do scaling. + */ + ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; + } else if (tsresol > ps->user_tsresol) { + /* + * The resolution is greater than what the user wants, + * so we have to scale the timestamps down. + */ + if (is_binary) + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_BIN; + else { + /* + * Calculate the scale factor. + */ + ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol; + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC; + } + } else { + /* + * The resolution is less than what the user wants, + * so we have to scale the timestamps up. + */ + if (is_binary) + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_BIN; + else { + /* + * Calculate the scale factor. + */ + ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol; + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC; + } + } + return (1); +} + /* * Check whether this is a pcap-ng savefile and, if it is, extract the * relevant information from the header. */ -int -pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) +pcap_t * +pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, + int *err) { size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; struct block_header *bhdrp; struct section_header_block *shbp; + pcap_t *p; + int swapped = 0; + struct pcap_ng_sf *ps; int status; struct block_cursor cursor; struct interface_description_block *idbp; + /* + * Assume no read errors. + */ + *err = 0; + /* * Check whether the first 4 bytes of the file are the block - * type for a pcap-ng savefile. + * type for a pcap-ng savefile. */ if (magic != BT_SHB) { /* @@ -524,7 +737,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * this as possibly being a pcap-ng file transferred * between UN*X and Windows in text file format? */ - return (0); /* nope */ + return (NULL); /* nope */ } /* @@ -541,32 +754,34 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) amt_read = fread(&total_length, 1, sizeof(total_length), fp); if (amt_read < sizeof(total_length)) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); - return (-1); /* fail */ + *err = 1; + return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ - return (0); + return (NULL); } amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp); if (amt_read < sizeof(byte_order_magic)) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); - return (-1); /* fail */ + *err = 1; + return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ - return (0); + return (NULL); } if (byte_order_magic != BYTE_ORDER_MAGIC) { byte_order_magic = SWAPLONG(byte_order_magic); @@ -574,9 +789,9 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) /* * Not a pcap-ng file. */ - return (0); + return (NULL); } - p->sf.swapped = 1; + swapped = 1; total_length = SWAPLONG(total_length); } @@ -584,12 +799,49 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * Check the sanity of the total length. */ if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Section Header Block in pcap-ng dump file has a length of %u < %lu", total_length, (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); - return (-1); + *err = 1; + return (NULL); + } + + /* + * OK, this is a good pcap-ng file. + * Allocate a pcap_t for it. + */ + p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf)); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); } + p->swapped = swapped; + ps = p->priv; + + /* + * What precision does the user want? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + ps->user_tsresol = 1000000; + break; + + case PCAP_TSTAMP_PRECISION_NANO: + ps->user_tsresol = 1000000000; + break; + + default: + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } + + p->opt.tstamp_precision = precision; /* * Allocate a buffer into which to read blocks. We default to @@ -608,8 +860,10 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) p->bufsize = total_length; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); - return (-1); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); } /* @@ -617,17 +871,17 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * of the SHB. */ bhdrp = (struct block_header *)p->buffer; - shbp = (struct section_header_block *)(p->buffer + sizeof(struct block_header)); + shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header)); bhdrp->block_type = magic; bhdrp->total_length = total_length; shbp->byte_order_magic = byte_order_magic; if (read_bytes(fp, - p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), + (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), 1, errbuf) == -1) goto fail; - if (p->sf.swapped) { + if (p->swapped) { /* * Byte-swap the fields we've read. */ @@ -638,21 +892,21 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * XXX - we don't care about the section length. */ } - if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, - "unknown pcap-ng savefile major version number %u", - shbp->major_version); + /* currently only SHB version 1.0 is supported */ + if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR && + shbp->minor_version == PCAP_NG_VERSION_MINOR)) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unsupported pcap-ng savefile version %u.%u", + shbp->major_version, shbp->minor_version); goto fail; } - p->sf.version_major = shbp->major_version; - p->sf.version_minor = shbp->minor_version; + p->version_major = shbp->major_version; + p->version_minor = shbp->minor_version; /* - * Set the default time stamp resolution and offset. + * Save the time stamp resolution the user requested. */ - p->sf.tsresol = 1000000; /* microsecond resolution */ - p->sf.tsscale = 1; /* multiply by 1 to scale to microseconds */ - p->sf.tsoffset = 0; /* absolute timestamps */ + p->opt.tstamp_precision = precision; /* * Now start looking for an Interface Description Block. @@ -664,7 +918,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) status = read_block(fp, p, &cursor, errbuf); if (status == 0) { /* EOF - no IDB in this file */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "the capture file has no Interface Description Blocks"); goto fail; } @@ -685,42 +939,28 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* - * Count this interface. + * Interface capture length sanity check */ - p->sf.ifcount++; + if (idbp->snaplen > MAXIMUM_SNAPLEN) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "invalid interface capture length %u, " + "bigger than maximum of %u", + idbp->snaplen, MAXIMUM_SNAPLEN); + goto fail; + } /* - * Now look for various time stamp options, so - * we know how to interpret the time stamps. + * Try to add this interface. */ - if (process_idb_options(p, &cursor, &p->sf.tsresol, - &p->sf.tsoffset, errbuf) == -1) + if (!add_interface(p, &cursor, errbuf)) goto fail; - /* - * Compute the scaling factor to convert the - * sub-second part of the time stamp to - * microseconds. - */ - if (p->sf.tsresol > 1000000) { - /* - * Higher than microsecond resolution; - * scale down to microseconds. - */ - p->sf.tsscale = (p->sf.tsresol / 1000000); - } else { - /* - * Lower than microsecond resolution; - * scale up to microseconds. - */ - p->sf.tsscale = (1000000 / p->sf.tsresol); - } goto done; case BT_EPB: @@ -731,7 +971,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * not valid, as we don't know what link-layer * encapsulation the packet has. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "the capture file has a packet block before any Interface Description Blocks"); goto fail; @@ -749,13 +989,26 @@ done: p->linktype = linktype_to_dlt(idbp->linktype); p->linktype_ext = 0; - p->sf.next_packet_op = pcap_ng_next_packet; + p->next_packet_op = pcap_ng_next_packet; + p->cleanup_op = pcap_ng_cleanup; - return (1); + return (p); fail: + free(ps->ifaces); free(p->buffer); - return (-1); + free(p); + *err = 1; + return (NULL); +} + +static void +pcap_ng_cleanup(pcap_t *p) +{ + struct pcap_ng_sf *ps = p->priv; + + free(ps->ifaces); + sf_cleanup(p); } /* @@ -766,6 +1019,7 @@ fail: static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { + struct pcap_ng_sf *ps = p->priv; struct block_cursor cursor; int status; struct enhanced_packet_block *epbp; @@ -774,9 +1028,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) bpf_u_int32 interface_id = 0xFFFFFFFF; struct interface_description_block *idbp; struct section_header_block *shbp; - FILE *fp = p->sf.rfile; - u_int tsresol; - u_int64_t tsoffset; + FILE *fp = p->rfile; u_int64_t t, sec, frac; /* @@ -808,7 +1060,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { /* these were written in opposite byte order */ interface_id = SWAPLONG(epbp->interface_id); hdr->caplen = SWAPLONG(epbp->caplen); @@ -823,7 +1075,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) epbp->timestamp_low; } goto found; - + case BT_SPB: /* * Get a pointer to the fixed-length portion of the @@ -843,7 +1095,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { /* these were written in opposite byte order */ hdr->len = SWAPLONG(spbp->len); } else @@ -855,7 +1107,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * and the packet length. */ hdr->caplen = hdr->len; - if (hdr->caplen > p->snapshot) + if (hdr->caplen > (bpf_u_int32)p->snapshot) hdr->caplen = p->snapshot; t = 0; /* no time stamps */ goto found; @@ -873,7 +1125,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { /* these were written in opposite byte order */ interface_id = SWAPSHORT(pbp->interface_id); hdr->caplen = SWAPLONG(pbp->caplen); @@ -902,7 +1154,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Byte-swap it if necessary. */ - if (p->sf.swapped) { + if (p->swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } @@ -916,50 +1168,23 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * interfaces? */ if (p->linktype != idbp->linktype) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a type %u different from the type of the first interface", idbp->linktype); return (-1); } - if (p->snapshot != idbp->snaplen) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + if ((bpf_u_int32)p->snapshot != idbp->snaplen) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a snapshot length %u different from the type of the first interface", idbp->snaplen); return (-1); } /* - * Count this interface. + * Try to add this interface. */ - p->sf.ifcount++; - - /* - * Set the default time stamp resolution and offset. - */ - tsresol = 1000000; /* microsecond resolution */ - tsoffset = 0; /* absolute timestamps */ - - /* - * Now look for various time stamp options, to - * make sure they're the same. - * - * XXX - we could, in theory, handle multiple - * different resolutions and offsets, but we - * don't do so for now. - */ - if (process_idb_options(p, &cursor, &tsresol, &tsoffset, - p->errbuf) == -1) - return (-1); - if (tsresol != p->sf.tsresol) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "an interface has a time stamp resolution different from the time stamp resolution of the first interface"); + if (!add_interface(p, &cursor, p->errbuf)) return (-1); - } - if (tsoffset != p->sf.tsoffset) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "an interface has a time stamp offset different from the time stamp offset of the first interface"); - return (-1); - } break; case BT_SHB: @@ -977,7 +1202,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * the same as that of the previous section. * We'll check for that later. */ - if (p->sf.swapped) { + if (p->swapped) { shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic); shbp->major_version = @@ -1001,7 +1226,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Byte order changes. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has sections with different byte orders"); return (-1); @@ -1009,7 +1234,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * Not a valid SHB. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has a section with a bad byte order magic field"); return (-1); } @@ -1019,7 +1244,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * we handle. */ if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown pcap-ng savefile major version number %u", shbp->major_version); return (-1); @@ -1034,7 +1259,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * any IDBs, we'll fail when we see a packet * block.) */ - p->sf.ifcount = 0; + ps->ifcount = 0; break; default: @@ -1042,43 +1267,148 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * Not a packet block, IDB, or SHB; ignore it. */ break; - } + } } found: /* * Is the interface ID an interface we know? */ - if (interface_id >= p->sf.ifcount) { + if (interface_id >= ps->ifcount) { /* * Yes. Fail. */ - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "a packet arrived on interface %u, but there's no Interface Description Block for that interface", interface_id); return (-1); } /* - * Convert the time stamp to a struct timeval. + * Convert the time stamp to seconds and fractions of a second, + * with the fractions being in units of the file-supplied resolution. */ - sec = t / p->sf.tsresol + p->sf.tsoffset; - frac = t % p->sf.tsresol; - if (p->sf.tsresol > 1000000) { + sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; + frac = t % ps->ifaces[interface_id].tsresol; + + /* + * Convert the fractions from units of the file-supplied resolution + * to units of the user-requested resolution. + */ + switch (ps->ifaces[interface_id].scale_type) { + + case PASS_THROUGH: /* - * Higher than microsecond resolution; scale down to - * microseconds. + * The interface resolution is what the user wants, + * so we're done. */ - frac /= p->sf.tsscale; - } else { + break; + + case SCALE_UP_DEC: + /* + * The interface resolution is less than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * Those resolutions are both powers of 10, and the user- + * requested resolution is greater than the file-supplied + * resolution, so the quotient in question is an integer. + * We've calculated that quotient already, so we just + * multiply by it. + */ + frac *= ps->ifaces[interface_id].scale_factor; + break; + + case SCALE_UP_BIN: /* - * Lower than microsecond resolution; scale up to - * microseconds. + * The interface resolution is less than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * The file-supplied resolution is a power of 2, so the + * quotient is not an integer, so, in order to do this + * entirely with integer arithmetic, we multiply by the + * user-requested resolution and divide by the file- + * supplied resolution. + * + * XXX - Is there something clever we could do here, + * given that we know that the file-supplied resolution + * is a power of 2? Doing a multiplication followed by + * a division runs the risk of overflowing, and involves + * two non-simple arithmetic operations. */ - frac *= p->sf.tsscale; + frac *= ps->user_tsresol; + frac /= ps->ifaces[interface_id].tsresol; + break; + + case SCALE_DOWN_DEC: + /* + * The interface resolution is greater than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * Those resolutions are both powers of 10, and the user- + * requested resolution is less than the file-supplied + * resolution, so the quotient in question isn't an + * integer, but its reciprocal is, and we can just divide + * by the reciprocal of the quotient. We've calculated + * the reciprocal of that quotient already, so we must + * divide by it. + */ + frac /= ps->ifaces[interface_id].scale_factor; + break; + + + case SCALE_DOWN_BIN: + /* + * The interface resolution is greater than what the user + * wants; convert the fractional part to units of the + * resolution the user requested by multiplying by the + * quotient of the user-requested resolution and the + * file-supplied resolution. We do that by multiplying + * by the user-requested resolution and dividing by the + * file-supplied resolution, as the quotient might not + * fit in an integer. + * + * The file-supplied resolution is a power of 2, so the + * quotient is not an integer, and neither is its + * reciprocal, so, in order to do this entirely with + * integer arithmetic, we multiply by the user-requested + * resolution and divide by the file-supplied resolution. + * + * XXX - Is there something clever we could do here, + * given that we know that the file-supplied resolution + * is a power of 2? Doing a multiplication followed by + * a division runs the risk of overflowing, and involves + * two non-simple arithmetic operations. + */ + frac *= ps->user_tsresol; + frac /= ps->ifaces[interface_id].tsresol; + break; } - hdr->ts.tv_sec = sec; - hdr->ts.tv_usec = frac; +#ifdef _WIN32 + /* + * tv_sec and tv_used in the Windows struct timeval are both + * longs. + */ + hdr->ts.tv_sec = (long)sec; + hdr->ts.tv_usec = (long)frac; +#else + /* + * tv_sec in the UN*X struct timeval is a time_t; tv_usec is + * suseconds_t in UN*Xes that work the way the current Single + * UNIX Standard specify - but not all older UN*Xes necessarily + * support that type, so just cast to int. + */ + hdr->ts.tv_sec = (time_t)sec; + hdr->ts.tv_usec = (int)frac; +#endif /* * Get a pointer to the packet data. @@ -1087,23 +1417,8 @@ found: if (*data == NULL) return (-1); - if (p->sf.swapped) { - /* - * Convert pseudo-headers from the byte order of - * the host on which the file was saved to our - * byte order, as necessary. - */ - switch (p->linktype) { - - case DLT_USB_LINUX: - swap_linux_usb_header(hdr, *data, 0); - break; - - case DLT_USB_LINUX_MMAPPED: - swap_linux_usb_header(hdr, *data, 1); - break; - } - } + if (p->swapped) + swap_pseudo_headers(p->linktype, hdr, *data); return (0); } diff --git a/contrib/libpcap/sf-pcap-ng.h b/contrib/libpcap/sf-pcap-ng.h index cc5518241b..3c93498fb5 100644 --- a/contrib/libpcap/sf-pcap-ng.h +++ b/contrib/libpcap/sf-pcap-ng.h @@ -26,6 +26,7 @@ #ifndef sf_pcap_ng_h #define sf_pcap_ng_h -extern int pcap_ng_check_header(pcap_t *, bpf_u_int32, FILE *, char *); +extern pcap_t *pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, + u_int precision, char *errbuf, int *err); #endif diff --git a/contrib/libpcap/sf-pcap.c b/contrib/libpcap/sf-pcap.c index 2b31a2b7a0..ac305d4b01 100644 --- a/contrib/libpcap/sf-pcap.c +++ b/contrib/libpcap/sf-pcap.c @@ -37,9 +37,9 @@ static const char rcsid[] _U_ = #include "config.h" #endif -#ifdef WIN32 +#ifdef _WIN32 #include -#else /* WIN32 */ +#else /* _WIN32 */ #if HAVE_INTTYPES_H #include #elif HAVE_STDINT_H @@ -49,7 +49,7 @@ static const char rcsid[] _U_ = #include #endif #include -#endif /* WIN32 */ +#endif /* _WIN32 */ #include #include @@ -70,7 +70,7 @@ static const char rcsid[] _U_ = /* * Setting O_BINARY on DOS/Windows is a bit tricky */ -#if defined(WIN32) +#if defined(_WIN32) #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #elif defined(MSDOS) #if defined(__HIGHC__) @@ -122,26 +122,58 @@ static const char rcsid[] _U_ = static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); +/* + * Private data for reading pcap savefiles. + */ +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef enum { + PASS_THROUGH, + SCALE_UP, + SCALE_DOWN +} tstamp_scale_type_t; + +struct pcap_sf { + size_t hdrsize; + swapped_type_t lengths_swapped; + tstamp_scale_type_t scale_type; +}; + /* * Check whether this is a pcap savefile and, if it is, extract the * relevant information from the header. */ -int -pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) +pcap_t * +pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, + int *err) { struct pcap_file_header hdr; size_t amt_read; + pcap_t *p; + int swapped = 0; + struct pcap_sf *ps; + + /* + * Assume no read errors. + */ + *err = 0; /* * Check whether the first 4 bytes of the file are the magic * number for a pcap savefile, or for a byte-swapped pcap * savefile. */ - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) { + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) { magic = SWAPLONG(magic); - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) - return (0); /* nope */ - p->sf.swapped = 1; + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) + return (NULL); /* nope */ + swapped = 1; } /* @@ -153,22 +185,23 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) sizeof(hdr) - sizeof(hdr.magic), fp); if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu file header bytes, only got %lu", (unsigned long)sizeof(hdr), (unsigned long)amt_read); } - return (-1); + *err = 1; + return (NULL); } /* * If it's a byte-swapped capture file, byte-swap the header. */ - if (p->sf.swapped) { + if (swapped) { hdr.version_major = SWAPSHORT(hdr.version_major); hdr.version_minor = SWAPSHORT(hdr.version_minor); hdr.thiszone = SWAPLONG(hdr.thiszone); @@ -178,18 +211,106 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) } if (hdr.version_major < PCAP_VERSION_MAJOR) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "archaic pcap savefile format"); - return (-1); + *err = 1; + return (NULL); + } + + /* + * currently only versions 2.[0-4] are supported with + * the exception of 543.0 for DG/UX tcpdump. + */ + if (! ((hdr.version_major == PCAP_VERSION_MAJOR && + hdr.version_minor <= PCAP_VERSION_MINOR) || + (hdr.version_major == 543 && + hdr.version_minor == 0))) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unsupported pcap savefile version %u.%u", + hdr.version_major, hdr.version_minor); + *err = 1; + return NULL; + } + + if (hdr.snaplen > MAXIMUM_SNAPLEN) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "invalid file capture length %u, bigger than " + "maximum of %u", hdr.snaplen, MAXIMUM_SNAPLEN); + *err = 1; + return NULL; + } + + /* + * OK, this is a good pcap file. + * Allocate a pcap_t for it. + */ + p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); } - p->sf.version_major = hdr.version_major; - p->sf.version_minor = hdr.version_minor; + p->swapped = swapped; + p->version_major = hdr.version_major; + p->version_minor = hdr.version_minor; p->tzoff = hdr.thiszone; p->snapshot = hdr.snaplen; p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); - p->sf.next_packet_op = pcap_next_packet; + p->next_packet_op = pcap_next_packet; + + ps = p->priv; + + p->opt.tstamp_precision = precision; + + /* + * Will we need to scale the timestamps to match what the + * user wants? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the user + * wants microseconds; scale the + * precision down. + */ + ps->scale_type = SCALE_DOWN; + } else { + /* + * The file has microseconds, the + * user wants microseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } + break; + + case PCAP_TSTAMP_PRECISION_NANO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the + * user wants nanoseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } else { + /* + * The file has microoseconds, the user + * wants nanoseconds; scale the + * precision up. + */ + ps->scale_type = SCALE_UP; + } + break; + + default: + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } /* * We interchanged the caplen and len fields at version 2.3, @@ -205,19 +326,19 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) case 2: if (hdr.version_minor < 3) - p->sf.lengths_swapped = SWAPPED; + ps->lengths_swapped = SWAPPED; else if (hdr.version_minor == 3) - p->sf.lengths_swapped = MAYBE_SWAPPED; + ps->lengths_swapped = MAYBE_SWAPPED; else - p->sf.lengths_swapped = NOT_SWAPPED; + ps->lengths_swapped = NOT_SWAPPED; break; case 543: - p->sf.lengths_swapped = SWAPPED; + ps->lengths_swapped = SWAPPED; break; default: - p->sf.lengths_swapped = NOT_SWAPPED; + ps->lengths_swapped = NOT_SWAPPED; break; } @@ -239,7 +360,7 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * data ourselves and read from that buffer in order to * make that work. */ - p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr); + ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); if (p->linktype == DLT_EN10MB) { /* @@ -265,7 +386,7 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) p->snapshot += 14; } } else - p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); + ps->hdrsize = sizeof(struct pcap_sf_pkthdr); /* * Allocate a buffer for the packet data. @@ -273,17 +394,21 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) p->bufsize = p->snapshot; if (p->bufsize <= 0) { /* - * Bogus snapshot length; use 64KiB as a fallback. + * Bogus snapshot length; use the maximum as a fallback. */ - p->bufsize = 65536; + p->bufsize = MAXIMUM_SNAPLEN; } p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); - return (-1); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); } - return (1); + p->cleanup_op = sf_cleanup; + + return (p); } /* @@ -294,8 +419,9 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { + struct pcap_sf *ps = p->priv; struct pcap_sf_patched_pkthdr sf_hdr; - FILE *fp = p->sf.rfile; + FILE *fp = p->rfile; size_t amt_read; bpf_u_int32 t; @@ -306,18 +432,18 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * unpatched libpcap we only read as many bytes as the regular * header has. */ - amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp); - if (amt_read != p->sf.hdrsize) { + amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); + if (amt_read != ps->hdrsize) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); return (-1); } else { if (amt_read != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu header bytes, only got %lu", - (unsigned long)p->sf.hdrsize, + (unsigned long)ps->hdrsize, (unsigned long)amt_read); return (-1); } @@ -326,7 +452,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } } - if (p->sf.swapped) { + if (p->swapped) { /* these were written in opposite byte order */ hdr->caplen = SWAPLONG(sf_hdr.caplen); hdr->len = SWAPLONG(sf_hdr.len); @@ -338,8 +464,34 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) hdr->ts.tv_sec = sf_hdr.ts.tv_sec; hdr->ts.tv_usec = sf_hdr.ts.tv_usec; } + + switch (ps->scale_type) { + + case PASS_THROUGH: + /* + * Just pass the time stamp through. + */ + break; + + case SCALE_UP: + /* + * File has microseconds, user wants nanoseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; + break; + + case SCALE_DOWN: + /* + * File has nanoseconds, user wants microseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; + break; + } + /* Swap the caplen and len fields, if necessary. */ - switch (p->sf.lengths_swapped) { + switch (ps->lengths_swapped) { case NOT_SWAPPED: break; @@ -365,63 +517,93 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * This can happen due to Solaris 2.3 systems tripping * over the BUFMOD problem and not setting the snapshot - * correctly in the savefile header. If the caplen isn't - * grossly wrong, try to salvage. + * correctly in the savefile header. + * This can also happen with a corrupted savefile or a + * savefile built/modified by a fuzz tester. + * If the caplen isn't grossly wrong, try to salvage. */ - static u_char *tp = NULL; - static size_t tsize = 0; - - if (hdr->caplen > 65535) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "bogus savefile header"); + size_t bytes_to_discard; + size_t bytes_to_read, bytes_read; + char discard_buf[4096]; + + if (hdr->caplen > MAXIMUM_SNAPLEN) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "invalid packet capture length %u, bigger than " + "maximum of %u", hdr->caplen, MAXIMUM_SNAPLEN); return (-1); } - if (tsize < hdr->caplen) { - tsize = ((hdr->caplen + 1023) / 1024) * 1024; - if (tp != NULL) - free((u_char *)tp); - tp = (u_char *)malloc(tsize); - if (tp == NULL) { - tsize = 0; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BUFMOD hack malloc"); - return (-1); - } - } - amt_read = fread((char *)tp, 1, hdr->caplen, fp); - if (amt_read != hdr->caplen) { + /* + * XXX - we don't grow the buffer here because some + * program might assume that it will never get packets + * bigger than the snapshot length; for example, it might + * copy data from our buffer to a buffer of its own, + * allocated based on the return value of pcap_snapshot(). + * + * Read the first p->bufsize bytes into the buffer. + */ + amt_read = fread(p->buffer, 1, p->bufsize, fp); + if (amt_read != p->bufsize) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + /* + * Yes, this uses hdr->caplen; technically, + * it's true, because we would try to read + * and discard the rest of those bytes, and + * that would fail because we got EOF before + * the read finished. + */ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } return (-1); } + /* - * We can only keep up to p->bufsize bytes. Since - * caplen > p->bufsize is exactly how we got here, - * we know we can only keep the first p->bufsize bytes - * and must drop the remainder. Adjust caplen accordingly, - * so we don't get confused later as to how many bytes we - * have to play with. + * Now read and discard what's left. + */ + bytes_to_discard = hdr->caplen - p->bufsize; + bytes_read = amt_read; + while (bytes_to_discard != 0) { + bytes_to_read = bytes_to_discard; + if (bytes_to_read > sizeof (discard_buf)) + bytes_to_read = sizeof (discard_buf); + amt_read = fread(discard_buf, 1, bytes_to_read, fp); + bytes_read += amt_read; + if (amt_read != bytes_to_read) { + if (ferror(fp)) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)bytes_read); + } + return (-1); + } + bytes_to_discard -= amt_read; + } + + /* + * Adjust caplen accordingly, so we don't get confused later + * as to how many bytes we have to play with. */ hdr->caplen = p->bufsize; - memcpy(p->buffer, (char *)tp, p->bufsize); } else { /* read the packet itself */ amt_read = fread(p->buffer, 1, hdr->caplen, fp); if (amt_read != hdr->caplen) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } @@ -430,33 +612,18 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } *data = p->buffer; - if (p->sf.swapped) { - /* - * Convert pseudo-headers from the byte order of - * the host on which the file was saved to our - * byte order, as necessary. - */ - switch (p->linktype) { - - case DLT_USB_LINUX: - swap_linux_usb_header(hdr, *data, 0); - break; - - case DLT_USB_LINUX_MMAPPED: - swap_linux_usb_header(hdr, *data, 1); - break; - } - } + if (p->swapped) + swap_pseudo_headers(p->linktype, hdr, *data); return (0); } static int -sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) +sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) { struct pcap_file_header hdr; - hdr.magic = TCPDUMP_MAGIC; + hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; @@ -494,7 +661,7 @@ static pcap_dumper_t * pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) { -#if defined(WIN32) || defined(MSDOS) +#if defined(_WIN32) || defined(MSDOS) /* * If we're writing to the standard output, put it in binary * mode, as savefiles are binary files. @@ -507,8 +674,8 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) else setbuf(f, NULL); #endif - if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", fname, pcap_strerror(errno)); if (f != stdout) (void)fclose(f); @@ -531,31 +698,36 @@ pcap_dump_open(pcap_t *p, const char *fname) * link-layer type, so we can't use it. */ if (!p->activated) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not-yet-activated pcap_t passed to pcap_dump_open", fname); return (NULL); } linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: link-layer type %d isn't supported in savefiles", fname, p->linktype); return (NULL); } linktype |= p->linktype_ext; + if (fname == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } if (fname[0] == '-' && fname[1] == '\0') { f = stdout; fname = "standard output"; } else { -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) f = fopen(fname, "w"); #else f = fopen(fname, "wb"); #endif if (f == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } @@ -568,12 +740,12 @@ pcap_dump_open(pcap_t *p, const char *fname) */ pcap_dumper_t * pcap_dump_fopen(pcap_t *p, FILE *f) -{ +{ int linktype; linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "stream: link-layer type %d isn't supported in savefiles", p->linktype); return (NULL); @@ -583,6 +755,174 @@ pcap_dump_fopen(pcap_t *p, FILE *f) return (pcap_setup_dump(p, linktype, f, "stream")); } +pcap_dumper_t * +pcap_dump_open_append(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + size_t amt_read; + struct pcap_file_header ph; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, linktype); + return (NULL); + } + + if (fname == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } + if (fname[0] == '-' && fname[1] == '\0') + return (pcap_setup_dump(p, linktype, stdout, "standard output")); + +#if !defined(_WIN32) && !defined(MSDOS) + f = fopen(fname, "r+"); +#else + f = fopen(fname, "rb+"); +#endif + if (f == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + return (NULL); + } + + /* + * Try to read a pcap header. + */ + amt_read = fread(&ph, 1, sizeof (ph), f); + if (amt_read != sizeof (ph)) { + if (ferror(f)) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + fclose(f); + return (NULL); + } else if (feof(f) && amt_read > 0) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: truncated pcap file header", fname); + fclose(f); + return (NULL); + } + } + +#if defined(_WIN32) || defined(MSDOS) + /* + * We turn off buffering. + * XXX - why? And why not on the standard output? + */ + setbuf(f, NULL); +#endif + + /* + * If a header is already present and: + * + * it's not for a pcap file of the appropriate resolution + * and the right byte order for this machine; + * + * the link-layer header types don't match; + * + * the snapshot lengths don't match; + * + * return an error. + */ + if (amt_read > 0) { + /* + * A header is already present. + * Do the checks. + */ + switch (ph.magic) { + + case TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case NSEC_TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case SWAPLONG(TCPDUMP_MAGIC): + case SWAPLONG(NSEC_TCPDUMP_MAGIC): + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different byte order, cannot append to file", fname); + fclose(f); + return (NULL); + + case KUZNETZOV_TCPDUMP_MAGIC: + case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): + case NAVTEL_TCPDUMP_MAGIC: + case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file to which we can append", fname); + fclose(f); + return (NULL); + + default: + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file", fname); + fclose(f); + return (NULL); + } + + /* + * Good version? + */ + if (ph.version_major != PCAP_VERSION_MAJOR || + ph.version_minor != PCAP_VERSION_MINOR) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: version is %u.%u, cannot append to file", fname, + ph.version_major, ph.version_minor); + fclose(f); + return (NULL); + } + if ((bpf_u_int32)linktype != ph.linktype) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different linktype, cannot append to file", fname); + fclose(f); + return (NULL); + } + if ((bpf_u_int32)p->snapshot != ph.snaplen) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different snaplen, cannot append to file", fname); + fclose(f); + return (NULL); + } + } else { + /* + * A header isn't present; attempt to write it. + */ + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + } + + /* + * Start writing at the end of the file. + */ + if (fseek(f, 0, SEEK_END) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + FILE * pcap_dump_file(pcap_dumper_t *p) { diff --git a/contrib/libpcap/sf-pcap.h b/contrib/libpcap/sf-pcap.h index 3b3fbe893b..e9c7eafa65 100644 --- a/contrib/libpcap/sf-pcap.h +++ b/contrib/libpcap/sf-pcap.h @@ -31,6 +31,7 @@ #ifndef sf_pcap_h #define sf_pcap_h -extern int pcap_check_header(pcap_t *, bpf_u_int32, FILE *, char *); +extern pcap_t *pcap_check_header(bpf_u_int32 magic, FILE *fp, + u_int precision, char *errbuf, int *err); #endif diff --git a/contrib/libpcap/sockutils.c b/contrib/libpcap/sockutils.c new file mode 100644 index 0000000000..c05ff1a1b5 --- /dev/null +++ b/contrib/libpcap/sockutils.c @@ -0,0 +1,1230 @@ +/* + * 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 "config.h" +#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 /* for strerror() */ +#include /* for the errno variable */ +#include /* for the stderr file */ +#include /* for malloc() and free() */ +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +#include "portability.h" +#include "sockutils.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)" + +/**************************************************** + * * + * Locally defined functions * + * * + ****************************************************/ + +static int sock_ismcastaddr(const struct sockaddr *saddr); + +/**************************************************** + * * + * Function bodies * + * * + ****************************************************/ + +/* + * \brief It retrieves the error message after an error occurred in the socket interface. + * + * This function is defined because of the different way errors are returned in UNIX + * and Win32. This function provides a consistent way to retrieve the error message + * (after a socket error occurred) on all the platforms. + * + * \param caller: a pointer to a user-allocated string which contains a message that has + * to be printed *before* the true error message. It could be, for example, 'this error + * comes from the recv() call at line 31'. It may be NULL. + * + * \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 No return values. The error message is returned in the 'string' parameter. + */ +void sock_geterror(const char *caller, char *errbuf, int errbuflen) +{ +#ifdef _WIN32 + int retval; + int code; + TCHAR message[SOCK_ERRBUF_SIZE]; /* It will be char (if we're using ascii) or wchar_t (if we're using unicode) */ + + if (errbuf == NULL) + return; + + code = GetLastError(); + + retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + message, sizeof(message) / sizeof(TCHAR), NULL); + + if (retval == 0) + { + if ((caller) && (*caller)) + pcap_snprintf(errbuf, errbuflen, "%sUnable to get the exact error message", caller); + else + pcap_snprintf(errbuf, errbuflen, "Unable to get the exact error message"); + return; + } + else + { + if ((caller) && (*caller)) + pcap_snprintf(errbuf, errbuflen, "%s%s (code %d)", caller, message, code); + else + pcap_snprintf(errbuf, errbuflen, "%s (code %d)", message, code); + } +#else + char *message; + + if (errbuf == NULL) + return; + + message = strerror(errno); + + if ((caller) && (*caller)) + pcap_snprintf(errbuf, errbuflen, "%s%s (code %d)", caller, message, errno); + else + pcap_snprintf(errbuf, errbuflen, "%s (code %d)", message, errno); +#endif +} + +/* + * \brief It initializes sockets. + * + * This function is pretty useless on UNIX, since socket initialization is not required. + * However it is required on Win32. In UNIX, this function appears to be completely empty. + * + * \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_init(char *errbuf, int errbuflen) +{ +#ifdef _WIN32 + if (sockcount == 0) + { + WSADATA wsaData; /* helper variable needed to initialize Winsock */ + + if (WSAStartup(MAKEWORD(WINSOCK_MAJOR_VERSION, + WINSOCK_MINOR_VERSION), &wsaData) != 0) + { + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n"); + + WSACleanup(); + + return -1; + } + } + + sockcount++; +#endif + + return 0; +} + +/* + * \brief It deallocates sockets. + * + * This function is pretty useless on UNIX, since socket deallocation is not required. + * However it is required on Win32. In UNIX, this function appears to be completely empty. + * + * \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; + } +} + +/* + * \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 preceeded by the sock_initaddress(). + * + * \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, '0' if some errors occurred. The error message is returned + * in the 'errbuf' variable. + */ +SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen) +{ + SOCKET sock; + + sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); + if (sock == -1) + { + sock_geterror("socket(): ", errbuf, errbuflen); + return -1; + } + + + /* This is a server socket */ + if (server) + { +#ifdef BSD + /* + * Force the use of IPv6-only addresses; in BSD you can accept both v4 and v6 + * connections if you have a "NULL" pointer as the nodename in the getaddrinfo() + * This behavior is not clear in the RFC 2553, so each system implements the + * bind() differently from this point of view + */ + if (addrinfo->ai_family == PF_INET6) + { + int on; + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *)&on, sizeof (int)) == -1) + { + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "setsockopt(IPV6_BINDV6ONLY)"); + return -1; + } + } +#endif + + /* 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_geterror("bind(): ", errbuf, errbuflen); + return -1; + } + + if (addrinfo->ai_socktype == SOCK_STREAM) + if (listen(sock, nconn) == -1) + { + sock_geterror("listen(): ", errbuf, errbuflen); + return -1; + } + + /* server side ended */ + return sock; + } + else /* we're the client */ + { + struct addrinfo *tempaddrinfo; + char *errbufptr; + size_t bufspaceleft; + + tempaddrinfo = addrinfo; + errbufptr = errbuf; + bufspaceleft = errbuflen; + *errbufptr = 0; + + /* + * We have to loop though all the addinfo 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 + */ + while (tempaddrinfo) + { + + if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1) + { + size_t msglen; + char TmpBuffer[100]; + char SocketErrorMessage[SOCK_ERRBUF_SIZE]; + + /* + * We have to retrieve the error message before any other socket call completes, otherwise + * the error message is lost + */ + sock_geterror(NULL, SocketErrorMessage, sizeof(SocketErrorMessage)); + + /* Returns the numeric address of the host that triggered the error */ + sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer)); + + pcap_snprintf(errbufptr, bufspaceleft, + "Is the server properly installed on %s? connect() failed: %s", TmpBuffer, SocketErrorMessage); + + /* In case more then one 'connect' fails, we manage to keep all the error messages */ + msglen = strlen(errbufptr); + + errbufptr[msglen] = ' '; + errbufptr[msglen + 1] = 0; + + bufspaceleft = bufspaceleft - (msglen + 1); + errbufptr += (msglen + 1); + + tempaddrinfo = tempaddrinfo->ai_next; + } + else + break; + } + + /* + * Check how we exit from the previous loop + * If tempaddrinfo is equal to NULL, it means that all the connect() failed. + */ + if (tempaddrinfo == NULL) + { + closesocket(sock); + return -1; + } + else + 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_geterror("shutdown(): ", errbuf, errbuflen); + /* close the socket anyway */ + closesocket(sock); + return -1; + } + + closesocket(sock); + return 0; +} + +/* + * \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; + + retval = getaddrinfo(host, port, hints, addrinfo); + if (retval != 0) + { + /* + * if the getaddrinfo() fails, you have to use gai_strerror(), instead of using the standard + * error routines (errno) in UNIX; Winsock suggests using the GetLastError() instead. + */ + if (errbuf) + { +#ifdef _WIN32 + sock_geterror("getaddrinfo(): ", errbuf, errbuflen); +#else + pcap_snprintf(errbuf, errbuflen, "getaddrinfo() %s", gai_strerror(retval)); +#endif + } + 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) + pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported"); + return -1; + } + + /* + * You can't do multicast (or broadcast) TCP. + */ + if (((*addrinfo)->ai_socktype == SOCK_STREAM) && + (sock_ismcastaddr((*addrinfo)->ai_addr) == 0)) + { + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); + 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 some errors occurred. The error message is returned + * in the 'errbuf' variable. + */ +int sock_send(SOCKET socket, const char *buffer, int size, char *errbuf, int errbuflen) +{ + int nsent; + +send: +#ifdef linux + /* + * Another pain... in Linux there's this flag + * MSG_NOSIGNAL + * Requests not to send SIGPIPE on errors on stream-oriented + * sockets when the other end breaks the connection. + * The EPIPE error is still returned. + */ + nsent = send(socket, buffer, size, MSG_NOSIGNAL); +#else + nsent = send(socket, buffer, size, 0); +#endif + + if (nsent == -1) + { + sock_geterror("send(): ", errbuf, errbuflen); + return -1; + } + + if (nsent != size) + { + size -= nsent; + buffer += nsent; + goto send; + } + + return 0; +} + +/* + * \brief It copies the amount of data contained into 'buffer' into 'tempbuf'. + * and it checks for buffer overflows. + * + * This function basically copies 'size' bytes of data contained into 'buffer' + * into 'tempbuf', 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 'buffer' and 'tempbuf' 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 buffer: a char pointer to a user-allocated buffer that keeps the data + * that has to be copied. + * + * \param size: number of bytes that have to be copied. + * + * \param tempbuf: user-allocated buffer (of size 'totsize') in which data + * has to be copied. + * + * \param offset: an index into 'tempbuf' which keeps the location of its first + * empty location. + * + * \param totsize: total size of the buffer in 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, 'tempbuf' 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 char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen) +{ + if ((*offset + size) > totsize) + { + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer."); + return -1; + } + + if (!checkonly) + memcpy(tempbuf + (*offset), buffer, 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 receiveall: if '0' (or SOCK_RECEIVEALL_NO), it returns as soon as some data + * is ready; otherwise, (or SOCK_RECEIVEALL_YES) it waits until 'size' data has been + * received (in case the socket does not have enough data available). + * + * \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. + */ + +/* + * On UN*X, recv() returns ssize_t. + * On Windows, there *is* no ssize_t, and it returns an int. + * Define ssize_t as int on Windows so we can use it as the return value + * from recv(). + */ +#ifdef _WIN32 +typedef int ssize_t; +#endif + +int sock_recv(SOCKET sock, void *buffer, size_t size, int receiveall, + char *errbuf, int errbuflen) +{ + char *bufp = buffer; + int remaining; + ssize_t nread; + + if (size == 0) + { + SOCK_ASSERT("I have been requested to read zero bytes", 1); + return 0; + } + if (size > INT_MAX) + { + pcap_snprintf(errbuf, errbuflen, "Can't read more than %u bytes with sock_recv", + INT_MAX); + return -1; + } + + bufp = (char *) buffer; + remaining = (int) size; + + /* + * We don't use MSG_WAITALL because it's not supported in + * Win32. + */ + for (;;) { + nread = recv(sock, bufp, remaining, 0); + + if (nread == -1) + { +#ifndef _WIN32 + if (errno == EINTR) + return -3; +#endif + sock_geterror("recv(): ", errbuf, errbuflen); + return -1; + } + + if (nread == 0) + { + if (errbuf) + { + pcap_snprintf(errbuf, errbuflen, + "The other host terminated the connection."); + } + return -1; + } + + /* + * Do we want to read the amount requested, or just return + * what we got? + */ + if (!receiveall) + { + /* + * Just return what we got. + */ + return (int) nread; + } + + bufp += nread; + remaining -= nread; + + if (remaining == 0) + return (int) size; + } +} + +/* + * \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, 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, 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, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1) + return -1; + } + + SOCK_ASSERT("I'm currently discarding data\n", 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; + + /* + * 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_geterror("sock_check_hostlist(), malloc() failed", errbuf, errbuflen); + 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, "0", &hints, &addrinfo); + if (retval != 0) + { + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "getaddrinfo() %s", gai_strerror(retval)); + + SOCK_ASSERT(errbuf, 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); + 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; + } + + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused."); + + free(temphostlist); + 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_geterror("getsockname(): ", errbuf, errbuflen); + return 0; + } + else + { + /* Returns the numeric address of the host that triggered the error */ + return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen); + } + + return 0; +} + +/* + * \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, int 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) + 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_geterror("getnameinfo(): ", errbuf, errbuflen); + errbuf[errbuflen - 1] = 0; + } + + if (address) + { + strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen); + address[addrlen - 1] = 0; + } + + if (port) + { + 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) + pcap_snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned"); + return -2; + } + + freeaddrinfo(addrinfo); + return -1; +} diff --git a/contrib/libpcap/sockutils.h b/contrib/libpcap/sockutils.h new file mode 100644 index 0000000000..f50bbce881 --- /dev/null +++ b/contrib/libpcap/sockutils.h @@ -0,0 +1,241 @@ +/* + * 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 __SOCKUTILS_H__ +#define __SOCKUTILS_H__ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef _WIN32 + /* Windows */ + /* + * Prevents a compiler warning in case this was already defined (to + * avoid that windows.h includes winsock.h) + */ + #ifdef _WINSOCKAPI_ + #undef _WINSOCKAPI_ + #endif + /* Need windef.h for defines used in winsock2.h under MingW32 */ + #ifdef __MINGW32__ + #include + #endif + #include + #include +#else + /* UN*X */ + #include + #include /* for memset() */ + #include + #include + #include /* DNS lookup */ + #include /* close() */ + #include /* errno() */ + #include /* for sockaddr_in, in BSD at least */ + #include + #include + + /*! + * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's + * a file descriptor, and therefore a signed integer. + * We define SOCKET to be a signed integer on UN*X, so that it can + * be used on both platforms. + */ + #ifndef SOCKET + #define SOCKET int + #endif + + /*! + * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; + * in UN*X, it's -1. + * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on + * both platforms. + */ + #ifndef INVALID_SOCKET + #define INVALID_SOCKET -1 + #endif +#endif + +/* + * MingW headers include this definition, but only for Windows XP and above. + * MSDN states that this function is available for most versions on Windows. + */ +#if ((defined(__MINGW32__)) && (_WIN32_WINNT < 0x0501)) +int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, + char*,DWORD,int); +#endif + +/* + * \defgroup SockUtils Cross-platform socket utilities (IPv4-IPv6) + */ + +/* + * \addtogroup SockUtils + * \{ + */ + +/* + * \defgroup ExportedStruct Exported Structures and Definitions + */ + +/* + * \addtogroup ExportedStruct + * \{ + */ + +/* + * Some minor differences between UN*X sockets and and Winsock sockets. + */ +#ifdef _WIN32 + /* + * Winsock doesn't have these UN*X types; they're used in the UN*X + * sockets API. + * + * XXX - do we need to worry about UN*Xes so old that *they* don't + * have them, either? + */ + typedef int socklen_t; +#else + /*! + * \brief In Winsock, the close() call cannot be used on a socket; + * closesocket() must be used. + * We define closesocket() to be a wrapper around close() on UN*X, + * so that it can be used on both platforms. + */ + #define closesocket(a) close(a) +#endif + +/* + * \brief DEBUG facility: it prints an error message on the screen (stderr) + * + * This macro prints the error on the standard error stream (stderr); + * if we are working in debug mode (i.e. there is no NDEBUG defined) and we are in + * Microsoft Visual C++, the error message will appear on the MSVC console as well. + * + * When NDEBUG is defined, this macro is empty. + * + * \param msg: the message you want to print. + * + * \param expr: 'false' if you want to abort the program, 'true' it you want + * to print the message and continue. + * + * \return No return values. + */ +#ifdef NDEBUG + #define SOCK_ASSERT(msg, expr) ((void)0) +#else + #include + #if (defined(_WIN32) && defined(_MSC_VER)) + #include /* for _CrtDbgReport */ + /* Use MessageBox(NULL, msg, "warning", MB_OK)' instead of the other calls if you want to debug a Win32 service */ + /* Remember to activate the 'allow service to interact with desktop' flag of the service */ + #define SOCK_ASSERT(msg, expr) { _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%s\n", msg); fprintf(stderr, "%s\n", msg); assert(expr); } + #else + #define SOCK_ASSERT(msg, expr) { fprintf(stderr, "%s\n", msg); assert(expr); } + #endif +#endif + +/**************************************************** + * * + * Exported functions / definitions * + * * + ****************************************************/ + +/* 'checkonly' flag, into the rpsock_bufferize() */ +#define SOCKBUF_CHECKONLY 1 +/* no 'checkonly' flag, into the rpsock_bufferize() */ +#define SOCKBUF_BUFFERIZE 0 + +/* no 'server' flag; it opens a client socket */ +#define SOCKOPEN_CLIENT 0 +/* 'server' flag; it opens a server socket */ +#define SOCKOPEN_SERVER 1 + +/* Changes the behaviour of the sock_recv(); it does not wait to receive all data */ +#define SOCK_RECEIVEALL_NO 0 +/* Changes the behaviour of the sock_recv(); it waits to receive all data */ +#define SOCK_RECEIVEALL_YES 1 + +/* + * \} + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * \defgroup ExportedFunc Exported Functions + */ + +/* + * \addtogroup ExportedFunc + * \{ + */ + +int sock_init(char *errbuf, int errbuflen); +void sock_cleanup(void); +/* It is 'public' because there are calls (like accept() ) which are not managed from inside the sockutils files */ +void sock_geterror(const char *caller, char *errbuf, int errbufsize); +int sock_initaddress(const char *address, const char *port, + struct addrinfo *hints, struct addrinfo **addrinfo, + char *errbuf, int errbuflen); +int sock_recv(SOCKET socket, void *buffer, size_t size, int receiveall, + char *errbuf, int errbuflen); +SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen); +int sock_close(SOCKET sock, char *errbuf, int errbuflen); + +int sock_send(SOCKET socket, const char *buffer, int size, char *errbuf, int errbuflen); +int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen); +int sock_discard(SOCKET socket, int size, char *errbuf, int errbuflen); +int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen); +int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second); + +int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); + +int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); +int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen); + +#ifdef __cplusplus +} +#endif + +/* + * \} + */ + +/* + * \} + */ + +#endif diff --git a/contrib/libpcap/sunatmpos.h b/contrib/libpcap/sunatmpos.h index 916017fa93..787de85743 100644 --- a/contrib/libpcap/sunatmpos.h +++ b/contrib/libpcap/sunatmpos.h @@ -28,8 +28,6 @@ * 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. - * - * @(#) $Header: /tcpdump/master/libpcap/sunatmpos.h,v 1.1 2002-07-11 09:06:47 guy Exp $ (LBL) */ /* SunATM header for ATM packet */ -- 2.41.0