[initial] Pull libpcap tags/libpcap-1.10.1
Bug: 55476, 84480
Change-Id: I1a0e648381a61abaeb2a0320d2d7405dab60b1ab
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..d01e832
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,254 @@
+This file lists people who have contributed to libpcap.
+
+The current maintainers (in alphabetical order):
+ Denis Ovsienko <denis at ovsienko dot info>
+ Francois-Xavier Le Bail <devel dot fx dot lebail at orange dot fr>
+ Guy Harris <gharris at sonic dot net>
+ Michael Richardson <mcr at sandelman dot ottawa dot on dot ca>
+
+Additional people who have contributed patches (in alphabetical order):
+ Adrian Budau <adbudau at bitdefender dot com>
+ Akos Vandra <axos88 at gmail dot com>
+ Alan Bawden <Alan at LCS dot MIT dot EDU>
+ Albert Chin <china at thewrittenword dot com>
+ Alexander Galanin <al at galanin dot nnov dot ru>
+ Alexander 'Leo' Bergolth <Leo dot Bergolth at wu-wien dot ac dot at>
+ Alexey Kuznetsov <kuznet at ms2 dot inr dot ac dot ru>
+ Alex Smith <44322503+MadAlexUK at users dot noreply dot github dot com>
+ Alfredo Alvarez Fernandez <alfredoalvarezernandez at gmail dot com>
+ Ali Abdulkadir <autostart dot ini at gmail dot com>
+ Alon Bar-Lev <alonbl at sourceforge dot net>
+ Anders Broman <anders dot broman at ericsson dot com>
+ Andres Perera <andres dot p at zoho dot com>
+ Andrew Brown <atatat at atatdot dot net>
+ <andy-1 at sourceforge dot net>
+ Ani Sinha <ani at aristanetworks dot com>
+ Anthony Kirby <Anthony dot Kirby at nominet dot uk>
+ Antti Kantee <pooka at netbsd dot org>
+ Arien Vijn <arienvijn at sourceforge dot net>
+ Arkadiusz Miskiewicz <misiek at pld dot org dot pl>
+ Armando L. Caro Jr. <acaro at mail dot eecis dot udel dot edu>
+ Assar Westerlund <assar at sics dot se>
+ Atzm Watanabe <atzm at atzm dot org>
+ Baptiste Peugnez <baptiste dot peugnez at cea dot fr>
+ Baruch Siach <baruch at tkos dot co dot il>
+ Bill Parker <wp02855 at gmail dot com>
+ blazeable <blazeable at blazeable dot eu>
+ bleader <bleader at ratonland dot org>
+ Brent Cook <brent at boundary dot com>
+ Brian Ginsbach <ginsbach at cray dot com>
+ B. Scott Michel <scooter dot phd at gmail dot com>
+ Cedric Cellier <rixed at happyleptic dot org>
+ Charles M. Hannum <mycroft at netbsd dot org>
+ Chris G. Demetriou <cgd at netbsd dot org>
+ Chris Lightfoot <cwrl at users dot sourceforge dot net>
+ Chris Maynard <Chris dot Maynard at gtech dot com>
+ Chris Pepper <pepper at mail dot reppep dot com>
+ Christian Bell <csbell at myri dot com>
+ Christian Peron <csjp at freebsd dot org>
+ Christian Svensson <blue at cmd dot nu>
+ Christopher K Lee <christopher dot lee at cspi dot com>
+ Daniel Borkmann <dborkman at redhat dot com>
+ Daniele Orlandi <daniele at orlandi dot com>
+ Daniel Lublin <daniel at lublin dot se>
+ Daniel Miller <dmiller at nmap dot org>
+ Dario Lombardo <lomato at gmail dot com>
+ Darren Lim <darren dot lim at endace dot com>
+ Darren Reed <darrenr at sun dot com>
+ Dave Barach <dave at barachs dot net>
+ David Clark <david dot clark at datasoft dot com>
+ David Kaelbling <drk at sgi dot com>
+ David Ward <david dot ward at ll dot mit dot edu>
+ David Young <dyoung at ojctech dot com>
+ Dean Gaudet <dean at arctic dot org>
+ dhruv <rsrivat at sourceforge dot net>
+ Dmytro Ovdiienko <dmitriy dot ovdienko at gmail dot com>
+ Don Ebright <Don dot Ebright at compuware dot com>
+ Dug Song <dugsong at monkey dot org>
+ Dustin Spicuzza <dustin at virtualroadside dot com>
+ dzejarczech <dzejarczech at sourceforge dot net>
+ Edward Sheldrake <ejs1920 at sourceforge dot net>
+ Eric Anderson <anderse at hpl dot hp dot com>
+ Erik de Castro Lopo <erik dot de dot castro dot lopo at sensorynetworks dot com>
+ Fedor Sakharov <fedor dot sakharov at gmail dot com>
+ Felix Janda <felix dot janda at posteo dot de>
+ Felix Obenhuber <felix at obenhuber dot de>
+ Florent Drouin <Florent dot Drouin at alcatel-lucent dot fr>
+ Florian Fainelli <f dot fainelli at gmail dot com>
+ François Revol <revol at free dot fr>
+ Franz Schaefer <schaefer at mond dot at>
+ frederich <frederich at sourceforge dot net>
+ Fulko Hew <fulko dot hew at gmail dot com>
+ Fumiyuki Shimizu <fumifumi at abacustech dot jp>
+ Gabor Tatarka <gabor dot tatarka at ericsson dot com>
+ Garrett Cooper <yaberauneya at sourceforge dot net>
+ George Neville-Neil <gnn at freebsd dot org>
+ Gerald Combs <gerald at zing dot org>
+ Gerard Garcia <nouboh at gmail dot com>
+ Gianluca Varenni <gianluca dot varenni at gmail dot com>
+ Gilbert Hoyek <gil_hoyek at hotmail dot com>
+ Gisle Vanem <gvanem at yahoo dot no>
+ Graeme Hewson <ghewson at cix dot compulink dot co dot uk>
+ Gregor Maier <gregor at net dot in dot tum dot de>
+ Greg Stark <gsstark at mit dot edu>
+ Greg Troxel <gdt at ir dot bbn dot com>
+ Guillaume Pelat <endymion_ at users dot sourceforge dot net>
+ Gustavo Zacarias <gustavo at zacarias dot com dot ar>
+ Hagen Paul Pfeifer <hagen at jauu dot net>
+ Henri Doreau <hdoreau at sourceforge dot net>
+ Hiroaki KAWAI <kawai at stratosphere dot co dot jp>
+ Hyung Sik Yoon <hsyn at kr dot ibm dot com>
+ Igor Khristophorov <igor at atdot dot org>
+ Jakub Sitnicki <jsitnicki at gmail dot com>
+ Jakub Zawadzki <darkjames at darkjames dot pl>
+ James Ko <jck at exegin dot com>
+ Jan-Philip Velders <jpv at veldersjes dot net>
+ Jason R. Thorpe <thorpej at netbsd dot org>
+ Javier Achirica <achirica at ttd dot net>
+ Jean-Louis Charton <Jean-Louis dot CHARTON at oikialog dot com>
+ Jean Tourrilhes <jt at hpl dot hp dot com>
+ Jefferson Ogata <jogata at nodc dot noaa dot gov>
+ Jerome Duval <jerome dot duval at gmail dot com>
+ Jesper Dangaard Brouer <hawk at comx dot dk>
+ Jesper Peterson <jesper at endace dot com>
+ Jesse Gross <jesse at nicira dot com>
+ JHA <jon dot anderson at oracle dot com>
+ jingyu yang <jingleyang at users dot noreply dot github dot com>
+ Jiri Slaby <jirislaby at gmail dot com>
+ João Valverde <joao dot valverde at tecnico dot ulisboa dot pt>
+ Joerg Mayer <jmayer at loplof dot de>
+ John Bankier <jbankier at rainfinity dot com>
+ Jon Lindgren <jonl at yubyub dot net>
+ Jon Smirl <jonsmirl at gmail dot com>
+ Jorge Boncompte [DTI2] <jorge at dti2 dot net>
+ jromanr <jromanr at hotmail dot com>
+ Juergen Schoenwaelder <schoenw at ibr dot cs dot tu-bs dot de>
+ Julien Moutinho <julm at savines dot alpes dot fr dot eu dot org>
+ Jung-uk Kim <jkim at FreeBSD dot org>
+ Kazushi Sugyo <sugyo at pb dot jp dot nec dot com>
+ Kevin Boulain <kevin dot boulain at securactive dot net>
+ Klaus Klein <kleink at netbsd dot org>
+ Koryn Grant <koryn at endace dot com>
+ Kris Katterjohn <katterjohn at gmail dot com>
+ Krzysztof Halasa <khc at pm dot waw dot pl>
+ Lennert Buytenhek <buytenh at wantstofly dot org>
+ lixiaoyan <lixiaoyan at google dot com>
+ Lorenzo Cavallaro <sullivan at sikurezza dot org>
+ Loris Degioanni <loris at netgroup-serv dot polito dot it>
+ Love Hörnquist-Åstrand <lha at stacken dot kth dot se>
+ Luis MartinGarcia <luis dot mgarc at gmail dot com>
+ lxy <391861737 at qq dot com>
+ Maciej W. Rozycki <macro at ds2 dot pg dot gda dot pl>
+ Mansour Behabadi <mansour at oxplot dot com>
+ Marcus Felipe Pereira <marcus at task dot com dot br>
+ Mario J. Rugiero <mrugiero at gmail dot com>
+ Mark C. Brown <mbrown at hp dot com>
+ Mark Johnston <markjdb at gmail dot com>
+ Mark Marshall <mark dot marshall at omicronenergy dot com>
+ Mark Pizzolato <List-tcpdump-workers at subscriptions dot pizzolato dot net>
+ Markus Mayer <markus_mayer at sourceforge dot net>
+ Martin Husemann <martin at netbsd dot org>
+ Márton Németh <nm127 at freemail dot hu>
+ Matt Eaton <agnosticdev at gmail dot com>
+ Matthew Luckie <mjl at luckie dot org dot nz>
+ Matthias Hannig <matthias at hannig dot cc>
+ Matwey V. Kornilov <matwey dot kornilov at gmail dot com>
+ maxice8 <thinkabit dot ukim at gmail dot com>
+ Max Laier <max at love2party dot net>
+ Michal Kubecek <mkubecek at suse dot cz>
+ Michal Labedzki <michal dot labedzki at tieto dot com>
+ Michal Sekletar <msekleta at redhat dot com>
+ Mike Frysinger <vapier at gmail dot com>
+ Mike Kershaw <dragorn at kismetwireless dot net>
+ Mike Wiacek <mike at iroot dot net>
+ Milosz Kaniewski <milosz dot kaniewski at gmail dot com>
+ Miroslav Lichvar <mlichvar at redhat dot com>
+ Monroe Williams <monroe at pobox dot com>
+ Myricom Help <myri at users dot noreply dot github dot com>
+ Nan Xiao <nan at chinadtrace dot org>
+ Nick Kelsey <nickk at silicondust dot com>
+ Nicolas Dade <ndade at nsd dot dyndns dot org>
+ Niko Delarich <niko dot delarich at gmail dot com>
+ N. Leiten <nleiten at sourceforge dot net>
+ nnposter <nnposter at users dot noreply dot github dot com>
+ <nvercamm at sourceforge dot net>
+ Octavian Cerna <tavy at ylabs dot com>
+ Olaf Kirch <okir at caldera dot de>
+ Ollie Wild <aaw at users dot sourceforge dot net>
+ Ondřej Hošek <ondra dot hosek at gmail dot com>
+ Onno van der Linden <onno at simplex dot nl>
+ Orgad Shaneh <orgad dot shaneh at audiocodes dot com>
+ Ørjan Malde <red at foxi dot me>
+ Paolo Abeni <pabeni at redhat dot com>
+ Patrick Marie <mycroft at virgaria dot org>
+ Patrick McHardy <kaber at trash not net>
+ Paul Mundt <lethal at linux-sh dot org>
+ Pavel Kankovsky <kan at dcit dot cz>
+ Pawel Brzezinski <pawel dot brzezinski at harman dot com>
+ Pawel Pokrywka <publicpp at gmail dot com>
+ Peter Fales <peter at fales-lorenz dot net>
+ Peter Jeremy <peter dot jeremy at alcatel dot com dot au>
+ Peter Volkov <pva at gentoo dot org>
+ Petr Vorel <pvorel at suse dot cz>
+ Philippe Antoine <contact at catenacyber dot fr>
+ Phil Wood <cpw at lanl dot gov>
+ Rafal Maszkowski <rzm at icm dot edu dot pl>
+ <rcb-isis at users dot sourceforge dot net>
+ Richard Stearn <richard at rns-stearn dot demon dot co dot uk>
+ Rick Jones <raj at cup dot hp dot com>
+ Robert Edmonds <stu-42 at sourceforge dot net>
+ Roberto Mariani <jelot-tcpdump at jelot dot it>
+ Roland Dreier <roland at purestorage dot com>
+ Romain Francoise <rfrancoise at debian dot org>
+ Rongxi Li <rongxi dot li at chaitin dot com>
+ Sagun Shakya <sagun dot shakya at sun dot com>
+ Scott Barron <sb125499 at ohiou dot edu>
+ Scott Gifford <sgifford at tir dot com>
+ Scott Mcmillan <scott dot a dot mcmillan at intel dot com>
+ Sebastian Krahmer <krahmer at cs dot uni-potsdam dot de>
+ Sebastien Roy <Sebastien dot Roy at Sun dot COM>
+ Sepherosa Ziehau <sepherosa at gmail dot com>
+ Shaun Clowes <delius at progsoc dot uts dot edu dot au>
+ solofox <wensg100 at sina dot com>
+ Solomon Peachy <pizza at shaftnet dot org>
+ Stefan Hudson <hudson at mbay dot net>
+ Stephen Donnelly <stephen at endace dot com>
+ Steve Karg <skarg at users dot sourceforge dot net>
+ stubbfel <stubbfel at gmail dot com>
+ Takashi Yamamoto <yamt at mwd dot biglobe dot ne dot jp>
+ Tanaka Shin-ya <zstanaka at archer dot livedoor dot com>
+ Thomas Habets <habets at google dot com>
+ Thomas Petazzoni <thomas dot petazzoni at free-electrons dot com>
+ Tobias Poschwatta <posch at sourceforge dot net>
+ Tomasz Moń <desowin at gmail dot com>
+ Tommy Beadle <tbeadle at arbor dot net>
+ Tony Li <tli at procket dot com>
+ Torsten Landschoff <torsten at debian dot org>
+ Tymoteusz Blazejczyk <tymoteusz dot blazejczyk at intel dot com>
+ Uns Lider <unslider at miranda dot org>
+ Uwe Girlich <Uwe dot Girlich at philosys dot de>
+ Vitaly Lavrov <vel21ripn at gmail dot com>
+ Vivien Didelot <vivien dot didelot at gmail dot com>
+ Vladimir Gladkov <vovkos at gmail dot com>
+ Vladimir Marek <vlmarek at volny dot cz>
+ Walter Schell <walterschell at users dot noreply dot github dot com>
+ Wesley Shields <wxs at FreeBSD dot org>
+ Xianjie Zhang <xzhang at cup dot hp dot com>
+ Xin Li <delphij at FreeBSD dot org>
+ Xue Jiang Qing <xuejianqing at star-net dot cn>
+ Yang Luo <hsluoyz at qq dot com>
+ Yen Yen Lim
+ Yoann Vandoorselaere <yoann at prelude-ids dot org>
+ Yogesh Prasad <yogesh dot prasad at rockwellcollins dot com>
+ Yvan Vanhullebus <vanhu at sourceforge dot net>
+
+The original LBL crew:
+ Steve McCanne
+ Craig Leres
+ Van Jacobson
+
+Past maintainers (in alphabetical order):
+ Bill Fenner <fenner at research dot att dot com>
+ Fulvio Risso <risso at polito dot it>
+ Hannes Gredler <hannes at gredler dot at>
+ Jun-ichiro itojun Hagino <itojun at iijlab dot net> Also see: http://www.wide.ad.jp/itojun-award/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a10474d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+License: BSD
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d89e3bb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# LIBPCAP 1.x.y by [The Tcpdump Group](https://www.tcpdump.org)
+
+**To report a security issue please send an e-mail to security@tcpdump.org.**
+
+To report bugs and other problems, contribute patches, request a
+feature, provide generic feedback etc please see the
+[guidelines for contributing](CONTRIBUTING.md).
+
+The [documentation directory](doc/) has README files about specific
+operating systems and options.
+
+Anonymous Git is available via:
+
+ https://github.com/the-tcpdump-group/libpcap.git
+
+This directory contains source code for libpcap, a system-independent
+interface for user-level packet capture. libpcap provides a portable
+framework for low-level network monitoring. Applications include
+network statistics collection, security monitoring, network debugging,
+etc. Since almost every system vendor provides a different interface
+for packet capture, and since we've developed several tools that
+require this functionality, we've created this system-independent API
+to ease in porting and to alleviate the need for several
+system-dependent packet capture modules in each application.
+
+```text
+formerly from Lawrence Berkeley National Laboratory
+ Network Research Group <libpcap@ee.lbl.gov>
+ ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z
+```
+
+### Support for particular platforms and BPF
+For some platforms there are `README.{system}` files that discuss issues
+with the OS's interface for packet capture on those platforms, such as
+how to enable support for that interface in the OS, if it's not built in
+by default.
+
+The libpcap interface supports a filtering mechanism based on the
+architecture in the BSD packet filter. BPF is described in the 1993
+Winter Usenix paper ``The BSD Packet Filter: A New Architecture for
+User-level Packet Capture''
+([compressed PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.Z),
+[gzipped PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.gz),
+[PDF](https://www.tcpdump.org/papers/bpf-usenix93.pdf)).
+
+Although most packet capture interfaces support in-kernel filtering,
+libpcap utilizes in-kernel filtering only for the BPF interface.
+On systems that don't have BPF, all packets are read into user-space
+and the BPF filters are evaluated in the libpcap library, incurring
+added overhead (especially, for selective filters). Ideally, libpcap
+would translate BPF filters into a filter program that is compatible
+with the underlying kernel subsystem, but this is not yet implemented.
+
+BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly
+BSD, and macOS; an older, modified and undocumented version is standard
+in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the packetfilter
+interface but has been extended to accept BPF filters (which libpcap
+utilizes). Also, you can add BPF filter support to Ultrix using the
+kernel source and/or object patches available
+[here](https://www.tcpdump.org/other/bpfext42.tar.Z).
+
+Linux has a number of BPF based systems, and libpcap does not support
+any of the eBPF mechanisms as yet, although it supports many of the
+memory mapped receive mechanisms.
+See the [Linux-specific README](doc/README.linux) for more information.
+
+### Note to Linux distributions and *BSD systems that include libpcap:
+
+There's now a rule to make a shared library, which should work on Linux
+and *BSD, among other platforms.
+
+It sets the soname of the library to `libpcap.so.1`; this is what it
+should be, **NOT** `libpcap.so.1.x` or `libpcap.so.1.x.y` or something such as
+that.
+
+We've been maintaining binary compatibility between libpcap releases for
+quite a while; there's no reason to tie a binary linked with libpcap to
+a particular release of libpcap.
diff --git a/arcnet.h b/arcnet.h
new file mode 100644
index 0000000..5869098
--- /dev/null
+++ b/arcnet.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
+ */
+
+/* RFC 1051 */
+#define ARCTYPE_IP_OLD 240 /* IP protocol */
+#define ARCTYPE_ARP_OLD 241 /* address resolution protocol */
+
+/* RFC 1201 */
+#define ARCTYPE_IP 212 /* IP protocol */
+#define ARCTYPE_ARP 213 /* address resolution protocol */
+#define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */
+
+#define ARCTYPE_ATALK 221 /* Appletalk */
+#define ARCTYPE_BANIAN 247 /* Banyan Vines */
+#define ARCTYPE_IPX 250 /* Novell IPX */
+
+#define ARCTYPE_INET6 0xc4 /* IPng */
+#define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */
diff --git a/atmuni31.h b/atmuni31.h
new file mode 100644
index 0000000..7d4f270
--- /dev/null
+++ b/atmuni31.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * 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 Yen Yen Lim and
+ North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Based on UNI3.1 standard by ATM Forum */
+
+/* ATM traffic types based on VPI=0 and (the following VCI */
+#define VCI_PPC 0x05 /* Point-to-point signal msg */
+#define VCI_BCC 0x02 /* Broadcast signal msg */
+#define VCI_OAMF4SC 0x03 /* Segment OAM F4 flow cell */
+#define VCI_OAMF4EC 0x04 /* End-to-end OAM F4 flow cell */
+#define VCI_METAC 0x01 /* Meta signal msg */
+#define VCI_ILMIC 0x10 /* ILMI msg */
+
+/* Q.2931 signalling messages */
+#define CALL_PROCEED 0x02 /* call proceeding */
+#define CONNECT 0x07 /* connect */
+#define CONNECT_ACK 0x0f /* connect_ack */
+#define SETUP 0x05 /* setup */
+#define RELEASE 0x4d /* release */
+#define RELEASE_DONE 0x5a /* release_done */
+#define RESTART 0x46 /* restart */
+#define RESTART_ACK 0x4e /* restart ack */
+#define STATUS 0x7d /* status */
+#define STATUS_ENQ 0x75 /* status ack */
+#define ADD_PARTY 0x80 /* add party */
+#define ADD_PARTY_ACK 0x81 /* add party ack */
+#define ADD_PARTY_REJ 0x82 /* add party rej */
+#define DROP_PARTY 0x83 /* drop party */
+#define DROP_PARTY_ACK 0x84 /* drop party ack */
+
+/* Information Element Parameters in the signalling messages */
+#define CAUSE 0x08 /* cause */
+#define ENDPT_REF 0x54 /* endpoint reference */
+#define AAL_PARA 0x58 /* ATM adaptation layer parameters */
+#define TRAFF_DESCRIP 0x59 /* atm traffic descriptors */
+#define CONNECT_ID 0x5a /* connection identifier */
+#define QOS_PARA 0x5c /* quality of service parameters */
+#define B_HIGHER 0x5d /* broadband higher layer information */
+#define B_BEARER 0x5e /* broadband bearer capability */
+#define B_LOWER 0x5f /* broadband lower information */
+#define CALLING_PARTY 0x6c /* calling party number */
+#define CALLED_PARTY 0x70 /* called party nmber */
+
+#define Q2931 0x09
+
+/* Q.2931 signalling general messages format */
+#define PROTO_POS 0 /* offset of protocol discriminator */
+#define CALL_REF_POS 2 /* offset of call reference value */
+#define MSG_TYPE_POS 5 /* offset of message type */
+#define MSG_LEN_POS 7 /* offset of message length */
+#define IE_BEGIN_POS 9 /* offset of first information element */
+
+/* format of signalling messages */
+#define TYPE_POS 0
+#define LEN_POS 2
+#define FIELD_BEGIN_POS 4
diff --git a/bpf_dump.c b/bpf_dump.c
new file mode 100644
index 0000000..a9c9116
--- /dev/null
+++ b/bpf_dump.c
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap.h>
+#include <stdio.h>
+
+#include "optimize.h"
+
+void
+bpf_dump(const struct bpf_program *p, int option)
+{
+ const struct bpf_insn *insn;
+ int i;
+ int n = p->bf_len;
+
+ insn = p->bf_insns;
+ if (option > 2) {
+ printf("%d\n", n);
+ for (i = 0; i < n; ++insn, ++i) {
+ printf("%u %u %u %u\n", insn->code,
+ insn->jt, insn->jf, insn->k);
+ }
+ return ;
+ }
+ if (option > 1) {
+ for (i = 0; i < n; ++insn, ++i)
+ printf("{ 0x%x, %d, %d, 0x%08x },\n",
+ insn->code, insn->jt, insn->jf, insn->k);
+ return;
+ }
+ for (i = 0; i < n; ++insn, ++i) {
+#ifdef BDEBUG
+ if (i < NBIDS && bids[i] > 0)
+ printf("[%02d]", bids[i] - 1);
+ else
+ printf(" -- ");
+#endif
+ puts(bpf_image(insn, i));
+ }
+}
diff --git a/bpf_filter.c b/bpf_filter.c
new file mode 100644
index 0000000..8691d0d
--- /dev/null
+++ b/bpf_filter.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.c 7.5 (Berkeley) 7/15/91
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+#include "pcap-types.h"
+#include "extract.h"
+#include "diag-control.h"
+
+#define EXTRACT_SHORT EXTRACT_BE_U_2
+#define EXTRACT_LONG EXTRACT_BE_U_4
+
+#ifndef _WIN32
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#endif /* _WIN32 */
+
+#include <pcap-int.h>
+
+#include <stdlib.h>
+
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#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 <ani@arista.com> for providing initial implementation
+ */
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+u_int
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+ u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data)
+#else
+u_int
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+ u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data _U_)
+#endif
+{
+ register uint32_t A, X;
+ register bpf_u_int32 k;
+ uint32_t mem[BPF_MEMWORDS];
+
+ if (pc == 0)
+ /*
+ * No filter means accept all.
+ */
+ return (u_int)-1;
+ A = 0;
+ X = 0;
+ --pc;
+ for (;;) {
+ ++pc;
+ switch (pc->code) {
+
+ default:
+ abort();
+ case BPF_RET|BPF_K:
+ return (u_int)pc->k;
+
+ case BPF_RET|BPF_A:
+ return (u_int)A;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = pc->k;
+ if (k > buflen || sizeof(int32_t) > buflen - k) {
+ return 0;
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = pc->k;
+ if (k > buflen || sizeof(int16_t) > buflen - k) {
+ return 0;
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ /*
+ * Yes, we know, this switch doesn't do
+ * anything unless we're building for
+ * a Linux kernel with removed VLAN
+ * tags available as meta-data.
+ */
+DIAG_OFF_DEFAULT_ONLY_SWITCH
+ switch (pc->k) {
+
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+ case SKF_AD_OFF + SKF_AD_VLAN_TAG:
+ if (!aux_data)
+ return 0;
+ A = aux_data->vlan_tag;
+ break;
+
+ case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
+ if (!aux_data)
+ return 0;
+ A = aux_data->vlan_tag_present;
+ break;
+#endif
+ default:
+ k = pc->k;
+ if (k >= buflen) {
+ return 0;
+ }
+ A = p[k];
+ break;
+ }
+DIAG_ON_DEFAULT_ONLY_SWITCH
+ continue;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = wirelen;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = wirelen;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + pc->k;
+ if (pc->k > buflen || X > buflen - pc->k ||
+ sizeof(int32_t) > buflen - k) {
+ return 0;
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + pc->k;
+ if (X > buflen || pc->k > buflen - X ||
+ sizeof(int16_t) > buflen - k) {
+ return 0;
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + pc->k;
+ if (pc->k >= buflen || X >= buflen - pc->k) {
+ return 0;
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ k = pc->k;
+ if (k >= buflen) {
+ return 0;
+ }
+ X = (p[pc->k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = pc->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = pc->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[pc->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[pc->k];
+ continue;
+
+ case BPF_ST:
+ mem[pc->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[pc->k] = X;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ /*
+ * XXX - we currently implement "ip6 protochain"
+ * with backward jumps, so sign-extend pc->k.
+ */
+ pc += (bpf_int32)pc->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if (X == 0)
+ return 0;
+ 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;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_XOR|BPF_X:
+ A ^= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ if (X < 32)
+ A <<= X;
+ else
+ A = 0;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ if (X < 32)
+ A >>= X;
+ else
+ A = 0;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += pc->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ 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;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ 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;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ /*
+ * Most BPF arithmetic is unsigned, but negation
+ * can't be unsigned; respecify it as subtracting
+ * the accumulator from 0U, so that 1) we don't
+ * get compiler warnings about negating an unsigned
+ * value and 2) don't get UBSan warnings about
+ * the result of negating 0x80000000 being undefined.
+ */
+ A = (0U - A);
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+ }
+ }
+}
+
+u_int
+pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+ u_int buflen)
+{
+ return pcap_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
+ * code, that memory accesses are within valid ranges (to the
+ * extent that this can be checked statically; loads of packet
+ * data have to be, and are, also checked at run time), and that
+ * the code terminates with either an accept or reject.
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+pcap_validate_filter(const struct bpf_insn *f, int len)
+{
+ u_int i, from;
+ const struct bpf_insn *p;
+
+ if (len < 1)
+ return 0;
+
+ for (i = 0; i < (u_int)len; ++i) {
+ p = &f[i];
+ switch (BPF_CLASS(p->code)) {
+ /*
+ * Check that memory operations use valid addresses.
+ */
+ case BPF_LD:
+ case BPF_LDX:
+ switch (BPF_MODE(p->code)) {
+ case BPF_IMM:
+ break;
+ case BPF_ABS:
+ case BPF_IND:
+ case BPF_MSH:
+ /*
+ * There's no maximum packet data size
+ * in userland. The runtime packet length
+ * check suffices.
+ */
+ break;
+ case BPF_MEM:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_LEN:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_ST:
+ case BPF_STX:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_ALU:
+ switch (BPF_OP(p->code)) {
+ case BPF_ADD:
+ case BPF_SUB:
+ 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 or modulus
+ * by 0.
+ */
+ if (BPF_SRC(p->code) == BPF_K && p->k == 0)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_JMP:
+ /*
+ * Check that jumps are within the code block,
+ * and that unconditional branches don't go
+ * backwards as a result of an overflow.
+ * Unconditional branches have a 32-bit offset,
+ * so they could overflow; we check to make
+ * sure they don't. Conditional branches have
+ * an 8-bit offset, and the from address is <=
+ * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
+ * is sufficiently small that adding 255 to it
+ * won't overflow.
+ *
+ * We know that len is <= BPF_MAXINSNS, and we
+ * assume that BPF_MAXINSNS is < the maximum size
+ * of a u_int, so that i + 1 doesn't overflow.
+ *
+ * For userland, we don't know that the from
+ * or len are <= BPF_MAXINSNS, but we know that
+ * from <= len, and, except on a 64-bit system,
+ * it's unlikely that len, if it truly reflects
+ * the size of the program we've been handed,
+ * will be anywhere near the maximum size of
+ * a u_int. We also don't check for backward
+ * branches, as we currently support them in
+ * userland for the protochain operation.
+ */
+ from = i + 1;
+ switch (BPF_OP(p->code)) {
+ case BPF_JA:
+ if (from + p->k >= (u_int)len)
+ return 0;
+ break;
+ case BPF_JEQ:
+ case BPF_JGT:
+ case BPF_JGE:
+ case BPF_JSET:
+ if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)len)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_RET:
+ break;
+ case BPF_MISC:
+ break;
+ default:
+ return 0;
+ }
+ }
+ return BPF_CLASS(f[len - 1].code) == BPF_RET;
+}
+
+/*
+ * Exported because older versions of libpcap exported them.
+ */
+u_int
+bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+ u_int buflen)
+{
+ return pcap_filter(pc, p, wirelen, buflen);
+}
+
+int
+bpf_validate(const struct bpf_insn *f, int len)
+{
+ return pcap_validate_filter(f, len);
+}
diff --git a/bpf_image.c b/bpf_image.c
new file mode 100644
index 0000000..e48c76d
--- /dev/null
+++ b/bpf_image.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+/*
+ * We want our versions of these #defines, not Linux's version.
+ * (The two should be the same; if not, we have a problem; all BPF
+ * implementations *should* be source-compatible supersets of ours.)
+ */
+#undef BPF_STMT
+#undef BPF_JUMP
+#endif
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef SKF_AD_OFF
+/*
+ * Symbolic names for offsets that refer to the special Linux BPF locations.
+ */
+static const char *offsets[SKF_AD_MAX] = {
+#ifdef SKF_AD_PROTOCOL
+ [SKF_AD_PROTOCOL] = "proto",
+#endif
+#ifdef SKF_AD_PKTTYPE
+ [SKF_AD_PKTTYPE] = "type",
+#endif
+#ifdef SKF_AD_IFINDEX
+ [SKF_AD_IFINDEX] = "ifidx",
+#endif
+#ifdef SKF_AD_NLATTR
+ [SKF_AD_NLATTR] = "nla",
+#endif
+#ifdef SKF_AD_NLATTR_NEST
+ [SKF_AD_NLATTR_NEST] = "nlan",
+#endif
+#ifdef SKF_AD_MARK
+ [SKF_AD_MARK] = "mark",
+#endif
+#ifdef SKF_AD_QUEUE
+ [SKF_AD_QUEUE] = "queue",
+#endif
+#ifdef SKF_AD_HATYPE
+ [SKF_AD_HATYPE] = "hatype",
+#endif
+#ifdef SKF_AD_RXHASH
+ [SKF_AD_RXHASH] = "rxhash",
+#endif
+#ifdef SKF_AD_CPU
+ [SKF_AD_CPU] = "cpu",
+#endif
+#ifdef SKF_AD_ALU_XOR_X
+ [SKF_AD_ALU_XOR_X] = "xor_x",
+#endif
+#ifdef SKF_AD_VLAN_TAG
+ [SKF_AD_VLAN_TAG] = "vlan_tci",
+#endif
+#ifdef SKF_AD_VLAN_TAG_PRESENT
+ [SKF_AD_VLAN_TAG_PRESENT] = "vlanp",
+#endif
+#ifdef SKF_AD_PAY_OFFSET
+ [SKF_AD_PAY_OFFSET] = "poff",
+#endif
+#ifdef SKF_AD_RANDOM
+ [SKF_AD_RANDOM] = "random",
+#endif
+#ifdef SKF_AD_VLAN_TPID
+ [SKF_AD_VLAN_TPID] = "vlan_tpid"
+#endif
+};
+#endif
+
+static void
+bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p)
+{
+#ifdef SKF_AD_OFF
+ const char *sym;
+
+ /*
+ * It's an absolute load.
+ * Is the offset a special Linux offset that we know about?
+ */
+ if (p->k >= (bpf_u_int32)SKF_AD_OFF &&
+ p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) &&
+ (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) {
+ /*
+ * Yes. Print the offset symbolically.
+ */
+ (void)snprintf(buf, bufsize, "[%s]", sym);
+ } else
+#endif
+ (void)snprintf(buf, bufsize, "[%d]", p->k);
+}
+
+char *
+bpf_image(const struct bpf_insn *p, int n)
+{
+ const char *op;
+ static char image[256];
+ char operand_buf[64];
+ const char *operand;
+
+ switch (p->code) {
+
+ default:
+ op = "unimp";
+ (void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
+ operand = operand_buf;
+ break;
+
+ case BPF_RET|BPF_K:
+ op = "ret";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_RET|BPF_A:
+ op = "ret";
+ operand = "";
+ break;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ op = "ld";
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ op = "ldh";
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ op = "ldb";
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ op = "ld";
+ operand = "#pktlen";
+ break;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ op = "ld";
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ op = "ldh";
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ op = "ldb";
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_IMM:
+ op = "ld";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ op = "ldx";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ op = "ldxb";
+ (void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LD|BPF_MEM:
+ op = "ld";
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ op = "ldx";
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ST:
+ op = "st";
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_STX:
+ op = "stx";
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JA:
+ op = "ja";
+ (void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ op = "jgt";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ op = "jge";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ op = "jeq";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ op = "jset";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ op = "jgt";
+ operand = "x";
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ op = "jge";
+ operand = "x";
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ op = "jeq";
+ operand = "x";
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ op = "jset";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ op = "add";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ op = "sub";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ op = "mul";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ op = "div";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_MOD|BPF_X:
+ op = "mod";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ op = "and";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ op = "or";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_XOR|BPF_X:
+ op = "xor";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ op = "lsh";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = "rsh";
+ operand = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ op = "add";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ op = "sub";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ op = "mul";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ op = "div";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_MOD|BPF_K:
+ op = "mod";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ op = "and";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ op = "or";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_XOR|BPF_K:
+ op = "xor";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ op = "lsh";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = "rsh";
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ operand = operand_buf;
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ op = "neg";
+ operand = "";
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ op = "tax";
+ operand = "";
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ op = "txa";
+ operand = "";
+ break;
+ }
+ if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) {
+ (void)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,
+ "(%03d) %-8s %s",
+ n, op, operand);
+ }
+ return image;
+}
diff --git a/charconv.h b/charconv.h
new file mode 100644
index 0000000..a37d424
--- /dev/null
+++ b/charconv.h
@@ -0,0 +1,44 @@
+/* -*- 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 charonv_h
+#define charonv_h
+
+#ifdef _WIN32
+extern wchar_t *cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags);
+extern char *utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string);
+extern void utf_8_to_acp_truncated(char *);
+#endif
+
+#endif
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..a1e371a
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,371 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if arpa/inet.h declares `ether_hostton' */
+#undef ARPA_INET_H_DECLARES_ETHER_HOSTTON
+
+/* Enable optimizer debugging */
+#undef BDEBUG
+
+/* Define to 1 if remote packet capture is to be supported */
+#undef ENABLE_REMOTE
+
+/* define if we have the AIX getnetbyname_r() */
+#undef HAVE_AIX_GETNETBYNAME_R
+
+/* define if we have the AIX getprotobyname_r() */
+#undef HAVE_AIX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the <config/HaikuConfig.h> header file. */
+#undef HAVE_CONFIG_HAIKUCONFIG_H
+
+/* Define to 1 if you have the <dagapi.h> header file. */
+#undef HAVE_DAGAPI_H
+
+/* define if you have the DAG API */
+#undef HAVE_DAG_API
+
+/* define if you have dag_get_erf_types() */
+#undef HAVE_DAG_GET_ERF_TYPES
+
+/* define if you have dag_get_stream_erf_types() */
+#undef HAVE_DAG_GET_STREAM_ERF_TYPES
+
+/* define if you have large streams capable DAG API */
+#undef HAVE_DAG_LARGE_STREAMS_API
+
+/* define if you have vdag_set_device_info() */
+#undef HAVE_DAG_VDAG
+
+/* Define to 1 if you have the declaration of `ether_hostton' */
+#undef HAVE_DECL_ETHER_HOSTTON
+
+/* Define to 1 if `dl_module_id_1' is a member of `dl_hp_ppa_info_t'. */
+#undef HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1
+
+/* Define to 1 if the system has the type `dl_passive_req_t'. */
+#undef HAVE_DL_PASSIVE_REQ_T
+
+/* Define to 1 if you have the `ether_hostton' function. */
+#undef HAVE_ETHER_HOSTTON
+
+/* Define to 1 if you have the `ffs' function. */
+#undef HAVE_FFS
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `getspnam' function. */
+#undef HAVE_GETSPNAM
+
+/* Define to 1 if you have a GNU-style `strerror_r' function. */
+#undef HAVE_GNU_STRERROR_R
+
+/* on HP-UX 10.20 or later */
+#undef HAVE_HPUX10_20_OR_LATER
+
+/* on HP-UX 9.x */
+#undef HAVE_HPUX9
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `dag' library (-ldag). */
+#undef HAVE_LIBDAG
+
+/* if libdlpi exists */
+#undef HAVE_LIBDLPI
+
+/* if libnl exists */
+#undef HAVE_LIBNL
+
+/* Define to 1 if you have the <linux/compiler.h> header file. */
+#undef HAVE_LINUX_COMPILER_H
+
+/* define if we have the Linux getnetbyname_r() */
+#undef HAVE_LINUX_GETNETBYNAME_R
+
+/* define if we have the Linux getprotobyname_r() */
+#undef HAVE_LINUX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
+#undef HAVE_LINUX_NET_TSTAMP_H
+
+/* Define to 1 if you have the <linux/socket.h> header file. */
+#undef HAVE_LINUX_SOCKET_H
+
+/* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
+#undef HAVE_LINUX_USBDEVICE_FS_H
+
+/* Define to 1 if you have the <linux/wireless.h> header file. */
+#undef HAVE_LINUX_WIRELESS_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/bpf.h> header file. */
+#undef HAVE_NET_BPF_H
+
+/* Define to 1 if you have the <net/enet.h> header file. */
+#undef HAVE_NET_ENET_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_media.h> header file. */
+#undef HAVE_NET_IF_MEDIA_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define to 1 if you have the <net/nit.h> header file. */
+#undef HAVE_NET_NIT_H
+
+/* Define to 1 if you have the <net/pfilt.h> header file. */
+#undef HAVE_NET_PFILT_H
+
+/* Define to 1 if you have the <net/pfvar.h> header file. */
+#undef HAVE_NET_PFVAR_H
+
+/* Define to 1 if you have the <net/raw.h> header file. */
+#undef HAVE_NET_RAW_H
+
+/* Use OpenSSL */
+#undef HAVE_OPENSSL
+
+/* if there's an os_proto.h for this platform, to use additional prototypes */
+#undef HAVE_OS_PROTO_H
+
+/* define if net/pfvar.h defines PF_NAT through PF_NORDR */
+#undef HAVE_PF_NAT_THROUGH_PF_NORDR
+
+/* Define to 1 if you have a POSIX-style `strerror_r' function. */
+#undef HAVE_POSIX_STRERROR_R
+
+/* define if you have the Septel API */
+#undef HAVE_SEPTEL_API
+
+/* define if you have the Myricom SNF API */
+#undef HAVE_SNF_API
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#undef HAVE_SOCKLEN_T
+
+/* On solaris */
+#undef HAVE_SOLARIS
+
+/* define if we have the Solaris/IRIX getnetbyname_r() */
+#undef HAVE_SOLARIS_IRIX_GETNETBYNAME_R
+
+/* define if we have the Solaris/IRIX getprotobyname_r() */
+#undef HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */
+#undef HAVE_STRUCT_BPF_TIMEVAL
+
+/* Define to 1 if the system has the type `struct ether_addr'. */
+#undef HAVE_STRUCT_ETHER_ADDR
+
+/* Define to 1 if `msg_control' is a member of `struct msghdr'. */
+#undef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+
+/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
+#undef HAVE_STRUCT_MSGHDR_MSG_FLAGS
+
+/* Define to 1 if the system has the type `struct rte_ether_addr'. */
+#undef HAVE_STRUCT_RTE_ETHER_ADDR
+
+/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */
+#undef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+#undef HAVE_STRUCT_SOCKADDR_SA_LEN
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */
+#undef HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI
+
+/* Define to 1 if `bRequestType' is a member of `struct
+ usbdevfs_ctrltransfer'. */
+#undef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+
+/* Define to 1 if you have the <sys/bufmod.h> header file. */
+#undef HAVE_SYS_BUFMOD_H
+
+/* Define to 1 if you have the <sys/dlpi_ext.h> header file. */
+#undef HAVE_SYS_DLPI_EXT_H
+
+/* Define to 1 if you have the <sys/dlpi.h> header file. */
+#undef HAVE_SYS_DLPI_H
+
+/* Define to 1 if you have the <sys/ioccom.h> header file. */
+#undef HAVE_SYS_IOCCOM_H
+
+/* Define to 1 if you have the <sys/net/nit.h> header file. */
+#undef HAVE_SYS_NET_NIT_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* define if you have the TurboCap API */
+#undef HAVE_TC_API
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `_wcserror_s' function. */
+#undef HAVE__WCSERROR_S
+
+/* define if __atomic_load_n is supported by the compiler */
+#undef HAVE___ATOMIC_LOAD_N
+
+/* define if __atomic_store_n is supported by the compiler */
+#undef HAVE___ATOMIC_STORE_N
+
+/* IPv6 */
+#undef INET6
+
+/* path for device for USB sniffing */
+#undef LINUX_USB_MON_DEV
+
+/* Define to 1 if netinet/ether.h declares `ether_hostton' */
+#undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON
+
+/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */
+#undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON
+
+/* Define to 1 if net/ethernet.h declares `ether_hostton' */
+#undef NET_ETHERNET_H_DECLARES_ETHER_HOSTTON
+
+/* do not use protochain */
+#undef NO_PROTOCHAIN
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* target host supports Bluetooth sniffing */
+#undef PCAP_SUPPORT_BT
+
+/* target host supports Bluetooth Monitor */
+#undef PCAP_SUPPORT_BT_MONITOR
+
+/* support D-Bus sniffing */
+#undef PCAP_SUPPORT_DBUS
+
+/* target host supports DPDK */
+#undef PCAP_SUPPORT_DPDK
+
+/* target host supports Linux usbmon for USB sniffing */
+#undef PCAP_SUPPORT_LINUX_USBMON
+
+/* target host supports netfilter sniffing */
+#undef PCAP_SUPPORT_NETFILTER
+
+/* target host supports netmap */
+#undef PCAP_SUPPORT_NETMAP
+
+/* target host supports RDMA sniffing */
+#undef PCAP_SUPPORT_RDMASNIFF
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if strings.h declares `ffs' */
+#undef STRINGS_H_DECLARES_FFS
+
+/* Define to 1 if sys/ethernet.h declares `ether_hostton' */
+#undef SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON
+
+/* Enable parser debugging */
+#undef YYDEBUG
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* define on AIX to get certain functions */
+#undef _SUN
+
+/* to handle Ultrix compilers that don't support const in prototypes */
+#undef const
+
+/* Define as token for inline if inlining supported */
+#undef inline
+
+/* on sinix */
+#undef sinix
diff --git a/diag-control.h b/diag-control.h
new file mode 100644
index 0000000..47d31b9
--- /dev/null
+++ b/diag-control.h
@@ -0,0 +1,297 @@
+/* -*- 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 _diag_control_h
+#define _diag_control_h
+
+#include "pcap/compiler-tests.h"
+
+#ifndef _MSC_VER
+ /*
+ * Clang and GCC both support this way of putting pragmas into #defines.
+ * We don't use it unless we have a compiler that supports it; the
+ * warning-suppressing pragmas differ between Clang and GCC, so we test
+ * for both of those separately.
+ */
+ #define PCAP_DO_PRAGMA(x) _Pragma (#x)
+#endif
+
+/*
+ * Suppress "enum value not explicitly handled in switch" warnings.
+ * We may have to build on multiple different Windows SDKs, so we
+ * may not be able to include all enum values in a switch, as they
+ * won't necessarily be defined on all the SDKs, and, unlike
+ * #defines, there's no easy way to test whether a given enum has
+ * a given value. It *could* be done by the configure script or
+ * CMake tests.
+ */
+#if defined(_MSC_VER)
+ #define DIAG_OFF_ENUM_SWITCH \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4061))
+ #define DIAG_ON_ENUM_SWITCH \
+ __pragma(warning(pop))
+#else
+ #define DIAG_OFF_ENUM_SWITCH
+ #define DIAG_ON_ENUM_SWITCH
+#endif
+
+/*
+ * Suppress "switch statement has only a default case" warnings.
+ * There's a switch in bpf_filter.c that only has additional
+ * cases on Linux.
+ */
+#if defined(_MSC_VER)
+ #define DIAG_OFF_DEFAULT_ONLY_SWITCH \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4065))
+ #define DIAG_ON_DEFAULT_ONLY_SWITCH \
+ __pragma(warning(pop))
+#else
+ #define DIAG_OFF_DEFAULT_ONLY_SWITCH
+ #define DIAG_ON_DEFAULT_ONLY_SWITCH
+#endif
+
+/*
+ * Suppress Flex, narrowing, and deprecation warnings.
+ */
+#if defined(_MSC_VER)
+ /*
+ * This is Microsoft Visual Studio; we can use __pragma(warning(disable:XXXX))
+ * and __pragma(warning(push/pop)).
+ *
+ * Suppress signed-vs-unsigned comparison, narrowing, and unreachable
+ * code warnings.
+ */
+ #define DIAG_OFF_FLEX \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4127)) \
+ __pragma(warning(disable:4242)) \
+ __pragma(warning(disable:4244)) \
+ __pragma(warning(disable:4702))
+ #define DIAG_ON_FLEX \
+ __pragma(warning(pop))
+
+ /*
+ * Suppress narrowing warnings.
+ */
+ #define DIAG_OFF_NARROWING \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4242)) \
+ __pragma(warning(disable:4311))
+ #define DIAG_ON_NARROWING \
+ __pragma(warning(pop))
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4996))
+ #define DIAG_ON_DEPRECATION \
+ __pragma(warning(pop))
+#elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+ /*
+ * This is Clang 2.8 or later; we can use "clang diagnostic
+ * ignored -Wxxx" and "clang diagnostic push/pop".
+ *
+ * Suppress -Wdocumentation warnings; GCC doesn't support -Wdocumentation,
+ * at least according to the GCC 7.3 documentation. Apparently, Flex
+ * generates code that upsets at least some versions of Clang's
+ * -Wdocumentation.
+ */
+ #define DIAG_OFF_FLEX \
+ PCAP_DO_PRAGMA(clang diagnostic push) \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wsign-compare") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdocumentation") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wmissing-noreturn") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunused-parameter") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+ #define DIAG_ON_FLEX \
+ PCAP_DO_PRAGMA(clang diagnostic pop)
+
+ /*
+ * Suppress the only narrowing warnings you get from Clang.
+ */
+ #define DIAG_OFF_NARROWING \
+ PCAP_DO_PRAGMA(clang diagnostic push) \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32")
+
+ #define DIAG_ON_NARROWING \
+ PCAP_DO_PRAGMA(clang diagnostic pop)
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ PCAP_DO_PRAGMA(clang diagnostic push) \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-declarations")
+ #define DIAG_ON_DEPRECATION \
+ PCAP_DO_PRAGMA(clang diagnostic pop)
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+ /*
+ * This is GCC 4.6 or later, or a compiler claiming to be that.
+ * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2)
+ * and "GCC diagnostic push/pop" (introduced in 4.6).
+ */
+ #define DIAG_OFF_FLEX \
+ PCAP_DO_PRAGMA(GCC diagnostic push) \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wsign-compare") \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunused-parameter") \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+ #define DIAG_ON_FLEX \
+ PCAP_DO_PRAGMA(GCC diagnostic pop)
+
+ /*
+ * GCC currently doesn't issue any narrowing warnings.
+ */
+ #define DIAG_OFF_NARROWING
+ #define DIAG_ON_NARROWING
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ PCAP_DO_PRAGMA(GCC diagnostic push) \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations")
+ #define DIAG_ON_DEPRECATION \
+ PCAP_DO_PRAGMA(GCC diagnostic pop)
+#else
+ /*
+ * Neither Visual Studio, nor Clang 2.8 or later, nor GCC 4.6 or later
+ * or a compiler claiming to be that; there's nothing we know of that
+ * we can do.
+ */
+ #define DIAG_OFF_FLEX
+ #define DIAG_ON_FLEX
+ #define DIAG_OFF_NARROWING
+ #define DIAG_ON_NARROWING
+ #define DIAG_OFF_DEPRECATION
+ #define DIAG_ON_DEPRECATION
+#endif
+
+#ifdef YYBYACC
+ /*
+ * Berkeley YACC.
+ *
+ * It generates a global declaration of yylval, or the appropriately
+ * prefixed version of yylval, in grammar.h, *even though it's been
+ * told to generate a pure parser, meaning it doesn't have any global
+ * variables*. Bison doesn't do this.
+ *
+ * That causes a warning due to the local declaration in the parser
+ * shadowing the global declaration.
+ *
+ * So, if the compiler warns about that, we turn off -Wshadow warnings.
+ *
+ * In addition, the generated code may have functions with unreachable
+ * code, so suppress warnings about those.
+ */
+ #if defined(_MSC_VER)
+ /*
+ * This is Microsoft Visual Studio; we can use
+ * __pragma(warning(disable:XXXX)).
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ __pragma(warning(disable:4702))
+ #elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+ /*
+ * This is Clang 2.8 or later; we can use "clang diagnostic
+ * ignored -Wxxx".
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshadow") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+ #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+ /*
+ * This is GCC 4.6 or later, or a compiler claiming to be that.
+ * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+ * but it may not actually work very well prior to 4.6).
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wshadow") \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+ #else
+ /*
+ * Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
+ * claiming to be that; there's nothing we know of that we can do.
+ */
+ #define DIAG_OFF_BISON_BYACC
+ #endif
+#else
+ /*
+ * Bison.
+ *
+ * The generated code may have functions with unreachable code and
+ * switches with only a default case, so suppress warnings about those.
+ */
+ #if defined(_MSC_VER)
+ /*
+ * This is Microsoft Visual Studio; we can use
+ * __pragma(warning(disable:XXXX)).
+ *
+ * Suppress some /Wall warnings.
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ __pragma(warning(disable:4065)) \
+ __pragma(warning(disable:4127)) \
+ __pragma(warning(disable:4242)) \
+ __pragma(warning(disable:4244)) \
+ __pragma(warning(disable:4702))
+ #elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
+ /*
+ * This is Clang 2.8 or later; we can use "clang diagnostic
+ * ignored -Wxxx".
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
+ #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
+ /*
+ * This is GCC 4.6 or later, or a compiler claiming to be that.
+ * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+ * but it may not actually work very well prior to 4.6).
+ */
+ #define DIAG_OFF_BISON_BYACC \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
+ #else
+ /*
+ * Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
+ * claiming to be that; there's nothing we know of that we can do.
+ */
+ #define DIAG_OFF_BISON_BYACC
+ #endif
+#endif
+
+#endif /* _diag_control_h */
diff --git a/etherent.c b/etherent.c
new file mode 100644
index 0000000..69da9a5
--- /dev/null
+++ b/etherent.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1990, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+#include <pcap/namedb.h>
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+static inline int skip_space(FILE *);
+static inline int skip_line(FILE *);
+
+/* Hex digit to integer. */
+static inline u_char
+xdtoi(u_char c)
+{
+ if (c >= '0' && c <= '9')
+ return (u_char)(c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (u_char)(c - 'a' + 10);
+ else
+ return (u_char)(c - 'A' + 10);
+}
+
+/*
+ * Skip linear white space (space and tab) and any CRs before LF.
+ * Stop when we hit a non-white-space character or an end-of-line LF.
+ */
+static inline int
+skip_space(FILE *f)
+{
+ int c;
+
+ do {
+ c = getc(f);
+ } while (c == ' ' || c == '\t' || c == '\r');
+
+ return c;
+}
+
+static inline int
+skip_line(FILE *f)
+{
+ int c;
+
+ do
+ c = getc(f);
+ while (c != '\n' && c != EOF);
+
+ return c;
+}
+
+struct pcap_etherent *
+pcap_next_etherent(FILE *fp)
+{
+ register int c, i;
+ u_char d;
+ char *bp;
+ size_t namesize;
+ static struct pcap_etherent e;
+
+ memset((char *)&e, 0, sizeof(e));
+ for (;;) {
+ /* Find addr */
+ c = skip_space(fp);
+ if (c == EOF)
+ return (NULL);
+ if (c == '\n')
+ continue;
+
+ /* If this is a comment, or first thing on line
+ cannot be Ethernet address, skip the line. */
+ if (!PCAP_ISXDIGIT(c)) {
+ c = skip_line(fp);
+ if (c == EOF)
+ return (NULL);
+ continue;
+ }
+
+ /* must be the start of an address */
+ for (i = 0; i < 6; i += 1) {
+ d = xdtoi((u_char)c);
+ c = getc(fp);
+ if (c == EOF)
+ return (NULL);
+ if (PCAP_ISXDIGIT(c)) {
+ d <<= 4;
+ d |= xdtoi((u_char)c);
+ c = getc(fp);
+ if (c == EOF)
+ return (NULL);
+ }
+ e.addr[i] = d;
+ if (c != ':')
+ break;
+ c = getc(fp);
+ if (c == EOF)
+ return (NULL);
+ }
+
+ /* Must be whitespace */
+ if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+ c = skip_line(fp);
+ if (c == EOF)
+ return (NULL);
+ continue;
+ }
+ c = skip_space(fp);
+ if (c == EOF)
+ return (NULL);
+
+ /* hit end of line... */
+ if (c == '\n')
+ continue;
+
+ if (c == '#') {
+ c = skip_line(fp);
+ if (c == EOF)
+ return (NULL);
+ continue;
+ }
+
+ /* pick up name */
+ bp = e.name;
+ /* Use 'namesize' to prevent buffer overflow. */
+ namesize = sizeof(e.name) - 1;
+ do {
+ *bp++ = (u_char)c;
+ c = getc(fp);
+ if (c == EOF)
+ return (NULL);
+ } while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
+ && --namesize != 0);
+ *bp = '\0';
+
+ /* Eat trailing junk */
+ if (c != '\n')
+ (void)skip_line(fp);
+
+ return &e;
+ }
+}
diff --git a/ethertype.h b/ethertype.h
new file mode 100644
index 0000000..e34e07b
--- /dev/null
+++ b/ethertype.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1993, 1994, 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.
+ */
+
+/*
+ * Ethernet types.
+ *
+ * We wrap the declarations with #ifdef, so that if a file includes
+ * <netinet/if_ether.h>, which may declare some of these, we don't
+ * get a bunch of complaints from the C compiler about redefinitions
+ * of these values.
+ *
+ * We declare all of them here so that no file has to include
+ * <netinet/if_ether.h> if all it needs are ETHERTYPE_ values.
+ */
+
+#ifndef ETHERTYPE_PUP
+#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
+#endif
+#ifndef ETHERTYPE_IP
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#endif
+#ifndef ETHERTYPE_ARP
+#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS 0x0600
+#endif
+#ifndef ETHERTYPE_SPRITE
+#define ETHERTYPE_SPRITE 0x0500
+#endif
+#ifndef ETHERTYPE_TRAIL
+#define ETHERTYPE_TRAIL 0x1000
+#endif
+#ifndef ETHERTYPE_MOPDL
+#define ETHERTYPE_MOPDL 0x6001
+#endif
+#ifndef ETHERTYPE_MOPRC
+#define ETHERTYPE_MOPRC 0x6002
+#endif
+#ifndef ETHERTYPE_DN
+#define ETHERTYPE_DN 0x6003
+#endif
+#ifndef ETHERTYPE_LAT
+#define ETHERTYPE_LAT 0x6004
+#endif
+#ifndef ETHERTYPE_SCA
+#define ETHERTYPE_SCA 0x6007
+#endif
+#ifndef ETHERTYPE_TEB
+#define ETHERTYPE_TEB 0x6558
+#endif
+#ifndef ETHERTYPE_REVARP
+#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */
+#endif
+#ifndef ETHERTYPE_LANBRIDGE
+#define ETHERTYPE_LANBRIDGE 0x8038
+#endif
+#ifndef ETHERTYPE_DECDNS
+#define ETHERTYPE_DECDNS 0x803c
+#endif
+#ifndef ETHERTYPE_DECDTS
+#define ETHERTYPE_DECDTS 0x803e
+#endif
+#ifndef ETHERTYPE_VEXP
+#define ETHERTYPE_VEXP 0x805b
+#endif
+#ifndef ETHERTYPE_VPROD
+#define ETHERTYPE_VPROD 0x805c
+#endif
+#ifndef ETHERTYPE_ATALK
+#define ETHERTYPE_ATALK 0x809b
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP 0x80f3
+#endif
+#ifndef ETHERTYPE_8021Q
+#define ETHERTYPE_8021Q 0x8100
+#endif
+#ifndef ETHERTYPE_IPX
+#define ETHERTYPE_IPX 0x8137
+#endif
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6 0x86dd
+#endif
+#ifndef ETHERTYPE_MPLS
+#define ETHERTYPE_MPLS 0x8847
+#endif
+#ifndef ETHERTYPE_MPLS_MULTI
+#define ETHERTYPE_MPLS_MULTI 0x8848
+#endif
+#ifndef ETHERTYPE_PPPOED
+#define ETHERTYPE_PPPOED 0x8863
+#endif
+#ifndef ETHERTYPE_PPPOES
+#define ETHERTYPE_PPPOES 0x8864
+#endif
+#ifndef ETHERTYPE_8021AD
+#define ETHERTYPE_8021AD 0x88a8
+#endif
+#ifndef ETHERTYPE_LOOPBACK
+#define ETHERTYPE_LOOPBACK 0x9000
+#endif
+#ifndef ETHERTYPE_8021QINQ
+#define ETHERTYPE_8021QINQ 0x9100
+#endif
diff --git a/extract.h b/extract.h
new file mode 100644
index 0000000..e776a9e
--- /dev/null
+++ b/extract.h
@@ -0,0 +1,423 @@
+/*
+ * 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 <arpa/inet.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+#include <pcap/compiler-tests.h>
+#include "portability.h"
+
+/*
+ * If we have versions of GCC or Clang that support an __attribute__
+ * to say "if we're building with unsigned behavior sanitization,
+ * don't complain about undefined behavior in this function", we
+ * label these functions with that attribute - we *know* it's undefined
+ * in the C standard, but we *also* know it does what we want with
+ * the ISA we're targeting and the compiler we're using.
+ *
+ * For GCC 4.9.0 and later, we use __attribute__((no_sanitize_undefined));
+ * pre-5.0 GCC doesn't have __has_attribute, and I'm not sure whether
+ * GCC or Clang first had __attribute__((no_sanitize(XXX)).
+ *
+ * For Clang, we check for __attribute__((no_sanitize(XXX)) with
+ * __has_attribute, as there are versions of Clang that support
+ * __attribute__((no_sanitize("undefined")) but don't support
+ * __attribute__((no_sanitize_undefined)).
+ *
+ * We define this here, rather than in funcattrs.h, because we
+ * only want it used here, we don't want it to be broadly used.
+ * (Any printer will get this defined, but this should at least
+ * make it harder for people to find.)
+ */
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409)
+#define UNALIGNED_OK __attribute__((no_sanitize_undefined))
+#elif __has_attribute(no_sanitize)
+#define UNALIGNED_OK __attribute__((no_sanitize("undefined")))
+#else
+#define UNALIGNED_OK
+#endif
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
+ (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
+ (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
+ (defined(__s390__) || defined(__s390x__) || defined(__zarch__))
+/*
+ * The processor natively handles unaligned loads, so we can just
+ * cast the pointer and fetch through it.
+ *
+ * XXX - are those all the x86 tests we need?
+ * XXX - are those the only 68k tests we need not to generated
+ * unaligned accesses if the target is the 68000 or 68010?
+ * XXX - are there any tests we don't need, because some definitions are for
+ * compilers that also predefine the GCC symbols?
+ * XXX - do we need to test for both 32-bit and 64-bit versions of those
+ * architectures in all cases?
+ */
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
+{
+ return ((uint16_t)ntohs(*(const uint16_t *)(p)));
+}
+
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+ return ((int16_t)ntohs(*(const int16_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
+{
+ return ((uint32_t)ntohl(*(const uint32_t *)(p)));
+}
+
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+ return ((int32_t)ntohl(*(const int32_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(const void *p)
+{
+ return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+ ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+ return ((int64_t)(((int64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+ ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \
+ (defined(__alpha) || defined(__alpha__) || \
+ defined(__mips) || defined(__mips__))
+/*
+ * This is MIPS or Alpha, which don't natively handle unaligned loads,
+ * but which have instructions that can help when doing unaligned
+ * loads, and this is GCC 2.0 or later or a compiler that claims to
+ * be GCC 2.0 or later, which we assume that mean we have
+ * __attribute__((packed)), which we can use to convince the compiler
+ * to generate those instructions.
+ *
+ * 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 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 {
+ int16_t val;
+} __attribute__((packed)) unaligned_int16_t;
+
+typedef struct {
+ uint32_t val;
+} __attribute__((packed)) unaligned_uint32_t;
+
+typedef struct {
+ int32_t val;
+} __attribute__((packed)) unaligned_int32_t;
+
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
+{
+ return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+ return ((int16_t)ntohs(((const unaligned_int16_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
+{
+ return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+ return ((int32_t)ntohl(((const unaligned_int32_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(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));
+}
+
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+ return ((int64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
+ ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
+}
+#else
+/*
+ * This architecture doesn't natively support unaligned loads, and either
+ * 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.
+ *
+ * XXX - ARM is a special case. ARMv1 through ARMv5 didn't suppory
+ * unaligned loads; ARMv6 and later support it *but* have a bit in
+ * the system control register that the OS can set and that causes
+ * unaligned loads to fault rather than succeeding.
+ *
+ * At least some OSes may set that flag, so we do *not* treat ARM
+ * as supporting unaligned loads. If your OS supports them on ARM,
+ * and you want to use them, please update the tests in the #if above
+ * to check for ARM *and* for your OS.
+ */
+#define EXTRACT_BE_U_2(p) \
+ ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_BE_S_2(p) \
+ ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_BE_U_4(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_BE_S_4(p) \
+ ((int32_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_BE_U_8(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)))
+#define EXTRACT_BE_S_8(p) \
+ ((int64_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)))
+
+/*
+ * Extract an IPv4 address, which is in network byte order, and not
+ * necessarily aligned, and provide the result in host byte order.
+ */
+#define EXTRACT_IPV4_TO_HOST_ORDER(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)))
+#endif /* unaligned access checks */
+
+/*
+ * Non-power-of-2 sizes.
+ */
+#define EXTRACT_BE_U_3(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_BE_S_3(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int32_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))) : \
+ ((int32_t)(0xFF000000U | \
+ ((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_BE_U_5(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_BE_S_5(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_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))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFF0000000000U) | \
+ ((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_BE_U_6(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_BE_S_6(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_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))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFF00000000U) | \
+ ((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_BE_U_7(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)))
+
+#define EXTRACT_BE_S_7(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_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))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFFFF000000U) | \
+ ((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_U_2(p) \
+ ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_2(p) \
+ ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_4(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_S_4(p) \
+ ((int32_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_U_3(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_S_3(p) \
+ ((int32_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_U_8(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)))
+#define EXTRACT_LE_S_8(p) \
+ ((int64_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/fad-getad.c b/fad-getad.c
new file mode 100644
index 0000000..ba8f975
--- /dev/null
+++ b/fad-getad.c
@@ -0,0 +1,279 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+/*
+ * 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 <net/bpf.h> and our <pcap/bpf.h>,
+ * and their definitions of some data structures collide.
+ */
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
+# ifdef HAVE_NETPACKET_PACKET_H
+/* Linux distributions with newer glibc */
+# include <netpacket/packet.h>
+# else /* HAVE_NETPACKET_PACKET_H */
+/* LynxOS, Linux distributions with older glibc */
+# ifdef __Lynx__
+/* LynxOS */
+# include <netpacket/if_packet.h>
+# else /* __Lynx__ */
+/* Linux */
+# include <linux/types.h>
+# include <linux/if_packet.h>
+# endif /* __Lynx__ */
+# endif /* HAVE_NETPACKET_PACKET_H */
+#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */
+
+/*
+ * This is fun.
+ *
+ * In older BSD systems, socket addresses were fixed-length, and
+ * "sizeof (struct sockaddr)" gave the size of the structure.
+ * All addresses fit within a "struct sockaddr".
+ *
+ * In newer BSD systems, the socket address is variable-length, and
+ * there's an "sa_len" field giving the length of the structure;
+ * this allows socket addresses to be longer than 2 bytes of family
+ * and 14 bytes of data.
+ *
+ * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
+ * variant of the old BSD scheme (with "struct sockaddr_storage" rather
+ * than "struct sockaddr"), and some use the new BSD scheme.
+ *
+ * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
+ * macro that determines the size based on the address family. Other
+ * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
+ * but not in the final version). On the latter systems, we explicitly
+ * check the AF_ type to determine the length; we assume that on
+ * all those systems we have "struct sockaddr_storage".
+ */
+#ifndef SA_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+#define SA_LEN(addr) ((addr)->sa_len)
+#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+static size_t
+get_sa_len(struct sockaddr *addr)
+{
+ switch (addr->sa_family) {
+
+#ifdef AF_INET
+ case AF_INET:
+ return (sizeof (struct sockaddr_in));
+#endif
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return (sizeof (struct sockaddr_in6));
+#endif
+
+#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
+ case AF_PACKET:
+ return (sizeof (struct sockaddr_ll));
+#endif
+
+ default:
+ return (sizeof (struct sockaddr));
+ }
+}
+#define SA_LEN(addr) (get_sa_len(addr))
+#else /* HAVE_STRUCT_SOCKADDR_STORAGE */
+#define SA_LEN(addr) (sizeof (struct sockaddr))
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+#endif /* SA_LEN */
+
+/*
+ * 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
+ * could be opened.
+ */
+int
+pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
+ int (*check_usable)(const char *), get_if_flags_func get_flags_func)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr *addr, *netmask, *broadaddr, *dstaddr;
+ size_t addr_size, broadaddr_size, dstaddr_size;
+ int ret = 0;
+ char *p, *q;
+
+ /*
+ * Get the list of interface addresses.
+ *
+ * Note: this won't return information about interfaces
+ * 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
+ * of "getifaddrs()" now, or in the future, will return
+ * those.
+ */
+ if (getifaddrs(&ifap) != 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "getifaddrs");
+ return (-1);
+ }
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ /*
+ * 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 (PCAP_ISDIGIT(*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. 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;
+ addr_size = SA_LEN(addr);
+ netmask = ifa->ifa_netmask;
+ } else {
+ addr = NULL;
+ 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 macOS), 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;
+ broadaddr_size = SA_LEN(broadaddr);
+ } else {
+ broadaddr = NULL;
+ broadaddr_size = 0;
+ }
+ if (ifa->ifa_flags & IFF_POINTOPOINT &&
+ ifa->ifa_dstaddr != NULL) {
+ dstaddr = ifa->ifa_dstaddr;
+ dstaddr_size = SA_LEN(ifa->ifa_dstaddr);
+ } else {
+ dstaddr = NULL;
+ dstaddr_size = 0;
+ }
+
+ /*
+ * Add information for this address to the list.
+ */
+ if (add_addr_to_if(devlistp, ifa->ifa_name, ifa->ifa_flags,
+ get_flags_func,
+ addr, addr_size, netmask, addr_size,
+ broadaddr, broadaddr_size, dstaddr, dstaddr_size,
+ errbuf) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+
+ freeifaddrs(ifap);
+
+ return (ret);
+}
diff --git a/fmtutils.c b/fmtutils.c
new file mode 100644
index 0000000..5c7ddad
--- /dev/null
+++ b/fmtutils.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that 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.
+ */
+
+/*
+ * Utilities for message formatting used both by libpcap and rpcapd.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ftmacros.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "pcap-int.h"
+
+#include "portability.h"
+
+#include "fmtutils.h"
+
+#ifdef _WIN32
+#include "charconv.h"
+#endif
+
+/*
+ * Set the encoding.
+ */
+#ifdef _WIN32
+/*
+ * True if we shouold use UTF-8.
+ */
+static int use_utf_8;
+
+void
+pcap_fmt_set_encoding(unsigned int opts)
+{
+ if (opts == PCAP_CHAR_ENC_UTF_8)
+ use_utf_8 = 1;
+}
+#else
+void
+pcap_fmt_set_encoding(unsigned int opts _U_)
+{
+ /*
+ * Nothing to do here.
+ */
+}
+#endif
+
+#ifdef _WIN32
+/*
+ * Convert a null-terminated UTF-16LE string to UTF-8, putting it into
+ * a buffer starting at the specified location and stopping if we go
+ * past the specified size. This will only put out complete UTF-8
+ * sequences.
+ *
+ * We do this ourselves because Microsoft doesn't offer a "convert and
+ * stop at a UTF-8 character boundary if we run out of space" routine.
+ */
+#define IS_LEADING_SURROGATE(c) \
+ ((c) >= 0xd800 && (c) < 0xdc00)
+#define IS_TRAILING_SURROGATE(c) \
+ ((c) >= 0xdc00 && (c) < 0xe000)
+#define SURROGATE_VALUE(leading, trailing) \
+ (((((leading) - 0xd800) << 10) | ((trailing) - 0xdc00)) + 0x10000)
+#define REPLACEMENT_CHARACTER 0x0FFFD
+
+static char *
+utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8,
+ size_t utf_8_len)
+{
+ wchar_t c, c2;
+ uint32_t uc;
+
+ if (utf_8_len == 0) {
+ /*
+ * Not even enough room for a trailing '\0'.
+ * Don't put anything into the buffer.
+ */
+ return (utf_8);
+ }
+
+ while ((c = *utf_16++) != '\0') {
+ if (IS_LEADING_SURROGATE(c)) {
+ /*
+ * Leading surrogate. Must be followed by
+ * a trailing surrogate.
+ */
+ c2 = *utf_16;
+ if (c2 == '\0') {
+ /*
+ * Oops, string ends with a lead
+ * surrogate. Try to drop in
+ * a REPLACEMENT CHARACTER, and
+ * don't move the string pointer,
+ * so on the next trip through
+ * the loop we grab the terminating
+ * '\0' and quit.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ } else {
+ /*
+ * OK, we can consume this 2-octet
+ * value.
+ */
+ utf_16++;
+ if (IS_TRAILING_SURROGATE(c2)) {
+ /*
+ * Trailing surrogate.
+ * This calculation will,
+ * for c being a leading
+ * surrogate and c2 being
+ * a trailing surrogate,
+ * produce a value between
+ * 0x100000 and 0x10ffff,
+ * so it's always going to be
+ * a valid Unicode code point.
+ */
+ uc = SURROGATE_VALUE(c, c2);
+ } else {
+ /*
+ * Not a trailing surroage;
+ * try to drop in a
+ * REPLACEMENT CHARACTER.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ }
+ }
+ } else {
+ /*
+ * Not a leading surrogate.
+ */
+ if (IS_TRAILING_SURROGATE(c)) {
+ /*
+ * Trailing surrogate without
+ * a preceding leading surrogate.
+ * Try to drop in a REPLACEMENT
+ * CHARACTER.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ } else {
+ /*
+ * This is a valid BMP character;
+ * drop it in.
+ */
+ uc = c;
+ }
+ }
+
+ /*
+ * OK, uc is a valid Unicode character; how
+ * many bytes worth of UTF-8 does it require?
+ */
+ if (uc < 0x0080) {
+ /* 1 byte. */
+ if (utf_8_len < 2) {
+ /*
+ * Not enough room for that byte
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = (char)uc;
+ utf_8_len--;
+ } else if (uc < 0x0800) {
+ /* 2 bytes. */
+ if (utf_8_len < 3) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0xC0;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 2;
+ } else if (uc < 0x010000) {
+ /* 3 bytes. */
+ if (utf_8_len < 4) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 12) & 0x0F) | 0xE0;
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 3;
+ } else {
+ /* 4 bytes. */
+ if (utf_8_len < 5) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 18) & 0x03) | 0xF0;
+ *utf_8++ = ((uc >> 12) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 3;
+ }
+ }
+
+ /*
+ * OK, we have enough room for (at least) a trailing '\0'.
+ * (We started out with enough room, thanks to the test
+ * for a zero-length buffer at the beginning, and if
+ * there wasn't enough room for any character we wanted
+ * to put into the buffer *plus* a trailing '\0',
+ * we'd have quit before putting it into the buffer,
+ * and thus would have left enough room for the trailing
+ * '\0'.)
+ *
+ * Drop it in.
+ */
+ *utf_8 = '\0';
+
+ /*
+ * Return a pointer to the terminating '\0', in case we
+ * want to drop something in after that.
+ */
+ return (utf_8);
+}
+#endif /* _WIN32 */
+
+/*
+ * Generate an error message based on a format, arguments, and an
+ * errno, with a message for the errno after the formatted output.
+ */
+void
+pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
+ const char *fmt, ...)
+{
+ va_list ap;
+ size_t msglen;
+ char *p;
+ size_t errbuflen_remaining;
+
+ va_start(ap, fmt);
+ vsnprintf(errbuf, errbuflen, fmt, ap);
+ va_end(ap);
+ msglen = strlen(errbuf);
+
+ /*
+ * Do we have enough space to append ": "?
+ * Including the terminating '\0', that's 3 bytes.
+ */
+ if (msglen + 3 > errbuflen) {
+ /* No - just give them what we've produced. */
+ return;
+ }
+ p = errbuf + msglen;
+ errbuflen_remaining = errbuflen - msglen;
+ *p++ = ':';
+ *p++ = ' ';
+ *p = '\0';
+ errbuflen_remaining -= 2;
+
+ /*
+ * Now append the string for the error code.
+ */
+#if defined(HAVE__WCSERROR_S)
+ /*
+ * We have a Windows-style _wcserror_s().
+ * Generate a UTF-16LE error message.
+ */
+ wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+ errno_t err = _wcserror_s(utf_16_errbuf, PCAP_ERRBUF_SIZE, errnum);
+ if (err != 0) {
+ /*
+ * It doesn't appear to be documented anywhere obvious
+ * what the error returns from _wcserror_s().
+ */
+ snprintf(p, errbuflen_remaining, "Error %d", errnum);
+ return;
+ }
+
+ /*
+ * Now convert it from UTF-16LE to UTF-8, dropping it in the
+ * remaining space in the buffer, and truncating it - cleanly,
+ * on a UTF-8 character boundary - if it doesn't fit.
+ */
+ utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+ /*
+ * Now, if we're not in UTF-8 mode, convert errbuf to the
+ * local code page.
+ */
+ if (!use_utf_8)
+ utf_8_to_acp_truncated(errbuf);
+#elif defined(HAVE_GNU_STRERROR_R)
+ /*
+ * We have a GNU-style strerror_r(), which is *not* guaranteed to
+ * do anything to the buffer handed to it, and which returns a
+ * pointer to the error string, which may or may not be in
+ * the buffer.
+ *
+ * It is, however, guaranteed to succeed.
+ */
+ char strerror_buf[PCAP_ERRBUF_SIZE];
+ char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
+ snprintf(p, errbuflen_remaining, "%s", errstring);
+#elif defined(HAVE_POSIX_STRERROR_R)
+ /*
+ * We have a POSIX-style strerror_r(), which is guaranteed to fill
+ * in the buffer, but is not guaranteed to succeed.
+ */
+ int err = strerror_r(errnum, p, errbuflen_remaining);
+ if (err == EINVAL) {
+ /*
+ * UNIX 03 says this isn't guaranteed to produce a
+ * fallback error message.
+ */
+ snprintf(p, errbuflen_remaining, "Unknown error: %d",
+ errnum);
+ } else if (err == ERANGE) {
+ /*
+ * UNIX 03 says this isn't guaranteed to produce a
+ * fallback error message.
+ */
+ snprintf(p, errbuflen_remaining,
+ "Message for error %d is too long", errnum);
+ }
+#else
+ /*
+ * We have neither _wcserror_s() nor strerror_r(), so we're
+ * stuck with using pcap_strerror().
+ */
+ snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
+#endif
+}
+
+#ifdef _WIN32
+/*
+ * Generate an error message based on a format, arguments, and a
+ * Win32 error, with a message for the Win32 error after the formatted output.
+ */
+void
+pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
+ const char *fmt, ...)
+{
+ va_list ap;
+ size_t msglen;
+ char *p;
+ size_t errbuflen_remaining;
+ DWORD retval;
+ wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+ size_t utf_8_len;
+
+ va_start(ap, fmt);
+ vsnprintf(errbuf, errbuflen, fmt, ap);
+ va_end(ap);
+ msglen = strlen(errbuf);
+
+ /*
+ * Do we have enough space to append ": "?
+ * Including the terminating '\0', that's 3 bytes.
+ */
+ if (msglen + 3 > errbuflen) {
+ /* No - just give them what we've produced. */
+ return;
+ }
+ p = errbuf + msglen;
+ errbuflen_remaining = errbuflen - msglen;
+ *p++ = ':';
+ *p++ = ' ';
+ *p = '\0';
+ msglen += 2;
+ errbuflen_remaining -= 2;
+
+ /*
+ * Now append the string for the error code.
+ *
+ * XXX - what language ID to use?
+ *
+ * For UN*Xes, pcap_strerror() may or may not return localized
+ * strings.
+ *
+ * We currently don't have localized messages for libpcap, but
+ * we might want to do so. On the other hand, if most of these
+ * messages are going to be read by libpcap developers and
+ * perhaps by developers of libpcap-based applications, English
+ * might be a better choice, so the developer doesn't have to
+ * get the message translated if it's in a language they don't
+ * happen to understand.
+ */
+ retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL);
+ if (retval == 0) {
+ /*
+ * Failed.
+ */
+ snprintf(p, errbuflen_remaining,
+ "Couldn't get error message for error (%lu)", errnum);
+ return;
+ }
+
+ /*
+ * Now convert it from UTF-16LE to UTF-8.
+ */
+ p = utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+ /*
+ * Now append the error number, if it fits.
+ */
+ utf_8_len = p - errbuf;
+ errbuflen_remaining -= utf_8_len;
+ if (utf_8_len == 0) {
+ /* The message was empty. */
+ snprintf(p, errbuflen_remaining, "(%lu)", errnum);
+ } else
+ snprintf(p, errbuflen_remaining, " (%lu)", errnum);
+
+ /*
+ * Now, if we're not in UTF-8 mode, convert errbuf to the
+ * local code page.
+ */
+ if (!use_utf_8)
+ utf_8_to_acp_truncated(errbuf);
+}
+#endif
diff --git a/fmtutils.h b/fmtutils.h
new file mode 100644
index 0000000..ba0f66c
--- /dev/null
+++ b/fmtutils.h
@@ -0,0 +1,57 @@
+/*
+ * 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 fmtutils_h
+#define fmtutils_h
+
+#include "pcap/funcattrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void pcap_fmt_set_encoding(unsigned int);
+
+void pcap_fmt_errmsg_for_errno(char *, size_t, int,
+ PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+
+#ifdef _WIN32
+void pcap_fmt_errmsg_for_win32_err(char *, size_t, DWORD,
+ PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ftmacros.h b/ftmacros.h
new file mode 100644
index 0000000..3cd7505
--- /dev/null
+++ b/ftmacros.h
@@ -0,0 +1,122 @@
+/*
+ * 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 ftmacros_h
+#define ftmacros_h
+
+/*
+ * Define some feature test macros to make sure that everything we want
+ * to be declared gets declared.
+ *
+ * On some UN*Xes we need to force strtok_r() to be declared.
+ * We do *NOT* want to define _POSIX_C_SOURCE, as that tends
+ * to make non-POSIX APIs that we use unavailable.
+ * XXX - is there no portable way to say "please pollute the
+ * namespace to the maximum extent possible"?
+ */
+#if defined(sun) || defined(__sun)
+ #define __EXTENSIONS__
+
+ /*
+ * We also need to define _XPG4_2 in order to get
+ * the Single UNIX Specification version of
+ * recvmsg().
+ */
+ #define _XPG4_2
+#elif defined(_hpux) || defined(hpux) || defined(__hpux)
+ #define _REENTRANT
+
+ /*
+ * We need this to get the versions of socket functions that
+ * use socklen_t. Define it only if it's not already defined,
+ * so we don't get redefiniton warnings.
+ */
+ #ifndef _XOPEN_SOURCE_EXTENDED
+ #define _XOPEN_SOURCE_EXTENDED
+ #endif
+
+ /*
+ * XXX - the list of PA-RISC options for GCC makes it sound as if
+ * building code that uses a particular vintage of UNIX API/ABI
+ * is complicated:
+ *
+ * https://gcc.gnu.org/onlinedocs/gcc/HPPA-Options.html
+ *
+ * See the description of the -munix flag.
+ *
+ * We probably want libpcap to work with programs built for any
+ * UN*X standard. I'm not sure whether that's possible and, if
+ * it is, what sort of stuff it'd have to do.
+ *
+ * It might also be a requirement that we build with a special
+ * flag to allow the library to be used with threaded code, at
+ * least with HP's C compiler; hopefully doing so won't make it
+ * *not* work with *un*-threaded code.
+ */
+#else
+ /*
+ * Turn on _GNU_SOURCE to get everything GNU libc has to offer,
+ * including asprintf(), if we're using GNU libc.
+ *
+ * Unfortunately, one thing it has to offer is a strerror_r()
+ * that's not POSIX-compliant, but we deal with that in
+ * pcap_fmt_errmsg_for_errno().
+ *
+ * We don't limit this to, for example, Linux and Cygwin, because
+ * this might, for example, be GNU/HURD or one of Debian's kFreeBSD
+ * OSes ("GNU/FreeBSD").
+ */
+ #define _GNU_SOURCE
+
+ /*
+ * We turn on both _DEFAULT_SOURCE and _BSD_SOURCE to try to get
+ * the BSD u_XXX types, such as u_int and u_short, defined. We
+ * define _DEFAULT_SOURCE first, so that newer versions of GNU libc
+ * don't whine about _BSD_SOURCE being deprecated; we still have
+ * to define _BSD_SOURCE to handle older versions of GNU libc that
+ * don't support _DEFAULT_SOURCE.
+ *
+ * But, if it's already defined, don't define it, so that we don't
+ * get a warning of it being redefined if it's defined as, for
+ * example, 1.
+ */
+ #ifndef _DEFAULT_SOURCE
+ #define _DEFAULT_SOURCE
+ #endif
+ /* Avoid redefining _BSD_SOURCE if it's already defined as for ex. 1 */
+ #ifndef _BSD_SOURCE
+ #define _BSD_SOURCE
+ #endif
+#endif
+
+#endif
diff --git a/gencode.c b/gencode.c
new file mode 100644
index 0000000..efdcb98
--- /dev/null
+++ b/gencode.c
@@ -0,0 +1,10058 @@
+/*#define CHASE_CHAIN*/
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+ #include <ws2tcpip.h>
+#else
+ #include <sys/socket.h>
+
+ #ifdef __NetBSD__
+ #include <sys/param.h>
+ #endif
+
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif /* _WIN32 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <setjmp.h>
+#include <stdarg.h>
+
+#ifdef MSDOS
+#include "pcap-dos.h"
+#endif
+
+#ifdef HAVE_NET_PFVAR_H
+/*
+ * In NetBSD <net/if.h> includes <net/dlt.h>, which is an older version of
+ * "pcap/dlt.h" with a lower value of DLT_MATCHING_MAX. Include the headers
+ * below before "pcap-int.h", which eventually includes "pcap/dlt.h", which
+ * redefines DLT_MATCHING_MAX from what this version of NetBSD has to what
+ * this version of libpcap has.
+ */
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pflog.h>
+#endif /* HAVE_NET_PFVAR_H */
+
+#include "pcap-int.h"
+
+#include "extract.h"
+
+#include "ethertype.h"
+#include "nlpid.h"
+#include "llc.h"
+#include "gencode.h"
+#include "ieee80211.h"
+#include "atmuni31.h"
+#include "sunatmpos.h"
+#include "ppp.h"
+#include "pcap/sll.h"
+#include "pcap/ipnet.h"
+#include "arcnet.h"
+
+#include "grammar.h"
+#include "scanner.h"
+
+#if defined(linux)
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#endif
+
+#ifndef offsetof
+#define offsetof(s, e) ((size_t)&((s *)0)->e)
+#endif
+
+#ifdef _WIN32
+ #ifdef INET6
+ #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+/* IPv6 address */
+struct in6_addr
+ {
+ union
+ {
+ uint8_t u6_addr8[16];
+ uint16_t u6_addr16[8];
+ uint32_t u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#define s6_addr64 in6_u.u6_addr64
+ };
+
+typedef unsigned short sa_family_t;
+
+#define __SOCKADDR_COMMON(sa_prefix) \
+ sa_family_t sa_prefix##family
+
+/* Ditto, for IPv6. */
+struct sockaddr_in6
+ {
+ __SOCKADDR_COMMON (sin6_);
+ uint16_t sin6_port; /* Transport layer port # */
+ uint32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ };
+
+ #ifndef EAI_ADDRFAMILY
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+ #endif /* EAI_ADDRFAMILY */
+ #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
+ #endif /* INET6 */
+#else /* _WIN32 */
+ #include <netdb.h> /* for "struct addrinfo" */
+#endif /* _WIN32 */
+#include <pcap/namedb.h>
+
+#include "nametoaddr.h"
+
+#define ETHERMTU 1500
+
+#ifndef IPPROTO_HOPOPTS
+#define IPPROTO_HOPOPTS 0
+#endif
+#ifndef IPPROTO_ROUTING
+#define IPPROTO_ROUTING 43
+#endif
+#ifndef IPPROTO_FRAGMENT
+#define IPPROTO_FRAGMENT 44
+#endif
+#ifndef IPPROTO_DSTOPTS
+#define IPPROTO_DSTOPTS 60
+#endif
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+#define GENEVE_PORT 6081
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#define JMP(c) ((c)|BPF_JMP|BPF_K)
+
+/*
+ * "Push" the current value of the link-layer header type and link-layer
+ * header offset onto a "stack", and set a new value. (It's not a
+ * full-blown stack; we keep only the top two items.)
+ */
+#define PUSH_LINKHDR(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \
+{ \
+ (cs)->prevlinktype = (cs)->linktype; \
+ (cs)->off_prevlinkhdr = (cs)->off_linkhdr; \
+ (cs)->linktype = (new_linktype); \
+ (cs)->off_linkhdr.is_variable = (new_is_variable); \
+ (cs)->off_linkhdr.constant_part = (new_constant_part); \
+ (cs)->off_linkhdr.reg = (new_reg); \
+ (cs)->is_geneve = 0; \
+}
+
+/*
+ * Offset "not set" value.
+ */
+#define OFFSET_NOT_SET 0xffffffffU
+
+/*
+ * Absolute offsets, which are offsets from the beginning of the raw
+ * packet data, are, in the general case, the sum of a variable value
+ * and a constant value; the variable value may be absent, in which
+ * case the offset is only the constant value, and the constant value
+ * may be zero, in which case the offset is only the variable value.
+ *
+ * bpf_abs_offset is a structure containing all that information:
+ *
+ * is_variable is 1 if there's a variable part.
+ *
+ * constant_part is the constant part of the value, possibly zero;
+ *
+ * if is_variable is 1, reg is the register number for a register
+ * containing the variable value if the register has been assigned,
+ * and -1 otherwise.
+ */
+typedef struct {
+ int is_variable;
+ u_int constant_part;
+ int reg;
+} bpf_abs_offset;
+
+/*
+ * Value passed to gen_load_a() to indicate what the offset argument
+ * is relative to the beginning of.
+ */
+enum e_offrel {
+ OR_PACKET, /* full packet data */
+ OR_LINKHDR, /* link-layer header */
+ OR_PREVLINKHDR, /* previous link-layer header */
+ OR_LLC, /* 802.2 LLC header */
+ OR_PREVMPLSHDR, /* previous MPLS header */
+ OR_LINKTYPE, /* link-layer type */
+ OR_LINKPL, /* link-layer payload */
+ OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */
+ OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */
+ OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */
+};
+
+/*
+ * We divy out chunks of memory rather than call malloc each time so
+ * we don't have to worry about leaking memory. It's probably
+ * not a big deal if all this memory was wasted but if this ever
+ * goes into a library that would probably not be a good idea.
+ *
+ * XXX - this *is* in a library....
+ */
+#define NCHUNKS 16
+#define CHUNK0SIZE 1024
+struct chunk {
+ size_t n_left;
+ void *m;
+};
+
+/* Code generator state */
+
+struct _compiler_state {
+ jmp_buf top_ctx;
+ pcap_t *bpf_pcap;
+ int error_set;
+
+ struct icode ic;
+
+ int snaplen;
+
+ int linktype;
+ int prevlinktype;
+ int outermostlinktype;
+
+ bpf_u_int32 netmask;
+ int no_optimize;
+
+ /* Hack for handling VLAN and MPLS stacks. */
+ u_int label_stack_depth;
+ u_int vlan_stack_depth;
+
+ /* XXX */
+ u_int pcap_fddipad;
+
+ /*
+ * As errors are handled by a longjmp, anything allocated must
+ * be freed in the longjmp handler, so it must be reachable
+ * from that handler.
+ *
+ * One thing that's allocated is the result of pcap_nametoaddrinfo();
+ * it must be freed with freeaddrinfo(). This variable points to
+ * any addrinfo structure that would need to be freed.
+ */
+ struct addrinfo *ai;
+
+ /*
+ * Another thing that's allocated is the result of pcap_ether_aton();
+ * it must be freed with free(). This variable points to any
+ * address that would need to be freed.
+ */
+ u_char *e;
+
+ /*
+ * Various code constructs need to know the layout of the packet.
+ * These values give the necessary offsets from the beginning
+ * of the packet data.
+ */
+
+ /*
+ * Absolute offset of the beginning of the link-layer header.
+ */
+ bpf_abs_offset off_linkhdr;
+
+ /*
+ * If we're checking a link-layer header for a packet encapsulated
+ * in another protocol layer, this is the equivalent information
+ * for the previous layers' link-layer header from the beginning
+ * of the raw packet data.
+ */
+ bpf_abs_offset off_prevlinkhdr;
+
+ /*
+ * This is the equivalent information for the outermost layers'
+ * link-layer header.
+ */
+ bpf_abs_offset off_outermostlinkhdr;
+
+ /*
+ * Absolute offset of the beginning of the link-layer payload.
+ */
+ bpf_abs_offset off_linkpl;
+
+ /*
+ * "off_linktype" is the offset to information in the link-layer
+ * header giving the packet type. This is an absolute offset
+ * from the beginning of the packet.
+ *
+ * For Ethernet, it's the offset of the Ethernet type field; this
+ * means that it must have a value that skips VLAN tags.
+ *
+ * For link-layer types that always use 802.2 headers, it's the
+ * offset of the LLC header; this means that it must have a value
+ * that skips VLAN tags.
+ *
+ * For PPP, it's the offset of the PPP type field.
+ *
+ * For Cisco HDLC, it's the offset of the CHDLC type field.
+ *
+ * For BSD loopback, it's the offset of the AF_ value.
+ *
+ * For Linux cooked sockets, it's the offset of the type field.
+ *
+ * off_linktype.constant_part is set to OFFSET_NOT_SET for no
+ * encapsulation, in which case, IP is assumed.
+ */
+ bpf_abs_offset off_linktype;
+
+ /*
+ * TRUE if the link layer includes an ATM pseudo-header.
+ */
+ int is_atm;
+
+ /*
+ * TRUE if "geneve" appeared in the filter; it causes us to
+ * generate code that checks for a Geneve header and assume
+ * that later filters apply to the encapsulated payload.
+ */
+ int is_geneve;
+
+ /*
+ * TRUE if we need variable length part of VLAN offset
+ */
+ int is_vlan_vloffset;
+
+ /*
+ * These are offsets for the ATM pseudo-header.
+ */
+ u_int off_vpi;
+ u_int off_vci;
+ u_int off_proto;
+
+ /*
+ * These are offsets for the MTP2 fields.
+ */
+ u_int off_li;
+ u_int off_li_hsl;
+
+ /*
+ * These are offsets for the MTP3 fields.
+ */
+ u_int off_sio;
+ u_int off_opc;
+ u_int off_dpc;
+ u_int off_sls;
+
+ /*
+ * This is the offset of the first byte after the ATM pseudo_header,
+ * or -1 if there is no ATM pseudo-header.
+ */
+ u_int off_payload;
+
+ /*
+ * These are offsets to the beginning of the network-layer header.
+ * They are relative to the beginning of the link-layer payload
+ * (i.e., they don't include off_linkhdr.constant_part or
+ * off_linkpl.constant_part).
+ *
+ * If the link layer never uses 802.2 LLC:
+ *
+ * "off_nl" and "off_nl_nosnap" are the same.
+ *
+ * If the link layer always uses 802.2 LLC:
+ *
+ * "off_nl" is the offset if there's a SNAP header following
+ * the 802.2 header;
+ *
+ * "off_nl_nosnap" is the offset if there's no SNAP header.
+ *
+ * If the link layer is Ethernet:
+ *
+ * "off_nl" is the offset if the packet is an Ethernet II packet
+ * (we assume no 802.3+802.2+SNAP);
+ *
+ * "off_nl_nosnap" is the offset if the packet is an 802.3 packet
+ * with an 802.2 header following it.
+ */
+ u_int off_nl;
+ u_int off_nl_nosnap;
+
+ /*
+ * Here we handle simple allocation of the scratch registers.
+ * If too many registers are alloc'd, the allocator punts.
+ */
+ int regused[BPF_MEMWORDS];
+ int curreg;
+
+ /*
+ * Memory chunks.
+ */
+ struct chunk chunks[NCHUNKS];
+ int cur_chunk;
+};
+
+/*
+ * For use by routines outside this file.
+ */
+/* VARARGS */
+void
+bpf_set_error(compiler_state_t *cstate, const char *fmt, ...)
+{
+ va_list ap;
+
+ /*
+ * If we've already set an error, don't override it.
+ * The lexical analyzer reports some errors by setting
+ * the error and then returning a LEX_ERROR token, which
+ * is not recognized by any grammar rule, and thus forces
+ * the parse to stop. We don't want the error reported
+ * by the lexical analyzer to be overwritten by the syntax
+ * error.
+ */
+ if (!cstate->error_set) {
+ va_start(ap, fmt);
+ (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+ fmt, ap);
+ va_end(ap);
+ cstate->error_set = 1;
+ }
+}
+
+/*
+ * For use *ONLY* in routines in this file.
+ */
+static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
+
+/* VARARGS */
+static void PCAP_NORETURN
+bpf_error(compiler_state_t *cstate, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+ fmt, ap);
+ va_end(ap);
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+}
+
+static int init_linktype(compiler_state_t *, pcap_t *);
+
+static void init_regs(compiler_state_t *);
+static int alloc_reg(compiler_state_t *);
+static void free_reg(compiler_state_t *, int);
+
+static void initchunks(compiler_state_t *cstate);
+static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t);
+static void *newchunk(compiler_state_t *cstate, size_t);
+static void freechunks(compiler_state_t *cstate);
+static inline struct block *new_block(compiler_state_t *cstate, int);
+static inline struct slist *new_stmt(compiler_state_t *cstate, int);
+static struct block *gen_retblk(compiler_state_t *cstate, int);
+static inline void syntax(compiler_state_t *cstate);
+
+static void backpatch(struct block *, struct block *);
+static void merge(struct block *, struct block *);
+static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32);
+static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32);
+static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32);
+static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32);
+static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32);
+static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32, bpf_u_int32);
+static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
+ u_int, const u_char *);
+static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32, int, int, bpf_u_int32);
+static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
+ u_int, u_int);
+static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
+ u_int);
+static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
+static struct block *gen_uncond(compiler_state_t *, int);
+static inline struct block *gen_true(compiler_state_t *);
+static inline struct block *gen_false(compiler_state_t *);
+static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
+static struct slist *gen_load_prism_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_avs_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *);
+static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *);
+static void insert_compute_vloffsets(compiler_state_t *, struct block *);
+static struct slist *gen_abs_offset_varpart(compiler_state_t *,
+ bpf_abs_offset *);
+static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32);
+static struct block *gen_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32);
+static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
+ int, bpf_u_int32, u_int, u_int);
+#ifdef INET6
+static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
+ struct in6_addr *, int, bpf_u_int32, u_int, u_int);
+#endif
+static struct block *gen_ahostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_fhostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
+static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
+static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
+ int, int, int);
+#ifdef INET6
+static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
+ struct in6_addr *, int, int, int);
+#endif
+#ifndef INET6
+static struct block *gen_gateway(compiler_state_t *, const u_char *,
+ struct addrinfo *, int, int);
+#endif
+static struct block *gen_ipfrag(compiler_state_t *);
+static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32,
+ bpf_u_int32);
+static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32,
+ bpf_u_int32);
+static struct block *gen_portop(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port(compiler_state_t *, u_int, int, int);
+static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int,
+ bpf_u_int32, int);
+static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int);
+struct block *gen_portop6(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port6(compiler_state_t *, u_int, int, int);
+static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int,
+ bpf_u_int32, int);
+static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int);
+static int lookup_proto(compiler_state_t *, const char *, int);
+static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int);
+static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int);
+static struct slist *xfer_to_x(compiler_state_t *, struct arth *);
+static struct slist *xfer_to_a(compiler_state_t *, struct arth *);
+static struct block *gen_mac_multicast(compiler_state_t *, int);
+static struct block *gen_len(compiler_state_t *, int, int);
+static struct block *gen_check_802_11_data_frame(compiler_state_t *);
+static struct block *gen_geneve_ll_check(compiler_state_t *cstate);
+
+static struct block *gen_ppi_dlt_check(compiler_state_t *);
+static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
+ bpf_u_int32, int, int);
+static struct block *gen_atmtype_llc(compiler_state_t *);
+static struct block *gen_msg_abbrev(compiler_state_t *, int type);
+
+static void
+initchunks(compiler_state_t *cstate)
+{
+ int i;
+
+ for (i = 0; i < NCHUNKS; i++) {
+ cstate->chunks[i].n_left = 0;
+ cstate->chunks[i].m = NULL;
+ }
+ cstate->cur_chunk = 0;
+}
+
+static void *
+newchunk_nolongjmp(compiler_state_t *cstate, size_t n)
+{
+ struct chunk *cp;
+ int k;
+ size_t size;
+
+#ifndef __NetBSD__
+ /* XXX Round up to nearest long. */
+ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+#else
+ /* XXX Round up to structure boundary. */
+ n = ALIGN(n);
+#endif
+
+ cp = &cstate->chunks[cstate->cur_chunk];
+ if (n > cp->n_left) {
+ ++cp;
+ k = ++cstate->cur_chunk;
+ if (k >= NCHUNKS) {
+ bpf_set_error(cstate, "out of memory");
+ return (NULL);
+ }
+ size = CHUNK0SIZE << k;
+ cp->m = (void *)malloc(size);
+ if (cp->m == NULL) {
+ bpf_set_error(cstate, "out of memory");
+ return (NULL);
+ }
+ memset((char *)cp->m, 0, size);
+ cp->n_left = size;
+ if (n > size) {
+ bpf_set_error(cstate, "out of memory");
+ return (NULL);
+ }
+ }
+ cp->n_left -= n;
+ return (void *)((char *)cp->m + cp->n_left);
+}
+
+static void *
+newchunk(compiler_state_t *cstate, size_t n)
+{
+ void *p;
+
+ p = newchunk_nolongjmp(cstate, n);
+ if (p == NULL) {
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+ }
+ return (p);
+}
+
+static void
+freechunks(compiler_state_t *cstate)
+{
+ int i;
+
+ for (i = 0; i < NCHUNKS; ++i)
+ if (cstate->chunks[i].m != NULL)
+ free(cstate->chunks[i].m);
+}
+
+/*
+ * A strdup whose allocations are freed after code generation is over.
+ * This is used by the lexical analyzer, so it can't longjmp; it just
+ * returns NULL on an allocation error, and the callers must check
+ * for it.
+ */
+char *
+sdup(compiler_state_t *cstate, const char *s)
+{
+ size_t n = strlen(s) + 1;
+ char *cp = newchunk_nolongjmp(cstate, n);
+
+ if (cp == NULL)
+ return (NULL);
+ pcap_strlcpy(cp, s, n);
+ return (cp);
+}
+
+static inline struct block *
+new_block(compiler_state_t *cstate, int code)
+{
+ struct block *p;
+
+ p = (struct block *)newchunk(cstate, sizeof(*p));
+ p->s.code = code;
+ p->head = p;
+
+ return p;
+}
+
+static inline struct slist *
+new_stmt(compiler_state_t *cstate, int code)
+{
+ struct slist *p;
+
+ p = (struct slist *)newchunk(cstate, sizeof(*p));
+ p->s.code = code;
+
+ return p;
+}
+
+static struct block *
+gen_retblk(compiler_state_t *cstate, int v)
+{
+ struct block *b = new_block(cstate, BPF_RET|BPF_K);
+
+ b->s.k = v;
+ return b;
+}
+
+static inline PCAP_NORETURN_DEF void
+syntax(compiler_state_t *cstate)
+{
+ bpf_error(cstate, "syntax error in filter expression");
+}
+
+int
+pcap_compile(pcap_t *p, struct bpf_program *program,
+ const char *buf, int optimize, bpf_u_int32 mask)
+{
+#ifdef _WIN32
+ static int done = 0;
+#endif
+ compiler_state_t cstate;
+ const char * volatile xbuf = buf;
+ yyscan_t scanner = NULL;
+ volatile YY_BUFFER_STATE in_buffer = NULL;
+ u_int len;
+ int rc;
+
+ /*
+ * If this pcap_t hasn't been activated, it doesn't have a
+ * link-layer type, so we can't use it.
+ */
+ if (!p->activated) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "not-yet-activated pcap_t passed to pcap_compile");
+ return (-1);
+ }
+
+#ifdef _WIN32
+ if (!done)
+ pcap_wsockinit();
+ done = 1;
+#endif
+
+#ifdef ENABLE_REMOTE
+ /*
+ * If the device on which we're capturing need to be notified
+ * that a new filter is being compiled, do so.
+ *
+ * This allows them to save a copy of it, in case, for example,
+ * they're implementing a form of remote packet capture, and
+ * want the remote machine to filter out the packets in which
+ * it's sending the packets it's captured.
+ *
+ * XXX - the fact that we happen to be compiling a filter
+ * doesn't necessarily mean we'll be installing it as the
+ * filter for this pcap_t; we might be running it from userland
+ * on captured packets to do packet classification. We really
+ * need a better way of handling this, but this is all that
+ * the WinPcap remote capture code did.
+ */
+ if (p->save_current_filter_op != NULL)
+ (p->save_current_filter_op)(p, buf);
+#endif
+
+ initchunks(&cstate);
+ cstate.no_optimize = 0;
+#ifdef INET6
+ cstate.ai = NULL;
+#endif
+ cstate.e = NULL;
+ cstate.ic.root = NULL;
+ cstate.ic.cur_mark = 0;
+ cstate.bpf_pcap = p;
+ cstate.error_set = 0;
+ init_regs(&cstate);
+
+ cstate.netmask = mask;
+
+ cstate.snaplen = pcap_snapshot(p);
+ if (cstate.snaplen == 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "snaplen of 0 rejects all packets");
+ rc = -1;
+ goto quit;
+ }
+
+ if (pcap_lex_init(&scanner) != 0)
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "can't initialize scanner");
+ in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
+
+ /*
+ * Associate the compiler state with the lexical analyzer
+ * state.
+ */
+ pcap_set_extra(&cstate, scanner);
+
+ if (init_linktype(&cstate, p) == -1) {
+ rc = -1;
+ goto quit;
+ }
+ if (pcap_parse(scanner, &cstate) != 0) {
+#ifdef INET6
+ if (cstate.ai != NULL)
+ freeaddrinfo(cstate.ai);
+#endif
+ if (cstate.e != NULL)
+ free(cstate.e);
+ rc = -1;
+ goto quit;
+ }
+
+ if (cstate.ic.root == NULL) {
+ /*
+ * Catch errors reported by gen_retblk().
+ */
+ if (setjmp(cstate.top_ctx)) {
+ rc = -1;
+ goto quit;
+ }
+ cstate.ic.root = gen_retblk(&cstate, cstate.snaplen);
+ }
+
+ if (optimize && !cstate.no_optimize) {
+ if (bpf_optimize(&cstate.ic, p->errbuf) == -1) {
+ /* Failure */
+ rc = -1;
+ goto quit;
+ }
+ if (cstate.ic.root == NULL ||
+ (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
+ (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "expression rejects all packets");
+ rc = -1;
+ goto quit;
+ }
+ }
+ program->bf_insns = icode_to_fcode(&cstate.ic,
+ cstate.ic.root, &len, p->errbuf);
+ if (program->bf_insns == NULL) {
+ /* Failure */
+ rc = -1;
+ goto quit;
+ }
+ program->bf_len = len;
+
+ rc = 0; /* We're all okay */
+
+quit:
+ /*
+ * Clean up everything for the lexical analyzer.
+ */
+ if (in_buffer != NULL)
+ pcap__delete_buffer(in_buffer, scanner);
+ if (scanner != NULL)
+ pcap_lex_destroy(scanner);
+
+ /*
+ * Clean up our own allocated memory.
+ */
+ freechunks(&cstate);
+
+ return (rc);
+}
+
+/*
+ * entry point for using the compiler with no pcap open
+ * pass in all the stuff that is needed explicitly instead.
+ */
+int
+pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
+ struct bpf_program *program,
+ const char *buf, int optimize, bpf_u_int32 mask)
+{
+ pcap_t *p;
+ int ret;
+
+ p = pcap_open_dead(linktype_arg, snaplen_arg);
+ if (p == NULL)
+ return (-1);
+ ret = pcap_compile(p, program, buf, optimize, mask);
+ pcap_close(p);
+ return (ret);
+}
+
+/*
+ * Clean up a "struct bpf_program" by freeing all the memory allocated
+ * in it.
+ */
+void
+pcap_freecode(struct bpf_program *program)
+{
+ program->bf_len = 0;
+ if (program->bf_insns != NULL) {
+ free((char *)program->bf_insns);
+ program->bf_insns = NULL;
+ }
+}
+
+/*
+ * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates
+ * which of the jt and jf fields has been resolved and which is a pointer
+ * back to another unresolved block (or nil). At least one of the fields
+ * in each block is already resolved.
+ */
+static void
+backpatch(struct block *list, struct block *target)
+{
+ struct block *next;
+
+ while (list) {
+ if (!list->sense) {
+ next = JT(list);
+ JT(list) = target;
+ } else {
+ next = JF(list);
+ JF(list) = target;
+ }
+ list = next;
+ }
+}
+
+/*
+ * Merge the lists in b0 and b1, using the 'sense' field to indicate
+ * which of jt and jf is the link.
+ */
+static void
+merge(struct block *b0, struct block *b1)
+{
+ register struct block **p = &b0;
+
+ /* Find end of list. */
+ while (*p)
+ p = !((*p)->sense) ? &JT(*p) : &JF(*p);
+
+ /* Concatenate the lists. */
+ *p = b1;
+}
+
+int
+finish_parse(compiler_state_t *cstate, struct block *p)
+{
+ struct block *ppi_dlt_check;
+
+ /*
+ * Catch errors reported by us and routines below us, and return -1
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (-1);
+
+ /*
+ * Insert before the statements of the first (root) block any
+ * statements needed to load the lengths of any variable-length
+ * headers into registers.
+ *
+ * XXX - a fancier strategy would be to insert those before the
+ * statements of all blocks that use those lengths and that
+ * have no predecessors that use them, so that we only compute
+ * the lengths if we need them. There might be even better
+ * approaches than that.
+ *
+ * However, those strategies would be more complicated, and
+ * as we don't generate code to compute a length if the
+ * program has no tests that use the length, and as most
+ * tests will probably use those lengths, we would just
+ * postpone computing the lengths so that it's not done
+ * for tests that fail early, and it's not clear that's
+ * worth the effort.
+ */
+ insert_compute_vloffsets(cstate, p->head);
+
+ /*
+ * For DLT_PPI captures, generate a check of the per-packet
+ * DLT value to make sure it's DLT_IEEE802_11.
+ *
+ * XXX - TurboCap cards use DLT_PPI for Ethernet.
+ * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header
+ * with appropriate Ethernet information and use that rather
+ * than using something such as DLT_PPI where you don't know
+ * the link-layer header type until runtime, which, in the
+ * general case, would force us to generate both Ethernet *and*
+ * 802.11 code (*and* anything else for which PPI is used)
+ * and choose between them early in the BPF program?
+ */
+ ppi_dlt_check = gen_ppi_dlt_check(cstate);
+ if (ppi_dlt_check != NULL)
+ gen_and(ppi_dlt_check, p);
+
+ backpatch(p, gen_retblk(cstate, cstate->snaplen));
+ p->sense = !p->sense;
+ backpatch(p, gen_retblk(cstate, 0));
+ cstate->ic.root = p->head;
+ return (0);
+}
+
+void
+gen_and(struct block *b0, struct block *b1)
+{
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ b1->sense = !b1->sense;
+ merge(b1, b0);
+ b1->sense = !b1->sense;
+ b1->head = b0->head;
+}
+
+void
+gen_or(struct block *b0, struct block *b1)
+{
+ b0->sense = !b0->sense;
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ merge(b1, b0);
+ b1->head = b0->head;
+}
+
+void
+gen_not(struct block *b)
+{
+ b->sense = !b->sense;
+}
+
+static struct block *
+gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v)
+{
+ return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
+}
+
+static struct block *
+gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v)
+{
+ return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
+}
+
+static struct block *
+gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v)
+{
+ return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
+}
+
+static struct block *
+gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v)
+{
+ return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
+}
+
+static struct block *
+gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v)
+{
+ return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
+}
+
+static struct block *
+gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 v, bpf_u_int32 mask)
+{
+ return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
+}
+
+static struct block *
+gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, const u_char *v)
+{
+ register struct block *b, *tmp;
+
+ b = NULL;
+ while (size >= 4) {
+ register const u_char *p = &v[size - 4];
+
+ tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
+ EXTRACT_BE_U_4(p));
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 4;
+ }
+ while (size >= 2) {
+ register const u_char *p = &v[size - 2];
+
+ tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
+ EXTRACT_BE_U_2(p));
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 2;
+ }
+ if (size > 0) {
+ tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
+ if (b != NULL)
+ gen_and(b, tmp);
+ b = tmp;
+ }
+ return b;
+}
+
+/*
+ * AND the field of size "size" at offset "offset" relative to the header
+ * specified by "offrel" with "mask", and compare it with the value "v"
+ * with the test specified by "jtype"; if "reverse" is true, the test
+ * should test the opposite of "jtype".
+ */
+static struct block *
+gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 mask, int jtype, int reverse,
+ bpf_u_int32 v)
+{
+ struct slist *s, *s2;
+ struct block *b;
+
+ s = gen_load_a(cstate, offrel, offset, size);
+
+ if (mask != 0xffffffff) {
+ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+ s2->s.k = mask;
+ sappend(s, s2);
+ }
+
+ b = new_block(cstate, JMP(jtype));
+ b->stmts = s;
+ b->s.k = v;
+ if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE))
+ gen_not(b);
+ return b;
+}
+
+static int
+init_linktype(compiler_state_t *cstate, pcap_t *p)
+{
+ cstate->pcap_fddipad = p->fddipad;
+
+ /*
+ * We start out with only one link-layer header.
+ */
+ cstate->outermostlinktype = pcap_datalink(p);
+ cstate->off_outermostlinkhdr.constant_part = 0;
+ cstate->off_outermostlinkhdr.is_variable = 0;
+ cstate->off_outermostlinkhdr.reg = -1;
+
+ cstate->prevlinktype = cstate->outermostlinktype;
+ cstate->off_prevlinkhdr.constant_part = 0;
+ cstate->off_prevlinkhdr.is_variable = 0;
+ cstate->off_prevlinkhdr.reg = -1;
+
+ cstate->linktype = cstate->outermostlinktype;
+ cstate->off_linkhdr.constant_part = 0;
+ cstate->off_linkhdr.is_variable = 0;
+ cstate->off_linkhdr.reg = -1;
+
+ /*
+ * XXX
+ */
+ cstate->off_linkpl.constant_part = 0;
+ cstate->off_linkpl.is_variable = 0;
+ cstate->off_linkpl.reg = -1;
+
+ cstate->off_linktype.constant_part = 0;
+ cstate->off_linktype.is_variable = 0;
+ cstate->off_linktype.reg = -1;
+
+ /*
+ * Assume it's not raw ATM with a pseudo-header, for now.
+ */
+ cstate->is_atm = 0;
+ cstate->off_vpi = OFFSET_NOT_SET;
+ cstate->off_vci = OFFSET_NOT_SET;
+ cstate->off_proto = OFFSET_NOT_SET;
+ cstate->off_payload = OFFSET_NOT_SET;
+
+ /*
+ * And not Geneve.
+ */
+ cstate->is_geneve = 0;
+
+ /*
+ * No variable length VLAN offset by default
+ */
+ cstate->is_vlan_vloffset = 0;
+
+ /*
+ * And assume we're not doing SS7.
+ */
+ cstate->off_li = OFFSET_NOT_SET;
+ cstate->off_li_hsl = OFFSET_NOT_SET;
+ cstate->off_sio = OFFSET_NOT_SET;
+ cstate->off_opc = OFFSET_NOT_SET;
+ cstate->off_dpc = OFFSET_NOT_SET;
+ cstate->off_sls = OFFSET_NOT_SET;
+
+ cstate->label_stack_depth = 0;
+ cstate->vlan_stack_depth = 0;
+
+ switch (cstate->linktype) {
+
+ case DLT_ARCNET:
+ cstate->off_linktype.constant_part = 2;
+ cstate->off_linkpl.constant_part = 6;
+ cstate->off_nl = 0; /* XXX in reality, variable! */
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_ARCNET_LINUX:
+ cstate->off_linktype.constant_part = 4;
+ cstate->off_linkpl.constant_part = 8;
+ cstate->off_nl = 0; /* XXX in reality, variable! */
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_EN10MB:
+ cstate->off_linktype.constant_part = 12;
+ cstate->off_linkpl.constant_part = 14; /* Ethernet header length */
+ cstate->off_nl = 0; /* Ethernet II */
+ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
+ break;
+
+ case DLT_SLIP:
+ /*
+ * SLIP doesn't have a link level type. The 16 byte
+ * header is hacked into our SLIP driver.
+ */
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 16;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_SLIP_BSDOS:
+ /* XXX this may be the same as the DLT_PPP_BSDOS case */
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ /* XXX end */
+ cstate->off_linkpl.constant_part = 24;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ cstate->off_linktype.constant_part = 0;
+ cstate->off_linkpl.constant_part = 4;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_ENC:
+ cstate->off_linktype.constant_part = 0;
+ cstate->off_linkpl.constant_part = 12;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_PPP:
+ case DLT_PPP_PPPD:
+ case DLT_C_HDLC: /* BSD/OS Cisco HDLC */
+ case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */
+ cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */
+ cstate->off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_PPP_ETHER:
+ /*
+ * This does no include the Ethernet header, and
+ * only covers session state.
+ */
+ cstate->off_linktype.constant_part = 6;
+ cstate->off_linkpl.constant_part = 8;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_PPP_BSDOS:
+ cstate->off_linktype.constant_part = 5;
+ cstate->off_linkpl.constant_part = 24;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_FDDI:
+ /*
+ * FDDI doesn't really have a link-level type field.
+ * We set "off_linktype" to the offset of the LLC header.
+ *
+ * To check for Ethernet types, we assume that SSAP = SNAP
+ * is being used and pick out the encapsulated Ethernet type.
+ * XXX - should we generate code to check for SNAP?
+ */
+ cstate->off_linktype.constant_part = 13;
+ cstate->off_linktype.constant_part += cstate->pcap_fddipad;
+ cstate->off_linkpl.constant_part = 13; /* FDDI MAC header length */
+ cstate->off_linkpl.constant_part += cstate->pcap_fddipad;
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_IEEE802:
+ /*
+ * Token Ring doesn't really have a link-level type field.
+ * We set "off_linktype" to the offset of the LLC header.
+ *
+ * To check for Ethernet types, we assume that SSAP = SNAP
+ * is being used and pick out the encapsulated Ethernet type.
+ * XXX - should we generate code to check for SNAP?
+ *
+ * XXX - the header is actually variable-length.
+ * Some various Linux patched versions gave 38
+ * as "off_linktype" and 40 as "off_nl"; however,
+ * if a token ring packet has *no* routing
+ * information, i.e. is not source-routed, the correct
+ * values are 20 and 22, as they are in the vanilla code.
+ *
+ * A packet is source-routed iff the uppermost bit
+ * of the first byte of the source address, at an
+ * offset of 8, has the uppermost bit set. If the
+ * packet is source-routed, the total number of bytes
+ * of routing information is 2 plus bits 0x1F00 of
+ * the 16-bit value at an offset of 14 (shifted right
+ * 8 - figure out which byte that is).
+ */
+ cstate->off_linktype.constant_part = 14;
+ cstate->off_linkpl.constant_part = 14; /* Token Ring MAC header length */
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ cstate->off_linkhdr.is_variable = 1;
+ /* Fall through, 802.11 doesn't have a variable link
+ * prefix but is otherwise the same. */
+ /* FALLTHROUGH */
+
+ case DLT_IEEE802_11:
+ /*
+ * 802.11 doesn't really have a link-level type field.
+ * We set "off_linktype.constant_part" to the offset of
+ * the LLC header.
+ *
+ * To check for Ethernet types, we assume that SSAP = SNAP
+ * is being used and pick out the encapsulated Ethernet type.
+ * XXX - should we generate code to check for SNAP?
+ *
+ * We also handle variable-length radio headers here.
+ * The Prism header is in theory variable-length, but in
+ * practice it's always 144 bytes long. However, some
+ * drivers on Linux use ARPHRD_IEEE80211_PRISM, but
+ * sometimes or always supply an AVS header, so we
+ * have to check whether the radio header is a Prism
+ * header or an AVS header, so, in practice, it's
+ * variable-length.
+ */
+ cstate->off_linktype.constant_part = 24;
+ cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */
+ cstate->off_linkpl.is_variable = 1;
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_PPI:
+ /*
+ * At the moment we treat PPI the same way that we treat
+ * normal Radiotap encoded packets. The difference is in
+ * the function that generates the code at the beginning
+ * to compute the header length. Since this code generator
+ * of PPI supports bare 802.11 encapsulation only (i.e.
+ * the encapsulated DLT should be DLT_IEEE802_11) we
+ * generate code to check for this too.
+ */
+ cstate->off_linktype.constant_part = 24;
+ cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */
+ cstate->off_linkpl.is_variable = 1;
+ cstate->off_linkhdr.is_variable = 1;
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_ATM_RFC1483:
+ case DLT_ATM_CLIP: /* Linux ATM defines this */
+ /*
+ * assume routed, non-ISO PDUs
+ * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00)
+ *
+ * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS,
+ * or PPP with the PPP NLPID (e.g., PPPoA)? The
+ * latter would presumably be treated the way PPPoE
+ * should be, so you can do "pppoe and udp port 2049"
+ * or "pppoa and tcp port 80" and have it check for
+ * PPPo{A,E} and a PPP protocol of IP and....
+ */
+ cstate->off_linktype.constant_part = 0;
+ cstate->off_linkpl.constant_part = 0; /* packet begins with LLC header */
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_SUNATM:
+ /*
+ * Full Frontal ATM; you get AALn PDUs with an ATM
+ * pseudo-header.
+ */
+ cstate->is_atm = 1;
+ cstate->off_vpi = SUNATM_VPI_POS;
+ cstate->off_vci = SUNATM_VCI_POS;
+ cstate->off_proto = PROTO_POS;
+ cstate->off_payload = SUNATM_PKT_BEGIN_POS;
+ cstate->off_linktype.constant_part = cstate->off_payload;
+ cstate->off_linkpl.constant_part = cstate->off_payload; /* if LLC-encapsulated */
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_RAW:
+ case DLT_IPV4:
+ case DLT_IPV6:
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 0;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */
+ cstate->off_linktype.constant_part = 14;
+ cstate->off_linkpl.constant_part = 16;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */
+ cstate->off_linktype.constant_part = 0;
+ cstate->off_linkpl.constant_part = 20;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_LTALK:
+ /*
+ * LocalTalk does have a 1-byte type field in the LLAP header,
+ * but really it just indicates whether there is a "short" or
+ * "long" DDP packet following.
+ */
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 0;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_IP_OVER_FC:
+ /*
+ * RFC 2625 IP-over-Fibre-Channel doesn't really have a
+ * link-level type field. We set "off_linktype" to the
+ * offset of the LLC header.
+ *
+ * To check for Ethernet types, we assume that SSAP = SNAP
+ * is being used and pick out the encapsulated Ethernet type.
+ * XXX - should we generate code to check for SNAP? RFC
+ * 2625 says SNAP should be used.
+ */
+ cstate->off_linktype.constant_part = 16;
+ cstate->off_linkpl.constant_part = 16;
+ cstate->off_nl = 8; /* 802.2+SNAP */
+ cstate->off_nl_nosnap = 3; /* 802.2 */
+ break;
+
+ case DLT_FRELAY:
+ /*
+ * XXX - we should set this to handle SNAP-encapsulated
+ * frames (NLPID of 0x80).
+ */
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 0;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ /*
+ * the only BPF-interesting FRF.16 frames are non-control frames;
+ * Frame Relay has a variable length link-layer
+ * so lets start with offset 4 for now and increments later on (FIXME);
+ */
+ case DLT_MFR:
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 0;
+ cstate->off_nl = 4;
+ cstate->off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */
+ break;
+
+ case DLT_APPLE_IP_OVER_IEEE1394:
+ cstate->off_linktype.constant_part = 16;
+ cstate->off_linkpl.constant_part = 18;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+ break;
+
+ case DLT_SYMANTEC_FIREWALL:
+ cstate->off_linktype.constant_part = 6;
+ cstate->off_linkpl.constant_part = 44;
+ cstate->off_nl = 0; /* Ethernet II */
+ cstate->off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */
+ break;
+
+#ifdef HAVE_NET_PFVAR_H
+ case DLT_PFLOG:
+ 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:
+ case DLT_JUNIPER_MLFR:
+ case DLT_JUNIPER_MLPPP:
+ case DLT_JUNIPER_PPP:
+ case DLT_JUNIPER_CHDLC:
+ case DLT_JUNIPER_FRELAY:
+ cstate->off_linktype.constant_part = 4;
+ cstate->off_linkpl.constant_part = 4;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_JUNIPER_ATM1:
+ cstate->off_linktype.constant_part = 4; /* in reality variable between 4-8 */
+ cstate->off_linkpl.constant_part = 4; /* in reality variable between 4-8 */
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 10;
+ break;
+
+ case DLT_JUNIPER_ATM2:
+ cstate->off_linktype.constant_part = 8; /* in reality variable between 8-12 */
+ cstate->off_linkpl.constant_part = 8; /* in reality variable between 8-12 */
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 10;
+ break;
+
+ /* frames captured on a Juniper PPPoE service PIC
+ * contain raw ethernet frames */
+ case DLT_JUNIPER_PPPOE:
+ case DLT_JUNIPER_ETHER:
+ cstate->off_linkpl.constant_part = 14;
+ cstate->off_linktype.constant_part = 16;
+ cstate->off_nl = 18; /* Ethernet II */
+ cstate->off_nl_nosnap = 21; /* 802.3+802.2 */
+ break;
+
+ case DLT_JUNIPER_PPPOE_ATM:
+ cstate->off_linktype.constant_part = 4;
+ cstate->off_linkpl.constant_part = 6;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_JUNIPER_GGSN:
+ cstate->off_linktype.constant_part = 6;
+ cstate->off_linkpl.constant_part = 12;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_JUNIPER_ES:
+ cstate->off_linktype.constant_part = 6;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */
+ cstate->off_nl = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_JUNIPER_MONITOR:
+ cstate->off_linktype.constant_part = 12;
+ cstate->off_linkpl.constant_part = 12;
+ cstate->off_nl = 0; /* raw IP/IP6 header */
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_BACNET_MS_TP:
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_JUNIPER_SERVICES:
+ cstate->off_linktype.constant_part = 12;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */
+ cstate->off_nl = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_JUNIPER_VP:
+ cstate->off_linktype.constant_part = 18;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_JUNIPER_ST:
+ cstate->off_linktype.constant_part = 18;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_JUNIPER_ISM:
+ cstate->off_linktype.constant_part = 8;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_JUNIPER_VS:
+ case DLT_JUNIPER_SRX_E2E:
+ case DLT_JUNIPER_FIBRECHANNEL:
+ case DLT_JUNIPER_ATM_CEMIC:
+ cstate->off_linktype.constant_part = 8;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_MTP2:
+ cstate->off_li = 2;
+ cstate->off_li_hsl = 4;
+ cstate->off_sio = 3;
+ cstate->off_opc = 4;
+ cstate->off_dpc = 4;
+ cstate->off_sls = 7;
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_MTP2_WITH_PHDR:
+ cstate->off_li = 6;
+ cstate->off_li_hsl = 8;
+ cstate->off_sio = 7;
+ cstate->off_opc = 8;
+ cstate->off_dpc = 8;
+ cstate->off_sls = 11;
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_ERF:
+ cstate->off_li = 22;
+ cstate->off_li_hsl = 24;
+ cstate->off_sio = 23;
+ cstate->off_opc = 24;
+ cstate->off_dpc = 24;
+ cstate->off_sls = 27;
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_PFSYNC:
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = 4;
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0;
+ break;
+
+ case DLT_AX25_KISS:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET; /* variable, min 16, max 71 steps of 7 */
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
+ break;
+
+ case DLT_IPNET:
+ cstate->off_linktype.constant_part = 1;
+ cstate->off_linkpl.constant_part = 24; /* ipnet header length */
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ break;
+
+ case DLT_NETANALYZER:
+ cstate->off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */
+ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+ cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */
+ cstate->off_nl = 0; /* Ethernet II */
+ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
+ break;
+
+ case DLT_NETANALYZER_TRANSPARENT:
+ cstate->off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */
+ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+ cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */
+ cstate->off_nl = 0; /* Ethernet II */
+ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
+ break;
+
+ default:
+ /*
+ * For values in the range in which we've assigned new
+ * DLT_ values, only raw "link[N:M]" filtering is supported.
+ */
+ if (cstate->linktype >= DLT_MATCHING_MIN &&
+ cstate->linktype <= DLT_MATCHING_MAX) {
+ cstate->off_linktype.constant_part = OFFSET_NOT_SET;
+ cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
+ } else {
+ bpf_set_error(cstate, "unknown data link type %d", cstate->linktype);
+ return (-1);
+ }
+ break;
+ }
+
+ cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr;
+ return (0);
+}
+
+/*
+ * Load a value relative to the specified absolute offset.
+ */
+static struct slist *
+gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset,
+ u_int offset, u_int size)
+{
+ struct slist *s, *s2;
+
+ s = gen_abs_offset_varpart(cstate, abs_offset);
+
+ /*
+ * If "s" is non-null, it has code to arrange that the X register
+ * contains the variable part of the absolute offset, so we
+ * generate a load relative to that, with an offset of
+ * abs_offset->constant_part + offset.
+ *
+ * Otherwise, we can do an absolute load with an offset of
+ * abs_offset->constant_part + offset.
+ */
+ if (s != NULL) {
+ /*
+ * "s" points to a list of statements that puts the
+ * variable part of the absolute offset into the X register.
+ * Do an indirect load, to use the X register as an offset.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ s2->s.k = abs_offset->constant_part + offset;
+ sappend(s, s2);
+ } else {
+ /*
+ * There is no variable part of the absolute offset, so
+ * just do an absolute load.
+ */
+ s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
+ s->s.k = abs_offset->constant_part + offset;
+ }
+ return s;
+}
+
+/*
+ * Load a value relative to the beginning of the specified header.
+ */
+static struct slist *
+gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size)
+{
+ struct slist *s, *s2;
+
+ /*
+ * Squelch warnings from compilers that *don't* assume that
+ * offrel always has a valid enum value and therefore don't
+ * assume that we'll always go through one of the case arms.
+ *
+ * If we have a default case, compilers that *do* assume that
+ * will then complain about the default case code being
+ * unreachable.
+ *
+ * Damned if you do, damned if you don't.
+ */
+ s = NULL;
+
+ switch (offrel) {
+
+ case OR_PACKET:
+ s = new_stmt(cstate, BPF_LD|BPF_ABS|size);
+ s->s.k = offset;
+ break;
+
+ case OR_LINKHDR:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size);
+ break;
+
+ case OR_PREVLINKHDR:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size);
+ break;
+
+ case OR_LLC:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size);
+ break;
+
+ case OR_PREVMPLSHDR:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl - 4 + offset, size);
+ break;
+
+ case OR_LINKPL:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + offset, size);
+ break;
+
+ case OR_LINKPL_NOSNAP:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl_nosnap + offset, size);
+ break;
+
+ case OR_LINKTYPE:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linktype, offset, size);
+ break;
+
+ case OR_TRAN_IPV4:
+ /*
+ * Load the X register with the length of the IPv4 header
+ * (plus the offset of the link-layer header, if it's
+ * preceded by a variable-length header such as a radio
+ * header), in bytes.
+ */
+ s = gen_loadx_iphdrlen(cstate);
+
+ /*
+ * Load the item at {offset of the link-layer payload} +
+ * {offset, relative to the start of the link-layer
+ * paylod, of the IPv4 header} + {length of the IPv4 header} +
+ * {specified offset}.
+ *
+ * If the offset of the link-layer payload is variable,
+ * the variable part of that offset is included in the
+ * value in the X register, and we include the constant
+ * part in the offset of the load.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + offset;
+ sappend(s, s2);
+ break;
+
+ case OR_TRAN_IPV6:
+ s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size);
+ break;
+ }
+ return s;
+}
+
+/*
+ * Generate code to load into the X register the sum of the length of
+ * the IPv4 header and the variable part of the offset of the link-layer
+ * payload.
+ */
+static struct slist *
+gen_loadx_iphdrlen(compiler_state_t *cstate)
+{
+ struct slist *s, *s2;
+
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+ if (s != NULL) {
+ /*
+ * The offset of the link-layer payload has a variable
+ * part. "s" points to a list of statements that put
+ * the variable part of that offset into the X register.
+ *
+ * The 4*([k]&0xf) addressing mode can't be used, as we
+ * don't have a constant offset, so we have to load the
+ * value in question into the A register and add to it
+ * the value from the X register.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+ s2->s.k = 0xf;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+ s2->s.k = 2;
+ sappend(s, s2);
+
+ /*
+ * The A register now contains the length of the IP header.
+ * We need to add to it the variable part of the offset of
+ * the link-layer payload, which is still in the X
+ * register, and move the result into the X register.
+ */
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ } else {
+ /*
+ * The offset of the link-layer payload is a constant,
+ * so no code was generated to load the (non-existent)
+ * variable part of that offset.
+ *
+ * This means we can use the 4*([k]&0xf) addressing
+ * mode. Load the length of the IPv4 header, which
+ * is at an offset of cstate->off_nl from the beginning of
+ * the link-layer payload, and thus at an offset of
+ * cstate->off_linkpl.constant_part + cstate->off_nl from the beginning
+ * of the raw packet data, using that addressing mode.
+ */
+ s = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B);
+ s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ }
+ return s;
+}
+
+
+static struct block *
+gen_uncond(compiler_state_t *cstate, int rsense)
+{
+ struct block *b;
+ struct slist *s;
+
+ s = new_stmt(cstate, BPF_LD|BPF_IMM);
+ s->s.k = !rsense;
+ b = new_block(cstate, JMP(BPF_JEQ));
+ b->stmts = s;
+
+ return b;
+}
+
+static inline struct block *
+gen_true(compiler_state_t *cstate)
+{
+ return gen_uncond(cstate, 1);
+}
+
+static inline struct block *
+gen_false(compiler_state_t *cstate)
+{
+ return gen_uncond(cstate, 0);
+}
+
+/*
+ * Byte-swap a 32-bit number.
+ * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on
+ * big-endian platforms.)
+ */
+#define SWAPLONG(y) \
+((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+
+/*
+ * Generate code to match a particular packet type.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU. We use that to determine whether to
+ * match the type/length field or to check the type/length field for
+ * a value <= ETHERMTU to see whether it's a type field and then do
+ * the appropriate test.
+ */
+static struct block *
+gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ struct block *b0, *b1;
+
+ switch (ll_proto) {
+
+ case LLCSAP_ISONS:
+ case LLCSAP_IP:
+ case LLCSAP_NETBEUI:
+ /*
+ * OSI protocols and NetBEUI always use 802.2 encapsulation,
+ * so we check the DSAP and SSAP.
+ *
+ * LLCSAP_IP checks for IP-over-802.2, rather
+ * than IP-over-Ethernet or IP-over-SNAP.
+ *
+ * XXX - should we check both the DSAP and the
+ * SSAP, like this, or should we check just the
+ * DSAP, as we do for other types <= ETHERMTU
+ * (i.e., other SAP values)?
+ */
+ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+ gen_not(b0);
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
+ gen_and(b0, b1);
+ return b1;
+
+ case LLCSAP_IPX:
+ /*
+ * Check for;
+ *
+ * Ethernet_II frames, which are Ethernet
+ * frames with a frame type of ETHERTYPE_IPX;
+ *
+ * Ethernet_802.3 frames, which are 802.3
+ * frames (i.e., the type/length field is
+ * a length field, <= ETHERMTU, rather than
+ * a type field) with the first two bytes
+ * after the Ethernet/802.3 header being
+ * 0xFFFF;
+ *
+ * Ethernet_802.2 frames, which are 802.3
+ * frames with an 802.2 LLC header and
+ * with the IPX LSAP as the DSAP in the LLC
+ * header;
+ *
+ * Ethernet_SNAP frames, which are 802.3
+ * frames with an LLC header and a SNAP
+ * header and with an OUI of 0x000000
+ * (encapsulated Ethernet) and a protocol
+ * ID of ETHERTYPE_IPX in the SNAP header.
+ *
+ * XXX - should we generate the same code both
+ * for tests for LLCSAP_IPX and for ETHERTYPE_IPX?
+ */
+
+ /*
+ * This generates code to check both for the
+ * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
+ */
+ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
+ gen_or(b0, b1);
+
+ /*
+ * Now we add code to check for SNAP frames with
+ * ETHERTYPE_IPX, i.e. Ethernet_SNAP.
+ */
+ b0 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
+ gen_or(b0, b1);
+
+ /*
+ * Now we generate code to check for 802.3
+ * frames in general.
+ */
+ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+ gen_not(b0);
+
+ /*
+ * Now add the check for 802.3 frames before the
+ * check for Ethernet_802.2 and Ethernet_802.3,
+ * as those checks should only be done on 802.3
+ * frames, not on Ethernet frames.
+ */
+ gen_and(b0, b1);
+
+ /*
+ * Now add the check for Ethernet_II frames, and
+ * do that before checking for the other frame
+ * types.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
+ gen_or(b0, b1);
+ return b1;
+
+ case ETHERTYPE_ATALK:
+ case ETHERTYPE_AARP:
+ /*
+ * EtherTalk (AppleTalk protocols on Ethernet link
+ * layer) may use 802.2 encapsulation.
+ */
+
+ /*
+ * Check for 802.2 encapsulation (EtherTalk phase 2?);
+ * we check for an Ethernet type field less than
+ * 1500, which means it's an 802.3 length field.
+ */
+ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+ gen_not(b0);
+
+ /*
+ * 802.2-encapsulated ETHERTYPE_ATALK packets are
+ * SNAP packets with an organization code of
+ * 0x080007 (Apple, for Appletalk) and a protocol
+ * type of ETHERTYPE_ATALK (Appletalk).
+ *
+ * 802.2-encapsulated ETHERTYPE_AARP packets are
+ * SNAP packets with an organization code of
+ * 0x000000 (encapsulated Ethernet) and a protocol
+ * type of ETHERTYPE_AARP (Appletalk ARP).
+ */
+ if (ll_proto == ETHERTYPE_ATALK)
+ b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+ else /* ll_proto == ETHERTYPE_AARP */
+ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
+ gen_and(b0, b1);
+
+ /*
+ * Check for Ethernet encapsulation (Ethertalk
+ * phase 1?); we just check for the Ethernet
+ * protocol type.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ if (ll_proto <= ETHERMTU) {
+ /*
+ * This is an LLC SAP value, so the frames
+ * that match would be 802.2 frames.
+ * Check that the frame is an 802.2 frame
+ * (i.e., that the length/type field is
+ * a length field, <= ETHERMTU) and
+ * then check the DSAP.
+ */
+ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+ gen_not(b0);
+ b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto);
+ gen_and(b0, b1);
+ return b1;
+ } else {
+ /*
+ * This is an Ethernet type, so compare
+ * the length/type field with it (if
+ * the frame is an 802.2 frame, the length
+ * field will be <= ETHERMTU, and, as
+ * "ll_proto" is > ETHERMTU, this test
+ * will fail and the frame won't match,
+ * which is what we want).
+ */
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+ }
+ }
+}
+
+static struct block *
+gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ /*
+ * For DLT_NULL, the link-layer header is a 32-bit word
+ * containing an AF_ value in *host* byte order, and for
+ * DLT_ENC, the link-layer header begins with a 32-bit
+ * word containing an AF_ value in host byte order.
+ *
+ * In addition, if we're reading a saved capture file,
+ * the host byte order in the capture may not be the
+ * same as the host byte order on this machine.
+ *
+ * For DLT_LOOP, the link-layer header is a 32-bit
+ * word containing an AF_ value in *network* byte order.
+ */
+ if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
+ /*
+ * The AF_ value is in host byte order, but the BPF
+ * interpreter will convert it to network byte order.
+ *
+ * If this is a save file, and it's from a machine
+ * with the opposite byte order to ours, we byte-swap
+ * the AF_ value.
+ *
+ * Then we run it through "htonl()", and generate
+ * code to compare against the result.
+ */
+ if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
+ ll_proto = SWAPLONG(ll_proto);
+ ll_proto = htonl(ll_proto);
+ }
+ return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto));
+}
+
+/*
+ * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
+ * or IPv6 then we have an error.
+ */
+static struct block *
+gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET);
+ /*NOTREACHED*/
+
+ case ETHERTYPE_IPV6:
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6);
+ /*NOTREACHED*/
+
+ default:
+ break;
+ }
+
+ return gen_false(cstate);
+}
+
+/*
+ * Generate code to match a particular packet type.
+ *
+ * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU. We use that to determine whether to
+ * match the type field or to check the type field for the special
+ * LINUX_SLL_P_802_2 value and then do the appropriate test.
+ */
+static struct block *
+gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ struct block *b0, *b1;
+
+ switch (ll_proto) {
+
+ case LLCSAP_ISONS:
+ case LLCSAP_IP:
+ case LLCSAP_NETBEUI:
+ /*
+ * OSI protocols and NetBEUI always use 802.2 encapsulation,
+ * so we check the DSAP and SSAP.
+ *
+ * LLCSAP_IP checks for IP-over-802.2, rather
+ * than IP-over-Ethernet or IP-over-SNAP.
+ *
+ * XXX - should we check both the DSAP and the
+ * SSAP, like this, or should we check just the
+ * DSAP, as we do for other types <= ETHERMTU
+ * (i.e., other SAP values)?
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
+ gen_and(b0, b1);
+ return b1;
+
+ case LLCSAP_IPX:
+ /*
+ * Ethernet_II frames, which are Ethernet
+ * frames with a frame type of ETHERTYPE_IPX;
+ *
+ * Ethernet_802.3 frames, which have a frame
+ * type of LINUX_SLL_P_802_3;
+ *
+ * Ethernet_802.2 frames, which are 802.3
+ * frames with an 802.2 LLC header (i.e, have
+ * a frame type of LINUX_SLL_P_802_2) and
+ * with the IPX LSAP as the DSAP in the LLC
+ * header;
+ *
+ * Ethernet_SNAP frames, which are 802.3
+ * frames with an LLC header and a SNAP
+ * header and with an OUI of 0x000000
+ * (encapsulated Ethernet) and a protocol
+ * ID of ETHERTYPE_IPX in the SNAP header.
+ *
+ * First, do the checks on LINUX_SLL_P_802_2
+ * frames; generate the check for either
+ * Ethernet_802.2 or Ethernet_SNAP frames, and
+ * then put a check for LINUX_SLL_P_802_2 frames
+ * before it.
+ */
+ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
+ gen_or(b0, b1);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+ gen_and(b0, b1);
+
+ /*
+ * Now check for 802.3 frames and OR that with
+ * the previous test.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3);
+ gen_or(b0, b1);
+
+ /*
+ * Now add the check for Ethernet_II frames, and
+ * do that before checking for the other frame
+ * types.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
+ gen_or(b0, b1);
+ return b1;
+
+ case ETHERTYPE_ATALK:
+ case ETHERTYPE_AARP:
+ /*
+ * EtherTalk (AppleTalk protocols on Ethernet link
+ * layer) may use 802.2 encapsulation.
+ */
+
+ /*
+ * Check for 802.2 encapsulation (EtherTalk phase 2?);
+ * we check for the 802.2 protocol type in the
+ * "Ethernet type" field.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+
+ /*
+ * 802.2-encapsulated ETHERTYPE_ATALK packets are
+ * SNAP packets with an organization code of
+ * 0x080007 (Apple, for Appletalk) and a protocol
+ * type of ETHERTYPE_ATALK (Appletalk).
+ *
+ * 802.2-encapsulated ETHERTYPE_AARP packets are
+ * SNAP packets with an organization code of
+ * 0x000000 (encapsulated Ethernet) and a protocol
+ * type of ETHERTYPE_AARP (Appletalk ARP).
+ */
+ if (ll_proto == ETHERTYPE_ATALK)
+ b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+ else /* ll_proto == ETHERTYPE_AARP */
+ b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
+ gen_and(b0, b1);
+
+ /*
+ * Check for Ethernet encapsulation (Ethertalk
+ * phase 1?); we just check for the Ethernet
+ * protocol type.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ if (ll_proto <= ETHERMTU) {
+ /*
+ * This is an LLC SAP value, so the frames
+ * that match would be 802.2 frames.
+ * Check for the 802.2 protocol type
+ * in the "Ethernet type" field, and
+ * then check the DSAP.
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+ b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B,
+ ll_proto);
+ gen_and(b0, b1);
+ return b1;
+ } else {
+ /*
+ * This is an Ethernet type, so compare
+ * the length/type field with it (if
+ * the frame is an 802.2 frame, the length
+ * field will be <= ETHERMTU, and, as
+ * "ll_proto" is > ETHERMTU, this test
+ * will fail and the frame won't match,
+ * which is what we want).
+ */
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+ }
+ }
+}
+
+static struct slist *
+gen_load_prism_llprefixlen(compiler_state_t *cstate)
+{
+ struct slist *s1, *s2;
+ struct slist *sjeq_avs_cookie;
+ struct slist *sjcommon;
+
+ /*
+ * This code is not compatible with the optimizer, as
+ * we are generating jmp instructions within a normal
+ * slist of instructions
+ */
+ cstate->no_optimize = 1;
+
+ /*
+ * Generate code to load the length of the radio header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ *
+ * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes
+ * or always use the AVS header rather than the Prism header.
+ * We load a 4-byte big-endian value at the beginning of the
+ * raw packet data, and see whether, when masked with 0xFFFFF000,
+ * it's equal to 0x80211000. If so, that indicates that it's
+ * an AVS header (the masked-out bits are the version number).
+ * Otherwise, it's a Prism header.
+ *
+ * XXX - the Prism header is also, in theory, variable-length,
+ * but no known software generates headers that aren't 144
+ * bytes long.
+ */
+ if (cstate->off_linkhdr.reg != -1) {
+ /*
+ * Load the cookie.
+ */
+ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 0;
+
+ /*
+ * AND it with 0xFFFFF000.
+ */
+ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+ s2->s.k = 0xFFFFF000;
+ sappend(s1, s2);
+
+ /*
+ * Compare with 0x80211000.
+ */
+ sjeq_avs_cookie = new_stmt(cstate, JMP(BPF_JEQ));
+ sjeq_avs_cookie->s.k = 0x80211000;
+ sappend(s1, sjeq_avs_cookie);
+
+ /*
+ * If it's AVS:
+ *
+ * The 4 bytes at an offset of 4 from the beginning of
+ * the AVS header are the length of the AVS header.
+ * That field is big-endian.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+ s2->s.k = 4;
+ sappend(s1, s2);
+ sjeq_avs_cookie->s.jt = s2;
+
+ /*
+ * Now jump to the code to allocate a register
+ * into which to save the header length and
+ * store the length there. (The "jump always"
+ * instruction needs to have the k field set;
+ * it's added to the PC, so, as we're jumping
+ * over a single instruction, it should be 1.)
+ */
+ sjcommon = new_stmt(cstate, JMP(BPF_JA));
+ sjcommon->s.k = 1;
+ sappend(s1, sjcommon);
+
+ /*
+ * Now for the code that handles the Prism header.
+ * Just load the length of the Prism header (144)
+ * into the A register. Have the test for an AVS
+ * header branch here if we don't have an AVS header.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM);
+ s2->s.k = 144;
+ sappend(s1, s2);
+ sjeq_avs_cookie->s.jf = s2;
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it. The code for the AVS header will jump here after
+ * loading the length of the AVS header.
+ */
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkhdr.reg;
+ sappend(s1, s2);
+ sjcommon->s.jf = s2;
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+static struct slist *
+gen_load_avs_llprefixlen(compiler_state_t *cstate)
+{
+ struct slist *s1, *s2;
+
+ /*
+ * Generate code to load the length of the AVS header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ */
+ if (cstate->off_linkhdr.reg != -1) {
+ /*
+ * The 4 bytes at an offset of 4 from the beginning of
+ * the AVS header are the length of the AVS header.
+ * That field is big-endian.
+ */
+ s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 4;
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it.
+ */
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkhdr.reg;
+ sappend(s1, s2);
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+static struct slist *
+gen_load_radiotap_llprefixlen(compiler_state_t *cstate)
+{
+ struct slist *s1, *s2;
+
+ /*
+ * Generate code to load the length of the radiotap header into
+ * the register assigned to hold that length, if one has been
+ * assigned. (If one hasn't been assigned, no code we've
+ * generated uses that prefix, so we don't need to generate any
+ * code to load it.)
+ */
+ if (cstate->off_linkhdr.reg != -1) {
+ /*
+ * The 2 bytes at offsets of 2 and 3 from the beginning
+ * of the radiotap header are the length of the radiotap
+ * header; unfortunately, it's little-endian, so we have
+ * to load it a byte at a time and construct the value.
+ */
+
+ /*
+ * Load the high-order byte, at an offset of 3, shift it
+ * left a byte, and put the result in the X register.
+ */
+ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s1->s.k = 3;
+ s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+ sappend(s1, s2);
+ s2->s.k = 8;
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ /*
+ * Load the next byte, at an offset of 2, and OR the
+ * value from the X register into it.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ sappend(s1, s2);
+ s2->s.k = 2;
+ s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X);
+ sappend(s1, s2);
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it.
+ */
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkhdr.reg;
+ sappend(s1, s2);
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+/*
+ * At the moment we treat PPI as normal Radiotap encoded
+ * packets. The difference is in the function that generates
+ * the code at the beginning to compute the header length.
+ * Since this code generator of PPI supports bare 802.11
+ * encapsulation only (i.e. the encapsulated DLT should be
+ * DLT_IEEE802_11) we generate code to check for this too;
+ * that's done in finish_parse().
+ */
+static struct slist *
+gen_load_ppi_llprefixlen(compiler_state_t *cstate)
+{
+ struct slist *s1, *s2;
+
+ /*
+ * Generate code to load the length of the radiotap header
+ * into the register assigned to hold that length, if one has
+ * been assigned.
+ */
+ if (cstate->off_linkhdr.reg != -1) {
+ /*
+ * The 2 bytes at offsets of 2 and 3 from the beginning
+ * of the radiotap header are the length of the radiotap
+ * header; unfortunately, it's little-endian, so we have
+ * to load it a byte at a time and construct the value.
+ */
+
+ /*
+ * Load the high-order byte, at an offset of 3, shift it
+ * left a byte, and put the result in the X register.
+ */
+ s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s1->s.k = 3;
+ s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
+ sappend(s1, s2);
+ s2->s.k = 8;
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ /*
+ * Load the next byte, at an offset of 2, and OR the
+ * value from the X register into it.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ sappend(s1, s2);
+ s2->s.k = 2;
+ s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X);
+ sappend(s1, s2);
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it.
+ */
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkhdr.reg;
+ sappend(s1, s2);
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+/*
+ * Load a value relative to the beginning of the link-layer header after the 802.11
+ * header, i.e. LLC_SNAP.
+ * The link-layer header doesn't necessarily begin at the beginning
+ * of the packet data; there might be a variable-length prefix containing
+ * radio information.
+ */
+static struct slist *
+gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct slist *snext)
+{
+ struct slist *s2;
+ struct slist *sjset_data_frame_1;
+ struct slist *sjset_data_frame_2;
+ struct slist *sjset_qos;
+ struct slist *sjset_radiotap_flags_present;
+ struct slist *sjset_radiotap_ext_present;
+ struct slist *sjset_radiotap_tsft_present;
+ struct slist *sjset_tsft_datapad, *sjset_notsft_datapad;
+ struct slist *s_roundup;
+
+ if (cstate->off_linkpl.reg == -1) {
+ /*
+ * No register has been assigned to the offset of
+ * the link-layer payload, which means nobody needs
+ * it; don't bother computing it - just return
+ * what we already have.
+ */
+ return (s);
+ }
+
+ /*
+ * This code is not compatible with the optimizer, as
+ * we are generating jmp instructions within a normal
+ * slist of instructions
+ */
+ cstate->no_optimize = 1;
+
+ /*
+ * If "s" is non-null, it has code to arrange that the X register
+ * contains the length of the prefix preceding the link-layer
+ * header.
+ *
+ * Otherwise, the length of the prefix preceding the link-layer
+ * header is "off_outermostlinkhdr.constant_part".
+ */
+ if (s == NULL) {
+ /*
+ * There is no variable-length header preceding the
+ * link-layer header.
+ *
+ * Load the length of the fixed-length prefix preceding
+ * the link-layer header (if any) into the X register,
+ * and store it in the cstate->off_linkpl.reg register.
+ * That length is off_outermostlinkhdr.constant_part.
+ */
+ s = new_stmt(cstate, BPF_LDX|BPF_IMM);
+ s->s.k = cstate->off_outermostlinkhdr.constant_part;
+ }
+
+ /*
+ * The X register contains the offset of the beginning of the
+ * link-layer header; add 24, which is the minimum length
+ * of the MAC header for a data frame, to that, and store it
+ * in cstate->off_linkpl.reg, and then load the Frame Control field,
+ * which is at the offset in the X register, with an indexed load.
+ */
+ s2 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s2->s.k = 24;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+
+ s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s2->s.k = 0;
+ sappend(s, s2);
+
+ /*
+ * Check the Frame Control field to see if this is a data frame;
+ * a data frame has the 0x08 bit (b3) in that field set and the
+ * 0x04 bit (b2) clear.
+ */
+ sjset_data_frame_1 = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_data_frame_1->s.k = 0x08;
+ sappend(s, sjset_data_frame_1);
+
+ /*
+ * If b3 is set, test b2, otherwise go to the first statement of
+ * the rest of the program.
+ */
+ sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_data_frame_2->s.k = 0x04;
+ sappend(s, sjset_data_frame_2);
+ sjset_data_frame_1->s.jf = snext;
+
+ /*
+ * If b2 is not set, this is a data frame; test the QoS bit.
+ * Otherwise, go to the first statement of the rest of the
+ * program.
+ */
+ sjset_data_frame_2->s.jt = snext;
+ sjset_data_frame_2->s.jf = sjset_qos = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_qos->s.k = 0x80; /* QoS bit */
+ sappend(s, sjset_qos);
+
+ /*
+ * If it's set, add 2 to cstate->off_linkpl.reg, to skip the QoS
+ * field.
+ * Otherwise, go to the first statement of the rest of the
+ * program.
+ */
+ sjset_qos->s.jt = s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = 2;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+
+ /*
+ * If we have a radiotap header, look at it to see whether
+ * there's Atheros padding between the MAC-layer header
+ * and the payload.
+ *
+ * Note: all of the fields in the radiotap header are
+ * little-endian, so we byte-swap all of the values
+ * we test against, as they will be loaded as big-endian
+ * values.
+ *
+ * XXX - in the general case, we would have to scan through
+ * *all* the presence bits, if there's more than one word of
+ * presence bits. That would require a loop, meaning that
+ * we wouldn't be able to run the filter in the kernel.
+ *
+ * We assume here that the Atheros adapters that insert the
+ * annoying padding don't have multiple antennae and therefore
+ * do not generate radiotap headers with multiple presence words.
+ */
+ if (cstate->linktype == DLT_IEEE802_11_RADIO) {
+ /*
+ * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set
+ * in the first presence flag word?
+ */
+ sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W);
+ s2->s.k = 4;
+ sappend(s, s2);
+
+ sjset_radiotap_flags_present = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_radiotap_flags_present->s.k = SWAPLONG(0x00000002);
+ sappend(s, sjset_radiotap_flags_present);
+
+ /*
+ * If not, skip all of this.
+ */
+ sjset_radiotap_flags_present->s.jf = snext;
+
+ /*
+ * Otherwise, is the "extension" bit set in that word?
+ */
+ sjset_radiotap_ext_present = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_radiotap_ext_present->s.k = SWAPLONG(0x80000000);
+ sappend(s, sjset_radiotap_ext_present);
+ sjset_radiotap_flags_present->s.jt = sjset_radiotap_ext_present;
+
+ /*
+ * If so, skip all of this.
+ */
+ sjset_radiotap_ext_present->s.jt = snext;
+
+ /*
+ * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set?
+ */
+ sjset_radiotap_tsft_present = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_radiotap_tsft_present->s.k = SWAPLONG(0x00000001);
+ sappend(s, sjset_radiotap_tsft_present);
+ sjset_radiotap_ext_present->s.jf = sjset_radiotap_tsft_present;
+
+ /*
+ * If IEEE80211_RADIOTAP_TSFT is set, the flags field is
+ * at an offset of 16 from the beginning of the raw packet
+ * data (8 bytes for the radiotap header and 8 bytes for
+ * the TSFT field).
+ *
+ * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+ * is set.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+ s2->s.k = 16;
+ sappend(s, s2);
+ sjset_radiotap_tsft_present->s.jt = s2;
+
+ sjset_tsft_datapad = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_tsft_datapad->s.k = 0x20;
+ sappend(s, sjset_tsft_datapad);
+
+ /*
+ * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is
+ * at an offset of 8 from the beginning of the raw packet
+ * data (8 bytes for the radiotap header).
+ *
+ * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20)
+ * is set.
+ */
+ s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+ s2->s.k = 8;
+ sappend(s, s2);
+ sjset_radiotap_tsft_present->s.jf = s2;
+
+ sjset_notsft_datapad = new_stmt(cstate, JMP(BPF_JSET));
+ sjset_notsft_datapad->s.k = 0x20;
+ sappend(s, sjset_notsft_datapad);
+
+ /*
+ * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is
+ * set, round the length of the 802.11 header to
+ * a multiple of 4. Do that by adding 3 and then
+ * dividing by and multiplying by 4, which we do by
+ * ANDing with ~3.
+ */
+ s_roundup = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s_roundup->s.k = cstate->off_linkpl.reg;
+ sappend(s, s_roundup);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = 3;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM);
+ s2->s.k = (bpf_u_int32)~3;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+
+ sjset_tsft_datapad->s.jt = s_roundup;
+ sjset_tsft_datapad->s.jf = snext;
+ sjset_notsft_datapad->s.jt = s_roundup;
+ sjset_notsft_datapad->s.jf = snext;
+ } else
+ sjset_qos->s.jf = snext;
+
+ return s;
+}
+
+static void
+insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
+{
+ struct slist *s;
+
+ /* There is an implicit dependency between the link
+ * payload and link header since the payload computation
+ * includes the variable part of the header. Therefore,
+ * if nobody else has allocated a register for the link
+ * header and we need it, do it now. */
+ if (cstate->off_linkpl.reg != -1 && cstate->off_linkhdr.is_variable &&
+ cstate->off_linkhdr.reg == -1)
+ cstate->off_linkhdr.reg = alloc_reg(cstate);
+
+ /*
+ * For link-layer types that have a variable-length header
+ * preceding the link-layer header, generate code to load
+ * the offset of the link-layer header into the register
+ * assigned to that offset, if any.
+ *
+ * XXX - this, and the next switch statement, won't handle
+ * encapsulation of 802.11 or 802.11+radio information in
+ * some other protocol stack. That's significantly more
+ * complicated.
+ */
+ switch (cstate->outermostlinktype) {
+
+ case DLT_PRISM_HEADER:
+ s = gen_load_prism_llprefixlen(cstate);
+ break;
+
+ case DLT_IEEE802_11_RADIO_AVS:
+ s = gen_load_avs_llprefixlen(cstate);
+ break;
+
+ case DLT_IEEE802_11_RADIO:
+ s = gen_load_radiotap_llprefixlen(cstate);
+ break;
+
+ case DLT_PPI:
+ s = gen_load_ppi_llprefixlen(cstate);
+ break;
+
+ default:
+ s = NULL;
+ break;
+ }
+
+ /*
+ * For link-layer types that have a variable-length link-layer
+ * header, generate code to load the offset of the link-layer
+ * payload into the register assigned to that offset, if any.
+ */
+ switch (cstate->outermostlinktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ s = gen_load_802_11_header_len(cstate, s, b->stmts);
+ break;
+ }
+
+ /*
+ * If there is no initialization yet and we need variable
+ * length offsets for VLAN, initialize them to zero
+ */
+ if (s == NULL && cstate->is_vlan_vloffset) {
+ struct slist *s2;
+
+ if (cstate->off_linkpl.reg == -1)
+ cstate->off_linkpl.reg = alloc_reg(cstate);
+ if (cstate->off_linktype.reg == -1)
+ cstate->off_linktype.reg = alloc_reg(cstate);
+
+ s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM);
+ s->s.k = 0;
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linktype.reg;
+ sappend(s, s2);
+ }
+
+ /*
+ * If we have any offset-loading code, append all the
+ * existing statements in the block to those statements,
+ * and make the resulting list the list of statements
+ * for the block.
+ */
+ if (s != NULL) {
+ sappend(s, b->stmts);
+ b->stmts = s;
+ }
+}
+
+static struct block *
+gen_ppi_dlt_check(compiler_state_t *cstate)
+{
+ struct slist *s_load_dlt;
+ struct block *b;
+
+ if (cstate->linktype == DLT_PPI)
+ {
+ /* Create the statements that check for the DLT
+ */
+ s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS);
+ s_load_dlt->s.k = 4;
+
+ b = new_block(cstate, JMP(BPF_JEQ));
+
+ b->stmts = s_load_dlt;
+ b->s.k = SWAPLONG(DLT_IEEE802_11);
+ }
+ else
+ {
+ b = NULL;
+ }
+
+ return b;
+}
+
+/*
+ * Take an absolute offset, and:
+ *
+ * if it has no variable part, return NULL;
+ *
+ * if it has a variable part, generate code to load the register
+ * containing that variable part into the X register, returning
+ * a pointer to that code - if no register for that offset has
+ * been allocated, allocate it first.
+ *
+ * (The code to set that register will be generated later, but will
+ * be placed earlier in the code sequence.)
+ */
+static struct slist *
+gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
+{
+ struct slist *s;
+
+ if (off->is_variable) {
+ if (off->reg == -1) {
+ /*
+ * We haven't yet assigned a register for the
+ * variable part of the offset of the link-layer
+ * header; allocate one.
+ */
+ off->reg = alloc_reg(cstate);
+ }
+
+ /*
+ * Load the register containing the variable part of the
+ * offset of the link-layer header into the X register.
+ */
+ s = new_stmt(cstate, BPF_LDX|BPF_MEM);
+ s->s.k = off->reg;
+ return s;
+ } else {
+ /*
+ * That offset isn't variable, there's no variable part,
+ * so we don't need to generate any code.
+ */
+ return NULL;
+ }
+}
+
+/*
+ * Map an Ethernet type to the equivalent PPP type.
+ */
+static bpf_u_int32
+ethertype_to_ppptype(bpf_u_int32 ll_proto)
+{
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ ll_proto = PPP_IP;
+ break;
+
+ case ETHERTYPE_IPV6:
+ ll_proto = PPP_IPV6;
+ break;
+
+ case ETHERTYPE_DN:
+ ll_proto = PPP_DECNET;
+ break;
+
+ case ETHERTYPE_ATALK:
+ ll_proto = PPP_APPLE;
+ break;
+
+ case ETHERTYPE_NS:
+ ll_proto = PPP_NS;
+ break;
+
+ case LLCSAP_ISONS:
+ ll_proto = PPP_OSI;
+ break;
+
+ case LLCSAP_8021D:
+ /*
+ * I'm assuming the "Bridging PDU"s that go
+ * over PPP are Spanning Tree Protocol
+ * Bridging PDUs.
+ */
+ ll_proto = PPP_BRPDU;
+ break;
+
+ case LLCSAP_IPX:
+ ll_proto = PPP_IPX;
+ break;
+ }
+ return (ll_proto);
+}
+
+/*
+ * Generate any tests that, for encapsulation of a link-layer packet
+ * inside another protocol stack, need to be done to check for those
+ * link-layer packets (and that haven't already been done by a check
+ * for that encapsulation).
+ */
+static struct block *
+gen_prevlinkhdr_check(compiler_state_t *cstate)
+{
+ struct block *b0;
+
+ if (cstate->is_geneve)
+ return gen_geneve_ll_check(cstate);
+
+ switch (cstate->prevlinktype) {
+
+ case DLT_SUNATM:
+ /*
+ * This is LANE-encapsulated Ethernet; check that the LANE
+ * packet doesn't begin with an LE Control marker, i.e.
+ * that it's data, not a control message.
+ *
+ * (We've already generated a test for LANE.)
+ */
+ b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00);
+ gen_not(b0);
+ return b0;
+
+ default:
+ /*
+ * No such tests are necessary.
+ */
+ return NULL;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * The three different values we should check for when checking for an
+ * IPv6 packet with DLT_NULL.
+ */
+#define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */
+#define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */
+#define BSD_AFNUM_INET6_DARWIN 30 /* macOS, iOS, other Darwin-based OSes */
+
+/*
+ * Generate code to match a particular packet type by matching the
+ * link-layer type field or fields in the 802.2 LLC header.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU.
+ */
+static struct block *
+gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ struct block *b0, *b1, *b2;
+ const char *description;
+
+ /* are we checking MPLS-encapsulated packets? */
+ if (cstate->label_stack_depth > 0)
+ return gen_mpls_linktype(cstate, ll_proto);
+
+ switch (cstate->linktype) {
+
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ /* Geneve has an EtherType regardless of whether there is an
+ * L2 header. */
+ if (!cstate->is_geneve)
+ b0 = gen_prevlinkhdr_check(cstate);
+ else
+ b0 = NULL;
+
+ b1 = gen_ether_linktype(cstate, ll_proto);
+ if (b0 != NULL)
+ gen_and(b0, b1);
+ return b1;
+ /*NOTREACHED*/
+
+ case DLT_C_HDLC:
+ switch (ll_proto) {
+
+ case LLCSAP_ISONS:
+ ll_proto = (ll_proto << 8 | LLCSAP_ISONS);
+ /* fall through */
+
+ default:
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+ /*NOTREACHED*/
+ }
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ /*
+ * Check that we have a data frame.
+ */
+ b0 = gen_check_802_11_data_frame(cstate);
+
+ /*
+ * Now check for the specified link-layer type.
+ */
+ b1 = gen_llc_linktype(cstate, ll_proto);
+ gen_and(b0, b1);
+ return b1;
+ /*NOTREACHED*/
+
+ case DLT_FDDI:
+ /*
+ * XXX - check for LLC frames.
+ */
+ return gen_llc_linktype(cstate, ll_proto);
+ /*NOTREACHED*/
+
+ case DLT_IEEE802:
+ /*
+ * XXX - check for LLC PDUs, as per IEEE 802.5.
+ */
+ return gen_llc_linktype(cstate, ll_proto);
+ /*NOTREACHED*/
+
+ case DLT_ATM_RFC1483:
+ case DLT_ATM_CLIP:
+ case DLT_IP_OVER_FC:
+ return gen_llc_linktype(cstate, ll_proto);
+ /*NOTREACHED*/
+
+ case DLT_SUNATM:
+ /*
+ * Check for an LLC-encapsulated version of this protocol;
+ * if we were checking for LANE, linktype would no longer
+ * be DLT_SUNATM.
+ *
+ * Check for LLC encapsulation and then check the protocol.
+ */
+ b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+ b1 = gen_llc_linktype(cstate, ll_proto);
+ gen_and(b0, b1);
+ return b1;
+ /*NOTREACHED*/
+
+ case DLT_LINUX_SLL:
+ return gen_linux_sll_linktype(cstate, ll_proto);
+ /*NOTREACHED*/
+
+ case DLT_SLIP:
+ case DLT_SLIP_BSDOS:
+ case DLT_RAW:
+ /*
+ * These types don't provide any type field; packets
+ * are always IPv4 or IPv6.
+ *
+ * XXX - for IPv4, check for a version number of 4, and,
+ * for IPv6, check for a version number of 6?
+ */
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ /* Check for a version number of 4. */
+ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0);
+
+ case ETHERTYPE_IPV6:
+ /* Check for a version number of 6. */
+ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0);
+
+ default:
+ return gen_false(cstate); /* always false */
+ }
+ /*NOTREACHED*/
+
+ case DLT_IPV4:
+ /*
+ * Raw IPv4, so no type field.
+ */
+ if (ll_proto == ETHERTYPE_IP)
+ return gen_true(cstate); /* always true */
+
+ /* Checking for something other than IPv4; always false */
+ return gen_false(cstate);
+ /*NOTREACHED*/
+
+ case DLT_IPV6:
+ /*
+ * Raw IPv6, so no type field.
+ */
+ if (ll_proto == ETHERTYPE_IPV6)
+ return gen_true(cstate); /* always true */
+
+ /* Checking for something other than IPv6; always false */
+ return gen_false(cstate);
+ /*NOTREACHED*/
+
+ case DLT_PPP:
+ case DLT_PPP_PPPD:
+ case DLT_PPP_SERIAL:
+ case DLT_PPP_ETHER:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+ ethertype_to_ppptype(ll_proto));
+ /*NOTREACHED*/
+
+ case DLT_PPP_BSDOS:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ /*
+ * Also check for Van Jacobson-compressed IP.
+ * XXX - do this for other forms of PPP?
+ */
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_IP);
+ b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJC);
+ gen_or(b0, b1);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC);
+ gen_or(b1, b0);
+ return b0;
+
+ default:
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+ ethertype_to_ppptype(ll_proto));
+ }
+ /*NOTREACHED*/
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ case DLT_ENC:
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ return (gen_loopback_linktype(cstate, AF_INET));
+
+ case ETHERTYPE_IPV6:
+ /*
+ * AF_ values may, unfortunately, be platform-
+ * dependent; AF_INET isn't, because everybody
+ * used 4.2BSD's value, but AF_INET6 is, because
+ * 4.2BSD didn't have a value for it (given that
+ * IPv6 didn't exist back in the early 1980's),
+ * and they all picked their own values.
+ *
+ * This means that, if we're reading from a
+ * savefile, we need to check for all the
+ * possible values.
+ *
+ * If we're doing a live capture, we only need
+ * to check for this platform's value; however,
+ * Npcap uses 24, which isn't Windows's AF_INET6
+ * value. (Given the multiple different values,
+ * programs that read pcap files shouldn't be
+ * checking for their platform's AF_INET6 value
+ * anyway, they should check for all of the
+ * possible values. and they might as well do
+ * that even for live captures.)
+ */
+ if (cstate->bpf_pcap->rfile != NULL) {
+ /*
+ * Savefile - check for all three
+ * possible IPv6 values.
+ */
+ b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD);
+ b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD);
+ gen_or(b0, b1);
+ b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN);
+ gen_or(b0, b1);
+ return (b1);
+ } else {
+ /*
+ * Live capture, so we only need to
+ * check for the value used on this
+ * platform.
+ */
+#ifdef _WIN32
+ /*
+ * Npcap doesn't use Windows's AF_INET6,
+ * as that collides with AF_IPX on
+ * some BSDs (both have the value 23).
+ * Instead, it uses 24.
+ */
+ return (gen_loopback_linktype(cstate, 24));
+#else /* _WIN32 */
+#ifdef AF_INET6
+ return (gen_loopback_linktype(cstate, AF_INET6));
+#else /* AF_INET6 */
+ /*
+ * I guess this platform doesn't support
+ * IPv6, so we just reject all packets.
+ */
+ return gen_false(cstate);
+#endif /* AF_INET6 */
+#endif /* _WIN32 */
+ }
+
+ default:
+ /*
+ * Not a type on which we support filtering.
+ * XXX - support those that have AF_ values
+ * #defined on this platform, at least?
+ */
+ return gen_false(cstate);
+ }
+
+#ifdef HAVE_NET_PFVAR_H
+ case DLT_PFLOG:
+ /*
+ * af field is host byte order in contrast to the rest of
+ * the packet.
+ */
+ if (ll_proto == ETHERTYPE_IP)
+ return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
+ BPF_B, AF_INET));
+ else if (ll_proto == ETHERTYPE_IPV6)
+ return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
+ BPF_B, AF_INET6));
+ else
+ return gen_false(cstate);
+ /*NOTREACHED*/
+#endif /* HAVE_NET_PFVAR_H */
+
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ /*
+ * XXX should we check for first fragment if the protocol
+ * uses PHDS?
+ */
+ switch (ll_proto) {
+
+ default:
+ return gen_false(cstate);
+
+ case ETHERTYPE_IPV6:
+ return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_INET6));
+
+ case ETHERTYPE_IP:
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_IP);
+ b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_IP_OLD);
+ gen_or(b0, b1);
+ return (b1);
+
+ case ETHERTYPE_ARP:
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_ARP);
+ b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_ARP_OLD);
+ gen_or(b0, b1);
+ return (b1);
+
+ case ETHERTYPE_REVARP:
+ return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_REVARP));
+
+ case ETHERTYPE_ATALK:
+ return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
+ ARCTYPE_ATALK));
+ }
+ /*NOTREACHED*/
+
+ case DLT_LTALK:
+ switch (ll_proto) {
+ case ETHERTYPE_ATALK:
+ return gen_true(cstate);
+ default:
+ return gen_false(cstate);
+ }
+ /*NOTREACHED*/
+
+ case DLT_FRELAY:
+ /*
+ * XXX - assumes a 2-byte Frame Relay header with
+ * DLCI and flags. What if the address is longer?
+ */
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ /*
+ * Check for the special NLPID for IP.
+ */
+ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc);
+
+ case ETHERTYPE_IPV6:
+ /*
+ * Check for the special NLPID for IPv6.
+ */
+ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e);
+
+ case LLCSAP_ISONS:
+ /*
+ * Check for several OSI protocols.
+ *
+ * Frame Relay packets typically have an OSI
+ * NLPID at the beginning; we check for each
+ * of them.
+ *
+ * What we check for is the NLPID and a frame
+ * control field of UI, i.e. 0x03 followed
+ * by the NLPID.
+ */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP);
+ b1 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS);
+ b2 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS);
+ gen_or(b1, b2);
+ gen_or(b0, b2);
+ return b2;
+
+ default:
+ return gen_false(cstate);
+ }
+ /*NOTREACHED*/
+
+ case DLT_MFR:
+ bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented");
+
+ case DLT_JUNIPER_MFR:
+ case DLT_JUNIPER_MLFR:
+ case DLT_JUNIPER_MLPPP:
+ case DLT_JUNIPER_ATM1:
+ case DLT_JUNIPER_ATM2:
+ case DLT_JUNIPER_PPPOE:
+ case DLT_JUNIPER_PPPOE_ATM:
+ case DLT_JUNIPER_GGSN:
+ case DLT_JUNIPER_ES:
+ case DLT_JUNIPER_MONITOR:
+ case DLT_JUNIPER_SERVICES:
+ case DLT_JUNIPER_ETHER:
+ case DLT_JUNIPER_PPP:
+ case DLT_JUNIPER_FRELAY:
+ case DLT_JUNIPER_CHDLC:
+ case DLT_JUNIPER_VP:
+ case DLT_JUNIPER_ST:
+ case DLT_JUNIPER_ISM:
+ case DLT_JUNIPER_VS:
+ case DLT_JUNIPER_SRX_E2E:
+ case DLT_JUNIPER_FIBRECHANNEL:
+ case DLT_JUNIPER_ATM_CEMIC:
+
+ /* just lets verify the magic number for now -
+ * on ATM we may have up to 6 different encapsulations on the wire
+ * and need a lot of heuristics to figure out that the payload
+ * might be;
+ *
+ * FIXME encapsulation specific BPF_ filters
+ */
+ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */
+
+ case DLT_BACNET_MS_TP:
+ return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
+
+ case DLT_IPNET:
+ return gen_ipnet_linktype(cstate, ll_proto);
+
+ case DLT_LINUX_IRDA:
+ bpf_error(cstate, "IrDA link-layer type filtering not implemented");
+
+ case DLT_DOCSIS:
+ bpf_error(cstate, "DOCSIS link-layer type filtering not implemented");
+
+ case DLT_MTP2:
+ case DLT_MTP2_WITH_PHDR:
+ bpf_error(cstate, "MTP2 link-layer type filtering not implemented");
+
+ case DLT_ERF:
+ bpf_error(cstate, "ERF link-layer type filtering not implemented");
+
+ case DLT_PFSYNC:
+ bpf_error(cstate, "PFSYNC link-layer type filtering not implemented");
+
+ case DLT_LINUX_LAPD:
+ bpf_error(cstate, "LAPD link-layer type filtering not implemented");
+
+ case DLT_USB_FREEBSD:
+ case DLT_USB_LINUX:
+ case DLT_USB_LINUX_MMAPPED:
+ case DLT_USBPCAP:
+ bpf_error(cstate, "USB link-layer type filtering not implemented");
+
+ case DLT_BLUETOOTH_HCI_H4:
+ case DLT_BLUETOOTH_HCI_H4_WITH_PHDR:
+ bpf_error(cstate, "Bluetooth link-layer type filtering not implemented");
+
+ case DLT_CAN20B:
+ case DLT_CAN_SOCKETCAN:
+ bpf_error(cstate, "CAN link-layer type filtering not implemented");
+
+ case DLT_IEEE802_15_4:
+ case DLT_IEEE802_15_4_LINUX:
+ case DLT_IEEE802_15_4_NONASK_PHY:
+ case DLT_IEEE802_15_4_NOFCS:
+ case DLT_IEEE802_15_4_TAP:
+ bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented");
+
+ case DLT_IEEE802_16_MAC_CPS_RADIO:
+ bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented");
+
+ case DLT_SITA:
+ bpf_error(cstate, "SITA link-layer type filtering not implemented");
+
+ case DLT_RAIF1:
+ bpf_error(cstate, "RAIF1 link-layer type filtering not implemented");
+
+ case DLT_IPMB_KONTRON:
+ case DLT_IPMB_LINUX:
+ bpf_error(cstate, "IPMB link-layer type filtering not implemented");
+
+ case DLT_AX25_KISS:
+ bpf_error(cstate, "AX.25 link-layer type filtering not implemented");
+
+ case DLT_NFLOG:
+ /* Using the fixed-size NFLOG header it is possible to tell only
+ * the address family of the packet, other meaningful data is
+ * either missing or behind TLVs.
+ */
+ bpf_error(cstate, "NFLOG link-layer type filtering not implemented");
+
+ default:
+ /*
+ * Does this link-layer header type have a field
+ * indicating the type of the next protocol? If
+ * so, off_linktype.constant_part will be the offset of that
+ * field in the packet; if not, it will be OFFSET_NOT_SET.
+ */
+ if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) {
+ /*
+ * Yes; assume it's an Ethernet type. (If
+ * it's not, it needs to be handled specially
+ * above.)
+ */
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
+ /*NOTREACHED */
+ } else {
+ /*
+ * No; report an error.
+ */
+ description = pcap_datalink_val_to_description_or_dlt(cstate->linktype);
+ bpf_error(cstate, "%s link-layer type filtering not implemented",
+ description);
+ /*NOTREACHED */
+ }
+ }
+}
+
+/*
+ * Check for an LLC SNAP packet with a given organization code and
+ * protocol type; we check the entire contents of the 802.2 LLC and
+ * snap headers, checking for DSAP and SSAP of SNAP and a control
+ * field of 0x03 in the LLC header, and for the specified organization
+ * code and protocol type in the SNAP header.
+ */
+static struct block *
+gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype)
+{
+ u_char snapblock[8];
+
+ snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */
+ snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */
+ snapblock[2] = 0x03; /* control = UI */
+ snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */
+ snapblock[4] = (u_char)(orgcode >> 8); /* middle 8 bits of organization code */
+ snapblock[5] = (u_char)(orgcode >> 0); /* lower 8 bits of organization code */
+ snapblock[6] = (u_char)(ptype >> 8); /* upper 8 bits of protocol type */
+ snapblock[7] = (u_char)(ptype >> 0); /* lower 8 bits of protocol type */
+ return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock);
+}
+
+/*
+ * Generate code to match frames with an LLC header.
+ */
+static struct block *
+gen_llc_internal(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+
+ switch (cstate->linktype) {
+
+ case DLT_EN10MB:
+ /*
+ * We check for an Ethernet type field less than
+ * 1500, which means it's an 802.3 length field.
+ */
+ b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
+ gen_not(b0);
+
+ /*
+ * Now check for the purported DSAP and SSAP not being
+ * 0xFF, to rule out NetWare-over-802.3.
+ */
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
+ gen_not(b1);
+ gen_and(b0, b1);
+ return b1;
+
+ case DLT_SUNATM:
+ /*
+ * We check for LLC traffic.
+ */
+ b0 = gen_atmtype_llc(cstate);
+ return b0;
+
+ case DLT_IEEE802: /* Token Ring */
+ /*
+ * XXX - check for LLC frames.
+ */
+ return gen_true(cstate);
+
+ case DLT_FDDI:
+ /*
+ * XXX - check for LLC frames.
+ */
+ return gen_true(cstate);
+
+ case DLT_ATM_RFC1483:
+ /*
+ * For LLC encapsulation, these are defined to have an
+ * 802.2 LLC header.
+ *
+ * For VC encapsulation, they don't, but there's no
+ * way to check for that; the protocol used on the VC
+ * is negotiated out of band.
+ */
+ return gen_true(cstate);
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_PPI:
+ /*
+ * Check that we have a data frame.
+ */
+ b0 = gen_check_802_11_data_frame(cstate);
+ return b0;
+
+ default:
+ bpf_error(cstate, "'llc' not supported for %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+ }
+}
+
+struct block *
+gen_llc(compiler_state_t *cstate)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_llc_internal(cstate);
+}
+
+struct block *
+gen_llc_i(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+ struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Check whether this is an LLC frame.
+ */
+ b0 = gen_llc_internal(cstate);
+
+ /*
+ * Load the control byte and test the low-order bit; it must
+ * be clear for I frames.
+ */
+ s = gen_load_a(cstate, OR_LLC, 2, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x01;
+ b1->stmts = s;
+ gen_not(b1);
+ gen_and(b0, b1);
+ return b1;
+}
+
+struct block *
+gen_llc_s(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Check whether this is an LLC frame.
+ */
+ b0 = gen_llc_internal(cstate);
+
+ /*
+ * Now compare the low-order 2 bit of the control byte against
+ * the appropriate value for S frames.
+ */
+ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03);
+ gen_and(b0, b1);
+ return b1;
+}
+
+struct block *
+gen_llc_u(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Check whether this is an LLC frame.
+ */
+ b0 = gen_llc_internal(cstate);
+
+ /*
+ * Now compare the low-order 2 bit of the control byte against
+ * the appropriate value for U frames.
+ */
+ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03);
+ gen_and(b0, b1);
+ return b1;
+}
+
+struct block *
+gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Check whether this is an LLC frame.
+ */
+ b0 = gen_llc_internal(cstate);
+
+ /*
+ * Now check for an S frame with the appropriate type.
+ */
+ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK);
+ gen_and(b0, b1);
+ return b1;
+}
+
+struct block *
+gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Check whether this is an LLC frame.
+ */
+ b0 = gen_llc_internal(cstate);
+
+ /*
+ * Now check for a U frame with the appropriate type.
+ */
+ b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK);
+ gen_and(b0, b1);
+ return b1;
+}
+
+/*
+ * Generate code to match a particular packet type, for link-layer types
+ * using 802.2 LLC headers.
+ *
+ * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used
+ * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues.
+ *
+ * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * value, if <= ETHERMTU. We use that to determine whether to
+ * match the DSAP or both DSAP and LSAP or to check the OUI and
+ * protocol ID in a SNAP header.
+ */
+static struct block *
+gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ /*
+ * XXX - handle token-ring variable-length header.
+ */
+ switch (ll_proto) {
+
+ case LLCSAP_IP:
+ case LLCSAP_ISONS:
+ case LLCSAP_NETBEUI:
+ /*
+ * XXX - should we check both the DSAP and the
+ * SSAP, like this, or should we check just the
+ * DSAP, as we do for other SAP values?
+ */
+ return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32)
+ ((ll_proto << 8) | ll_proto));
+
+ case LLCSAP_IPX:
+ /*
+ * XXX - are there ever SNAP frames for IPX on
+ * non-Ethernet 802.x networks?
+ */
+ return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+
+ case ETHERTYPE_ATALK:
+ /*
+ * 802.2-encapsulated ETHERTYPE_ATALK packets are
+ * SNAP packets with an organization code of
+ * 0x080007 (Apple, for Appletalk) and a protocol
+ * type of ETHERTYPE_ATALK (Appletalk).
+ *
+ * XXX - check for an organization code of
+ * encapsulated Ethernet as well?
+ */
+ return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
+
+ default:
+ /*
+ * XXX - we don't have to check for IPX 802.3
+ * here, but should we check for the IPX Ethertype?
+ */
+ if (ll_proto <= ETHERMTU) {
+ /*
+ * This is an LLC SAP value, so check
+ * the DSAP.
+ */
+ return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto);
+ } else {
+ /*
+ * This is an Ethernet type; we assume that it's
+ * unlikely that it'll appear in the right place
+ * at random, and therefore check only the
+ * location that would hold the Ethernet type
+ * in a SNAP frame with an organization code of
+ * 0x000000 (encapsulated Ethernet).
+ *
+ * XXX - if we were to check for the SNAP DSAP and
+ * LSAP, as per XXX, and were also to check for an
+ * organization code of 0x000000 (encapsulated
+ * Ethernet), we'd do
+ *
+ * return gen_snap(cstate, 0x000000, ll_proto);
+ *
+ * here; for now, we don't, as per the above.
+ * I don't know whether it's worth the extra CPU
+ * time to do the right check or not.
+ */
+ return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto);
+ }
+ }
+}
+
+static struct block *
+gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
+ int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off)
+{
+ struct block *b0, *b1;
+ u_int offset;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ b0 = gen_linktype(cstate, ll_proto);
+ b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
+ gen_and(b0, b1);
+ return b1;
+}
+
+#ifdef INET6
+static struct block *
+gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
+ struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off,
+ u_int dst_off)
+{
+ struct block *b0, *b1;
+ u_int offset;
+ uint32_t *a, *m;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ /* this order is important */
+ a = (uint32_t *)addr;
+ m = (uint32_t *)mask;
+ b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
+ b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
+ gen_and(b0, b1);
+ b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
+ gen_and(b0, b1);
+ b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
+ gen_and(b0, b1);
+ b0 = gen_linktype(cstate, ll_proto);
+ gen_and(b0, b1);
+ return b1;
+}
+#endif
+
+static struct block *
+gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ register struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_ehostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ehostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_ehostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ehostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers");
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_FDDI
+ */
+static struct block *
+gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_fhostop(cstate, eaddr, Q_SRC);
+ b1 = gen_fhostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_fhostop(cstate, eaddr, Q_SRC);
+ b1 = gen_fhostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is only supported on 802.11");
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_IEEE802 (Token Ring)
+ */
+static struct block *
+gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ register struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_thostop(cstate, eaddr, Q_SRC);
+ b1 = gen_thostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_thostop(cstate, eaddr, Q_SRC);
+ b1 = gen_thostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is only supported on 802.11");
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * various 802.11 + radio headers.
+ */
+static struct block *
+gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ register struct block *b0, *b1, *b2;
+ register struct slist *s;
+
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+ /*
+ * TODO GV 20070613
+ * We need to disable the optimizer because the optimizer is buggy
+ * and wipes out some LD instructions generated by the below
+ * code to validate the Frame Control bits
+ */
+ cstate->no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
+ switch (dir) {
+ case Q_SRC:
+ /*
+ * Oh, yuk.
+ *
+ * For control frames, there is no SA.
+ *
+ * For management frames, SA is at an
+ * offset of 10 from the beginning of
+ * the packet.
+ *
+ * For data frames, SA is at an offset
+ * of 10 from the beginning of the packet
+ * if From DS is clear, at an offset of
+ * 16 from the beginning of the packet
+ * if From DS is set and To DS is clear,
+ * and an offset of 24 from the beginning
+ * of the packet if From DS is set and To DS
+ * is set.
+ */
+
+ /*
+ * Generate the tests to be done for data frames
+ * with From DS set.
+ *
+ * First, check for To DS set, i.e. check "link[1] & 0x01".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x01; /* To DS */
+ b1->stmts = s;
+
+ /*
+ * If To DS is set, the SA is at 24.
+ */
+ b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+ gen_and(b1, b0);
+
+ /*
+ * Now, check for To DS not set, i.e. check
+ * "!(link[1] & 0x01)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x01; /* To DS */
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * If To DS is not set, the SA is at 16.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+ gen_and(b2, b1);
+
+ /*
+ * Now OR together the last two checks. That gives
+ * the complete set of checks for data frames with
+ * From DS set.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * Now check for From DS being set, and AND that with
+ * the ORed-together checks.
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x02; /* From DS */
+ b1->stmts = s;
+ gen_and(b1, b0);
+
+ /*
+ * Now check for data frames with From DS not set.
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x02; /* From DS */
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * If From DS isn't set, the SA is at 10.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+ gen_and(b2, b1);
+
+ /*
+ * Now OR together the checks for data frames with
+ * From DS not set and for data frames with From DS
+ * set; that gives the checks done for data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * Now check for a data frame.
+ * I.e, check "link[0] & 0x08".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * AND that with the checks done for data frames.
+ */
+ gen_and(b1, b0);
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "!(link[0] & 0x08)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x08;
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * For management frames, the SA is at 10.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+ gen_and(b2, b1);
+
+ /*
+ * OR that with the checks done for data frames.
+ * That gives the checks done for management and
+ * data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * If the low-order bit of the type value is 1,
+ * this is either a control frame or a frame
+ * with a reserved type, and thus not a
+ * frame with an SA.
+ *
+ * I.e., check "!(link[0] & 0x04)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
+ gen_not(b1);
+
+ /*
+ * AND that with the checks for data and management
+ * frames.
+ */
+ gen_and(b1, b0);
+ return b0;
+
+ case Q_DST:
+ /*
+ * Oh, yuk.
+ *
+ * For control frames, there is no DA.
+ *
+ * For management frames, DA is at an
+ * offset of 4 from the beginning of
+ * the packet.
+ *
+ * For data frames, DA is at an offset
+ * of 4 from the beginning of the packet
+ * if To DS is clear and at an offset of
+ * 16 from the beginning of the packet
+ * if To DS is set.
+ */
+
+ /*
+ * Generate the tests to be done for data frames.
+ *
+ * First, check for To DS set, i.e. "link[1] & 0x01".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x01; /* To DS */
+ b1->stmts = s;
+
+ /*
+ * If To DS is set, the DA is at 16.
+ */
+ b0 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+ gen_and(b1, b0);
+
+ /*
+ * Now, check for To DS not set, i.e. check
+ * "!(link[1] & 0x01)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x01; /* To DS */
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * If To DS is not set, the DA is at 4.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+ gen_and(b2, b1);
+
+ /*
+ * Now OR together the last two checks. That gives
+ * the complete set of checks for data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * Now check for a data frame.
+ * I.e, check "link[0] & 0x08".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * AND that with the checks done for data frames.
+ */
+ gen_and(b1, b0);
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "!(link[0] & 0x08)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x08;
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * For management frames, the DA is at 4.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+ gen_and(b2, b1);
+
+ /*
+ * OR that with the checks done for data frames.
+ * That gives the checks done for management and
+ * data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * If the low-order bit of the type value is 1,
+ * this is either a control frame or a frame
+ * with a reserved type, and thus not a
+ * frame with an SA.
+ *
+ * I.e., check "!(link[0] & 0x04)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
+ gen_not(b1);
+
+ /*
+ * AND that with the checks for data and management
+ * frames.
+ */
+ gen_and(b1, b0);
+ return b0;
+
+ case Q_AND:
+ b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+ b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_wlanhostop(cstate, eaddr, Q_SRC);
+ b1 = gen_wlanhostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ /*
+ * XXX - add BSSID keyword?
+ */
+ case Q_ADDR1:
+ return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr));
+
+ case Q_ADDR2:
+ /*
+ * Not present in CTS or ACK control frames.
+ */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ IEEE80211_FC0_TYPE_MASK);
+ gen_not(b0);
+ b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b1);
+ b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b2);
+ gen_and(b1, b2);
+ gen_or(b0, b2);
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+ gen_and(b2, b1);
+ return b1;
+
+ case Q_ADDR3:
+ /*
+ * Not present in control frames.
+ */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ IEEE80211_FC0_TYPE_MASK);
+ gen_not(b0);
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ADDR4:
+ /*
+ * Present only if the direction mask has both "From DS"
+ * and "To DS" set. Neither control frames nor management
+ * frames should have both of those set, so we don't
+ * check the frame type.
+ */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B,
+ IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_RA:
+ /*
+ * Not present in management frames; addr1 in other
+ * frames.
+ */
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "(link[0] & 0x08)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * Check addr1.
+ */
+ b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr);
+
+ /*
+ * AND that with the check of addr1.
+ */
+ gen_and(b1, b0);
+ return (b0);
+
+ case Q_TA:
+ /*
+ * Not present in management frames; addr2, if present,
+ * in other frames.
+ */
+
+ /*
+ * Not present in CTS or ACK control frames.
+ */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ IEEE80211_FC0_TYPE_MASK);
+ gen_not(b0);
+ b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b1);
+ b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
+ IEEE80211_FC0_SUBTYPE_MASK);
+ gen_not(b2);
+ gen_and(b1, b2);
+ gen_or(b0, b2);
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "(link[0] & 0x08)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * AND that with the check for frames other than
+ * CTS and ACK frames.
+ */
+ gen_and(b1, b2);
+
+ /*
+ * Check addr2.
+ */
+ b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+ gen_and(b2, b1);
+ return b1;
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+/*
+ * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel.
+ * (We assume that the addresses are IEEE 48-bit MAC addresses,
+ * as the RFC states.)
+ */
+static struct block *
+gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ register struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_ipfchostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ipfchostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is only supported on 802.11");
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+/*
+ * This is quite tricky because there may be pad bytes in front of the
+ * DECNET header, and then there are two possible data packet formats that
+ * carry both src and dst addresses, plus 5 packet types in a format that
+ * carries only the src node, plus 2 types that use a different format and
+ * also carry just the src node.
+ *
+ * Yuck.
+ *
+ * Instead of doing those all right, we just look for data packets with
+ * 0 or 1 bytes of padding. If you want to look at other packets, that
+ * will require a lot more hacking.
+ *
+ * To add support for filtering on DECNET "areas" (network numbers)
+ * one would want to add a "mask" argument to this routine. That would
+ * make the filter even more inefficient, although one could be clever
+ * and not generate masking instructions if the mask is 0xFFFF.
+ */
+static struct block *
+gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
+{
+ struct block *b0, *b1, *b2, *tmp;
+ u_int offset_lh; /* offset if long header is received */
+ u_int offset_sh; /* offset if short header is received */
+
+ switch (dir) {
+
+ case Q_DST:
+ offset_sh = 1; /* follows flags */
+ offset_lh = 7; /* flgs,darea,dsubarea,HIORD */
+ break;
+
+ case Q_SRC:
+ offset_sh = 3; /* follows flags, dstnode */
+ offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */
+ break;
+
+ case Q_AND:
+ /* Inefficient because we do our Calvinball dance twice */
+ b0 = gen_dnhostop(cstate, addr, Q_SRC);
+ b1 = gen_dnhostop(cstate, addr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ /* Inefficient because we do our Calvinball dance twice */
+ b0 = gen_dnhostop(cstate, addr, Q_SRC);
+ b1 = gen_dnhostop(cstate, addr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ b0 = gen_linktype(cstate, ETHERTYPE_DN);
+ /* Check for pad = 1, long header case */
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
+ (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF));
+ b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh,
+ BPF_H, (bpf_u_int32)ntohs((u_short)addr));
+ gen_and(tmp, b1);
+ /* Check for pad = 0, long header case */
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x06,
+ (bpf_u_int32)0x7);
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+ /* Check for pad = 1, short header case */
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
+ (bpf_u_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF));
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+ /* Check for pad = 0, short header case */
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x02,
+ (bpf_u_int32)0x7);
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
+ gen_and(tmp, b2);
+ gen_or(b2, b1);
+
+ /* Combine with test for cstate->linktype */
+ gen_and(b0, b1);
+ return b1;
+}
+
+/*
+ * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets;
+ * test the bottom-of-stack bit, and then check the version number
+ * field in the IP header.
+ */
+static struct block *
+gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
+{
+ struct block *b0, *b1;
+
+ switch (ll_proto) {
+
+ case ETHERTYPE_IP:
+ /* match the bottom-of-stack bit */
+ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+ /* match the IPv4 version number */
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
+ gen_and(b0, b1);
+ return b1;
+
+ case ETHERTYPE_IPV6:
+ /* match the bottom-of-stack bit */
+ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
+ /* match the IPv4 version number */
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
+ gen_and(b0, b1);
+ return b1;
+
+ default:
+ /* FIXME add other L3 proto IDs */
+ bpf_error(cstate, "unsupported protocol over mpls");
+ /*NOTREACHED*/
+ }
+}
+
+static struct block *
+gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
+ int proto, int dir, int type)
+{
+ struct block *b0, *b1;
+ const char *typestr;
+
+ if (type == Q_NET)
+ typestr = "net";
+ else
+ typestr = "host";
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ b0 = gen_host(cstate, addr, mask, Q_IP, dir, type);
+ /*
+ * Only check for non-IPv4 addresses if we're not
+ * checking MPLS-encapsulated packets.
+ */
+ if (cstate->label_stack_depth == 0) {
+ b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type);
+ gen_or(b0, b1);
+ b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type);
+ gen_or(b1, b0);
+ }
+ return b0;
+
+ case Q_LINK:
+ bpf_error(cstate, "link-layer modifier applied to %s", typestr);
+
+ case Q_IP:
+ return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16);
+
+ case Q_RARP:
+ return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24);
+
+ case Q_ARP:
+ return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24);
+
+ case Q_SCTP:
+ bpf_error(cstate, "'sctp' modifier applied to %s", typestr);
+
+ case Q_TCP:
+ bpf_error(cstate, "'tcp' modifier applied to %s", typestr);
+
+ case Q_UDP:
+ bpf_error(cstate, "'udp' modifier applied to %s", typestr);
+
+ case Q_ICMP:
+ bpf_error(cstate, "'icmp' modifier applied to %s", typestr);
+
+ case Q_IGMP:
+ bpf_error(cstate, "'igmp' modifier applied to %s", typestr);
+
+ case Q_IGRP:
+ bpf_error(cstate, "'igrp' modifier applied to %s", typestr);
+
+ case Q_ATALK:
+ bpf_error(cstate, "AppleTalk host filtering not implemented");
+
+ case Q_DECNET:
+ return gen_dnhostop(cstate, addr, dir);
+
+ case Q_LAT:
+ bpf_error(cstate, "LAT host filtering not implemented");
+
+ case Q_SCA:
+ bpf_error(cstate, "SCA host filtering not implemented");
+
+ case Q_MOPRC:
+ bpf_error(cstate, "MOPRC host filtering not implemented");
+
+ case Q_MOPDL:
+ bpf_error(cstate, "MOPDL host filtering not implemented");
+
+ case Q_IPV6:
+ bpf_error(cstate, "'ip6' modifier applied to ip host");
+
+ case Q_ICMPV6:
+ bpf_error(cstate, "'icmp6' modifier applied to %s", typestr);
+
+ case Q_AH:
+ bpf_error(cstate, "'ah' modifier applied to %s", typestr);
+
+ case Q_ESP:
+ bpf_error(cstate, "'esp' modifier applied to %s", typestr);
+
+ case Q_PIM:
+ bpf_error(cstate, "'pim' modifier applied to %s", typestr);
+
+ case Q_VRRP:
+ bpf_error(cstate, "'vrrp' modifier applied to %s", typestr);
+
+ case Q_AARP:
+ bpf_error(cstate, "AARP host filtering not implemented");
+
+ case Q_ISO:
+ bpf_error(cstate, "ISO host filtering not implemented");
+
+ case Q_ESIS:
+ bpf_error(cstate, "'esis' modifier applied to %s", typestr);
+
+ case Q_ISIS:
+ bpf_error(cstate, "'isis' modifier applied to %s", typestr);
+
+ case Q_CLNP:
+ bpf_error(cstate, "'clnp' modifier applied to %s", typestr);
+
+ case Q_STP:
+ bpf_error(cstate, "'stp' modifier applied to %s", typestr);
+
+ case Q_IPX:
+ bpf_error(cstate, "IPX host filtering not implemented");
+
+ case Q_NETBEUI:
+ bpf_error(cstate, "'netbeui' modifier applied to %s", typestr);
+
+ case Q_ISIS_L1:
+ bpf_error(cstate, "'l1' modifier applied to %s", typestr);
+
+ case Q_ISIS_L2:
+ bpf_error(cstate, "'l2' modifier applied to %s", typestr);
+
+ case Q_ISIS_IIH:
+ bpf_error(cstate, "'iih' modifier applied to %s", typestr);
+
+ case Q_ISIS_SNP:
+ bpf_error(cstate, "'snp' modifier applied to %s", typestr);
+
+ case Q_ISIS_CSNP:
+ bpf_error(cstate, "'csnp' modifier applied to %s", typestr);
+
+ case Q_ISIS_PSNP:
+ bpf_error(cstate, "'psnp' modifier applied to %s", typestr);
+
+ case Q_ISIS_LSP:
+ bpf_error(cstate, "'lsp' modifier applied to %s", typestr);
+
+ case Q_RADIO:
+ bpf_error(cstate, "'radio' modifier applied to %s", typestr);
+
+ case Q_CARP:
+ bpf_error(cstate, "'carp' modifier applied to %s", typestr);
+
+ default:
+ abort();
+ }
+ /*NOTREACHED*/
+}
+
+#ifdef INET6
+static struct block *
+gen_host6(compiler_state_t *cstate, struct in6_addr *addr,
+ struct in6_addr *mask, int proto, int dir, int type)
+{
+ const char *typestr;
+
+ if (type == Q_NET)
+ typestr = "net";
+ else
+ typestr = "host";
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ return gen_host6(cstate, addr, mask, Q_IPV6, dir, type);
+
+ case Q_LINK:
+ bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr);
+
+ case Q_IP:
+ bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr);
+
+ case Q_RARP:
+ bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr);
+
+ case Q_ARP:
+ bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr);
+
+ case Q_SCTP:
+ bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr);
+
+ case Q_TCP:
+ bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr);
+
+ case Q_UDP:
+ bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr);
+
+ case Q_ICMP:
+ bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr);
+
+ case Q_IGMP:
+ bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr);
+
+ case Q_IGRP:
+ bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr);
+
+ case Q_ATALK:
+ bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr);
+
+ case Q_DECNET:
+ bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr);
+
+ case Q_LAT:
+ bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr);
+
+ case Q_SCA:
+ bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr);
+
+ case Q_MOPRC:
+ bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr);
+
+ case Q_MOPDL:
+ bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr);
+
+ case Q_IPV6:
+ return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24);
+
+ case Q_ICMPV6:
+ bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr);
+
+ case Q_AH:
+ bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr);
+
+ case Q_ESP:
+ bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr);
+
+ case Q_PIM:
+ bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr);
+
+ case Q_VRRP:
+ bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr);
+
+ case Q_AARP:
+ bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr);
+
+ case Q_ISO:
+ bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr);
+
+ case Q_ESIS:
+ bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS:
+ bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr);
+
+ case Q_CLNP:
+ bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr);
+
+ case Q_STP:
+ bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr);
+
+ case Q_IPX:
+ bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr);
+
+ case Q_NETBEUI:
+ bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_L1:
+ bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_L2:
+ bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_IIH:
+ bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_SNP:
+ bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_CSNP:
+ bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_PSNP:
+ bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr);
+
+ case Q_ISIS_LSP:
+ bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr);
+
+ case Q_RADIO:
+ bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr);
+
+ case Q_CARP:
+ bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr);
+
+ default:
+ abort();
+ }
+ /*NOTREACHED*/
+}
+#endif
+
+#ifndef INET6
+static struct block *
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
+ struct addrinfo *alist, int proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+ struct addrinfo *ai;
+ struct sockaddr_in *sin;
+
+ if (dir != 0)
+ bpf_error(cstate, "direction applied to 'gateway'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ switch (cstate->linktype) {
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check(cstate);
+ b0 = gen_ehostop(cstate, eaddr, Q_OR);
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ break;
+ case DLT_FDDI:
+ b0 = gen_fhostop(cstate, eaddr, Q_OR);
+ break;
+ case DLT_IEEE802:
+ b0 = gen_thostop(cstate, eaddr, Q_OR);
+ break;
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ b0 = gen_wlanhostop(cstate, eaddr, Q_OR);
+ break;
+ case DLT_SUNATM:
+ /*
+ * This is LLC-multiplexed traffic; if it were
+ * LANE, cstate->linktype would have been set to
+ * DLT_EN10MB.
+ */
+ bpf_error(cstate,
+ "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+ break;
+ case DLT_IP_OVER_FC:
+ b0 = gen_ipfchostop(cstate, eaddr, Q_OR);
+ break;
+ default:
+ bpf_error(cstate,
+ "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+ }
+ b1 = NULL;
+ for (ai = alist; ai != NULL; ai = ai->ai_next) {
+ /*
+ * Does it have an address?
+ */
+ if (ai->ai_addr != NULL) {
+ /*
+ * Yes. Is it an IPv4 address?
+ */
+ if (ai->ai_addr->sa_family == AF_INET) {
+ /*
+ * Generate an entry for it.
+ */
+ sin = (struct sockaddr_in *)ai->ai_addr;
+ tmp = gen_host(cstate,
+ ntohl(sin->sin_addr.s_addr),
+ 0xffffffff, proto, Q_OR, Q_HOST);
+ /*
+ * Is it the *first* IPv4 address?
+ */
+ if (b1 == NULL) {
+ /*
+ * Yes, so start with it.
+ */
+ b1 = tmp;
+ } else {
+ /*
+ * No, so OR it into the
+ * existing set of
+ * addresses.
+ */
+ gen_or(b1, tmp);
+ b1 = tmp;
+ }
+ }
+ }
+ }
+ if (b1 == NULL) {
+ /*
+ * No IPv4 addresses found.
+ */
+ return (NULL);
+ }
+ gen_not(b1);
+ gen_and(b0, b1);
+ return b1;
+ }
+ bpf_error(cstate, "illegal modifier of 'gateway'");
+ /*NOTREACHED*/
+}
+#endif
+
+static struct block *
+gen_proto_abbrev_internal(compiler_state_t *cstate, int proto)
+{
+ struct block *b0;
+ struct block *b1;
+
+ switch (proto) {
+
+ case Q_SCTP:
+ b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT);
+ b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_TCP:
+ 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(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(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT);
+ break;
+
+#ifndef IPPROTO_IGMP
+#define IPPROTO_IGMP 2
+#endif
+
+ case Q_IGMP:
+ b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT);
+ break;
+
+#ifndef IPPROTO_IGRP
+#define IPPROTO_IGRP 9
+#endif
+ case Q_IGRP:
+ b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT);
+ break;
+
+#ifndef IPPROTO_PIM
+#define IPPROTO_PIM 103
+#endif
+
+ case Q_PIM:
+ b1 = gen_proto(cstate, IPPROTO_PIM, Q_IP, Q_DEFAULT);
+ b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+#ifndef IPPROTO_VRRP
+#define IPPROTO_VRRP 112
+#endif
+
+ case Q_VRRP:
+ b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT);
+ break;
+
+#ifndef IPPROTO_CARP
+#define IPPROTO_CARP 112
+#endif
+
+ case Q_CARP:
+ b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT);
+ break;
+
+ case Q_IP:
+ b1 = gen_linktype(cstate, ETHERTYPE_IP);
+ break;
+
+ case Q_ARP:
+ b1 = gen_linktype(cstate, ETHERTYPE_ARP);
+ break;
+
+ case Q_RARP:
+ b1 = gen_linktype(cstate, ETHERTYPE_REVARP);
+ break;
+
+ case Q_LINK:
+ bpf_error(cstate, "link layer applied in wrong context");
+
+ case Q_ATALK:
+ b1 = gen_linktype(cstate, ETHERTYPE_ATALK);
+ break;
+
+ case Q_AARP:
+ b1 = gen_linktype(cstate, ETHERTYPE_AARP);
+ break;
+
+ case Q_DECNET:
+ b1 = gen_linktype(cstate, ETHERTYPE_DN);
+ break;
+
+ case Q_SCA:
+ b1 = gen_linktype(cstate, ETHERTYPE_SCA);
+ break;
+
+ case Q_LAT:
+ b1 = gen_linktype(cstate, ETHERTYPE_LAT);
+ break;
+
+ case Q_MOPDL:
+ b1 = gen_linktype(cstate, ETHERTYPE_MOPDL);
+ break;
+
+ case Q_MOPRC:
+ b1 = gen_linktype(cstate, ETHERTYPE_MOPRC);
+ break;
+
+ case Q_IPV6:
+ b1 = gen_linktype(cstate, ETHERTYPE_IPV6);
+ break;
+
+#ifndef IPPROTO_ICMPV6
+#define IPPROTO_ICMPV6 58
+#endif
+ case Q_ICMPV6:
+ b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT);
+ break;
+
+#ifndef IPPROTO_AH
+#define IPPROTO_AH 51
+#endif
+ case Q_AH:
+ b1 = gen_proto(cstate, IPPROTO_AH, Q_IP, Q_DEFAULT);
+ b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP 50
+#endif
+ case Q_ESP:
+ 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(cstate, LLCSAP_ISONS);
+ break;
+
+ case Q_ESIS:
+ b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT);
+ break;
+
+ case Q_ISIS:
+ b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+ break;
+
+ case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */
+ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */
+ b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */
+ b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_LSP:
+ b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_SNP:
+ b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_CSNP:
+ b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_ISIS_PSNP:
+ b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT);
+ b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT);
+ gen_or(b0, b1);
+ break;
+
+ case Q_CLNP:
+ b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT);
+ break;
+
+ case Q_STP:
+ b1 = gen_linktype(cstate, LLCSAP_8021D);
+ break;
+
+ case Q_IPX:
+ b1 = gen_linktype(cstate, LLCSAP_IPX);
+ break;
+
+ case Q_NETBEUI:
+ b1 = gen_linktype(cstate, LLCSAP_NETBEUI);
+ break;
+
+ case Q_RADIO:
+ bpf_error(cstate, "'radio' is not a valid protocol type");
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+struct block *
+gen_proto_abbrev(compiler_state_t *cstate, int proto)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_proto_abbrev_internal(cstate, proto);
+}
+
+static struct block *
+gen_ipfrag(compiler_state_t *cstate)
+{
+ struct slist *s;
+ struct block *b;
+
+ /* not IPv4 frag other than the first frag */
+ s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H);
+ b = new_block(cstate, JMP(BPF_JSET));
+ b->s.k = 0x1fff;
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+/*
+ * Generate a comparison to a port value in the transport-layer header
+ * at the specified offset from the beginning of that header.
+ *
+ * XXX - this handles a variable-length prefix preceding the link-layer
+ * header, such as the radiotap or AVS radio prefix, but doesn't handle
+ * variable-length link-layer headers (such as Token Ring or 802.11
+ * headers).
+ */
+static struct block *
+gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v)
+{
+ return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v);
+}
+
+static struct block *
+gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v)
+{
+ return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
+}
+
+static struct block *
+gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip proto 'proto' and not a fragment other than the first fragment */
+ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
+ b0 = gen_ipfrag(cstate);
+ gen_and(tmp, b0);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portatom(cstate, 0, port);
+ break;
+
+ case Q_DST:
+ b1 = gen_portatom(cstate, 2, port);
+ break;
+
+ case Q_AND:
+ tmp = gen_portatom(cstate, 0, port);
+ b1 = gen_portatom(cstate, 2, port);
+ gen_and(tmp, b1);
+ break;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ tmp = gen_portatom(cstate, 0, port);
+ b1 = gen_portatom(cstate, 2, port);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for ports");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for ports");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /*
+ * ether proto ip
+ *
+ * For FDDI, RFC 1188 says that SNAP encapsulation is used,
+ * not LLC encapsulation with LLCSAP_IP.
+ *
+ * For IEEE 802 networks - which includes 802.5 token ring
+ * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042
+ * says that SNAP encapsulation is used, not LLC encapsulation
+ * with LLCSAP_IP.
+ *
+ * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and
+ * RFC 2225 say that SNAP encapsulation is used, not LLC
+ * encapsulation with LLCSAP_IP.
+ *
+ * So we always check for ETHERTYPE_IP.
+ */
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portop(cstate, port, (u_int)ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portop(cstate, port, IPPROTO_TCP, dir);
+ b1 = gen_portop(cstate, port, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+struct block *
+gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip6 proto 'proto' */
+ /* XXX - catch the first fragment of a fragmented packet? */
+ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portatom6(cstate, 0, port);
+ break;
+
+ case Q_DST:
+ b1 = gen_portatom6(cstate, 2, port);
+ break;
+
+ case Q_AND:
+ tmp = gen_portatom6(cstate, 0, port);
+ b1 = gen_portatom6(cstate, 2, port);
+ gen_and(tmp, b1);
+ break;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ tmp = gen_portatom6(cstate, 0, port);
+ b1 = gen_portatom6(cstate, 2, port);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* link proto ip6 */
+ b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir);
+ b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+/* gen_portrange code */
+static struct block *
+gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+ bpf_u_int32 v2)
+{
+ struct block *b1, *b2;
+
+ if (v1 > v2) {
+ /*
+ * Reverse the order of the ports, so v1 is the lower one.
+ */
+ bpf_u_int32 vtemp;
+
+ vtemp = v1;
+ v1 = v2;
+ v2 = vtemp;
+ }
+
+ b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1);
+ b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2);
+
+ gen_and(b1, b2);
+
+ return b2;
+}
+
+static struct block *
+gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2,
+ bpf_u_int32 proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip proto 'proto' and not a fragment other than the first fragment */
+ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
+ b0 = gen_ipfrag(cstate);
+ gen_and(tmp, b0);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portrangeatom(cstate, 0, port1, port2);
+ break;
+
+ case Q_DST:
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
+ break;
+
+ case Q_AND:
+ tmp = gen_portrangeatom(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
+ gen_and(tmp, b1);
+ break;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ tmp = gen_portrangeatom(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for port ranges");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for port ranges");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
+ int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* link proto ip */
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto,
+ dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir);
+ b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+ bpf_u_int32 v2)
+{
+ struct block *b1, *b2;
+
+ if (v1 > v2) {
+ /*
+ * Reverse the order of the ports, so v1 is the lower one.
+ */
+ bpf_u_int32 vtemp;
+
+ vtemp = v1;
+ v1 = v2;
+ v2 = vtemp;
+ }
+
+ b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1);
+ b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2);
+
+ gen_and(b1, b2);
+
+ return b2;
+}
+
+static struct block *
+gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2,
+ bpf_u_int32 proto, int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip6 proto 'proto' */
+ /* XXX - catch the first fragment of a fragmented packet? */
+ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portrangeatom6(cstate, 0, port1, port2);
+ break;
+
+ case Q_DST:
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+ break;
+
+ case Q_AND:
+ tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+ gen_and(tmp, b1);
+ break;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
+ int dir)
+{
+ struct block *b0, *b1, *tmp;
+
+ /* link proto ip6 */
+ b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto,
+ dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir);
+ b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+static int
+lookup_proto(compiler_state_t *cstate, const char *name, int proto)
+{
+ register int v;
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_IP:
+ case Q_IPV6:
+ v = pcap_nametoproto(name);
+ if (v == PROTO_UNDEF)
+ bpf_error(cstate, "unknown ip proto '%s'", name);
+ break;
+
+ case Q_LINK:
+ /* XXX should look up h/w protocol type based on cstate->linktype */
+ v = pcap_nametoeproto(name);
+ if (v == PROTO_UNDEF) {
+ v = pcap_nametollc(name);
+ if (v == PROTO_UNDEF)
+ bpf_error(cstate, "unknown ether proto '%s'", name);
+ }
+ break;
+
+ case Q_ISO:
+ if (strcmp(name, "esis") == 0)
+ v = ISO9542_ESIS;
+ else if (strcmp(name, "isis") == 0)
+ v = ISO10589_ISIS;
+ else if (strcmp(name, "clnp") == 0)
+ v = ISO8473_CLNP;
+ else
+ bpf_error(cstate, "unknown osi proto '%s'", name);
+ break;
+
+ default:
+ v = PROTO_UNDEF;
+ break;
+ }
+ return v;
+}
+
+#if 0
+struct stmt *
+gen_joinsp(struct stmt **s, int n)
+{
+ return NULL;
+}
+#endif
+
+static struct block *
+gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
+{
+#ifdef NO_PROTOCHAIN
+ return gen_proto(cstate, v, proto);
+#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(cstate);
+
+ memset(s, 0, sizeof(s));
+ fix3 = fix4 = fix5 = 0;
+
+ switch (proto) {
+ case Q_IP:
+ case Q_IPV6:
+ break;
+ case Q_DEFAULT:
+ b0 = gen_protochain(cstate, v, Q_IP);
+ b = gen_protochain(cstate, v, Q_IPV6);
+ gen_or(b0, b);
+ return b;
+ default:
+ bpf_error(cstate, "bad protocol applied for 'protochain'");
+ /*NOTREACHED*/
+ }
+
+ /*
+ * We don't handle variable-length prefixes before the link-layer
+ * header, or variable-length link-layer headers, here yet.
+ * We might want to add BPF instructions to do the protochain
+ * work, to simplify that and, on platforms that have a BPF
+ * interpreter with the new instructions, let the filtering
+ * be done in the kernel. (We already require a modified BPF
+ * engine to do the protochain stuff, to support backward
+ * branches, and backward branch support is unlikely to appear
+ * in kernel BPF engines.)
+ */
+ if (cstate->off_linkpl.is_variable)
+ bpf_error(cstate, "'protochain' not supported with variable length headers");
+
+ /*
+ * To quote a comment in optimize.c:
+ *
+ * "These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme. Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined."
+ *
+ * "Acyclic" means "no backward branches", which means "no
+ * loops", so we have to turn the optimizer off.
+ */
+ cstate->no_optimize = 1;
+
+ /*
+ * s[0] is a dummy entry to protect other BPF insn from damage
+ * by s[fix] = foo with uninitialized variable "fix". It is somewhat
+ * hard to find interdependency made by jump table fixup.
+ */
+ i = 0;
+ s[i] = new_stmt(cstate, 0); /*dummy*/
+ i++;
+
+ switch (proto) {
+ case Q_IP:
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+
+ /* A = ip->ip_p */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 9;
+ i++;
+ /* X = ip->ip_hl << 2 */
+ s[i] = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ i++;
+ break;
+
+ case Q_IPV6:
+ b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+
+ /* A = ip6->ip_nxt */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 6;
+ i++;
+ /* X = sizeof(struct ip6_hdr) */
+ s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM);
+ s[i]->s.k = 40;
+ i++;
+ break;
+
+ default:
+ bpf_error(cstate, "unsupported proto to gen_protochain");
+ /*NOTREACHED*/
+ }
+
+ /* again: if (A == v) goto end; else fall through; */
+ again = i;
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.k = v;
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*update in next stmt*/
+ fix5 = i;
+ i++;
+
+#ifndef IPPROTO_NONE
+#define IPPROTO_NONE 59
+#endif
+ /* if (A == IPPROTO_NONE) goto end */
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*update in next stmt*/
+ s[i]->s.k = IPPROTO_NONE;
+ s[fix5]->s.jf = s[i];
+ fix2 = i;
+ i++;
+
+ if (proto == Q_IPV6) {
+ int v6start, v6end, v6advance, j;
+
+ v6start = i;
+ /* if (A == IPPROTO_HOPOPTS) goto v6advance */
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*update in next stmt*/
+ s[i]->s.k = IPPROTO_HOPOPTS;
+ s[fix2]->s.jf = s[i];
+ i++;
+ /* if (A == IPPROTO_DSTOPTS) goto v6advance */
+ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*update in next stmt*/
+ s[i]->s.k = IPPROTO_DSTOPTS;
+ i++;
+ /* if (A == IPPROTO_ROUTING) goto v6advance */
+ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*update in next stmt*/
+ s[i]->s.k = IPPROTO_ROUTING;
+ i++;
+ /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */
+ s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*later*/
+ s[i]->s.k = IPPROTO_FRAGMENT;
+ fix3 = i;
+ v6end = i;
+ i++;
+
+ /* v6advance: */
+ v6advance = i;
+
+ /*
+ * in short,
+ * A = P[X + packet head];
+ * X = X + (P[X + packet head + 1] + 1) * 8;
+ */
+ /* A = P[X + packet head] */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ i++;
+ /* MEM[reg2] = A */
+ s[i] = new_stmt(cstate, BPF_ST);
+ s[i]->s.k = reg2;
+ i++;
+ /* A = P[X + packet head + 1]; */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 1;
+ i++;
+ /* A += 1 */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s[i]->s.k = 1;
+ i++;
+ /* A *= 8 */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+ s[i]->s.k = 8;
+ i++;
+ /* A += X */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+ s[i]->s.k = 0;
+ i++;
+ /* X = A; */
+ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ i++;
+ /* A = MEM[reg2] */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s[i]->s.k = reg2;
+ i++;
+
+ /* goto again; (must use BPF_JA for backward jump) */
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA);
+ s[i]->s.k = again - i - 1;
+ s[i - 1]->s.jf = s[i];
+ i++;
+
+ /* fixup */
+ for (j = v6start; j <= v6end; j++)
+ s[j]->s.jt = s[v6advance];
+ } else {
+ /* nop */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s[i]->s.k = 0;
+ s[fix2]->s.jf = s[i];
+ i++;
+ }
+
+ /* ahcheck: */
+ ahcheck = i;
+ /* if (A == IPPROTO_AH) then fall through; else goto end; */
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K);
+ s[i]->s.jt = NULL; /*later*/
+ s[i]->s.jf = NULL; /*later*/
+ s[i]->s.k = IPPROTO_AH;
+ if (fix3)
+ s[fix3]->s.jf = s[ahcheck];
+ fix4 = i;
+ i++;
+
+ /*
+ * in short,
+ * A = P[X];
+ * X = X + (P[X + 1] + 2) * 4;
+ */
+ /* A = X */
+ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA);
+ i++;
+ /* A = P[X + packet head]; */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ i++;
+ /* MEM[reg2] = A */
+ s[i] = new_stmt(cstate, BPF_ST);
+ s[i]->s.k = reg2;
+ i++;
+ /* A = X */
+ s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA);
+ i++;
+ /* A += 1 */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s[i]->s.k = 1;
+ i++;
+ /* X = A */
+ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ i++;
+ /* A = P[X + packet head] */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ i++;
+ /* A += 2 */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s[i]->s.k = 2;
+ i++;
+ /* A *= 4 */
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+ s[i]->s.k = 4;
+ i++;
+ /* X = A; */
+ s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ i++;
+ /* A = MEM[reg2] */
+ s[i] = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s[i]->s.k = reg2;
+ i++;
+
+ /* goto again; (must use BPF_JA for backward jump) */
+ s[i] = new_stmt(cstate, BPF_JMP|BPF_JA);
+ s[i]->s.k = again - i - 1;
+ i++;
+
+ /* end: nop */
+ end = i;
+ s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s[i]->s.k = 0;
+ s[fix2]->s.jt = s[end];
+ s[fix4]->s.jf = s[end];
+ s[fix5]->s.jt = s[end];
+ i++;
+
+ /*
+ * make slist chain
+ */
+ max = i;
+ for (i = 0; i < max - 1; i++)
+ s[i]->next = s[i + 1];
+ s[max - 1]->next = NULL;
+
+ /*
+ * emit final check
+ */
+ b = new_block(cstate, JMP(BPF_JEQ));
+ b->stmts = s[1]; /*remember, s[0] is dummy*/
+ b->s.k = v;
+
+ free_reg(cstate, reg2);
+
+ gen_and(b0, b);
+ return b;
+#endif
+}
+
+static struct block *
+gen_check_802_11_data_frame(compiler_state_t *cstate)
+{
+ struct slist *s;
+ struct block *b0, *b1;
+
+ /*
+ * A data frame has the 0x08 bit (b3) in the frame control field set
+ * and the 0x04 bit (b2) clear.
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b0 = new_block(cstate, JMP(BPF_JSET));
+ b0->s.k = 0x08;
+ b0->stmts = s;
+
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
+ gen_not(b1);
+
+ gen_and(b1, b0);
+
+ return b0;
+}
+
+/*
+ * Generate code that checks whether the packet is a packet for protocol
+ * <proto> and whether the type field in that protocol's header has
+ * the value <v>, e.g. if <proto> is Q_IP, it checks whether it's an
+ * IP packet and checks the protocol number in the IP header against <v>.
+ *
+ * If <proto> is Q_DEFAULT, i.e. just "proto" was specified, it checks
+ * against Q_IP and Q_IPV6.
+ */
+static struct block *
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
+{
+ struct block *b0, *b1;
+#ifndef CHASE_CHAIN
+ struct block *b2;
+#endif
+
+ if (dir != Q_DEFAULT)
+ bpf_error(cstate, "direction applied to 'proto'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ b0 = gen_proto(cstate, v, Q_IP, dir);
+ b1 = gen_proto(cstate, v, Q_IPV6, dir);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_LINK:
+ return gen_linktype(cstate, v);
+
+ case Q_IP:
+ /*
+ * For FDDI, RFC 1188 says that SNAP encapsulation is used,
+ * not LLC encapsulation with LLCSAP_IP.
+ *
+ * For IEEE 802 networks - which includes 802.5 token ring
+ * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042
+ * says that SNAP encapsulation is used, not LLC encapsulation
+ * with LLCSAP_IP.
+ *
+ * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and
+ * RFC 2225 say that SNAP encapsulation is used, not LLC
+ * encapsulation with LLCSAP_IP.
+ *
+ * So we always check for ETHERTYPE_IP.
+ */
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+#ifndef CHASE_CHAIN
+ b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v);
+#else
+ b1 = gen_protochain(cstate, v, Q_IP);
+#endif
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ARP:
+ bpf_error(cstate, "arp does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_RARP:
+ bpf_error(cstate, "rarp does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_SCTP:
+ bpf_error(cstate, "'sctp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_TCP:
+ bpf_error(cstate, "'tcp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_UDP:
+ bpf_error(cstate, "'udp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ICMP:
+ bpf_error(cstate, "'icmp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_IGMP:
+ bpf_error(cstate, "'igmp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_IGRP:
+ bpf_error(cstate, "'igrp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ATALK:
+ bpf_error(cstate, "AppleTalk encapsulation is not specifiable");
+ /*NOTREACHED*/
+
+ case Q_DECNET:
+ bpf_error(cstate, "DECNET encapsulation is not specifiable");
+ /*NOTREACHED*/
+
+ case Q_LAT:
+ bpf_error(cstate, "LAT does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_SCA:
+ bpf_error(cstate, "SCA does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_MOPRC:
+ bpf_error(cstate, "MOPRC does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_MOPDL:
+ bpf_error(cstate, "MOPDL does not encapsulate another protocol");
+ /*NOTREACHED*/
+
+ case Q_IPV6:
+ b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+#ifndef CHASE_CHAIN
+ /*
+ * Also check for a fragment header before the final
+ * header.
+ */
+ b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
+ b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
+ gen_and(b2, b1);
+ b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v);
+ gen_or(b2, b1);
+#else
+ b1 = gen_protochain(cstate, v, Q_IPV6);
+#endif
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ICMPV6:
+ bpf_error(cstate, "'icmp6 proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_AH:
+ bpf_error(cstate, "'ah proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ESP:
+ bpf_error(cstate, "'esp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_PIM:
+ bpf_error(cstate, "'pim proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_VRRP:
+ bpf_error(cstate, "'vrrp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_AARP:
+ bpf_error(cstate, "'aarp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISO:
+ switch (cstate->linktype) {
+
+ case DLT_FRELAY:
+ /*
+ * Frame Relay packets typically have an OSI
+ * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)"
+ * generates code to check for all the OSI
+ * NLPIDs, so calling it and then adding a check
+ * for the particular NLPID for which we're
+ * looking is bogus, as we can just check for
+ * the NLPID.
+ *
+ * What we check for is the NLPID and a frame
+ * control field value of UI, i.e. 0x03 followed
+ * by the NLPID.
+ *
+ * XXX - assumes a 2-byte Frame Relay header with
+ * DLCI and flags. What if the address is longer?
+ *
+ * XXX - what about SNAP-encapsulated frames?
+ */
+ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v);
+ /*NOTREACHED*/
+
+ case DLT_C_HDLC:
+ /*
+ * Cisco uses an Ethertype lookalike - for OSI,
+ * it's 0xfefe.
+ */
+ b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS);
+ /* OSI in C-HDLC is stuffed with a fudge byte */
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v);
+ gen_and(b0, b1);
+ return b1;
+
+ default:
+ b0 = gen_linktype(cstate, LLCSAP_ISONS);
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v);
+ gen_and(b0, b1);
+ return b1;
+ }
+
+ case Q_ESIS:
+ bpf_error(cstate, "'esis proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS:
+ b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT);
+ /*
+ * 4 is the offset of the PDU type relative to the IS-IS
+ * header.
+ */
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_CLNP:
+ bpf_error(cstate, "'clnp proto' is not supported");
+ /*NOTREACHED*/
+
+ case Q_STP:
+ bpf_error(cstate, "'stp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_IPX:
+ bpf_error(cstate, "'ipx proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_NETBEUI:
+ bpf_error(cstate, "'netbeui proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_L1:
+ bpf_error(cstate, "'l1 proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_L2:
+ bpf_error(cstate, "'l2 proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_IIH:
+ bpf_error(cstate, "'iih proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_SNP:
+ bpf_error(cstate, "'snp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_CSNP:
+ bpf_error(cstate, "'csnp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_PSNP:
+ bpf_error(cstate, "'psnp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_ISIS_LSP:
+ bpf_error(cstate, "'lsp proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_RADIO:
+ bpf_error(cstate, "'radio proto' is bogus");
+ /*NOTREACHED*/
+
+ case Q_CARP:
+ bpf_error(cstate, "'carp proto' is bogus");
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
+{
+ int proto = q.proto;
+ int dir = q.dir;
+ int tproto;
+ u_char *eaddr;
+ bpf_u_int32 mask, addr;
+ struct addrinfo *res, *res0;
+ struct sockaddr_in *sin4;
+#ifdef INET6
+ int tproto6;
+ struct sockaddr_in6 *sin6;
+ struct in6_addr mask128;
+#endif /*INET6*/
+ struct block *b, *tmp;
+ int port, real_proto;
+ int port1, port2;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (q.addr) {
+
+ case Q_NET:
+ addr = pcap_nametonetaddr(name);
+ if (addr == 0)
+ bpf_error(cstate, "unknown network '%s'", name);
+ /* Left justify network addr and calculate its network mask */
+ mask = 0xffffffff;
+ while (addr && (addr & 0xff000000) == 0) {
+ addr <<= 8;
+ mask <<= 8;
+ }
+ return gen_host(cstate, addr, mask, proto, dir, q.addr);
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ if (proto == Q_LINK) {
+ switch (cstate->linktype) {
+
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate,
+ "unknown ether host '%s'", name);
+ tmp = gen_prevlinkhdr_check(cstate);
+ b = gen_ehostop(cstate, eaddr, dir);
+ if (tmp != NULL)
+ gen_and(tmp, b);
+ free(eaddr);
+ return b;
+
+ case DLT_FDDI:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate,
+ "unknown FDDI host '%s'", name);
+ b = gen_fhostop(cstate, eaddr, dir);
+ free(eaddr);
+ return b;
+
+ case DLT_IEEE802:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate,
+ "unknown token ring host '%s'", name);
+ b = gen_thostop(cstate, eaddr, dir);
+ free(eaddr);
+ return b;
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate,
+ "unknown 802.11 host '%s'", name);
+ b = gen_wlanhostop(cstate, eaddr, dir);
+ free(eaddr);
+ return b;
+
+ case DLT_IP_OVER_FC:
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate,
+ "unknown Fibre Channel host '%s'", name);
+ b = gen_ipfchostop(cstate, eaddr, dir);
+ free(eaddr);
+ return b;
+ }
+
+ bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name");
+ } else if (proto == Q_DECNET) {
+ unsigned short dn_addr;
+
+ if (!__pcap_nametodnaddr(name, &dn_addr)) {
+#ifdef DECNETLIB
+ bpf_error(cstate, "unknown decnet host name '%s'\n", name);
+#else
+ bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n",
+ name);
+#endif
+ }
+ /*
+ * I don't think DECNET hosts can be multihomed, so
+ * there is no need to build up a list of addresses
+ */
+ return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr));
+ } else {
+#ifdef INET6
+ memset(&mask128, 0xff, sizeof(mask128));
+#endif
+ res0 = res = pcap_nametoaddrinfo(name);
+ if (res == NULL)
+ bpf_error(cstate, "unknown host '%s'", name);
+ cstate->ai = res;
+ b = tmp = NULL;
+ tproto = proto;
+#ifdef INET6
+ tproto6 = proto;
+#endif
+ if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
+ tproto == Q_DEFAULT) {
+ tproto = Q_IP;
+#ifdef INET6
+ tproto6 = Q_IPV6;
+#endif
+ }
+ for (res = res0; res; res = res->ai_next) {
+ switch (res->ai_family) {
+ case AF_INET:
+#ifdef INET6
+ if (tproto == Q_IPV6)
+ continue;
+#endif
+
+ sin4 = (struct sockaddr_in *)
+ res->ai_addr;
+ tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr),
+ 0xffffffff, tproto, dir, q.addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (tproto6 == Q_IP)
+ continue;
+
+ sin6 = (struct sockaddr_in6 *)
+ res->ai_addr;
+ tmp = gen_host6(cstate, &sin6->sin6_addr,
+ &mask128, tproto6, dir, q.addr);
+ break;
+#endif
+ default:
+ continue;
+ }
+ if (b)
+ gen_or(b, tmp);
+ b = tmp;
+ }
+ cstate->ai = NULL;
+ freeaddrinfo(res0);
+ if (b == NULL) {
+ bpf_error(cstate, "unknown host '%s'%s", name,
+ (proto == Q_DEFAULT)
+ ? ""
+ : " for specified address family");
+ }
+ return b;
+ }
+
+ case Q_PORT:
+ if (proto != Q_DEFAULT &&
+ proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
+ bpf_error(cstate, "illegal qualifier of 'port'");
+ if (pcap_nametoport(name, &port, &real_proto) == 0)
+ bpf_error(cstate, "unknown port '%s'", name);
+ if (proto == Q_UDP) {
+ if (real_proto == IPPROTO_TCP)
+ bpf_error(cstate, "port '%s' is tcp", name);
+ else if (real_proto == IPPROTO_SCTP)
+ bpf_error(cstate, "port '%s' is sctp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_UDP;
+ }
+ if (proto == Q_TCP) {
+ if (real_proto == IPPROTO_UDP)
+ bpf_error(cstate, "port '%s' is udp", name);
+
+ else if (real_proto == IPPROTO_SCTP)
+ bpf_error(cstate, "port '%s' is sctp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_TCP;
+ }
+ if (proto == Q_SCTP) {
+ if (real_proto == IPPROTO_UDP)
+ bpf_error(cstate, "port '%s' is udp", name);
+
+ else if (real_proto == IPPROTO_TCP)
+ bpf_error(cstate, "port '%s' is tcp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_SCTP;
+ }
+ if (port < 0)
+ bpf_error(cstate, "illegal port number %d < 0", port);
+ if (port > 65535)
+ bpf_error(cstate, "illegal port number %d > 65535", port);
+ b = gen_port(cstate, port, real_proto, dir);
+ gen_or(gen_port6(cstate, port, real_proto, dir), b);
+ return b;
+
+ case Q_PORTRANGE:
+ if (proto != Q_DEFAULT &&
+ proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
+ bpf_error(cstate, "illegal qualifier of 'portrange'");
+ if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0)
+ bpf_error(cstate, "unknown port in range '%s'", name);
+ if (proto == Q_UDP) {
+ if (real_proto == IPPROTO_TCP)
+ bpf_error(cstate, "port in range '%s' is tcp", name);
+ else if (real_proto == IPPROTO_SCTP)
+ bpf_error(cstate, "port in range '%s' is sctp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_UDP;
+ }
+ if (proto == Q_TCP) {
+ if (real_proto == IPPROTO_UDP)
+ bpf_error(cstate, "port in range '%s' is udp", name);
+ else if (real_proto == IPPROTO_SCTP)
+ bpf_error(cstate, "port in range '%s' is sctp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_TCP;
+ }
+ if (proto == Q_SCTP) {
+ if (real_proto == IPPROTO_UDP)
+ bpf_error(cstate, "port in range '%s' is udp", name);
+ else if (real_proto == IPPROTO_TCP)
+ bpf_error(cstate, "port in range '%s' is tcp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_SCTP;
+ }
+ if (port1 < 0)
+ bpf_error(cstate, "illegal port number %d < 0", port1);
+ if (port1 > 65535)
+ bpf_error(cstate, "illegal port number %d > 65535", port1);
+ if (port2 < 0)
+ bpf_error(cstate, "illegal port number %d < 0", port2);
+ if (port2 > 65535)
+ bpf_error(cstate, "illegal port number %d > 65535", port2);
+
+ b = gen_portrange(cstate, port1, port2, real_proto, dir);
+ gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b);
+ return b;
+
+ case Q_GATEWAY:
+#ifndef INET6
+ eaddr = pcap_ether_hostton(name);
+ if (eaddr == NULL)
+ bpf_error(cstate, "unknown ether host: %s", name);
+
+ res = pcap_nametoaddrinfo(name);
+ cstate->ai = res;
+ if (res == NULL)
+ bpf_error(cstate, "unknown host '%s'", name);
+ b = gen_gateway(cstate, eaddr, res, proto, dir);
+ cstate->ai = NULL;
+ freeaddrinfo(res);
+ if (b == NULL)
+ bpf_error(cstate, "unknown host '%s'", name);
+ return b;
+#else
+ bpf_error(cstate, "'gateway' not supported in this configuration");
+#endif /*INET6*/
+
+ case Q_PROTO:
+ real_proto = lookup_proto(cstate, name, proto);
+ if (real_proto >= 0)
+ return gen_proto(cstate, real_proto, proto, dir);
+ else
+ bpf_error(cstate, "unknown protocol: %s", name);
+
+ case Q_PROTOCHAIN:
+ real_proto = lookup_proto(cstate, name, proto);
+ if (real_proto >= 0)
+ return gen_protochain(cstate, real_proto, proto);
+ else
+ bpf_error(cstate, "unknown protocol: %s", name);
+
+ case Q_UNDEF:
+ syntax(cstate);
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
+ bpf_u_int32 masklen, struct qual q)
+{
+ register int nlen, mlen;
+ bpf_u_int32 n, m;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ nlen = __pcap_atoin(s1, &n);
+ if (nlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s1);
+ /* Promote short ipaddr */
+ n <<= 32 - nlen;
+
+ if (s2 != NULL) {
+ mlen = __pcap_atoin(s2, &m);
+ if (mlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s2);
+ /* Promote short ipaddr */
+ m <<= 32 - mlen;
+ if ((n & ~m) != 0)
+ bpf_error(cstate, "non-network bits set in \"%s mask %s\"",
+ s1, s2);
+ } else {
+ /* Convert mask len to mask */
+ if (masklen > 32)
+ bpf_error(cstate, "mask length must be <= 32");
+ if (masklen == 0) {
+ /*
+ * X << 32 is not guaranteed by C to be 0; it's
+ * undefined.
+ */
+ m = 0;
+ } else
+ m = 0xffffffff << (32 - masklen);
+ if ((n & ~m) != 0)
+ bpf_error(cstate, "non-network bits set in \"%s/%d\"",
+ s1, masklen);
+ }
+
+ switch (q.addr) {
+
+ case Q_NET:
+ return gen_host(cstate, n, m, q.proto, q.dir, q.addr);
+
+ default:
+ bpf_error(cstate, "Mask syntax for networks only");
+ /*NOTREACHED*/
+ }
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
+{
+ bpf_u_int32 mask;
+ int proto;
+ int dir;
+ register int vlen;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ proto = q.proto;
+ dir = q.dir;
+ if (s == NULL)
+ vlen = 32;
+ else if (q.proto == Q_DECNET) {
+ vlen = __pcap_atodn(s, &v);
+ if (vlen == 0)
+ bpf_error(cstate, "malformed decnet address '%s'", s);
+ } else {
+ vlen = __pcap_atoin(s, &v);
+ if (vlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s);
+ }
+
+ switch (q.addr) {
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ case Q_NET:
+ if (proto == Q_DECNET)
+ return gen_host(cstate, v, 0, proto, dir, q.addr);
+ else if (proto == Q_LINK) {
+ bpf_error(cstate, "illegal link layer address");
+ } else {
+ mask = 0xffffffff;
+ if (s == NULL && q.addr == Q_NET) {
+ /* Promote short net number */
+ while (v && (v & 0xff000000) == 0) {
+ v <<= 8;
+ mask <<= 8;
+ }
+ } else {
+ /* Promote short ipaddr */
+ v <<= 32 - vlen;
+ mask <<= 32 - vlen ;
+ }
+ return gen_host(cstate, v, mask, proto, dir, q.addr);
+ }
+
+ case Q_PORT:
+ if (proto == Q_UDP)
+ proto = IPPROTO_UDP;
+ else if (proto == Q_TCP)
+ proto = IPPROTO_TCP;
+ else if (proto == Q_SCTP)
+ proto = IPPROTO_SCTP;
+ else if (proto == Q_DEFAULT)
+ proto = PROTO_UNDEF;
+ else
+ bpf_error(cstate, "illegal qualifier of 'port'");
+
+ if (v > 65535)
+ bpf_error(cstate, "illegal port number %u > 65535", v);
+
+ {
+ struct block *b;
+ b = gen_port(cstate, v, proto, dir);
+ gen_or(gen_port6(cstate, v, proto, dir), b);
+ return b;
+ }
+
+ case Q_PORTRANGE:
+ if (proto == Q_UDP)
+ proto = IPPROTO_UDP;
+ else if (proto == Q_TCP)
+ proto = IPPROTO_TCP;
+ else if (proto == Q_SCTP)
+ proto = IPPROTO_SCTP;
+ else if (proto == Q_DEFAULT)
+ proto = PROTO_UNDEF;
+ else
+ bpf_error(cstate, "illegal qualifier of 'portrange'");
+
+ if (v > 65535)
+ bpf_error(cstate, "illegal port number %u > 65535", v);
+
+ {
+ struct block *b;
+ b = gen_portrange(cstate, v, v, proto, dir);
+ gen_or(gen_portrange6(cstate, v, v, proto, dir), b);
+ return b;
+ }
+
+ case Q_GATEWAY:
+ bpf_error(cstate, "'gateway' requires a name");
+ /*NOTREACHED*/
+
+ case Q_PROTO:
+ return gen_proto(cstate, v, proto, dir);
+
+ case Q_PROTOCHAIN:
+ return gen_protochain(cstate, v, proto);
+
+ case Q_UNDEF:
+ syntax(cstate);
+ /*NOTREACHED*/
+
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+ /*NOTREACHED*/
+}
+
+#ifdef INET6
+struct block *
+gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
+ bpf_u_int32 masklen, struct qual q)
+{
+ struct addrinfo *res;
+ struct in6_addr *addr;
+ struct in6_addr mask;
+ struct block *b;
+ uint32_t *a, *m;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (s2)
+ bpf_error(cstate, "no mask %s supported", s2);
+
+ res = pcap_nametoaddrinfo(s1);
+ if (!res)
+ bpf_error(cstate, "invalid ip6 address %s", s1);
+ cstate->ai = res;
+ if (res->ai_next)
+ bpf_error(cstate, "%s resolved to multiple address", s1);
+ addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+
+ if (masklen > sizeof(mask.s6_addr) * 8)
+ bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask.s6_addr) * 8));
+ memset(&mask, 0, sizeof(mask));
+ memset(&mask.s6_addr, 0xff, masklen / 8);
+ if (masklen % 8) {
+ mask.s6_addr[masklen / 8] =
+ (0xff << (8 - masklen % 8)) & 0xff;
+ }
+
+ a = (uint32_t *)addr;
+ m = (uint32_t *)&mask;
+ if ((a[0] & ~m[0]) || (a[1] & ~m[1])
+ || (a[2] & ~m[2]) || (a[3] & ~m[3])) {
+ bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
+ }
+
+ switch (q.addr) {
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ if (masklen != 128)
+ bpf_error(cstate, "Mask syntax for networks only");
+ /* FALLTHROUGH */
+
+ case Q_NET:
+ b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr);
+ cstate->ai = NULL;
+ freeaddrinfo(res);
+ return b;
+
+ default:
+ bpf_error(cstate, "invalid qualifier against IPv6 address");
+ /*NOTREACHED*/
+ }
+}
+#endif /*INET6*/
+
+struct block *
+gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
+{
+ struct block *b, *tmp;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+ cstate->e = pcap_ether_aton(s);
+ if (cstate->e == NULL)
+ bpf_error(cstate, "malloc");
+ switch (cstate->linktype) {
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ tmp = gen_prevlinkhdr_check(cstate);
+ b = gen_ehostop(cstate, cstate->e, (int)q.dir);
+ if (tmp != NULL)
+ gen_and(tmp, b);
+ break;
+ case DLT_FDDI:
+ b = gen_fhostop(cstate, cstate->e, (int)q.dir);
+ break;
+ case DLT_IEEE802:
+ b = gen_thostop(cstate, cstate->e, (int)q.dir);
+ break;
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ b = gen_wlanhostop(cstate, cstate->e, (int)q.dir);
+ break;
+ case DLT_IP_OVER_FC:
+ b = gen_ipfchostop(cstate, cstate->e, (int)q.dir);
+ break;
+ default:
+ free(cstate->e);
+ cstate->e = NULL;
+ bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+ /*NOTREACHED*/
+ }
+ free(cstate->e);
+ cstate->e = NULL;
+ return (b);
+ }
+ bpf_error(cstate, "ethernet address used in non-ether expression");
+ /*NOTREACHED*/
+}
+
+void
+sappend(struct slist *s0, struct slist *s1)
+{
+ /*
+ * This is definitely not the best way to do this, but the
+ * lists will rarely get long.
+ */
+ while (s0->next)
+ s0 = s0->next;
+ s0->next = s1;
+}
+
+static struct slist *
+xfer_to_x(compiler_state_t *cstate, struct arth *a)
+{
+ struct slist *s;
+
+ s = new_stmt(cstate, BPF_LDX|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+static struct slist *
+xfer_to_a(compiler_state_t *cstate, struct arth *a)
+{
+ struct slist *s;
+
+ s = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+/*
+ * Modify "index" to use the value stored into its register as an
+ * offset relative to the beginning of the header for the protocol
+ * "proto", and allocate a register and put an item "size" bytes long
+ * (1, 2, or 4) at that offset into that register, making it the register
+ * for "index".
+ */
+static struct arth *
+gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
+ bpf_u_int32 size)
+{
+ int size_code;
+ struct slist *s, *tmp;
+ struct block *b;
+ int regno = alloc_reg(cstate);
+
+ free_reg(cstate, inst->regno);
+ switch (size) {
+
+ default:
+ bpf_error(cstate, "data size must be 1, 2, or 4");
+ /*NOTREACHED*/
+
+ case 1:
+ size_code = BPF_B;
+ break;
+
+ case 2:
+ size_code = BPF_H;
+ break;
+
+ case 4:
+ size_code = BPF_W;
+ break;
+ }
+ switch (proto) {
+ default:
+ bpf_error(cstate, "unsupported index operation");
+
+ case Q_RADIO:
+ /*
+ * The offset is relative to the beginning of the packet
+ * data, if we have a radio header. (If we don't, this
+ * is an error.)
+ */
+ if (cstate->linktype != DLT_IEEE802_11_RADIO_AVS &&
+ cstate->linktype != DLT_IEEE802_11_RADIO &&
+ cstate->linktype != DLT_PRISM_HEADER)
+ bpf_error(cstate, "radio information not present in capture");
+
+ /*
+ * Load into the X register the offset computed into the
+ * register specified by "index".
+ */
+ s = xfer_to_x(cstate, inst);
+
+ /*
+ * Load the item at that offset.
+ */
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+ sappend(s, tmp);
+ sappend(inst->s, s);
+ break;
+
+ case Q_LINK:
+ /*
+ * The offset is relative to the beginning of
+ * the link-layer header.
+ *
+ * XXX - what about ATM LANE? Should the index be
+ * relative to the beginning of the AAL5 frame, so
+ * that 0 refers to the beginning of the LE Control
+ * field, or relative to the beginning of the LAN
+ * frame, so that 0 refers, for Ethernet LANE, to
+ * the beginning of the destination address?
+ */
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr);
+
+ /*
+ * If "s" is non-null, it has code to arrange that the
+ * X register contains the length of the prefix preceding
+ * the link-layer header. Add to it the offset computed
+ * into the register specified by "index", and move that
+ * into the X register. Otherwise, just load into the X
+ * register the offset computed into the register specified
+ * by "index".
+ */
+ if (s != NULL) {
+ sappend(s, xfer_to_a(cstate, inst));
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ } else
+ s = xfer_to_x(cstate, inst);
+
+ /*
+ * Load the item at the sum of the offset we've put in the
+ * X register and the offset of the start of the link
+ * layer header (which is 0 if the radio header is
+ * variable-length; that header length is what we put
+ * into the X register and then added to the index).
+ */
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+ tmp->s.k = cstate->off_linkhdr.constant_part;
+ sappend(s, tmp);
+ sappend(inst->s, s);
+ break;
+
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ case Q_ATALK:
+ case Q_DECNET:
+ case Q_SCA:
+ case Q_LAT:
+ case Q_MOPRC:
+ case Q_MOPDL:
+ case Q_IPV6:
+ /*
+ * The offset is relative to the beginning of
+ * the network-layer header.
+ * XXX - are there any cases where we want
+ * cstate->off_nl_nosnap?
+ */
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+
+ /*
+ * If "s" is non-null, it has code to arrange that the
+ * X register contains the variable part of the offset
+ * of the link-layer payload. Add to it the offset
+ * computed into the register specified by "index",
+ * and move that into the X register. Otherwise, just
+ * load into the X register the offset computed into
+ * the register specified by "index".
+ */
+ if (s != NULL) {
+ sappend(s, xfer_to_a(cstate, inst));
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ } else
+ s = xfer_to_x(cstate, inst);
+
+ /*
+ * Load the item at the sum of the offset we've put in the
+ * X register, the offset of the start of the network
+ * layer header from the beginning of the link-layer
+ * payload, and the constant part of the offset of the
+ * start of the link-layer payload.
+ */
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+ tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ sappend(s, tmp);
+ sappend(inst->s, s);
+
+ /*
+ * Do the computation only if the packet contains
+ * the protocol in question.
+ */
+ b = gen_proto_abbrev_internal(cstate, proto);
+ if (inst->b)
+ gen_and(inst->b, b);
+ inst->b = b;
+ break;
+
+ case Q_SCTP:
+ case Q_TCP:
+ case Q_UDP:
+ case Q_ICMP:
+ case Q_IGMP:
+ case Q_IGRP:
+ case Q_PIM:
+ case Q_VRRP:
+ case Q_CARP:
+ /*
+ * The offset is relative to the beginning of
+ * the transport-layer header.
+ *
+ * Load the X register with the length of the IPv4 header
+ * (plus the offset of the link-layer header, if it's
+ * a variable-length header), in bytes.
+ *
+ * XXX - are there any cases where we want
+ * cstate->off_nl_nosnap?
+ * XXX - we should, if we're built with
+ * IPv6 support, generate code to load either
+ * IPv4, IPv6, or both, as appropriate.
+ */
+ s = gen_loadx_iphdrlen(cstate);
+
+ /*
+ * The X register now contains the sum of the variable
+ * part of the offset of the link-layer payload and the
+ * length of the network-layer header.
+ *
+ * Load into the A register the offset relative to
+ * the beginning of the transport layer header,
+ * add the X register to that, move that to the
+ * X register, and load with an offset from the
+ * X register equal to the sum of the constant part of
+ * the offset of the link-layer payload and the offset,
+ * relative to the beginning of the link-layer payload,
+ * of the network-layer header.
+ */
+ sappend(s, xfer_to_a(cstate, inst));
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code));
+ tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
+ sappend(inst->s, s);
+
+ /*
+ * Do the computation only if the packet contains
+ * the protocol in question - which is true only
+ * if this is an IP datagram and is the first or
+ * only fragment of that datagram.
+ */
+ gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate));
+ if (inst->b)
+ gen_and(inst->b, b);
+ gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b);
+ inst->b = b;
+ break;
+ case Q_ICMPV6:
+ /*
+ * Do the computation only if the packet contains
+ * the protocol in question.
+ */
+ b = gen_proto_abbrev_internal(cstate, Q_IPV6);
+ if (inst->b) {
+ gen_and(inst->b, b);
+ }
+ inst->b = b;
+
+ /*
+ * Check if we have an icmp6 next header
+ */
+ b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58);
+ if (inst->b) {
+ gen_and(inst->b, b);
+ }
+ inst->b = b;
+
+
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+ /*
+ * If "s" is non-null, it has code to arrange that the
+ * X register contains the variable part of the offset
+ * of the link-layer payload. Add to it the offset
+ * computed into the register specified by "index",
+ * and move that into the X register. Otherwise, just
+ * load into the X register the offset computed into
+ * the register specified by "index".
+ */
+ if (s != NULL) {
+ sappend(s, xfer_to_a(cstate, inst));
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ } else {
+ s = xfer_to_x(cstate, inst);
+ }
+
+ /*
+ * Load the item at the sum of the offset we've put in the
+ * X register, the offset of the start of the network
+ * layer header from the beginning of the link-layer
+ * payload, and the constant part of the offset of the
+ * start of the link-layer payload.
+ */
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
+ tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
+
+ sappend(s, tmp);
+ sappend(inst->s, s);
+
+ break;
+ }
+ inst->regno = regno;
+ s = new_stmt(cstate, BPF_ST);
+ s->s.k = regno;
+ sappend(inst->s, s);
+
+ return inst;
+}
+
+struct arth *
+gen_load(compiler_state_t *cstate, int proto, struct arth *inst,
+ bpf_u_int32 size)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_load_internal(cstate, proto, inst, size);
+}
+
+static struct block *
+gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0,
+ struct arth *a1, int reversed)
+{
+ struct slist *s0, *s1, *s2;
+ struct block *b, *tmp;
+
+ s0 = xfer_to_x(cstate, a1);
+ s1 = xfer_to_a(cstate, a0);
+ if (code == BPF_JEQ) {
+ s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X);
+ b = new_block(cstate, JMP(code));
+ sappend(s1, s2);
+ }
+ else
+ b = new_block(cstate, BPF_JMP|code|BPF_X);
+ if (reversed)
+ gen_not(b);
+
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ b->stmts = a0->s;
+
+ free_reg(cstate, a0->regno);
+ free_reg(cstate, a1->regno);
+
+ /* 'and' together protocol checks */
+ if (a0->b) {
+ if (a1->b) {
+ gen_and(a0->b, tmp = a1->b);
+ }
+ else
+ tmp = a0->b;
+ } else
+ tmp = a1->b;
+
+ if (tmp)
+ gen_and(tmp, b);
+
+ return b;
+}
+
+struct block *
+gen_relation(compiler_state_t *cstate, int code, struct arth *a0,
+ struct arth *a1, int reversed)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_relation_internal(cstate, code, a0, a1, reversed);
+}
+
+struct arth *
+gen_loadlen(compiler_state_t *cstate)
+{
+ int regno;
+ struct arth *a;
+ struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ regno = alloc_reg(cstate);
+ a = (struct arth *)newchunk(cstate, sizeof(*a));
+ s = new_stmt(cstate, BPF_LD|BPF_LEN);
+ s->next = new_stmt(cstate, BPF_ST);
+ s->next->s.k = regno;
+ a->s = s;
+ a->regno = regno;
+
+ return a;
+}
+
+static struct arth *
+gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val)
+{
+ struct arth *a;
+ struct slist *s;
+ int reg;
+
+ a = (struct arth *)newchunk(cstate, sizeof(*a));
+
+ reg = alloc_reg(cstate);
+
+ s = new_stmt(cstate, BPF_LD|BPF_IMM);
+ s->s.k = val;
+ s->next = new_stmt(cstate, BPF_ST);
+ s->next->s.k = reg;
+ a->s = s;
+ a->regno = reg;
+
+ return a;
+}
+
+struct arth *
+gen_loadi(compiler_state_t *cstate, bpf_u_int32 val)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_loadi_internal(cstate, val);
+}
+
+/*
+ * The a_arg dance is to avoid annoying whining by compilers that
+ * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct arth *
+gen_neg(compiler_state_t *cstate, struct arth *a_arg)
+{
+ struct arth *a = a_arg;
+ struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ s = xfer_to_a(cstate, a);
+ sappend(a->s, s);
+ s = new_stmt(cstate, BPF_ALU|BPF_NEG);
+ s->s.k = 0;
+ sappend(a->s, s);
+ s = new_stmt(cstate, BPF_ST);
+ s->s.k = a->regno;
+ sappend(a->s, s);
+
+ return a;
+}
+
+/*
+ * The a0_arg dance is to avoid annoying whining by compilers that
+ * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct arth *
+gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg,
+ struct arth *a1)
+{
+ struct arth *a0 = a0_arg;
+ struct slist *s0, *s1, *s2;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Disallow division by, or modulus by, zero; we do this here
+ * so that it gets done even if the optimizer is disabled.
+ *
+ * Also disallow shifts by a value greater than 31; we do this
+ * here, for the same reason.
+ */
+ if (code == BPF_DIV) {
+ if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+ bpf_error(cstate, "division by zero");
+ } else if (code == BPF_MOD) {
+ if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+ bpf_error(cstate, "modulus by zero");
+ } else if (code == BPF_LSH || code == BPF_RSH) {
+ if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31)
+ bpf_error(cstate, "shift by more than 31 bits");
+ }
+ s0 = xfer_to_x(cstate, a1);
+ s1 = xfer_to_a(cstate, a0);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_X|code);
+
+ sappend(s1, s2);
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ free_reg(cstate, a0->regno);
+ free_reg(cstate, a1->regno);
+
+ s0 = new_stmt(cstate, BPF_ST);
+ a0->regno = s0->s.k = alloc_reg(cstate);
+ sappend(a0->s, s0);
+
+ return a0;
+}
+
+/*
+ * Initialize the table of used registers and the current register.
+ */
+static void
+init_regs(compiler_state_t *cstate)
+{
+ cstate->curreg = 0;
+ memset(cstate->regused, 0, sizeof cstate->regused);
+}
+
+/*
+ * Return the next free register.
+ */
+static int
+alloc_reg(compiler_state_t *cstate)
+{
+ int n = BPF_MEMWORDS;
+
+ while (--n >= 0) {
+ if (cstate->regused[cstate->curreg])
+ cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS;
+ else {
+ cstate->regused[cstate->curreg] = 1;
+ return cstate->curreg;
+ }
+ }
+ bpf_error(cstate, "too many registers needed to evaluate expression");
+ /*NOTREACHED*/
+}
+
+/*
+ * Return a register to the table so it can
+ * be used later.
+ */
+static void
+free_reg(compiler_state_t *cstate, int n)
+{
+ cstate->regused[n] = 0;
+}
+
+static struct block *
+gen_len(compiler_state_t *cstate, int jmp, int n)
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(cstate, BPF_LD|BPF_LEN);
+ b = new_block(cstate, JMP(jmp));
+ b->stmts = s;
+ b->s.k = n;
+
+ return b;
+}
+
+struct block *
+gen_greater(compiler_state_t *cstate, int n)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_len(cstate, BPF_JGE, n);
+}
+
+/*
+ * Actually, this is less than or equal.
+ */
+struct block *
+gen_less(compiler_state_t *cstate, int n)
+{
+ struct block *b;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ b = gen_len(cstate, BPF_JGT, n);
+ gen_not(b);
+
+ return b;
+}
+
+/*
+ * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to
+ * the beginning of the link-layer header.
+ * XXX - that means you can't test values in the radiotap header, but
+ * as that header is difficult if not impossible to parse generally
+ * without a loop, that might not be a severe problem. A new keyword
+ * "radio" could be added for that, although what you'd really want
+ * would be a way of testing particular radio header values, which
+ * would generate code appropriate to the radio header in question.
+ */
+struct block *
+gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
+{
+ struct block *b;
+ struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (op) {
+ default:
+ abort();
+
+ case '=':
+ return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+
+ case '<':
+ b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+ return b;
+
+ case '>':
+ b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
+ return b;
+
+ case '|':
+ s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K);
+ break;
+
+ case '&':
+ s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+ break;
+ }
+ s->s.k = val;
+ b = new_block(cstate, JMP(BPF_JEQ));
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+static const u_char abroadcast[] = { 0x0 };
+
+struct block *
+gen_broadcast(compiler_state_t *cstate, int proto)
+{
+ bpf_u_int32 hostmask;
+ struct block *b0, *b1, *b2;
+ static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ switch (cstate->linktype) {
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ return gen_ahostop(cstate, abroadcast, Q_DST);
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check(cstate);
+ b0 = gen_ehostop(cstate, ebroadcast, Q_DST);
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ return b0;
+ case DLT_FDDI:
+ return gen_fhostop(cstate, ebroadcast, Q_DST);
+ case DLT_IEEE802:
+ return gen_thostop(cstate, ebroadcast, Q_DST);
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ return gen_wlanhostop(cstate, ebroadcast, Q_DST);
+ case DLT_IP_OVER_FC:
+ return gen_ipfchostop(cstate, ebroadcast, Q_DST);
+ default:
+ bpf_error(cstate, "not a broadcast link");
+ }
+ /*NOTREACHED*/
+
+ case Q_IP:
+ /*
+ * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff)
+ * as an indication that we don't know the netmask, and fail
+ * in that case.
+ */
+ if (cstate->netmask == PCAP_NETMASK_UNKNOWN)
+ bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported");
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+ hostmask = ~cstate->netmask;
+ b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask);
+ b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W,
+ ~0 & hostmask, hostmask);
+ gen_or(b1, b2);
+ gen_and(b0, b2);
+ return b2;
+ }
+ bpf_error(cstate, "only link-layer/IP broadcast filters supported");
+ /*NOTREACHED*/
+}
+
+/*
+ * Generate code to test the low-order bit of a MAC address (that's
+ * the bottom bit of the *first* byte).
+ */
+static struct block *
+gen_mac_multicast(compiler_state_t *cstate, int offset)
+{
+ register struct block *b0;
+ register struct slist *s;
+
+ /* link[offset] & 1 != 0 */
+ s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B);
+ b0 = new_block(cstate, JMP(BPF_JSET));
+ b0->s.k = 1;
+ b0->stmts = s;
+ return b0;
+}
+
+struct block *
+gen_multicast(compiler_state_t *cstate, int proto)
+{
+ register struct block *b0, *b1, *b2;
+ register struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ switch (cstate->linktype) {
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ /* all ARCnet multicasts use the same address */
+ return gen_ahostop(cstate, abroadcast, Q_DST);
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check(cstate);
+ /* ether[0] & 1 != 0 */
+ b0 = gen_mac_multicast(cstate, 0);
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ return b0;
+ case DLT_FDDI:
+ /*
+ * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
+ *
+ * XXX - was that referring to bit-order issues?
+ */
+ /* fddi[1] & 1 != 0 */
+ return gen_mac_multicast(cstate, 1);
+ case DLT_IEEE802:
+ /* tr[2] & 1 != 0 */
+ return gen_mac_multicast(cstate, 2);
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ /*
+ * Oh, yuk.
+ *
+ * For control frames, there is no DA.
+ *
+ * For management frames, DA is at an
+ * offset of 4 from the beginning of
+ * the packet.
+ *
+ * For data frames, DA is at an offset
+ * of 4 from the beginning of the packet
+ * if To DS is clear and at an offset of
+ * 16 from the beginning of the packet
+ * if To DS is set.
+ */
+
+ /*
+ * Generate the tests to be done for data frames.
+ *
+ * First, check for To DS set, i.e. "link[1] & 0x01".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x01; /* To DS */
+ b1->stmts = s;
+
+ /*
+ * If To DS is set, the DA is at 16.
+ */
+ b0 = gen_mac_multicast(cstate, 16);
+ gen_and(b1, b0);
+
+ /*
+ * Now, check for To DS not set, i.e. check
+ * "!(link[1] & 0x01)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x01; /* To DS */
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * If To DS is not set, the DA is at 4.
+ */
+ b1 = gen_mac_multicast(cstate, 4);
+ gen_and(b2, b1);
+
+ /*
+ * Now OR together the last two checks. That gives
+ * the complete set of checks for data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * Now check for a data frame.
+ * I.e, check "link[0] & 0x08".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x08;
+ b1->stmts = s;
+
+ /*
+ * AND that with the checks done for data frames.
+ */
+ gen_and(b1, b0);
+
+ /*
+ * If the high-order bit of the type value is 0, this
+ * is a management frame.
+ * I.e, check "!(link[0] & 0x08)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b2 = new_block(cstate, JMP(BPF_JSET));
+ b2->s.k = 0x08;
+ b2->stmts = s;
+ gen_not(b2);
+
+ /*
+ * For management frames, the DA is at 4.
+ */
+ b1 = gen_mac_multicast(cstate, 4);
+ gen_and(b2, b1);
+
+ /*
+ * OR that with the checks done for data frames.
+ * That gives the checks done for management and
+ * data frames.
+ */
+ gen_or(b1, b0);
+
+ /*
+ * If the low-order bit of the type value is 1,
+ * this is either a control frame or a frame
+ * with a reserved type, and thus not a
+ * frame with an SA.
+ *
+ * I.e., check "!(link[0] & 0x04)".
+ */
+ s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B);
+ b1 = new_block(cstate, JMP(BPF_JSET));
+ b1->s.k = 0x04;
+ b1->stmts = s;
+ gen_not(b1);
+
+ /*
+ * AND that with the checks for data and management
+ * frames.
+ */
+ gen_and(b1, b0);
+ return b0;
+ case DLT_IP_OVER_FC:
+ b0 = gen_mac_multicast(cstate, 2);
+ return b0;
+ default:
+ break;
+ }
+ /* Link not known to support multicasts */
+ break;
+
+ case Q_IP:
+ b0 = gen_linktype(cstate, ETHERTYPE_IP);
+ b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_IPV6:
+ b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
+ b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255);
+ gen_and(b0, b1);
+ return b1;
+ }
+ bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_ifindex(compiler_state_t *cstate, int ifindex)
+{
+ register struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Only some data link types support ifindex qualifiers.
+ */
+ switch (cstate->linktype) {
+ case DLT_LINUX_SLL2:
+ /* match packets on this interface */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
+ break;
+ default:
+#if defined(linux)
+ /*
+ * This is Linux; we require PF_PACKET support.
+ * If this is a *live* capture, we can look at
+ * special meta-data in the filter expression;
+ * if it's a savefile, we can't.
+ */
+ if (cstate->bpf_pcap->rfile != NULL) {
+ /* We have a FILE *, so this is a savefile */
+ bpf_error(cstate, "ifindex not supported on %s when reading savefiles",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ b0 = NULL;
+ /*NOTREACHED*/
+ }
+ /* match ifindex */
+ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
+ ifindex);
+#else /* defined(linux) */
+ bpf_error(cstate, "ifindex not supported on %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+#endif /* defined(linux) */
+ }
+ return (b0);
+}
+
+/*
+ * Filter on inbound (dir == 0) or outbound (dir == 1) traffic.
+ * Outbound traffic is sent by this machine, while inbound traffic is
+ * sent by a remote machine (and may include packets destined for a
+ * unicast or multicast link-layer address we are not subscribing to).
+ * These are the same definitions implemented by pcap_setdirection().
+ * Capturing only unicast traffic destined for this host is probably
+ * better accomplished using a higher-layer filter.
+ */
+struct block *
+gen_inbound(compiler_state_t *cstate, int dir)
+{
+ register struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Only some data link types support inbound/outbound qualifiers.
+ */
+ switch (cstate->linktype) {
+ case DLT_SLIP:
+ b0 = gen_relation_internal(cstate, BPF_JEQ,
+ gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1),
+ gen_loadi_internal(cstate, 0),
+ dir);
+ break;
+
+ case DLT_IPNET:
+ if (dir) {
+ /* match outgoing packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND);
+ } else {
+ /* match incoming packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND);
+ }
+ break;
+
+ case DLT_LINUX_SLL:
+ /* match outgoing packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING);
+ if (!dir) {
+ /* to filter on inbound traffic, invert the match */
+ gen_not(b0);
+ }
+ break;
+
+ case DLT_LINUX_SLL2:
+ /* match outgoing packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING);
+ if (!dir) {
+ /* to filter on inbound traffic, invert the match */
+ gen_not(b0);
+ }
+ break;
+
+#ifdef HAVE_NET_PFVAR_H
+ case DLT_PFLOG:
+ b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
+ ((dir == 0) ? PF_IN : PF_OUT));
+ break;
+#endif
+
+ case DLT_PPP_PPPD:
+ if (dir) {
+ /* match outgoing packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT);
+ } else {
+ /* match incoming packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN);
+ }
+ break;
+
+ case DLT_JUNIPER_MFR:
+ case DLT_JUNIPER_MLFR:
+ case DLT_JUNIPER_MLPPP:
+ case DLT_JUNIPER_ATM1:
+ case DLT_JUNIPER_ATM2:
+ case DLT_JUNIPER_PPPOE:
+ case DLT_JUNIPER_PPPOE_ATM:
+ case DLT_JUNIPER_GGSN:
+ case DLT_JUNIPER_ES:
+ case DLT_JUNIPER_MONITOR:
+ case DLT_JUNIPER_SERVICES:
+ case DLT_JUNIPER_ETHER:
+ case DLT_JUNIPER_PPP:
+ case DLT_JUNIPER_FRELAY:
+ case DLT_JUNIPER_CHDLC:
+ case DLT_JUNIPER_VP:
+ case DLT_JUNIPER_ST:
+ case DLT_JUNIPER_ISM:
+ case DLT_JUNIPER_VS:
+ case DLT_JUNIPER_SRX_E2E:
+ case DLT_JUNIPER_FIBRECHANNEL:
+ case DLT_JUNIPER_ATM_CEMIC:
+
+ /* juniper flags (including direction) are stored
+ * the byte after the 3-byte magic number */
+ if (dir) {
+ /* match outgoing packets */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01);
+ } else {
+ /* match incoming packets */
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01);
+ }
+ break;
+
+ default:
+ /*
+ * If we have packet meta-data indicating a direction,
+ * and that metadata can be checked by BPF code, check
+ * it. Otherwise, give up, as this link-layer type has
+ * nothing in the packet data.
+ *
+ * Currently, the only platform where a BPF filter can
+ * check that metadata is Linux with the in-kernel
+ * BPF interpreter. If other packet capture mechanisms
+ * and BPF filters also supported this, it would be
+ * nice. It would be even better if they made that
+ * metadata available so that we could provide it
+ * with newer capture APIs, allowing it to be saved
+ * in pcapng files.
+ */
+#if defined(linux)
+ /*
+ * This is Linux; we require PF_PACKET support.
+ * If this is a *live* capture, we can look at
+ * special meta-data in the filter expression;
+ * if it's a savefile, we can't.
+ */
+ if (cstate->bpf_pcap->rfile != NULL) {
+ /* We have a FILE *, so this is a savefile */
+ bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+ }
+ /* match outgoing packets */
+ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H,
+ PACKET_OUTGOING);
+ if (!dir) {
+ /* to filter on inbound traffic, invert the match */
+ gen_not(b0);
+ }
+#else /* defined(linux) */
+ bpf_error(cstate, "inbound/outbound not supported on %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+#endif /* defined(linux) */
+ }
+ return (b0);
+}
+
+#ifdef HAVE_NET_PFVAR_H
+/* PF firewall log matched interface */
+struct block *
+gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
+{
+ struct block *b0;
+ u_int len, off;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "ifname supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+ len = sizeof(((struct pfloghdr *)0)->ifname);
+ off = offsetof(struct pfloghdr, ifname);
+ if (strlen(ifname) >= len) {
+ bpf_error(cstate, "ifname interface names can only be %d characters",
+ len-1);
+ /*NOTREACHED*/
+ }
+ b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname),
+ (const u_char *)ifname);
+ return (b0);
+}
+
+/* PF firewall log ruleset name */
+struct block *
+gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "ruleset supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+
+ if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
+ bpf_error(cstate, "ruleset names can only be %ld characters",
+ (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1));
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
+ (u_int)strlen(ruleset), (const u_char *)ruleset);
+ return (b0);
+}
+
+/* PF firewall log rule number */
+struct block *
+gen_pf_rnr(compiler_state_t *cstate, int rnr)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "rnr supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
+ (bpf_u_int32)rnr);
+ return (b0);
+}
+
+/* PF firewall log sub-rule number */
+struct block *
+gen_pf_srnr(compiler_state_t *cstate, int srnr)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "srnr supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
+ (bpf_u_int32)srnr);
+ return (b0);
+}
+
+/* PF firewall log reason code */
+struct block *
+gen_pf_reason(compiler_state_t *cstate, int reason)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "reason supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
+ (bpf_u_int32)reason);
+ return (b0);
+}
+
+/* PF firewall log action */
+struct block *
+gen_pf_action(compiler_state_t *cstate, int action)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->linktype != DLT_PFLOG) {
+ bpf_error(cstate, "action supported only on PF linktype");
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
+ (bpf_u_int32)action);
+ return (b0);
+}
+#else /* !HAVE_NET_PFVAR_H */
+struct block *
+gen_pf_ifname(compiler_state_t *cstate, const char *ifname _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled without pf support");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_pf_ruleset(compiler_state_t *cstate, char *ruleset _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_pf_rnr(compiler_state_t *cstate, int rnr _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_pf_srnr(compiler_state_t *cstate, int srnr _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_pf_reason(compiler_state_t *cstate, int reason _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+ /*NOTREACHED*/
+}
+
+struct block *
+gen_pf_action(compiler_state_t *cstate, int action _U_)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ bpf_error(cstate, "libpcap was compiled on a machine without pf support");
+ /*NOTREACHED*/
+}
+#endif /* HAVE_NET_PFVAR_H */
+
+/* IEEE 802.11 wireless header */
+struct block *
+gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (cstate->linktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
+ break;
+
+ default:
+ bpf_error(cstate, "802.11 link-layer types supported only on 802.11");
+ /*NOTREACHED*/
+ }
+
+ return (b0);
+}
+
+struct block *
+gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (cstate->linktype) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ break;
+
+ default:
+ bpf_error(cstate, "frame direction supported only with 802.11 headers");
+ /*NOTREACHED*/
+ }
+
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
+ IEEE80211_FC1_DIR_MASK);
+
+ return (b0);
+}
+
+struct block *
+gen_acode(compiler_state_t *cstate, const char *s, struct qual q)
+{
+ struct block *b;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (cstate->linktype) {
+
+ case DLT_ARCNET:
+ case DLT_ARCNET_LINUX:
+ if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) &&
+ q.proto == Q_LINK) {
+ cstate->e = pcap_ether_aton(s);
+ if (cstate->e == NULL)
+ bpf_error(cstate, "malloc");
+ b = gen_ahostop(cstate, cstate->e, (int)q.dir);
+ free(cstate->e);
+ cstate->e = NULL;
+ return (b);
+ } else
+ bpf_error(cstate, "ARCnet address used in non-arc expression");
+ /*NOTREACHED*/
+
+ default:
+ bpf_error(cstate, "aid supported only on ARCnet");
+ /*NOTREACHED*/
+ }
+}
+
+static struct block *
+gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
+{
+ register struct block *b0, *b1;
+
+ switch (dir) {
+ /* src comes first, different from Ethernet */
+ case Q_SRC:
+ return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr);
+
+ case Q_AND:
+ b0 = gen_ahostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ahostop(cstate, eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_ahostop(cstate, eaddr, Q_SRC);
+ b1 = gen_ahostop(cstate, eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is only supported on 802.11");
+ /*NOTREACHED*/
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is only supported on 802.11");
+ /*NOTREACHED*/
+ }
+ abort();
+ /*NOTREACHED*/
+}
+
+static struct block *
+gen_vlan_tpid_test(compiler_state_t *cstate)
+{
+ 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);
+
+ return b1;
+}
+
+static struct block *
+gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num)
+{
+ if (vlan_num > 0x0fff) {
+ bpf_error(cstate, "VLAN tag %u greater than maximum %u",
+ vlan_num, 0x0fff);
+ }
+ return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
+}
+
+static struct block *
+gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+ int has_vlan_tag)
+{
+ struct block *b0, *b1;
+
+ b0 = gen_vlan_tpid_test(cstate);
+
+ if (has_vlan_tag) {
+ b1 = gen_vlan_vid_test(cstate, vlan_num);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ /*
+ * Both payload and link header type follow the VLAN tags so that
+ * both need to be updated.
+ */
+ cstate->off_linkpl.constant_part += 4;
+ cstate->off_linktype.constant_part += 4;
+
+ return b0;
+}
+
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+/* add v to variable part of off */
+static void
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off,
+ bpf_u_int32 v, struct slist *s)
+{
+ struct slist *s2;
+
+ if (!off->is_variable)
+ off->is_variable = 1;
+ if (off->reg == -1)
+ off->reg = alloc_reg(cstate);
+
+ s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s2->s.k = off->reg;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = v;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = off->reg;
+ sappend(s, s2);
+}
+
+/*
+ * patch block b_tpid (VLAN TPID test) to update variable parts of link payload
+ * and link type offsets first
+ */
+static void
+gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid)
+{
+ struct slist s;
+
+ /* offset determined at run time, shift variable part */
+ s.next = NULL;
+ cstate->is_vlan_vloffset = 1;
+ gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s);
+ gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s);
+
+ /* we get a pointer to a chain of or-ed blocks, patch first of them */
+ sappend(s.next, b_tpid->head->stmts);
+ b_tpid->head->stmts = s.next;
+}
+
+/*
+ * patch block b_vid (VLAN id test) to load VID value either from packet
+ * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true
+ */
+static void
+gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
+{
+ struct slist *s, *s2, *sjeq;
+ unsigned cnt;
+
+ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+ /* true -> next instructions, false -> beginning of b_vid */
+ sjeq = new_stmt(cstate, JMP(BPF_JEQ));
+ sjeq->s.k = 1;
+ sjeq->s.jf = b_vid->stmts;
+ sappend(s, sjeq);
+
+ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+ sappend(s, s2);
+ sjeq->s.jt = s2;
+
+ /* Jump to the test in b_vid. We need to jump one instruction before
+ * the end of the b_vid block so that we only skip loading the TCI
+ * from packet data and not the 'and' instruction extractging VID.
+ */
+ cnt = 0;
+ for (s2 = b_vid->stmts; s2; s2 = s2->next)
+ cnt++;
+ s2 = new_stmt(cstate, JMP(BPF_JA));
+ s2->s.k = cnt - 1;
+ sappend(s, s2);
+
+ /* insert our statements at the beginning of b_vid */
+ sappend(s, b_vid->stmts);
+ b_vid->stmts = s;
+}
+
+/*
+ * Generate check for "vlan" or "vlan <id>" on systems with support for BPF
+ * extensions. Even if kernel supports VLAN BPF extensions, (outermost) VLAN
+ * tag can be either in metadata or in packet data; therefore if the
+ * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link
+ * header for VLAN tag. As the decision is done at run time, we need
+ * update variable part of the offsets
+ */
+static struct block *
+gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
+ int has_vlan_tag)
+{
+ struct block *b0, *b_tpid, *b_vid = NULL;
+ struct slist *s;
+
+ /* generate new filter code based on extracting packet
+ * metadata */
+ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+ b0 = new_block(cstate, JMP(BPF_JEQ));
+ b0->stmts = s;
+ b0->s.k = 1;
+
+ /*
+ * This is tricky. We need to insert the statements updating variable
+ * parts of offsets before the traditional TPID and VID tests so
+ * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
+ * we do not want this update to affect those checks. That's why we
+ * generate both test blocks first and insert the statements updating
+ * variable parts of both offsets after that. This wouldn't work if
+ * there already were variable length link header when entering this
+ * function but gen_vlan_bpf_extensions() isn't called in that case.
+ */
+ b_tpid = gen_vlan_tpid_test(cstate);
+ if (has_vlan_tag)
+ b_vid = gen_vlan_vid_test(cstate, vlan_num);
+
+ gen_vlan_patch_tpid_test(cstate, b_tpid);
+ gen_or(b0, b_tpid);
+ b0 = b_tpid;
+
+ if (has_vlan_tag) {
+ gen_vlan_patch_vid_test(cstate, b_vid);
+ gen_and(b0, b_vid);
+ b0 = b_vid;
+ }
+
+ return b0;
+}
+#endif
+
+/*
+ * support IEEE 802.1Q VLAN trunk over ethernet
+ */
+struct block *
+gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag)
+{
+ struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /* can't check for VLAN-encapsulated packets inside MPLS */
+ if (cstate->label_stack_depth > 0)
+ bpf_error(cstate, "no VLAN match after MPLS");
+
+ /*
+ * Check for a VLAN packet, and then change the offsets to point
+ * to the type and data fields within the VLAN packet. Just
+ * increment the offsets, so that we can support a hierarchy, e.g.
+ * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within
+ * VLAN 100.
+ *
+ * XXX - this is a bit of a kludge. If we were to split the
+ * compiler into a parser that parses an expression and
+ * generates an expression tree, and a code generator that
+ * takes an expression tree (which could come from our
+ * parser or from some other parser) and generates BPF code,
+ * we could perhaps make the offsets parameters of routines
+ * and, in the handler for an "AND" node, pass to subnodes
+ * other than the VLAN node the adjusted offsets.
+ *
+ * This would mean that "vlan" would, instead of changing the
+ * behavior of *all* tests after it, change only the behavior
+ * of tests ANDed with it. That would change the documented
+ * semantics of "vlan", which might break some expressions.
+ * However, it would mean that "(vlan and ip) or ip" would check
+ * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than
+ * checking only for VLAN-encapsulated IP, so that could still
+ * be considered worth doing; it wouldn't break expressions
+ * that are of the form "vlan and ..." or "vlan N and ...",
+ * which I suspect are the most common expressions involving
+ * "vlan". "vlan or ..." doesn't necessarily do what the user
+ * would really want, now, as all the "or ..." tests would
+ * be done assuming a VLAN, even though the "or" could be viewed
+ * as meaning "or, if this isn't a VLAN packet...".
+ */
+ switch (cstate->linktype) {
+
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+ /* Verify that this is the outer part of the packet and
+ * not encapsulated somehow. */
+ if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable &&
+ cstate->off_linkhdr.constant_part ==
+ cstate->off_outermostlinkhdr.constant_part) {
+ /*
+ * Do we need special VLAN handling?
+ */
+ if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING)
+ b0 = gen_vlan_bpf_extensions(cstate, vlan_num,
+ has_vlan_tag);
+ else
+ b0 = gen_vlan_no_bpf_extensions(cstate,
+ vlan_num, has_vlan_tag);
+ } else
+#endif
+ b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num,
+ has_vlan_tag);
+ break;
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag);
+ break;
+
+ default:
+ bpf_error(cstate, "no VLAN support for %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+ }
+
+ cstate->vlan_stack_depth++;
+
+ return (b0);
+}
+
+/*
+ * support for MPLS
+ *
+ * The label_num_arg dance is to avoid annoying whining by compilers that
+ * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct block *
+gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg,
+ int has_label_num)
+{
+ volatile bpf_u_int32 label_num = label_num_arg;
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ if (cstate->label_stack_depth > 0) {
+ /* just match the bottom-of-stack bit clear */
+ b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01);
+ } else {
+ /*
+ * We're not in an MPLS stack yet, so check the link-layer
+ * type against MPLS.
+ */
+ switch (cstate->linktype) {
+
+ case DLT_C_HDLC: /* fall through */
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ b0 = gen_linktype(cstate, ETHERTYPE_MPLS);
+ break;
+
+ case DLT_PPP:
+ b0 = gen_linktype(cstate, PPP_MPLS_UCAST);
+ break;
+
+ /* FIXME add other DLT_s ...
+ * for Frame-Relay/and ATM this may get messy due to SNAP headers
+ * leave it for now */
+
+ default:
+ bpf_error(cstate, "no MPLS support for %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+ }
+ }
+
+ /* If a specific MPLS label is requested, check it */
+ if (has_label_num) {
+ if (label_num > 0xFFFFF) {
+ bpf_error(cstate, "MPLS label %u greater than maximum %u",
+ label_num, 0xFFFFF);
+ }
+ label_num = label_num << 12; /* label is shifted 12 bits on the wire */
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
+ 0xfffff000); /* only compare the first 20 bits */
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ /*
+ * Change the offsets to point to the type and data fields within
+ * the MPLS packet. Just increment the offsets, so that we
+ * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to
+ * capture packets with an outer label of 100000 and an inner
+ * label of 1024.
+ *
+ * Increment the MPLS stack depth as well; this indicates that
+ * we're checking MPLS-encapsulated headers, to make sure higher
+ * level code generators don't try to match against IP-related
+ * protocols such as Q_ARP, Q_RARP etc.
+ *
+ * XXX - this is a bit of a kludge. See comments in gen_vlan().
+ */
+ cstate->off_nl_nosnap += 4;
+ cstate->off_nl += 4;
+ cstate->label_stack_depth++;
+ return (b0);
+}
+
+/*
+ * Support PPPOE discovery and session.
+ */
+struct block *
+gen_pppoed(compiler_state_t *cstate)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /* check for PPPoE discovery */
+ return gen_linktype(cstate, ETHERTYPE_PPPOED);
+}
+
+struct block *
+gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Test against the PPPoE session link-layer type.
+ */
+ b0 = gen_linktype(cstate, ETHERTYPE_PPPOES);
+
+ /* If a specific session is requested, check PPPoE session id */
+ if (has_sess_num) {
+ if (sess_num > 0x0000ffff) {
+ bpf_error(cstate, "PPPoE session number %u greater than maximum %u",
+ sess_num, 0x0000ffff);
+ }
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ /*
+ * Change the offsets to point to the type and data fields within
+ * the PPP packet, and note that this is PPPoE rather than
+ * raw PPP.
+ *
+ * XXX - this is a bit of a kludge. See the comments in
+ * gen_vlan().
+ *
+ * The "network-layer" protocol is PPPoE, which has a 6-byte
+ * PPPoE header, followed by a PPP packet.
+ *
+ * There is no HDLC encapsulation for the PPP packet (it's
+ * encapsulated in PPPoES instead), so the link-layer type
+ * starts at the first byte of the PPP packet. For PPPoE,
+ * that offset is relative to the beginning of the total
+ * link-layer payload, including any 802.2 LLC header, so
+ * it's 6 bytes past cstate->off_nl.
+ */
+ PUSH_LINKHDR(cstate, DLT_PPP, cstate->off_linkpl.is_variable,
+ cstate->off_linkpl.constant_part + cstate->off_nl + 6, /* 6 bytes past the PPPoE header */
+ cstate->off_linkpl.reg);
+
+ cstate->off_linktype = cstate->off_linkhdr;
+ cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 2;
+
+ cstate->off_nl = 0;
+ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
+
+ return b0;
+}
+
+/* Check that this is Geneve and the VNI is correct if
+ * specified. Parameterized to handle both IPv4 and IPv6. */
+static struct block *
+gen_geneve_check(compiler_state_t *cstate,
+ struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int),
+ enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
+{
+ struct block *b0, *b1;
+
+ b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST);
+
+ /* Check that we are operating on version 0. Otherwise, we
+ * can't decode the rest of the fields. The version is 2 bits
+ * in the first byte of the Geneve header. */
+ b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0);
+ gen_and(b0, b1);
+ b0 = b1;
+
+ if (has_vni) {
+ if (vni > 0xffffff) {
+ bpf_error(cstate, "Geneve VNI %u greater than maximum %u",
+ vni, 0xffffff);
+ }
+ vni <<= 8; /* VNI is in the upper 3 bytes */
+ b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ return b0;
+}
+
+/* The IPv4 and IPv6 Geneve checks need to do two things:
+ * - Verify that this actually is Geneve with the right VNI.
+ * - Place the IP header length (plus variable link prefix if
+ * needed) into register A to be used later to compute
+ * the inner packet offsets. */
+static struct block *
+gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+ struct block *b0, *b1;
+ struct slist *s, *s1;
+
+ b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni);
+
+ /* Load the IP header length into A. */
+ s = gen_loadx_iphdrlen(cstate);
+
+ s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+ sappend(s, s1);
+
+ /* Forcibly append these statements to the true condition
+ * of the protocol check by creating a new block that is
+ * always true and ANDing them. */
+ b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+ b1->stmts = s;
+ b1->s.k = 0;
+
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+ struct block *b0, *b1;
+ struct slist *s, *s1;
+
+ b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni);
+
+ /* Load the IP header length. We need to account for a
+ * variable length link prefix if there is one. */
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+ if (s) {
+ s1 = new_stmt(cstate, BPF_LD|BPF_IMM);
+ s1->s.k = 40;
+ sappend(s, s1);
+
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+ s1->s.k = 0;
+ sappend(s, s1);
+ } else {
+ s = new_stmt(cstate, BPF_LD|BPF_IMM);
+ s->s.k = 40;
+ }
+
+ /* Forcibly append these statements to the true condition
+ * of the protocol check by creating a new block that is
+ * always true and ANDing them. */
+ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s, s1);
+
+ b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+ b1->stmts = s;
+ b1->s.k = 0;
+
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+/* We need to store three values based on the Geneve header::
+ * - The offset of the linktype.
+ * - The offset of the end of the Geneve header.
+ * - The offset of the end of the encapsulated MAC header. */
+static struct slist *
+gen_geneve_offsets(compiler_state_t *cstate)
+{
+ struct slist *s, *s1, *s_proto;
+
+ /* First we need to calculate the offset of the Geneve header
+ * itself. This is composed of the IP header previously calculated
+ * (include any variable link prefix) and stored in A plus the
+ * fixed sized headers (fixed link prefix, MAC length, and UDP
+ * header). */
+ s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8;
+
+ /* Stash this in X since we'll need it later. */
+ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s, s1);
+
+ /* The EtherType in Geneve is 2 bytes in. Calculate this and
+ * store it. */
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s1->s.k = 2;
+ sappend(s, s1);
+
+ cstate->off_linktype.reg = alloc_reg(cstate);
+ cstate->off_linktype.is_variable = 1;
+ cstate->off_linktype.constant_part = 0;
+
+ s1 = new_stmt(cstate, BPF_ST);
+ s1->s.k = cstate->off_linktype.reg;
+ sappend(s, s1);
+
+ /* Load the Geneve option length and mask and shift to get the
+ * number of bytes. It is stored in the first byte of the Geneve
+ * header. */
+ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
+ s1->s.k = 0;
+ sappend(s, s1);
+
+ s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+ s1->s.k = 0x3f;
+ sappend(s, s1);
+
+ s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K);
+ s1->s.k = 4;
+ sappend(s, s1);
+
+ /* Add in the rest of the Geneve base header. */
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s1->s.k = 8;
+ sappend(s, s1);
+
+ /* Add the Geneve header length to its offset and store. */
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
+ s1->s.k = 0;
+ sappend(s, s1);
+
+ /* Set the encapsulated type as Ethernet. Even though we may
+ * not actually have Ethernet inside there are two reasons this
+ * is useful:
+ * - The linktype field is always in EtherType format regardless
+ * of whether it is in Geneve or an inner Ethernet frame.
+ * - The only link layer that we have specific support for is
+ * Ethernet. We will confirm that the packet actually is
+ * Ethernet at runtime before executing these checks. */
+ PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate));
+
+ s1 = new_stmt(cstate, BPF_ST);
+ s1->s.k = cstate->off_linkhdr.reg;
+ sappend(s, s1);
+
+ /* Calculate whether we have an Ethernet header or just raw IP/
+ * MPLS/etc. If we have Ethernet, advance the end of the MAC offset
+ * and linktype by 14 bytes so that the network header can be found
+ * seamlessly. Otherwise, keep what we've calculated already. */
+
+ /* We have a bare jmp so we can't use the optimizer. */
+ cstate->no_optimize = 1;
+
+ /* Load the EtherType in the Geneve header, 2 bytes in. */
+ s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H);
+ s1->s.k = 2;
+ sappend(s, s1);
+
+ /* Load X with the end of the Geneve header. */
+ s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
+ s1->s.k = cstate->off_linkhdr.reg;
+ sappend(s, s1);
+
+ /* Check if the EtherType is Transparent Ethernet Bridging. At the
+ * end of this check, we should have the total length in X. In
+ * the non-Ethernet case, it's already there. */
+ s_proto = new_stmt(cstate, JMP(BPF_JEQ));
+ s_proto->s.k = ETHERTYPE_TEB;
+ sappend(s, s_proto);
+
+ s1 = new_stmt(cstate, BPF_MISC|BPF_TXA);
+ sappend(s, s1);
+ s_proto->s.jt = s1;
+
+ /* Since this is Ethernet, use the EtherType of the payload
+ * directly as the linktype. Overwrite what we already have. */
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s1->s.k = 12;
+ sappend(s, s1);
+
+ s1 = new_stmt(cstate, BPF_ST);
+ s1->s.k = cstate->off_linktype.reg;
+ sappend(s, s1);
+
+ /* Advance two bytes further to get the end of the Ethernet
+ * header. */
+ s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
+ s1->s.k = 2;
+ sappend(s, s1);
+
+ /* Move the result to X. */
+ s1 = new_stmt(cstate, BPF_MISC|BPF_TAX);
+ sappend(s, s1);
+
+ /* Store the final result of our linkpl calculation. */
+ cstate->off_linkpl.reg = alloc_reg(cstate);
+ cstate->off_linkpl.is_variable = 1;
+ cstate->off_linkpl.constant_part = 0;
+
+ s1 = new_stmt(cstate, BPF_STX);
+ s1->s.k = cstate->off_linkpl.reg;
+ sappend(s, s1);
+ s_proto->s.jf = s1;
+
+ cstate->off_nl = 0;
+
+ return s;
+}
+
+/* Check to see if this is a Geneve packet. */
+struct block *
+gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
+{
+ struct block *b0, *b1;
+ struct slist *s;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ b0 = gen_geneve4(cstate, vni, has_vni);
+ b1 = gen_geneve6(cstate, vni, has_vni);
+
+ gen_or(b0, b1);
+ b0 = b1;
+
+ /* Later filters should act on the payload of the Geneve frame,
+ * update all of the header pointers. Attach this code so that
+ * it gets executed in the event that the Geneve filter matches. */
+ s = gen_geneve_offsets(cstate);
+
+ b1 = gen_true(cstate);
+ sappend(s, b1->stmts);
+ b1->stmts = s;
+
+ gen_and(b0, b1);
+
+ cstate->is_geneve = 1;
+
+ return b1;
+}
+
+/* Check that the encapsulated frame has a link layer header
+ * for Ethernet filters. */
+static struct block *
+gen_geneve_ll_check(compiler_state_t *cstate)
+{
+ struct block *b0;
+ struct slist *s, *s1;
+
+ /* The easiest way to see if there is a link layer present
+ * is to check if the link layer header and payload are not
+ * the same. */
+
+ /* Geneve always generates pure variable offsets so we can
+ * compare only the registers. */
+ s = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s->s.k = cstate->off_linkhdr.reg;
+
+ s1 = new_stmt(cstate, BPF_LDX|BPF_MEM);
+ s1->s.k = cstate->off_linkpl.reg;
+ sappend(s, s1);
+
+ b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X);
+ b0->stmts = s;
+ b0->s.k = 0;
+ gen_not(b0);
+
+ return b0;
+}
+
+static struct block *
+gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
+ bpf_u_int32 jvalue, int jtype, int reverse)
+{
+ struct block *b0;
+
+ switch (atmfield) {
+
+ case A_VPI:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'vpi' supported only on raw ATM");
+ if (cstate->off_vpi == OFFSET_NOT_SET)
+ abort();
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+ 0xffffffffU, jtype, reverse, jvalue);
+ break;
+
+ case A_VCI:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'vci' supported only on raw ATM");
+ if (cstate->off_vci == OFFSET_NOT_SET)
+ abort();
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
+ 0xffffffffU, jtype, reverse, jvalue);
+ break;
+
+ case A_PROTOTYPE:
+ if (cstate->off_proto == OFFSET_NOT_SET)
+ abort(); /* XXX - this isn't on FreeBSD */
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+ 0x0fU, jtype, reverse, jvalue);
+ break;
+
+ case A_MSGTYPE:
+ if (cstate->off_payload == OFFSET_NOT_SET)
+ abort();
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
+ 0xffffffffU, jtype, reverse, jvalue);
+ break;
+
+ case A_CALLREFTYPE:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'callref' supported only on raw ATM");
+ if (cstate->off_proto == OFFSET_NOT_SET)
+ abort();
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+ 0xffffffffU, jtype, reverse, jvalue);
+ break;
+
+ default:
+ abort();
+ }
+ return b0;
+}
+
+static struct block *
+gen_atmtype_metac(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_atmtype_sc(compiler_state_t *cstate)
+{
+ struct block *b0, *b1;
+
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_atmtype_llc(compiler_state_t *cstate)
+{
+ struct block *b0;
+
+ b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+ cstate->linktype = cstate->prevlinktype;
+ return b0;
+}
+
+struct block *
+gen_atmfield_code(compiler_state_t *cstate, int atmfield,
+ bpf_u_int32 jvalue, int jtype, int reverse)
+{
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype,
+ reverse);
+}
+
+struct block *
+gen_atmtype_abbrev(compiler_state_t *cstate, int type)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (type) {
+
+ case A_METAC:
+ /* Get all packets in Meta signalling Circuit */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'metac' supported only on raw ATM");
+ b1 = gen_atmtype_metac(cstate);
+ break;
+
+ case A_BCC:
+ /* Get all packets in Broadcast Circuit*/
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'bcc' supported only on raw ATM");
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_OAMF4SC:
+ /* Get all cells in Segment OAM F4 circuit*/
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'oam4sc' supported only on raw ATM");
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_OAMF4EC:
+ /* Get all cells in End-to-End OAM F4 Circuit*/
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'oam4ec' supported only on raw ATM");
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_SC:
+ /* Get all packets in connection Signalling Circuit */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'sc' supported only on raw ATM");
+ b1 = gen_atmtype_sc(cstate);
+ break;
+
+ case A_ILMIC:
+ /* Get all packets in ILMI Circuit */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'ilmic' supported only on raw ATM");
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_LANE:
+ /* Get all LANE packets */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'lane' supported only on raw ATM");
+ b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0);
+
+ /*
+ * Arrange that all subsequent tests assume LANE
+ * rather than LLC-encapsulated packets, and set
+ * the offsets appropriately for LANE-encapsulated
+ * Ethernet.
+ *
+ * We assume LANE means Ethernet, not Token Ring.
+ */
+ PUSH_LINKHDR(cstate, DLT_EN10MB, 0,
+ cstate->off_payload + 2, /* Ethernet header */
+ -1);
+ cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
+ cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* Ethernet */
+ cstate->off_nl = 0; /* Ethernet II */
+ cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
+ break;
+
+ case A_LLC:
+ /* Get all LLC-encapsulated packets */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'llc' supported only on raw ATM");
+ b1 = gen_atmtype_llc(cstate);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+/*
+ * Filtering for MTP2 messages based on li value
+ * FISU, length is null
+ * LSSU, length is 1 or 2
+ * MSU, length is 3 or more
+ * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits
+ */
+struct block *
+gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (type) {
+
+ case M_FISU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'fisu' supported only on MTP2");
+ /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JEQ, 0, 0U);
+ break;
+
+ case M_LSSU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'lssu' supported only on MTP2");
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 1, 2U);
+ b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 0, 0U);
+ gen_and(b1, b0);
+ break;
+
+ case M_MSU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'msu' supported only on MTP2");
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 0, 2U);
+ break;
+
+ case MH_FISU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'hfisu' supported only on MTP2_HSL");
+ /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JEQ, 0, 0U);
+ break;
+
+ case MH_LSSU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'hlssu' supported only on MTP2_HSL");
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 1, 0x0100U);
+ b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 0, 0U);
+ gen_and(b1, b0);
+ break;
+
+ case MH_MSU:
+ if ( (cstate->linktype != DLT_MTP2) &&
+ (cstate->linktype != DLT_ERF) &&
+ (cstate->linktype != DLT_MTP2_WITH_PHDR) )
+ bpf_error(cstate, "'hmsu' supported only on MTP2_HSL");
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 0, 0x0100U);
+ break;
+
+ default:
+ abort();
+ }
+ return b0;
+}
+
+/*
+ * The jvalue_arg dance is to avoid annoying whining by compilers that
+ * jvalue might be clobbered by longjmp - yeah, it might, but *WHO CARES*?
+ * It's not *used* after setjmp returns.
+ */
+struct block *
+gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
+ bpf_u_int32 jvalue_arg, int jtype, int reverse)
+{
+ volatile bpf_u_int32 jvalue = jvalue_arg;
+ struct block *b0;
+ bpf_u_int32 val1 , val2 , val3;
+ u_int newoff_sio;
+ u_int newoff_opc;
+ u_int newoff_dpc;
+ u_int newoff_sls;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ newoff_sio = cstate->off_sio;
+ newoff_opc = cstate->off_opc;
+ newoff_dpc = cstate->off_dpc;
+ newoff_sls = cstate->off_sls;
+ switch (mtp3field) {
+
+ case MH_SIO:
+ newoff_sio += 3; /* offset for MTP2_HSL */
+ /* FALLTHROUGH */
+
+ case M_SIO:
+ if (cstate->off_sio == OFFSET_NOT_SET)
+ bpf_error(cstate, "'sio' supported only on SS7");
+ /* sio coded on 1 byte so max value 255 */
+ if(jvalue > 255)
+ bpf_error(cstate, "sio value %u too big; max value = 255",
+ jvalue);
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU,
+ jtype, reverse, jvalue);
+ break;
+
+ case MH_OPC:
+ newoff_opc += 3;
+
+ /* FALLTHROUGH */
+ case M_OPC:
+ if (cstate->off_opc == OFFSET_NOT_SET)
+ bpf_error(cstate, "'opc' supported only on SS7");
+ /* opc coded on 14 bits so max value 16383 */
+ if (jvalue > 16383)
+ bpf_error(cstate, "opc value %u too big; max value = 16383",
+ jvalue);
+ /* the following instructions are made to convert jvalue
+ * to the form used to write opc in an ss7 message*/
+ val1 = jvalue & 0x00003c00;
+ val1 = val1 >>10;
+ val2 = jvalue & 0x000003fc;
+ val2 = val2 <<6;
+ val3 = jvalue & 0x00000003;
+ val3 = val3 <<22;
+ jvalue = val1 + val2 + val3;
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU,
+ jtype, reverse, jvalue);
+ break;
+
+ case MH_DPC:
+ newoff_dpc += 3;
+ /* FALLTHROUGH */
+
+ case M_DPC:
+ if (cstate->off_dpc == OFFSET_NOT_SET)
+ bpf_error(cstate, "'dpc' supported only on SS7");
+ /* dpc coded on 14 bits so max value 16383 */
+ if (jvalue > 16383)
+ bpf_error(cstate, "dpc value %u too big; max value = 16383",
+ jvalue);
+ /* the following instructions are made to convert jvalue
+ * to the forme used to write dpc in an ss7 message*/
+ val1 = jvalue & 0x000000ff;
+ val1 = val1 << 24;
+ val2 = jvalue & 0x00003f00;
+ val2 = val2 << 8;
+ jvalue = val1 + val2;
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U,
+ jtype, reverse, jvalue);
+ break;
+
+ case MH_SLS:
+ newoff_sls += 3;
+ /* FALLTHROUGH */
+
+ case M_SLS:
+ if (cstate->off_sls == OFFSET_NOT_SET)
+ bpf_error(cstate, "'sls' supported only on SS7");
+ /* sls coded on 4 bits so max value 15 */
+ if (jvalue > 15)
+ bpf_error(cstate, "sls value %u too big; max value = 15",
+ jvalue);
+ /* the following instruction is made to convert jvalue
+ * to the forme used to write sls in an ss7 message*/
+ jvalue = jvalue << 4;
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U,
+ jtype, reverse, jvalue);
+ break;
+
+ default:
+ abort();
+ }
+ return b0;
+}
+
+static struct block *
+gen_msg_abbrev(compiler_state_t *cstate, int type)
+{
+ struct block *b1;
+
+ /*
+ * Q.2931 signalling protocol messages for handling virtual circuits
+ * establishment and teardown
+ */
+ switch (type) {
+
+ case A_SETUP:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0);
+ break;
+
+ case A_CALLPROCEED:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0);
+ break;
+
+ case A_CONNECT:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0);
+ break;
+
+ case A_CONNECTACK:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0);
+ break;
+
+ case A_RELEASE:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0);
+ break;
+
+ case A_RELEASE_DONE:
+ b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+struct block *
+gen_atmmulti_abbrev(compiler_state_t *cstate, int type)
+{
+ struct block *b0, *b1;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ switch (type) {
+
+ case A_OAM:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'oam' supported only on raw ATM");
+ /* OAM F4 type */
+ b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+ gen_or(b0, b1);
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_OAMF4:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'oamf4' supported only on raw ATM");
+ /* OAM F4 type */
+ b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0);
+ b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0);
+ gen_or(b0, b1);
+ b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_CONNECTMSG:
+ /*
+ * Get Q.2931 signalling messages for switched
+ * virtual connection
+ */
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'connectmsg' supported only on raw ATM");
+ b0 = gen_msg_abbrev(cstate, A_SETUP);
+ b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_CONNECT);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_CONNECTACK);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_RELEASE);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+ gen_or(b0, b1);
+ b0 = gen_atmtype_sc(cstate);
+ gen_and(b0, b1);
+ break;
+
+ case A_METACONNECT:
+ if (!cstate->is_atm)
+ bpf_error(cstate, "'metaconnect' supported only on raw ATM");
+ b0 = gen_msg_abbrev(cstate, A_SETUP);
+ b1 = gen_msg_abbrev(cstate, A_CALLPROCEED);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_CONNECT);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_RELEASE);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE);
+ gen_or(b0, b1);
+ b0 = gen_atmtype_metac(cstate);
+ gen_and(b0, b1);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}
diff --git a/gencode.h b/gencode.h
new file mode 100644
index 0000000..053e85f
--- /dev/null
+++ b/gencode.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1990, 1991, 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.
+ */
+
+#include "pcap/funcattrs.h"
+
+/*
+ * ATM support:
+ *
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * 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 Yen Yen Lim and
+ * North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Address qualifiers. */
+
+#define Q_HOST 1
+#define Q_NET 2
+#define Q_PORT 3
+#define Q_GATEWAY 4
+#define Q_PROTO 5
+#define Q_PROTOCHAIN 6
+#define Q_PORTRANGE 7
+
+/* Protocol qualifiers. */
+
+#define Q_LINK 1
+#define Q_IP 2
+#define Q_ARP 3
+#define Q_RARP 4
+#define Q_SCTP 5
+#define Q_TCP 6
+#define Q_UDP 7
+#define Q_ICMP 8
+#define Q_IGMP 9
+#define Q_IGRP 10
+
+
+#define Q_ATALK 11
+#define Q_DECNET 12
+#define Q_LAT 13
+#define Q_SCA 14
+#define Q_MOPRC 15
+#define Q_MOPDL 16
+
+
+#define Q_IPV6 17
+#define Q_ICMPV6 18
+#define Q_AH 19
+#define Q_ESP 20
+
+#define Q_PIM 21
+#define Q_VRRP 22
+
+#define Q_AARP 23
+
+#define Q_ISO 24
+#define Q_ESIS 25
+#define Q_ISIS 26
+#define Q_CLNP 27
+
+#define Q_STP 28
+
+#define Q_IPX 29
+
+#define Q_NETBEUI 30
+
+/* IS-IS Levels */
+#define Q_ISIS_L1 31
+#define Q_ISIS_L2 32
+/* PDU types */
+#define Q_ISIS_IIH 33
+#define Q_ISIS_SNP 34
+#define Q_ISIS_CSNP 35
+#define Q_ISIS_PSNP 36
+#define Q_ISIS_LSP 37
+
+#define Q_RADIO 38
+
+#define Q_CARP 39
+
+/* Directional qualifiers. */
+
+#define Q_SRC 1
+#define Q_DST 2
+#define Q_OR 3
+#define Q_AND 4
+#define Q_ADDR1 5
+#define Q_ADDR2 6
+#define Q_ADDR3 7
+#define Q_ADDR4 8
+#define Q_RA 9
+#define Q_TA 10
+
+#define Q_DEFAULT 0
+#define Q_UNDEF 255
+
+/* ATM types */
+#define A_METAC 22 /* Meta signalling Circuit */
+#define A_BCC 23 /* Broadcast Circuit */
+#define A_OAMF4SC 24 /* Segment OAM F4 Circuit */
+#define A_OAMF4EC 25 /* End-to-End OAM F4 Circuit */
+#define A_SC 26 /* Signalling Circuit*/
+#define A_ILMIC 27 /* ILMI Circuit */
+#define A_OAM 28 /* OAM cells : F4 only */
+#define A_OAMF4 29 /* OAM F4 cells: Segment + End-to-end */
+#define A_LANE 30 /* LANE traffic */
+#define A_LLC 31 /* LLC-encapsulated traffic */
+
+/* Based on Q.2931 signalling protocol */
+#define A_SETUP 41 /* Setup message */
+#define A_CALLPROCEED 42 /* Call proceeding message */
+#define A_CONNECT 43 /* Connect message */
+#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
+#define A_PROTOTYPE 53
+#define A_MSGTYPE 54
+#define A_CALLREFTYPE 55
+
+#define A_CONNECTMSG 70 /* returns Q.2931 signalling messages for
+ establishing and destroying switched
+ virtual connection */
+#define A_METACONNECT 71 /* returns Q.2931 signalling messages for
+ establishing and destroying predefined
+ virtual circuits, such as broadcast
+ circuit, oamf4 segment circuit, oamf4
+ end-to-end circuits, ILMI circuits or
+ connection signalling circuit. */
+
+/* MTP2 types */
+#define M_FISU 22 /* FISU */
+#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;
+
+/*
+ * A single statement, corresponding to an instruction in a block.
+ */
+struct stmt {
+ int code; /* opcode */
+ struct slist *jt; /* only for relative jump in block */
+ struct slist *jf; /* only for relative jump in block */
+ bpf_u_int32 k; /* k field */
+};
+
+struct slist {
+ struct stmt s;
+ struct slist *next;
+};
+
+/*
+ * A bit vector to represent definition sets. We assume TOT_REGISTERS
+ * is smaller than 8*sizeof(atomset).
+ */
+typedef bpf_u_int32 atomset;
+#define ATOMMASK(n) (1 << (n))
+#define ATOMELEM(d, n) (d & ATOMMASK(n))
+
+/*
+ * An unbounded set.
+ */
+typedef bpf_u_int32 *uset;
+
+/*
+ * Total number of atomic entities, including accumulator (A) and index (X).
+ * We treat all these guys similarly during flow analysis.
+ */
+#define N_ATOMS (BPF_MEMWORDS+2)
+
+/*
+ * Control flow graph of a program.
+ * This corresponds to an edge in the CFG.
+ * It's a directed graph, so an edge has a predecessor and a successor.
+ */
+struct edge {
+ u_int id;
+ int code; /* opcode for branch corresponding to this edge */
+ uset edom;
+ struct block *succ; /* successor vertex */
+ struct block *pred; /* predecessor vertex */
+ struct edge *next; /* link list of incoming edges for a node */
+};
+
+/*
+ * A block is a vertex in the CFG.
+ * It has a list of statements, with the final statement being a
+ * branch to successor blocks.
+ */
+struct block {
+ u_int id;
+ struct slist *stmts; /* side effect stmts */
+ struct stmt s; /* branch stmt */
+ int mark;
+ u_int longjt; /* jt branch requires long jump */
+ u_int longjf; /* jf branch requires long jump */
+ int level;
+ int offset;
+ int sense;
+ struct edge et; /* edge corresponding to the jt branch */
+ struct edge ef; /* edge corresponding to the jf branch */
+ struct block *head;
+ struct block *link; /* link field used by optimizer */
+ uset dom;
+ uset closure;
+ struct edge *in_edges; /* first edge in the set (linked list) of edges with this as a successor */
+ atomset def, kill;
+ atomset in_use;
+ atomset out_use;
+ int oval; /* value ID for value tested in branch stmt */
+ bpf_u_int32 val[N_ATOMS];
+};
+
+/*
+ * A value of 0 for val[i] means the value is unknown.
+ */
+#define VAL_UNKNOWN 0
+
+struct arth {
+ struct block *b; /* protocol checks */
+ struct slist *s; /* stmt list */
+ int regno; /* virtual register number of result */
+};
+
+struct qual {
+ unsigned char addr;
+ unsigned char proto;
+ unsigned char dir;
+ unsigned char pad;
+};
+
+struct _compiler_state;
+
+typedef struct _compiler_state compiler_state_t;
+
+struct arth *gen_loadi(compiler_state_t *, bpf_u_int32);
+struct arth *gen_load(compiler_state_t *, int, struct arth *, bpf_u_int32);
+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(compiler_state_t *, const char *, struct qual);
+struct block *gen_ecode(compiler_state_t *, const char *, struct qual);
+struct block *gen_acode(compiler_state_t *, const char *, struct qual);
+struct block *gen_mcode(compiler_state_t *, const char *, const char *,
+ bpf_u_int32, struct qual);
+#ifdef INET6
+struct block *gen_mcode6(compiler_state_t *, const char *, const char *,
+ bpf_u_int32, struct qual);
+#endif
+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, bpf_u_int32);
+struct block *gen_broadcast(compiler_state_t *, int);
+struct block *gen_multicast(compiler_state_t *, int);
+struct block *gen_ifindex(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 *, bpf_u_int32, int);
+struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_pppoed(compiler_state_t *);
+struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int);
+
+struct block *gen_atmfield_code(compiler_state_t *, int, bpf_u_int32,
+ int, int);
+struct block *gen_atmtype_abbrev(compiler_state_t *, int);
+struct block *gen_atmmulti_abbrev(compiler_state_t *, int);
+
+struct block *gen_mtp2type_abbrev(compiler_state_t *, int);
+struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32,
+ int, 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 *, bpf_u_int32, bpf_u_int32);
+struct block *gen_p80211_fcdir(compiler_state_t *, bpf_u_int32);
+
+/*
+ * 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;
+};
+
+int bpf_optimize(struct icode *, char *);
+void bpf_set_error(compiler_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
+
+int finish_parse(compiler_state_t *, struct block *);
+char *sdup(compiler_state_t *, const char *);
+
+struct bpf_insn *icode_to_fcode(struct icode *, struct block *, u_int *,
+ char *);
+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)
diff --git a/grammar.y.in b/grammar.y.in
new file mode 100644
index 0000000..2fbd861
--- /dev/null
+++ b/grammar.y.in
@@ -0,0 +1,843 @@
+/*
+ * We want a reentrant parser.
+ */
+@REENTRANT_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}
+
+/*
+ * According to bison documentation, shift/reduce conflicts are not an issue
+ * in most parsers as long as the number does not evolve over time:
+ * https://www.gnu.org/software/bison/manual/html_node/Expect-Decl.html
+ * So, following the advice use %expect to check the amount of shift/reduce
+ * warnings.
+ *
+ * This doesn't appear to work in Berkeley YACC - 1.9 20170709; it still
+ * warns of 38 shift/reduce conflicts.
+ *
+ * The Berkeley YACC documentation:
+ *
+ * https://invisible-island.net/byacc/manpage/yacc.html
+ *
+ * claims that "Bison's support for "%expect" is broken in more than one
+ * release.", but doesn't give details. Hopefully, that only means that
+ * you get warnings even if you have the expected number of shift/reduce
+ * conflicts, not that anything else fails.
+ */
+%expect 38
+
+/*
+ * 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
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* _WIN32 */
+
+#include <stdio.h>
+
+#include "diag-control.h"
+
+#include "pcap-int.h"
+
+#include "gencode.h"
+#include "grammar.h"
+#include "scanner.h"
+
+#ifdef HAVE_NET_PFVAR_H
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pflog.h>
+#endif
+#include "llc.h"
+#include "ieee80211.h"
+#include <pcap/namedb.h>
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef YYBYACC
+/*
+ * Both Berkeley YACC and Bison define yydebug (under whatever name
+ * it has) as a global, but Bison does so only if YYDEBUG is defined.
+ * Berkeley YACC define it even if YYDEBUG isn't defined; declare it
+ * here to suppress a warning.
+ */
+#if !defined(YYDEBUG)
+extern int yydebug;
+#endif
+
+/*
+ * In Berkeley YACC, yynerrs (under whatever name it has) is global,
+ * even if it's building a reentrant parser. In Bison, it's local
+ * in reentrant parsers.
+ *
+ * Declare it to squelch a warning.
+ */
+extern int yynerrs;
+#endif
+
+#define QSET(q, p, d, a) (q).proto = (unsigned char)(p),\
+ (q).dir = (unsigned char)(d),\
+ (q).addr = (unsigned char)(a)
+
+struct tok {
+ int v; /* value */
+ const char *s; /* string */
+};
+
+static const struct tok ieee80211_types[] = {
+ { IEEE80211_FC0_TYPE_DATA, "data" },
+ { IEEE80211_FC0_TYPE_MGT, "mgt" },
+ { IEEE80211_FC0_TYPE_MGT, "management" },
+ { IEEE80211_FC0_TYPE_CTL, "ctl" },
+ { IEEE80211_FC0_TYPE_CTL, "control" },
+ { 0, NULL }
+};
+static const struct tok ieee80211_mgt_subtypes[] = {
+ { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" },
+ { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" },
+ { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" },
+ { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" },
+ { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" },
+ { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" },
+ { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" },
+ { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" },
+ { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" },
+ { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" },
+ { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" },
+ { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" },
+ { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" },
+ { IEEE80211_FC0_SUBTYPE_ATIM, "atim" },
+ { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" },
+ { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" },
+ { IEEE80211_FC0_SUBTYPE_AUTH, "auth" },
+ { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" },
+ { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" },
+ { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" },
+ { 0, NULL }
+};
+static const struct tok ieee80211_ctl_subtypes[] = {
+ { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" },
+ { IEEE80211_FC0_SUBTYPE_RTS, "rts" },
+ { IEEE80211_FC0_SUBTYPE_CTS, "cts" },
+ { IEEE80211_FC0_SUBTYPE_ACK, "ack" },
+ { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" },
+ { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" },
+ { 0, NULL }
+};
+static const struct tok ieee80211_data_subtypes[] = {
+ { IEEE80211_FC0_SUBTYPE_DATA, "data" },
+ { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" },
+ { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" },
+ { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" },
+ { IEEE80211_FC0_SUBTYPE_NODATA, "null" },
+ { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" },
+ { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll" },
+ { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" },
+ { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" },
+ { 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;
+};
+static const struct type2tok ieee80211_type_subtypes[] = {
+ { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes },
+ { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes },
+ { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes },
+ { 0, NULL }
+};
+
+static int
+str2tok(const char *str, const struct tok *toks)
+{
+ int i;
+
+ for (i = 0; toks[i].s != NULL; i++) {
+ if (pcap_strcasecmp(toks[i].s, str) == 0) {
+ /*
+ * Just in case somebody is using this to
+ * generate values of -1/0xFFFFFFFF.
+ * That won't work, as it's indistinguishable
+ * from an error.
+ */
+ if (toks[i].v == -1)
+ abort();
+ return (toks[i].v);
+ }
+ }
+ return (-1);
+}
+
+static const struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
+
+static void
+yyerror(void *yyscanner _U_, compiler_state_t *cstate, const char *msg)
+{
+ bpf_set_error(cstate, "can't parse filter expression: %s", msg);
+}
+
+#ifdef HAVE_NET_PFVAR_H
+static int
+pfreason_to_num(compiler_state_t *cstate, const char *reason)
+{
+ const char *reasons[] = PFRES_NAMES;
+ int i;
+
+ for (i = 0; reasons[i]; i++) {
+ if (pcap_strcasecmp(reason, reasons[i]) == 0)
+ return (i);
+ }
+ bpf_set_error(cstate, "unknown PF reason \"%s\"", reason);
+ return (-1);
+}
+
+static int
+pfaction_to_num(compiler_state_t *cstate, const char *action)
+{
+ if (pcap_strcasecmp(action, "pass") == 0 ||
+ pcap_strcasecmp(action, "accept") == 0)
+ return (PF_PASS);
+ else if (pcap_strcasecmp(action, "drop") == 0 ||
+ pcap_strcasecmp(action, "block") == 0)
+ return (PF_DROP);
+#if HAVE_PF_NAT_THROUGH_PF_NORDR
+ else if (pcap_strcasecmp(action, "rdr") == 0)
+ return (PF_RDR);
+ else if (pcap_strcasecmp(action, "nat") == 0)
+ return (PF_NAT);
+ else if (pcap_strcasecmp(action, "binat") == 0)
+ return (PF_BINAT);
+ else if (pcap_strcasecmp(action, "nordr") == 0)
+ return (PF_NORDR);
+#endif
+ else {
+ bpf_set_error(cstate, "unknown PF action \"%s\"", action);
+ return (-1);
+ }
+}
+#else /* !HAVE_NET_PFVAR_H */
+static int
+pfreason_to_num(compiler_state_t *cstate, const char *reason _U_)
+{
+ bpf_set_error(cstate, "libpcap was compiled on a machine without pf support");
+ return (-1);
+}
+
+static int
+pfaction_to_num(compiler_state_t *cstate, const char *action _U_)
+{
+ bpf_set_error(cstate, "libpcap was compiled on a machine without pf support");
+ return (-1);
+}
+#endif /* HAVE_NET_PFVAR_H */
+
+/*
+ * For calls that might return an "an error occurred" value.
+ */
+#define CHECK_INT_VAL(val) if (val == -1) YYABORT
+#define CHECK_PTR_VAL(val) if (val == NULL) YYABORT
+
+DIAG_OFF_BISON_BYACC
+%}
+
+%union {
+ int i;
+ bpf_u_int32 h;
+ char *s;
+ struct stmt *stmt;
+ struct arth *a;
+ struct {
+ struct qual q;
+ int atmfieldtype;
+ int mtp3fieldtype;
+ struct block *b;
+ } blk;
+ struct block *rblk;
+}
+
+%type <blk> expr id nid pid term rterm qid
+%type <blk> head
+%type <i> pqual dqual aqual ndaqual
+%type <a> arth narth
+%type <i> byteop pname relop irelop
+%type <h> pnum
+%type <blk> and or paren not null prog
+%type <rblk> other pfvar p80211 pllc
+%type <i> atmtype atmmultitype
+%type <blk> atmfield
+%type <blk> atmfieldvalue atmvalue atmlistvalue
+%type <i> mtp2type
+%type <blk> mtp3field
+%type <blk> mtp3fieldvalue mtp3value mtp3listvalue
+
+
+%token DST SRC HOST GATEWAY
+%token NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE
+%token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP CARP
+%token ATALK AARP DECNET LAT SCA MOPRC MOPDL
+%token TK_BROADCAST TK_MULTICAST
+%token NUM INBOUND OUTBOUND
+%token IFINDEX
+%token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION
+%token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA
+%token LINK
+%token GEQ LEQ NEQ
+%token ID EID HID HID6 AID
+%token LSH RSH
+%token LEN
+%token IPV6 ICMPV6 AH ESP
+%token VLAN MPLS
+%token PPPOED PPPOES GENEVE
+%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP
+%token STP
+%token IPX
+%token NETBEUI
+%token LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC
+%token OAM OAMF4 CONNECTMSG METACONNECT
+%token VPI VCI
+%token RADIO
+%token FISU LSSU MSU HFISU HLSSU HMSU
+%token SIO OPC DPC SLS HSIO HOPC HDPC HSLS
+%token LEX_ERROR
+
+%type <s> ID EID AID
+%type <s> HID HID6
+%type <h> NUM
+%type <i> action reason type subtype type_subtype dir
+
+%left OR AND
+%nonassoc '!'
+%left '|'
+%left '&'
+%left LSH RSH
+%left '+' '-'
+%left '*' '/'
+%nonassoc UMINUS
+%%
+prog: null expr
+{
+ CHECK_INT_VAL(finish_parse(cstate, $2.b));
+}
+ | null
+ ;
+null: /* null */ { $$.q = qerr; }
+ ;
+expr: term
+ | expr and term { gen_and($1.b, $3.b); $$ = $3; }
+ | expr and id { gen_and($1.b, $3.b); $$ = $3; }
+ | expr or term { gen_or($1.b, $3.b); $$ = $3; }
+ | expr or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+and: AND { $$ = $<blk>0; }
+ ;
+or: OR { $$ = $<blk>0; }
+ ;
+id: nid
+ | pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
+ $$.q = $<blk>0.q))); }
+ | paren pid ')' { $$ = $2; }
+ ;
+nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.q = $<blk>0.q))); }
+ | HID '/' NUM { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3,
+ $$.q = $<blk>0.q))); }
+ | HID NETMASK HID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0,
+ $$.q = $<blk>0.q))); }
+ | HID {
+ CHECK_PTR_VAL($1);
+ /* Decide how to parse HID based on proto */
+ $$.q = $<blk>0.q;
+ if ($$.q.addr == Q_PORT) {
+ bpf_set_error(cstate, "'port' modifier applied to ip host");
+ YYABORT;
+ } else if ($$.q.addr == Q_PORTRANGE) {
+ bpf_set_error(cstate, "'portrange' modifier applied to ip host");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTO) {
+ bpf_set_error(cstate, "'proto' modifier applied to ip host");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTOCHAIN) {
+ bpf_set_error(cstate, "'protochain' modifier applied to ip host");
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q)));
+ }
+ | HID6 '/' NUM {
+ CHECK_PTR_VAL($1);
+#ifdef INET6
+ CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, NULL, $3,
+ $$.q = $<blk>0.q)));
+#else
+ bpf_set_error(cstate, "'ip6addr/prefixlen' not supported "
+ "in this configuration");
+ YYABORT;
+#endif /*INET6*/
+ }
+ | HID6 {
+ CHECK_PTR_VAL($1);
+#ifdef INET6
+ CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 0, 128,
+ $$.q = $<blk>0.q)));
+#else
+ bpf_set_error(cstate, "'ip6addr' not supported "
+ "in this configuration");
+ YYABORT;
+#endif /*INET6*/
+ }
+ | EID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_ecode(cstate, $1, $$.q = $<blk>0.q))); }
+ | AID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_acode(cstate, $1, $$.q = $<blk>0.q))); }
+ | not id { gen_not($2.b); $$ = $2; }
+ ;
+not: '!' { $$ = $<blk>0; }
+ ;
+paren: '(' { $$ = $<blk>0; }
+ ;
+pid: nid
+ | qid and id { gen_and($1.b, $3.b); $$ = $3; }
+ | qid or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+qid: pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
+ $$.q = $<blk>0.q))); }
+ | pid
+ ;
+term: rterm
+ | not term { gen_not($2.b); $$ = $2; }
+ ;
+head: pqual dqual aqual { QSET($$.q, $1, $2, $3); }
+ | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); }
+ | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
+ | pqual PROTOCHAIN {
+#ifdef NO_PROTOCHAIN
+ bpf_set_error(cstate, "protochain not supported");
+ YYABORT;
+#else
+ QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN);
+#endif
+ }
+ | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ ;
+rterm: head id { $$ = $2; }
+ | paren expr ')' { $$.b = $2.b; $$.q = $1.q; }
+ | pname { CHECK_PTR_VAL(($$.b = gen_proto_abbrev(cstate, $1))); $$.q = qerr; }
+ | arth relop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 0)));
+ $$.q = qerr; }
+ | arth irelop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 1)));
+ $$.q = qerr; }
+ | other { $$.b = $1; $$.q = qerr; }
+ | atmtype { CHECK_PTR_VAL(($$.b = gen_atmtype_abbrev(cstate, $1))); $$.q = qerr; }
+ | atmmultitype { CHECK_PTR_VAL(($$.b = gen_atmmulti_abbrev(cstate, $1))); $$.q = qerr; }
+ | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; }
+ | mtp2type { CHECK_PTR_VAL(($$.b = gen_mtp2type_abbrev(cstate, $1))); $$.q = qerr; }
+ | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; }
+ ;
+/* protocol level qualifiers */
+pqual: pname
+ | { $$ = Q_DEFAULT; }
+ ;
+/* 'direction' qualifiers */
+dqual: SRC { $$ = Q_SRC; }
+ | DST { $$ = Q_DST; }
+ | SRC OR DST { $$ = Q_OR; }
+ | DST OR SRC { $$ = Q_OR; }
+ | SRC AND DST { $$ = Q_AND; }
+ | DST AND SRC { $$ = Q_AND; }
+ | ADDR1 { $$ = Q_ADDR1; }
+ | ADDR2 { $$ = Q_ADDR2; }
+ | ADDR3 { $$ = Q_ADDR3; }
+ | ADDR4 { $$ = Q_ADDR4; }
+ | RA { $$ = Q_RA; }
+ | TA { $$ = Q_TA; }
+ ;
+/* address type qualifiers */
+aqual: HOST { $$ = Q_HOST; }
+ | NET { $$ = Q_NET; }
+ | PORT { $$ = Q_PORT; }
+ | PORTRANGE { $$ = Q_PORTRANGE; }
+ ;
+/* non-directional address type qualifiers */
+ndaqual: GATEWAY { $$ = Q_GATEWAY; }
+ ;
+pname: LINK { $$ = Q_LINK; }
+ | IP { $$ = Q_IP; }
+ | ARP { $$ = Q_ARP; }
+ | RARP { $$ = Q_RARP; }
+ | SCTP { $$ = Q_SCTP; }
+ | TCP { $$ = Q_TCP; }
+ | UDP { $$ = Q_UDP; }
+ | ICMP { $$ = Q_ICMP; }
+ | IGMP { $$ = Q_IGMP; }
+ | IGRP { $$ = Q_IGRP; }
+ | PIM { $$ = Q_PIM; }
+ | VRRP { $$ = Q_VRRP; }
+ | CARP { $$ = Q_CARP; }
+ | ATALK { $$ = Q_ATALK; }
+ | AARP { $$ = Q_AARP; }
+ | DECNET { $$ = Q_DECNET; }
+ | LAT { $$ = Q_LAT; }
+ | SCA { $$ = Q_SCA; }
+ | MOPDL { $$ = Q_MOPDL; }
+ | MOPRC { $$ = Q_MOPRC; }
+ | IPV6 { $$ = Q_IPV6; }
+ | ICMPV6 { $$ = Q_ICMPV6; }
+ | AH { $$ = Q_AH; }
+ | ESP { $$ = Q_ESP; }
+ | ISO { $$ = Q_ISO; }
+ | ESIS { $$ = Q_ESIS; }
+ | ISIS { $$ = Q_ISIS; }
+ | L1 { $$ = Q_ISIS_L1; }
+ | L2 { $$ = Q_ISIS_L2; }
+ | IIH { $$ = Q_ISIS_IIH; }
+ | LSP { $$ = Q_ISIS_LSP; }
+ | SNP { $$ = Q_ISIS_SNP; }
+ | PSNP { $$ = Q_ISIS_PSNP; }
+ | CSNP { $$ = Q_ISIS_CSNP; }
+ | CLNP { $$ = Q_CLNP; }
+ | STP { $$ = Q_STP; }
+ | IPX { $$ = Q_IPX; }
+ | NETBEUI { $$ = Q_NETBEUI; }
+ | RADIO { $$ = Q_RADIO; }
+ ;
+other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); }
+ | pqual TK_MULTICAST { CHECK_PTR_VAL(($$ = gen_multicast(cstate, $1))); }
+ | LESS NUM { CHECK_PTR_VAL(($$ = gen_less(cstate, $2))); }
+ | GREATER NUM { CHECK_PTR_VAL(($$ = gen_greater(cstate, $2))); }
+ | CBYTE NUM byteop NUM { CHECK_PTR_VAL(($$ = gen_byteop(cstate, $3, $2, $4))); }
+ | INBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 0))); }
+ | OUTBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 1))); }
+ | IFINDEX NUM { CHECK_PTR_VAL(($$ = gen_ifindex(cstate, $2))); }
+ | VLAN pnum { CHECK_PTR_VAL(($$ = gen_vlan(cstate, $2, 1))); }
+ | VLAN { CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); }
+ | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, $2, 1))); }
+ | MPLS { CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); }
+ | PPPOED { CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); }
+ | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, $2, 1))); }
+ | PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); }
+ | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); }
+ | GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); }
+ | pfvar { $$ = $1; }
+ | pqual p80211 { $$ = $2; }
+ | pllc { $$ = $1; }
+ ;
+
+pfvar: PF_IFNAME ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ifname(cstate, $2))); }
+ | PF_RSET ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ruleset(cstate, $2))); }
+ | PF_RNR NUM { CHECK_PTR_VAL(($$ = gen_pf_rnr(cstate, $2))); }
+ | PF_SRNR NUM { CHECK_PTR_VAL(($$ = gen_pf_srnr(cstate, $2))); }
+ | PF_REASON reason { CHECK_PTR_VAL(($$ = gen_pf_reason(cstate, $2))); }
+ | PF_ACTION action { CHECK_PTR_VAL(($$ = gen_pf_action(cstate, $2))); }
+ ;
+
+p80211: TYPE type SUBTYPE subtype
+ { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2 | $4,
+ IEEE80211_FC0_TYPE_MASK |
+ IEEE80211_FC0_SUBTYPE_MASK)));
+ }
+ | TYPE type { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2,
+ IEEE80211_FC0_TYPE_MASK)));
+ }
+ | SUBTYPE type_subtype { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2,
+ IEEE80211_FC0_TYPE_MASK |
+ IEEE80211_FC0_SUBTYPE_MASK)));
+ }
+ | DIR dir { CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); }
+ ;
+
+type: NUM { if (($1 & (~IEEE80211_FC0_TYPE_MASK)) != 0) {
+ bpf_set_error(cstate, "invalid 802.11 type value 0x%02x", $1);
+ YYABORT;
+ }
+ $$ = (int)$1;
+ }
+ | ID { CHECK_PTR_VAL($1);
+ $$ = str2tok($1, ieee80211_types);
+ if ($$ == -1) {
+ bpf_set_error(cstate, "unknown 802.11 type name \"%s\"", $1);
+ YYABORT;
+ }
+ }
+ ;
+
+subtype: NUM { if (($1 & (~IEEE80211_FC0_SUBTYPE_MASK)) != 0) {
+ bpf_set_error(cstate, "invalid 802.11 subtype value 0x%02x", $1);
+ YYABORT;
+ }
+ $$ = (int)$1;
+ }
+ | ID { const struct tok *types = NULL;
+ int i;
+ CHECK_PTR_VAL($1);
+ for (i = 0;; i++) {
+ if (ieee80211_type_subtypes[i].tok == NULL) {
+ /* Ran out of types */
+ bpf_set_error(cstate, "unknown 802.11 type");
+ YYABORT;
+ }
+ if ($<i>-1 == ieee80211_type_subtypes[i].type) {
+ types = ieee80211_type_subtypes[i].tok;
+ break;
+ }
+ }
+
+ $$ = str2tok($1, types);
+ if ($$ == -1) {
+ bpf_set_error(cstate, "unknown 802.11 subtype name \"%s\"", $1);
+ YYABORT;
+ }
+ }
+ ;
+
+type_subtype: ID { int i;
+ CHECK_PTR_VAL($1);
+ for (i = 0;; i++) {
+ if (ieee80211_type_subtypes[i].tok == NULL) {
+ /* Ran out of types */
+ bpf_set_error(cstate, "unknown 802.11 type name");
+ YYABORT;
+ }
+ $$ = str2tok($1, ieee80211_type_subtypes[i].tok);
+ if ($$ != -1) {
+ $$ |= ieee80211_type_subtypes[i].type;
+ break;
+ }
+ }
+ }
+ ;
+
+pllc: LLC { CHECK_PTR_VAL(($$ = gen_llc(cstate))); }
+ | LLC ID { CHECK_PTR_VAL($2);
+ if (pcap_strcasecmp($2, "i") == 0) {
+ CHECK_PTR_VAL(($$ = gen_llc_i(cstate)));
+ } else if (pcap_strcasecmp($2, "s") == 0) {
+ CHECK_PTR_VAL(($$ = gen_llc_s(cstate)));
+ } else if (pcap_strcasecmp($2, "u") == 0) {
+ CHECK_PTR_VAL(($$ = gen_llc_u(cstate)));
+ } else {
+ int subtype;
+
+ subtype = str2tok($2, llc_s_subtypes);
+ if (subtype != -1) {
+ CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, subtype)));
+ } else {
+ subtype = str2tok($2, llc_u_subtypes);
+ if (subtype == -1) {
+ bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype)));
+ }
+ }
+ }
+ /* sigh, "rnr" is already a keyword for PF */
+ | LLC PF_RNR { CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); }
+ ;
+
+dir: NUM { $$ = (int)$1; }
+ | ID { CHECK_PTR_VAL($1);
+ if (pcap_strcasecmp($1, "nods") == 0)
+ $$ = IEEE80211_FC1_DIR_NODS;
+ else if (pcap_strcasecmp($1, "tods") == 0)
+ $$ = IEEE80211_FC1_DIR_TODS;
+ else if (pcap_strcasecmp($1, "fromds") == 0)
+ $$ = IEEE80211_FC1_DIR_FROMDS;
+ else if (pcap_strcasecmp($1, "dstods") == 0)
+ $$ = IEEE80211_FC1_DIR_DSTODS;
+ else {
+ bpf_set_error(cstate, "unknown 802.11 direction");
+ YYABORT;
+ }
+ }
+ ;
+
+reason: NUM { $$ = $1; }
+ | ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfreason_to_num(cstate, $1))); }
+ ;
+
+action: ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfaction_to_num(cstate, $1))); }
+ ;
+
+relop: '>' { $$ = BPF_JGT; }
+ | GEQ { $$ = BPF_JGE; }
+ | '=' { $$ = BPF_JEQ; }
+ ;
+irelop: LEQ { $$ = BPF_JGT; }
+ | '<' { $$ = BPF_JGE; }
+ | NEQ { $$ = BPF_JEQ; }
+ ;
+arth: pnum { CHECK_PTR_VAL(($$ = gen_loadi(cstate, $1))); }
+ | narth
+ ;
+narth: pname '[' arth ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, 1))); }
+ | pname '[' arth ':' NUM ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, $5))); }
+ | arth '+' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_ADD, $1, $3))); }
+ | arth '-' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_SUB, $1, $3))); }
+ | arth '*' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MUL, $1, $3))); }
+ | arth '/' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_DIV, $1, $3))); }
+ | arth '%' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MOD, $1, $3))); }
+ | arth '&' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_AND, $1, $3))); }
+ | arth '|' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_OR, $1, $3))); }
+ | arth '^' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_XOR, $1, $3))); }
+ | arth LSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_LSH, $1, $3))); }
+ | arth RSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_RSH, $1, $3))); }
+ | '-' arth %prec UMINUS { CHECK_PTR_VAL(($$ = gen_neg(cstate, $2))); }
+ | paren narth ')' { $$ = $2; }
+ | LEN { CHECK_PTR_VAL(($$ = gen_loadlen(cstate))); }
+ ;
+byteop: '&' { $$ = '&'; }
+ | '|' { $$ = '|'; }
+ | '<' { $$ = '<'; }
+ | '>' { $$ = '>'; }
+ | '=' { $$ = '='; }
+ ;
+pnum: NUM
+ | paren pnum ')' { $$ = $2; }
+ ;
+atmtype: LANE { $$ = A_LANE; }
+ | METAC { $$ = A_METAC; }
+ | BCC { $$ = A_BCC; }
+ | OAMF4EC { $$ = A_OAMF4EC; }
+ | OAMF4SC { $$ = A_OAMF4SC; }
+ | SC { $$ = A_SC; }
+ | ILMIC { $$ = A_ILMIC; }
+ ;
+atmmultitype: OAM { $$ = A_OAM; }
+ | OAMF4 { $$ = A_OAMF4; }
+ | CONNECTMSG { $$ = A_CONNECTMSG; }
+ | METACONNECT { $$ = A_METACONNECT; }
+ ;
+ /* ATM field types quantifier */
+atmfield: VPI { $$.atmfieldtype = A_VPI; }
+ | VCI { $$.atmfieldtype = A_VCI; }
+ ;
+atmvalue: atmfieldvalue
+ | relop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 0))); }
+ | irelop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 1))); }
+ | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; }
+ ;
+atmfieldvalue: NUM {
+ $$.atmfieldtype = $<blk>0.atmfieldtype;
+ if ($$.atmfieldtype == A_VPI ||
+ $$.atmfieldtype == A_VCI)
+ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, $1, BPF_JEQ, 0)));
+ }
+ ;
+atmlistvalue: atmfieldvalue
+ | atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+ /* MTP2 types quantifier */
+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 { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 0))); }
+ | irelop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 1))); }
+ | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; }
+ ;
+mtp3fieldvalue: NUM {
+ $$.mtp3fieldtype = $<blk>0.mtp3fieldtype;
+ if ($$.mtp3fieldtype == M_SIO ||
+ $$.mtp3fieldtype == M_OPC ||
+ $$.mtp3fieldtype == M_DPC ||
+ $$.mtp3fieldtype == M_SLS ||
+ $$.mtp3fieldtype == MH_SIO ||
+ $$.mtp3fieldtype == MH_OPC ||
+ $$.mtp3fieldtype == MH_DPC ||
+ $$.mtp3fieldtype == MH_SLS)
+ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, $1, BPF_JEQ, 0)));
+ }
+ ;
+mtp3listvalue: mtp3fieldvalue
+ | mtp3listvalue or mtp3fieldvalue { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+%%
diff --git a/ieee80211.h b/ieee80211.h
new file mode 100644
index 0000000..473803d
--- /dev/null
+++ b/ieee80211.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 2001 Atsushi Onoe
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $
+ */
+#ifndef _NET80211_IEEE80211_H_
+#define _NET80211_IEEE80211_H_
+
+/*
+ * 802.11 protocol definitions.
+ */
+
+#define IEEE80211_FC0_VERSION_MASK 0x03
+#define IEEE80211_FC0_VERSION_SHIFT 0
+#define IEEE80211_FC0_VERSION_0 0x00
+#define IEEE80211_FC0_TYPE_MASK 0x0c
+#define IEEE80211_FC0_TYPE_SHIFT 2
+#define IEEE80211_FC0_TYPE_MGT 0x00
+#define IEEE80211_FC0_TYPE_CTL 0x04
+#define IEEE80211_FC0_TYPE_DATA 0x08
+
+#define IEEE80211_FC0_SUBTYPE_MASK 0xf0
+#define IEEE80211_FC0_SUBTYPE_SHIFT 4
+/* for TYPE_MGT */
+#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00
+#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10
+#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20
+#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30
+#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40
+#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50
+#define IEEE80211_FC0_SUBTYPE_BEACON 0x80
+#define IEEE80211_FC0_SUBTYPE_ATIM 0x90
+#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0
+#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0
+#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0
+/* for TYPE_CTL */
+#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0
+#define IEEE80211_FC0_SUBTYPE_RTS 0xb0
+#define IEEE80211_FC0_SUBTYPE_CTS 0xc0
+#define IEEE80211_FC0_SUBTYPE_ACK 0xd0
+#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0
+#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0
+/* for TYPE_DATA (bit combination) */
+#define IEEE80211_FC0_SUBTYPE_DATA 0x00
+#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10
+#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20
+#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30
+#define IEEE80211_FC0_SUBTYPE_NODATA 0x40
+#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK 0x50
+#define IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL 0x60
+#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL 0x70
+#define IEEE80211_FC0_SUBTYPE_QOS 0x80
+#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0
+
+#define IEEE80211_FC1_DIR_MASK 0x03
+#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
+#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */
+#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */
+#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */
+
+#define IEEE80211_FC1_MORE_FRAG 0x04
+#define IEEE80211_FC1_RETRY 0x08
+#define IEEE80211_FC1_PWR_MGT 0x10
+#define IEEE80211_FC1_MORE_DATA 0x20
+#define IEEE80211_FC1_WEP 0x40
+#define IEEE80211_FC1_ORDER 0x80
+
+#define IEEE80211_SEQ_FRAG_MASK 0x000f
+#define IEEE80211_SEQ_FRAG_SHIFT 0
+#define IEEE80211_SEQ_SEQ_MASK 0xfff0
+#define IEEE80211_SEQ_SEQ_SHIFT 4
+
+#define IEEE80211_NWID_LEN 32
+
+#define IEEE80211_QOS_TXOP 0x00ff
+/* bit 8 is reserved */
+#define IEEE80211_QOS_ACKPOLICY 0x60
+#define IEEE80211_QOS_ACKPOLICY_S 5
+#define IEEE80211_QOS_ESOP 0x10
+#define IEEE80211_QOS_ESOP_S 4
+#define IEEE80211_QOS_TID 0x0f
+
+#define IEEE80211_MGT_SUBTYPE_NAMES { \
+ "assoc-req", "assoc-resp", \
+ "reassoc-req", "reassoc-resp", \
+ "probe-req", "probe-resp", \
+ "reserved#6", "reserved#7", \
+ "beacon", "atim", \
+ "disassoc", "auth", \
+ "deauth", "reserved#13", \
+ "reserved#14", "reserved#15" \
+}
+
+#define IEEE80211_CTL_SUBTYPE_NAMES { \
+ "reserved#0", "reserved#1", \
+ "reserved#2", "reserved#3", \
+ "reserved#3", "reserved#5", \
+ "reserved#6", "reserved#7", \
+ "reserved#8", "reserved#9", \
+ "ps-poll", "rts", \
+ "cts", "ack", \
+ "cf-end", "cf-end-ack" \
+}
+
+#define IEEE80211_DATA_SUBTYPE_NAMES { \
+ "data", "data-cf-ack", \
+ "data-cf-poll", "data-cf-ack-poll", \
+ "null", "cf-ack", \
+ "cf-poll", "cf-ack-poll", \
+ "qos-data", "qos-data-cf-ack", \
+ "qos-data-cf-poll", "qos-data-cf-ack-poll", \
+ "qos", "reserved#13", \
+ "qos-cf-poll", "qos-cf-ack-poll" \
+}
+
+#define IEEE80211_TYPE_NAMES { "mgt", "ctl", "data", "reserved#4" }
+
+#endif /* _NET80211_IEEE80211_H_ */
diff --git a/llc.h b/llc.h
new file mode 100644
index 0000000..b0cf881
--- /dev/null
+++ b/llc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1993, 1994, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef LLCSAP_NULL
+#define LLCSAP_NULL 0x00
+#endif
+#ifndef LLCSAP_GLOBAL
+#define LLCSAP_GLOBAL 0xff
+#endif
+#ifndef LLCSAP_8021B_I
+#define LLCSAP_8021B_I 0x02
+#endif
+#ifndef LLCSAP_8021B_G
+#define LLCSAP_8021B_G 0x03
+#endif
+#ifndef LLCSAP_IP
+#define LLCSAP_IP 0x06
+#endif
+#ifndef LLCSAP_PROWAYNM
+#define LLCSAP_PROWAYNM 0x0e
+#endif
+#ifndef LLCSAP_8021D
+#define LLCSAP_8021D 0x42
+#endif
+#ifndef LLCSAP_RS511
+#define LLCSAP_RS511 0x4e
+#endif
+#ifndef LLCSAP_ISO8208
+#define LLCSAP_ISO8208 0x7e
+#endif
+#ifndef LLCSAP_PROWAY
+#define LLCSAP_PROWAY 0x8e
+#endif
+#ifndef LLCSAP_SNAP
+#define LLCSAP_SNAP 0xaa
+#endif
+#ifndef LLCSAP_IPX
+#define LLCSAP_IPX 0xe0
+#endif
+#ifndef LLCSAP_NETBEUI
+#define LLCSAP_NETBEUI 0xf0
+#endif
+#ifndef LLCSAP_ISONS
+#define LLCSAP_ISONS 0xfe
+#endif
diff --git a/nametoaddr.c b/nametoaddr.c
new file mode 100644
index 0000000..c944ad3
--- /dev/null
+++ b/nametoaddr.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Name to id translation routines used by the scanner.
+ * These functions are not time critical.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef DECNETLIB
+#include <sys/types.h>
+#include <netdnet/dnetdb.h>
+#endif
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+
+ #ifdef INET6
+ /*
+ * To quote the MSDN page for getaddrinfo() at
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
+ *
+ * "Support for getaddrinfo on Windows 2000 and older versions
+ * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
+ * later. To execute an application that uses this function on earlier
+ * versions of Windows, then you need to include the Ws2tcpip.h and
+ * Wspiapi.h files. When the Wspiapi.h include file is added, the
+ * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
+ * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
+ * function is implemented in such a way that if the Ws2_32.dll or the
+ * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
+ * Preview for Windows 2000) does not include getaddrinfo, then a
+ * version of getaddrinfo is implemented inline based on code in the
+ * Wspiapi.h header file. This inline code will be used on older Windows
+ * platforms that do not natively support the getaddrinfo function."
+ *
+ * We use getaddrinfo(), so we include Wspiapi.h here.
+ */
+ #include <wspiapi.h>
+ #endif /* INET6 */
+#else /* _WIN32 */
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/time.h>
+
+ #include <netinet/in.h>
+
+ #ifdef HAVE_ETHER_HOSTTON
+ #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON)
+ /*
+ * OK, just include <net/ethernet.h>.
+ */
+ #include <net/ethernet.h>
+ #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON)
+ /*
+ * OK, just include <netinet/ether.h>
+ */
+ #include <netinet/ether.h>
+ #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON)
+ /*
+ * OK, just include <sys/ethernet.h>
+ */
+ #include <sys/ethernet.h>
+ #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON)
+ /*
+ * OK, just include <arpa/inet.h>
+ */
+ #include <arpa/inet.h>
+ #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON)
+ /*
+ * OK, include <netinet/if_ether.h>, after all the other stuff we
+ * need to include or define for its benefit.
+ */
+ #define NEED_NETINET_IF_ETHER_H
+ #else
+ /*
+ * We'll have to declare it ourselves.
+ * If <netinet/if_ether.h> defines struct ether_addr, include
+ * it. Otherwise, define it ourselves.
+ */
+ #ifdef HAVE_STRUCT_ETHER_ADDR
+ #define NEED_NETINET_IF_ETHER_H
+ #else /* HAVE_STRUCT_ETHER_ADDR */
+ struct ether_addr {
+ unsigned char ether_addr_octet[6];
+ };
+ #endif /* HAVE_STRUCT_ETHER_ADDR */
+ #endif /* what declares ether_hostton() */
+
+ #ifdef NEED_NETINET_IF_ETHER_H
+ #include <net/if.h> /* Needed on some platforms */
+ #include <netinet/in.h> /* Needed on some platforms */
+ #include <netinet/if_ether.h>
+ #endif /* NEED_NETINET_IF_ETHER_H */
+
+ #ifndef HAVE_DECL_ETHER_HOSTTON
+ /*
+ * No header declares it, so declare it ourselves.
+ */
+ extern int ether_hostton(const char *, struct ether_addr *);
+ #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */
+ #endif /* HAVE_ETHER_HOSTTON */
+
+ #include <arpa/inet.h>
+ #include <netdb.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "pcap-int.h"
+
+#include "diag-control.h"
+
+#include "gencode.h"
+#include <pcap/namedb.h>
+#include "nametoaddr.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifndef NTOHL
+#define NTOHL(x) (x) = ntohl(x)
+#define NTOHS(x) (x) = ntohs(x)
+#endif
+
+/*
+ * Convert host name to internet address.
+ * Return 0 upon failure.
+ * XXX - not thread-safe; don't use it inside libpcap.
+ */
+bpf_u_int32 **
+pcap_nametoaddr(const char *name)
+{
+#ifndef h_addr
+ static bpf_u_int32 *hlist[2];
+#endif
+ bpf_u_int32 **p;
+ struct hostent *hp;
+
+ /*
+ * gethostbyname() is deprecated on Windows, perhaps because
+ * it's not thread-safe, or because it doesn't support IPv6,
+ * or both.
+ *
+ * We deprecate pcap_nametoaddr() on all platforms because
+ * it's not thread-safe; we supply it for backwards compatibility,
+ * so suppress the deprecation warning. We could, I guess,
+ * use getaddrinfo() and construct the array ourselves, but
+ * that's probably not worth the effort, as that wouldn't make
+ * this thread-safe - we can't change the API to require that
+ * our caller free the address array, so we still have to reuse
+ * a local array.
+ */
+DIAG_OFF_DEPRECATION
+ if ((hp = gethostbyname(name)) != NULL) {
+DIAG_ON_DEPRECATION
+#ifndef h_addr
+ hlist[0] = (bpf_u_int32 *)hp->h_addr;
+ NTOHL(hp->h_addr);
+ return hlist;
+#else
+ for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
+ NTOHL(**p);
+ return (bpf_u_int32 **)hp->h_addr_list;
+#endif
+ }
+ else
+ return 0;
+}
+
+struct addrinfo *
+pcap_nametoaddrinfo(const char *name)
+{
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM; /*not really*/
+ hints.ai_protocol = IPPROTO_TCP; /*not really*/
+ error = getaddrinfo(name, NULL, &hints, &res);
+ if (error)
+ return NULL;
+ else
+ return res;
+}
+
+/*
+ * Convert net name to internet address.
+ * Return 0 upon failure.
+ * XXX - not guaranteed to be thread-safe! See below for platforms
+ * on which it is thread-safe and on which it isn't.
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+bpf_u_int32
+pcap_nametonetaddr(const char *name _U_)
+{
+ /*
+ * There's no "getnetbyname()" on Windows.
+ *
+ * XXX - I guess we could use the BSD code to read
+ * C:\Windows\System32\drivers\etc/networks, assuming
+ * that's its home on all the versions of Windows
+ * we use, but that file probably just has the loopback
+ * network on 127/24 on 99 44/100% of Windows machines.
+ *
+ * (Heck, these days it probably just has that on 99 44/100%
+ * of *UN*X* machines.)
+ */
+ return 0;
+}
+#else /* _WIN32 */
+bpf_u_int32
+pcap_nametonetaddr(const char *name)
+{
+ /*
+ * UN*X.
+ */
+ struct netent *np;
+ #if defined(HAVE_LINUX_GETNETBYNAME_R)
+ /*
+ * We have Linux's reentrant getnetbyname_r().
+ */
+ struct netent result_buf;
+ char buf[1024]; /* arbitrary size */
+ int h_errnoval;
+ int err;
+
+ /*
+ * Apparently, the man page at
+ *
+ * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html
+ *
+ * lies when it says
+ *
+ * If the function call successfully obtains a network record,
+ * then *result is set pointing to result_buf; otherwise, *result
+ * is set to NULL.
+ *
+ * and, in fact, at least in some versions of GNU libc, it does
+ * *not* always get set if getnetbyname_r() succeeds.
+ */
+ np = NULL;
+ err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np,
+ &h_errnoval);
+ if (err != 0) {
+ /*
+ * XXX - dynamically allocate the buffer, and make it
+ * bigger if we get ERANGE back?
+ */
+ return 0;
+ }
+ #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
+ /*
+ * We have Solaris's and IRIX's reentrant getnetbyname_r().
+ */
+ struct netent result_buf;
+ char buf[1024]; /* arbitrary size */
+
+ np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf);
+ #elif defined(HAVE_AIX_GETNETBYNAME_R)
+ /*
+ * We have AIX's reentrant getnetbyname_r().
+ */
+ struct netent result_buf;
+ struct netent_data net_data;
+
+ if (getnetbyname_r(name, &result_buf, &net_data) == -1)
+ np = NULL;
+ else
+ np = &result_buf;
+ #else
+ /*
+ * We don't have any getnetbyname_r(); either we have a
+ * getnetbyname() that uses thread-specific data, in which
+ * case we're thread-safe (sufficiently recent FreeBSD,
+ * sufficiently recent Darwin-based OS, sufficiently recent
+ * HP-UX, sufficiently recent Tru64 UNIX), or we have the
+ * traditional getnetbyname() (everything else, including
+ * current NetBSD and OpenBSD), in which case we're not
+ * thread-safe.
+ */
+ np = getnetbyname(name);
+ #endif
+ if (np != NULL)
+ return np->n_net;
+ else
+ return 0;
+}
+#endif /* _WIN32 */
+
+/*
+ * Convert a port name to its port and protocol numbers.
+ * We assume only TCP or UDP.
+ * Return 0 upon failure.
+ */
+int
+pcap_nametoport(const char *name, int *port, int *proto)
+{
+ struct addrinfo hints, *res, *ai;
+ int error;
+ struct sockaddr_in *in4;
+#ifdef INET6
+ struct sockaddr_in6 *in6;
+#endif
+ int tcp_port = -1;
+ int udp_port = -1;
+
+ /*
+ * We check for both TCP and UDP in case there are
+ * ambiguous entries.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ error = getaddrinfo(NULL, name, &hints, &res);
+ if (error != 0) {
+ if (error != EAI_NONAME &&
+ error != EAI_SERVICE) {
+ /*
+ * This is a real error, not just "there's
+ * no such service name".
+ * XXX - this doesn't return an error string.
+ */
+ return 0;
+ }
+ } else {
+ /*
+ * OK, we found it. Did it find anything?
+ */
+ for (ai = res; ai != NULL; ai = ai->ai_next) {
+ /*
+ * Does it have an address?
+ */
+ if (ai->ai_addr != NULL) {
+ /*
+ * Yes. Get a port number; we're done.
+ */
+ if (ai->ai_addr->sa_family == AF_INET) {
+ in4 = (struct sockaddr_in *)ai->ai_addr;
+ tcp_port = ntohs(in4->sin_port);
+ break;
+ }
+#ifdef INET6
+ if (ai->ai_addr->sa_family == AF_INET6) {
+ in6 = (struct sockaddr_in6 *)ai->ai_addr;
+ tcp_port = ntohs(in6->sin6_port);
+ break;
+ }
+#endif
+ }
+ }
+ freeaddrinfo(res);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ error = getaddrinfo(NULL, name, &hints, &res);
+ if (error != 0) {
+ if (error != EAI_NONAME &&
+ error != EAI_SERVICE) {
+ /*
+ * This is a real error, not just "there's
+ * no such service name".
+ * XXX - this doesn't return an error string.
+ */
+ return 0;
+ }
+ } else {
+ /*
+ * OK, we found it. Did it find anything?
+ */
+ for (ai = res; ai != NULL; ai = ai->ai_next) {
+ /*
+ * Does it have an address?
+ */
+ if (ai->ai_addr != NULL) {
+ /*
+ * Yes. Get a port number; we're done.
+ */
+ if (ai->ai_addr->sa_family == AF_INET) {
+ in4 = (struct sockaddr_in *)ai->ai_addr;
+ udp_port = ntohs(in4->sin_port);
+ break;
+ }
+#ifdef INET6
+ if (ai->ai_addr->sa_family == AF_INET6) {
+ in6 = (struct sockaddr_in6 *)ai->ai_addr;
+ udp_port = ntohs(in6->sin6_port);
+ break;
+ }
+#endif
+ }
+ }
+ freeaddrinfo(res);
+ }
+
+ /*
+ * We need to check /etc/services for ambiguous entries.
+ * If we find an ambiguous entry, and it has the
+ * same port number, change the proto to PROTO_UNDEF
+ * so both TCP and UDP will be checked.
+ */
+ if (tcp_port >= 0) {
+ *port = tcp_port;
+ *proto = IPPROTO_TCP;
+ if (udp_port >= 0) {
+ if (udp_port == tcp_port)
+ *proto = PROTO_UNDEF;
+#ifdef notdef
+ else
+ /* Can't handle ambiguous names that refer
+ to different port numbers. */
+ warning("ambiguous port %s in /etc/services",
+ name);
+#endif
+ }
+ return 1;
+ }
+ if (udp_port >= 0) {
+ *port = udp_port;
+ *proto = IPPROTO_UDP;
+ return 1;
+ }
+#if defined(ultrix) || defined(__osf__)
+ /* Special hack in case NFS isn't in /etc/services */
+ if (strcmp(name, "nfs") == 0) {
+ *port = 2049;
+ *proto = PROTO_UNDEF;
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * Convert a string in the form PPP-PPP, where correspond to ports, to
+ * a starting and ending port in a port range.
+ * Return 0 on failure.
+ */
+int
+pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
+{
+ u_int p1, p2;
+ char *off, *cpy;
+ int save_proto;
+
+ if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
+ if ((cpy = strdup(name)) == NULL)
+ return 0;
+
+ if ((off = strchr(cpy, '-')) == NULL) {
+ free(cpy);
+ return 0;
+ }
+
+ *off = '\0';
+
+ if (pcap_nametoport(cpy, port1, proto) == 0) {
+ free(cpy);
+ return 0;
+ }
+ save_proto = *proto;
+
+ if (pcap_nametoport(off + 1, port2, proto) == 0) {
+ free(cpy);
+ return 0;
+ }
+ free(cpy);
+
+ if (*proto != save_proto)
+ *proto = PROTO_UNDEF;
+ } else {
+ *port1 = p1;
+ *port2 = p2;
+ *proto = PROTO_UNDEF;
+ }
+
+ return 1;
+}
+
+/*
+ * XXX - not guaranteed to be thread-safe! See below for platforms
+ * on which it is thread-safe and on which it isn't.
+ */
+int
+pcap_nametoproto(const char *str)
+{
+ struct protoent *p;
+ #if defined(HAVE_LINUX_GETNETBYNAME_R)
+ /*
+ * We have Linux's reentrant getprotobyname_r().
+ */
+ struct protoent result_buf;
+ char buf[1024]; /* arbitrary size */
+ int err;
+
+ err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p);
+ if (err != 0) {
+ /*
+ * XXX - dynamically allocate the buffer, and make it
+ * bigger if we get ERANGE back?
+ */
+ return 0;
+ }
+ #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
+ /*
+ * We have Solaris's and IRIX's reentrant getprotobyname_r().
+ */
+ struct protoent result_buf;
+ char buf[1024]; /* arbitrary size */
+
+ p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf);
+ #elif defined(HAVE_AIX_GETNETBYNAME_R)
+ /*
+ * We have AIX's reentrant getprotobyname_r().
+ */
+ struct protoent result_buf;
+ struct protoent_data proto_data;
+
+ if (getprotobyname_r(str, &result_buf, &proto_data) == -1)
+ p = NULL;
+ else
+ p = &result_buf;
+ #else
+ /*
+ * We don't have any getprotobyname_r(); either we have a
+ * getprotobyname() that uses thread-specific data, in which
+ * case we're thread-safe (sufficiently recent FreeBSD,
+ * sufficiently recent Darwin-based OS, sufficiently recent
+ * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have
+ * the traditional getprotobyname() (everything else, including
+ * current NetBSD and OpenBSD), in which case we're not
+ * thread-safe.
+ */
+ p = getprotobyname(str);
+ #endif
+ if (p != 0)
+ return p->p_proto;
+ else
+ return PROTO_UNDEF;
+}
+
+#include "ethertype.h"
+
+struct eproto {
+ const char *s;
+ u_short p;
+};
+
+/*
+ * Static data base of ether protocol types.
+ * tcpdump used to import this, and it's declared as an export on
+ * Debian, at least, so make it a public symbol, even though we
+ * don't officially export it by declaring it in a header file.
+ * (Programs *should* do this themselves, as tcpdump now does.)
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API struct eproto eproto_db[];
+PCAP_API_DEF struct eproto eproto_db[] = {
+ { "aarp", ETHERTYPE_AARP },
+ { "arp", ETHERTYPE_ARP },
+ { "atalk", ETHERTYPE_ATALK },
+ { "decnet", ETHERTYPE_DN },
+ { "ip", ETHERTYPE_IP },
+#ifdef INET6
+ { "ip6", ETHERTYPE_IPV6 },
+#endif
+ { "lat", ETHERTYPE_LAT },
+ { "loopback", ETHERTYPE_LOOPBACK },
+ { "mopdl", ETHERTYPE_MOPDL },
+ { "moprc", ETHERTYPE_MOPRC },
+ { "rarp", ETHERTYPE_REVARP },
+ { "sca", ETHERTYPE_SCA },
+ { (char *)0, 0 }
+};
+
+int
+pcap_nametoeproto(const char *s)
+{
+ struct eproto *p = eproto_db;
+
+ while (p->s != 0) {
+ if (strcmp(p->s, s) == 0)
+ return p->p;
+ p += 1;
+ }
+ return PROTO_UNDEF;
+}
+
+#include "llc.h"
+
+/* Static data base of LLC values. */
+static struct eproto llc_db[] = {
+ { "iso", LLCSAP_ISONS },
+ { "stp", LLCSAP_8021D },
+ { "ipx", LLCSAP_IPX },
+ { "netbeui", LLCSAP_NETBEUI },
+ { (char *)0, 0 }
+};
+
+int
+pcap_nametollc(const char *s)
+{
+ struct eproto *p = llc_db;
+
+ while (p->s != 0) {
+ if (strcmp(p->s, s) == 0)
+ return p->p;
+ p += 1;
+ }
+ return PROTO_UNDEF;
+}
+
+/* Hex digit to 8-bit unsigned integer. */
+static inline u_char
+xdtoi(u_char c)
+{
+ if (c >= '0' && c <= '9')
+ return (u_char)(c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (u_char)(c - 'a' + 10);
+ else
+ return (u_char)(c - 'A' + 10);
+}
+
+int
+__pcap_atoin(const char *s, bpf_u_int32 *addr)
+{
+ u_int n;
+ int len;
+
+ *addr = 0;
+ len = 0;
+ for (;;) {
+ n = 0;
+ while (*s && *s != '.') {
+ if (n > 25) {
+ /* The result will be > 255 */
+ return -1;
+ }
+ n = n * 10 + *s++ - '0';
+ }
+ if (n > 255)
+ return -1;
+ *addr <<= 8;
+ *addr |= n & 0xff;
+ len += 8;
+ if (*s == '\0')
+ return len;
+ ++s;
+ }
+ /* NOTREACHED */
+}
+
+int
+__pcap_atodn(const char *s, bpf_u_int32 *addr)
+{
+#define AREASHIFT 10
+#define AREAMASK 0176000
+#define NODEMASK 01777
+
+ u_int node, area;
+
+ if (sscanf(s, "%d.%d", &area, &node) != 2)
+ return(0);
+
+ *addr = (area << AREASHIFT) & AREAMASK;
+ *addr |= (node & NODEMASK);
+
+ return(32);
+}
+
+/*
+ * Convert 's', which can have the one of the forms:
+ *
+ * "xx:xx:xx:xx:xx:xx"
+ * "xx.xx.xx.xx.xx.xx"
+ * "xx-xx-xx-xx-xx-xx"
+ * "xxxx.xxxx.xxxx"
+ * "xxxxxxxxxxxx"
+ *
+ * (or various mixes of ':', '.', and '-') into a new
+ * ethernet address. Assumes 's' is well formed.
+ */
+u_char *
+pcap_ether_aton(const char *s)
+{
+ register u_char *ep, *e;
+ register u_char d;
+
+ e = ep = (u_char *)malloc(6);
+ if (e == NULL)
+ return (NULL);
+
+ while (*s) {
+ if (*s == ':' || *s == '.' || *s == '-')
+ s += 1;
+ d = xdtoi(*s++);
+ if (PCAP_ISXDIGIT(*s)) {
+ d <<= 4;
+ d |= xdtoi(*s++);
+ }
+ *ep++ = d;
+ }
+
+ return (e);
+}
+
+#ifndef HAVE_ETHER_HOSTTON
+/*
+ * Roll our own.
+ * XXX - not thread-safe, because pcap_next_etherent() isn't thread-
+ * safe! Needs a mutex or a thread-safe pcap_next_etherent().
+ */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+ register struct pcap_etherent *ep;
+ register u_char *ap;
+ static FILE *fp = NULL;
+ static int init = 0;
+
+ if (!init) {
+ fp = fopen(PCAP_ETHERS_FILE, "r");
+ ++init;
+ if (fp == NULL)
+ return (NULL);
+ } else if (fp == NULL)
+ return (NULL);
+ else
+ rewind(fp);
+
+ while ((ep = pcap_next_etherent(fp)) != NULL) {
+ if (strcmp(ep->name, name) == 0) {
+ ap = (u_char *)malloc(6);
+ if (ap != NULL) {
+ memcpy(ap, ep->addr, 6);
+ return (ap);
+ }
+ break;
+ }
+ }
+ return (NULL);
+}
+#else
+/*
+ * Use the OS-supplied routine.
+ * This *should* be thread-safe; the API doesn't have a static buffer.
+ */
+u_char *
+pcap_ether_hostton(const char *name)
+{
+ register u_char *ap;
+ u_char a[6];
+
+ ap = NULL;
+ if (ether_hostton(name, (struct ether_addr *)a) == 0) {
+ ap = (u_char *)malloc(6);
+ if (ap != NULL)
+ memcpy((char *)ap, (char *)a, 6);
+ }
+ return (ap);
+}
+#endif
+
+/*
+ * XXX - not guaranteed to be thread-safe!
+ */
+int
+#ifdef DECNETLIB
+__pcap_nametodnaddr(const char *name, u_short *res)
+{
+ struct nodeent *getnodebyname();
+ struct nodeent *nep;
+
+ nep = getnodebyname(name);
+ if (nep == ((struct nodeent *)0))
+ return(0);
+
+ memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short));
+ return(1);
+#else
+__pcap_nametodnaddr(const char *name _U_, u_short *res _U_)
+{
+ return(0);
+#endif
+}
diff --git a/nametoaddr.h b/nametoaddr.h
new file mode 100644
index 0000000..fd6b7e1
--- /dev/null
+++ b/nametoaddr.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1994, 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Routines used for name-or-address-string-to-address resolution
+ * that are *not* exported to code using libpcap.
+ */
+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/nlpid.h b/nlpid.h
new file mode 100644
index 0000000..9dfa752
--- /dev/null
+++ b/nlpid.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1996
+ * Juniper Networks, Inc. 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. The name of Juniper Networks 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.
+ */
+
+/* Types missing from some systems */
+
+/*
+ * Network layer prototocol identifiers
+ */
+#ifndef ISO8473_CLNP
+#define ISO8473_CLNP 0x81
+#endif
+#ifndef ISO9542_ESIS
+#define ISO9542_ESIS 0x82
+#endif
+#ifndef ISO9542X25_ESIS
+#define ISO9542X25_ESIS 0x8a
+#endif
+#ifndef ISO10589_ISIS
+#define ISO10589_ISIS 0x83
+#endif
+/*
+ * this does not really belong in the nlpid.h file
+ * however we need it for generating nice
+ * IS-IS related BPF filters
+ */
+#define ISIS_L1_LAN_IIH 15
+#define ISIS_L2_LAN_IIH 16
+#define ISIS_PTP_IIH 17
+#define ISIS_L1_LSP 18
+#define ISIS_L2_LSP 20
+#define ISIS_L1_CSNP 24
+#define ISIS_L2_CSNP 25
+#define ISIS_L1_PSNP 26
+#define ISIS_L2_PSNP 27
+
+#ifndef ISO8878A_CONS
+#define ISO8878A_CONS 0x84
+#endif
+#ifndef ISO10747_IDRP
+#define ISO10747_IDRP 0x85
+#endif
diff --git a/optimize.c b/optimize.c
new file mode 100644
index 0000000..610a030
--- /dev/null
+++ b/optimize.c
@@ -0,0 +1,3093 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Optimization module for BPF code intermediate representation.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <setjmp.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include "pcap-int.h"
+
+#include "gencode.h"
+#include "optimize.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef BDEBUG
+/*
+ * The internal "debug printout" flag for the filter expression optimizer.
+ * The code to print that stuff is present only if BDEBUG is defined, so
+ * the flag, and the routine to set it, are defined only if BDEBUG is
+ * defined.
+ */
+static int pcap_optimizer_debug;
+
+/*
+ * Routine to set that flag.
+ *
+ * This is intended for libpcap developers, not for general use.
+ * If you want to set these in a program, you'll have to declare this
+ * routine yourself, with the appropriate DLL import attribute on Windows;
+ * it's not declared in any header file, and won't be declared in any
+ * header file provided by libpcap.
+ */
+PCAP_API void pcap_set_optimizer_debug(int value);
+
+PCAP_API_DEF void
+pcap_set_optimizer_debug(int value)
+{
+ pcap_optimizer_debug = value;
+}
+
+/*
+ * The internal "print dot graph" flag for the filter expression optimizer.
+ * The code to print that stuff is present only if BDEBUG is defined, so
+ * the flag, and the routine to set it, are defined only if BDEBUG is
+ * defined.
+ */
+static int pcap_print_dot_graph;
+
+/*
+ * Routine to set that flag.
+ *
+ * This is intended for libpcap developers, not for general use.
+ * If you want to set these in a program, you'll have to declare this
+ * routine yourself, with the appropriate DLL import attribute on Windows;
+ * it's not declared in any header file, and won't be declared in any
+ * header file provided by libpcap.
+ */
+PCAP_API void pcap_set_print_dot_graph(int value);
+
+PCAP_API_DEF void
+pcap_set_print_dot_graph(int value)
+{
+ pcap_print_dot_graph = value;
+}
+
+#endif
+
+/*
+ * lowest_set_bit().
+ *
+ * Takes a 32-bit integer as an argument.
+ *
+ * If handed a non-zero value, returns the index of the lowest set bit,
+ * counting upwards from zero.
+ *
+ * If handed zero, the results are platform- and compiler-dependent.
+ * Keep it out of the light, don't give it any water, don't feed it
+ * after midnight, and don't pass zero to it.
+ *
+ * This is the same as the count of trailing zeroes in the word.
+ */
+#if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4)
+ /*
+ * GCC 3.4 and later; we have __builtin_ctz().
+ */
+ #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask))
+#elif defined(_MSC_VER)
+ /*
+ * Visual Studio; we support only 2005 and later, so use
+ * _BitScanForward().
+ */
+#include <intrin.h>
+
+#ifndef __clang__
+#pragma intrinsic(_BitScanForward)
+#endif
+
+static __forceinline u_int
+lowest_set_bit(int mask)
+{
+ unsigned long bit;
+
+ /*
+ * Don't sign-extend mask if long is longer than int.
+ * (It's currently not, in MSVC, even on 64-bit platforms, but....)
+ */
+ if (_BitScanForward(&bit, (unsigned int)mask) == 0)
+ abort(); /* mask is zero */
+ return (u_int)bit;
+}
+#elif defined(MSDOS) && defined(__DJGPP__)
+ /*
+ * MS-DOS with DJGPP, which declares ffs() in <string.h>, which
+ * we've already included.
+ */
+ #define lowest_set_bit(mask) ((u_int)(ffs((mask)) - 1))
+#elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS)
+ /*
+ * MS-DOS with Watcom C, which has <strings.h> and declares ffs() there,
+ * or some other platform (UN*X conforming to a sufficient recent version
+ * of the Single UNIX Specification).
+ */
+ #include <strings.h>
+ #define lowest_set_bit(mask) (u_int)((ffs((mask)) - 1))
+#else
+/*
+ * None of the above.
+ * Use a perfect-hash-function-based function.
+ */
+static u_int
+lowest_set_bit(int mask)
+{
+ unsigned int v = (unsigned int)mask;
+
+ static const u_int MultiplyDeBruijnBitPosition[32] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+
+ /*
+ * We strip off all but the lowermost set bit (v & ~v),
+ * and perform a minimal perfect hash on it to look up the
+ * number of low-order zero bits in a table.
+ *
+ * See:
+ *
+ * http://7ooo.mooo.com/text/ComputingTrailingZerosHOWTO.pdf
+ *
+ * http://supertech.csail.mit.edu/papers/debruijn.pdf
+ */
+ return (MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27]);
+}
+#endif
+
+/*
+ * Represents a deleted instruction.
+ */
+#define NOP -1
+
+/*
+ * Register numbers for use-def values.
+ * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory
+ * location. A_ATOM is the accumulator and X_ATOM is the index
+ * register.
+ */
+#define A_ATOM BPF_MEMWORDS
+#define X_ATOM (BPF_MEMWORDS+1)
+
+/*
+ * This define is used to represent *both* the accumulator and
+ * x register in use-def computations.
+ * Currently, the use-def code assumes only one definition per instruction.
+ */
+#define AX_ATOM N_ATOMS
+
+/*
+ * These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme. Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined.
+ */
+struct valnode {
+ int code;
+ bpf_u_int32 v0, v1;
+ int val; /* the value number */
+ struct valnode *next;
+};
+
+/* Integer constants mapped with the load immediate opcode. */
+#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U)
+
+struct vmapinfo {
+ int is_const;
+ bpf_u_int32 const_val;
+};
+
+typedef struct {
+ /*
+ * Place to longjmp to on an error.
+ */
+ jmp_buf top_ctx;
+
+ /*
+ * The buffer into which to put error message.
+ */
+ char *errbuf;
+
+ /*
+ * A flag to indicate that further optimization is needed.
+ * Iterative passes are continued until a given pass yields no
+ * code simplification or branch movement.
+ */
+ int done;
+
+ /*
+ * XXX - detect loops that do nothing but repeated AND/OR pullups
+ * and edge moves.
+ * If 100 passes in a row do nothing but that, treat that as a
+ * sign that we're in a loop that just shuffles in a cycle in
+ * which each pass just shuffles the code and we eventually
+ * get back to the original configuration.
+ *
+ * XXX - we need a non-heuristic way of detecting, or preventing,
+ * such a cycle.
+ */
+ int non_branch_movement_performed;
+
+ u_int n_blocks; /* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */
+ struct block **blocks;
+ u_int n_edges; /* twice n_blocks, so guaranteed to be > 0 */
+ struct edge **edges;
+
+ /*
+ * A bit vector set representation of the dominators.
+ * We round up the set size to the next power of two.
+ */
+ u_int nodewords; /* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */
+ u_int edgewords; /* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */
+ struct block **levels;
+ bpf_u_int32 *space;
+
+#define BITS_PER_WORD (8*sizeof(bpf_u_int32))
+/*
+ * True if a is in uset {p}
+ */
+#define SET_MEMBER(p, a) \
+((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)))
+
+/*
+ * Add 'a' to uset p.
+ */
+#define SET_INSERT(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * Delete 'a' from uset p.
+ */
+#define SET_DELETE(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * a := a intersect b
+ * n must be guaranteed to be > 0
+ */
+#define SET_INTERSECT(a, b, n)\
+{\
+ register bpf_u_int32 *_x = a, *_y = b;\
+ register u_int _n = n;\
+ do *_x++ &= *_y++; while (--_n != 0);\
+}
+
+/*
+ * a := a - b
+ * n must be guaranteed to be > 0
+ */
+#define SET_SUBTRACT(a, b, n)\
+{\
+ register bpf_u_int32 *_x = a, *_y = b;\
+ register u_int _n = n;\
+ do *_x++ &=~ *_y++; while (--_n != 0);\
+}
+
+/*
+ * a := a union b
+ * n must be guaranteed to be > 0
+ */
+#define SET_UNION(a, b, n)\
+{\
+ register bpf_u_int32 *_x = a, *_y = b;\
+ register u_int _n = n;\
+ do *_x++ |= *_y++; while (--_n != 0);\
+}
+
+ uset all_dom_sets;
+ uset all_closure_sets;
+ uset all_edge_sets;
+
+#define MODULUS 213
+ struct valnode *hashtbl[MODULUS];
+ bpf_u_int32 curval;
+ bpf_u_int32 maxval;
+
+ struct vmapinfo *vmap;
+ struct valnode *vnode_base;
+ struct valnode *next_vnode;
+} opt_state_t;
+
+typedef struct {
+ /*
+ * Place to longjmp to on an error.
+ */
+ jmp_buf top_ctx;
+
+ /*
+ * The buffer into which to put error message.
+ */
+ char *errbuf;
+
+ /*
+ * Some pointers used to convert the basic block form of the code,
+ * into the array form that BPF requires. 'fstart' will point to
+ * the malloc'd array while 'ftail' is used during the recursive
+ * traversal.
+ */
+ struct bpf_insn *fstart;
+ struct bpf_insn *ftail;
+} conv_state_t;
+
+static void opt_init(opt_state_t *, struct icode *);
+static void opt_cleanup(opt_state_t *);
+static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
+
+static void intern_blocks(opt_state_t *, struct icode *);
+
+static void find_inedges(opt_state_t *, struct block *);
+#ifdef BDEBUG
+static void opt_dump(opt_state_t *, struct icode *);
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+static void
+find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b)
+{
+ int level;
+
+ if (isMarked(ic, b))
+ return;
+
+ Mark(ic, b);
+ b->link = 0;
+
+ if (JT(b)) {
+ find_levels_r(opt_state, ic, JT(b));
+ find_levels_r(opt_state, ic, JF(b));
+ level = MAX(JT(b)->level, JF(b)->level) + 1;
+ } else
+ level = 0;
+ b->level = level;
+ b->link = opt_state->levels[level];
+ opt_state->levels[level] = b;
+}
+
+/*
+ * Level graph. The levels go from 0 at the leaves to
+ * N_LEVELS at the root. The opt_state->levels[] array points to the
+ * first node of the level list, whose elements are linked
+ * with the 'link' field of the struct block.
+ */
+static void
+find_levels(opt_state_t *opt_state, struct icode *ic)
+{
+ memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels));
+ unMarkAll(ic);
+ find_levels_r(opt_state, ic, ic->root);
+}
+
+/*
+ * Find dominator relationships.
+ * Assumes graph has been leveled.
+ */
+static void
+find_dom(opt_state_t *opt_state, struct block *root)
+{
+ u_int i;
+ int level;
+ struct block *b;
+ bpf_u_int32 *x;
+
+ /*
+ * Initialize sets to contain all nodes.
+ */
+ x = opt_state->all_dom_sets;
+ /*
+ * In opt_init(), we've made sure the product doesn't overflow.
+ */
+ i = opt_state->n_blocks * opt_state->nodewords;
+ while (i != 0) {
+ --i;
+ *x++ = 0xFFFFFFFFU;
+ }
+ /* Root starts off empty. */
+ for (i = opt_state->nodewords; i != 0;) {
+ --i;
+ root->dom[i] = 0;
+ }
+
+ /* root->level is the highest level no found. */
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b; b = b->link) {
+ SET_INSERT(b->dom, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords);
+ SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords);
+ }
+ }
+}
+
+static void
+propedom(opt_state_t *opt_state, struct edge *ep)
+{
+ SET_INSERT(ep->edom, ep->id);
+ if (ep->succ) {
+ SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords);
+ SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords);
+ }
+}
+
+/*
+ * Compute edge dominators.
+ * Assumes graph has been leveled and predecessors established.
+ */
+static void
+find_edom(opt_state_t *opt_state, struct block *root)
+{
+ u_int i;
+ uset x;
+ int level;
+ struct block *b;
+
+ x = opt_state->all_edge_sets;
+ /*
+ * In opt_init(), we've made sure the product doesn't overflow.
+ */
+ for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) {
+ --i;
+ x[i] = 0xFFFFFFFFU;
+ }
+
+ /* root->level is the highest level no found. */
+ memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
+ memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b != 0; b = b->link) {
+ propedom(opt_state, &b->et);
+ propedom(opt_state, &b->ef);
+ }
+ }
+}
+
+/*
+ * Find the backwards transitive closure of the flow graph. These sets
+ * are backwards in the sense that we find the set of nodes that reach
+ * a given node, not the set of nodes that can be reached by a node.
+ *
+ * Assumes graph has been leveled.
+ */
+static void
+find_closure(opt_state_t *opt_state, struct block *root)
+{
+ int level;
+ struct block *b;
+
+ /*
+ * Initialize sets to contain no nodes.
+ */
+ memset((char *)opt_state->all_closure_sets, 0,
+ opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets));
+
+ /* root->level is the highest level no found. */
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b; b = b->link) {
+ SET_INSERT(b->closure, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords);
+ SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords);
+ }
+ }
+}
+
+/*
+ * Return the register number that is used by s.
+ *
+ * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X
+ * are used, the scratch memory location's number if a scratch memory
+ * location is used (e.g., 0 for M[0]), or -1 if none of those are used.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomuse(struct stmt *s)
+{
+ register int c = s->code;
+
+ if (c == NOP)
+ return -1;
+
+ switch (BPF_CLASS(c)) {
+
+ case BPF_RET:
+ return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
+ (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
+
+ case BPF_LD:
+ case BPF_LDX:
+ /*
+ * As there are fewer than 2^31 memory locations,
+ * s->k should be convertible to int without problems.
+ */
+ return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
+ (BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1;
+
+ case BPF_ST:
+ return A_ATOM;
+
+ case BPF_STX:
+ return X_ATOM;
+
+ case BPF_JMP:
+ case BPF_ALU:
+ if (BPF_SRC(c) == BPF_X)
+ return AX_ATOM;
+ return A_ATOM;
+
+ case BPF_MISC:
+ return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Return the register number that is defined by 's'. We assume that
+ * a single stmt cannot define more than one register. If no register
+ * is defined, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomdef(struct stmt *s)
+{
+ if (s->code == NOP)
+ return -1;
+
+ switch (BPF_CLASS(s->code)) {
+
+ case BPF_LD:
+ case BPF_ALU:
+ return A_ATOM;
+
+ case BPF_LDX:
+ return X_ATOM;
+
+ case BPF_ST:
+ case BPF_STX:
+ return s->k;
+
+ case BPF_MISC:
+ return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
+ }
+ return -1;
+}
+
+/*
+ * Compute the sets of registers used, defined, and killed by 'b'.
+ *
+ * "Used" means that a statement in 'b' uses the register before any
+ * statement in 'b' defines it, i.e. it uses the value left in
+ * that register by a predecessor block of this block.
+ * "Defined" means that a statement in 'b' defines it.
+ * "Killed" means that a statement in 'b' defines it before any
+ * statement in 'b' uses it, i.e. it kills the value left in that
+ * register by a predecessor block of this block.
+ */
+static void
+compute_local_ud(struct block *b)
+{
+ struct slist *s;
+ atomset def = 0, use = 0, killed = 0;
+ int atom;
+
+ for (s = b->stmts; s; s = s->next) {
+ if (s->s.code == NOP)
+ continue;
+ atom = atomuse(&s->s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ if (!ATOMELEM(def, X_ATOM))
+ use |= ATOMMASK(X_ATOM);
+ if (!ATOMELEM(def, A_ATOM))
+ use |= ATOMMASK(A_ATOM);
+ }
+ else if (atom < N_ATOMS) {
+ if (!ATOMELEM(def, atom))
+ use |= ATOMMASK(atom);
+ }
+ else
+ abort();
+ }
+ atom = atomdef(&s->s);
+ if (atom >= 0) {
+ if (!ATOMELEM(use, atom))
+ killed |= ATOMMASK(atom);
+ def |= ATOMMASK(atom);
+ }
+ }
+ if (BPF_CLASS(b->s.code) == BPF_JMP) {
+ /*
+ * XXX - what about RET?
+ */
+ atom = atomuse(&b->s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ if (!ATOMELEM(def, X_ATOM))
+ use |= ATOMMASK(X_ATOM);
+ if (!ATOMELEM(def, A_ATOM))
+ use |= ATOMMASK(A_ATOM);
+ }
+ else if (atom < N_ATOMS) {
+ if (!ATOMELEM(def, atom))
+ use |= ATOMMASK(atom);
+ }
+ else
+ abort();
+ }
+ }
+
+ b->def = def;
+ b->kill = killed;
+ b->in_use = use;
+}
+
+/*
+ * Assume graph is already leveled.
+ */
+static void
+find_ud(opt_state_t *opt_state, struct block *root)
+{
+ int i, maxlevel;
+ struct block *p;
+
+ /*
+ * root->level is the highest level no found;
+ * count down from there.
+ */
+ maxlevel = root->level;
+ for (i = maxlevel; i >= 0; --i)
+ for (p = opt_state->levels[i]; p; p = p->link) {
+ compute_local_ud(p);
+ p->out_use = 0;
+ }
+
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = opt_state->levels[i]; p; p = p->link) {
+ p->out_use |= JT(p)->in_use | JF(p)->in_use;
+ p->in_use |= p->out_use &~ p->kill;
+ }
+ }
+}
+static void
+init_val(opt_state_t *opt_state)
+{
+ opt_state->curval = 0;
+ opt_state->next_vnode = opt_state->vnode_base;
+ memset((char *)opt_state->vmap, 0, opt_state->maxval * sizeof(*opt_state->vmap));
+ memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl);
+}
+
+/*
+ * Because we really don't have an IR, this stuff is a little messy.
+ *
+ * This routine looks in the table of existing value number for a value
+ * with generated from an operation with the specified opcode and
+ * the specified values. If it finds it, it returns its value number,
+ * otherwise it makes a new entry in the table and returns the
+ * value number of that entry.
+ */
+static bpf_u_int32
+F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1)
+{
+ u_int hash;
+ bpf_u_int32 val;
+ struct valnode *p;
+
+ hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+ hash %= MODULUS;
+
+ for (p = opt_state->hashtbl[hash]; p; p = p->next)
+ if (p->code == code && p->v0 == v0 && p->v1 == v1)
+ return p->val;
+
+ /*
+ * Not found. Allocate a new value, and assign it a new
+ * value number.
+ *
+ * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we
+ * increment it before using it as the new value number, which
+ * means we never assign VAL_UNKNOWN.
+ *
+ * XXX - unless we overflow, but we probably won't have 2^32-1
+ * values; we treat 32 bits as effectively infinite.
+ */
+ val = ++opt_state->curval;
+ if (BPF_MODE(code) == BPF_IMM &&
+ (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
+ opt_state->vmap[val].const_val = v0;
+ opt_state->vmap[val].is_const = 1;
+ }
+ p = opt_state->next_vnode++;
+ p->val = val;
+ p->code = code;
+ p->v0 = v0;
+ p->v1 = v1;
+ p->next = opt_state->hashtbl[hash];
+ opt_state->hashtbl[hash] = p;
+
+ return val;
+}
+
+static inline void
+vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter)
+{
+ if (alter && newval != VAL_UNKNOWN && *valp == newval)
+ s->code = NOP;
+ else
+ *valp = newval;
+}
+
+/*
+ * Do constant-folding on binary operators.
+ * (Unary operators are handled elsewhere.)
+ */
+static void
+fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1)
+{
+ bpf_u_int32 a, b;
+
+ a = opt_state->vmap[v0].const_val;
+ b = opt_state->vmap[v1].const_val;
+
+ switch (BPF_OP(s->code)) {
+ case BPF_ADD:
+ a += b;
+ break;
+
+ case BPF_SUB:
+ a -= b;
+ break;
+
+ case BPF_MUL:
+ a *= b;
+ break;
+
+ case BPF_DIV:
+ if (b == 0)
+ opt_error(opt_state, "division by zero");
+ a /= b;
+ break;
+
+ case BPF_MOD:
+ if (b == 0)
+ opt_error(opt_state, "modulus by zero");
+ a %= b;
+ break;
+
+ case BPF_AND:
+ a &= b;
+ break;
+
+ case BPF_OR:
+ a |= b;
+ break;
+
+ case BPF_XOR:
+ a ^= b;
+ break;
+
+ case BPF_LSH:
+ /*
+ * A left shift of more than the width of the type
+ * is undefined in C; we'll just treat it as shifting
+ * all the bits out.
+ *
+ * XXX - the BPF interpreter doesn't check for this,
+ * so its behavior is dependent on the behavior of
+ * the processor on which it's running. There are
+ * processors on which it shifts all the bits out
+ * and processors on which it does no shift.
+ */
+ if (b < 32)
+ a <<= b;
+ else
+ a = 0;
+ break;
+
+ case BPF_RSH:
+ /*
+ * A right shift of more than the width of the type
+ * is undefined in C; we'll just treat it as shifting
+ * all the bits out.
+ *
+ * XXX - the BPF interpreter doesn't check for this,
+ * so its behavior is dependent on the behavior of
+ * the processor on which it's running. There are
+ * processors on which it shifts all the bits out
+ * and processors on which it does no shift.
+ */
+ if (b < 32)
+ a >>= b;
+ else
+ a = 0;
+ break;
+
+ default:
+ abort();
+ }
+ s->k = a;
+ s->code = BPF_LD|BPF_IMM;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+}
+
+static inline struct slist *
+this_op(struct slist *s)
+{
+ while (s != 0 && s->s.code == NOP)
+ s = s->next;
+ return s;
+}
+
+static void
+opt_not(struct block *b)
+{
+ struct block *tmp = JT(b);
+
+ JT(b) = JF(b);
+ JF(b) = tmp;
+}
+
+static void
+opt_peep(opt_state_t *opt_state, struct block *b)
+{
+ struct slist *s;
+ struct slist *next, *last;
+ bpf_u_int32 val;
+
+ s = b->stmts;
+ if (s == 0)
+ return;
+
+ last = s;
+ for (/*empty*/; /*empty*/; s = next) {
+ /*
+ * Skip over nops.
+ */
+ s = this_op(s);
+ if (s == 0)
+ break; /* nothing left in the block */
+
+ /*
+ * Find the next real instruction after that one
+ * (skipping nops).
+ */
+ next = this_op(s->next);
+ if (next == 0)
+ break; /* no next instruction */
+ last = next;
+
+ /*
+ * st M[k] --> st M[k]
+ * ldx M[k] tax
+ */
+ if (s->s.code == BPF_ST &&
+ next->s.code == (BPF_LDX|BPF_MEM) &&
+ s->s.k == next->s.k) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ next->s.code = BPF_MISC|BPF_TAX;
+ }
+ /*
+ * ld #k --> ldx #k
+ * tax txa
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM) &&
+ next->s.code == (BPF_MISC|BPF_TAX)) {
+ s->s.code = BPF_LDX|BPF_IMM;
+ next->s.code = BPF_MISC|BPF_TXA;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ /*
+ * This is an ugly special case, but it happens
+ * when you say tcp[k] or udp[k] where k is a constant.
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM)) {
+ struct slist *add, *tax, *ild;
+
+ /*
+ * Check that X isn't used on exit from this
+ * block (which the optimizer might cause).
+ * We know the code generator won't generate
+ * any local dependencies.
+ */
+ if (ATOMELEM(b->out_use, X_ATOM))
+ continue;
+
+ /*
+ * Check that the instruction following the ldi
+ * is an addx, or it's an ldxms with an addx
+ * following it (with 0 or more nops between the
+ * ldxms and addx).
+ */
+ if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+ add = next;
+ else
+ add = this_op(next->next);
+ if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
+ continue;
+
+ /*
+ * Check that a tax follows that (with 0 or more
+ * nops between them).
+ */
+ tax = this_op(add->next);
+ if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
+ continue;
+
+ /*
+ * Check that an ild follows that (with 0 or more
+ * nops between them).
+ */
+ ild = this_op(tax->next);
+ if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
+ BPF_MODE(ild->s.code) != BPF_IND)
+ continue;
+ /*
+ * We want to turn this sequence:
+ *
+ * (004) ldi #0x2 {s}
+ * (005) ldxms [14] {next} -- optional
+ * (006) addx {add}
+ * (007) tax {tax}
+ * (008) ild [x+0] {ild}
+ *
+ * into this sequence:
+ *
+ * (004) nop
+ * (005) ldxms [14]
+ * (006) nop
+ * (007) nop
+ * (008) ild [x+2]
+ *
+ * XXX We need to check that X is not
+ * subsequently used, because we want to change
+ * what'll be in it after this sequence.
+ *
+ * We know we can eliminate the accumulator
+ * modifications earlier in the sequence since
+ * it is defined by the last stmt of this sequence
+ * (i.e., the last statement of the sequence loads
+ * a value into the accumulator, so we can eliminate
+ * earlier operations on the accumulator).
+ */
+ ild->s.k += s->s.k;
+ s->s.code = NOP;
+ add->s.code = NOP;
+ tax->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ }
+ /*
+ * If the comparison at the end of a block is an equality
+ * comparison against a constant, and nobody uses the value
+ * we leave in the A register at the end of a block, and
+ * the operation preceding the comparison is an arithmetic
+ * operation, we can sometime optimize it away.
+ */
+ if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) &&
+ !ATOMELEM(b->out_use, A_ATOM)) {
+ /*
+ * We can optimize away certain subtractions of the
+ * X register.
+ */
+ if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) {
+ val = b->val[X_ATOM];
+ if (opt_state->vmap[val].is_const) {
+ /*
+ * If we have a subtract to do a comparison,
+ * and the X register is a known constant,
+ * we can merge this value into the
+ * comparison:
+ *
+ * sub x -> nop
+ * jeq #y jeq #(x+y)
+ */
+ b->s.k += opt_state->vmap[val].const_val;
+ last->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ } else if (b->s.k == 0) {
+ /*
+ * If the X register isn't a constant,
+ * and the comparison in the test is
+ * against 0, we can compare with the
+ * X register, instead:
+ *
+ * sub x -> nop
+ * jeq #0 jeq x
+ */
+ last->s.code = NOP;
+ b->s.code = BPF_JMP|BPF_JEQ|BPF_X;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ }
+ /*
+ * Likewise, a constant subtract can be simplified:
+ *
+ * sub #x -> nop
+ * jeq #y -> jeq #(x+y)
+ */
+ else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) {
+ last->s.code = NOP;
+ b->s.k += last->s.k;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ /*
+ * And, similarly, a constant AND can be simplified
+ * if we're testing against 0, i.e.:
+ *
+ * and #k nop
+ * jeq #0 -> jset #k
+ */
+ else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
+ b->s.k == 0) {
+ b->s.k = last->s.k;
+ b->s.code = BPF_JMP|BPF_K|BPF_JSET;
+ last->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ opt_not(b);
+ }
+ }
+ /*
+ * jset #0 -> never
+ * jset #ffffffff -> always
+ */
+ if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) {
+ if (b->s.k == 0)
+ JT(b) = JF(b);
+ if (b->s.k == 0xffffffffU)
+ JF(b) = JT(b);
+ }
+ /*
+ * If we're comparing against the index register, and the index
+ * register is a known constant, we can just compare against that
+ * constant.
+ */
+ val = b->val[X_ATOM];
+ if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
+ bpf_u_int32 v = opt_state->vmap[val].const_val;
+ b->s.code &= ~BPF_X;
+ b->s.k = v;
+ }
+ /*
+ * If the accumulator is a known constant, we can compute the
+ * comparison result.
+ */
+ val = b->val[A_ATOM];
+ if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
+ bpf_u_int32 v = opt_state->vmap[val].const_val;
+ switch (BPF_OP(b->s.code)) {
+
+ case BPF_JEQ:
+ v = v == b->s.k;
+ break;
+
+ case BPF_JGT:
+ v = v > b->s.k;
+ break;
+
+ case BPF_JGE:
+ v = v >= b->s.k;
+ break;
+
+ case BPF_JSET:
+ v &= b->s.k;
+ break;
+
+ default:
+ abort();
+ }
+ if (JF(b) != JT(b)) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ if (v)
+ JF(b) = JT(b);
+ else
+ JT(b) = JF(b);
+ }
+}
+
+/*
+ * Compute the symbolic value of expression of 's', and update
+ * anything it defines in the value table 'val'. If 'alter' is true,
+ * do various optimizations. This code would be cleaner if symbolic
+ * evaluation and code transformations weren't folded together.
+ */
+static void
+opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter)
+{
+ int op;
+ bpf_u_int32 v;
+
+ switch (s->code) {
+
+ case BPF_LD|BPF_ABS|BPF_W:
+ case BPF_LD|BPF_ABS|BPF_H:
+ case BPF_LD|BPF_ABS|BPF_B:
+ v = F(opt_state, s->code, s->k, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IND|BPF_W:
+ case BPF_LD|BPF_IND|BPF_H:
+ case BPF_LD|BPF_IND|BPF_B:
+ v = val[X_ATOM];
+ if (alter && opt_state->vmap[v].is_const) {
+ s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
+ s->k += opt_state->vmap[v].const_val;
+ v = F(opt_state, s->code, s->k, 0L);
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ else
+ v = F(opt_state, s->code, s->k, v);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_LEN:
+ v = F(opt_state, s->code, 0L, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ v = F(opt_state, s->code, s->k, 0L);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ if (alter && opt_state->vmap[val[A_ATOM]].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ /*
+ * Do this negation as unsigned arithmetic; that's
+ * what modern BPF engines do, and it guarantees
+ * that all possible values can be negated. (Yeah,
+ * negating 0x80000000, the minimum signed 32-bit
+ * two's-complement value, results in 0x80000000,
+ * so it's still negative, but we *should* be doing
+ * all unsigned arithmetic here, to match what
+ * modern BPF engines do.)
+ *
+ * Express it as 0U - (unsigned value) so that we
+ * don't get compiler warnings about negating an
+ * unsigned value and don't get UBSan warnings
+ * about the result of negating 0x80000000 being
+ * undefined.
+ */
+ s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val;
+ val[A_ATOM] = K(s->k);
+ }
+ else
+ val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], 0L);
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ case BPF_ALU|BPF_SUB|BPF_K:
+ case BPF_ALU|BPF_MUL|BPF_K:
+ case BPF_ALU|BPF_DIV|BPF_K:
+ case BPF_ALU|BPF_MOD|BPF_K:
+ case BPF_ALU|BPF_AND|BPF_K:
+ case BPF_ALU|BPF_OR|BPF_K:
+ case BPF_ALU|BPF_XOR|BPF_K:
+ case BPF_ALU|BPF_LSH|BPF_K:
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = BPF_OP(s->code);
+ if (alter) {
+ if (s->k == 0) {
+ /*
+ * Optimize operations where the constant
+ * is zero.
+ *
+ * Don't optimize away "sub #0"
+ * as it may be needed later to
+ * fixup the generated math code.
+ *
+ * Fail if we're dividing by zero or taking
+ * a modulus by zero.
+ */
+ if (op == BPF_ADD ||
+ op == BPF_LSH || op == BPF_RSH ||
+ op == BPF_OR || op == BPF_XOR) {
+ s->code = NOP;
+ break;
+ }
+ if (op == BPF_MUL || op == BPF_AND) {
+ s->code = BPF_LD|BPF_IMM;
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ if (op == BPF_DIV)
+ opt_error(opt_state,
+ "division by zero");
+ if (op == BPF_MOD)
+ opt_error(opt_state,
+ "modulus by zero");
+ }
+ if (opt_state->vmap[val[A_ATOM]].is_const) {
+ fold_op(opt_state, s, val[A_ATOM], K(s->k));
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ }
+ val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k));
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ case BPF_ALU|BPF_SUB|BPF_X:
+ case BPF_ALU|BPF_MUL|BPF_X:
+ case BPF_ALU|BPF_DIV|BPF_X:
+ case BPF_ALU|BPF_MOD|BPF_X:
+ case BPF_ALU|BPF_AND|BPF_X:
+ case BPF_ALU|BPF_OR|BPF_X:
+ case BPF_ALU|BPF_XOR|BPF_X:
+ case BPF_ALU|BPF_LSH|BPF_X:
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = BPF_OP(s->code);
+ if (alter && opt_state->vmap[val[X_ATOM]].is_const) {
+ if (opt_state->vmap[val[A_ATOM]].is_const) {
+ fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]);
+ val[A_ATOM] = K(s->k);
+ }
+ else {
+ s->code = BPF_ALU|BPF_K|op;
+ s->k = opt_state->vmap[val[X_ATOM]].const_val;
+ if ((op == BPF_LSH || op == BPF_RSH) &&
+ s->k > 31)
+ opt_error(opt_state,
+ "shift by more than 31 bits");
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ val[A_ATOM] =
+ F(opt_state, s->code, val[A_ATOM], K(s->k));
+ }
+ break;
+ }
+ /*
+ * Check if we're doing something to an accumulator
+ * that is 0, and simplify. This may not seem like
+ * much of a simplification but it could open up further
+ * optimizations.
+ * XXX We could also check for mul by 1, etc.
+ */
+ if (alter && opt_state->vmap[val[A_ATOM]].is_const
+ && opt_state->vmap[val[A_ATOM]].const_val == 0) {
+ if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) {
+ s->code = BPF_MISC|BPF_TXA;
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+ }
+ else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD ||
+ op == BPF_AND || op == BPF_LSH || op == BPF_RSH) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = 0;
+ vstore(s, &val[A_ATOM], K(s->k), alter);
+ break;
+ }
+ else if (op == BPF_NEG) {
+ s->code = NOP;
+ break;
+ }
+ }
+ val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]);
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+
+ case BPF_LD|BPF_MEM:
+ v = val[s->k];
+ if (alter && opt_state->vmap[v].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = opt_state->vmap[v].const_val;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ vstore(s, &val[X_ATOM], val[A_ATOM], alter);
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ v = val[s->k];
+ if (alter && opt_state->vmap[v].is_const) {
+ s->code = BPF_LDX|BPF_IMM;
+ s->k = opt_state->vmap[v].const_val;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ST:
+ vstore(s, &val[s->k], val[A_ATOM], alter);
+ break;
+
+ case BPF_STX:
+ vstore(s, &val[s->k], val[X_ATOM], alter);
+ break;
+ }
+}
+
+static void
+deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[])
+{
+ register int atom;
+
+ atom = atomuse(s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ last[X_ATOM] = 0;
+ last[A_ATOM] = 0;
+ }
+ else
+ last[atom] = 0;
+ }
+ atom = atomdef(s);
+ if (atom >= 0) {
+ if (last[atom]) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ last[atom]->code = NOP;
+ }
+ last[atom] = s;
+ }
+}
+
+static void
+opt_deadstores(opt_state_t *opt_state, register struct block *b)
+{
+ register struct slist *s;
+ register int atom;
+ struct stmt *last[N_ATOMS];
+
+ memset((char *)last, 0, sizeof last);
+
+ for (s = b->stmts; s != 0; s = s->next)
+ deadstmt(opt_state, &s->s, last);
+ deadstmt(opt_state, &b->s, last);
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (last[atom] && !ATOMELEM(b->out_use, atom)) {
+ last[atom]->code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+}
+
+static void
+opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
+{
+ struct slist *s;
+ struct edge *p;
+ int i;
+ bpf_u_int32 aval, xval;
+
+#if 0
+ for (s = b->stmts; s && s->next; s = s->next)
+ if (BPF_CLASS(s->s.code) == BPF_JMP) {
+ do_stmts = 0;
+ break;
+ }
+#endif
+
+ /*
+ * Initialize the atom values.
+ */
+ p = b->in_edges;
+ if (p == 0) {
+ /*
+ * We have no predecessors, so everything is undefined
+ * upon entry to this block.
+ */
+ memset((char *)b->val, 0, sizeof(b->val));
+ } else {
+ /*
+ * Inherit values from our predecessors.
+ *
+ * First, get the values from the predecessor along the
+ * first edge leading to this node.
+ */
+ memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
+ /*
+ * Now look at all the other nodes leading to this node.
+ * If, for the predecessor along that edge, a register
+ * has a different value from the one we have (i.e.,
+ * control paths are merging, and the merging paths
+ * assign different values to that register), give the
+ * register the undefined value of 0.
+ */
+ while ((p = p->next) != NULL) {
+ for (i = 0; i < N_ATOMS; ++i)
+ if (b->val[i] != p->pred->val[i])
+ b->val[i] = 0;
+ }
+ }
+ aval = b->val[A_ATOM];
+ xval = b->val[X_ATOM];
+ for (s = b->stmts; s; s = s->next)
+ opt_stmt(opt_state, &s->s, b->val, do_stmts);
+
+ /*
+ * This is a special case: if we don't use anything from this
+ * block, and we load the accumulator or index register with a
+ * value that is already there, or if this block is a return,
+ * eliminate all the statements.
+ *
+ * XXX - what if it does a store? Presumably that falls under
+ * the heading of "if we don't use anything from this block",
+ * i.e., if we use any memory location set to a different
+ * value by this block, then we use something from this block.
+ *
+ * XXX - why does it matter whether we use anything from this
+ * block? If the accumulator or index register doesn't change
+ * its value, isn't that OK even if we use that value?
+ *
+ * XXX - if we load the accumulator with a different value,
+ * and the block ends with a conditional branch, we obviously
+ * can't eliminate it, as the branch depends on that value.
+ * For the index register, the conditional branch only depends
+ * on the index register value if the test is against the index
+ * register value rather than a constant; if nothing uses the
+ * value we put into the index register, and we're not testing
+ * against the index register's value, and there aren't any
+ * other problems that would keep us from eliminating this
+ * block, can we eliminate it?
+ */
+ if (do_stmts &&
+ ((b->out_use == 0 &&
+ aval != VAL_UNKNOWN && b->val[A_ATOM] == aval &&
+ xval != VAL_UNKNOWN && b->val[X_ATOM] == xval) ||
+ BPF_CLASS(b->s.code) == BPF_RET)) {
+ if (b->stmts != 0) {
+ b->stmts = 0;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ }
+ } else {
+ opt_peep(opt_state, b);
+ opt_deadstores(opt_state, b);
+ }
+ /*
+ * Set up values for branch optimizer.
+ */
+ if (BPF_SRC(b->s.code) == BPF_K)
+ b->oval = K(b->s.k);
+ else
+ b->oval = b->val[X_ATOM];
+ b->et.code = b->s.code;
+ b->ef.code = -b->s.code;
+}
+
+/*
+ * Return true if any register that is used on exit from 'succ', has
+ * an exit value that is different from the corresponding exit value
+ * from 'b'.
+ */
+static int
+use_conflict(struct block *b, struct block *succ)
+{
+ int atom;
+ atomset use = succ->out_use;
+
+ if (use == 0)
+ return 0;
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (ATOMELEM(use, atom))
+ if (b->val[atom] != succ->val[atom])
+ return 1;
+ return 0;
+}
+
+/*
+ * Given a block that is the successor of an edge, and an edge that
+ * dominates that edge, return either a pointer to a child of that
+ * block (a block to which that block jumps) if that block is a
+ * candidate to replace the successor of the latter edge or NULL
+ * if neither of the children of the first block are candidates.
+ */
+static struct block *
+fold_edge(struct block *child, struct edge *ep)
+{
+ int sense;
+ bpf_u_int32 aval0, aval1, oval0, oval1;
+ int code = ep->code;
+
+ if (code < 0) {
+ /*
+ * This edge is a "branch if false" edge.
+ */
+ code = -code;
+ sense = 0;
+ } else {
+ /*
+ * This edge is a "branch if true" edge.
+ */
+ sense = 1;
+ }
+
+ /*
+ * If the opcode for the branch at the end of the block we
+ * were handed isn't the same as the opcode for the branch
+ * to which the edge we were handed corresponds, the tests
+ * for those branches aren't testing the same conditions,
+ * so the blocks to which the first block branches aren't
+ * candidates to replace the successor of the edge.
+ */
+ if (child->s.code != code)
+ return 0;
+
+ aval0 = child->val[A_ATOM];
+ oval0 = child->oval;
+ aval1 = ep->pred->val[A_ATOM];
+ oval1 = ep->pred->oval;
+
+ /*
+ * If the A register value on exit from the successor block
+ * isn't the same as the A register value on exit from the
+ * predecessor of the edge, the blocks to which the first
+ * block branches aren't candidates to replace the successor
+ * of the edge.
+ */
+ if (aval0 != aval1)
+ return 0;
+
+ if (oval0 == oval1)
+ /*
+ * The operands of the branch instructions are
+ * identical, so the branches are testing the
+ * same condition, and the result is true if a true
+ * branch was taken to get here, otherwise false.
+ */
+ return sense ? JT(child) : JF(child);
+
+ if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
+ /*
+ * At this point, we only know the comparison if we
+ * came down the true branch, and it was an equality
+ * comparison with a constant.
+ *
+ * I.e., if we came down the true branch, and the branch
+ * was an equality comparison with a constant, we know the
+ * accumulator contains that constant. If we came down
+ * the false branch, or the comparison wasn't with a
+ * constant, we don't know what was in the accumulator.
+ *
+ * We rely on the fact that distinct constants have distinct
+ * value numbers.
+ */
+ return JF(child);
+
+ return 0;
+}
+
+/*
+ * If we can make this edge go directly to a child of the edge's current
+ * successor, do so.
+ */
+static void
+opt_j(opt_state_t *opt_state, struct edge *ep)
+{
+ register u_int i, k;
+ register struct block *target;
+
+ /*
+ * Does this edge go to a block where, if the test
+ * at the end of it succeeds, it goes to a block
+ * that's a leaf node of the DAG, i.e. a return
+ * statement?
+ * If so, there's nothing to optimize.
+ */
+ if (JT(ep->succ) == 0)
+ return;
+
+ /*
+ * Does this edge go to a block that goes, in turn, to
+ * the same block regardless of whether the test at the
+ * end succeeds or fails?
+ */
+ if (JT(ep->succ) == JF(ep->succ)) {
+ /*
+ * Common branch targets can be eliminated, provided
+ * there is no data dependency.
+ *
+ * Check whether any register used on exit from the
+ * block to which the successor of this edge goes
+ * has a value at that point that's different from
+ * the value it has on exit from the predecessor of
+ * this edge. If not, the predecessor of this edge
+ * can just go to the block to which the successor
+ * of this edge goes, bypassing the successor of this
+ * edge, as the successor of this edge isn't doing
+ * any calculations whose results are different
+ * from what the blocks before it did and isn't
+ * doing any tests the results of which matter.
+ */
+ if (!use_conflict(ep->pred, JT(ep->succ))) {
+ /*
+ * No, there isn't.
+ * Make this edge go to the block to
+ * which the successor of that edge
+ * goes.
+ *
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
+ opt_state->done = 0;
+ ep->succ = JT(ep->succ);
+ }
+ }
+ /*
+ * For each edge dominator that matches the successor of this
+ * edge, promote the edge successor to the its grandchild.
+ *
+ * XXX We violate the set abstraction here in favor a reasonably
+ * efficient loop.
+ */
+ top:
+ for (i = 0; i < opt_state->edgewords; ++i) {
+ /* i'th word in the bitset of dominators */
+ register bpf_u_int32 x = ep->edom[i];
+
+ while (x != 0) {
+ /* Find the next dominator in that word and mark it as found */
+ k = lowest_set_bit(x);
+ x &=~ ((bpf_u_int32)1 << k);
+ k += i * BITS_PER_WORD;
+
+ target = fold_edge(ep->succ, opt_state->edges[k]);
+ /*
+ * We have a candidate to replace the successor
+ * of ep.
+ *
+ * Check that there is no data dependency between
+ * nodes that will be violated if we move the edge;
+ * i.e., if any register used on exit from the
+ * candidate has a value at that point different
+ * from the value it has when we exit the
+ * predecessor of that edge, there's a data
+ * dependency that will be violated.
+ */
+ if (target != 0 && !use_conflict(ep->pred, target)) {
+ /*
+ * It's safe to replace the successor of
+ * ep; do so, and note that we've made
+ * at least one change.
+ *
+ * XXX - this is one of the operations that
+ * happens when the optimizer gets into
+ * one of those infinite loops.
+ */
+ opt_state->done = 0;
+ ep->succ = target;
+ if (JT(target) != 0)
+ /*
+ * Start over unless we hit a leaf.
+ */
+ goto top;
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * XXX - is this, and and_pullup(), what's described in section 6.1.2
+ * "Predicate Assertion Propagation" in the BPF+ paper?
+ *
+ * Note that this looks at block dominators, not edge dominators.
+ * Don't think so.
+ *
+ * "A or B" compiles into
+ *
+ * A
+ * t / \ f
+ * / B
+ * / t / \ f
+ * \ /
+ * \ /
+ * X
+ *
+ *
+ */
+static void
+or_pullup(opt_state_t *opt_state, struct block *b)
+{
+ bpf_u_int32 val;
+ int at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ * XXX why?
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ /*
+ * For the first edge in the list of edges coming into this block,
+ * see whether the predecessor of that edge comes here via a true
+ * branch or a false branch.
+ */
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred); /* jt */
+ else
+ diffp = &JF(b->in_edges->pred); /* jf */
+
+ /*
+ * diffp is a pointer to a pointer to the block.
+ *
+ * Go down the false chain looking as far as you can,
+ * making sure that each jump-compare is doing the
+ * same as the original block.
+ *
+ * If you reach the bottom before you reach a
+ * different jump-compare, just exit. There's nothing
+ * to do here. XXX - no, this version is checking for
+ * the value leaving the block; that's from the BPF+
+ * pullup routine.
+ */
+ at_top = 1;
+ for (;;) {
+ /*
+ * Done if that's not going anywhere XXX
+ */
+ if (*diffp == 0)
+ return;
+
+ /*
+ * Done if that predecessor blah blah blah isn't
+ * going the same place we're going XXX
+ *
+ * Does the true edge of this block point to the same
+ * location as the true edge of b?
+ */
+ if (JT(*diffp) != JT(b))
+ return;
+
+ /*
+ * Done if this node isn't a dominator of that
+ * node blah blah blah XXX
+ *
+ * Does b dominate diffp?
+ */
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ /*
+ * Break out of the loop if that node's value of A
+ * isn't the value of A above XXX
+ */
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ /*
+ * Get the JF for that node XXX
+ * Go down the false path.
+ */
+ diffp = &JF(*diffp);
+ at_top = 0;
+ }
+
+ /*
+ * Now that we've found a different jump-compare in a chain
+ * below b, search further down until we find another
+ * jump-compare that looks at the original value. This
+ * jump-compare should get pulled up. XXX again we're
+ * comparing values not jump-compares.
+ */
+ samep = &JF(*diffp);
+ for (;;) {
+ /*
+ * Done if that's not going anywhere XXX
+ */
+ if (*samep == 0)
+ return;
+
+ /*
+ * Done if that predecessor blah blah blah isn't
+ * going the same place we're going XXX
+ */
+ if (JT(*samep) != JT(b))
+ return;
+
+ /*
+ * Done if this node isn't a dominator of that
+ * node blah blah blah XXX
+ *
+ * Does b dominate samep?
+ */
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ /*
+ * Break out of the loop if that node's value of A
+ * is the value of A above XXX
+ */
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between dp0 and dp1. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JF(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JF(pull);
+ JF(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ /*
+ * XXX - this is one of the operations that happens when the
+ * optimizer gets into one of those infinite loops.
+ */
+ opt_state->done = 0;
+}
+
+static void
+and_pullup(opt_state_t *opt_state, struct block *b)
+{
+ bpf_u_int32 val;
+ int at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred);
+ else
+ diffp = &JF(b->in_edges->pred);
+
+ at_top = 1;
+ for (;;) {
+ if (*diffp == 0)
+ return;
+
+ if (JF(*diffp) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ diffp = &JT(*diffp);
+ at_top = 0;
+ }
+ samep = &JT(*diffp);
+ for (;;) {
+ if (*samep == 0)
+ return;
+
+ if (JF(*samep) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between diffp and samep. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JT(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JT(pull);
+ JT(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ /*
+ * XXX - this is one of the operations that happens when the
+ * optimizer gets into one of those infinite loops.
+ */
+ opt_state->done = 0;
+}
+
+static void
+opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts)
+{
+ int i, maxlevel;
+ struct block *p;
+
+ init_val(opt_state);
+ maxlevel = ic->root->level;
+
+ find_inedges(opt_state, ic->root);
+ for (i = maxlevel; i >= 0; --i)
+ for (p = opt_state->levels[i]; p; p = p->link)
+ opt_blk(opt_state, p, do_stmts);
+
+ if (do_stmts)
+ /*
+ * No point trying to move branches; it can't possibly
+ * make a difference at this point.
+ *
+ * XXX - this might be after we detect a loop where
+ * we were just looping infinitely moving branches
+ * in such a fashion that we went through two or more
+ * versions of the machine code, eventually returning
+ * to the first version. (We're really not doing a
+ * full loop detection, we're just testing for two
+ * passes in a row where where we do nothing but
+ * move branches.)
+ */
+ return;
+
+ /*
+ * Is this what the BPF+ paper describes in sections 6.1.1,
+ * 6.1.2, and 6.1.3?
+ */
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = opt_state->levels[i]; p; p = p->link) {
+ opt_j(opt_state, &p->et);
+ opt_j(opt_state, &p->ef);
+ }
+ }
+
+ find_inedges(opt_state, ic->root);
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = opt_state->levels[i]; p; p = p->link) {
+ or_pullup(opt_state, p);
+ and_pullup(opt_state, p);
+ }
+ }
+}
+
+static inline void
+link_inedge(struct edge *parent, struct block *child)
+{
+ parent->next = child->in_edges;
+ child->in_edges = parent;
+}
+
+static void
+find_inedges(opt_state_t *opt_state, struct block *root)
+{
+ u_int i;
+ int level;
+ struct block *b;
+
+ for (i = 0; i < opt_state->n_blocks; ++i)
+ opt_state->blocks[i]->in_edges = 0;
+
+ /*
+ * Traverse the graph, adding each edge to the predecessor
+ * list of its successors. Skip the leaves (i.e. level 0).
+ */
+ for (level = root->level; level > 0; --level) {
+ for (b = opt_state->levels[level]; b != 0; b = b->link) {
+ link_inedge(&b->et, JT(b));
+ link_inedge(&b->ef, JF(b));
+ }
+ }
+}
+
+static void
+opt_root(struct block **b)
+{
+ struct slist *tmp, *s;
+
+ s = (*b)->stmts;
+ (*b)->stmts = 0;
+ while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
+ *b = JT(*b);
+
+ tmp = (*b)->stmts;
+ if (tmp != 0)
+ sappend(s, tmp);
+ (*b)->stmts = s;
+
+ /*
+ * If the root node is a return, then there is no
+ * point executing any statements (since the bpf machine
+ * has no side effects).
+ */
+ if (BPF_CLASS((*b)->s.code) == BPF_RET)
+ (*b)->stmts = 0;
+}
+
+static void
+opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
+{
+
+#ifdef BDEBUG
+ if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+ printf("opt_loop(root, %d) begin\n", do_stmts);
+ opt_dump(opt_state, ic);
+ }
+#endif
+
+ /*
+ * XXX - optimizer loop detection.
+ */
+ int loop_count = 0;
+ for (;;) {
+ opt_state->done = 1;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 0;
+ find_levels(opt_state, ic);
+ find_dom(opt_state, ic->root);
+ find_closure(opt_state, ic->root);
+ find_ud(opt_state, ic->root);
+ find_edom(opt_state, ic->root);
+ opt_blks(opt_state, ic, do_stmts);
+#ifdef BDEBUG
+ if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+ printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done);
+ opt_dump(opt_state, ic);
+ }
+#endif
+
+ /*
+ * Was anything done in this optimizer pass?
+ */
+ if (opt_state->done) {
+ /*
+ * No, so we've reached a fixed point.
+ * We're done.
+ */
+ break;
+ }
+
+ /*
+ * XXX - was anything done other than branch movement
+ * in this pass?
+ */
+ if (opt_state->non_branch_movement_performed) {
+ /*
+ * Yes. Clear any loop-detection counter;
+ * we're making some form of progress (assuming
+ * we can't get into a cycle doing *other*
+ * optimizations...).
+ */
+ loop_count = 0;
+ } else {
+ /*
+ * No - increment the counter, and quit if
+ * it's up to 100.
+ */
+ loop_count++;
+ if (loop_count >= 100) {
+ /*
+ * We've done nothing but branch movement
+ * for 100 passes; we're probably
+ * in a cycle and will never reach a
+ * fixed point.
+ *
+ * XXX - yes, we really need a non-
+ * heuristic way of detecting a cycle.
+ */
+ opt_state->done = 1;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Optimize the filter code in its dag representation.
+ * Return 0 on success, -1 on error.
+ */
+int
+bpf_optimize(struct icode *ic, char *errbuf)
+{
+ opt_state_t opt_state;
+
+ memset(&opt_state, 0, sizeof(opt_state));
+ opt_state.errbuf = errbuf;
+ opt_state.non_branch_movement_performed = 0;
+ if (setjmp(opt_state.top_ctx)) {
+ opt_cleanup(&opt_state);
+ return -1;
+ }
+ opt_init(&opt_state, ic);
+ opt_loop(&opt_state, ic, 0);
+ opt_loop(&opt_state, ic, 1);
+ intern_blocks(&opt_state, ic);
+#ifdef BDEBUG
+ if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+ printf("after intern_blocks()\n");
+ opt_dump(&opt_state, ic);
+ }
+#endif
+ opt_root(&ic->root);
+#ifdef BDEBUG
+ if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
+ printf("after opt_root()\n");
+ opt_dump(&opt_state, ic);
+ }
+#endif
+ opt_cleanup(&opt_state);
+ return 0;
+}
+
+static void
+make_marks(struct icode *ic, struct block *p)
+{
+ if (!isMarked(ic, p)) {
+ Mark(ic, p);
+ if (BPF_CLASS(p->s.code) != BPF_RET) {
+ make_marks(ic, JT(p));
+ make_marks(ic, JF(p));
+ }
+ }
+}
+
+/*
+ * Mark code array such that isMarked(ic->cur_mark, i) is true
+ * only for nodes that are alive.
+ */
+static void
+mark_code(struct icode *ic)
+{
+ ic->cur_mark += 1;
+ make_marks(ic, ic->root);
+}
+
+/*
+ * True iff the two stmt lists load the same value from the packet into
+ * the accumulator.
+ */
+static int
+eq_slist(struct slist *x, struct slist *y)
+{
+ for (;;) {
+ while (x && x->s.code == NOP)
+ x = x->next;
+ while (y && y->s.code == NOP)
+ y = y->next;
+ if (x == 0)
+ return y == 0;
+ if (y == 0)
+ return x == 0;
+ if (x->s.code != y->s.code || x->s.k != y->s.k)
+ return 0;
+ x = x->next;
+ y = y->next;
+ }
+}
+
+static inline int
+eq_blk(struct block *b0, struct block *b1)
+{
+ if (b0->s.code == b1->s.code &&
+ b0->s.k == b1->s.k &&
+ b0->et.succ == b1->et.succ &&
+ b0->ef.succ == b1->ef.succ)
+ return eq_slist(b0->stmts, b1->stmts);
+ return 0;
+}
+
+static void
+intern_blocks(opt_state_t *opt_state, struct icode *ic)
+{
+ struct block *p;
+ u_int i, j;
+ int done1; /* don't shadow global */
+ top:
+ done1 = 1;
+ for (i = 0; i < opt_state->n_blocks; ++i)
+ opt_state->blocks[i]->link = 0;
+
+ mark_code(ic);
+
+ for (i = opt_state->n_blocks - 1; i != 0; ) {
+ --i;
+ if (!isMarked(ic, opt_state->blocks[i]))
+ continue;
+ for (j = i + 1; j < opt_state->n_blocks; ++j) {
+ if (!isMarked(ic, opt_state->blocks[j]))
+ continue;
+ if (eq_blk(opt_state->blocks[i], opt_state->blocks[j])) {
+ opt_state->blocks[i]->link = opt_state->blocks[j]->link ?
+ opt_state->blocks[j]->link : opt_state->blocks[j];
+ break;
+ }
+ }
+ }
+ for (i = 0; i < opt_state->n_blocks; ++i) {
+ p = opt_state->blocks[i];
+ if (JT(p) == 0)
+ continue;
+ if (JT(p)->link) {
+ done1 = 0;
+ JT(p) = JT(p)->link;
+ }
+ if (JF(p)->link) {
+ done1 = 0;
+ JF(p) = JF(p)->link;
+ }
+ }
+ if (!done1)
+ goto top;
+}
+
+static void
+opt_cleanup(opt_state_t *opt_state)
+{
+ free((void *)opt_state->vnode_base);
+ free((void *)opt_state->vmap);
+ free((void *)opt_state->edges);
+ free((void *)opt_state->space);
+ free((void *)opt_state->levels);
+ free((void *)opt_state->blocks);
+}
+
+/*
+ * For optimizer errors.
+ */
+static void PCAP_NORETURN
+opt_error(opt_state_t *opt_state, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (opt_state->errbuf != NULL) {
+ va_start(ap, fmt);
+ (void)vsnprintf(opt_state->errbuf,
+ PCAP_ERRBUF_SIZE, fmt, ap);
+ va_end(ap);
+ }
+ longjmp(opt_state->top_ctx, 1);
+ /* NOTREACHED */
+}
+
+/*
+ * Return the number of stmts in 's'.
+ */
+static u_int
+slength(struct slist *s)
+{
+ u_int n = 0;
+
+ for (; s; s = s->next)
+ if (s->s.code != NOP)
+ ++n;
+ return n;
+}
+
+/*
+ * Return the number of nodes reachable by 'p'.
+ * All nodes should be initially unmarked.
+ */
+static int
+count_blocks(struct icode *ic, struct block *p)
+{
+ if (p == 0 || isMarked(ic, p))
+ return 0;
+ Mark(ic, p);
+ return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1;
+}
+
+/*
+ * Do a depth first search on the flow graph, numbering the
+ * the basic blocks, and entering them into the 'blocks' array.`
+ */
+static void
+number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p)
+{
+ u_int n;
+
+ if (p == 0 || isMarked(ic, p))
+ return;
+
+ Mark(ic, p);
+ n = opt_state->n_blocks++;
+ if (opt_state->n_blocks == 0) {
+ /*
+ * Overflow.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+ p->id = n;
+ opt_state->blocks[n] = p;
+
+ number_blks_r(opt_state, ic, JT(p));
+ number_blks_r(opt_state, ic, JF(p));
+}
+
+/*
+ * Return the number of stmts in the flowgraph reachable by 'p'.
+ * The nodes should be unmarked before calling.
+ *
+ * Note that "stmts" means "instructions", and that this includes
+ *
+ * side-effect statements in 'p' (slength(p->stmts));
+ *
+ * statements in the true branch from 'p' (count_stmts(JT(p)));
+ *
+ * statements in the false branch from 'p' (count_stmts(JF(p)));
+ *
+ * the conditional jump itself (1);
+ *
+ * an extra long jump if the true branch requires it (p->longjt);
+ *
+ * an extra long jump if the false branch requires it (p->longjf).
+ */
+static u_int
+count_stmts(struct icode *ic, struct block *p)
+{
+ u_int n;
+
+ if (p == 0 || isMarked(ic, p))
+ return 0;
+ Mark(ic, p);
+ n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p));
+ return slength(p->stmts) + n + 1 + p->longjt + p->longjf;
+}
+
+/*
+ * Allocate memory. All allocation is done before optimization
+ * is begun. A linear bound on the size of all data structures is computed
+ * from the total number of blocks and/or statements.
+ */
+static void
+opt_init(opt_state_t *opt_state, struct icode *ic)
+{
+ bpf_u_int32 *p;
+ int i, n, max_stmts;
+ u_int product;
+ size_t block_memsize, edge_memsize;
+
+ /*
+ * First, count the blocks, so we can malloc an array to map
+ * block number to block. Then, put the blocks into the array.
+ */
+ unMarkAll(ic);
+ n = count_blocks(ic, ic->root);
+ opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks));
+ if (opt_state->blocks == NULL)
+ opt_error(opt_state, "malloc");
+ unMarkAll(ic);
+ opt_state->n_blocks = 0;
+ number_blks_r(opt_state, ic, ic->root);
+
+ /*
+ * This "should not happen".
+ */
+ if (opt_state->n_blocks == 0)
+ opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue");
+
+ opt_state->n_edges = 2 * opt_state->n_blocks;
+ if ((opt_state->n_edges / 2) != opt_state->n_blocks) {
+ /*
+ * Overflow.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+ opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges));
+ if (opt_state->edges == NULL) {
+ opt_error(opt_state, "malloc");
+ }
+
+ /*
+ * The number of levels is bounded by the number of nodes.
+ */
+ opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels));
+ if (opt_state->levels == NULL) {
+ opt_error(opt_state, "malloc");
+ }
+
+ opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1;
+ opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1;
+
+ /*
+ * Make sure opt_state->n_blocks * opt_state->nodewords fits
+ * in a u_int; we use it as a u_int number-of-iterations
+ * value.
+ */
+ product = opt_state->n_blocks * opt_state->nodewords;
+ if ((product / opt_state->n_blocks) != opt_state->nodewords) {
+ /*
+ * XXX - just punt and don't try to optimize?
+ * In practice, this is unlikely to happen with
+ * a normal filter.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for that doesn't
+ * overflow.
+ */
+ block_memsize = (size_t)2 * product * sizeof(*opt_state->space);
+ if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure opt_state->n_edges * opt_state->edgewords fits
+ * in a u_int; we use it as a u_int number-of-iterations
+ * value.
+ */
+ product = opt_state->n_edges * opt_state->edgewords;
+ if ((product / opt_state->n_edges) != opt_state->edgewords) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for that doesn't
+ * overflow.
+ */
+ edge_memsize = (size_t)product * sizeof(*opt_state->space);
+ if (edge_memsize / product != sizeof(*opt_state->space)) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for both of them dosn't
+ * overflow.
+ */
+ if (block_memsize > SIZE_MAX - edge_memsize) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /* XXX */
+ opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize);
+ if (opt_state->space == NULL) {
+ opt_error(opt_state, "malloc");
+ }
+ p = opt_state->space;
+ opt_state->all_dom_sets = p;
+ for (i = 0; i < n; ++i) {
+ opt_state->blocks[i]->dom = p;
+ p += opt_state->nodewords;
+ }
+ opt_state->all_closure_sets = p;
+ for (i = 0; i < n; ++i) {
+ opt_state->blocks[i]->closure = p;
+ p += opt_state->nodewords;
+ }
+ opt_state->all_edge_sets = p;
+ for (i = 0; i < n; ++i) {
+ register struct block *b = opt_state->blocks[i];
+
+ b->et.edom = p;
+ p += opt_state->edgewords;
+ b->ef.edom = p;
+ p += opt_state->edgewords;
+ b->et.id = i;
+ opt_state->edges[i] = &b->et;
+ b->ef.id = opt_state->n_blocks + i;
+ opt_state->edges[opt_state->n_blocks + i] = &b->ef;
+ b->et.pred = b;
+ b->ef.pred = b;
+ }
+ max_stmts = 0;
+ for (i = 0; i < n; ++i)
+ max_stmts += slength(opt_state->blocks[i]->stmts) + 1;
+ /*
+ * We allocate at most 3 value numbers per statement,
+ * so this is an upper bound on the number of valnodes
+ * we'll need.
+ */
+ opt_state->maxval = 3 * max_stmts;
+ opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap));
+ if (opt_state->vmap == NULL) {
+ opt_error(opt_state, "malloc");
+ }
+ opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base));
+ if (opt_state->vnode_base == NULL) {
+ opt_error(opt_state, "malloc");
+ }
+}
+
+/*
+ * This is only used when supporting optimizer debugging. It is
+ * global state, so do *not* do more than one compile in parallel
+ * and expect it to provide meaningful information.
+ */
+#ifdef BDEBUG
+int bids[NBIDS];
+#endif
+
+static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
+
+/*
+ * Returns true if successful. Returns false if a branch has
+ * an offset that is too large. If so, we have marked that
+ * branch so that on a subsequent iteration, it will be treated
+ * properly.
+ */
+static int
+convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p)
+{
+ struct bpf_insn *dst;
+ struct slist *src;
+ u_int slen;
+ u_int off;
+ struct slist **offset = NULL;
+
+ if (p == 0 || isMarked(ic, p))
+ return (1);
+ Mark(ic, p);
+
+ if (convert_code_r(conv_state, ic, JF(p)) == 0)
+ return (0);
+ if (convert_code_r(conv_state, ic, JT(p)) == 0)
+ return (0);
+
+ slen = slength(p->stmts);
+ dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf);
+ /* inflate length by any extra jumps */
+
+ p->offset = (int)(dst - conv_state->fstart);
+
+ /* generate offset[] for convenience */
+ if (slen) {
+ offset = (struct slist **)calloc(slen, sizeof(struct slist *));
+ if (!offset) {
+ conv_error(conv_state, "not enough core");
+ /*NOTREACHED*/
+ }
+ }
+ src = p->stmts;
+ for (off = 0; off < slen && src; off++) {
+#if 0
+ printf("off=%d src=%x\n", off, src);
+#endif
+ offset[off] = src;
+ src = src->next;
+ }
+
+ off = 0;
+ for (src = p->stmts; src; src = src->next) {
+ if (src->s.code == NOP)
+ continue;
+ dst->code = (u_short)src->s.code;
+ dst->k = src->s.k;
+
+ /* fill block-local relative jump */
+ if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) {
+#if 0
+ if (src->s.jt || src->s.jf) {
+ free(offset);
+ conv_error(conv_state, "illegal jmp destination");
+ /*NOTREACHED*/
+ }
+#endif
+ goto filled;
+ }
+ if (off == slen - 2) /*???*/
+ goto filled;
+
+ {
+ u_int i;
+ int jt, jf;
+ const char ljerr[] = "%s for block-local relative jump: off=%d";
+
+#if 0
+ printf("code=%x off=%d %x %x\n", src->s.code,
+ off, src->s.jt, src->s.jf);
+#endif
+
+ if (!src->s.jt || !src->s.jf) {
+ free(offset);
+ conv_error(conv_state, ljerr, "no jmp destination", off);
+ /*NOTREACHED*/
+ }
+
+ jt = jf = 0;
+ for (i = 0; i < slen; i++) {
+ if (offset[i] == src->s.jt) {
+ if (jt) {
+ free(offset);
+ conv_error(conv_state, ljerr, "multiple matches", off);
+ /*NOTREACHED*/
+ }
+
+ if (i - off - 1 >= 256) {
+ free(offset);
+ conv_error(conv_state, ljerr, "out-of-range jump", off);
+ /*NOTREACHED*/
+ }
+ dst->jt = (u_char)(i - off - 1);
+ jt++;
+ }
+ if (offset[i] == src->s.jf) {
+ if (jf) {
+ free(offset);
+ conv_error(conv_state, ljerr, "multiple matches", off);
+ /*NOTREACHED*/
+ }
+ if (i - off - 1 >= 256) {
+ free(offset);
+ conv_error(conv_state, ljerr, "out-of-range jump", off);
+ /*NOTREACHED*/
+ }
+ dst->jf = (u_char)(i - off - 1);
+ jf++;
+ }
+ }
+ if (!jt || !jf) {
+ free(offset);
+ conv_error(conv_state, ljerr, "no destination found", off);
+ /*NOTREACHED*/
+ }
+ }
+filled:
+ ++dst;
+ ++off;
+ }
+ if (offset)
+ free(offset);
+
+#ifdef BDEBUG
+ if (dst - conv_state->fstart < NBIDS)
+ bids[dst - conv_state->fstart] = p->id + 1;
+#endif
+ dst->code = (u_short)p->s.code;
+ dst->k = p->s.k;
+ if (JT(p)) {
+ /* number of extra jumps inserted */
+ u_char extrajmps = 0;
+ off = JT(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256) {
+ /* offset too large for branch, must add a jump */
+ if (p->longjt == 0) {
+ /* mark this instruction and retry */
+ p->longjt++;
+ return(0);
+ }
+ dst->jt = extrajmps;
+ extrajmps++;
+ dst[extrajmps].code = BPF_JMP|BPF_JA;
+ dst[extrajmps].k = off - extrajmps;
+ }
+ else
+ dst->jt = (u_char)off;
+ off = JF(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256) {
+ /* offset too large for branch, must add a jump */
+ if (p->longjf == 0) {
+ /* mark this instruction and retry */
+ p->longjf++;
+ return(0);
+ }
+ /* branch if F to following jump */
+ /* if two jumps are inserted, F goes to second one */
+ dst->jf = extrajmps;
+ extrajmps++;
+ dst[extrajmps].code = BPF_JMP|BPF_JA;
+ dst[extrajmps].k = off - extrajmps;
+ }
+ else
+ dst->jf = (u_char)off;
+ }
+ return (1);
+}
+
+
+/*
+ * Convert flowgraph intermediate representation to the
+ * BPF array representation. Set *lenp to the number of instructions.
+ *
+ * This routine does *NOT* leak the memory pointed to by fp. It *must
+ * not* do free(fp) before returning fp; doing so would make no sense,
+ * as the BPF array pointed to by the return value of icode_to_fcode()
+ * must be valid - it's being returned for use in a bpf_program structure.
+ *
+ * If it appears that icode_to_fcode() is leaking, the problem is that
+ * the program using pcap_compile() is failing to free the memory in
+ * the BPF program when it's done - the leak is in the program, not in
+ * the routine that happens to be allocating the memory. (By analogy, if
+ * a program calls fopen() without ever calling fclose() on the FILE *,
+ * it will leak the FILE structure; the leak is not in fopen(), it's in
+ * the program.) Change the program to use pcap_freecode() when it's
+ * done with the filter program. See the pcap man page.
+ */
+struct bpf_insn *
+icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
+ char *errbuf)
+{
+ u_int n;
+ struct bpf_insn *fp;
+ conv_state_t conv_state;
+
+ conv_state.fstart = NULL;
+ conv_state.errbuf = errbuf;
+ if (setjmp(conv_state.top_ctx) != 0) {
+ free(conv_state.fstart);
+ return NULL;
+ }
+
+ /*
+ * Loop doing convert_code_r() until no branches remain
+ * with too-large offsets.
+ */
+ for (;;) {
+ unMarkAll(ic);
+ n = *lenp = count_stmts(ic, root);
+
+ fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
+ if (fp == NULL) {
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "malloc");
+ free(fp);
+ return NULL;
+ }
+ memset((char *)fp, 0, sizeof(*fp) * n);
+ conv_state.fstart = fp;
+ conv_state.ftail = fp + n;
+
+ unMarkAll(ic);
+ if (convert_code_r(&conv_state, ic, root))
+ break;
+ free(fp);
+ }
+
+ return fp;
+}
+
+/*
+ * For iconv_to_fconv() errors.
+ */
+static void PCAP_NORETURN
+conv_error(conv_state_t *conv_state, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)vsnprintf(conv_state->errbuf,
+ PCAP_ERRBUF_SIZE, fmt, ap);
+ va_end(ap);
+ longjmp(conv_state->top_ctx, 1);
+ /* NOTREACHED */
+}
+
+/*
+ * Make a copy of a BPF program and put it in the "fcode" member of
+ * a "pcap_t".
+ *
+ * If we fail to allocate memory for the copy, fill in the "errbuf"
+ * member of the "pcap_t" with an error message, and return -1;
+ * otherwise, return 0.
+ */
+int
+install_bpf_program(pcap_t *p, struct bpf_program *fp)
+{
+ size_t prog_size;
+
+ /*
+ * Validate the program.
+ */
+ if (!pcap_validate_filter(fp->bf_insns, fp->bf_len)) {
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "BPF program is not valid");
+ return (-1);
+ }
+
+ /*
+ * Free up any already installed program.
+ */
+ pcap_freecode(&p->fcode);
+
+ prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
+ p->fcode.bf_len = fp->bf_len;
+ p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
+ if (p->fcode.bf_insns == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (-1);
+ }
+ memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
+ return (0);
+}
+
+#ifdef BDEBUG
+static void
+dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog,
+ FILE *out)
+{
+ int icount, noffset;
+ int i;
+
+ if (block == NULL || isMarked(ic, block))
+ return;
+ Mark(ic, block);
+
+ icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
+ noffset = min(block->offset + icount, (int)prog->bf_len);
+
+ fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id);
+ for (i = block->offset; i < noffset; i++) {
+ fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i));
+ }
+ fprintf(out, "\" tooltip=\"");
+ for (i = 0; i < BPF_MEMWORDS; i++)
+ if (block->val[i] != VAL_UNKNOWN)
+ fprintf(out, "val[%d]=%d ", i, block->val[i]);
+ fprintf(out, "val[A]=%d ", block->val[A_ATOM]);
+ fprintf(out, "val[X]=%d", block->val[X_ATOM]);
+ fprintf(out, "\"");
+ if (JT(block) == NULL)
+ fprintf(out, ", peripheries=2");
+ fprintf(out, "];\n");
+
+ dot_dump_node(ic, JT(block), prog, out);
+ dot_dump_node(ic, JF(block), prog, out);
+}
+
+static void
+dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
+{
+ if (block == NULL || isMarked(ic, block))
+ return;
+ Mark(ic, block);
+
+ if (JT(block)) {
+ fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n",
+ block->id, JT(block)->id);
+ fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n",
+ block->id, JF(block)->id);
+ }
+ dot_dump_edge(ic, JT(block), out);
+ dot_dump_edge(ic, JF(block), out);
+}
+
+/* Output the block CFG using graphviz/DOT language
+ * In the CFG, block's code, value index for each registers at EXIT,
+ * and the jump relationship is show.
+ *
+ * example DOT for BPF `ip src host 1.1.1.1' is:
+ digraph BPF {
+ block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh [12]\n(001) jeq #0x800 jt 2 jf 5" tooltip="val[A]=0 val[X]=0"];
+ block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld [26]\n(003) jeq #0x1010101 jt 4 jf 5" tooltip="val[A]=0 val[X]=0"];
+ block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2];
+ block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2];
+ "block0":se -> "block1":n [label="T"];
+ "block0":sw -> "block3":n [label="F"];
+ "block1":se -> "block2":n [label="T"];
+ "block1":sw -> "block3":n [label="F"];
+ }
+ *
+ * After install graphviz on https://www.graphviz.org/, save it as bpf.dot
+ * and run `dot -Tpng -O bpf.dot' to draw the graph.
+ */
+static int
+dot_dump(struct icode *ic, char *errbuf)
+{
+ struct bpf_program f;
+ FILE *out = stdout;
+
+ memset(bids, 0, sizeof bids);
+ f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+ if (f.bf_insns == NULL)
+ return -1;
+
+ fprintf(out, "digraph BPF {\n");
+ unMarkAll(ic);
+ dot_dump_node(ic, ic->root, &f, out);
+ unMarkAll(ic);
+ dot_dump_edge(ic, ic->root, out);
+ fprintf(out, "}\n");
+
+ free((char *)f.bf_insns);
+ return 0;
+}
+
+static int
+plain_dump(struct icode *ic, char *errbuf)
+{
+ struct bpf_program f;
+
+ memset(bids, 0, sizeof bids);
+ f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+ if (f.bf_insns == NULL)
+ return -1;
+ bpf_dump(&f, 1);
+ putchar('\n');
+ free((char *)f.bf_insns);
+ return 0;
+}
+
+static void
+opt_dump(opt_state_t *opt_state, struct icode *ic)
+{
+ int status;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ /*
+ * If the CFG, in DOT format, is requested, output it rather than
+ * the code that would be generated from that graph.
+ */
+ if (pcap_print_dot_graph)
+ status = dot_dump(ic, errbuf);
+ else
+ status = plain_dump(ic, errbuf);
+ if (status == -1)
+ opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf);
+}
+#endif
diff --git a/optimize.h b/optimize.h
new file mode 100644
index 0000000..56b31f4
--- /dev/null
+++ b/optimize.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1990, 1991, 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.
+ */
+
+/*
+ * Some stuff for use when debugging the optimizer.
+ */
+#ifdef BDEBUG
+#define NBIDS 1000
+extern int bids[NBIDS];
+#endif
diff --git a/pcap-common.c b/pcap-common.c
new file mode 100644
index 0000000..51d0666
--- /dev/null
+++ b/pcap-common.c
@@ -0,0 +1,1676 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-common.c - common code for pcap and pcapng files
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#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"
+
+/*
+ * We don't write DLT_* values to capture files, because they're not the
+ * same on all platforms.
+ *
+ * Unfortunately, the various flavors of BSD have not always used the same
+ * numerical values for the same data types, and various patches to
+ * libpcap for non-BSD OSes have added their own DLT_* codes for link
+ * layer encapsulation types seen on those OSes, and those codes have had,
+ * in some cases, values that were also used, on other platforms, for other
+ * link layer encapsulation types.
+ *
+ * This means that capture files of a type whose numerical DLT_* code
+ * means different things on different BSDs, or with different versions
+ * of libpcap, can't always be read on systems other than those like
+ * the one running on the machine on which the capture was made.
+ *
+ * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes
+ * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_*
+ * codes to DLT_* codes when reading a savefile header.
+ *
+ * For those DLT_* codes that have, as far as we know, the same values on
+ * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as
+ * DLT_xxx; that way, captures of those types can still be read by
+ * versions of libpcap that map LINKTYPE_* values to DLT_* values, and
+ * captures of those types written by versions of libpcap that map DLT_
+ * values to LINKTYPE_ values can still be read by older versions
+ * of libpcap.
+ *
+ * The other LINKTYPE_* codes are given values starting at 100, in the
+ * hopes that no DLT_* code will be given one of those values.
+ *
+ * In order to ensure that a given LINKTYPE_* code's value will refer to
+ * the same encapsulation type on all platforms, you should not allocate
+ * a new LINKTYPE_* value without consulting
+ * "tcpdump-workers@lists.tcpdump.org". The tcpdump developers will
+ * allocate a value for you, and will not subsequently allocate it to
+ * anybody else; that value will be added to the "pcap.h" in the
+ * tcpdump.org Git repository, so that a future libpcap release will
+ * include it.
+ *
+ * You should, if possible, also contribute patches to libpcap and tcpdump
+ * to handle the new encapsulation type, so that they can also be checked
+ * into the tcpdump.org Git repository and so that they will appear in
+ * future libpcap and tcpdump releases.
+ *
+ * Do *NOT* assume that any values after the largest value in this file
+ * are available; you might not have the most up-to-date version of this
+ * file, and new values after that one might have been assigned. Also,
+ * do *NOT* use any values below 100 - those might already have been
+ * taken by one (or more!) organizations.
+ *
+ * Any platform that defines additional DLT_* codes should:
+ *
+ * request a LINKTYPE_* code and value from tcpdump.org,
+ * as per the above;
+ *
+ * add, in their version of libpcap, an entry to map
+ * those DLT_* codes to the corresponding LINKTYPE_*
+ * code;
+ *
+ * redefine, in their "net/bpf.h", any DLT_* values
+ * that collide with the values used by their additional
+ * DLT_* codes, to remove those collisions (but without
+ * making them collide with any of the LINKTYPE_*
+ * values equal to 50 or above; they should also avoid
+ * defining DLT_* values that collide with those
+ * LINKTYPE_* values, either).
+ */
+#define LINKTYPE_NULL DLT_NULL
+#define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */
+#define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */
+#define LINKTYPE_AX25 DLT_AX25
+#define LINKTYPE_PRONET DLT_PRONET
+#define LINKTYPE_CHAOS DLT_CHAOS
+#define LINKTYPE_IEEE802_5 DLT_IEEE802 /* DLT_IEEE802 is used for 802.5 Token Ring */
+#define LINKTYPE_ARCNET_BSD DLT_ARCNET /* BSD-style headers */
+#define LINKTYPE_SLIP DLT_SLIP
+#define LINKTYPE_PPP DLT_PPP
+#define LINKTYPE_FDDI DLT_FDDI
+
+/*
+ * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662
+ * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol
+ * field) at the beginning of the packet.
+ *
+ * This is for use when there is always such a header; the address field
+ * might be 0xff, for regular PPP, or it might be an address field for Cisco
+ * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco
+ * HDLC"). This is, for example, what you get with NetBSD's DLT_PPP_SERIAL.
+ *
+ * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that
+ * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL
+ * captures will be written out with a link type that NetBSD's tcpdump
+ * can read.
+ */
+#define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */
+
+#define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */
+
+#define LINKTYPE_SYMANTEC_FIREWALL 99 /* Symantec Enterprise Firewall */
+
+/*
+ * These correspond to DLT_s that have different values on different
+ * platforms; we map between these values in capture files and
+ * the DLT_ values as returned by pcap_datalink() and passed to
+ * pcap_open_dead().
+ */
+#define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */
+#define LINKTYPE_RAW 101 /* raw IP */
+#define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */
+#define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */
+
+/*
+ * Values starting with 104 are used for newly-assigned link-layer
+ * header type values; for those link-layer header types, the DLT_
+ * value returned by pcap_datalink() and passed to pcap_open_dead(),
+ * and the LINKTYPE_ value that appears in capture files, are the
+ * same.
+ *
+ * LINKTYPE_MATCHING_MIN is the lowest such value; LINKTYPE_MATCHING_MAX
+ * is the highest such value.
+ */
+#define LINKTYPE_MATCHING_MIN 104 /* lowest value in the "matching" range */
+
+#define LINKTYPE_C_HDLC 104 /* Cisco HDLC */
+#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */
+#define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */
+#define LINKTYPE_FRELAY 107 /* Frame Relay */
+#define LINKTYPE_LOOP 108 /* OpenBSD loopback */
+#define LINKTYPE_ENC 109 /* OpenBSD IPSEC enc */
+
+/*
+ * These three types are reserved for future use.
+ */
+#define LINKTYPE_LANE8023 110 /* ATM LANE + 802.3 */
+#define LINKTYPE_HIPPI 111 /* NetBSD HIPPI */
+#define LINKTYPE_HDLC 112 /* NetBSD HDLC framing */
+
+#define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */
+#define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */
+#define LINKTYPE_ECONET 115 /* Acorn Econet */
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define LINKTYPE_IPFILTER 116
+
+#define LINKTYPE_PFLOG 117 /* OpenBSD DLT_PFLOG */
+#define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */
+#define LINKTYPE_IEEE802_11_PRISM 119 /* 802.11 plus Prism II monitor mode radio metadata header */
+#define LINKTYPE_IEEE802_11_AIRONET 120 /* 802.11 plus FreeBSD Aironet driver radio metadata header */
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define LINKTYPE_HHDLC 121
+
+#define LINKTYPE_IP_OVER_FC 122 /* RFC 2625 IP-over-Fibre Channel */
+#define LINKTYPE_SUNATM 123 /* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define LINKTYPE_RIO 124 /* RapidIO */
+#define LINKTYPE_PCI_EXP 125 /* PCI Express */
+#define LINKTYPE_AURORA 126 /* Xilinx Aurora link layer */
+
+#define LINKTYPE_IEEE802_11_RADIOTAP 127 /* 802.11 plus radiotap radio metadata header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define LINKTYPE_TZSP 128 /* Tazmen Sniffer Protocol */
+
+#define LINKTYPE_ARCNET_LINUX 129 /* Linux-style headers */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The corresponding
+ * DLT_s are used for passing on chassis-internal
+ * metainformation such as QOS profiles, etc..
+ */
+#define LINKTYPE_JUNIPER_MLPPP 130
+#define LINKTYPE_JUNIPER_MLFR 131
+#define LINKTYPE_JUNIPER_ES 132
+#define LINKTYPE_JUNIPER_GGSN 133
+#define LINKTYPE_JUNIPER_MFR 134
+#define LINKTYPE_JUNIPER_ATM2 135
+#define LINKTYPE_JUNIPER_SERVICES 136
+#define LINKTYPE_JUNIPER_ATM1 137
+
+#define LINKTYPE_APPLE_IP_OVER_IEEE1394 138 /* Apple IP-over-IEEE 1394 cooked header */
+
+#define LINKTYPE_MTP2_WITH_PHDR 139
+#define LINKTYPE_MTP2 140
+#define LINKTYPE_MTP3 141
+#define LINKTYPE_SCCP 142
+
+#define LINKTYPE_DOCSIS 143 /* DOCSIS MAC frames */
+
+#define LINKTYPE_LINUX_IRDA 144 /* Linux-IrDA */
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define LINKTYPE_IBM_SP 145
+#define LINKTYPE_IBM_SN 146
+
+/*
+ * Reserved for private use. If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, in those cases, ask "tcpdump-workers@lists.tcpdump.org" for a
+ * new DLT_ and LINKTYPE_ value, as per the comment in pcap/bpf.h, and use
+ * the type you're given.
+ */
+#define LINKTYPE_USER0 147
+#define LINKTYPE_USER1 148
+#define LINKTYPE_USER2 149
+#define LINKTYPE_USER3 150
+#define LINKTYPE_USER4 151
+#define LINKTYPE_USER5 152
+#define LINKTYPE_USER6 153
+#define LINKTYPE_USER7 154
+#define LINKTYPE_USER8 155
+#define LINKTYPE_USER9 156
+#define LINKTYPE_USER10 157
+#define LINKTYPE_USER11 158
+#define LINKTYPE_USER12 159
+#define LINKTYPE_USER13 160
+#define LINKTYPE_USER14 161
+#define LINKTYPE_USER15 162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ * http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ */
+#define LINKTYPE_IEEE802_11_AVS 163 /* 802.11 plus AVS radio metadata header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The corresponding
+ * DLT_s are used for passing on chassis-internal
+ * metainformation such as QOS profiles, etc..
+ */
+#define LINKTYPE_JUNIPER_MONITOR 164
+
+/*
+ * BACnet MS/TP frames.
+ */
+#define LINKTYPE_BACNET_MS_TP 165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accommodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define LINKTYPE_PPP_PPPD 166
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define LINKTYPE_JUNIPER_PPPOE 167
+#define LINKTYPE_JUNIPER_PPPOE_ATM 168
+
+#define LINKTYPE_GPRS_LLC 169 /* GPRS LLC */
+#define LINKTYPE_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */
+#define LINKTYPE_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define LINKTYPE_GCOM_T1E1 172
+#define LINKTYPE_GCOM_SERIAL 173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define LINKTYPE_JUNIPER_PIC_PEER 174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems. They add an ERF header (see
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define LINKTYPE_ERF_ETH 175 /* Ethernet */
+#define LINKTYPE_ERF_POS 176 /* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define LINKTYPE_LINUX_LAPD 177
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The Link Types are used for prepending meta-information
+ * like interface index, interface name
+ * before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ */
+#define LINKTYPE_JUNIPER_ETHER 178
+#define LINKTYPE_JUNIPER_PPP 179
+#define LINKTYPE_JUNIPER_FRELAY 180
+#define LINKTYPE_JUNIPER_CHDLC 181
+
+/*
+ * Multi Link Frame Relay (FRF.16)
+ */
+#define LINKTYPE_MFR 182
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * voice Adapter Card (PIC)
+ */
+#define LINKTYPE_JUNIPER_VP 183
+
+/*
+ * Arinc 429 frames.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * 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 LINKTYPE_A429 184
+
+/*
+ * Arinc 653 Interpartition Communication messages.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Please refer to the A653-1 standard for more information.
+ */
+#define LINKTYPE_A653_ICM 185
+
+/*
+ * This used to be "USB packets, beginning with a USB setup header;
+ * requested by Paolo Abeni <paolo.abeni@email.it>."
+ *
+ * However, that header didn't work all that well - it left out some
+ * useful information - and was abandoned in favor of the DLT_USB_LINUX
+ * header.
+ *
+ * This is now used by FreeBSD for its BPF taps for USB; that has its
+ * own headers. So it is written, so it is done.
+ */
+#define LINKTYPE_USB_FREEBSD 186
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4); requested by
+ * Paolo Abeni.
+ */
+#define LINKTYPE_BLUETOOTH_HCI_H4 187
+
+/*
+ * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ * <cruz_petagay@bah.com>.
+ */
+#define LINKTYPE_IEEE802_16_MAC_CPS 188
+
+/*
+ * USB packets, beginning with a Linux USB header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define LINKTYPE_USB_LINUX 189
+
+/*
+ * Controller Area Network (CAN) v. 2.0B packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Used to dump CAN packets coming from a CAN Vector board.
+ * More documentation on the CAN v2.0B frames can be found at
+ * http://www.can-cia.org/downloads/?269
+ */
+#define LINKTYPE_CAN20B 190
+
+/*
+ * IEEE 802.15.4, with address fields padded, as is done by Linux
+ * drivers; requested by Juergen Schimmer.
+ */
+#define LINKTYPE_IEEE802_15_4_LINUX 191
+
+/*
+ * Per Packet Information encapsulated packets.
+ * LINKTYPE_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ */
+#define LINKTYPE_PPI 192
+
+/*
+ * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header;
+ * requested by Charles Clancy.
+ */
+#define LINKTYPE_IEEE802_16_MAC_CPS_RADIO 193
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * integrated service module (ISM).
+ */
+#define LINKTYPE_JUNIPER_ISM 194
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), and with the FCS at the end of the frame; requested by
+ * Mikko Saarnivala <mikko.saarnivala@sensinode.com>.
+ *
+ * This should only be used if the FCS is present at the end of the
+ * frame; if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be
+ * used.
+ */
+#define LINKTYPE_IEEE802_15_4_WITHFCS 195
+
+/*
+ * Various link-layer types, with a pseudo-header, for SITA
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ */
+#define LINKTYPE_SITA 196
+
+/*
+ * Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ * encapsulates Endace ERF records. Requested by Stephen Donnelly
+ * <stephen@endace.com>.
+ */
+#define LINKTYPE_ERF 197
+
+/*
+ * Special header prepended to Ethernet packets when capturing from a
+ * u10 Networks board. Requested by Phil Mulholland
+ * <phil@u10networks.com>.
+ */
+#define LINKTYPE_RAIF1 198
+
+/*
+ * IPMB packet for IPMI, beginning with a 2-byte header, followed by
+ * the I2C slave address, followed by the netFn and LUN, etc..
+ * Requested by Chanthy Toeung <chanthy.toeung@ca.kontron.com>.
+ *
+ * XXX - its DLT_ value used to be called DLT_IPMB, back when we got the
+ * impression from the email thread requesting it that the packet
+ * had no extra 2-byte header. We've renamed it; if anybody used
+ * DLT_IPMB and assumed no 2-byte header, this will cause the compile
+ * to fail, at which point we'll have to figure out what to do about
+ * the two header types using the same DLT_/LINKTYPE_ value. If that
+ * doesn't happen, we'll assume nobody used it and that the redefinition
+ * is safe.
+ */
+#define LINKTYPE_IPMB_KONTRON 199
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for capturing data on a secure tunnel interface.
+ */
+#define LINKTYPE_JUNIPER_ST 200
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4), with pseudo-header
+ * that includes direction information; requested by Paolo Abeni.
+ */
+#define LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR 201
+
+/*
+ * AX.25 packet with a 1-byte KISS header; see
+ *
+ * http://www.ax25.net/kiss.htm
+ *
+ * as per Richard Stearn <richard@rns-stearn.demon.co.uk>.
+ */
+#define LINKTYPE_AX25_KISS 202
+
+/*
+ * LAPD packets from an ISDN channel, starting with the address field,
+ * with no pseudo-header.
+ * Requested by Varuna De Silva <varunax@gmail.com>.
+ */
+#define LINKTYPE_LAPD 203
+
+/*
+ * PPP, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host", non-zero (any non-zero value) means "sent by
+ * this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_PPP_WITH_DIR 204 /* Don't confuse with LINKTYPE_PPP_PPPD */
+
+/*
+ * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host", non-zero (any non-zero value) means
+ * "sent by this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_C_HDLC_WITH_DIR 205 /* Cisco HDLC */
+
+/*
+ * Frame Relay, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host" (DCE -> DTE), non-zero (any non-zero
+ * value) means "sent by this host" (DTE -> DCE) - as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_FRELAY_WITH_DIR 206 /* Frame Relay */
+
+/*
+ * LAPB, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host" (DCE -> DTE), non-zero (any non-zero value)
+ * means "sent by this host" (DTE -> DCE)- as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define LINKTYPE_LAPB_WITH_DIR 207 /* LAPB */
+
+/*
+ * 208 is reserved for an as-yet-unspecified proprietary link-layer
+ * type, as requested by Will Barker.
+ */
+
+/*
+ * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ * <avn@pigeonpoint.com>.
+ */
+#define LINKTYPE_IPMB_LINUX 209
+
+/*
+ * FlexRay automotive bus - http://www.flexray.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_FLEXRAY 210
+
+/*
+ * Media Oriented Systems Transport (MOST) bus for multimedia
+ * transport - https://www.mostcooperation.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_MOST 211
+
+/*
+ * Local Interconnect Network (LIN) bus for vehicle networks -
+ * http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ * <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_LIN 212
+
+/*
+ * X2E-private data link type used for serial line capture,
+ * as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_X2E_SERIAL 213
+
+/*
+ * X2E-private data link type used for the Xoraya data logger
+ * family, as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define LINKTYPE_X2E_XORAYA 214
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), but with the PHY-level data for non-ASK PHYs (4 octets
+ * of 0 as preamble, one octet of SFD, one octet of frame length+
+ * reserved bit, and then the MAC-layer data, starting with the
+ * frame control field).
+ *
+ * Requested by Max Filippov <jcmvbkbc@gmail.com>.
+ */
+#define LINKTYPE_IEEE802_15_4_NONASK_PHY 215
+
+/*
+ * David Gibson <david@gibson.dropbear.id.au> requested this for
+ * captures from the Linux kernel /dev/input/eventN devices. This
+ * is used to communicate keystrokes and mouse movements from the
+ * Linux kernel to display systems, such as Xorg.
+ */
+#define LINKTYPE_LINUX_EVDEV 216
+
+/*
+ * GSM Um and Abis interfaces, preceded by a "gsmtap" header.
+ *
+ * Requested by Harald Welte <laforge@gnumonks.org>.
+ */
+#define LINKTYPE_GSMTAP_UM 217
+#define LINKTYPE_GSMTAP_ABIS 218
+
+/*
+ * MPLS, with an MPLS label as the link-layer header.
+ * Requested by Michele Marchetto <michele@openbsd.org> on behalf
+ * of OpenBSD.
+ */
+#define LINKTYPE_MPLS 219
+
+/*
+ * USB packets, beginning with a Linux USB header, with the USB header
+ * padded to 64 bytes; required for memory-mapped access.
+ */
+#define LINKTYPE_USB_LINUX_MMAPPED 220
+
+/*
+ * DECT packets, with a pseudo-header; requested by
+ * Matthias Wenzel <tcpdump@mazzoo.de>.
+ */
+#define LINKTYPE_DECT 221
+
+/*
+ * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" <eric.lidwa-1@nasa.gov>
+ * Date: Mon, 11 May 2009 11:18:30 -0500
+ *
+ * DLT_AOS. We need it for AOS Space Data Link Protocol.
+ * I have already written dissectors for but need an OK from
+ * legal before I can submit a patch.
+ *
+ */
+#define LINKTYPE_AOS 222
+
+/*
+ * Wireless HART (Highway Addressable Remote Transducer)
+ * From the HART Communication Foundation
+ * IES/PAS 62591
+ *
+ * Requested by Sam Roberts <vieuxtech@gmail.com>.
+ */
+#define LINKTYPE_WIHART 223
+
+/*
+ * Fibre Channel FC-2 frames, beginning with a Frame_Header.
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define LINKTYPE_FC_2 224
+
+/*
+ * Fibre Channel FC-2 frames, beginning with an encoding of the
+ * SOF, and ending with an encoding of the EOF.
+ *
+ * The encodings represent the frame delimiters as 4-byte sequences
+ * representing the corresponding ordered sets, with K28.5
+ * represented as 0xBC, and the D symbols as the corresponding
+ * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2,
+ * is represented as 0xBC 0xB5 0x55 0x55.
+ *
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#define LINKTYPE_FC_2_WITH_FRAME_DELIMS 225
+
+/*
+ * Solaris ipnet pseudo-header; requested by Darren Reed <Darren.Reed@Sun.COM>.
+ *
+ * The pseudo-header starts with a one-byte version number; for version 2,
+ * the pseudo-header is:
+ *
+ * struct dl_ipnetinfo {
+ * uint8_t dli_version;
+ * uint8_t dli_family;
+ * uint16_t dli_htype;
+ * uint32_t dli_pktlen;
+ * uint32_t dli_ifindex;
+ * uint32_t dli_grifindex;
+ * uint32_t dli_zsrc;
+ * uint32_t dli_zdst;
+ * };
+ *
+ * dli_version is 2 for the current version of the pseudo-header.
+ *
+ * dli_family is a Solaris address family value, so it's 2 for IPv4
+ * and 26 for IPv6.
+ *
+ * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing
+ * packets, and 2 for packets arriving from another zone on the same
+ * machine.
+ *
+ * dli_pktlen is the length of the packet data following the pseudo-header
+ * (so the captured length minus dli_pktlen is the length of the
+ * pseudo-header, assuming the entire pseudo-header was captured).
+ *
+ * dli_ifindex is the interface index of the interface on which the
+ * packet arrived.
+ *
+ * dli_grifindex is the group interface index number (for IPMP interfaces).
+ *
+ * dli_zsrc is the zone identifier for the source of the packet.
+ *
+ * dli_zdst is the zone identifier for the destination of the packet.
+ *
+ * A zone number of 0 is the global zone; a zone number of 0xffffffff
+ * means that the packet arrived from another host on the network, not
+ * from another zone on the same machine.
+ *
+ * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates
+ * which of those it is.
+ */
+#define LINKTYPE_IPNET 226
+
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ *
+ * Requested by Felix Obenhuber <felix@obenhuber.de>.
+ */
+#define LINKTYPE_CAN_SOCKETCAN 227
+
+/*
+ * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies
+ * whether it's v4 or v6. Requested by Darren Reed <Darren.Reed@Sun.COM>.
+ */
+#define LINKTYPE_IPV4 228
+#define LINKTYPE_IPV6 229
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), and with no FCS at the end of the frame; requested by
+ * Jon Smirl <jonsmirl@gmail.com>.
+ */
+#define LINKTYPE_IEEE802_15_4_NOFCS 230
+
+/*
+ * Raw D-Bus:
+ *
+ * https://www.freedesktop.org/wiki/Software/dbus
+ *
+ * messages:
+ *
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * starting with the endianness flag, followed by the message type, etc.,
+ * but without the authentication handshake before the message sequence:
+ *
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *
+ * Requested by Martin Vidner <martin@vidner.net>.
+ */
+#define LINKTYPE_DBUS 231
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define LINKTYPE_JUNIPER_VS 232
+#define LINKTYPE_JUNIPER_SRX_E2E 233
+#define LINKTYPE_JUNIPER_FIBRECHANNEL 234
+
+/*
+ * DVB-CI (DVB Common Interface for communication between a PC Card
+ * module and a DVB receiver). See
+ *
+ * https://www.kaiser.cx/pcap-dvbci.html
+ *
+ * for the specification.
+ *
+ * Requested by Martin Kaiser <martin@kaiser.cx>.
+ */
+#define LINKTYPE_DVB_CI 235
+
+/*
+ * Variant of 3GPP TS 27.010 multiplexing protocol. Requested
+ * by Hans-Christoph Schemmel <hans-christoph.schemmel@cinterion.com>.
+ */
+#define LINKTYPE_MUX27010 236
+
+/*
+ * STANAG 5066 D_PDUs. Requested by M. Baris Demiray
+ * <barisdemiray@gmail.com>.
+ */
+#define LINKTYPE_STANAG_5066_D_PDU 237
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define LINKTYPE_JUNIPER_ATM_CEMIC 238
+
+/*
+ * NetFilter LOG messages
+ * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets)
+ *
+ * Requested by Jakub Zawadzki <darkjames-ws@darkjames.pl>
+ */
+#define LINKTYPE_NFLOG 239
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and always
+ * with the payload including the FCS, as supplied by their
+ * netANALYZER hardware and software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define LINKTYPE_NETANALYZER 240
+
+/*
+ * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type
+ * for Ethernet packets with a 4-byte pseudo-header and FCS and
+ * 1 byte of SFD, as supplied by their netANALYZER hardware and
+ * software.
+ *
+ * Requested by Holger P. Frommer <HPfrommer@hilscher.com>
+ */
+#define LINKTYPE_NETANALYZER_TRANSPARENT 241
+
+/*
+ * IP-over-InfiniBand, as specified by RFC 4391.
+ *
+ * Requested by Petr Sumbera <petr.sumbera@oracle.com>.
+ */
+#define LINKTYPE_IPOIB 242
+
+/*
+ * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0).
+ *
+ * Requested by Guy Martin <gmsoft@tuxicoman.be>.
+ */
+#define LINKTYPE_MPEG_2_TS 243
+
+/*
+ * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as
+ * used by their ng40 protocol tester.
+ *
+ * Requested by Jens Grimmer <jens.grimmer@ng4t.com>.
+ */
+#define LINKTYPE_NG40 244
+
+/*
+ * Pseudo-header giving adapter number and flags, followed by an NFC
+ * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU,
+ * as specified by NFC Forum Logical Link Control Protocol Technical
+ * Specification LLCP 1.1.
+ *
+ * Requested by Mike Wakerly <mikey@google.com>.
+ */
+#define LINKTYPE_NFC_LLCP 245
+
+/*
+ * pfsync output; DLT_PFSYNC is 18, which collides with DLT_CIP in
+ * SuSE 6.3, on OpenBSD, NetBSD, DragonFly BSD, and macOS, and
+ * is 121, which collides with DLT_HHDLC, in FreeBSD. We pick a
+ * shiny new link-layer header type value that doesn't collide with
+ * anything, in the hopes that future pfsync savefiles, if any,
+ * won't require special hacks to distinguish from other savefiles.
+ *
+ */
+#define LINKTYPE_PFSYNC 246
+
+/*
+ * Raw InfiniBand packets, starting with the Local Routing Header.
+ *
+ * Requested by Oren Kladnitsky <orenk@mellanox.com>.
+ */
+#define LINKTYPE_INFINIBAND 247
+
+/*
+ * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6).
+ *
+ * Requested by Michael Tuexen <Michael.Tuexen@lurchi.franken.de>.
+ */
+#define LINKTYPE_SCTP 248
+
+/*
+ * USB packets, beginning with a USBPcap header.
+ *
+ * Requested by Tomasz Mon <desowin@gmail.com>
+ */
+#define LINKTYPE_USBPCAP 249
+
+/*
+ * Schweitzer Engineering Laboratories "RTAC" product serial-line
+ * packets.
+ *
+ * Requested by Chris Bontje <chris_bontje@selinc.com>.
+ */
+#define LINKTYPE_RTAC_SERIAL 250
+
+/*
+ * Bluetooth Low Energy air interface link-layer packets.
+ *
+ * Requested by Mike Kershaw <dragorn@kismetwireless.net>.
+ */
+#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 macOS*; that is *intentional*, so that
+ * PKTAP files look the same on *all* OSes (different OSes can have
+ * different numerical values for a given DLT_, but *MUST NOT* have
+ * different values for what goes in a file, as files can be moved
+ * between OSes!).
+ */
+#define LINKTYPE_PKTAP 258
+
+/*
+ * Ethernet packets preceded by a header giving the last 6 octets
+ * of the preamble specified by 802.3-2012 Clause 65, section
+ * 65.1.3.2 "Transmit".
+ */
+#define LINKTYPE_EPON 259
+
+/*
+ * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format"
+ * in the PICMG HPM.2 specification.
+ */
+#define LINKTYPE_IPMI_HPM_2 260
+
+/*
+ * per Joshua Wright <jwright@hasborg.com>, formats for Zwave captures.
+ */
+#define LINKTYPE_ZWAVE_R1_R2 261
+#define LINKTYPE_ZWAVE_R3 262
+
+/*
+ * per Steve Karg <skarg@users.sourceforge.net>, 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 <jonathan.brucke@gmail.com>.
+ */
+#define LINKTYPE_RDS 265
+
+/*
+ * USB packets, beginning with a Darwin (macOS, etc.) header.
+ */
+#define LINKTYPE_USB_DARWIN 266
+
+/*
+ * OpenBSD DLT_OPENFLOW.
+ */
+#define LINKTYPE_OPENFLOW 267
+
+/*
+ * SDLC frames containing SNA PDUs.
+ */
+#define LINKTYPE_SDLC 268
+
+/*
+ * per "Selvig, Bjorn" <b.selvig@ti.com> used for
+ * TI protocol sniffer.
+ */
+#define LINKTYPE_TI_LLN_SNIFFER 269
+
+/*
+ * per: Erik de Jong <erikdejong at gmail.com> for
+ * https://github.com/eriknl/LoRaTap/releases/tag/v0.1
+ */
+#define LINKTYPE_LORATAP 270
+
+/*
+ * per: Stefanha at gmail.com for
+ * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
+ * for: https://qemu-project.org/Features/VirtioVsock
+ */
+#define LINKTYPE_VSOCK 271
+
+/*
+ * Nordic Semiconductor Bluetooth LE sniffer.
+ */
+#define LINKTYPE_NORDIC_BLE 272
+
+/*
+ * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
+ * per: bruno.verstuyft at excentis.com
+ * https://www.xra31.com/xra-header
+ */
+#define LINKTYPE_DOCSIS31_XRA31 273
+
+/*
+ * mPackets, as specified by IEEE 802.3br Figure 99-4, starting
+ * with the preamble and always ending with a CRC field.
+ */
+#define LINKTYPE_ETHERNET_MPACKET 274
+
+/*
+ * DisplayPort AUX channel monitoring data as specified by VESA
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
+ * per dirk.eibach at gdsys.cc
+ */
+#define LINKTYPE_DISPLAYPORT_AUX 275
+
+/*
+ * Linux cooked sockets v2.
+ */
+#define LINKTYPE_LINUX_SLL2 276
+
+/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define LINKTYPE_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define LINKTYPE_OPENVIZSLA 278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ * https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define LINKTYPE_EBHSCR 279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define LINKTYPE_VPP_DISPATCH 280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_BRCM 281
+#define LINKTYPE_DSA_TAG_BRCM_PREPEND 282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV; requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define LINKTYPE_IEEE802_15_4_TAP 283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_DSA 284
+#define LINKTYPE_DSA_TAG_EDSA 285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define LINKTYPE_ELEE 286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define LINKTYPE_Z_WAVE_SERIAL 287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define LINKTYPE_USB_2_0 288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define LINKTYPE_ATSC_ALP 289
+
+#define LINKTYPE_MATCHING_MAX 289 /* highest value in the "matching" range */
+
+/*
+ * The DLT_ and LINKTYPE_ values in the "matching" range should be the
+ * same, so DLT_MATCHING_MAX and LINKTYPE_MATCHING_MAX should be the
+ * same.
+ */
+#if LINKTYPE_MATCHING_MAX != DLT_MATCHING_MAX
+#error The LINKTYPE_ matching range does not match the DLT_ matching range
+#endif
+
+static struct linktype_map {
+ int dlt;
+ int linktype;
+} map[] = {
+ /*
+ * These DLT_* codes have LINKTYPE_* codes with values identical
+ * to the values of the corresponding DLT_* code.
+ */
+ { DLT_NULL, LINKTYPE_NULL },
+ { DLT_EN10MB, LINKTYPE_ETHERNET },
+ { DLT_EN3MB, LINKTYPE_EXP_ETHERNET },
+ { DLT_AX25, LINKTYPE_AX25 },
+ { DLT_PRONET, LINKTYPE_PRONET },
+ { DLT_CHAOS, LINKTYPE_CHAOS },
+ { DLT_IEEE802, LINKTYPE_IEEE802_5 },
+ { DLT_ARCNET, LINKTYPE_ARCNET_BSD },
+ { DLT_SLIP, LINKTYPE_SLIP },
+ { DLT_PPP, LINKTYPE_PPP },
+ { DLT_FDDI, LINKTYPE_FDDI },
+ { DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL },
+
+ /*
+ * These DLT_* codes have different values on different
+ * platforms; we map them to LINKTYPE_* codes that
+ * have values that should never be equal to any DLT_*
+ * code.
+ */
+#ifdef DLT_FR
+ /* BSD/OS Frame Relay */
+ { DLT_FR, LINKTYPE_FRELAY },
+#endif
+
+ { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 },
+ { DLT_RAW, LINKTYPE_RAW },
+ { DLT_SLIP_BSDOS, LINKTYPE_SLIP_BSDOS },
+ { DLT_PPP_BSDOS, LINKTYPE_PPP_BSDOS },
+
+ /* BSD/OS Cisco HDLC */
+ { DLT_C_HDLC, LINKTYPE_C_HDLC },
+
+ /*
+ * These DLT_* codes are not on all platforms, but, so far,
+ * there don't appear to be any platforms that define
+ * other codes with those values; we map them to
+ * different LINKTYPE_* values anyway, just in case.
+ */
+
+ /* Linux ATM Classical IP */
+ { DLT_ATM_CLIP, LINKTYPE_ATM_CLIP },
+
+ /* NetBSD sync/async serial PPP (or Cisco HDLC) */
+ { DLT_PPP_SERIAL, LINKTYPE_PPP_HDLC },
+
+ /* NetBSD PPP over Ethernet */
+ { DLT_PPP_ETHER, LINKTYPE_PPP_ETHER },
+
+ /*
+ * All LINKTYPE_ values between LINKTYPE_MATCHING_MIN
+ * and LINKTYPE_MATCHING_MAX are mapped to identical
+ * DLT_ values.
+ */
+
+ { -1, -1 }
+};
+
+int
+dlt_to_linktype(int dlt)
+{
+ int i;
+
+ /*
+ * DLTs that, on some platforms, have values in the matching range
+ * but that *don't* have the same value as the corresponding
+ * LINKTYPE because, for some reason, not all OSes have the
+ * same value for that DLT (note that the DLT's value might be
+ * outside the matching range on some of those OSes).
+ */
+ if (dlt == DLT_PFSYNC)
+ return (LINKTYPE_PFSYNC);
+ if (dlt == DLT_PKTAP)
+ return (LINKTYPE_PKTAP);
+
+ /*
+ * For all other values in the matching range, the DLT
+ * value is the same as the LINKTYPE value.
+ */
+ if (dlt >= DLT_MATCHING_MIN && dlt <= DLT_MATCHING_MAX)
+ return (dlt);
+
+ /*
+ * Map the values outside that range.
+ */
+ for (i = 0; map[i].dlt != -1; i++) {
+ if (map[i].dlt == dlt)
+ return (map[i].linktype);
+ }
+
+ /*
+ * If we don't have a mapping for this DLT, return an
+ * error; that means that this is a value with no corresponding
+ * LINKTYPE, and we need to assign one.
+ */
+ return (-1);
+}
+
+int
+linktype_to_dlt(int linktype)
+{
+ int i;
+
+ /*
+ * LINKTYPEs in the matching range that *don't*
+ * have the same value as the corresponding DLTs
+ * because, for some reason, not all OSes have the
+ * same value for that DLT.
+ */
+ if (linktype == LINKTYPE_PFSYNC)
+ return (DLT_PFSYNC);
+ if (linktype == LINKTYPE_PKTAP)
+ return (DLT_PKTAP);
+
+ /*
+ * For all other values in the matching range, except for
+ * LINKTYPE_ATM_CLIP, the LINKTYPE value is the same as
+ * the DLT value.
+ *
+ * LINKTYPE_ATM_CLIP is a special case. DLT_ATM_CLIP is
+ * not on all platforms, but, so far, there don't appear
+ * to be any platforms that define it as anything other
+ * than 19; we define LINKTYPE_ATM_CLIP as something
+ * other than 19, just in case. That value is in the
+ * matching range, so we have to check for it.
+ */
+ if (linktype >= LINKTYPE_MATCHING_MIN &&
+ linktype <= LINKTYPE_MATCHING_MAX &&
+ linktype != LINKTYPE_ATM_CLIP)
+ return (linktype);
+
+ /*
+ * Map the values outside that range.
+ */
+ for (i = 0; map[i].linktype != -1; i++) {
+ if (map[i].linktype == linktype)
+ return (map[i].dlt);
+ }
+
+ /*
+ * If we don't have an entry for this LINKTYPE, return
+ * the link type value; it may be a DLT from an newer
+ * version of libpcap.
+ */
+ return linktype;
+}
+
+/*
+ * Return the maximum snapshot length for a given DLT_ value.
+ *
+ * For most link-layer types, we use MAXIMUM_SNAPLEN.
+ *
+ * For DLT_DBUS, the maximum is 128MiB, as per
+ *
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * For DLT_EBHSCR, the maximum is 8MiB, as per
+ *
+ * https://www.elektrobit.com/ebhscr
+ *
+ * For DLT_USBPCAP, the maximum is 1MiB, as per
+ *
+ * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985
+ */
+u_int
+max_snaplen_for_dlt(int dlt)
+{
+ switch (dlt) {
+
+ case DLT_DBUS:
+ return 128*1024*1024;
+
+ case DLT_EBHSCR:
+ return 8*1024*1024;
+
+ case DLT_USBPCAP:
+ return 1024*1024;
+
+ default:
+ return MAXIMUM_SNAPLEN;
+ }
+}
+
+/*
+ * 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;
+ uint16_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_BE_U_2(&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 byte order of the host that wrote
+ * the file to this host's byte order.
+ */
+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;
+
+ /*
+ * "offset" is the offset *past* the field we're swapping;
+ * we skip the field *before* checking to make sure
+ * the captured data length includes the entire field.
+ */
+
+ /*
+ * 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 */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->id = SWAPLL(uhdr->id);
+
+ offset += 4; /* skip past various 1-byte fields */
+
+ offset += 2; /* skip past bus_id */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
+
+ offset += 2; /* skip past various 1-byte fields */
+
+ offset += 8; /* skip past ts_sec */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
+
+ offset += 4; /* skip past ts_usec */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
+
+ offset += 4; /* skip past status */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->status = SWAPLONG(uhdr->status);
+
+ offset += 4; /* skip past urb_len */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->urb_len = SWAPLONG(uhdr->urb_len);
+
+ offset += 4; /* skip past data_len */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->data_len = SWAPLONG(uhdr->data_len);
+
+ if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+ offset += 4; /* skip past s.iso.error_count */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
+
+ offset += 4; /* skip past s.iso.numdesc */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
+ } 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
+ * 16 bytes of additional fields at the end, or
+ * a "version 0" header from a memory-mapped
+ * capture, with 16 bytes of zeroed-out padding
+ * at the end. Byte swap them as if this were
+ * a "version 1" header.
+ */
+ offset += 4; /* skip past interval */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->interval = SWAPLONG(uhdr->interval);
+
+ offset += 4; /* skip past start_frame */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->start_frame = SWAPLONG(uhdr->start_frame);
+
+ offset += 4; /* skip past xfer_flags */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
+
+ offset += 4; /* skip past ndesc */
+ if (hdr->caplen < offset)
+ return;
+ uhdr->ndesc = SWAPLONG(uhdr->ndesc);
+
+ if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+ /* swap the values in struct linux_usb_isodesc */
+ usb_isodesc *pisodesc;
+ uint32_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;
+ uint16_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/pcap-common.h b/pcap-common.h
new file mode 100644
index 0000000..8795a82
--- /dev/null
+++ b/pcap-common.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-common.h - common code for pcap and pcapng files
+ */
+
+/*
+ * We use the "receiver-makes-right" approach to byte order,
+ * because time is at a premium when we are writing the file.
+ * In other words, the pcap_file_header and pcap_pkthdr,
+ * records are written in host byte order.
+ * Note that the bytes of packet data are written out in the order in
+ * which they were received, so multi-byte fields in packets are not
+ * written in host byte order, they're written in whatever order the
+ * sending machine put them in.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define SWAPLONG(y) \
+ (((((u_int)(y))&0xff)<<24) | \
+ ((((u_int)(y))&0xff00)<<8) | \
+ ((((u_int)(y))&0xff0000)>>8) | \
+ ((((u_int)(y))>>24)&0xff))
+#define SWAPSHORT(y) \
+ ((u_short)(((((u_int)(y))&0xff)<<8) | \
+ ((((u_int)(y))&0xff00)>>8)))
+
+extern int dlt_to_linktype(int dlt);
+
+extern int linktype_to_dlt(int linktype);
+
+extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr,
+ u_char *data);
+
+extern u_int max_snaplen_for_dlt(int dlt);
diff --git a/pcap-int.h b/pcap-int.h
new file mode 100644
index 0000000..dc18d50
--- /dev/null
+++ b/pcap-int.h
@@ -0,0 +1,648 @@
+/*
+ * 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 pcap_int_h
+#define pcap_int_h
+
+#include <stddef.h>
+
+#include <signal.h>
+
+#include <pcap/pcap.h>
+
+#ifdef MSDOS
+ #include <fcntl.h>
+ #include <io.h>
+#endif
+
+#include "varattrs.h"
+#include "fmtutils.h"
+
+#include <stdarg.h>
+
+#include "portability.h"
+
+/*
+ * Version string.
+ * Uses PACKAGE_VERSION from config.h.
+ */
+#define PCAP_VERSION_STRING "libpcap version " PACKAGE_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If pcap_new_api is set, we disable pcap_lookupdev(), because:
+ *
+ * it's not thread-safe, and is marked as deprecated, on all
+ * platforms;
+ *
+ * on Windows, it may return UTF-16LE strings, which the program
+ * might then pass to pcap_create() (or to pcap_open_live(), which
+ * then passes them to pcap_create()), requiring pcap_create() to
+ * check for UTF-16LE strings using a hack, and that hack 1)
+ * *cannot* be 100% reliable and 2) runs the risk of going past the
+ * end of the string.
+ *
+ * We keep it around in legacy mode for compatibility.
+ *
+ * We also disable the aforementioned hack in pcap_create().
+ */
+extern int pcap_new_api;
+
+/*
+ * If pcap_utf_8_mode is set, on Windows we treat strings as UTF-8.
+ *
+ * On UN*Xes, we assume all strings are and should be in UTF-8, regardless
+ * of the setting of this flag.
+ */
+extern int pcap_utf_8_mode;
+
+/*
+ * Swap byte ordering of unsigned long long timestamp on a big endian
+ * machine.
+ */
+#define SWAPLL(ull) ((ull & 0xff00000000000000ULL) >> 56) | \
+ ((ull & 0x00ff000000000000ULL) >> 40) | \
+ ((ull & 0x0000ff0000000000ULL) >> 24) | \
+ ((ull & 0x000000ff00000000ULL) >> 8) | \
+ ((ull & 0x00000000ff000000ULL) << 8) | \
+ ((ull & 0x0000000000ff0000ULL) << 24) | \
+ ((ull & 0x000000000000ff00ULL) << 40) | \
+ ((ull & 0x00000000000000ffULL) << 56)
+
+/*
+ * 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:
+ *
+ * https://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. (libpcap uses it
+ * as a hint, but doesn't start out allocating a buffer bigger than
+ * 2 KiB, and grows the buffer as necessary, but not beyond the
+ * per-linktype maximum snapshot length. Other code might naively
+ * use it; we want to avoid writing a too-large snapshot length,
+ * in order not to cause that code problems.)
+ *
+ * We don't enforce this in pcap_set_snaplen(), but we use it internally.
+ */
+#define MAXIMUM_SNAPLEN 262144
+
+/*
+ * Locale-independent macros for testing character types.
+ * These can be passed any integral value, without worrying about, for
+ * example, sign-extending char values, unlike the C macros.
+ */
+#define PCAP_ISDIGIT(c) \
+ ((c) >= '0' && (c) <= '9')
+#define PCAP_ISXDIGIT(c) \
+ (((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'A' && (c) <= 'F') || \
+ ((c) >= 'a' && (c) <= 'f'))
+
+struct pcap_opt {
+ char *device;
+ int timeout; /* timeout for buffering */
+ u_int buffer_size;
+ int promisc;
+ int rfmon; /* monitor mode */
+ int immediate; /* immediate mode - deliver packets as soon as they arrive */
+ int nonblock; /* non-blocking mode - don't wait for packets to be delivered, return "no packets available" */
+ int tstamp_type;
+ int tstamp_precision;
+
+ /*
+ * Platform-dependent options.
+ */
+#ifdef __linux__
+ int protocol; /* protocol to use when creating PF_PACKET socket */
+#endif
+#ifdef _WIN32
+ int nocapture_local;/* disable NPF loopback */
+#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 *);
+typedef int (*next_packet_op_t)(pcap_t *, struct pcap_pkthdr *, u_char **);
+typedef int (*inject_op_t)(pcap_t *, const void *, int);
+typedef void (*save_current_filter_op_t)(pcap_t *, const char *);
+typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *);
+typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t);
+typedef int (*set_datalink_op_t)(pcap_t *, int);
+typedef int (*getnonblock_op_t)(pcap_t *);
+typedef int (*setnonblock_op_t)(pcap_t *, int);
+typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *);
+typedef void (*breakloop_op_t)(pcap_t *);
+#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 {
+ /*
+ * Method to call to read packets on a live capture.
+ */
+ read_op_t read_op;
+
+ /*
+ * Method to call to read the next packet from a savefile.
+ */
+ next_packet_op_t next_packet_op;
+
+#ifdef _WIN32
+ HANDLE handle;
+#else
+ int fd;
+#endif /* _WIN32 */
+
+ /*
+ * Read buffer.
+ */
+ u_int bufsize;
+ void *buffer;
+ u_char *bp;
+ int cc;
+
+ sig_atomic_t break_loop; /* flag set to force break from packet-reading loop */
+
+ void *priv; /* private data for methods */
+
+#ifdef ENABLE_REMOTE
+ struct pcap_samp rmt_samp; /* parameters related to the sampling process. */
+#endif
+
+ 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;
+
+ int snapshot;
+ int linktype; /* Network linktype */
+ int linktype_ext; /* Extended information stored in the linktype field of a file */
+ int offset; /* offset for proper alignment */
+ int activated; /* true if the capture is really started */
+ int oldstyle; /* if we're opening with pcap_open_live() */
+
+ struct pcap_opt opt;
+
+ /*
+ * Place holder for pcap_next().
+ */
+ u_char *pkt;
+
+#ifdef _WIN32
+ struct pcap_stat stat; /* used for pcap_stats_ex() */
+#endif
+
+ /* We're accepting only packets in this direction/these directions. */
+ pcap_direction_t direction;
+
+ /*
+ * Flags to affect BPF code generation.
+ */
+ int bpf_codegen_flags;
+
+#if !defined(_WIN32) && !defined(MSDOS)
+ int selectable_fd; /* FD on which select()/poll()/epoll_wait()/kevent()/etc. can be done */
+
+ /*
+ * In case there either is no selectable FD, or there is but
+ * it doesn't necessarily work (e.g., if it doesn't get notified
+ * if the packet capture timeout expires before the buffer
+ * fills up), this points to a timeout that should be used
+ * in select()/poll()/epoll_wait()/kevent() call. The pcap_t should
+ * be put into non-blocking mode, and, if the timeout expires on
+ * the call, an attempt should be made to read packets from all
+ * pcap_t's with a required timeout, and the code must be
+ * prepared not to see any packets from the attempt.
+ */
+ const struct timeval *required_select_timeout;
+#endif
+
+ /*
+ * Placeholder for filter code if bpf not in kernel.
+ */
+ struct bpf_program fcode;
+
+ char errbuf[PCAP_ERRBUF_SIZE + 1];
+#ifdef _WIN32
+ char acp_errbuf[PCAP_ERRBUF_SIZE + 1]; /* buffer for local code page error strings */
+#endif
+ 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 */
+
+ /*
+ * More methods.
+ */
+ activate_op_t activate_op;
+ can_set_rfmon_op_t can_set_rfmon_op;
+ inject_op_t inject_op;
+ save_current_filter_op_t save_current_filter_op;
+ setfilter_op_t setfilter_op;
+ setdirection_op_t setdirection_op;
+ set_datalink_op_t set_datalink_op;
+ getnonblock_op_t getnonblock_op;
+ setnonblock_op_t setnonblock_op;
+ stats_op_t stats_op;
+ breakloop_op_t breakloop_op;
+
+ /*
+ * Routine to use as callback for pcap_next()/pcap_next_ex().
+ */
+ pcap_handler oneshot_callback;
+
+#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;
+};
+
+/*
+ * 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
+ * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some
+ * platforms and 64-bit tv_sec values on other platforms, and writing
+ * out native `struct timeval' values would mean files could only be
+ * read on systems with the same tv_sec size as the system on which
+ * the file was written.
+ */
+
+struct pcap_timeval {
+ bpf_int32 tv_sec; /* seconds */
+ bpf_int32 tv_usec; /* microseconds */
+};
+
+/*
+ * This is a `pcap_pkthdr' as actually stored in a savefile.
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure),
+ * and do not make the time stamp anything other than seconds and
+ * microseconds (e.g., seconds and nanoseconds). Instead:
+ *
+ * introduce a new structure for the new format;
+ *
+ * send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ * a new magic number for your new capture file format, and, when
+ * you get the new magic number, put it in "savefile.c";
+ *
+ * use that magic number for save files with the changed record
+ * header;
+ *
+ * make the code in "savefile.c" capable of reading files with
+ * the old record header as well as files with the new record header
+ * (using the magic number to determine the header format).
+ *
+ * Then supply the changes by forking the branch at
+ *
+ * https://github.com/the-tcpdump-group/libpcap/tree/master
+ *
+ * and issuing a pull request, so that future versions of libpcap and
+ * programs that use it (such as tcpdump) will be able to read your new
+ * capture file format.
+ */
+
+struct pcap_sf_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length of this packet (off wire) */
+};
+
+/*
+ * How a `pcap_pkthdr' is actually stored in savefiles written
+ * by some patched versions of libpcap (e.g. the ones in Red
+ * Hat Linux 6.1 and 6.2).
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ * Instead, introduce a new structure, as per the above.
+ */
+
+struct pcap_sf_patched_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length of this packet (off wire) */
+ int index;
+ unsigned short protocol;
+ unsigned char pkt_type;
+};
+
+/*
+ * User data structure for the one-shot callback used for pcap_next()
+ * and pcap_next_ex().
+ */
+struct oneshot_userdata {
+ struct pcap_pkthdr *hdr;
+ const u_char **pkt;
+ pcap_t *pd;
+};
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
+
+/*
+ * 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)
+int pcap_getnonblock_fd(pcap_t *);
+int pcap_setnonblock_fd(pcap_t *p, int);
+#endif
+
+/*
+ * Internal interfaces for "pcap_create()".
+ *
+ * "pcap_create_interface()" is the routine to do a pcap_create on
+ * a regular network interface. There are multiple implementations
+ * of this, one for each platform type (Linux, BPF, DLPI, etc.),
+ * with the one used chosen by the configure script.
+ *
+ * "pcap_create_common()" allocates and fills in a pcap_t, for use
+ * by pcap_create routines.
+ */
+pcap_t *pcap_create_interface(const char *, char *);
+
+/*
+ * This wrapper takes an error buffer pointer and a type to use for the
+ * private data, and calls pcap_create_common(), passing it the error
+ * buffer pointer, the size fo the private data type, in bytes, and the
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
+ */
+#define PCAP_CREATE_COMMON(ebuf, type) \
+ pcap_create_common(ebuf, \
+ sizeof (struct { pcap_t __common; type __private; }), \
+ offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t *pcap_create_common(char *, size_t, 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_check_activated(pcap_t *);
+void pcap_breakloop_common(pcap_t *);
+
+/*
+ * Internal interfaces for "pcap_findalldevs()".
+ *
+ * A pcap_if_list_t * is a reference to a list of devices.
+ *
+ * A get_if_flags_func is a platform-dependent function called to get
+ * additional interface flags.
+ *
+ * "pcap_platform_finddevs()" is the platform-dependent routine to
+ * find local network interfaces.
+ *
+ * "pcap_findalldevs_interfaces()" is a helper to find those interfaces
+ * using the "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.).
+ *
+ * "add_dev()" adds an entry to a pcap_if_list_t.
+ *
+ * "find_dev()" tries to find a device, by name, in a pcap_if_list_t.
+ *
+ * "find_or_add_dev()" checks whether a device is already in a pcap_if_list_t
+ * and, if not, adds an entry for it.
+ */
+struct pcap_if_list;
+typedef struct pcap_if_list pcap_if_list_t;
+typedef int (*get_if_flags_func)(const char *, bpf_u_int32 *, char *);
+int pcap_platform_finddevs(pcap_if_list_t *, char *);
+#if !defined(_WIN32) && !defined(MSDOS)
+int pcap_findalldevs_interfaces(pcap_if_list_t *, char *,
+ int (*)(const char *), get_if_flags_func);
+#endif
+pcap_if_t *find_or_add_dev(pcap_if_list_t *, const char *, bpf_u_int32,
+ get_if_flags_func, const char *, char *);
+pcap_if_t *find_dev(pcap_if_list_t *, const char *);
+pcap_if_t *add_dev(pcap_if_list_t *, const char *, bpf_u_int32, const char *,
+ 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);
+#ifndef _WIN32
+pcap_if_t *find_or_add_if(pcap_if_list_t *, const char *, bpf_u_int32,
+ get_if_flags_func, char *);
+int add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32,
+ get_if_flags_func,
+ struct sockaddr *, size_t, struct sockaddr *, size_t,
+ struct sockaddr *, size_t, struct sockaddr *, size_t, char *);
+#endif
+
+/*
+ * Internal interfaces for "pcap_open_offline()" and other savefile
+ * I/O routines.
+ *
+ * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use
+ * by pcap_open_offline routines.
+ *
+ * "pcap_adjust_snapshot()" adjusts the snapshot to be non-zero and
+ * fit within an int.
+ *
+ * "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.
+ *
+ * "charset_fopen()", in UTF-8 mode on Windows, does an fopen() that
+ * treats the pathname as being in UTF-8, rather than the local
+ * code page, on Windows.
+ */
+
+/*
+ * This wrapper takes an error buffer pointer and a type to use for the
+ * private data, and calls pcap_create_common(), passing it the error
+ * buffer pointer, the size fo the private data type, in bytes, and the
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
+ */
+#define PCAP_OPEN_OFFLINE_COMMON(ebuf, type) \
+ pcap_open_offline_common(ebuf, \
+ sizeof (struct { pcap_t __common; type __private; }), \
+ offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t *pcap_open_offline_common(char *ebuf, size_t total_size,
+ size_t private_data);
+bpf_u_int32 pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen);
+void sf_cleanup(pcap_t *p);
+#ifdef _WIN32
+FILE *charset_fopen(const char *path, const char *mode);
+#else
+/*
+ * On other OSes, just use Boring Old fopen().
+ */
+#define charset_fopen(path, mode) fopen((path), (mode))
+#endif
+
+/*
+ * Internal interfaces for loading code at run time.
+ */
+#ifdef _WIN32
+#define pcap_code_handle_t HMODULE
+#define pcap_funcptr_t FARPROC
+
+pcap_code_handle_t pcap_load_code(const char *);
+pcap_funcptr_t pcap_find_function(pcap_code_handle_t, const char *);
+#endif
+
+/*
+ * Internal interfaces for doing user-mode filtering of packets and
+ * validating filter programs.
+ */
+/*
+ * 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 pcap_bpf_aux_data {
+ u_short vlan_tag_present;
+ u_short vlan_tag;
+};
+
+/*
+ * Filtering routine that takes the auxiliary data as an additional
+ * argument.
+ */
+u_int pcap_filter_with_aux_data(const struct bpf_insn *,
+ const u_char *, u_int, u_int, const struct pcap_bpf_aux_data *);
+
+/*
+ * Filtering routine that doesn't.
+ */
+u_int pcap_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+/*
+ * Routine to validate a BPF program.
+ */
+int pcap_validate_filter(const struct bpf_insn *, int);
+
+/*
+ * 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 *);
+
+int install_bpf_program(pcap_t *, struct bpf_program *);
+
+int pcap_strcasecmp(const char *, const char *);
+
+/*
+ * Internal interfaces for pcap_createsrcstr and pcap_parsesrcstr with
+ * the additional bit of information regarding SSL support (rpcap:// vs.
+ * rpcaps://).
+ */
+int pcap_createsrcstr_ex(char *, int, const char *, const char *,
+ const char *, unsigned char, char *);
+int pcap_parsesrcstr_ex(const char *, int *, char *, char *,
+ char *, unsigned char *, char *);
+
+#ifdef YYDEBUG
+extern int pcap_debug;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pcap-namedb.h b/pcap-namedb.h
new file mode 100644
index 0000000..d5908c9
--- /dev/null
+++ b/pcap-namedb.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1994, 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.
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file! Some applications
+ * might expect to be able to include <pcap-namedb.h>.
+ */
+#include <pcap/namedb.h>
diff --git a/pcap-null.c b/pcap-null.c
new file mode 100644
index 0000000..2ae27bf
--- /dev/null
+++ b/pcap-null.c
@@ -0,0 +1,65 @@
+/*
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "pcap-int.h"
+
+static char nosup[] = "live packet capture not supported on this system";
+
+pcap_t *
+pcap_create_interface(const char *device _U_, char *ebuf)
+{
+ (void)pcap_strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE);
+ return (NULL);
+}
+
+int
+pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf _U_)
+{
+ /*
+ * There are no interfaces on which we can capture.
+ */
+ return (0);
+}
+
+#ifdef _WIN32
+int
+pcap_lookupnet(const char *device _U_, bpf_u_int32 *netp _U_,
+ bpf_u_int32 *maskp _U_, char *errbuf)
+{
+ (void)pcap_strlcpy(errbuf, nosup, PCAP_ERRBUF_SIZE);
+ return (-1);
+}
+#endif
+
+/*
+ * Libpcap version string.
+ */
+const char *
+pcap_lib_version(void)
+{
+ return (PCAP_VERSION_STRING);
+}
diff --git a/pcap-types.h b/pcap-types.h
new file mode 100644
index 0000000..7d0fe81
--- /dev/null
+++ b/pcap-types.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino 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 pcap_types_h
+#define pcap_types_h
+
+/*
+ * Get u_int defined, by hook or by crook.
+ */
+#ifdef _WIN32
+ /*
+ * This defines u_int.
+ */
+ #include <winsock2.h>
+#else /* _WIN32 */
+ /*
+ * This defines u_int, among other types.
+ */
+ #include <sys/types.h>
+#endif
+
+#endif /* pcap_types_h */
diff --git a/pcap.c b/pcap.c
new file mode 100644
index 0000000..ed8570a
--- /dev/null
+++ b/pcap.c
@@ -0,0 +1,4434 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#ifndef MSDOS
+#include <sys/file.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+struct mbuf; /* Squelch compiler warnings on some platforms for */
+struct rtentry; /* declarations in <net/if.h> */
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* _WIN32 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "diag-control.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#ifdef MSDOS
+#include "pcap-dos.h"
+#endif
+
+#include "pcap-int.h"
+
+#include "optimize.h"
+
+#ifdef HAVE_DAG_API
+#include "pcap-dag.h"
+#endif /* HAVE_DAG_API */
+
+#ifdef HAVE_SEPTEL_API
+#include "pcap-septel.h"
+#endif /* HAVE_SEPTEL_API */
+
+#ifdef HAVE_SNF_API
+#include "pcap-snf.h"
+#endif /* HAVE_SNF_API */
+
+#ifdef HAVE_TC_API
+#include "pcap-tc.h"
+#endif /* HAVE_TC_API */
+
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+#include "pcap-usb-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_BT
+#include "pcap-bt-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_BT_MONITOR
+#include "pcap-bt-monitor-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_NETFILTER
+#include "pcap-netfilter-linux.h"
+#endif
+
+#ifdef PCAP_SUPPORT_NETMAP
+#include "pcap-netmap.h"
+#endif
+
+#ifdef PCAP_SUPPORT_DBUS
+#include "pcap-dbus.h"
+#endif
+
+#ifdef PCAP_SUPPORT_RDMASNIFF
+#include "pcap-rdmasniff.h"
+#endif
+
+#ifdef PCAP_SUPPORT_DPDK
+#include "pcap-dpdk.h"
+#endif
+
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
+#ifdef _WIN32
+/*
+ * DllMain(), required when built as a Windows DLL.
+ *
+ * To quote the WSAStartup() documentation:
+ *
+ * The WSAStartup function typically leads to protocol-specific helper
+ * DLLs being loaded. As a result, the WSAStartup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * and the WSACleanup() documentation:
+ *
+ * The WSACleanup function typically leads to protocol-specific helper
+ * DLLs being unloaded. As a result, the WSACleanup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * So we don't initialize Winsock here. pcap_init() should be called
+ * to initialize pcap on both UN*X and Windows; it will initialize
+ * Winsock on Windows. (It will also be initialized as needed if
+ * pcap_init() hasn't been called.)
+ */
+BOOL WINAPI DllMain(
+ HANDLE hinstDLL _U_,
+ DWORD dwReason _U_,
+ LPVOID lpvReserved _U_
+)
+{
+ return (TRUE);
+}
+
+/*
+ * Start Winsock.
+ * Internal routine.
+ */
+static int
+internal_wsockinit(char *errbuf)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ static int err = -1;
+ static int done = 0;
+ int status;
+
+ if (done)
+ return (err);
+
+ /*
+ * Versions of Windows that don't support Winsock 2.2 are
+ * too old for us.
+ */
+ wVersionRequested = MAKEWORD(2, 2);
+ status = WSAStartup(wVersionRequested, &wsaData);
+ done = 1;
+ if (status != 0) {
+ if (errbuf != NULL) {
+ pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE,
+ status, "WSAStartup() failed");
+ }
+ return (err);
+ }
+ atexit ((void(*)(void))WSACleanup);
+ err = 0;
+ return (err);
+}
+
+/*
+ * Exported in case some applications using WinPcap/Npcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+ return (internal_wsockinit(NULL));
+}
+
+/*
+ * This is the exported function; new programs should call this.
+ * *Newer* programs should call pcap_init().
+ */
+int
+pcap_wsockinit(void)
+{
+ return (internal_wsockinit(NULL));
+}
+#endif /* _WIN32 */
+
+/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed. For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api; /* pcap_lookupdev() always fails */
+int pcap_utf_8_mode; /* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+ static int initialized;
+
+ /*
+ * Don't allow multiple calls that set different modes; that
+ * may mean a library is initializing pcap in one mode and
+ * a program using that library, or another library used by
+ * that program, is initializing it in another mode.
+ */
+ switch (opts) {
+
+ case PCAP_CHAR_ENC_LOCAL:
+ /* Leave "UTF-8 mode" off. */
+ if (initialized) {
+ if (pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (-1);
+ }
+ }
+ break;
+
+ case PCAP_CHAR_ENC_UTF_8:
+ /* Turn on "UTF-8 mode". */
+ if (initialized) {
+ if (!pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (-1);
+ }
+ }
+ pcap_utf_8_mode = 1;
+ break;
+
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified");
+ return (-1);
+ }
+
+ /*
+ * Turn the appropriate mode on for error messages; those routines
+ * are also used in rpcapd, which has no access to pcap's internal
+ * UTF-8 mode flag, so we have to call a routine to set its
+ * UTF-8 mode flag.
+ */
+ pcap_fmt_set_encoding(opts);
+
+ if (initialized) {
+ /*
+ * Nothing more to do; for example, on Windows, we've
+ * already initialized Winsock.
+ */
+ return (0);
+ }
+
+#ifdef _WIN32
+ /*
+ * Now set up Winsock.
+ */
+ if (internal_wsockinit(errbuf) == -1) {
+ /* Failed. */
+ return (-1);
+ }
+#endif
+
+ /*
+ * We're done.
+ */
+ initialized = 1;
+ pcap_new_api = 1;
+ return (0);
+}
+
+/*
+ * String containing the library version.
+ * Not explicitly exported via a header file - the right API to use
+ * is pcap_lib_version() - but some programs included it, so we
+ * provide it.
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API char pcap_version[];
+PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
+
+static void
+pcap_set_not_initialized_message(pcap_t *pcap)
+{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return;
+ }
+ /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This handle hasn't been activated yet");
+}
+
+static int
+pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_,
+ u_char *user _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_getnonblock_not_initialized(pcap_t *pcap)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (NULL);
+}
+
+static int
+pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static HANDLE
+pcap_getevent_not_initialized(pcap_t *pcap)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (INVALID_HANDLE_VALUE);
+}
+
+static int
+pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+ void *data _U_, size_t *lenp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+ const void *data _U_, size_t *lenp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static u_int
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+ int sync _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (0);
+}
+
+static int
+pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
+{
+ pcap_set_not_initialized_message(pcap);
+ 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.
+ */
+int
+pcap_can_set_rfmon(pcap_t *p)
+{
+ return (p->can_set_rfmon_op(p));
+}
+
+/*
+ * For systems where rfmon mode is never supported.
+ */
+static int
+pcap_cant_set_rfmon(pcap_t *p _U_)
+{
+ return (0);
+}
+
+/*
+ * Sets *tstamp_typesp to point to an array 1 or more supported time stamp
+ * types; the return value is the number of supported time stamp types.
+ * The list should be freed by a call to pcap_free_tstamp_types() when
+ * you're done with it.
+ *
+ * A return value of 0 means "you don't get a choice of time stamp type",
+ * in which case *tstamp_typesp is set to null.
+ *
+ * PCAP_ERROR is returned on error.
+ */
+int
+pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
+{
+ if (p->tstamp_type_count == 0) {
+ /*
+ * We don't support multiple time stamp types.
+ * That means the only type we support is PCAP_TSTAMP_HOST;
+ * set up a list containing only that type.
+ */
+ *tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp));
+ if (*tstamp_typesp == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (PCAP_ERROR);
+ }
+ **tstamp_typesp = PCAP_TSTAMP_HOST;
+ return (1);
+ } else {
+ *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
+ p->tstamp_type_count);
+ if (*tstamp_typesp == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (PCAP_ERROR);
+ }
+ (void)memcpy(*tstamp_typesp, p->tstamp_type_list,
+ sizeof(**tstamp_typesp) * p->tstamp_type_count);
+ return (p->tstamp_type_count);
+ }
+}
+
+/*
+ * In Windows, you might have a library built with one version of the
+ * C runtime library and an application built with another version of
+ * the C runtime library, which means that the library might use one
+ * version of malloc() and free() and the application might use another
+ * version of malloc() and free(). If so, that means something
+ * allocated by the library cannot be freed by the application, so we
+ * need to have a pcap_free_tstamp_types() routine to free up the list
+ * allocated by pcap_list_tstamp_types(), even though it's just a wrapper
+ * around free().
+ */
+void
+pcap_free_tstamp_types(int *tstamp_type_list)
+{
+ free(tstamp_type_list);
+}
+
+/*
+ * Default one-shot callback; overridden for capture types where the
+ * packet data cannot be guaranteed to be available after the callback
+ * returns, so that a copy must be made.
+ */
+void
+pcap_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt)
+{
+ struct oneshot_userdata *sp = (struct oneshot_userdata *)user;
+
+ *sp->hdr = *h;
+ *sp->pkt = pkt;
+}
+
+const u_char *
+pcap_next(pcap_t *p, struct pcap_pkthdr *h)
+{
+ struct oneshot_userdata s;
+ const u_char *pkt;
+
+ s.hdr = h;
+ s.pkt = &pkt;
+ s.pd = p;
+ if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0)
+ return (0);
+ return (pkt);
+}
+
+int
+pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
+ const u_char **pkt_data)
+{
+ struct oneshot_userdata s;
+
+ s.hdr = &p->pcap_header;
+ s.pkt = pkt_data;
+ s.pd = p;
+
+ /* Saves a pointer to the packet headers */
+ *pkt_header= &p->pcap_header;
+
+ if (p->rfile != NULL) {
+ int status;
+
+ /* We are on an offline capture */
+ status = pcap_offline_read(p, 1, p->oneshot_callback,
+ (u_char *)&s);
+
+ /*
+ * Return codes for pcap_offline_read() are:
+ * - 0: EOF
+ * - -1: error
+ * - >1: OK
+ * The first one ('0') conflicts with the return code of
+ * 0 from pcap_read() meaning "no packets arrived before
+ * the timeout expired", so we map it to -2 so you can
+ * distinguish between an EOF from a savefile and a
+ * "no packets arrived before the timeout expired, try
+ * again" from a live capture.
+ */
+ if (status == 0)
+ return (-2);
+ else
+ return (status);
+ }
+
+ /*
+ * Return codes for pcap_read() are:
+ * - 0: timeout
+ * - -1: error
+ * - -2: loop was broken out of with pcap_breakloop()
+ * - >1: OK
+ * The first one ('0') conflicts with the return code of 0 from
+ * pcap_offline_read() meaning "end of file".
+ */
+ return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s));
+}
+
+/*
+ * Implementation of a pcap_if_list_t.
+ */
+struct pcap_if_list {
+ pcap_if_t *beginning;
+};
+
+static struct capture_source_type {
+ int (*findalldevs_op)(pcap_if_list_t *, char *);
+ pcap_t *(*create_op)(const char *, char *, int *);
+} capture_source_types[] = {
+#ifdef HAVE_DAG_API
+ { dag_findalldevs, dag_create },
+#endif
+#ifdef HAVE_SEPTEL_API
+ { septel_findalldevs, septel_create },
+#endif
+#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
+#ifdef PCAP_SUPPORT_BT_MONITOR
+ { bt_monitor_findalldevs, bt_monitor_create },
+#endif
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+ { usb_findalldevs, usb_create },
+#endif
+#ifdef PCAP_SUPPORT_NETFILTER
+ { netfilter_findalldevs, netfilter_create },
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ { pcap_netmap_findalldevs, pcap_netmap_create },
+#endif
+#ifdef PCAP_SUPPORT_DBUS
+ { dbus_findalldevs, dbus_create },
+#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+ { rdmasniff_findalldevs, rdmasniff_create },
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+ { pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+ { airpcap_findalldevs, airpcap_create },
+#endif
+ { NULL, NULL }
+};
+
+/*
+ * Get a list of all capture sources 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.
+ */
+int
+pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
+{
+ size_t i;
+ pcap_if_list_t devlist;
+
+ /*
+ * Find all the local network interfaces on which we
+ * can capture.
+ */
+ devlist.beginning = NULL;
+ if (pcap_platform_finddevs(&devlist, errbuf) == -1) {
+ /*
+ * Failed - free all of the entries we were given
+ * before we failed.
+ */
+ if (devlist.beginning != NULL)
+ pcap_freealldevs(devlist.beginning);
+ *alldevsp = NULL;
+ return (-1);
+ }
+
+ /*
+ * Ask each of the non-local-network-interface capture
+ * source types what interfaces they have.
+ */
+ for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) {
+ if (capture_source_types[i].findalldevs_op(&devlist, errbuf) == -1) {
+ /*
+ * We had an error; free the list we've been
+ * constructing.
+ */
+ if (devlist.beginning != NULL)
+ pcap_freealldevs(devlist.beginning);
+ *alldevsp = NULL;
+ return (-1);
+ }
+ }
+
+ /*
+ * Return the first entry of the list of all devices.
+ */
+ *alldevsp = devlist.beginning;
+ return (0);
+}
+
+static 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));
+}
+
+/*
+ * 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 bit below
+ * that set if it's the "any" interface.
+ *
+ * Note: we don't sort by unit number because 1) not all interfaces have
+ * a unit number (systemd, for example, might assign interface names
+ * based on the interface's MAC address or on the physical location of
+ * the adapter's connector), and 2) if the name does end with a simple
+ * unit number, it's not a global property of the interface, it's only
+ * useful as a sort key for device names with the same prefix, so xyz0
+ * shouldn't necessarily sort before abc2. This means that interfaces
+ * with the same figure of merit will be sorted by the order in which
+ * the mechanism from which we're getting the interfaces supplies them.
+ */
+static u_int
+get_figure_of_merit(pcap_if_t *dev)
+{
+ u_int n;
+
+ n = 0;
+ if (!(dev->flags & PCAP_IF_RUNNING))
+ n |= 0x80000000;
+ if (!(dev->flags & PCAP_IF_UP))
+ n |= 0x40000000;
+
+ /*
+ * Give non-wireless interfaces that aren't disconnected a better
+ * figure of merit than interfaces that are disconnected, as
+ * "disconnected" should indicate that the interface isn't
+ * plugged into a network and thus won't give you any traffic.
+ *
+ * For wireless interfaces, it means "associated with a network",
+ * which we presume not to necessarily prevent capture, as you
+ * might run the adapter in some flavor of monitor mode.
+ */
+ if (!(dev->flags & PCAP_IF_WIRELESS) &&
+ (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
+ n |= 0x20000000;
+
+ /*
+ * Sort loopback devices after non-loopback devices, *except* for
+ * disconnected devices.
+ */
+ if (dev->flags & PCAP_IF_LOOPBACK)
+ n |= 0x10000000;
+
+ /*
+ * Sort the "any" device before loopback and disconnected devices,
+ * but after all other devices.
+ */
+ if (strcmp(dev->name, "any") == 0)
+ n |= 0x08000000;
+
+ return (n);
+}
+
+#ifndef _WIN32
+/*
+ * 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 macOS, 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 *
+#ifdef SIOCGIFDESCR
+get_if_description(const char *name)
+{
+ char *description = NULL;
+ int s;
+ struct ifreq ifrdesc;
+#ifndef IFDESCRSIZE
+ size_t descrlen = 64;
+#else
+ size_t descrlen = IFDESCRSIZE;
+#endif /* IFDESCRSIZE */
+
+ /*
+ * Get the description for the interface.
+ */
+ memset(&ifrdesc, 0, sizeof ifrdesc);
+ pcap_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 && description[0] == '\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.
+ * (If that fails, we don't worry about
+ * it, we just return NULL.)
+ */
+ if (pcap_asprintf(&description,
+ "USB bus number %ld", busnum) == -1) {
+ /* Failed. */
+ description = NULL;
+ }
+ }
+ }
+ }
+#endif
+ return (description);
+#else /* SIOCGIFDESCR */
+get_if_description(const char *name _U_)
+{
+ return (NULL);
+#endif /* SIOCGIFDESCR */
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, return a pointer to its entry.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, return a pointer to
+ * the new entry, otherwise return NULL and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_if(pcap_if_list_t *devlistp, const char *name,
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
+{
+ bpf_u_int32 pcap_flags;
+
+ /*
+ * Convert IFF_ flags to pcap flags.
+ */
+ pcap_flags = 0;
+#ifdef IFF_LOOPBACK
+ if (if_flags & IFF_LOOPBACK)
+ pcap_flags |= PCAP_IF_LOOPBACK;
+#else
+ /*
+ * We don't have IFF_LOOPBACK, so look at the device name to
+ * see if it looks like a loopback device.
+ */
+ if (name[0] == 'l' && name[1] == 'o' &&
+ (PCAP_ISDIGIT(name[2]) || name[2] == '\0'))
+ pcap_flags |= PCAP_IF_LOOPBACK;
+#endif
+#ifdef IFF_UP
+ if (if_flags & IFF_UP)
+ pcap_flags |= PCAP_IF_UP;
+#endif
+#ifdef IFF_RUNNING
+ if (if_flags & IFF_RUNNING)
+ pcap_flags |= PCAP_IF_RUNNING;
+#endif
+
+ /*
+ * Attempt to find an entry for this device; if we don't find one,
+ * attempt to add one.
+ */
+ return (find_or_add_dev(devlistp, name, pcap_flags,
+ get_flags_func, get_if_description(name), errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * 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.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, add the specified
+ * address to its list of addresses if that address is non-null, and
+ * return 0, otherwise return -1 and set errbuf to an error message.
+ *
+ * (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_if(pcap_if_list_t *devlistp, const char *name,
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
+ 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;
+
+ /*
+ * Check whether the device exists and, if not, add it.
+ */
+ curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
+ errbuf);
+ if (curdev == NULL) {
+ /*
+ * Error - give up.
+ */
+ return (-1);
+ }
+
+ 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, and we have an
+ * address for it; add an entry for that address to the
+ * interface's list of addresses.
+ */
+ return (add_addr_to_dev(curdev, addr, addr_size, netmask,
+ netmask_size, broadaddr, broadaddr_size, dstaddr,
+ dstaddr_size, errbuf));
+}
+#endif /* _WIN32 */
+
+/*
+ * Add an entry to the list of addresses for an interface.
+ * "curdev" is the entry for that interface.
+ */
+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;
+
+ /*
+ * Allocate the new entry and fill it in.
+ */
+ curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
+ if (curaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+
+ curaddr->next = NULL;
+ if (addr != NULL && addr_size != 0) {
+ curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
+ if (curaddr->addr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->addr = NULL;
+
+ if (netmask != NULL && netmask_size != 0) {
+ curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
+ if (curaddr->netmask == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ if (curaddr->addr != NULL)
+ free(curaddr->addr);
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->netmask = NULL;
+
+ if (broadaddr != NULL && broadaddr_size != 0) {
+ curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
+ if (curaddr->broadaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ 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 && dstaddr_size != 0) {
+ curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
+ if (curaddr->dstaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ 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);
+}
+
+/*
+ * 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, attempt to add an entry for it, with the specified
+ * flags and description, and, if that succeeds, return 0, otherwise
+ * return -1 and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+ get_if_flags_func get_flags_func, const char *description, char *errbuf)
+{
+ pcap_if_t *curdev;
+
+ /*
+ * Is there already an entry in the list for this device?
+ */
+ curdev = find_dev(devlistp, name);
+ if (curdev != NULL) {
+ /*
+ * Yes, return it.
+ */
+ return (curdev);
+ }
+
+ /*
+ * No, we didn't find it.
+ */
+
+ /*
+ * Try to get additional flags for the device.
+ */
+ if ((*get_flags_func)(name, &flags, errbuf) == -1) {
+ /*
+ * Failed.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now, try to add it to the list of devices.
+ */
+ return (add_dev(devlistp, name, flags, description, errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices, and return
+ * the entry for it if we find it or NULL if we don't.
+ */
+pcap_if_t *
+find_dev(pcap_if_list_t *devlistp, const char *name)
+{
+ pcap_if_t *curdev;
+
+ /*
+ * Is there an entry in the list for this device?
+ */
+ for (curdev = devlistp->beginning; curdev != NULL;
+ curdev = curdev->next) {
+ if (strcmp(name, curdev->name) == 0) {
+ /*
+ * We found it, so, yes, there is. No need to
+ * add it. Provide the entry we found to our
+ * caller.
+ */
+ return (curdev);
+ }
+ }
+
+ /*
+ * No.
+ */
+ return (NULL);
+}
+
+/*
+ * Attempt to add an entry for a device, with the specified flags
+ * and description, and, if that succeeds, return 0 and return a pointer
+ * to the new entry, otherwise return NULL and set errbuf to an error
+ * message.
+ *
+ * If we weren't given a description, try to get one.
+ */
+pcap_if_t *
+add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+ const char *description, char *errbuf)
+{
+ pcap_if_t *curdev, *prevdev, *nextdev;
+ u_int this_figure_of_merit, nextdev_figure_of_merit;
+
+ curdev = malloc(sizeof(pcap_if_t));
+ if (curdev == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+
+ /*
+ * Fill in the entry.
+ */
+ curdev->next = NULL;
+ curdev->name = strdup(name);
+ if (curdev->name == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curdev);
+ return (NULL);
+ }
+ if (description == NULL) {
+ /*
+ * We weren't handed a description for the interface.
+ */
+ curdev->description = NULL;
+ } else {
+ /*
+ * We were handed a description; make a copy.
+ */
+ curdev->description = strdup(description);
+ if (curdev->description == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curdev->name);
+ free(curdev);
+ return (NULL);
+ }
+ }
+ curdev->addresses = NULL; /* list starts out as empty */
+ curdev->flags = flags;
+
+ /*
+ * Add it to the list, in the appropriate location.
+ * First, get the "figure of merit" for this interface.
+ */
+ this_figure_of_merit = get_figure_of_merit(curdev);
+
+ /*
+ * 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.
+ */
+ prevdev = NULL;
+ for (;;) {
+ /*
+ * Get the interface after this one.
+ */
+ if (prevdev == NULL) {
+ /*
+ * The next element is the first element.
+ */
+ nextdev = devlistp->beginning;
+ } 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's figure of merit less
+ * than the next interface's figure of merit,
+ * meaning that the new interface is better
+ * than the next interface?
+ */
+ 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".
+ */
+ 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. Make it
+ * the first element in the list of devices.
+ */
+ devlistp->beginning = curdev;
+ } else
+ prevdev->next = curdev;
+ return (curdev);
+}
+
+/*
+ * 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);
+ }
+}
+
+/*
+ * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
+ * it actually returns the names of all interfaces, with a NUL separator
+ * between them; some callers may depend on that.
+ *
+ * MS-DOS has its own pcap_lookupdev(), but that might be useful only
+ * as an optimization.
+ *
+ * In all other cases, we just use pcap_findalldevs() to get a list of
+ * devices, and pick from that list.
+ */
+#if !defined(HAVE_PACKET32) && !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(char *errbuf)
+{
+ pcap_if_t *alldevs;
+#ifdef _WIN32
+ /*
+ * Windows - use the same size as the old WinPcap 3.1 code.
+ * XXX - this is probably bigger than it needs to be.
+ */
+ #define IF_NAMESIZE 8192
+#else
+ /*
+ * UN*X - use the system's interface name size.
+ * XXX - that might not be large enough for capture devices
+ * that aren't regular network interfaces.
+ */
+ /* for old BSD systems, including bsdi3 */
+ #ifndef IF_NAMESIZE
+ #define IF_NAMESIZE IFNAMSIZ
+ #endif
+#endif
+ static char device[IF_NAMESIZE + 1];
+ char *ret;
+
+ /*
+ * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+ * it may return UTF-16 strings, for backwards-compatibility
+ * reasons, and we're also disabling the hack to make that work,
+ * for not-going-past-the-end-of-a-string reasons, and 2) we
+ * want its behavior to be consistent.
+ *
+ * In addition, it's not thread-safe, so we've marked it as
+ * deprecated.
+ */
+ if (pcap_new_api) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+ return (NULL);
+ }
+
+ 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)pcap_strlcpy(errbuf, "no suitable device found",
+ PCAP_ERRBUF_SIZE);
+ ret = NULL;
+ } else {
+ /*
+ * Return the name of the first device on the list.
+ */
+ (void)pcap_strlcpy(device, alldevs->name, sizeof(device));
+ ret = device;
+ }
+
+ pcap_freealldevs(alldevs);
+ return (ret);
+}
+#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * We don't just fetch the entire list of devices, search for the
+ * particular device, and use its first IPv4 address, as that's too
+ * much work to get just one device's netmask.
+ *
+ * If we had an API to get attributes for a given device, we could
+ * use that.
+ */
+int
+pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
+ 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_LINUX_USBMON
+ || strstr(device, "usbmon") != NULL
+#endif
+#ifdef HAVE_SNF_API
+ || strstr(device, "snf") != NULL
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ || strncmp(device, "netmap:", 7) == 0
+ || strncmp(device, "vale", 4) == 0
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+ || strncmp(device, "dpdk:", 5) == 0
+#endif
+ ) {
+ *netp = *maskp = 0;
+ return 0;
+ }
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "socket");
+ return (-1);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+ /* XXX Work around Linux kernel bug */
+ ifr.ifr_addr.sa_family = AF_INET;
+#endif
+ (void)pcap_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,
+ "%s: no IPv4 address assigned", device);
+ } else {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFADDR: %s", device);
+ }
+ (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)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFNETMASK: %s", device);
+ (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);
+}
+#endif /* !defined(_WIN32) && !defined(MSDOS) */
+
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+
+/*
+ * Extract a substring from a string.
+ */
+static char *
+get_substring(const char *p, size_t len, char *ebuf)
+{
+ char *token;
+
+ token = malloc(len + 1);
+ if (token == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+ memcpy(token, p, len);
+ token[len] = '\0';
+ return (token);
+}
+
+/*
+ * Parse a capture source that might be a URL.
+ *
+ * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
+ * are set to NULL, *pathp is set to point to the source, and 0 is
+ * returned.
+ *
+ * If source is a URL, and the URL refers to a local device (a special
+ * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
+ * to NULL, *pathp is set to point to the device name, and 0 is returned.
+ *
+ * If source is a URL, and it's not a special case that refers to a local
+ * device, and the parse succeeds:
+ *
+ * *schemep is set to point to an allocated string containing the scheme;
+ *
+ * if user information is present in the URL, *userinfop is set to point
+ * to an allocated string containing the user information, otherwise
+ * it's set to NULL;
+ *
+ * if host information is present in the URL, *hostp is set to point
+ * to an allocated string containing the host information, otherwise
+ * it's set to NULL;
+ *
+ * if a port number is present in the URL, *portp is set to point
+ * to an allocated string containing the port number, otherwise
+ * it's set to NULL;
+ *
+ * *pathp is set to point to an allocated string containing the
+ * path;
+ *
+ * and 0 is returned.
+ *
+ * If the parse fails, ebuf is set to an error string, and -1 is returned.
+ */
+static int
+pcap_parse_source(const char *source, char **schemep, char **userinfop,
+ char **hostp, char **portp, char **pathp, char *ebuf)
+{
+ char *colonp;
+ size_t scheme_len;
+ char *scheme;
+ const char *endp;
+ size_t authority_len;
+ char *authority;
+ char *parsep, *atsignp, *bracketp;
+ char *userinfo, *host, *port, *path;
+
+ /*
+ * Start out returning nothing.
+ */
+ *schemep = NULL;
+ *userinfop = NULL;
+ *hostp = NULL;
+ *portp = NULL;
+ *pathp = NULL;
+
+ /*
+ * RFC 3986 says:
+ *
+ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ *
+ * hier-part = "//" authority path-abempty
+ * / path-absolute
+ * / path-rootless
+ * / path-empty
+ *
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ *
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ *
+ * Step 1: look for the ":" at the end of the scheme.
+ * A colon in the source is *NOT* sufficient to indicate that
+ * this is a URL, as interface names on some platforms might
+ * include colons (e.g., I think some Solaris interfaces
+ * might).
+ */
+ colonp = strchr(source, ':');
+ if (colonp == NULL) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * All schemes must have "//" after them, i.e. we only support
+ * hier-part = "//" authority path-abempty, not
+ * hier-part = path-absolute
+ * hier-part = path-rootless
+ * hier-part = path-empty
+ *
+ * We need that in order to distinguish between a local device
+ * name that happens to contain a colon and a URI.
+ */
+ if (strncmp(colonp + 1, "//", 2) != 0) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * XXX - check whether the purported scheme could be a scheme?
+ */
+
+ /*
+ * OK, this looks like a URL.
+ * Get the scheme.
+ */
+ scheme_len = colonp - source;
+ scheme = malloc(scheme_len + 1);
+ if (scheme == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ memcpy(scheme, source, scheme_len);
+ scheme[scheme_len] = '\0';
+
+ /*
+ * Treat file: specially - take everything after file:// as
+ * the pathname.
+ */
+ if (pcap_strcasecmp(scheme, "file") == 0) {
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(scheme);
+ return (-1);
+ }
+ *schemep = scheme;
+ return (0);
+ }
+
+ /*
+ * The WinPcap documentation says you can specify a local
+ * interface with "rpcap://{device}"; we special-case
+ * that here. If the scheme is "rpcap", and there are
+ * no slashes past the "//", we just return the device.
+ *
+ * XXX - %-escaping?
+ */
+ if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+ pcap_strcasecmp(scheme, "rpcaps") == 0) &&
+ strchr(colonp + 3, '/') == NULL) {
+ /*
+ * Local device.
+ *
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ free(scheme);
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * OK, now start parsing the authority.
+ * Get token, terminated with / or terminated at the end of
+ * the string.
+ */
+ authority_len = strcspn(colonp + 3, "/");
+ authority = get_substring(colonp + 3, authority_len, ebuf);
+ if (authority == NULL) {
+ /*
+ * Error.
+ */
+ free(scheme);
+ return (-1);
+ }
+ endp = colonp + 3 + authority_len;
+
+ /*
+ * Now carve the authority field into its components.
+ */
+ parsep = authority;
+
+ /*
+ * Is there a userinfo field?
+ */
+ atsignp = strchr(parsep, '@');
+ if (atsignp != NULL) {
+ /*
+ * Yes.
+ */
+ size_t userinfo_len;
+
+ userinfo_len = atsignp - parsep;
+ userinfo = get_substring(parsep, userinfo_len, ebuf);
+ if (userinfo == NULL) {
+ /*
+ * Error.
+ */
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = atsignp + 1;
+ } else {
+ /*
+ * No.
+ */
+ userinfo = NULL;
+ }
+
+ /*
+ * Is there a host field?
+ */
+ if (*parsep == '\0') {
+ /*
+ * No; there's no host field or port field.
+ */
+ host = NULL;
+ port = NULL;
+ } else {
+ /*
+ * Yes.
+ */
+ size_t host_len;
+
+ /*
+ * Is it an IP-literal?
+ */
+ if (*parsep == '[') {
+ /*
+ * Yes.
+ * Treat verything up to the closing square
+ * bracket as the IP-Literal; we don't worry
+ * about whether it's a valid IPv6address or
+ * IPvFuture (or an IPv4address, for that
+ * matter, just in case we get handed a
+ * URL with an IPv4 IP-Literal, of the sort
+ * that pcap_createsrcstr() used to generate,
+ * and that pcap_parsesrcstr(), in the original
+ * WinPcap code, accepted).
+ */
+ bracketp = strchr(parsep, ']');
+ if (bracketp == NULL) {
+ /*
+ * There's no closing square bracket.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "IP-literal in URL doesn't end with ]");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ if (*(bracketp + 1) != '\0' &&
+ *(bracketp + 1) != ':') {
+ /*
+ * There's extra crud after the
+ * closing square bracketn.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Extra text after IP-literal in URL");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ host_len = (bracketp - 1) - parsep;
+ host = get_substring(parsep + 1, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = bracketp + 1;
+ } else {
+ /*
+ * No.
+ * Treat everything up to a : or the end of
+ * the string as the host.
+ */
+ host_len = strcspn(parsep, ":");
+ host = get_substring(parsep, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = parsep + host_len;
+ }
+
+ /*
+ * Is there a port field?
+ */
+ if (*parsep == ':') {
+ /*
+ * Yes. It's the rest of the authority field.
+ */
+ size_t port_len;
+
+ parsep++;
+ port_len = strlen(parsep);
+ port = get_substring(parsep, port_len, ebuf);
+ if (port == NULL) {
+ /*
+ * Error.
+ */
+ free(host);
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ } else {
+ /*
+ * No.
+ */
+ port = NULL;
+ }
+ }
+ free(authority);
+
+ /*
+ * Everything else is the path. Strip off the leading /.
+ */
+ if (*endp == '\0')
+ path = strdup("");
+ else
+ path = strdup(endp + 1);
+ if (path == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(port);
+ free(host);
+ free(userinfo);
+ free(scheme);
+ return (-1);
+ }
+ *schemep = scheme;
+ *userinfop = userinfo;
+ *hostp = host;
+ *portp = port;
+ *pathp = path;
+ return (0);
+}
+
+int
+pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
+ const char *name, unsigned char uses_ssl, char *errbuf)
+{
+ switch (type) {
+
+ case PCAP_SRC_FILE:
+ pcap_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
+ if (name != NULL && *name != '\0') {
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+ return (0);
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The file name cannot be NULL.");
+ return (-1);
+ }
+
+ case PCAP_SRC_IFREMOTE:
+ pcap_strlcpy(source,
+ (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING),
+ PCAP_BUF_SIZE);
+ if (host != NULL && *host != '\0') {
+ if (strchr(host, ':') != NULL) {
+ /*
+ * The host name contains a colon, so it's
+ * probably an IPv6 address, and needs to
+ * be included in square brackets.
+ */
+ pcap_strlcat(source, "[", PCAP_BUF_SIZE);
+ pcap_strlcat(source, host, PCAP_BUF_SIZE);
+ pcap_strlcat(source, "]", PCAP_BUF_SIZE);
+ } else
+ pcap_strlcat(source, host, PCAP_BUF_SIZE);
+
+ if (port != NULL && *port != '\0') {
+ pcap_strlcat(source, ":", PCAP_BUF_SIZE);
+ pcap_strlcat(source, port, PCAP_BUF_SIZE);
+ }
+
+ pcap_strlcat(source, "/", PCAP_BUF_SIZE);
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The host name cannot be NULL.");
+ return (-1);
+ }
+
+ if (name != NULL && *name != '\0')
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ case PCAP_SRC_IFLOCAL:
+ pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+
+ if (name != NULL && *name != '\0')
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The interface type is not valid.");
+ return (-1);
+ }
+}
+
+
+int
+pcap_createsrcstr(char *source, int type, const char *host, const char *port,
+ const char *name, char *errbuf)
+{
+ return (pcap_createsrcstr_ex(source, type, host, port, name, 0, errbuf));
+}
+
+int
+pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+ char *name, unsigned char *uses_ssl, char *errbuf)
+{
+ char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
+
+ /* Initialization stuff */
+ if (host)
+ *host = '\0';
+ if (port)
+ *port = '\0';
+ if (name)
+ *name = '\0';
+ if (uses_ssl)
+ *uses_ssl = 0;
+
+ /* Parse the source string */
+ if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
+ &tmpport, &tmppath, errbuf) == -1) {
+ /*
+ * Fail.
+ */
+ return (-1);
+ }
+
+ if (scheme == NULL) {
+ /*
+ * Local device.
+ */
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ return (0);
+ }
+
+ int is_rpcap = 0;
+ if (strcmp(scheme, "rpcaps") == 0) {
+ is_rpcap = 1;
+ if (uses_ssl) *uses_ssl = 1;
+ } else if (strcmp(scheme, "rpcap") == 0) {
+ is_rpcap = 1;
+ }
+
+ if (is_rpcap) {
+ /*
+ * rpcap[s]://
+ *
+ * pcap_parse_source() has already handled the case of
+ * rpcap[s]://device
+ */
+ if (host && tmphost) {
+ if (tmpuserinfo)
+ snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+ tmpuserinfo, tmphost);
+ else
+ pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
+ }
+ if (port && tmpport)
+ pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE);
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFREMOTE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+ }
+
+ if (strcmp(scheme, "file") == 0) {
+ /*
+ * file://
+ */
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_FILE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+ }
+
+ /*
+ * Neither rpcap: nor file:; just treat the entire string
+ * as a local device.
+ */
+ if (name)
+ pcap_strlcpy(name, source, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+ char *name, char *errbuf)
+{
+ return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf));
+}
+#endif
+
+pcap_t *
+pcap_create(const char *device, char *errbuf)
+{
+ size_t i;
+ int is_theirs;
+ pcap_t *p;
+ char *device_str;
+
+ /*
+ * 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 (device == NULL)
+ device_str = strdup("any");
+ else {
+#ifdef _WIN32
+ /*
+ * On Windows, for backwards compatibility reasons,
+ * pcap_lookupdev() returns a pointer to a sequence of
+ * pairs of UTF-16LE device names and local code page
+ * description strings.
+ *
+ * This means that if a program uses pcap_lookupdev()
+ * to get a default device, and hands that to an API
+ * that opens devices, we'll get handed a UTF-16LE
+ * string, not a string in the local code page.
+ *
+ * To work around that, we check whether the string
+ * looks as if it might be a UTF-16LE string and, if
+ * so, convert it back to the local code page's
+ * extended ASCII.
+ *
+ * We disable that check in "new API" mode, because:
+ *
+ * 1) You *cannot* reliably detect whether a
+ * string is UTF-16LE or not; "a" could either
+ * be a one-character ASCII string or the first
+ * character of a UTF-16LE string.
+ *
+ * 2) Doing that test can run past the end of
+ * the string, if it's a 1-character ASCII
+ * string
+ *
+ * This particular version of this heuristic dates
+ * back to WinPcap 4.1.1; PacketOpenAdapter() does
+ * uses the same heuristic, with the exact same
+ * vulnerability.
+ *
+ * That's why we disable this in "new API" mode.
+ * We keep it around in legacy mode for backwards
+ * compatibility.
+ */
+ if (!pcap_new_api && 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_fmt_errmsg_for_errno(errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "malloc");
+ return (NULL);
+ }
+
+ snprintf(device_str, length + 1, "%ws",
+ (const wchar_t *)device);
+ } else
+#endif
+ device_str = strdup(device);
+ }
+ if (device_str == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+
+ /*
+ * Try each of the non-local-network-interface capture
+ * source types until we find one that works for this
+ * device or run out of types.
+ */
+ for (i = 0; capture_source_types[i].create_op != NULL; i++) {
+ is_theirs = 0;
+ p = capture_source_types[i].create_op(device_str, errbuf,
+ &is_theirs);
+ if (is_theirs) {
+ /*
+ * The device name refers to a device of the
+ * type in question; either it succeeded,
+ * in which case p refers to a pcap_t to
+ * later activate for the device, or it
+ * failed, in which case p is null and we
+ * 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);
+ }
+ }
+
+ /*
+ * OK, try it as a regular network interface.
+ */
+ 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);
+}
+
+/*
+ * Set nonblocking mode on an unactivated pcap_t; this sets a flag
+ * checked by pcap_activate(), which sets the mode after calling
+ * the activate routine.
+ */
+static int
+pcap_setnonblock_unactivated(pcap_t *p, int nonblock)
+{
+ p->opt.nonblock = nonblock;
+ return (0);
+}
+
+static void
+initialize_ops(pcap_t *p)
+{
+ /*
+ * Set operation pointers for operations that only work on
+ * an activated pcap_t to point to a routine that returns
+ * a "this isn't activated" error.
+ */
+ p->read_op = pcap_read_not_initialized;
+ p->inject_op = pcap_inject_not_initialized;
+ p->setfilter_op = pcap_setfilter_not_initialized;
+ p->setdirection_op = pcap_setdirection_not_initialized;
+ p->set_datalink_op = pcap_set_datalink_not_initialized;
+ p->getnonblock_op = pcap_getnonblock_not_initialized;
+ p->stats_op = pcap_stats_not_initialized;
+#ifdef _WIN32
+ p->stats_ex_op = pcap_stats_ex_not_initialized;
+ p->setbuff_op = pcap_setbuff_not_initialized;
+ p->setmode_op = pcap_setmode_not_initialized;
+ p->setmintocopy_op = pcap_setmintocopy_not_initialized;
+ p->getevent_op = pcap_getevent_not_initialized;
+ p->oid_get_request_op = pcap_oid_get_request_not_initialized;
+ p->oid_set_request_op = pcap_oid_set_request_not_initialized;
+ p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized;
+ p->setuserbuffer_op = pcap_setuserbuffer_not_initialized;
+ p->live_dump_op = pcap_live_dump_not_initialized;
+ p->live_dump_ended_op = pcap_live_dump_ended_not_initialized;
+ p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized;
+#endif
+
+ /*
+ * Default cleanup operation - implementations can override
+ * this, but should call pcap_cleanup_live_common() after
+ * doing their own additional cleanup.
+ */
+ p->cleanup_op = pcap_cleanup_live_common;
+
+ /*
+ * In most cases, the standard one-shot callback can
+ * be used for pcap_next()/pcap_next_ex().
+ */
+ p->oneshot_callback = pcap_oneshot;
+
+ /*
+ * Default breakloop operation - implementations can override
+ * this, but should call pcap_breakloop_common() before doing
+ * their own logic.
+ */
+ p->breakloop_op = pcap_breakloop_common;
+}
+
+static pcap_t *
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
+{
+ char *chunk;
+ pcap_t *p;
+
+ /*
+ * total_size is the size of a structure containing a pcap_t
+ * followed by a private structure.
+ */
+ chunk = calloc(total_size, 1);
+ if (chunk == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+
+ /*
+ * Get a pointer to the pcap_t at the beginning.
+ */
+ p = (pcap_t *)chunk;
+
+#ifdef _WIN32
+ p->handle = INVALID_HANDLE_VALUE; /* not opened yet */
+#else /* _WIN32 */
+ p->fd = -1; /* not opened yet */
+#ifndef MSDOS
+ p->selectable_fd = -1;
+ p->required_select_timeout = NULL;
+#endif /* MSDOS */
+#endif /* _WIN32 */
+
+ /*
+ * private_offset is the offset, in bytes, of the private
+ * data from the beginning of the structure.
+ *
+ * Set the pointer to the private data; that's private_offset
+ * bytes past the pcap_t.
+ */
+ p->priv = (void *)(chunk + private_offset);
+
+ return (p);
+}
+
+pcap_t *
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
+{
+ pcap_t *p;
+
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
+ 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
+ * the op to its routine to check whether a particular
+ * device supports it.
+ */
+ p->can_set_rfmon_op = pcap_cant_set_rfmon;
+
+ /*
+ * If pcap_setnonblock() is called on a not-yet-activated
+ * pcap_t, default to setting a flag and turning
+ * on non-blocking mode when activated.
+ */
+ p->setnonblock_op = pcap_setnonblock_unactivated;
+
+ initialize_ops(p);
+
+ /* put in some defaults*/
+ p->snapshot = 0; /* max packet size unspecified */
+ p->opt.timeout = 0; /* no timeout specified */
+ p->opt.buffer_size = 0; /* use the platform's default */
+ p->opt.promisc = 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;
+ /*
+ * Platform-dependent options.
+ */
+#ifdef __linux__
+ p->opt.protocol = 0;
+#endif
+#ifdef _WIN32
+ p->opt.nocapture_local = 0;
+#endif
+
+ /*
+ * Start out with no BPF code generation flags set.
+ */
+ p->bpf_codegen_flags = 0;
+
+ return (p);
+}
+
+int
+pcap_check_activated(pcap_t *p)
+{
+ if (p->activated) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+ " operation on activated capture");
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pcap_set_snaplen(pcap_t *p, int snaplen)
+{
+ if (pcap_check_activated(p))
+ return (PCAP_ERROR_ACTIVATED);
+ p->snapshot = snaplen;
+ return (0);
+}
+
+int
+pcap_set_promisc(pcap_t *p, int promisc)
+{
+ if (pcap_check_activated(p))
+ return (PCAP_ERROR_ACTIVATED);
+ p->opt.promisc = promisc;
+ return (0);
+}
+
+int
+pcap_set_rfmon(pcap_t *p, int rfmon)
+{
+ if (pcap_check_activated(p))
+ return (PCAP_ERROR_ACTIVATED);
+ p->opt.rfmon = rfmon;
+ return (0);
+}
+
+int
+pcap_set_timeout(pcap_t *p, int timeout_ms)
+{
+ if (pcap_check_activated(p))
+ return (PCAP_ERROR_ACTIVATED);
+ p->opt.timeout = timeout_ms;
+ return (0);
+}
+
+int
+pcap_set_tstamp_type(pcap_t *p, int tstamp_type)
+{
+ 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_type < 0)
+ return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
+
+ /*
+ * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST;
+ * the default time stamp type is PCAP_TSTAMP_HOST.
+ */
+ 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);
+ }
+ }
+ }
+
+ /*
+ * 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)
+{
+ int status;
+
+ /*
+ * Catch attempts to re-activate an already-activated
+ * pcap_t; this should, for example, catch code that
+ * calls pcap_open_live() followed by pcap_activate(),
+ * as some code that showed up in a Stack Exchange
+ * question did.
+ */
+ if (pcap_check_activated(p))
+ return (PCAP_ERROR_ACTIVATED);
+ status = p->activate_op(p);
+ if (status >= 0) {
+ /*
+ * If somebody requested non-blocking mode before
+ * calling pcap_activate(), turn it on now.
+ */
+ if (p->opt.nonblock) {
+ status = p->setnonblock_op(p, 1);
+ if (status < 0) {
+ /*
+ * Failed. Undo everything done by
+ * the activate operation.
+ */
+ p->cleanup_op(p);
+ initialize_ops(p);
+ return (status);
+ }
+ }
+ p->activated = 1;
+ } else {
+ if (p->errbuf[0] == '\0') {
+ /*
+ * No error message supplied by the activate routine;
+ * for the benefit of programs that don't specially
+ * handle errors other than PCAP_ERROR, return the
+ * error message corresponding to the status.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
+ pcap_statustostr(status));
+ }
+
+ /*
+ * Undo any operation pointer setting, etc. done by
+ * the activate operation.
+ */
+ initialize_ops(p);
+ }
+ return (status);
+}
+
+pcap_t *
+pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf)
+{
+ pcap_t *p;
+ int status;
+#ifdef ENABLE_REMOTE
+ char host[PCAP_BUF_SIZE + 1];
+ char port[PCAP_BUF_SIZE + 1];
+ char name[PCAP_BUF_SIZE + 1];
+ int srctype;
+
+ /*
+ * 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 (device == NULL)
+ device = "any";
+
+ /*
+ * Retrofit - we have to make older applications compatible with
+ * remote capture.
+ * So we're calling pcap_open_remote() from here; this is a very
+ * dirty hack.
+ * Obviously, we cannot exploit all the new features; for instance,
+ * we cannot send authentication, we cannot use a UDP data connection,
+ * and so on.
+ */
+ if (pcap_parsesrcstr(device, &srctype, host, port, name, errbuf))
+ return (NULL);
+
+ if (srctype == PCAP_SRC_IFREMOTE) {
+ /*
+ * Although we already have host, port and iface, we prefer
+ * to pass only 'device' to pcap_open_rpcap(), so that it has
+ * to call pcap_parsesrcstr() again.
+ * This is less optimized, but much clearer.
+ */
+ return (pcap_open_rpcap(device, snaplen,
+ promisc ? PCAP_OPENFLAG_PROMISCUOUS : 0, to_ms,
+ NULL, errbuf));
+ }
+ if (srctype == PCAP_SRC_FILE) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+ return (NULL);
+ }
+ if (srctype == PCAP_SRC_IFLOCAL) {
+ /*
+ * If it starts with rpcap://, that refers to a local device
+ * (no host part in the URL). Remove the rpcap://, and
+ * fall through to the regular open path.
+ */
+ if (strncmp(device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) {
+ size_t len = strlen(device) - strlen(PCAP_SRC_IF_STRING) + 1;
+
+ if (len > 0)
+ device += strlen(PCAP_SRC_IF_STRING);
+ }
+ }
+#endif /* ENABLE_REMOTE */
+
+ p = pcap_create(device, errbuf);
+ if (p == NULL)
+ return (NULL);
+ status = pcap_set_snaplen(p, snaplen);
+ if (status < 0)
+ goto fail;
+ status = pcap_set_promisc(p, promisc);
+ if (status < 0)
+ goto fail;
+ status = pcap_set_timeout(p, to_ms);
+ if (status < 0)
+ goto fail;
+ /*
+ * Mark this as opened with pcap_open_live(), so that, for
+ * example, we show the full list of DLT_ values, rather
+ * than just the ones that are compatible with capturing
+ * when not in monitor mode. That allows existing applications
+ * to work the way they used to work, but allows new applications
+ * that know about the new open API to, for example, find out the
+ * DLT_ values that they can select without changing whether
+ * the adapter is in monitor mode or not.
+ */
+ p->oldstyle = 1;
+ status = pcap_activate(p);
+ if (status < 0)
+ goto fail;
+ return (p);
+fail:
+ if (status == PCAP_ERROR)
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+ PCAP_ERRBUF_SIZE - 3, 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)", device,
+ pcap_statustostr(status), PCAP_ERRBUF_SIZE - 6, p->errbuf);
+ else
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+ pcap_statustostr(status));
+ pcap_close(p);
+ return (NULL);
+}
+
+pcap_t *
+pcap_open_offline_common(char *ebuf, size_t total_size, size_t private_offset)
+{
+ pcap_t *p;
+
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
+ if (p == NULL)
+ return (NULL);
+
+ p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+
+ return (p);
+}
+
+int
+pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ return (p->read_op(p, cnt, callback, user));
+}
+
+int
+pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ register int n;
+
+ for (;;) {
+ if (p->rfile != NULL) {
+ /*
+ * 0 means EOF, so don't loop if we get 0.
+ */
+ n = pcap_offline_read(p, cnt, callback, user);
+ } else {
+ /*
+ * XXX keep reading until we get something
+ * (or an error occurs)
+ */
+ do {
+ n = p->read_op(p, cnt, callback, user);
+ } while (n == 0);
+ }
+ if (n <= 0)
+ return (n);
+ if (!PACKET_COUNT_IS_UNLIMITED(cnt)) {
+ cnt -= n;
+ if (cnt <= 0)
+ return (0);
+ }
+ }
+}
+
+/*
+ * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate.
+ */
+void
+pcap_breakloop(pcap_t *p)
+{
+ p->breakloop_op(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
+ * this platform doesn't support changing the
+ * DLT for an interface. Return a list of DLTs
+ * containing only the DLT this device supports.
+ */
+ *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
+ if (*dlt_buffer == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (PCAP_ERROR);
+ }
+ **dlt_buffer = p->linktype;
+ return (1);
+ } else {
+ *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
+ if (*dlt_buffer == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (PCAP_ERROR);
+ }
+ (void)memcpy(*dlt_buffer, p->dlt_list,
+ sizeof(**dlt_buffer) * p->dlt_count);
+ return (p->dlt_count);
+ }
+}
+
+/*
+ * In Windows, you might have a library built with one version of the
+ * C runtime library and an application built with another version of
+ * the C runtime library, which means that the library might use one
+ * version of malloc() and free() and the application might use another
+ * version of malloc() and free(). If so, that means something
+ * allocated by the library cannot be freed by the application, so we
+ * need to have a pcap_free_datalinks() routine to free up the list
+ * allocated by pcap_list_datalinks(), even though it's just a wrapper
+ * around free().
+ */
+void
+pcap_free_datalinks(int *dlt_list)
+{
+ free(dlt_list);
+}
+
+int
+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
+ * have a "set datalink" operation, which means
+ * this platform doesn't support changing the
+ * DLT for an interface. Check whether the new
+ * DLT is the one this interface supports.
+ */
+ if (p->linktype != dlt)
+ goto unsupported;
+
+ /*
+ * It is, so there's nothing we need to do here.
+ */
+ return (0);
+ }
+ for (i = 0; i < p->dlt_count; i++)
+ if (p->dlt_list[i] == (u_int)dlt)
+ break;
+ if (i >= p->dlt_count)
+ goto unsupported;
+ if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB &&
+ dlt == DLT_DOCSIS) {
+ /*
+ * This is presumably an Ethernet device, as the first
+ * link-layer type it offers is DLT_EN10MB, and the only
+ * other type it offers is DLT_DOCSIS. That means that
+ * we can't tell the driver to supply DOCSIS link-layer
+ * headers - we're just pretending that's what we're
+ * getting, as, presumably, we're capturing on a dedicated
+ * link to a Cisco Cable Modem Termination System, and
+ * it's putting raw DOCSIS frames on the wire inside low-level
+ * Ethernet framing.
+ */
+ p->linktype = dlt;
+ return (0);
+ }
+ if (p->set_datalink_op(p, dlt) == -1)
+ return (-1);
+ p->linktype = dlt;
+ return (0);
+
+unsupported:
+ dlt_name = pcap_datalink_val_to_name(dlt);
+ if (dlt_name != NULL) {
+ (void) 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),
+ "DLT %d is not one of the DLTs supported by this device",
+ dlt);
+ }
+ return (-1);
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison. The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+ (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
+ (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
+ (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
+ (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
+ (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
+ (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
+ (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
+ (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
+ (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
+ (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
+ (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
+ (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
+ (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
+ (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
+ (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
+ (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
+ (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+ (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+ (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+ (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+ (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+ (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+ (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
+ (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
+ (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+ (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+ (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+ (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+ (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+ (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+ (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
+ (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
+ (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
+ (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
+ (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
+ (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
+ (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
+ (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
+ (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
+ (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
+ (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
+ (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
+ (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
+ (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
+ (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
+ (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
+ (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
+ (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
+ (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+ (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+ (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+ (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+ (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+ (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+ (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
+ (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
+ (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+ (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+ (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+ (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+ (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+ (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+ (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
+ (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
+};
+
+int
+pcap_strcasecmp(const char *s1, const char *s2)
+{
+ register const u_char *cm = charmap,
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ while (cm[*us1] == cm[*us2++])
+ if (*us1++ == '\0')
+ return(0);
+ return (cm[*us1] - cm[*--us2]);
+}
+
+struct dlt_choice {
+ const char *name;
+ const char *description;
+ int dlt;
+};
+
+#define DLT_CHOICE(code, description) { #code, description, DLT_ ## code }
+#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
+
+static struct dlt_choice dlt_choices[] = {
+ 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 v1"),
+ 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_KONTRON, "IPMB with Kontron pseudo-header"),
+ 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(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-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(USB_DARWIN, "USB with Darwin header"),
+ DLT_CHOICE(OPENFLOW, "OpenBSD DLT_OPENFLOW"),
+ DLT_CHOICE(SDLC, "IBM SDLC frames"),
+ DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"),
+ DLT_CHOICE(VSOCK, "Linux vsock"),
+ DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"),
+ DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
+ DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
+ DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
+ DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
+ DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
+ DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+ DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"),
+ DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+ DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
+ DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"),
+ DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"),
+ DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"),
+ DLT_CHOICE(ELEE, "ELEE lawful intercept packets"),
+ DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"),
+ DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"),
+ DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"),
+ DLT_CHOICE_SENTINEL
+};
+
+int
+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, name) == 0)
+ return (dlt_choices[i].dlt);
+ }
+ return (-1);
+}
+
+const char *
+pcap_datalink_val_to_name(int dlt)
+{
+ int i;
+
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return (dlt_choices[i].name);
+ }
+ return (NULL);
+}
+
+const char *
+pcap_datalink_val_to_description(int dlt)
+{
+ int i;
+
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return (dlt_choices[i].description);
+ }
+ return (NULL);
+}
+
+const char *
+pcap_datalink_val_to_description_or_dlt(int dlt)
+{
+ static char unkbuf[40];
+ const char *description;
+
+ description = pcap_datalink_val_to_description(dlt);
+ if (description != NULL) {
+ return description;
+ } else {
+ (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+ return unkbuf;
+ }
+}
+
+struct tstamp_type_choice {
+ const char *name;
+ const char *description;
+ int type;
+};
+
+static struct tstamp_type_choice tstamp_type_choices[] = {
+ { "host", "Host", PCAP_TSTAMP_HOST },
+ { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC },
+ { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC },
+ { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER },
+ { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED },
+ { "host_hiprec_unsynced", "Host, high precision, not synced with system time", PCAP_TSTAMP_HOST_HIPREC_UNSYNCED },
+ { NULL, NULL, 0 }
+};
+
+int
+pcap_tstamp_type_name_to_val(const char *name)
+{
+ int i;
+
+ for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+ if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0)
+ return (tstamp_type_choices[i].type);
+ }
+ return (PCAP_ERROR);
+}
+
+const char *
+pcap_tstamp_type_val_to_name(int tstamp_type)
+{
+ int i;
+
+ for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+ if (tstamp_type_choices[i].type == tstamp_type)
+ return (tstamp_type_choices[i].name);
+ }
+ return (NULL);
+}
+
+const char *
+pcap_tstamp_type_val_to_description(int tstamp_type)
+{
+ int i;
+
+ for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+ if (tstamp_type_choices[i].type == tstamp_type)
+ return (tstamp_type_choices[i].description);
+ }
+ return (NULL);
+}
+
+int
+pcap_snapshot(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->snapshot);
+}
+
+int
+pcap_is_swapped(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->swapped);
+}
+
+int
+pcap_major_version(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->version_major);
+}
+
+int
+pcap_minor_version(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->version_minor);
+}
+
+int
+pcap_bufsize(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->bufsize);
+}
+
+FILE *
+pcap_file(pcap_t *p)
+{
+ return (p->rfile);
+}
+
+#ifdef _WIN32
+int
+pcap_fileno(pcap_t *p)
+{
+ if (p->handle != INVALID_HANDLE_VALUE) {
+ /*
+ * This is a bogus and now-deprecated API; we
+ * squelch the narrowing warning for the cast
+ * from HANDLE to DWORD. If Windows programmmers
+ * need to get at the HANDLE for a pcap_t, *if*
+ * there is one, they should request such a
+ * routine (and be prepared for it to return
+ * INVALID_HANDLE_VALUE).
+ */
+DIAG_OFF_NARROWING
+ return ((int)(DWORD)p->handle);
+DIAG_ON_NARROWING
+ } else
+ return (PCAP_ERROR);
+}
+#else /* _WIN32 */
+int
+pcap_fileno(pcap_t *p)
+{
+ return (p->fd);
+}
+#endif /* _WIN32 */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+int
+pcap_get_selectable_fd(pcap_t *p)
+{
+ return (p->selectable_fd);
+}
+
+const struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+ return (p->required_select_timeout);
+}
+#endif
+
+void
+pcap_perror(pcap_t *p, const char *prefix)
+{
+ fprintf(stderr, "%s: %s\n", prefix, p->errbuf);
+}
+
+char *
+pcap_geterr(pcap_t *p)
+{
+ return (p->errbuf);
+}
+
+int
+pcap_getnonblock(pcap_t *p, char *errbuf)
+{
+ int ret;
+
+ ret = p->getnonblock_op(p);
+ if (ret == -1) {
+ /*
+ * The get nonblock operation sets p->errbuf; this
+ * function *shouldn't* have had a separate errbuf
+ * argument, as it didn't need one, but I goofed
+ * when adding it.
+ *
+ * We copy the error message to errbuf, so callers
+ * can find it in either place.
+ */
+ pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+ }
+ return (ret);
+}
+
+/*
+ * Get the current non-blocking mode setting, under the assumption that
+ * it's just the standard POSIX non-blocking flag.
+ */
+#if !defined(_WIN32) && !defined(MSDOS)
+int
+pcap_getnonblock_fd(pcap_t *p)
+{
+ int fdflags;
+
+ fdflags = fcntl(p->fd, F_GETFL, 0);
+ if (fdflags == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
+ return (-1);
+ }
+ if (fdflags & O_NONBLOCK)
+ return (1);
+ else
+ return (0);
+}
+#endif
+
+int
+pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+{
+ int ret;
+
+ ret = p->setnonblock_op(p, nonblock);
+ if (ret == -1) {
+ /*
+ * The set nonblock operation sets p->errbuf; this
+ * function *shouldn't* have had a separate errbuf
+ * argument, as it didn't need one, but I goofed
+ * when adding it.
+ *
+ * We copy the error message to errbuf, so callers
+ * can find it in either place.
+ */
+ pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+ }
+ return (ret);
+}
+
+#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
+ * per-platform non-blocking-mode routine if that routine also
+ * needs to do some additional work.)
+ */
+int
+pcap_setnonblock_fd(pcap_t *p, int nonblock)
+{
+ int fdflags;
+
+ fdflags = fcntl(p->fd, F_GETFL, 0);
+ if (fdflags == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
+ return (-1);
+ }
+ if (nonblock)
+ fdflags |= O_NONBLOCK;
+ else
+ fdflags &= ~O_NONBLOCK;
+ if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_SETFL");
+ return (-1);
+ }
+ return (0);
+}
+#endif
+
+/*
+ * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values.
+ */
+const char *
+pcap_statustostr(int errnum)
+{
+ static char ebuf[15+10+1];
+
+ switch (errnum) {
+
+ case PCAP_WARNING:
+ return("Generic warning");
+
+ case PCAP_WARNING_TSTAMP_TYPE_NOTSUP:
+ return ("That type of time stamp is not supported by that device");
+
+ case PCAP_WARNING_PROMISC_NOTSUP:
+ return ("That device doesn't support promiscuous mode");
+
+ case PCAP_ERROR:
+ return("Generic error");
+
+ case PCAP_ERROR_BREAK:
+ return("Loop terminated by pcap_breakloop");
+
+ case PCAP_ERROR_NOT_ACTIVATED:
+ return("The pcap_t has not been activated");
+
+ case PCAP_ERROR_ACTIVATED:
+ return ("The setting can't be changed after the pcap_t is activated");
+
+ case PCAP_ERROR_NO_SUCH_DEVICE:
+ return ("No such device exists");
+
+ case PCAP_ERROR_RFMON_NOTSUP:
+ return ("That device doesn't support monitor mode");
+
+ case PCAP_ERROR_NOT_RFMON:
+ return ("That operation is supported only in monitor mode");
+
+ case PCAP_ERROR_PERM_DENIED:
+ return ("You don't have permission to capture on that device");
+
+ case PCAP_ERROR_IFACE_NOT_UP:
+ return ("That device is not up");
+
+ case PCAP_ERROR_CANTSET_TSTAMP_TYPE:
+ return ("That device doesn't support setting the time stamp type");
+
+ 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);
+ return(ebuf);
+}
+
+/*
+ * Not all systems have strerror().
+ */
+const char *
+pcap_strerror(int errnum)
+{
+#ifdef HAVE_STRERROR
+#ifdef _WIN32
+ static char errbuf[PCAP_ERRBUF_SIZE];
+ errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
+
+ if (err != 0) /* err = 0 if successful */
+ pcap_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 errbuf[PCAP_ERRBUF_SIZE];
+
+ if ((unsigned int)errnum < sys_nerr)
+ return ((char *)sys_errlist[errnum]);
+ (void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
+ return (errbuf);
+#endif
+}
+
+int
+pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+ return (p->setfilter_op(p, fp));
+}
+
+/*
+ * Set direction flag, which controls whether we accept only incoming
+ * packets, only outgoing packets, or both.
+ * Note that, depending on the platform, some or all direction arguments
+ * might not be supported.
+ */
+int
+pcap_setdirection(pcap_t *p, pcap_direction_t d)
+{
+ if (p->setdirection_op == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Setting direction is not supported on this device");
+ return (-1);
+ } else {
+ switch (d) {
+
+ case PCAP_D_IN:
+ case PCAP_D_OUT:
+ case PCAP_D_INOUT:
+ /*
+ * Valid direction.
+ */
+ return (p->setdirection_op(p, d));
+
+ default:
+ /*
+ * Invalid direction.
+ */
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "Invalid direction");
+ return (-1);
+ }
+ }
+}
+
+int
+pcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ return (p->stats_op(p, ps));
+}
+
+#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)
+{
+ return (p->setbuff_op(p, dim));
+}
+
+int
+pcap_setmode(pcap_t *p, int mode)
+{
+ return (p->setmode_op(p, mode));
+}
+
+int
+pcap_setmintocopy(pcap_t *p, int size)
+{
+ return (p->setmintocopy_op(p, size));
+}
+
+HANDLE
+pcap_getevent(pcap_t *p)
+{
+ return (p->getevent_op(p));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+int
+pcap_setuserbuffer(pcap_t *p, int size)
+{
+ return (p->setuserbuffer_op(p, size));
+}
+
+int
+pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
+{
+ return (p->live_dump_op(p, filename, maxsize, maxpacks));
+}
+
+int
+pcap_live_dump_ended(pcap_t *p, int sync)
+{
+ return (p->live_dump_ended_op(p, sync));
+}
+
+PAirpcapHandle
+pcap_get_airpcap_handle(pcap_t *p)
+{
+ PAirpcapHandle handle;
+
+ handle = p->get_airpcap_handle_op(p);
+ if (handle == NULL) {
+ (void)snprintf(p->errbuf, sizeof(p->errbuf),
+ "This isn't an AirPcap device");
+ }
+ return (handle);
+}
+#endif
+
+/*
+ * On some platforms, we need to clean up promiscuous or monitor mode
+ * when we close a device - and we want that to happen even if the
+ * application just exits without explicitl closing devices.
+ * On those platforms, we need to register a "close all the pcaps"
+ * routine to be called when we exit, and need to maintain a list of
+ * pcaps that need to be closed to clean up modes.
+ *
+ * XXX - not thread-safe.
+ */
+
+/*
+ * List of pcaps on which we've done something that needs to be
+ * cleaned up.
+ * If there are any such pcaps, we arrange to call "pcap_close_all()"
+ * when we exit, and have it close all of them.
+ */
+static struct pcap *pcaps_to_close;
+
+/*
+ * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to
+ * be called on exit.
+ */
+static int did_atexit;
+
+static void
+pcap_close_all(void)
+{
+ struct pcap *handle;
+
+ while ((handle = pcaps_to_close) != NULL) {
+ pcap_close(handle);
+
+ /*
+ * If a pcap module adds a pcap_t to the "close all"
+ * list by calling pcap_add_to_pcaps_to_close(), it
+ * must have a cleanup routine that removes it from the
+ * list, by calling pcap_remove_from_pcaps_to_close(),
+ * and must make that cleanup routine the cleanup_op
+ * for the pcap_t.
+ *
+ * That means that, after pcap_close() - which calls
+ * the cleanup_op for the pcap_t - the pcap_t must
+ * have been removed from the list, so pcaps_to_close
+ * must not be equal to handle.
+ *
+ * We check for that, and abort if handle is still
+ * at the head of the list, to prevent infinite loops.
+ */
+ if (pcaps_to_close == handle)
+ abort();
+ }
+}
+
+int
+pcap_do_addexit(pcap_t *p)
+{
+ /*
+ * If we haven't already done so, arrange to have
+ * "pcap_close_all()" called when we exit.
+ */
+ if (!did_atexit) {
+ if (atexit(pcap_close_all) != 0) {
+ /*
+ * "atexit()" failed; let our caller know.
+ */
+ pcap_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
+ return (0);
+ }
+ did_atexit = 1;
+ }
+ return (1);
+}
+
+void
+pcap_add_to_pcaps_to_close(pcap_t *p)
+{
+ p->next = pcaps_to_close;
+ pcaps_to_close = p;
+}
+
+void
+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->next) {
+ if (pc == p) {
+ /*
+ * Found it. Remove it from the list.
+ */
+ if (prevpc == NULL) {
+ /*
+ * It was at the head of the list.
+ */
+ pcaps_to_close = pc->next;
+ } else {
+ /*
+ * It was in the middle of the list.
+ */
+ prevpc->next = pc->next;
+ }
+ break;
+ }
+ }
+}
+
+void
+pcap_breakloop_common(pcap_t *p)
+{
+ p->break_loop = 1;
+}
+
+
+void
+pcap_cleanup_live_common(pcap_t *p)
+{
+ if (p->buffer != NULL) {
+ free(p->buffer);
+ p->buffer = NULL;
+ }
+ if (p->dlt_list != NULL) {
+ free(p->dlt_list);
+ p->dlt_list = NULL;
+ p->dlt_count = 0;
+ }
+ if (p->tstamp_type_list != NULL) {
+ free(p->tstamp_type_list);
+ 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 (p->fd >= 0) {
+ close(p->fd);
+ p->fd = -1;
+ }
+ p->selectable_fd = -1;
+#endif
+}
+
+/*
+ * API compatible with WinPcap's "send a packet" routine - returns -1
+ * on error, 0 otherwise.
+ *
+ * XXX - what if we get a short write?
+ */
+int
+pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
+{
+ if (size <= 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be sent must be positive");
+ return (PCAP_ERROR);
+ }
+
+ if (p->inject_op(p, buf, size) == -1)
+ return (-1);
+ return (0);
+}
+
+/*
+ * API compatible with OpenBSD's "send a packet" routine - returns -1 on
+ * error, number of bytes written otherwise.
+ */
+int
+pcap_inject(pcap_t *p, const void *buf, size_t size)
+{
+ /*
+ * We return the number of bytes written, so the number of
+ * bytes to write must fit in an int.
+ */
+ if (size > INT_MAX) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "More than %d bytes cannot be injected", INT_MAX);
+ return (PCAP_ERROR);
+ }
+
+ if (size == 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be injected must not be zero");
+ return (PCAP_ERROR);
+ }
+
+ return (p->inject_op(p, buf, (int)size));
+}
+
+void
+pcap_close(pcap_t *p)
+{
+ if (p->opt.device != NULL)
+ free(p->opt.device);
+ p->cleanup_op(p);
+ free(p);
+}
+
+/*
+ * Helpers for safely loding code at run time.
+ * Currently Windows-only.
+ */
+#ifdef _WIN32
+//
+// This wrapper around loadlibrary appends the system folder (usually
+// C:\Windows\System32) to the relative path of the DLL, so that the DLL
+// is always loaded from an absolute path (it's no longer possible to
+// load modules from the application folder).
+// This solves the DLL Hijacking issue discovered in August 2010:
+//
+// https://blog.rapid7.com/2010/08/23/exploiting-dll-hijacking-flaws/
+// https://blog.rapid7.com/2010/08/23/application-dll-load-hijacking/
+// (the purported Rapid7 blog post link in the first of those two links
+// is broken; the second of those links works.)
+//
+// If any links there are broken from all the content shuffling Rapid&
+// did, see archived versions of the posts at their original homes, at
+//
+// https://web.archive.org/web/20110122175058/http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
+// https://web.archive.org/web/20100828112111/http://blog.rapid7.com/?p=5325
+//
+pcap_code_handle_t
+pcap_load_code(const char *name)
+{
+ /*
+ * XXX - should this work in UTF-16LE rather than in the local
+ * ANSI code page?
+ */
+ CHAR path[MAX_PATH];
+ CHAR fullFileName[MAX_PATH];
+ UINT res;
+ HMODULE hModule = NULL;
+
+ do
+ {
+ res = GetSystemDirectoryA(path, MAX_PATH);
+
+ if (res == 0) {
+ //
+ // some bad failure occurred;
+ //
+ break;
+ }
+
+ if (res > MAX_PATH) {
+ //
+ // the buffer was not big enough
+ //
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ break;
+ }
+
+ if (res + 1 + strlen(name) + 1 < MAX_PATH) {
+ memcpy(fullFileName, path, res * sizeof(TCHAR));
+ fullFileName[res] = '\\';
+ memcpy(&fullFileName[res + 1], name, (strlen(name) + 1) * sizeof(TCHAR));
+
+ hModule = LoadLibraryA(fullFileName);
+ } else
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+ } while(FALSE);
+
+ return hModule;
+}
+
+pcap_funcptr_t
+pcap_find_function(pcap_code_handle_t code, const char *func)
+{
+ return (GetProcAddress(code, func));
+}
+#endif
+
+/*
+ * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
+ * data for the packet, check whether the packet passes the filter.
+ * Returns the return value of the filter program, which will be zero if
+ * the packet doesn't pass and non-zero if the packet does pass.
+ */
+int
+pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
+ const u_char *pkt)
+{
+ const struct bpf_insn *fcode = fp->bf_insns;
+
+ if (fcode != NULL)
+ return (pcap_filter(fcode, pkt, h->len, h->caplen));
+ else
+ return (0);
+}
+
+static int
+pcap_can_set_rfmon_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+ u_char *user _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets can't be sent on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A filter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The packet direction cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
+
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (NULL);
+}
+
+static int
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setmode_dead(pcap_t *p, int mode _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "impossible to set mode on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t has no event handle");
+ return (INVALID_HANDLE_VALUE);
+}
+
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+ size_t *lenp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
+
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+ size_t *lenp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
+
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+ int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+ return (0);
+}
+
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The user buffer cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
+{
+ return (NULL);
+}
+#endif /* _WIN32 */
+
+static void
+pcap_cleanup_dead(pcap_t *p _U_)
+{
+ /* Nothing to do. */
+}
+
+pcap_t *
+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:
+ /*
+ * This doesn't really matter, but we don't have any way
+ * to report particular errors, so the only failure we
+ * should have is a memory allocation failure. Just
+ * pick microsecond precision.
+ */
+ precision = PCAP_TSTAMP_PRECISION_MICRO;
+ break;
+ }
+ 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->can_set_rfmon_op = pcap_can_set_rfmon_dead;
+ p->read_op = pcap_read_dead;
+ p->inject_op = pcap_inject_dead;
+ p->setfilter_op = pcap_setfilter_dead;
+ p->setdirection_op = pcap_setdirection_dead;
+ p->set_datalink_op = pcap_set_datalink_dead;
+ p->getnonblock_op = pcap_getnonblock_dead;
+ p->setnonblock_op = pcap_setnonblock_dead;
+ p->stats_op = pcap_stats_dead;
+#ifdef _WIN32
+ p->stats_ex_op = pcap_stats_ex_dead;
+ 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));
+}
+
+#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)
+{
+ pcap_debug = value;
+}
+#endif
diff --git a/pcap.h b/pcap.h
new file mode 100644
index 0000000..174e32d
--- /dev/null
+++ b/pcap.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file! Many applications
+ * expect to be able to include <pcap.h>, and at least some of them
+ * go through contortions in their configure scripts to try to detect
+ * OSes that have "helpfully" moved pcap.h to <pcap/pcap.h> without
+ * leaving behind a <pcap.h> file.
+ */
+#include <pcap/pcap.h>
diff --git a/pcap/bpf.h b/pcap/bpf.h
new file mode 100644
index 0000000..54373af
--- /dev/null
+++ b/pcap/bpf.h
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ */
+
+/*
+ * This is libpcap's cut-down version of bpf.h; it includes only
+ * the stuff needed for the code generator and the userland BPF
+ * interpreter, and the libpcap APIs for setting filters, etc..
+ *
+ * "pcap-bpf.c" will include the native OS version, as it deals with
+ * the OS's BPF implementation.
+ *
+ * At least two programs found by Google Code Search explicitly includes
+ * <pcap/bpf.h> (even though <pcap.h>/<pcap/pcap.h> includes it for you),
+ * so moving that stuff to <pcap/pcap.h> would break the build for some
+ * programs.
+ */
+
+/*
+ * If we've already included <net/bpf.h>, don't re-define this stuff.
+ * We assume BSD-style multiple-include protection in <net/bpf.h>,
+ * which is true of all but the oldest versions of FreeBSD and NetBSD,
+ * or Tru64 UNIX-style multiple-include protection (or, at least,
+ * Tru64 UNIX 5.x-style; I don't have earlier versions available to check),
+ * or AIX-style multiple-include protection (or, at least, AIX 5.x-style;
+ * I don't have earlier versions available to check), or QNX-style
+ * multiple-include protection (as per GitHub pull request #394).
+ *
+ * We trust that they will define structures and macros and types in
+ * a fashion that's source-compatible and binary-compatible with our
+ * definitions.
+ *
+ * We do not check for BPF_MAJOR_VERSION, as that's defined by
+ * <linux/filter.h>, which is directly or indirectly included in some
+ * programs that also include pcap.h, and <linux/filter.h> doesn't
+ * define stuff we need. We *do* protect against <linux/filter.h>
+ * defining various macros for BPF code itself; <linux/filter.h> says
+ *
+ * Try and keep these values and structures similar to BSD, especially
+ * the BPF code definitions which need to match so you can share filters
+ *
+ * so we trust that it will define them in a fashion that's source-compatible
+ * and binary-compatible with our definitions.
+ *
+ * This also provides our own multiple-include protection.
+ */
+#if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h)
+#define lib_pcap_bpf_h
+
+#include <pcap/funcattrs.h>
+
+#include <pcap/dlt.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))
+
+/*
+ * Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * The instruction encodings.
+ *
+ * Please inform tcpdump-workers@lists.tcpdump.org if you use any
+ * of the reserved values, so that we can note that they're used
+ * (and perhaps implement it in the reference BPF implementation
+ * and encourage its implementation elsewhere).
+ */
+
+/*
+ * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000.
+ */
+
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+/* 0x18 reserved; used by BSD/OS */
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+/* 0xc0 reserved; used by BSD/OS */
+/* 0xe0 reserved; used by BSD/OS */
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_MOD 0x90
+#define BPF_XOR 0xa0
+/* 0xb0 reserved */
+/* 0xc0 reserved */
+/* 0xd0 reserved */
+/* 0xe0 reserved */
+/* 0xf0 reserved */
+
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+/* 0x50 reserved; used on BSD/OS */
+/* 0x60 reserved */
+/* 0x70 reserved */
+/* 0x80 reserved */
+/* 0x90 reserved */
+/* 0xa0 reserved */
+/* 0xb0 reserved */
+/* 0xc0 reserved */
+/* 0xd0 reserved */
+/* 0xe0 reserved */
+/* 0xf0 reserved */
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+/* 0x18 reserved */
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+/* 0x08 reserved */
+/* 0x10 reserved */
+/* 0x18 reserved */
+/* #define BPF_COP 0x20 NetBSD "coprocessor" extensions */
+/* 0x28 reserved */
+/* 0x30 reserved */
+/* 0x38 reserved */
+/* #define BPF_COPX 0x40 NetBSD "coprocessor" extensions */
+/* also used on BSD/OS */
+/* 0x48 reserved */
+/* 0x50 reserved */
+/* 0x58 reserved */
+/* 0x60 reserved */
+/* 0x68 reserved */
+/* 0x70 reserved */
+/* 0x78 reserved */
+#define BPF_TXA 0x80
+/* 0x88 reserved */
+/* 0x90 reserved */
+/* 0x98 reserved */
+/* 0xa0 reserved */
+/* 0xa8 reserved */
+/* 0xb0 reserved */
+/* 0xb8 reserved */
+/* 0xc0 reserved; used on BSD/OS */
+/* 0xc8 reserved */
+/* 0xd0 reserved */
+/* 0xd8 reserved */
+/* 0xe0 reserved */
+/* 0xe8 reserved */
+/* 0xf0 reserved */
+/* 0xf8 reserved */
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ bpf_u_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ *
+ * In case somebody's included <linux/filter.h>, or something else that
+ * gives the kernel's definitions of BPF statements, get rid of its
+ * definitions, so we can supply ours instead. If some kernel's
+ * definitions aren't *binary-compatible* with what BPF has had
+ * since it first sprung from the brows of Van Jacobson and Steve
+ * McCanne, that kernel should be fixed.
+ */
+#ifdef BPF_STMT
+#undef BPF_STMT
+#endif
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#ifdef BPF_JUMP
+#undef BPF_JUMP
+#endif
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+PCAP_AVAILABLE_0_4
+PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API int bpf_validate(const struct bpf_insn *f, int len);
+
+PCAP_AVAILABLE_0_4
+PCAP_API char *bpf_image(const struct bpf_insn *, int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API void bpf_dump(const struct bpf_program *, int);
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */
diff --git a/pcap/can_socketcan.h b/pcap/can_socketcan.h
new file mode 100644
index 0000000..332d9ff
--- /dev/null
+++ b/pcap/can_socketcan.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lib_pcap_can_socketcan_h
+#define lib_pcap_can_socketcan_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * SocketCAN header, as per Documentation/networking/can.txt in the
+ * Linux source.
+ */
+typedef struct {
+ uint32_t can_id;
+ uint8_t payload_length;
+ uint8_t pad;
+ uint8_t reserved1;
+ uint8_t reserved2;
+} pcap_can_socketcan_hdr;
+
+#endif
diff --git a/pcap/compiler-tests.h b/pcap/compiler-tests.h
new file mode 100644
index 0000000..a69c2b0
--- /dev/null
+++ b/pcap/compiler-tests.h
@@ -0,0 +1,163 @@
+/* -*- 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_compiler_tests_h
+#define lib_pcap_compiler_tests_h
+
+/*
+ * This was introduced by Clang:
+ *
+ * https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+ *
+ * in some version (which version?); it has been picked up by GCC 5.0.
+ */
+#ifndef __has_attribute
+ /*
+ * It's a macro, so you can check whether it's defined to check
+ * whether it's supported.
+ *
+ * If it's not, define it to always return 0, so that we move on to
+ * the fallback checks.
+ */
+ #define __has_attribute(x) 0
+#endif
+
+/*
+ * Note that the C90 spec's "6.8.1 Conditional inclusion" and the
+ * C99 spec's and C11 spec's "6.10.1 Conditional inclusion" say:
+ *
+ * Prior to evaluation, macro invocations in the list of preprocessing
+ * tokens that will become the controlling constant expression are
+ * replaced (except for those macro names modified by the defined unary
+ * operator), just as in normal text. If the token "defined" is
+ * generated as a result of this replacement process or use of the
+ * "defined" unary operator does not match one of the two specified
+ * forms prior to macro replacement, the behavior is undefined.
+ *
+ * so you shouldn't use defined() in a #define that's used in #if or
+ * #elif. Some versions of Clang, for example, will warn about this.
+ *
+ * Instead, we check whether the pre-defined macros for particular
+ * compilers are defined and, if not, define the "is this version XXX
+ * or a later version of this compiler" macros as 0.
+ */
+
+/*
+ * 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.
+ */
+
+#if ! defined(__GNUC__)
+#define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) 0
+#else
+#define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) \
+ (__GNUC__ > (major) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#endif
+
+/*
+ * Check whether this is Clang major.minor or a later release.
+ */
+
+#if !defined(__clang__)
+#define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) 0
+#else
+#define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) \
+ (__clang_major__ > (major) || \
+ (__clang_major__ == (major) && __clang_minor__ >= (minor)))
+#endif
+
+/*
+ * Check whether this is Sun C/SunPro C/Oracle Studio major.minor
+ * or a later release.
+ *
+ * The version number in __SUNPRO_C is encoded in hex BCD, with the
+ * uppermost hex digit being the major version number, the next
+ * one or two hex digits being the minor version number, and
+ * the last digit being the patch version.
+ *
+ * It represents the *compiler* version, not the product version;
+ * see
+ *
+ * https://sourceforge.net/p/predef/wiki/Compilers/
+ *
+ * for a partial mapping, which we assume continues for later
+ * 12.x product releases.
+ */
+
+#if ! defined(__SUNPRO_C)
+#define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) 0
+#else
+#define PCAP_SUNPRO_VERSION_TO_BCD(major, minor) \
+ (((minor) >= 10) ? \
+ (((major) << 12) | (((minor)/10) << 8) | (((minor)%10) << 4)) : \
+ (((major) << 8) | ((minor) << 4)))
+#define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) \
+ (__SUNPRO_C >= PCAP_SUNPRO_VERSION_TO_BCD((major), (minor)))
+#endif
+
+/*
+ * Check whether this is IBM XL C major.minor or a later release.
+ *
+ * The version number in __xlC__ has the major version in the
+ * upper 8 bits and the minor version in the lower 8 bits.
+ */
+
+#if ! defined(__xlC__)
+#define PCAP_IS_AT_LEAST_XL_C_VERSION(major,minor) 0
+#else
+#define PCAP_IS_AT_LEAST_XL_C_VERSION(major, minor) \
+ (__xlC__ >= (((major) << 8) | (minor)))
+#endif
+
+/*
+ * Check whether this is HP aC++/HP C major.minor or a later release.
+ *
+ * The version number in __HP_aCC is encoded in zero-padded decimal BCD,
+ * with the "A." stripped off, the uppermost two decimal digits being
+ * the major version number, the next two decimal digits being the minor
+ * version number, and the last two decimal digits being the patch version.
+ * (Strip off the A., remove the . between the major and minor version
+ * number, and add two digits of patch.)
+ */
+
+#if ! defined(__HP_aCC)
+#define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) 0
+#else
+#define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) \
+ (__HP_aCC >= ((major)*10000 + (minor)*100))
+#endif
+
+#endif /* lib_pcap_compiler_tests_h */
diff --git a/pcap/dlt.h b/pcap/dlt.h
new file mode 100644
index 0000000..eaba34f
--- /dev/null
+++ b/pcap/dlt.h
@@ -0,0 +1,1514 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ */
+
+#ifndef lib_pcap_dlt_h
+#define lib_pcap_dlt_h
+
+/*
+ * Link-layer header type codes.
+ *
+ * Do *NOT* add new values to this list without asking
+ * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run
+ * the risk of using a value that's already being used for some other
+ * purpose, and of having tools that read libpcap-format captures not
+ * being able to handle captures with your new DLT_ value, with no hope
+ * that they will ever be changed to do so (as that would destroy their
+ * ability to read captures using that value for that other purpose).
+ *
+ * See
+ *
+ * https://www.tcpdump.org/linktypes.html
+ *
+ * for detailed descriptions of some of these link-layer header types.
+ */
+
+/*
+ * These are the types that are the same on all platforms, and that
+ * have been defined by <net/bpf.h> 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 <net/bpf.h> for ages. We use #ifdefs to
+ * detect the BSDs that define them differently from the traditional
+ * libpcap <net/bpf.h>
+ *
+ * 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
+ * macOS; don't use it for anything else. (FreeBSD uses 121, which
+ * collides with DLT_HHDLC, even though it doesn't use 18 for
+ * anything and doesn't appear to have ever used it for anything.)
+ *
+ * We define it as 18 on those platforms; it is, unfortunately, used
+ * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC
+ * in general. As the packet format for it, like that for
+ * DLT_PFLOG, is not only OS-dependent but OS-version-dependent,
+ * we don't support printing it in tcpdump except on OSes that
+ * have the relevant header files, so it's not that useful on
+ * other platforms.
+ */
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+#define DLT_PFSYNC 18
+#endif
+
+#define DLT_ATM_CLIP 19 /* Linux Classical IP over ATM */
+
+/*
+ * Apparently Redback uses this for its SmartEdge 400/800. I hope
+ * nobody else decided to use it, too.
+ */
+#define DLT_REDBACK_SMARTEDGE 32
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER 51 /* PPP over Ethernet */
+
+/*
+ * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ * a link-layer type of 99 for the tcpdump it supplies. The link-layer
+ * header has 6 bytes of unknown data, something that appears to be an
+ * Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ * I've seen.
+ */
+#define DLT_SYMANTEC_FIREWALL 99
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer header type LINKTYPE_ values corresponding to DLT_ types
+ * that differ between platforms; don't use those values for new DLT_
+ * new types.
+ */
+
+/*
+ * Values starting with 104 are used for newly-assigned link-layer
+ * header type values; for those link-layer header types, the DLT_
+ * value returned by pcap_datalink() and passed to pcap_open_dead(),
+ * and the LINKTYPE_ value that appears in capture files, are the
+ * same.
+ *
+ * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is
+ * the highest such value.
+ */
+#define DLT_MATCHING_MIN 104
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC 104 /* Cisco HDLC */
+#define DLT_CHDLC DLT_C_HDLC
+
+#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+
+/*
+ * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ * except when it isn't. (I.e., sometimes it's just raw IP, and
+ * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL,
+ * so that we don't have to worry about the link-layer header.)
+ */
+
+/*
+ * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ * with other values.
+ * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ * (DLCI, etc.).
+ */
+#define DLT_FRELAY 107
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so
+ * we don't use 12 for it in OSes other than OpenBSD.
+ */
+#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.
+ */
+
+/*
+ * Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL 113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK 114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET 115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER 116
+
+/*
+ * OpenBSD DLT_PFLOG.
+ */
+#define DLT_PFLOG 117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS 118
+
+/*
+ * For 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER 119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER 120
+
+/*
+ * Sigh.
+ *
+ * 121 was reserved for Siemens HiPath HDLC on 2002-01-25, as
+ * requested by Tomas Kukosa.
+ *
+ * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that
+ * assigned 121 as DLT_PFSYNC. In current versions, its libpcap
+ * does DLT_ <-> LINKTYPE_ mapping, mapping DLT_PFSYNC to a
+ * LINKTYPE_PFSYNC value of 246, so it should write out DLT_PFSYNC
+ * dump files with 246 as the link-layer header type. (Earlier
+ * versions might not have done mapping, in which case they would
+ * have written them out with a link-layer header type of 121.)
+ *
+ * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC;
+ * its libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would
+ * write out DLT_PFSYNC dump files with use 18 as the link-layer
+ * header type.
+ *
+ * NetBSD, DragonFly BSD, and Darwin also use 18 for DLT_PFSYNC; in
+ * current versions, their libpcaps do DLT_ <-> LINKTYPE_ mapping,
+ * mapping DLT_PFSYNC to a LINKTYPE_PFSYNC value of 246, so they
+ * should write out DLT_PFSYNC dump files with 246 as the link-layer
+ * header type. (Earlier versions might not have done mapping,
+ * in which case they'd work the same way OpenBSD does, writing
+ * them out with a link-layer header type of 18.)
+ *
+ * We'll define DLT_PFSYNC as:
+ *
+ * 18 on NetBSD, OpenBSD, DragonFly BSD, and Darwin;
+ *
+ * 121 on FreeBSD;
+ *
+ * 246 everywhere else.
+ *
+ * We'll define DLT_HHDLC as 121 on everything except for FreeBSD;
+ * anybody who wants to compile, on FreeBSD, code that uses DLT_HHDLC
+ * is out of luck.
+ *
+ * We'll define LINKTYPE_PFSYNC as 246 on *all* platforms, so that
+ * savefiles written using *this* code won't use 18 or 121 for PFSYNC,
+ * they'll all use 246.
+ *
+ * Code that uses pcap_datalink() to determine the link-layer header
+ * type of a savefile won't, when built and run on FreeBSD, be able
+ * to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC capture
+ * files, as pcap_datalink() will give 121 for both of them. Code
+ * that doesn't, such as the code in Wireshark, will be able to
+ * distinguish between them.
+ *
+ * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e.,
+ * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD,
+ * DragonFly BSD, and macOS - to DLT_PFSYNC, so code built with FreeBSD's
+ * libpcap won't treat those files as DLT_PFSYNC files.
+ *
+ * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC;
+ * this means they can read DLT_HHDLC files, if any exist, but won't
+ * treat pcap files written by any older versions of FreeBSD libpcap that
+ * didn't map to 246 as DLT_PFSYNC files.
+ */
+#ifdef __FreeBSD__
+#define DLT_PFSYNC 121
+#else
+#define DLT_HHDLC 121
+#endif
+
+/*
+ * This is for RFC 2625 IP-over-Fibre Channel.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC 122
+
+/*
+ * This is for Full Frontal ATM on Solaris with SunATM, with a
+ * pseudo-header followed by an AALn PDU.
+ *
+ * There may be other forms of Full Frontal ATM on other OSes,
+ * with different pseudo-headers.
+ *
+ * If ATM software returns a pseudo-header with VPI/VCI information
+ * (and, ideally, packet type information, e.g. signalling, ILMI,
+ * LANE, LLC-multiplexed traffic, etc.), it should not use
+ * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ * and the like don't have to infer the presence or absence of a
+ * pseudo-header and the form of the pseudo-header.
+ */
+#define DLT_SUNATM 123 /* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * 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 <chris.waters@networkchemistry.com>
+ * 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 <hannes@juniper.net>. 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
+ * <dieter@apple.com>. 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
+ * <jeff.morriss[AT]ulticom.com> and subsequent discussions.
+ */
+#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */
+#define DLT_MTP2 140 /* MTP2, without pseudo-header */
+#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */
+#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */
+
+/*
+ * DOCSIS MAC frames.
+ */
+#define DLT_DOCSIS 143
+
+/*
+ * Linux-IrDA packets. Protocol defined at https://www.irda.org.
+ * Those packets include IrLAP headers and above (IrLMP...), but
+ * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ * framing can be handled by the hardware and depend on the bitrate.
+ * This is exactly the format you would get capturing on a Linux-IrDA
+ * interface (irdaX), but not on a raw serial port.
+ * Note the capture is done in "Linux-cooked" mode, so each packet include
+ * a fake packet header (struct sll_header). This is because IrDA packet
+ * decoding is dependent on the direction of the packet (incoming or
+ * outgoing).
+ * When/if other platform implement IrDA capture, we may revisit the
+ * issue and define a real DLT_IRDA...
+ * Jean II
+ */
+#define DLT_LINUX_IRDA 144
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define DLT_IBM_SP 145
+#define DLT_IBM_SN 146
+
+/*
+ * Reserved for private use. If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value,
+ * as per the comment above, and use the type you're given.
+ */
+#define DLT_USER0 147
+#define DLT_USER1 148
+#define DLT_USER2 149
+#define DLT_USER3 150
+#define DLT_USER4 151
+#define DLT_USER5 152
+#define DLT_USER6 153
+#define DLT_USER7 154
+#define DLT_USER8 155
+#define DLT_USER9 156
+#define DLT_USER10 157
+#define DLT_USER11 158
+#define DLT_USER12 159
+#define DLT_USER13 160
+#define DLT_USER14 161
+#define DLT_USER15 162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ * http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ *
+ * but it might be used by some non-AVS drivers now or in the
+ * future.
+ */
+#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. 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 <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accommodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define DLT_PPP_PPPD 166
+
+/*
+ * Names for backwards compatibility with older versions of some PPP
+ * software; new software should use DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD
+#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. 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 <oz@gcom.com> 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 <hannes@juniper.net>. The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define DLT_JUNIPER_PIC_PEER 174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems. They add an ERF header (see
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define DLT_ERF_ETH 175 /* Ethernet */
+#define DLT_ERF_POS 176 /* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> 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 <hannes@juniper.net>.
+ * The DLT_ are used for prepending meta-information
+ * like interface index, interface name
+ * before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ */
+#define DLT_JUNIPER_ETHER 178
+#define DLT_JUNIPER_PPP 179
+#define DLT_JUNIPER_FRELAY 180
+#define DLT_JUNIPER_CHDLC 181
+
+/*
+ * Multi Link Frame Relay (FRF.16)
+ */
+#define DLT_MFR 182
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * 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 <gianluca.varenni@cacetech.com>.
+ * 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 <gianluca.varenni@cacetech.com>.
+ * Please refer to the A653-1 standard for more information.
+ */
+#define DLT_A653_ICM 185
+
+/*
+ * This used to be "USB packets, beginning with a USB setup header;
+ * requested by Paolo Abeni <paolo.abeni@email.it>."
+ *
+ * However, that header didn't work all that well - it left out some
+ * useful information - and was abandoned in favor of the DLT_USB_LINUX
+ * header.
+ *
+ * This is now used by FreeBSD for its BPF taps for USB; that has its
+ * own headers. So it is written, so it is done.
+ *
+ * For source-code compatibility, we also define DLT_USB to have this
+ * value. We do it numerically so that, if code that includes this
+ * file (directly or indirectly) also includes an OS header that also
+ * defines DLT_USB as 186, we don't get a redefinition warning.
+ * (NetBSD 7 does that.)
+ */
+#define DLT_USB_FREEBSD 186
+#define DLT_USB 186
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4); requested by
+ * Paolo Abeni.
+ */
+#define DLT_BLUETOOTH_HCI_H4 187
+
+/*
+ * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ * <cruz_petagay@bah.com>.
+ */
+#define DLT_IEEE802_16_MAC_CPS 188
+
+/*
+ * USB packets, beginning with a Linux USB header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define DLT_USB_LINUX 189
+
+/*
+ * Controller Area Network (CAN) v. 2.0B packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * 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 <gianluca.varenni@cacetech.com>.
+ */
+#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 <hannes@juniper.net>.
+ * 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 <mikko.saarnivala@sensinode.com>.
+ * For this one, we expect the FCS to be present at the end of the frame;
+ * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used.
+ *
+ * We keep the name DLT_IEEE802_15_4 as an alias for backwards
+ * compatibility, but, again, this should *only* be used for 802.15.4
+ * frames that include the FCS.
+ */
+#define DLT_IEEE802_15_4_WITHFCS 195
+#define DLT_IEEE802_15_4 DLT_IEEE802_15_4_WITHFCS
+
+/*
+ * Various link-layer types, with a pseudo-header, for SITA
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ */
+#define DLT_SITA 196
+
+/*
+ * Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ * encapsulates Endace ERF records. Requested by Stephen Donnelly
+ * <stephen@endace.com>.
+ */
+#define DLT_ERF 197
+
+/*
+ * Special header prepended to Ethernet packets when capturing from a
+ * u10 Networks board. Requested by Phil Mulholland
+ * <phil@u10networks.com>.
+ */
+#define DLT_RAIF1 198
+
+/*
+ * IPMB packet for IPMI, beginning with a 2-byte header, followed by
+ * the I2C slave address, followed by the netFn and LUN, etc..
+ * Requested by Chanthy Toeung <chanthy.toeung@ca.kontron.com>.
+ *
+ * XXX - this used to be called DLT_IPMB, back when we got the
+ * impression from the email thread requesting it that the packet
+ * had no extra 2-byte header. We've renamed it; if anybody used
+ * DLT_IPMB and assumed no 2-byte header, this will cause the compile
+ * to fail, at which point we'll have to figure out what to do about
+ * the two header types using the same DLT_/LINKTYPE_ value. If that
+ * doesn't happen, we'll assume nobody used it and that the redefinition
+ * is safe.
+ */
+#define DLT_IPMB_KONTRON 199
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * 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 <richard@rns-stearn.demon.co.uk>.
+ */
+#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 <varunax@gmail.com>.
+ */
+#define DLT_LAPD 203
+
+/*
+ * PPP, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host", non-zero (any non-zero value) means "sent by
+ * this host" - as per Will Barker <w.barker@zen.co.uk>.
+ *
+ * Don't confuse this with DLT_PPP_WITH_DIRECTION, which is an old
+ * name for what is now called DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIR 204
+
+/*
+ * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host", non-zero (any non-zero value) means
+ * "sent by this host" - as per Will Barker <w.barker@zen.co.uk>.
+ */
+#define DLT_C_HDLC_WITH_DIR 205
+
+/*
+ * Frame Relay, with a one-byte direction pseudo-header prepended - zero
+ * means "received by this host" (DCE -> DTE), non-zero (any non-zero
+ * value) means "sent by this host" (DTE -> DCE) - as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define DLT_FRELAY_WITH_DIR 206
+
+/*
+ * LAPB, with a one-byte direction pseudo-header prepended - zero means
+ * "received by this host" (DCE -> DTE), non-zero (any non-zero value)
+ * means "sent by this host" (DTE -> DCE)- as per Will Barker
+ * <w.barker@zen.co.uk>.
+ */
+#define DLT_LAPB_WITH_DIR 207
+
+/*
+ * 208 is reserved for an as-yet-unspecified proprietary link-layer
+ * type, as requested by Will Barker.
+ */
+
+/*
+ * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ * <avn@pigeonpoint.com>.
+ */
+#define DLT_IPMB_LINUX 209
+
+/*
+ * FlexRay automotive bus - http://www.flexray.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_FLEXRAY 210
+
+/*
+ * Media Oriented Systems Transport (MOST) bus for multimedia
+ * transport - https://www.mostcooperation.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_MOST 211
+
+/*
+ * Local Interconnect Network (LIN) bus for vehicle networks -
+ * http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ * <hannes.kaelber@x2e.de>.
+ */
+#define DLT_LIN 212
+
+/*
+ * X2E-private data link type used for serial line capture,
+ * as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_X2E_SERIAL 213
+
+/*
+ * X2E-private data link type used for the Xoraya data logger
+ * family, as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#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 <jcmvbkbc@gmail.com>.
+ */
+#define DLT_IEEE802_15_4_NONASK_PHY 215
+
+/*
+ * David Gibson <david@gibson.dropbear.id.au> 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 <laforge@gnumonks.org>.
+ */
+#define DLT_GSMTAP_UM 217
+#define DLT_GSMTAP_ABIS 218
+
+/*
+ * MPLS, with an MPLS label as the link-layer header.
+ * Requested by Michele Marchetto <michele@openbsd.org> 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 <tcpdump@mazzoo.de>.
+ */
+#define DLT_DECT 221
+
+/*
+ * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" <eric.lidwa-1@nasa.gov>
+ * 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 <vieuxtech@gmail.com>.
+ */
+#define DLT_WIHART 223
+
+/*
+ * Fibre Channel FC-2 frames, beginning with a Frame_Header.
+ * Requested by Kahou Lei <kahou82@gmail.com>.
+ */
+#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 <kahou82@gmail.com>.
+ */
+#define DLT_FC_2_WITH_FRAME_DELIMS 225
+
+/*
+ * Solaris ipnet pseudo-header; requested by Darren Reed <Darren.Reed@Sun.COM>.
+ *
+ * The pseudo-header starts with a one-byte version number; for version 2,
+ * the pseudo-header is:
+ *
+ * struct dl_ipnetinfo {
+ * uint8_t dli_version;
+ * uint8_t dli_family;
+ * uint16_t dli_htype;
+ * uint32_t dli_pktlen;
+ * uint32_t dli_ifindex;
+ * uint32_t dli_grifindex;
+ * uint32_t dli_zsrc;
+ * uint32_t dli_zdst;
+ * };
+ *
+ * dli_version is 2 for the current version of the pseudo-header.
+ *
+ * dli_family is a Solaris address family value, so it's 2 for IPv4
+ * and 26 for IPv6.
+ *
+ * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing
+ * packets, and 2 for packets arriving from another zone on the same
+ * machine.
+ *
+ * dli_pktlen is the length of the packet data following the pseudo-header
+ * (so the captured length minus dli_pktlen is the length of the
+ * pseudo-header, assuming the entire pseudo-header was captured).
+ *
+ * dli_ifindex is the interface index of the interface on which the
+ * packet arrived.
+ *
+ * dli_grifindex is the group interface index number (for IPMP interfaces).
+ *
+ * dli_zsrc is the zone identifier for the source of the packet.
+ *
+ * dli_zdst is the zone identifier for the destination of the packet.
+ *
+ * A zone number of 0 is the global zone; a zone number of 0xffffffff
+ * means that the packet arrived from another host on the network, not
+ * from another zone on the same machine.
+ *
+ * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates
+ * which of those it is.
+ */
+#define DLT_IPNET 226
+
+/*
+ * CAN (Controller Area Network) frames, with a pseudo-header as supplied
+ * by Linux SocketCAN, and with multi-byte numerical fields in that header
+ * in big-endian byte order.
+ *
+ * See Documentation/networking/can.txt in the Linux source.
+ *
+ * Requested by Felix Obenhuber <felix@obenhuber.de>.
+ */
+#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 <Darren.Reed@Sun.COM>.
+ */
+#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 <jonsmirl@gmail.com>.
+ */
+#define DLT_IEEE802_15_4_NOFCS 230
+
+/*
+ * Raw D-Bus:
+ *
+ * https://www.freedesktop.org/wiki/Software/dbus
+ *
+ * messages:
+ *
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ *
+ * starting with the endianness flag, followed by the message type, etc.,
+ * but without the authentication handshake before the message sequence:
+ *
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *
+ * Requested by Martin Vidner <martin@vidner.net>.
+ */
+#define DLT_DBUS 231
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define DLT_JUNIPER_VS 232
+#define DLT_JUNIPER_SRX_E2E 233
+#define DLT_JUNIPER_FIBRECHANNEL 234
+
+/*
+ * DVB-CI (DVB Common Interface for communication between a PC Card
+ * module and a DVB receiver). See
+ *
+ * https://www.kaiser.cx/pcap-dvbci.html
+ *
+ * for the specification.
+ *
+ * Requested by Martin Kaiser <martin@kaiser.cx>.
+ */
+#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
+ * <hans-christoph.schemmel@cinterion.com>.
+ */
+#define DLT_MUX27010 236
+
+/*
+ * STANAG 5066 D_PDUs. Requested by M. Baris Demiray
+ * <barisdemiray@gmail.com>.
+ */
+#define DLT_STANAG_5066_D_PDU 237
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ */
+#define DLT_JUNIPER_ATM_CEMIC 238
+
+/*
+ * NetFilter LOG messages
+ * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets)
+ *
+ * Requested by Jakub Zawadzki <darkjames-ws@darkjames.pl>
+ */
+#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 <HPfrommer@hilscher.com>
+ */
+#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 <HPfrommer@hilscher.com>
+ */
+#define DLT_NETANALYZER_TRANSPARENT 241
+
+/*
+ * IP-over-InfiniBand, as specified by RFC 4391.
+ *
+ * Requested by Petr Sumbera <petr.sumbera@oracle.com>.
+ */
+#define DLT_IPOIB 242
+
+/*
+ * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0).
+ *
+ * Requested by Guy Martin <gmsoft@tuxicoman.be>.
+ */
+#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 <jens.grimmer@ng4t.com>.
+ */
+#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 <mikey@google.com>.
+ */
+#define DLT_NFC_LLCP 245
+
+/*
+ * 246 is used as LINKTYPE_PFSYNC; do not use it for any other purpose.
+ *
+ * DLT_PFSYNC has different values on different platforms, and all of
+ * them collide with something used elsewhere. On platforms that
+ * don't already define it, define it as 246.
+ */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__)
+#define DLT_PFSYNC 246
+#endif
+
+/*
+ * Raw InfiniBand packets, starting with the Local Routing Header.
+ *
+ * Requested by Oren Kladnitsky <orenk@mellanox.com>.
+ */
+#define DLT_INFINIBAND 247
+
+/*
+ * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6).
+ *
+ * Requested by Michael Tuexen <Michael.Tuexen@lurchi.franken.de>.
+ */
+#define DLT_SCTP 248
+
+/*
+ * USB packets, beginning with a USBPcap header.
+ *
+ * Requested by Tomasz Mon <desowin@gmail.com>
+ */
+#define DLT_USBPCAP 249
+
+/*
+ * Schweitzer Engineering Laboratories "RTAC" product serial-line
+ * packets.
+ *
+ * Requested by Chris Bontje <chris_bontje@selinc.com>.
+ */
+#define DLT_RTAC_SERIAL 250
+
+/*
+ * Bluetooth Low Energy air interface link-layer packets.
+ *
+ * Requested by Mike Kershaw <dragorn@kismetwireless.net>.
+ */
+#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 macOS*; that is *intentional*, so that
+ * PKTAP files look the same on *all* OSes (different OSes can have
+ * different numerical values for a given DLT_, but *MUST NOT* have
+ * different values for what goes in a file, as files can be moved
+ * between OSes!).
+ *
+ * When capturing, on a system with a Darwin-based OS, on a device
+ * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this
+ * version of libpcap, the DLT_ value for the pcap_t will be DLT_PKTAP,
+ * and that will continue to be DLT_USER2 on Darwin-based OSes. That way,
+ * binary compatibility with Mavericks is preserved for programs using
+ * this version of libpcap. This does mean that if you were using
+ * DLT_USER2 for some capture device on macOS, you can't do so with
+ * this version of libpcap, just as you can't with Apple's libpcap -
+ * on macOS, they define DLT_PKTAP to be DLT_USER2, so programs won't
+ * be able to distinguish between PKTAP and whatever you were using
+ * DLT_USER2 for.
+ *
+ * If the program saves the capture to a file using this version of
+ * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be
+ * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes.
+ * That way, the file will *not* be a DLT_USER2 file. That means
+ * that the latest version of tcpdump, when built with this version
+ * of libpcap, and sufficiently recent versions of Wireshark will
+ * be able to read those files and interpret them correctly; however,
+ * Apple's version of tcpdump in OS X 10.9 won't be able to handle
+ * them. (Hopefully, Apple will pick up this version of libpcap,
+ * and the corresponding version of tcpdump, so that tcpdump will
+ * be able to handle the old LINKTYPE_USER2 captures *and* the new
+ * LINKTYPE_PKTAP captures.)
+ */
+#ifdef __APPLE__
+#define DLT_PKTAP DLT_USER2
+#else
+#define DLT_PKTAP 258
+#endif
+
+/*
+ * Ethernet packets preceded by a header giving the last 6 octets
+ * of the preamble specified by 802.3-2012 Clause 65, section
+ * 65.1.3.2 "Transmit".
+ */
+#define DLT_EPON 259
+
+/*
+ * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format"
+ * in the PICMG HPM.2 specification.
+ */
+#define DLT_IPMI_HPM_2 260
+
+/*
+ * per Joshua Wright <jwright@hasborg.com>, formats for Zwave captures.
+ */
+#define DLT_ZWAVE_R1_R2 261
+#define DLT_ZWAVE_R3 262
+
+/*
+ * per Steve Karg <skarg@users.sourceforge.net>, 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 <jonathan.brucke@gmail.com>.
+ */
+#define DLT_RDS 265
+
+/*
+ * USB packets, beginning with a Darwin (macOS, etc.) header.
+ */
+#define DLT_USB_DARWIN 266
+
+/*
+ * OpenBSD DLT_OPENFLOW.
+ */
+#define DLT_OPENFLOW 267
+
+/*
+ * SDLC frames containing SNA PDUs.
+ */
+#define DLT_SDLC 268
+
+/*
+ * per "Selvig, Bjorn" <b.selvig@ti.com> used for
+ * TI protocol sniffer.
+ */
+#define DLT_TI_LLN_SNIFFER 269
+
+/*
+ * per: Erik de Jong <erikdejong at gmail.com> for
+ * https://github.com/eriknl/LoRaTap/releases/tag/v0.1
+ */
+#define DLT_LORATAP 270
+
+/*
+ * per: Stefanha at gmail.com for
+ * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
+ * for: https://qemu-project.org/Features/VirtioVsock
+ */
+#define DLT_VSOCK 271
+
+/*
+ * Nordic Semiconductor Bluetooth LE sniffer.
+ */
+#define DLT_NORDIC_BLE 272
+
+/*
+ * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
+ * per: bruno.verstuyft at excentis.com
+ * https://www.xra31.com/xra-header
+ */
+#define DLT_DOCSIS31_XRA31 273
+
+/*
+ * mPackets, as specified by IEEE 802.3br Figure 99-4, starting
+ * with the preamble and always ending with a CRC field.
+ */
+#define DLT_ETHERNET_MPACKET 274
+
+/*
+ * DisplayPort AUX channel monitoring data as specified by VESA
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
+ * per dirk.eibach at gdsys.cc
+ */
+#define DLT_DISPLAYPORT_AUX 275
+
+/*
+ * Linux cooked sockets v2.
+ */
+#define DLT_LINUX_SLL2 276
+
+/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define DLT_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define DLT_OPENVIZSLA 278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ * https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define DLT_EBHSCR 279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define DLT_VPP_DISPATCH 280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define DLT_DSA_TAG_BRCM 281
+#define DLT_DSA_TAG_BRCM_PREPEND 282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV; requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define DLT_IEEE802_15_4_TAP 283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define DLT_DSA_TAG_DSA 284
+#define DLT_DSA_TAG_EDSA 285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define DLT_ELEE 286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define DLT_Z_WAVE_SERIAL 287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define DLT_USB_2_0 288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define DLT_ATSC_ALP 289
+
+/*
+ * In case the code that includes this file (directly or indirectly)
+ * has also included OS files that happen to define DLT_MATCHING_MAX,
+ * with a different value (perhaps because that OS hasn't picked up
+ * the latest version of our DLT definitions), we undefine the
+ * previous value of DLT_MATCHING_MAX.
+ */
+#ifdef DLT_MATCHING_MAX
+#undef DLT_MATCHING_MAX
+#endif
+#define DLT_MATCHING_MAX 289 /* highest value in the "matching" range */
+
+/*
+ * DLT and savefile link type values are split into a class and
+ * a member of that class. A class value of 0 indicates a regular
+ * DLT_/LINKTYPE_ value.
+ */
+#define DLT_CLASS(x) ((x) & 0x03ff0000)
+
+/*
+ * NetBSD-specific generic "raw" link type. The class value indicates
+ * that this is the generic raw type, and the lower 16 bits are the
+ * address family we're dealing with. Those values are NetBSD-specific;
+ * do not assume that they correspond to AF_ values for your operating
+ * system.
+ */
+#define DLT_CLASS_NETBSD_RAWAF 0x02240000
+#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af))
+#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff)
+#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF)
+
+#endif /* !defined(lib_pcap_dlt_h) */
diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h
new file mode 100644
index 0000000..a2ca542
--- /dev/null
+++ b/pcap/funcattrs.h
@@ -0,0 +1,325 @@
+/* -*- 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_funcattrs_h
+#define lib_pcap_funcattrs_h
+
+#include <pcap/compiler-tests.h>
+
+/*
+ * Attributes to apply to functions and their arguments, using various
+ * compiler-specific extensions.
+ */
+
+/*
+ * 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.
+ */
+
+#if defined(_WIN32)
+ /*
+ * For Windows:
+ *
+ * when building libpcap:
+ *
+ * if we're building it as a DLL, we have to declare API
+ * functions with __declspec(dllexport);
+ *
+ * if we're building it as a static library, we don't want
+ * to do so.
+ *
+ * when using libpcap:
+ *
+ * if we're using the DLL, calls to its functions are a
+ * little more efficient if they're declared with
+ * __declspec(dllimport);
+ *
+ * if we're not using the dll, we don't want to declare
+ * them that way.
+ *
+ * So:
+ *
+ * if pcap_EXPORTS is defined, we define PCAP_API_DEF as
+ * __declspec(dllexport);
+ *
+ * if PCAP_DLL is defined, we define PCAP_API_DEF as
+ * __declspec(dllimport);
+ *
+ * otherwise, we define PCAP_API_DEF as nothing.
+ */
+ #if defined(pcap_EXPORTS)
+ /*
+ * We're compiling libpcap as a DLL, so we should export functions
+ * in our API.
+ */
+ #define PCAP_API_DEF __declspec(dllexport)
+ #elif defined(PCAP_DLL)
+ /*
+ * We're using libpcap as a DLL, so the calls will be a little more
+ * efficient if we explicitly import the functions.
+ */
+ #define PCAP_API_DEF __declspec(dllimport)
+ #else
+ /*
+ * Either we're building libpcap as a static library, or we're using
+ * it as a static library, or we don't know for certain that we're
+ * using it as a dynamic library, so neither import nor export the
+ * functions explicitly.
+ */
+ #define PCAP_API_DEF
+ #endif
+#elif defined(MSDOS)
+ /* XXX - does this need special treatment? */
+ #define PCAP_API_DEF
+#else /* UN*X */
+ #ifdef pcap_EXPORTS
+ /*
+ * We're compiling libpcap as a (dynamic) shared library, 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 PCAP_IS_AT_LEAST_GNUC_VERSION(3,4) \
+ || PCAP_IS_AT_LEAST_XL_C_VERSION(12,0)
+ /*
+ * GCC 3.4 or later, or some compiler asserting compatibility with
+ * GCC 3.4 or later, or XL C 13.0 or later, so we have
+ * __attribute__((visibility()).
+ */
+ #define PCAP_API_DEF __attribute__((visibility("default")))
+ #elif PCAP_IS_AT_LEAST_SUNC_VERSION(5,5)
+ /*
+ * 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
+
+/*
+ * Definitions to 1) indicate what version of libpcap first had a given
+ * API and 2) allow upstream providers whose build environments allow
+ * APIs to be designated as "first available in this release" to do so
+ * by appropriately defining them.
+ *
+ * Yes, that's you, Apple. :-) Please define PCAP_AVAILABLE_MACOS()
+ * as necessary to make various APIs "weak exports" to make it easier
+ * for software that's distributed in binary form and that uses libpcap
+ * to run on multiple macOS versions and use new APIs when available.
+ * (Yes, such third-party software exists - Wireshark provides binary
+ * packages for macOS, for example. tcpdump doesn't count, as that's
+ * provided by Apple, so each release can come with a version compiled
+ * to use the APIs present in that release.)
+ *
+ * We don't define it ourselves because, if you're building and
+ * installing libpcap on macOS yourself, the APIs will be available
+ * no matter what OS version you're installing it on.
+ *
+ * For other platforms, we don't define them, leaving it up to
+ * others to do so based on their OS versions, if appropriate.
+ *
+ * We start with libpcap 0.4, as that was the last LBL release, and
+ * I've never seen earlier releases.
+ */
+#ifdef __APPLE__
+#define PCAP_AVAILABLE_MACOS(v) /* define to say "first appears in v" */
+#define PCAP_AVAILABLE_0_4 PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_5 PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_6 PCAP_AVAILABLE_MACOS(10.1)
+#define PCAP_AVAILABLE_0_7 PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_8 PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_9 PCAP_AVAILABLE_MACOS(10.5)
+#define PCAP_AVAILABLE_1_0 PCAP_AVAILABLE_MACOS(10.6)
+/* #define PCAP_AVAILABLE_1_1 no routines added to the API */
+#define PCAP_AVAILABLE_1_2 PCAP_AVAILABLE_MACOS(10.9)
+/* #define PCAP_AVAILABLE_1_3 no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4 no routines added to the API */
+#define PCAP_AVAILABLE_1_5 PCAP_AVAILABLE_MACOS(10.10)
+/* #define PCAP_AVAILABLE_1_6 no routines added to the API */
+#define PCAP_AVAILABLE_1_7 PCAP_AVAILABLE_MACOS(10.12)
+#define PCAP_AVAILABLE_1_8 PCAP_AVAILABLE_MACOS(10.13) /* only Windows adds routines to the API; XXX - what version first had it? */
+#define PCAP_AVAILABLE_1_9 PCAP_AVAILABLE_MACOS(10.13)
+#define PCAP_AVAILABLE_1_10 /* not in macOS yet */
+#define PCAP_AVAILABLE_1_11 /* not released yet, so not in macOS yet */
+#else /* __APPLE__ */
+#define PCAP_AVAILABLE_0_4
+#define PCAP_AVAILABLE_0_5
+#define PCAP_AVAILABLE_0_6
+#define PCAP_AVAILABLE_0_7
+#define PCAP_AVAILABLE_0_8
+#define PCAP_AVAILABLE_0_9
+#define PCAP_AVAILABLE_1_0
+/* #define PCAP_AVAILABLE_1_1 no routines added to the API */
+#define PCAP_AVAILABLE_1_2
+/* #define PCAP_AVAILABLE_1_3 no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4 no routines added to the API */
+#define PCAP_AVAILABLE_1_5
+/* #define PCAP_AVAILABLE_1_6 no routines added to the API */
+#define PCAP_AVAILABLE_1_7
+#define PCAP_AVAILABLE_1_8
+#define PCAP_AVAILABLE_1_9
+#define PCAP_AVAILABLE_1_10
+#define PCAP_AVAILABLE_1_11
+#endif /* __APPLE__ */
+
+/*
+ * PCAP_NORETURN, before a function declaration, means "this function
+ * never returns". (It must go before the function declaration, e.g.
+ * "extern PCAP_NORETURN func(...)" rather than after the function
+ * declaration, as the MSVC version has to go before the declaration.)
+ *
+ * PCAP_NORETURN_DEF, before a function *definition*, means "this
+ * function never returns"; it would be used only for static functions
+ * that are defined before any use, and thus have no declaration.
+ * (MSVC doesn't support that; I guess the "decl" in "__declspec"
+ * means "declaration", and __declspec doesn't work with definitions.)
+ */
+#if __has_attribute(noreturn) \
+ || PCAP_IS_AT_LEAST_GNUC_VERSION(2,5) \
+ || PCAP_IS_AT_LEAST_SUNC_VERSION(5,9) \
+ || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \
+ || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10)
+ /*
+ * Compiler with support for __attribute((noreturn)), or GCC 2.5 or
+ * later, or some compiler asserting compatibility with GCC 2.5 or
+ * later, or Solaris Studio 12 (Sun C 5.9) or later, or IBM XL C 10.1
+ * or later (do any earlier versions of XL C support this?), or HP aCC
+ * A.06.10 or later.
+ */
+ #define PCAP_NORETURN __attribute((noreturn))
+ #define PCAP_NORETURN_DEF __attribute((noreturn))
+#elif defined(_MSC_VER)
+ /*
+ * MSVC.
+ */
+ #define PCAP_NORETURN __declspec(noreturn)
+ #define PCAP_NORETURN_DEF
+#else
+ #define PCAP_NORETURN
+ #define PCAP_NORETURN_DEF
+#endif
+
+/*
+ * PCAP_PRINTFLIKE(x,y), after a function declaration, means "this function
+ * does printf-style formatting, with the xth argument being the format
+ * string and the yth argument being the first argument for the format
+ * string".
+ */
+#if __has_attribute(__format__) \
+ || PCAP_IS_AT_LEAST_GNUC_VERSION(2,3) \
+ || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \
+ || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10)
+ /*
+ * Compiler with support for it, or GCC 2.3 or later, or some compiler
+ * asserting compatibility with GCC 2.3 or later, or IBM XL C 10.1
+ * and later (do any earlier versions of XL C support this?),
+ * or HP aCC A.06.10 and later.
+ */
+ #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y)))
+#else
+ #define PCAP_PRINTFLIKE(x,y)
+#endif
+
+/*
+ * PCAP_DEPRECATED(func, msg), after a function declaration, marks the
+ * function as deprecated.
+ *
+ * The first argument is the name of the function; the second argument is
+ * a string giving the warning message to use if the compiler supports that.
+ *
+ * (Thank you, Microsoft, for requiring the function name.)
+ */
+#if __has_attribute(deprecated) \
+ || PCAP_IS_AT_LEAST_GNUC_VERSION(4,5) \
+ || PCAP_IS_AT_LEAST_SUNC_VERSION(5,13)
+ /*
+ * Compiler that supports __has_attribute and __attribute__((deprecated)),
+ * or GCC 4.5 or later, or Sun/Oracle C 12.4 (Sun C 5.13) or later.
+ *
+ * Those support __attribute__((deprecated(msg))) (we assume, perhaps
+ * incorrectly, that anything that supports __has_attribute() is
+ * recent enough to support __attribute__((deprecated(msg)))).
+ */
+ #define PCAP_DEPRECATED(func, msg) __attribute__((deprecated(msg)))
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(3,1)
+ /*
+ * GCC 3.1 through 4.4.
+ *
+ * Those support __attribute__((deprecated)) but not
+ * __attribute__((deprecated(msg))).
+ */
+ #define PCAP_DEPRECATED(func, msg) __attribute__((deprecated))
+#elif defined(_MSC_VER) && !defined(BUILDING_PCAP)
+ /*
+ * MSVC, and we're not building libpcap itself; it's VS 2015
+ * or later, so we have the deprecated pragma.
+ *
+ * If we *are* building libpcap, we don't want this, as it'll warn
+ * us even if we *define* the function.
+ */
+ #define PCAP_DEPRECATED(func, msg) __pragma(deprecated(func))
+#else
+ #define PCAP_DEPRECATED(func, msg)
+#endif
+
+/*
+ * For flagging arguments as format strings in MSVC.
+ */
+#ifdef _MSC_VER
+ #include <sal.h>
+ #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
+#else
+ #define PCAP_FORMAT_STRING(p) p
+#endif
+
+#endif /* lib_pcap_funcattrs_h */
diff --git a/pcap/ipnet.h b/pcap/ipnet.h
new file mode 100644
index 0000000..5330847
--- /dev/null
+++ b/pcap/ipnet.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define IPH_AF_INET 2 /* Matches Solaris's AF_INET */
+#define IPH_AF_INET6 26 /* Matches Solaris's AF_INET6 */
+
+#define IPNET_OUTBOUND 1
+#define IPNET_INBOUND 2
diff --git a/pcap/namedb.h b/pcap/namedb.h
new file mode 100644
index 0000000..34a0ae7
--- /dev/null
+++ b/pcap/namedb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1994, 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 lib_pcap_namedb_h
+#define lib_pcap_namedb_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * As returned by the pcap_next_etherent()
+ * 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'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];
+ char name[122];
+};
+#ifndef PCAP_ETHERS_FILE
+#define PCAP_ETHERS_FILE "/etc/ethers"
+#endif
+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 *);
+
+PCAP_API bpf_u_int32 **pcap_nametoaddr(const char *)
+PCAP_DEPRECATED(pcap_nametoaddr, "this is not reentrant; use 'pcap_nametoaddrinfo' instead");
+PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *);
+PCAP_API bpf_u_int32 pcap_nametonetaddr(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.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF -1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pcap/nflog.h b/pcap/nflog.h
new file mode 100644
index 0000000..f7c85b5
--- /dev/null
+++ b/pcap/nflog.h
@@ -0,0 +1,94 @@
+/*
+ * 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
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * Structure of an NFLOG header and TLV parts, as described at
+ * https://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 {
+ uint8_t nflog_family; /* address family */
+ uint8_t nflog_version; /* version */
+ uint16_t nflog_rid; /* resource ID */
+} nflog_hdr_t;
+
+typedef struct nflog_tlv {
+ uint16_t tlv_length; /* tlv length */
+ uint16_t tlv_type; /* tlv type */
+ /* value follows this */
+} nflog_tlv_t;
+
+typedef struct nflog_packet_hdr {
+ uint16_t hw_protocol; /* hw protocol */
+ uint8_t hook; /* netfilter hook */
+ uint8_t pad; /* padding to 32 bits */
+} nflog_packet_hdr_t;
+
+typedef struct nflog_hwaddr {
+ uint16_t hw_addrlen; /* address length */
+ uint16_t pad; /* padding to 32-bit boundary */
+ uint8_t hw_addr[8]; /* address, up to 8 bytes */
+} nflog_hwaddr_t;
+
+typedef struct nflog_timestamp {
+ uint64_t sec;
+ uint64_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/pcap/pcap-inttypes.h b/pcap/pcap-inttypes.h
new file mode 100644
index 0000000..1cfa0bf
--- /dev/null
+++ b/pcap/pcap-inttypes.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino 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 pcap_pcap_inttypes_h
+#define pcap_pcap_inttypes_h
+
+/*
+ * If we're compiling with Visual Studio, make sure we have at least
+ * VS 2015 or later, so we have sufficient C99 support.
+ *
+ * XXX - verify that we have at least C99 support on UN*Xes?
+ *
+ * What about MinGW or various DOS toolchains? We're currently assuming
+ * sufficient C99 support there.
+ */
+#if defined(_MSC_VER)
+ /*
+ * Compiler is MSVC. Make sure we have VS 2015 or later.
+ */
+ #if _MSC_VER < 1900
+ #error "Building libpcap requires VS 2015 or later"
+ #endif
+#endif
+
+/*
+ * Include <inttypes.h> to get the integer types and PRi[doux]64 values
+ * defined.
+ *
+ * If the compiler is MSVC, we require VS 2015 or newer, so we
+ * have <inttypes.h> - and support for %zu in the formatted
+ * printing functions.
+ *
+ * If the compiler is MinGW, we assume we have <inttypes.h> - and
+ * support for %zu in the formatted printing functions.
+ *
+ * If the target is UN*X, we assume we have a C99-or-later development
+ * environment, and thus have <inttypes.h> - and support for %zu in
+ * the formatted printing functions.
+ *
+ * If the target is MS-DOS, we assume we have <inttypes.h> - and support
+ * for %zu in the formatted printing functions.
+ *
+ * I.e., assume we have <inttypes.h> and that it suffices.
+ */
+
+/*
+ * XXX - somehow make sure we have enough C99 support with other
+ * compilers and support libraries?
+ */
+
+#include <inttypes.h>
+
+#endif /* pcap/pcap-inttypes.h */
diff --git a/pcap/pcap.h b/pcap/pcap.h
new file mode 100644
index 0000000..8182bef
--- /dev/null
+++ b/pcap/pcap.h
@@ -0,0 +1,1219 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Remote packet capture mechanisms and extensions from WinPcap:
+ *
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef lib_pcap_pcap_h
+#define lib_pcap_pcap_h
+
+/*
+ * Some software that uses libpcap/WinPcap/Npcap defines _MSC_VER before
+ * includeing pcap.h if it's not defined - and it defines it to 1500.
+ * (I'm looking at *you*, lwIP!)
+ *
+ * Attempt to detect this, and undefine _MSC_VER so that we can *reliably*
+ * use it to know what compiler is being used and, if it's Visual Studio,
+ * what version is being used.
+ */
+#if defined(_MSC_VER)
+ /*
+ * We assume here that software such as that doesn't define _MSC_FULL_VER
+ * as well and that it defines _MSC_VER with a value > 1200.
+ *
+ * DO NOT BREAK THESE ASSUMPTIONS. IF YOU FEEL YOU MUST DEFINE _MSC_VER
+ * WITH A COMPILER THAT'S NOT MICROSOFT'S C COMPILER, PLEASE CONTACT
+ * US SO THAT WE CAN MAKE IT SO THAT YOU DON'T HAVE TO DO THAT. THANK
+ * YOU.
+ *
+ * OK, is _MSC_FULL_VER defined?
+ */
+ #if !defined(_MSC_FULL_VER)
+ /*
+ * According to
+ *
+ * https://sourceforge.net/p/predef/wiki/Compilers/
+ *
+ * with "Visual C++ 6.0 Processor Pack"/Visual C++ 6.0 SP6 and
+ * later, _MSC_FULL_VER is defined, so either this is an older
+ * version of Visual C++ or it's not Visual C++ at all.
+ *
+ * For Visual C++ 6.0, _MSC_VER is defined as 1200.
+ */
+ #if _MSC_VER > 1200
+ /*
+ * If this is Visual C++, _MSC_FULL_VER should be defined, so we
+ * assume this isn't Visual C++, and undo the lie that it is.
+ */
+ #undef _MSC_VER
+ #endif
+ #endif
+#endif
+
+#include <pcap/funcattrs.h>
+
+#include <pcap/pcap-inttypes.h>
+
+#if defined(_WIN32)
+ #include <winsock2.h> /* u_int, u_char etc. */
+ #include <io.h> /* _get_osfhandle() */
+#elif defined(MSDOS)
+ #include <sys/types.h> /* u_int, u_char etc. */
+ #include <sys/socket.h>
+#else /* UN*X */
+ #include <sys/types.h> /* u_int, u_char etc. */
+ #include <sys/time.h>
+#endif /* _WIN32/MSDOS/UN*X */
+
+#include <pcap/socket.h> /* for SOCKET, as the active-mode rpcap APIs use it */
+
+#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H
+#include <pcap/bpf.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Version number of the current version of the pcap file format.
+ *
+ * NOTE: this is *NOT* the version number of the libpcap library.
+ * To fetch the version information for the version of libpcap
+ * you're using, use pcap_lib_version().
+ */
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define PCAP_ERRBUF_SIZE 256
+
+/*
+ * Compatibility for systems that have a bpf.h that
+ * predates the bpf typedefs for 64-bit support.
+ */
+#if BPF_RELEASE - 0 < 199406
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+typedef struct pcap pcap_t;
+typedef struct pcap_dumper pcap_dumper_t;
+typedef struct pcap_if pcap_if_t;
+typedef struct pcap_addr pcap_addr_t;
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are 32 bit ints so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ * Documentation: https://www.tcpdump.org/manpages/pcap-savefile.5.txt.
+ *
+ * Do not change the layout of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ *
+ * Also, do not change the interpretation of any of the members of this
+ * structure, in any way (this includes using values other than
+ * LINKTYPE_ values, as defined in "savefile.c", in the "linktype"
+ * field).
+ *
+ * Instead:
+ *
+ * introduce a new structure for the new format, if the layout
+ * of the structure changed;
+ *
+ * send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ * a new magic number for your new capture file format, and, when
+ * you get the new magic number, put it in "savefile.c";
+ *
+ * use that magic number for save files with the changed file
+ * header;
+ *
+ * make the code in "savefile.c" capable of reading files with
+ * the old file header as well as files with the new file header
+ * (using the magic number to determine the header format).
+ *
+ * Then supply the changes by forking the branch at
+ *
+ * https://github.com/the-tcpdump-group/libpcap/tree/master
+ *
+ * and issuing a pull request, so that future versions of libpcap and
+ * programs that use it (such as tcpdump) will be able to read your new
+ * capture file format.
+ */
+struct pcap_file_header {
+ bpf_u_int32 magic;
+ u_short version_major;
+ u_short version_minor;
+ bpf_int32 thiszone; /* gmt to local correction; this is always 0 */
+ bpf_u_int32 sigfigs; /* accuracy of timestamps; this is always 0 */
+ bpf_u_int32 snaplen; /* max length saved portion of each pkt */
+ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
+};
+
+/*
+ * Macros for the value returned by pcap_datalink_ext().
+ *
+ * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro
+ * gives the FCS length of packets in the capture.
+ */
+#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000)
+#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28)
+#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000)
+
+typedef enum {
+ PCAP_D_INOUT = 0,
+ PCAP_D_IN,
+ PCAP_D_OUT
+} pcap_direction_t;
+
+/*
+ * Generic per-packet information, as supplied by libpcap.
+ *
+ * The time stamp can and should be a "struct timeval", regardless of
+ * whether your system supports 32-bit tv_sec in "struct timeval",
+ * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit
+ * and 64-bit applications. The on-disk format of savefiles uses 32-bit
+ * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit
+ * and 64-bit versions of libpcap, even if they're on the same platform,
+ * should supply the appropriate version of "struct timeval", even if
+ * that's not what the underlying packet capture mechanism supplies.
+ */
+struct pcap_pkthdr {
+ struct timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length of this packet (off wire) */
+};
+
+/*
+ * As returned by the pcap_stats()
+ */
+struct pcap_stat {
+ u_int ps_recv; /* number of packets received */
+ u_int ps_drop; /* number of packets dropped */
+ u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */
+#ifdef _WIN32
+ u_int ps_capt; /* number of packets that reach the application */
+ u_int ps_sent; /* number of packets sent by the server on the network */
+ u_int ps_netdrop; /* number of packets lost on the network */
+#endif /* _WIN32 */
+};
+
+#ifdef MSDOS
+/*
+ * As returned by the pcap_stats_ex()
+ */
+struct pcap_stat_ex {
+ u_long rx_packets; /* total packets received */
+ u_long tx_packets; /* total packets transmitted */
+ u_long rx_bytes; /* total bytes received */
+ u_long tx_bytes; /* total bytes transmitted */
+ u_long rx_errors; /* bad packets received */
+ u_long tx_errors; /* packet transmit problems */
+ u_long rx_dropped; /* no space in Rx buffers */
+ u_long tx_dropped; /* no space available for Tx */
+ u_long multicast; /* multicast packets received */
+ u_long collisions;
+
+ /* detailed rx_errors: */
+ u_long rx_length_errors;
+ u_long rx_over_errors; /* receiver ring buff overflow */
+ u_long rx_crc_errors; /* recv'd pkt with crc error */
+ u_long rx_frame_errors; /* recv'd frame alignment error */
+ u_long rx_fifo_errors; /* recv'r fifo overrun */
+ u_long rx_missed_errors; /* recv'r missed packet */
+
+ /* detailed tx_errors */
+ u_long tx_aborted_errors;
+ u_long tx_carrier_errors;
+ u_long tx_fifo_errors;
+ u_long tx_heartbeat_errors;
+ u_long tx_window_errors;
+ };
+#endif
+
+/*
+ * Item in a list of interfaces.
+ */
+struct pcap_if {
+ struct pcap_if *next;
+ char *name; /* name to hand to "pcap_open_live()" */
+ char *description; /* textual description of interface, or NULL */
+ struct pcap_addr *addresses;
+ bpf_u_int32 flags; /* PCAP_IF_ interface flags */
+};
+
+#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */
+#define PCAP_IF_UP 0x00000002 /* interface is up */
+#define PCAP_IF_RUNNING 0x00000004 /* interface is running */
+#define PCAP_IF_WIRELESS 0x00000008 /* interface is wireless (*NOT* necessarily Wi-Fi!) */
+#define PCAP_IF_CONNECTION_STATUS 0x00000030 /* connection status: */
+#define PCAP_IF_CONNECTION_STATUS_UNKNOWN 0x00000000 /* unknown */
+#define PCAP_IF_CONNECTION_STATUS_CONNECTED 0x00000010 /* connected */
+#define PCAP_IF_CONNECTION_STATUS_DISCONNECTED 0x00000020 /* disconnected */
+#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE 0x00000030 /* not applicable */
+
+/*
+ * Representation of an interface address.
+ */
+struct pcap_addr {
+ struct pcap_addr *next;
+ struct sockaddr *addr; /* address */
+ struct sockaddr *netmask; /* netmask for that address */
+ struct sockaddr *broadaddr; /* broadcast address for that address */
+ struct sockaddr *dstaddr; /* P2P destination address for that address */
+};
+
+typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+
+/*
+ * Error codes for the pcap API.
+ * These will all be negative, so you can check for the success or
+ * failure of a call that returns these codes by checking for a
+ * negative value.
+ */
+#define PCAP_ERROR -1 /* generic error code */
+#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */
+#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */
+#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */
+#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */
+#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */
+#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */
+#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */
+#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */
+#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */
+#define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */
+#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */
+
+/*
+ * Warning codes for the pcap API.
+ * These will all be positive and non-zero, so they won't look like
+ * errors.
+ */
+#define PCAP_WARNING 1 /* generic warning code */
+#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */
+#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */
+
+/*
+ * Value to pass to pcap_compile() as the netmask if you don't know what
+ * the netmask is.
+ */
+#define PCAP_NETMASK_UNKNOWN 0xffffffff
+
+/*
+ * Initialize pcap. If this isn't called, pcap is initialized to
+ * a mode source-compatible and binary-compatible with older versions
+ * that lack this routine.
+ */
+
+/*
+ * Initialization options.
+ * All bits not listed here are reserved for expansion.
+ *
+ * On UNIX-like systems, the local character encoding is assumed to be
+ * UTF-8, so no character encoding transformations are done.
+ *
+ * On Windows, the local character encoding is the local ANSI code page.
+ */
+#define PCAP_CHAR_ENC_LOCAL 0x00000000U /* strings are in the local character encoding */
+#define PCAP_CHAR_ENC_UTF_8 0x00000001U /* strings are in UTF-8 */
+
+PCAP_AVAILABLE_1_10
+PCAP_API int pcap_init(unsigned int, char *);
+
+/*
+ * We're deprecating pcap_lookupdev() for various reasons (not
+ * thread-safe, can behave weirdly with WinPcap). Callers
+ * should use pcap_findalldevs() and use the first device.
+ */
+PCAP_AVAILABLE_0_4
+PCAP_API char *pcap_lookupdev(char *)
+PCAP_DEPRECATED(pcap_lookupdev, "use 'pcap_findalldevs' and use the first device");
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API pcap_t *pcap_create(const char *, char *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_set_snaplen(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_set_promisc(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_can_set_rfmon(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_set_rfmon(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_set_timeout(pcap_t *, int);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int pcap_set_tstamp_type(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int pcap_set_immediate_mode(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_set_buffer_size(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int pcap_set_tstamp_precision(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API int pcap_get_tstamp_precision(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_activate(pcap_t *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int pcap_list_tstamp_types(pcap_t *, int **);
+
+PCAP_AVAILABLE_1_2
+PCAP_API void pcap_free_tstamp_types(int *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API int pcap_tstamp_type_name_to_val(const char *);
+
+PCAP_AVAILABLE_1_2
+PCAP_API const char *pcap_tstamp_type_val_to_name(int);
+
+PCAP_AVAILABLE_1_2
+PCAP_API const char *pcap_tstamp_type_val_to_description(int);
+
+#ifdef __linux__
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
+#endif
+
+/*
+ * Time stamp types.
+ * Not all systems and interfaces will necessarily support all of these.
+ *
+ * A system that supports PCAP_TSTAMP_HOST is offering time stamps
+ * provided by the host machine, rather than by the capture device,
+ * but not committing to any characteristics of the time stamp.
+ *
+ * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine,
+ * that's low-precision but relatively cheap to fetch; it's normally done
+ * using the system clock, so it's normally synchronized with times you'd
+ * fetch from system calls.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine,
+ * that's high-precision; it might be more expensive to fetch. It is
+ * synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC_UNSYNCED is a time stamp, provided by the host
+ * machine, that's high-precision; it might be more expensive to fetch.
+ * It is not synchronized with the system clock, and might have
+ * problems with time stamps for packets received on different CPUs,
+ * depending on the platform. It might be more likely to be strictly
+ * monotonic than PCAP_TSTAMP_HOST_HIPREC.
+ *
+ * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the
+ * capture device; it's synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by
+ * the capture device; it's not synchronized with the system clock.
+ *
+ * Note that time stamps synchronized with the system clock can go
+ * backwards, as the system clock can go backwards. If a clock is
+ * not in sync with the system clock, that could be because the
+ * system clock isn't keeping accurate time, because the other
+ * clock isn't keeping accurate time, or both.
+ *
+ * Note that host-provided time stamps generally correspond to the
+ * time when the time-stamping code sees the packet; this could
+ * be some unknown amount of time after the first or last bit of
+ * the packet is received by the network adapter, due to batching
+ * of interrupts for packet arrival, queueing delays, etc..
+ */
+#define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */
+#define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision, synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED 5 /* host-provided, high precision, not synced with the system clock */
+
+/*
+ * Time stamp resolution types.
+ * Not all systems and interfaces will necessarily support all of these
+ * resolutions when doing live captures; all of them can be requested
+ * when reading a savefile.
+ */
+#define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */
+#define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_t *pcap_open_live(const char *, int, int, int, char *);
+
+PCAP_AVAILABLE_0_6
+PCAP_API pcap_t *pcap_open_dead(int, int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int);
+
+PCAP_AVAILABLE_1_5
+PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_t *pcap_open_offline(const char *, char *);
+
+#ifdef _WIN32
+ PCAP_AVAILABLE_1_5
+ PCAP_API pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *);
+
+ PCAP_API pcap_t *pcap_hopen_offline(intptr_t, char *);
+ /*
+ * If we're building libpcap, these are internal routines in savefile.c,
+ * so we must not define them as macros.
+ *
+ * If we're not building libpcap, given that the version of the C runtime
+ * with which libpcap was built might be different from the version
+ * of the C runtime with which an application using libpcap was built,
+ * and that a FILE structure may differ between the two versions of the
+ * C runtime, calls to _fileno() must use the version of _fileno() in
+ * the C runtime used to open the FILE *, not the version in the C
+ * runtime with which libpcap was built. (Maybe once the Universal CRT
+ * rules the world, this will cease to be a problem.)
+ */
+ #ifndef BUILDING_PCAP
+ #define pcap_fopen_offline_with_tstamp_precision(f,p,b) \
+ pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b)
+ #define pcap_fopen_offline(f,b) \
+ pcap_hopen_offline(_get_osfhandle(_fileno(f)), b)
+ #endif
+#else /*_WIN32*/
+ PCAP_AVAILABLE_1_5
+ PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
+
+ PCAP_AVAILABLE_0_9
+ PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *);
+#endif /*_WIN32*/
+
+PCAP_AVAILABLE_0_4
+PCAP_API void pcap_close(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
+
+PCAP_AVAILABLE_0_8
+PCAP_API void pcap_breakloop(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int pcap_getnonblock(pcap_t *, char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int pcap_setnonblock(pcap_t *, int, char *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API int pcap_inject(pcap_t *, const void *, size_t);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int);
+
+PCAP_AVAILABLE_1_0
+PCAP_API const char *pcap_statustostr(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API const char *pcap_strerror(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API char *pcap_geterr(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void pcap_perror(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int,
+ bpf_u_int32);
+
+PCAP_AVAILABLE_0_5
+PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *,
+ const char *, int, bpf_u_int32);
+
+/* XXX - this took two arguments in 0.4 and 0.5 */
+PCAP_AVAILABLE_0_6
+PCAP_API void pcap_freecode(struct bpf_program *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_offline_filter(const struct bpf_program *,
+ const struct pcap_pkthdr *, const u_char *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_datalink(pcap_t *);
+
+PCAP_AVAILABLE_1_0
+PCAP_API int pcap_datalink_ext(pcap_t *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_list_datalinks(pcap_t *, int **);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_set_datalink(pcap_t *, int);
+
+PCAP_AVAILABLE_0_8
+PCAP_API void pcap_free_datalinks(int *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_datalink_name_to_val(const char *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_datalink_val_to_name(int);
+
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_datalink_val_to_description(int);
+
+PCAP_AVAILABLE_1_10
+PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_snapshot(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_is_swapped(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_major_version(pcap_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_minor_version(pcap_t *);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_bufsize(pcap_t *);
+
+/* XXX */
+PCAP_AVAILABLE_0_4
+PCAP_API FILE *pcap_file(pcap_t *);
+
+#ifdef _WIN32
+/*
+ * This probably shouldn't have been kept in WinPcap; most if not all
+ * UN*X code that used it won't work on Windows. We deprecate it; if
+ * anybody really needs access to whatever HANDLE may be associated
+ * with a pcap_t (there's no guarantee that there is one), we can add
+ * a Windows-only pcap_handle() API that returns the HANDLE.
+ */
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_fileno(pcap_t *)
+PCAP_DEPRECATED(pcap_fileno, "use 'pcap_handle'");
+#else /* _WIN32 */
+PCAP_AVAILABLE_0_4
+PCAP_API int pcap_fileno(pcap_t *);
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+ PCAP_API int pcap_wsockinit(void);
+#endif
+
+PCAP_AVAILABLE_0_4
+PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
+
+#ifdef _WIN32
+ PCAP_AVAILABLE_0_9
+ PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t);
+
+ /*
+ * If we're building libpcap, this is an internal routine in sf-pcap.c, so
+ * we must not define it as a macro.
+ *
+ * If we're not building libpcap, given that the version of the C runtime
+ * with which libpcap was built might be different from the version
+ * of the C runtime with which an application using libpcap was built,
+ * and that a FILE structure may differ between the two versions of the
+ * C runtime, calls to _fileno() must use the version of _fileno() in
+ * the C runtime used to open the FILE *, not the version in the C
+ * runtime with which libpcap was built. (Maybe once the Universal CRT
+ * rules the world, this will cease to be a problem.)
+ */
+ #ifndef BUILDING_PCAP
+ #define pcap_dump_fopen(p,f) \
+ pcap_dump_hopen(p, _get_osfhandle(_fileno(f)))
+ #endif
+#else /*_WIN32*/
+ PCAP_AVAILABLE_0_9
+ PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp);
+#endif /*_WIN32*/
+
+PCAP_AVAILABLE_1_7
+PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API FILE *pcap_dump_file(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_9
+PCAP_API long pcap_dump_ftell(pcap_dumper_t *);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int64_t pcap_dump_ftell64(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_8
+PCAP_API int pcap_dump_flush(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void pcap_dump_close(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
+PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API int pcap_findalldevs(pcap_if_t **, char *);
+
+PCAP_AVAILABLE_0_7
+PCAP_API void pcap_freealldevs(pcap_if_t *);
+
+/*
+ * We return a pointer to the version string, rather than exporting the
+ * version string directly.
+ *
+ * On at least some UNIXes, if you import data from a shared library into
+ * a program, the data is bound into the program binary, so if the string
+ * in the version of the library with which the program was linked isn't
+ * the same as the string in the version of the library with which the
+ * program is being run, various undesirable things may happen (warnings,
+ * the string being the one from the version of the library with which the
+ * program was linked, or even weirder things, such as the string being the
+ * one from the library but being truncated).
+ *
+ * On Windows, the string is constructed at run time.
+ */
+PCAP_AVAILABLE_0_8
+PCAP_API const char *pcap_lib_version(void);
+
+#if defined(_WIN32)
+
+ /*
+ * Win32 definitions
+ */
+
+ /*!
+ \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit().
+ */
+ struct pcap_send_queue
+ {
+ u_int maxlen; /* Maximum size of the queue, in bytes. This
+ variable contains the size of the buffer field. */
+ u_int len; /* Current size of the queue, in bytes. */
+ char *buffer; /* Buffer containing the packets to be sent. */
+ };
+
+ typedef struct pcap_send_queue pcap_send_queue;
+
+ /*!
+ \brief This typedef is a support for the pcap_get_airpcap_handle() function
+ */
+ #if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)
+ #define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_
+ typedef struct _AirpcapHandle *PAirpcapHandle;
+ #endif
+
+ PCAP_API int pcap_setbuff(pcap_t *p, int dim);
+ PCAP_API int pcap_setmode(pcap_t *p, int mode);
+ PCAP_API int pcap_setmintocopy(pcap_t *p, int size);
+
+ PCAP_API HANDLE pcap_getevent(pcap_t *p);
+
+ PCAP_AVAILABLE_1_8
+ PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *);
+
+ PCAP_AVAILABLE_1_8
+ PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *);
+
+ PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
+
+ PCAP_API void pcap_sendqueue_destroy(pcap_send_queue* queue);
+
+ PCAP_API int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);
+
+ PCAP_API u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync);
+
+ PCAP_API struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size);
+
+ PCAP_API int pcap_setuserbuffer(pcap_t *p, int size);
+
+ PCAP_API int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks);
+
+ PCAP_API int pcap_live_dump_ended(pcap_t *p, int sync);
+
+ PCAP_API int pcap_start_oem(char* err_str, int flags);
+
+ PCAP_API PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p);
+
+ #define MODE_CAPT 0
+ #define MODE_STAT 1
+ #define MODE_MON 2
+
+#elif defined(MSDOS)
+
+ /*
+ * MS-DOS definitions
+ */
+
+ PCAP_API int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *);
+ PCAP_API void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait);
+ PCAP_API u_long pcap_mac_packets (void);
+
+#else /* UN*X */
+
+ /*
+ * UN*X definitions
+ */
+
+ PCAP_AVAILABLE_0_8
+ PCAP_API int pcap_get_selectable_fd(pcap_t *);
+
+ PCAP_AVAILABLE_1_9
+ PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *);
+
+#endif /* _WIN32/MSDOS/UN*X */
+
+/*
+ * Remote capture definitions.
+ *
+ * These routines are only present if libpcap has been configured to
+ * include remote capture support.
+ */
+
+/*
+ * The maximum buffer size in which address, port, interface names are kept.
+ *
+ * In case the adapter name or such is larger than this value, it is truncated.
+ * This is not used by the user; however it must be aware that an hostname / interface
+ * name longer than this value will be truncated.
+ */
+#define PCAP_BUF_SIZE 1024
+
+/*
+ * The type of input source, passed to pcap_open().
+ */
+#define PCAP_SRC_FILE 2 /* local savefile */
+#define PCAP_SRC_IFLOCAL 3 /* local network interface */
+#define PCAP_SRC_IFREMOTE 4 /* interface on a remote host, using RPCAP */
+
+/*
+ * The formats allowed by pcap_open() are the following:
+ * - file://path_and_filename [opens a local file]
+ * - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol]
+ * - rpcap://host/devicename [opens the selected device available on a remote host]
+ * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP]
+ * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged]
+ * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged]
+ *
+ * The formats allowed by the pcap_findalldevs_ex() are the following:
+ * - file://folder/ [lists all the files in the given folder]
+ * - rpcap:// [lists all local adapters]
+ * - rpcap://host:port/ [lists the devices available on a remote host]
+ *
+ * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable
+ * SSL (if it has been compiled in).
+ *
+ * Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since
+ * IPv6 is fully supported, these are the allowed formats:
+ *
+ * - host (literal): e.g. host.foo.bar
+ * - host (numeric IPv4): e.g. 10.11.12.13
+ * - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13]
+ * - host (numeric IPv6): e.g. [1:2:3::4]
+ * - port: can be either numeric (e.g. '80') or literal (e.g. 'http')
+ *
+ * Here you find some allowed examples:
+ * - rpcap://host.foo.bar/devicename [everything literal, no port number]
+ * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number]
+ * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number]
+ * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number]
+ * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number]
+ * - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number]
+ * - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number]
+ * - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number]
+ */
+
+/*
+ * URL schemes for capture source.
+ */
+/*
+ * This string indicates that the user wants to open a capture from a
+ * local file.
+ */
+#define PCAP_SRC_FILE_STRING "file://"
+/*
+ * This string indicates that the user wants to open a capture from a
+ * network interface. This string does not necessarily involve the use
+ * of the RPCAP protocol. If the interface required resides on the local
+ * host, the RPCAP protocol is not involved and the local functions are used.
+ */
+#define PCAP_SRC_IF_STRING "rpcap://"
+
+/*
+ * Flags to pass to pcap_open().
+ */
+
+/*
+ * Specifies whether promiscuous mode is to be used.
+ */
+#define PCAP_OPENFLAG_PROMISCUOUS 0x00000001
+
+/*
+ * Specifies, for an RPCAP capture, whether the data transfer (in
+ * case of a remote capture) has to be done with UDP protocol.
+ *
+ * If it is '1' if you want a UDP data connection, '0' if you want
+ * a TCP data connection; control connection is always TCP-based.
+ * A UDP connection is much lighter, but it does not guarantee that all
+ * the captured packets arrive to the client workstation. Moreover,
+ * it could be harmful in case of network congestion.
+ * This flag is meaningless if the source is not a remote interface.
+ * In that case, it is simply ignored.
+ */
+#define PCAP_OPENFLAG_DATATX_UDP 0x00000002
+
+/*
+ * Specifies whether the remote probe will capture its own generated
+ * traffic.
+ *
+ * In case the remote probe uses the same interface to capture traffic
+ * and to send data back to the caller, the captured traffic includes
+ * the RPCAP traffic as well. If this flag is turned on, the RPCAP
+ * traffic is excluded from the capture, so that the trace returned
+ * back to the collector is does not include this traffic.
+ *
+ * Has no effect on local interfaces or savefiles.
+ */
+#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 0x00000004
+
+/*
+ * Specifies whether the local adapter will capture its own generated traffic.
+ *
+ * This flag tells the underlying capture driver to drop the packets
+ * that were sent by itself. This is useful when building applications
+ * such as bridges that should ignore the traffic they just sent.
+ *
+ * Supported only on Windows.
+ */
+#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 0x00000008
+
+/*
+ * This flag configures the adapter for maximum responsiveness.
+ *
+ * In presence of a large value for nbytes, WinPcap waits for the arrival
+ * of several packets before copying the data to the user. This guarantees
+ * a low number of system calls, i.e. lower processor usage, i.e. better
+ * performance, which is good for applications like sniffers. If the user
+ * sets the PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will
+ * copy the packets as soon as the application is ready to receive them.
+ * This is suggested for real time applications (such as, for example,
+ * a bridge) that need the best responsiveness.
+ *
+ * The equivalent with pcap_create()/pcap_activate() is "immediate mode".
+ */
+#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 0x00000010
+
+/*
+ * Remote authentication methods.
+ * These are used in the 'type' member of the pcap_rmtauth structure.
+ */
+
+/*
+ * NULL authentication.
+ *
+ * The 'NULL' authentication has to be equal to 'zero', so that old
+ * applications can just put every field of struct pcap_rmtauth to zero,
+ * and it does work.
+ */
+#define RPCAP_RMTAUTH_NULL 0
+/*
+ * Username/password authentication.
+ *
+ * With this type of authentication, the RPCAP protocol will use the username/
+ * password provided to authenticate the user on the remote machine. If the
+ * authentication is successful (and the user has the right to open network
+ * devices) the RPCAP connection will continue; otherwise it will be dropped.
+ *
+ * *******NOTE********: the username and password are sent over the network
+ * to the capture server *IN CLEAR TEXT*. Don't use this on a network
+ * that you don't completely control! (And be *really* careful in your
+ * definition of "completely"!)
+ */
+#define RPCAP_RMTAUTH_PWD 1
+
+/*
+ * This structure keeps the information needed to authenticate the user
+ * on a remote machine.
+ *
+ * The remote machine can either grant or refuse the access according
+ * to the information provided.
+ * In case the NULL authentication is required, both 'username' and
+ * 'password' can be NULL pointers.
+ *
+ * This structure is meaningless if the source is not a remote interface;
+ * in that case, the functions which requires such a structure can accept
+ * a NULL pointer as well.
+ */
+struct pcap_rmtauth
+{
+ /*
+ * \brief Type of the authentication required.
+ *
+ * In order to provide maximum flexibility, we can support different types
+ * of authentication based on the value of this 'type' variable. The currently
+ * supported authentication methods are defined into the
+ * \link remote_auth_methods Remote Authentication Methods Section\endlink.
+ */
+ int type;
+ /*
+ * \brief Zero-terminated string containing the username that has to be
+ * used on the remote machine for authentication.
+ *
+ * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ * and it can be NULL.
+ */
+ char *username;
+ /*
+ * \brief Zero-terminated string containing the password that has to be
+ * used on the remote machine for authentication.
+ *
+ * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ * and it can be NULL.
+ */
+ char *password;
+};
+
+/*
+ * This routine can open a savefile, a local device, or a device on
+ * a remote machine running an RPCAP server.
+ *
+ * For opening a savefile, the pcap_open_offline routines can be used,
+ * and will work just as well; code using them will work on more
+ * platforms than code using pcap_open() to open savefiles.
+ *
+ * For opening a local device, pcap_open_live() can be used; it supports
+ * most of the capabilities that pcap_open() supports, and code using it
+ * will work on more platforms than code using pcap_open(). pcap_create()
+ * and pcap_activate() can also be used; they support all capabilities
+ * that pcap_open() supports, except for the Windows-only
+ * PCAP_OPENFLAG_NOCAPTURE_LOCAL, and support additional capabilities.
+ *
+ * For opening a remote capture, pcap_open() is currently the only
+ * API available.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API pcap_t *pcap_open(const char *source, int snaplen, int flags,
+ int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_createsrcstr(char *source, int type, const char *host,
+ const char *port, const char *name, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host,
+ char *port, char *name, char *errbuf);
+
+/*
+ * This routine can scan a directory for savefiles, list local capture
+ * devices, or list capture devices on a remote machine running an RPCAP
+ * server.
+ *
+ * For scanning for savefiles, it can be used on both UN*X systems and
+ * Windows systems; for each directory entry it sees, it tries to open
+ * the file as a savefile using pcap_open_offline(), and only includes
+ * it in the list of files if the open succeeds, so it filters out
+ * files for which the user doesn't have read permission, as well as
+ * files that aren't valid savefiles readable by libpcap.
+ *
+ * For listing local capture devices, it's just a wrapper around
+ * pcap_findalldevs(); code using pcap_findalldevs() will work on more
+ * platforms than code using pcap_findalldevs_ex().
+ *
+ * For listing remote capture devices, pcap_findalldevs_ex() is currently
+ * the only API available.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_findalldevs_ex(const char *source,
+ struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
+
+/*
+ * Sampling methods.
+ *
+ * These allow pcap_loop(), pcap_dispatch(), pcap_next(), and pcap_next_ex()
+ * to see only a sample of packets, rather than all packets.
+ *
+ * Currently, they work only on Windows local captures.
+ */
+
+/*
+ * Specifies that no sampling is to be done on the current capture.
+ *
+ * In this case, no sampling algorithms are applied to the current capture.
+ */
+#define PCAP_SAMP_NOSAMP 0
+
+/*
+ * Specifies that only 1 out of N packets must be returned to the user.
+ *
+ * In this case, the 'value' field of the 'pcap_samp' structure indicates the
+ * number of packets (minus 1) that must be discarded before one packet got
+ * accepted.
+ * In other words, if 'value = 10', the first packet is returned to the
+ * caller, while the following 9 are discarded.
+ */
+#define PCAP_SAMP_1_EVERY_N 1
+
+/*
+ * Specifies that we have to return 1 packet every N milliseconds.
+ *
+ * In this case, the 'value' field of the 'pcap_samp' structure indicates
+ * the 'waiting time' in milliseconds before one packet got accepted.
+ * In other words, if 'value = 10', the first packet is returned to the
+ * caller; the next returned one will be the first packet that arrives
+ * when 10ms have elapsed.
+ */
+#define PCAP_SAMP_FIRST_AFTER_N_MS 2
+
+/*
+ * This structure defines the information related to sampling.
+ *
+ * In case the sampling is requested, the capturing device should read
+ * only a subset of the packets coming from the source. The returned packets
+ * depend on the sampling parameters.
+ *
+ * WARNING: The sampling process is applied *after* the filtering process.
+ * In other words, packets are filtered first, then the sampling process
+ * selects a subset of the 'filtered' packets and it returns them to the
+ * caller.
+ */
+struct pcap_samp
+{
+ /*
+ * Method used for sampling; see above.
+ */
+ int method;
+
+ /*
+ * This value depends on the sampling method defined.
+ * For its meaning, see above.
+ */
+ int value;
+};
+
+/*
+ * New functions.
+ */
+PCAP_AVAILABLE_1_9
+PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
+
+/*
+ * RPCAP active mode.
+ */
+
+/* Maximum length of an host name (needed for the RPCAP active mode) */
+#define RPCAP_HOSTLIST_SIZE 1024
+
+PCAP_AVAILABLE_1_9
+PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port,
+ const char *hostlist, char *connectinghost,
+ struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_10
+PCAP_API SOCKET pcap_remoteact_accept_ex(const char *address, const char *port,
+ const char *hostlist, char *connectinghost,
+ struct pcap_rmtauth *auth, int uses_ssl, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size,
+ char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API int pcap_remoteact_close(const char *host, char *errbuf);
+
+PCAP_AVAILABLE_1_9
+PCAP_API void pcap_remoteact_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* lib_pcap_pcap_h */
diff --git a/pcap/sll.h b/pcap/sll.h
new file mode 100644
index 0000000..392faae
--- /dev/null
+++ b/pcap/sll.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * For captures on Linux cooked sockets, we construct a fake header
+ * that includes:
+ *
+ * a 2-byte "packet type" which is one of:
+ *
+ * LINUX_SLL_HOST packet was sent to us
+ * LINUX_SLL_BROADCAST packet was broadcast
+ * LINUX_SLL_MULTICAST packet was multicast
+ * LINUX_SLL_OTHERHOST packet was sent to somebody else
+ * LINUX_SLL_OUTGOING packet was sent *by* us;
+ *
+ * a 2-byte Ethernet protocol field;
+ *
+ * a 2-byte link-layer type;
+ *
+ * a 2-byte link-layer address length;
+ *
+ * an 8-byte source link-layer address, whose actual length is
+ * specified by the previous value.
+ *
+ * All fields except for the link-layer address are in network byte order.
+ *
+ * DO NOT change the layout of this structure, or change any of the
+ * LINUX_SLL_ values below. If you must change the link-layer header
+ * for a "cooked" Linux capture, introduce a new DLT_ type (ask
+ * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it
+ * a value that collides with a value already being used), and use the
+ * new header in captures of that type, so that programs that can
+ * handle DLT_LINUX_SLL captures will continue to handle them correctly
+ * without any change, and so that capture files with different headers
+ * can be told apart and programs that read them can dissect the
+ * packets in them.
+ */
+
+#ifndef lib_pcap_sll_h
+#define lib_pcap_sll_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * A DLT_LINUX_SLL fake link-layer header.
+ */
+#define SLL_HDR_LEN 16 /* total header length */
+#define SLL_ADDRLEN 8 /* length of address field */
+
+struct sll_header {
+ uint16_t sll_pkttype; /* packet type */
+ uint16_t sll_hatype; /* link-layer address type */
+ uint16_t sll_halen; /* link-layer address length */
+ uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
+ uint16_t sll_protocol; /* protocol */
+};
+
+/*
+ * A DLT_LINUX_SLL2 fake link-layer header.
+ */
+#define SLL2_HDR_LEN 20 /* total header length */
+
+struct sll2_header {
+ uint16_t sll2_protocol; /* protocol */
+ uint16_t sll2_reserved_mbz; /* reserved - must be zero */
+ uint32_t sll2_if_index; /* 1-based interface index */
+ uint16_t sll2_hatype; /* link-layer address type */
+ uint8_t sll2_pkttype; /* packet type */
+ uint8_t sll2_halen; /* link-layer address length */
+ uint8_t sll2_addr[SLL_ADDRLEN]; /* link-layer address */
+};
+
+/*
+ * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for
+ * "sll2_pkttype"; these correspond to the PACKET_ values on Linux,
+ * which are defined by a header under include/uapi in the current
+ * kernel source, and are thus not going to change on Linux. We
+ * define them here so that they're available even on systems other
+ * than Linux.
+ */
+#define LINUX_SLL_HOST 0
+#define LINUX_SLL_BROADCAST 1
+#define LINUX_SLL_MULTICAST 2
+#define LINUX_SLL_OTHERHOST 3
+#define LINUX_SLL_OUTGOING 4
+
+/*
+ * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for
+ * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but
+ * are defined here so that they're available even on systems other than
+ * Linux. We assume, for now, that the ETH_P_ values won't change in
+ * Linux; if they do, then:
+ *
+ * if we don't translate them in "pcap-linux.c", capture files
+ * won't necessarily be readable if captured on a system that
+ * defines ETH_P_ values that don't match these values;
+ *
+ * if we do translate them in "pcap-linux.c", that makes life
+ * unpleasant for the BPF code generator, as the values you test
+ * for in the kernel aren't the values that you test for when
+ * reading a capture file, so the fixup code run on BPF programs
+ * handed to the kernel ends up having to do more work.
+ *
+ * Add other values here as necessary, for handling packet types that
+ * might show up on non-Ethernet, non-802.x networks. (Not all the ones
+ * in the Linux "if_ether.h" will, I suspect, actually show up in
+ * captures.)
+ */
+#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/pcap/socket.h b/pcap/socket.h
new file mode 100644
index 0000000..ee2e393
--- /dev/null
+++ b/pcap/socket.h
@@ -0,0 +1,84 @@
+/* -*- 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_socket_h
+#define lib_pcap_socket_h
+
+/*
+ * Some minor differences between sockets on various platforms.
+ * We include whatever sockets are needed for Internet-protocol
+ * socket access on UN*X and Windows.
+ */
+#ifdef _WIN32
+ /* Need windef.h for defines used in winsock2.h under MingW32 */
+ #ifdef __MINGW32__
+ #include <windef.h>
+ #endif
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+
+ /*
+ * Winsock doesn't have this POSIX type; it's used for the
+ * tv_usec value of struct timeval.
+ */
+ typedef long suseconds_t;
+#else /* _WIN32 */
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h> /* for struct addrinfo/getaddrinfo() */
+ #include <netinet/in.h> /* for sockaddr_in, in BSD at least */
+ #include <arpa/inet.h>
+
+ /*!
+ * \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 /* _WIN32 */
+
+#endif /* lib_pcap_socket_h */
diff --git a/pcap/usb.h b/pcap/usb.h
new file mode 100644
index 0000000..e485ec8
--- /dev/null
+++ b/pcap/usb.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Basic USB data struct
+ * By Paolo Abeni <paolo.abeni@email.it>
+ */
+
+#ifndef lib_pcap_usb_h
+#define lib_pcap_usb_h
+
+#include <pcap/pcap-inttypes.h>
+
+/*
+ * possible transfer mode
+ */
+#define URB_TRANSFER_IN 0x80
+#define URB_ISOCHRONOUS 0x0
+#define URB_INTERRUPT 0x1
+#define URB_CONTROL 0x2
+#define URB_BULK 0x3
+
+/*
+ * possible event type
+ */
+#define URB_SUBMIT 'S'
+#define URB_COMPLETE 'C'
+#define URB_ERROR 'E'
+
+/*
+ * USB setup header as defined in USB specification.
+ * Appears at the front of each Control S-type packet in DLT_USB captures.
+ */
+typedef struct _usb_setup {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} pcap_usb_setup;
+
+/*
+ * Information from the URB for Isochronous transfers.
+ */
+typedef struct _iso_rec {
+ int32_t error_count;
+ int32_t numdesc;
+} iso_rec;
+
+/*
+ * Header prepended by linux kernel to each event.
+ * Appears at the front of each packet in DLT_USB_LINUX captures.
+ */
+typedef struct _usb_header {
+ uint64_t id;
+ uint8_t event_type;
+ uint8_t transfer_type;
+ uint8_t endpoint_number;
+ uint8_t device_address;
+ uint16_t bus_id;
+ char setup_flag;/*if !=0 the urb setup header is not present*/
+ char data_flag; /*if !=0 no urb data is present*/
+ int64_t ts_sec;
+ int32_t ts_usec;
+ int32_t status;
+ uint32_t urb_len;
+ uint32_t data_len; /* amount of urb data really present in this event*/
+ pcap_usb_setup setup;
+} pcap_usb_header;
+
+/*
+ * Header prepended by linux kernel to each event for the 2.6.31
+ * and later kernels; for the 2.6.21 through 2.6.30 kernels, the
+ * "iso_rec" information, and the fields starting with "interval"
+ * are zeroed-out padding fields.
+ *
+ * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures.
+ */
+typedef struct _usb_header_mmapped {
+ uint64_t id;
+ uint8_t event_type;
+ uint8_t transfer_type;
+ uint8_t endpoint_number;
+ uint8_t device_address;
+ uint16_t bus_id;
+ char setup_flag;/*if !=0 the urb setup header is not present*/
+ char data_flag; /*if !=0 no urb data is present*/
+ int64_t ts_sec;
+ int32_t ts_usec;
+ int32_t status;
+ uint32_t urb_len;
+ uint32_t data_len; /* amount of urb data really present in this event*/
+ union {
+ pcap_usb_setup setup;
+ iso_rec iso;
+ } s;
+ int32_t interval; /* for Interrupt and Isochronous events */
+ int32_t start_frame; /* for Isochronous events */
+ uint32_t xfer_flags; /* copy of URB's transfer flags */
+ uint32_t ndesc; /* number of isochronous descriptors */
+} pcap_usb_header_mmapped;
+
+/*
+ * Isochronous descriptors; for isochronous transfers there might be
+ * one or more of these at the beginning of the packet data. The
+ * number of descriptors is given by the "ndesc" field in the header;
+ * as indicated, in older kernels that don't put the descriptors at
+ * the beginning of the packet, that field is zeroed out, so that field
+ * can be trusted even in captures from older kernels.
+ */
+typedef struct _usb_isodesc {
+ int32_t status;
+ uint32_t offset;
+ uint32_t len;
+ uint8_t pad[4];
+} usb_isodesc;
+
+#endif
diff --git a/portability.h b/portability.h
new file mode 100644
index 0000000..84d0778
--- /dev/null
+++ b/portability.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+#include <stdarg.h> /* we declare varargs functions on some platforms */
+
+#include "pcap/funcattrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_STRLCAT
+ #define pcap_strlcat strlcat
+#else
+ #if defined(_MSC_VER) || defined(__MINGW32__)
+ /*
+ * strncat_s() is supported at least back to Visual
+ * Studio 2005; we require Visual Studio 2015 or later.
+ */
+ #define pcap_strlcat(x, y, z) \
+ strncat_s((x), (z), (y), _TRUNCATE)
+ #else
+ /*
+ * Define it ourselves.
+ */
+ extern size_t pcap_strlcat(char * restrict dst, const char * restrict src, size_t dstsize);
+ #endif
+#endif
+
+#ifdef HAVE_STRLCPY
+ #define pcap_strlcpy strlcpy
+#else
+ #if defined(_MSC_VER) || defined(__MINGW32__)
+ /*
+ * strncpy_s() is supported at least back to Visual
+ * Studio 2005; we require Visual Studio 2015 or later.
+ */
+ #define pcap_strlcpy(x, y, z) \
+ strncpy_s((x), (z), (y), _TRUNCATE)
+ #else
+ /*
+ * Define it ourselves.
+ */
+ extern size_t pcap_strlcpy(char * restrict dst, const char * restrict src, size_t dstsize);
+ #endif
+#endif
+
+#ifdef _MSC_VER
+ /*
+ * If <crtdbg.h> has been included, and _DEBUG is defined, and
+ * __STDC__ is zero, <crtdbg.h> will define strdup() to call
+ * _strdup_dbg(). So if it's already defined, don't redefine
+ * it.
+ */
+ #ifndef strdup
+ #define strdup _strdup
+ #endif
+#endif
+
+/*
+ * We want asprintf(), for some cases where we use it to construct
+ * dynamically-allocated variable-length strings; it's present on
+ * some, but not all, platforms.
+ */
+#ifdef HAVE_ASPRINTF
+#define pcap_asprintf asprintf
+#else
+extern int pcap_asprintf(char **, PCAP_FORMAT_STRING(const char *), ...)
+ PCAP_PRINTFLIKE(2, 3);
+#endif
+
+#ifdef HAVE_VASPRINTF
+#define pcap_vasprintf vasprintf
+#else
+extern int pcap_vasprintf(char **, const char *, va_list ap);
+#endif
+
+/* For Solaris before 11. */
+#ifndef timeradd
+#define timeradd(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+ if ((result)->tv_usec >= 1000000) { \
+ ++(result)->tv_sec; \
+ (result)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif /* timeradd */
+#ifndef timersub
+#define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* timersub */
+
+#ifdef HAVE_STRTOK_R
+ #define pcap_strtok_r strtok_r
+#else
+ #ifdef _WIN32
+ /*
+ * Microsoft gives it a different name.
+ */
+ #define pcap_strtok_r strtok_s
+ #else
+ /*
+ * Define it ourselves.
+ */
+ extern char *pcap_strtok_r(char *, const char *, char **);
+ #endif
+#endif /* HAVE_STRTOK_R */
+
+#ifdef _WIN32
+ #if !defined(__cplusplus)
+ #define inline __inline
+ #endif
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ppp.h b/ppp.h
new file mode 100644
index 0000000..d6e70c1
--- /dev/null
+++ b/ppp.h
@@ -0,0 +1,57 @@
+/*
+ * Point to Point Protocol (PPP) RFC1331
+ *
+ * Copyright 1989 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University. Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+#define PPP_ADDRESS 0xff /* The address byte value */
+#define PPP_CONTROL 0x03 /* The control byte value */
+
+#define PPP_PPPD_IN 0x00 /* non-standard for DLT_PPP_PPPD */
+#define PPP_PPPD_OUT 0x01 /* non-standard for DLT_PPP_PPPD */
+
+/* Protocol numbers */
+#define PPP_IP 0x0021 /* Raw IP */
+#define PPP_OSI 0x0023 /* OSI Network Layer */
+#define PPP_NS 0x0025 /* Xerox NS IDP */
+#define PPP_DECNET 0x0027 /* DECnet Phase IV */
+#define PPP_APPLE 0x0029 /* Appletalk */
+#define PPP_IPX 0x002b /* Novell IPX */
+#define PPP_VJC 0x002d /* Van Jacobson Compressed TCP/IP */
+#define PPP_VJNC 0x002f /* Van Jacobson Uncompressed TCP/IP */
+#define PPP_BRPDU 0x0031 /* Bridging PDU */
+#define PPP_STII 0x0033 /* Stream Protocol (ST-II) */
+#define PPP_VINES 0x0035 /* Banyan Vines */
+#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */
+
+#define PPP_HELLO 0x0201 /* 802.1d Hello Packets */
+#define PPP_LUXCOM 0x0231 /* Luxcom */
+#define PPP_SNS 0x0233 /* Sigma Network Systems */
+#define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */
+#define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */
+
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */
+#define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */
+#define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */
+#define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */
+#define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */
+#define PPP_STIICP 0x8033 /* Strean Protocol Control Protocol */
+#define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
+#define PPP_MPLSCP 0x8281 /* rfc 3022 */
+
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQM 0xc025 /* Link Quality Monitoring */
+#define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */
diff --git a/savefile.c b/savefile.c
new file mode 100644
index 0000000..d04b917
--- /dev/null
+++ b/savefile.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * savefile.c - supports offline use of tcpdump
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ * Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* for INT_MAX */
+
+#include "pcap-int.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcap.h"
+#include "sf-pcapng.h"
+#include "pcap-common.h"
+#include "charconv.h"
+
+#ifdef _WIN32
+/*
+ * This isn't exported on Windows, because it would only work if both
+ * WinPcap/Npcap and the code using it were to use the Universal CRT; otherwise,
+ * a FILE structure in WinPcap/Npcap 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 it as a macro that wraps the hopen version,
+ * with the wrapper calling _fileno() and _get_osfhandle() themselves,
+ * so that it 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 *);
+#endif
+
+/*
+ * Setting O_BINARY on DOS/Windows is a bit tricky
+ */
+#if defined(_WIN32)
+ #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
+#elif defined(MSDOS)
+ #if defined(__HIGHC__)
+ #define SET_BINMODE(f) setmode(f, O_BINARY)
+ #else
+ #define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
+ #endif
+#endif
+
+static int
+sf_getnonblock(pcap_t *p _U_)
+{
+ /*
+ * This is a savefile, not a live capture file, so never say
+ * it's in non-blocking mode.
+ */
+ return (0);
+}
+
+static int
+sf_setnonblock(pcap_t *p, int nonblock _U_)
+{
+ /*
+ * This is a savefile, not a live capture file, so reject
+ * requests to put it in non-blocking mode. (If it's a
+ * pipe, it could be put in non-blocking mode, but that
+ * would significantly complicate the code to read packets,
+ * as it would have to handle reading partial packets and
+ * keeping the state of the read.)
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Savefiles cannot be put into non-blocking mode");
+ return (-1);
+}
+
+static int
+sf_stats(pcap_t *p, struct pcap_stat *ps _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from savefiles");
+ return (-1);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+sf_stats_ex(pcap_t *p, int *size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from savefiles");
+ return (NULL);
+}
+
+static int
+sf_setbuff(pcap_t *p, int dim _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The kernel buffer size cannot be set while reading from a file");
+ return (-1);
+}
+
+static int
+sf_setmode(pcap_t *p, int mode _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "impossible to set mode while reading from a file");
+ return (-1);
+}
+
+static int
+sf_setmintocopy(pcap_t *p, int size _U_)
+{
+ 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)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_)
+{
+ 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_)
+{
+ 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 _U_, int sync _U_)
+{
+ pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
+ PCAP_ERRBUF_SIZE);
+ return (0);
+}
+
+static int
+sf_setuserbuffer(pcap_t *p, int size _U_)
+{
+ 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 _U_, int maxsize _U_, int maxpacks _U_)
+{
+ 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 _U_)
+{
+ 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 _U_)
+{
+ return (NULL);
+}
+#endif
+
+static int
+sf_inject(pcap_t *p, const void *buf _U_, int size _U_)
+{
+ pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
+ PCAP_ERRBUF_SIZE);
+ return (-1);
+}
+
+/*
+ * Set direction flag: Which packets do we accept on a forwarding
+ * single device? IN, OUT or both?
+ */
+static int
+sf_setdirection(pcap_t *p, pcap_direction_t d _U_)
+{
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "Setting direction is not supported on savefiles");
+ return (-1);
+}
+
+void
+sf_cleanup(pcap_t *p)
+{
+ if (p->rfile != stdin)
+ (void)fclose(p->rfile);
+ if (p->buffer != NULL)
+ free(p->buffer);
+ pcap_freecode(&p->fcode);
+}
+
+#ifdef _WIN32
+/*
+ * Wrapper for fopen() and _wfopen().
+ *
+ * If we're in UTF-8 mode, map the pathname from UTF-8 to UTF-16LE and
+ * call _wfopen().
+ *
+ * If we're not, just use fopen(); that'll treat it as being in the
+ * local code page.
+ */
+FILE *
+charset_fopen(const char *path, const char *mode)
+{
+ wchar_t *utf16_path;
+#define MAX_MODE_LEN 16
+ wchar_t utf16_mode[MAX_MODE_LEN+1];
+ int i;
+ char c;
+ FILE *fp;
+ int save_errno;
+
+ if (pcap_utf_8_mode) {
+ /*
+ * Map from UTF-8 to UTF-16LE.
+ * Fail if there are invalid characters in the input
+ * string, rather than converting them to REPLACEMENT
+ * CHARACTER; the latter is appropriate for strings
+ * to be displayed to the user, but for file names
+ * you just want the attempt to open the file to fail.
+ */
+ utf16_path = cp_to_utf_16le(CP_UTF8, path,
+ MB_ERR_INVALID_CHARS);
+ if (utf16_path == NULL) {
+ /*
+ * Error. Assume errno has been set.
+ *
+ * XXX - what about Windows errors?
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now convert the mode to UTF-16LE as well.
+ * We assume the mode is ASCII, and that
+ * it's short, so that's easy.
+ */
+ for (i = 0; (c = *mode) != '\0'; i++, mode++) {
+ if (c > 0x7F) {
+ /* Not an ASCII character; fail with EINVAL. */
+ free(utf16_path);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (i >= MAX_MODE_LEN) {
+ /* The mode string is longer than we allow. */
+ free(utf16_path);
+ errno = EINVAL;
+ return (NULL);
+ }
+ utf16_mode[i] = c;
+ }
+ utf16_mode[i] = '\0';
+
+ /*
+ * OK, we have UTF-16LE strings; hand them to
+ * _wfopen().
+ */
+ fp = _wfopen(utf16_path, utf16_mode);
+
+ /*
+ * Make sure freeing the UTF-16LE string doesn't
+ * overwrite the error code we got from _wfopen().
+ */
+ save_errno = errno;
+ free(utf16_path);
+ errno = save_errno;
+
+ return (fp);
+ } else {
+ /*
+ * This takes strings in the local code page as an
+ * argument.
+ */
+ return (fopen(path, mode));
+ }
+}
+#endif
+
+pcap_t *
+pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
+ char *errbuf)
+{
+ FILE *fp;
+ pcap_t *p;
+
+ if (fname == NULL) {
+ 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 (stdin == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The standard input is not open");
+ return (NULL);
+ }
+#if defined(_WIN32) || defined(MSDOS)
+ /*
+ * We're reading from the standard input, so put it in binary
+ * mode, as savefiles are binary files.
+ */
+ SET_BINMODE(fp);
+#endif
+ }
+ else {
+ /*
+ * Use charset_fopen(); on Windows, it tests whether we're
+ * in "local code page" or "UTF-8" mode, and treats the
+ * pathname appropriately, and on other platforms, it just
+ * wraps fopen().
+ *
+ * "b" is supported as of C90, so *all* UN*Xes should
+ * support it, even though it does nothing. For MS-DOS,
+ * we again need it.
+ */
+ fp = charset_fopen(fname, "rb");
+ if (fp == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "%s", fname);
+ return (NULL);
+ }
+ }
+ p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
+ if (p == NULL) {
+ if (fp != stdin)
+ fclose(fp);
+ }
+ return (p);
+}
+
+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 )
+ {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "_open_osfhandle");
+ return NULL;
+ }
+
+ file = _fdopen(fd, "rb");
+ if ( file == NULL )
+ {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "_fdopen");
+ _close(fd);
+ return NULL;
+ }
+
+ 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
+
+/*
+ * Given a link-layer header type and snapshot length, return a
+ * snapshot length to use when reading the file; it's guaranteed
+ * to be > 0 and <= INT_MAX.
+ *
+ * XXX - the only reason why we limit it to <= INT_MAX is so that
+ * it fits in p->snapshot, and the only reason that p->snapshot is
+ * signed is that pcap_snapshot() returns an int, not an unsigned int.
+ */
+bpf_u_int32
+pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen)
+{
+ if (snaplen == 0 || snaplen > INT_MAX) {
+ /*
+ * Bogus snapshot length; use the maximum for this
+ * link-layer type as a fallback.
+ *
+ * XXX - we don't clamp snapshot lengths that are
+ * <= INT_MAX but > max_snaplen_for_dlt(linktype),
+ * so a capture file could cause us to allocate
+ * a Really Big Buffer.
+ */
+ snaplen = max_snaplen_for_dlt(linktype);
+ }
+ return snaplen;
+}
+
+static pcap_t *(*check_headers[])(const uint8_t *, 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
+static
+#endif
+pcap_t *
+pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
+ char *errbuf)
+{
+ register pcap_t *p;
+ uint8_t magic[4];
+ size_t amt_read;
+ u_int i;
+ int err;
+
+ /*
+ * Fail if we were passed a NULL fp.
+ *
+ * That shouldn't happen if we're opening with a path name, but
+ * it could happen if buggy code is opening with a FILE * and
+ * didn't bother to make sure the FILE * isn't null.
+ */
+ if (fp == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Null FILE * pointer provided to savefile open routine");
+ return (NULL);
+ }
+
+ /*
+ * Read the first 4 bytes of the file; the network analyzer dump
+ * file formats we support (pcap and pcapng), and several other
+ * formats we might support in the future (such as snoop, DOS and
+ * Windows Sniffer, and Microsoft Network Monitor) all have magic
+ * numbers that are unique in their first 4 bytes.
+ */
+ amt_read = fread(&magic, 1, sizeof(magic), fp);
+ if (amt_read != sizeof(magic)) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu file header bytes, only got %zu",
+ sizeof(magic), amt_read);
+ }
+ return (NULL);
+ }
+
+ /*
+ * Try all file types.
+ */
+ for (i = 0; i < N_FILE_TYPES; i++) {
+ 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.
+ */
+ return (NULL);
+ }
+ }
+
+ /*
+ * Well, who knows what this mess is....
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
+ return (NULL);
+
+found:
+ p->rfile = fp;
+
+ /* Padding only needed for live capture fcode */
+ p->fddipad = 0;
+
+#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.
+ *
+ * You can't do "select()" on anything other than sockets in
+ * Windows, so, on Win32 systems, we don't have "selectable_fd".
+ */
+ p->selectable_fd = fileno(fp);
+#endif
+
+ p->read_op = pcap_offline_read;
+ p->inject_op = sf_inject;
+ p->setfilter_op = install_bpf_program;
+ p->setdirection_op = sf_setdirection;
+ p->set_datalink_op = NULL; /* we don't support munging link-layer headers */
+ p->getnonblock_op = sf_getnonblock;
+ p->setnonblock_op = sf_setnonblock;
+ p->stats_op = sf_stats;
+#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
+
+ /*
+ * For offline captures, the standard one-shot callback can
+ * be used for pcap_next()/pcap_next_ex().
+ */
+ p->oneshot_callback = pcap_oneshot;
+
+ /*
+ * Default breakloop operation.
+ */
+ p->breakloop_op = pcap_breakloop_common;
+
+ /*
+ * Savefiles never require special BPF code generation.
+ */
+ p->bpf_codegen_flags = 0;
+
+ p->activated = 1;
+
+ return (p);
+}
+
+/*
+ * This isn't needed on Windows; we #define pcap_fopen_offline() as
+ * a wrapper around pcap_hopen_offline(), and we don't call it from
+ * inside this file, so it's unused.
+ */
+#ifndef _WIN32
+pcap_t *
+pcap_fopen_offline(FILE *fp, char *errbuf)
+{
+ return (pcap_fopen_offline_with_tstamp_precision(fp,
+ PCAP_TSTAMP_PRECISION_MICRO, errbuf));
+}
+#endif
+
+/*
+ * Read packets from a capture file, and call the callback for each
+ * packet.
+ * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
+ */
+int
+pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ struct bpf_insn *fcode;
+ int status = 0;
+ int n = 0;
+ u_char *data;
+
+ while (status == 0) {
+ struct pcap_pkthdr h;
+
+ /*
+ * Has "pcap_breakloop()" been called?
+ * If so, return immediately - if we haven't read any
+ * packets, clear the flag and return -2 to indicate
+ * that we were told to break out of the loop, otherwise
+ * leave the flag set, so that the *next* call will break
+ * out of the loop without having read any packets, and
+ * return the number of packets we've processed so far.
+ */
+ if (p->break_loop) {
+ if (n == 0) {
+ p->break_loop = 0;
+ return (-2);
+ } else
+ return (n);
+ }
+
+ status = p->next_packet_op(p, &h, &data);
+ if (status) {
+ if (status == 1)
+ return (0);
+ return (status);
+ }
+
+ if ((fcode = p->fcode.bf_insns) == NULL ||
+ pcap_filter(fcode, data, h.len, h.caplen)) {
+ (*callback)(user, &h, data);
+ if (++n >= cnt && cnt > 0)
+ break;
+ }
+ }
+ /*XXX this breaks semantics tcpslice expects */
+ return (n);
+}
diff --git a/scanner.l b/scanner.l
new file mode 100644
index 0000000..06b9acc
--- /dev/null
+++ b/scanner.l
@@ -0,0 +1,596 @@
+%top {
+/* Must come first for _LARGE_FILE_API on AIX. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * Must come first to avoid warnings on Windows.
+ *
+ * Flex-generated scanners may only include <inttypes.h> if __STDC_VERSION__
+ * is defined with a value >= 199901, meaning "full C99", and MSVC may not
+ * define it with that value, because it isn't 100% C99-compliant, even
+ * though it has an <inttypes.h> capable of defining everything the Flex
+ * scanner needs.
+ *
+ * We, however, will include it if we know we have an MSVC version that has
+ * it; this means that we may define the INTn_MAX and UINTn_MAX values in
+ * scanner.c, and then include <stdint.h>, which may define them differently
+ * (same value, but different string of characters), causing compiler warnings.
+ *
+ * If we include it here, and they're defined, that'll prevent scanner.c
+ * from defining them. So we include <pcap/pcap-inttypes.h>, to get
+ * <inttypes.h> if we have it.
+ */
+#include <pcap/pcap-inttypes.h>
+
+#include "diag-control.h"
+}
+
+/*
+ * 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
+ * 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.
+ */
+
+#include <string.h>
+
+#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 <winsock2.h>
+#include <ws2tcpip.h>
+/*
+ * To quote the MSDN page for getaddrinfo() at
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
+ *
+ * "Support for getaddrinfo on Windows 2000 and older versions
+ * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
+ * later. To execute an application that uses this function on earlier
+ * versions of Windows, then you need to include the Ws2tcpip.h and
+ * Wspiapi.h files. When the Wspiapi.h include file is added, the
+ * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
+ * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
+ * function is implemented in such a way that if the Ws2_32.dll or the
+ * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
+ * Preview for Windows 2000) does not include getaddrinfo, then a
+ * version of getaddrinfo is implemented inline based on code in the
+ * Wspiapi.h header file. This inline code will be used on older Windows
+ * platforms that do not natively support the getaddrinfo function."
+ *
+ * We use getaddrinfo(), so we include Wspiapi.h here.
+ */
+#include <wspiapi.h>
+#else /* _WIN32 */
+#include <sys/socket.h> /* for "struct sockaddr" in "struct addrinfo" */
+#include <netdb.h> /* for "struct addrinfo" */
+#endif /* _WIN32 */
+
+/* Workaround for AIX 4.3 */
+#if !defined(AI_NUMERICHOST)
+#define AI_NUMERICHOST 0x04
+#endif
+
+#endif /*INET6*/
+
+#include <pcap/namedb.h>
+#include "grammar.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+static int stou(char *, YYSTYPE *, compiler_state_t *);
+
+/*
+ * Disable diagnostics in the code generated by Flex.
+ */
+DIAG_OFF_FLEX
+
+%}
+
+N ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
+B ([0-9A-Fa-f][0-9A-Fa-f]?)
+B2 ([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])
+W ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?)
+
+%a 18400
+%o 21500
+%e 7600
+%k 4550
+%p 27600
+%n 2000
+
+V680 {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W}
+
+V670 ::{W}:{W}:{W}:{W}:{W}:{W}:{W}
+V671 {W}::{W}:{W}:{W}:{W}:{W}:{W}
+V672 {W}:{W}::{W}:{W}:{W}:{W}:{W}
+V673 {W}:{W}:{W}::{W}:{W}:{W}:{W}
+V674 {W}:{W}:{W}:{W}::{W}:{W}:{W}
+V675 {W}:{W}:{W}:{W}:{W}::{W}:{W}
+V676 {W}:{W}:{W}:{W}:{W}:{W}::{W}
+V677 {W}:{W}:{W}:{W}:{W}:{W}:{W}::
+
+V660 ::{W}:{W}:{W}:{W}:{W}:{W}
+V661 {W}::{W}:{W}:{W}:{W}:{W}
+V662 {W}:{W}::{W}:{W}:{W}:{W}
+V663 {W}:{W}:{W}::{W}:{W}:{W}
+V664 {W}:{W}:{W}:{W}::{W}:{W}
+V665 {W}:{W}:{W}:{W}:{W}::{W}
+V666 {W}:{W}:{W}:{W}:{W}:{W}::
+
+V650 ::{W}:{W}:{W}:{W}:{W}
+V651 {W}::{W}:{W}:{W}:{W}
+V652 {W}:{W}::{W}:{W}:{W}
+V653 {W}:{W}:{W}::{W}:{W}
+V654 {W}:{W}:{W}:{W}::{W}
+V655 {W}:{W}:{W}:{W}:{W}::
+
+V640 ::{W}:{W}:{W}:{W}
+V641 {W}::{W}:{W}:{W}
+V642 {W}:{W}::{W}:{W}
+V643 {W}:{W}:{W}::{W}
+V644 {W}:{W}:{W}:{W}::
+
+V630 ::{W}:{W}:{W}
+V631 {W}::{W}:{W}
+V632 {W}:{W}::{W}
+V633 {W}:{W}:{W}::
+
+V620 ::{W}:{W}
+V621 {W}::{W}
+V622 {W}:{W}::
+
+V610 ::{W}
+V611 {W}::
+
+V600 ::
+
+V6604 {W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+
+V6504 ::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6514 {W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6524 {W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6534 {W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6544 {W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6554 {W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6404 ::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6414 {W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6424 {W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6434 {W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6444 {W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6304 ::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6314 {W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6324 {W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
+V6334 {W}:{W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6204 ::{W}:{W}:{N}\.{N}\.{N}\.{N}
+V6214 {W}::{W}:{N}\.{N}\.{N}\.{N}
+V6224 {W}:{W}::{N}\.{N}\.{N}\.{N}
+
+V6104 ::{W}:{N}\.{N}\.{N}\.{N}
+V6114 {W}::{N}\.{N}\.{N}\.{N}
+
+V6004 ::{N}\.{N}\.{N}\.{N}
+
+
+V6 ({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004})
+
+MAC ({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3})
+
+
+
+%%
+dst return DST;
+src return SRC;
+
+link|ether|ppp|slip return LINK;
+fddi|tr|wlan return LINK;
+arp return ARP;
+rarp return RARP;
+ip return IP;
+sctp return SCTP;
+tcp return TCP;
+udp return UDP;
+icmp return ICMP;
+igmp return IGMP;
+igrp return IGRP;
+pim return PIM;
+vrrp return VRRP;
+carp return CARP;
+radio return RADIO;
+
+ip6 return IPV6;
+icmp6 return ICMPV6;
+ah return AH;
+esp return ESP;
+
+atalk return ATALK;
+aarp return AARP;
+decnet return DECNET;
+lat return LAT;
+sca return SCA;
+moprc return MOPRC;
+mopdl return MOPDL;
+
+iso return ISO;
+esis return ESIS;
+es-is return ESIS;
+isis return ISIS;
+is-is return ISIS;
+l1 return L1;
+l2 return L2;
+iih return IIH;
+lsp return LSP;
+snp return SNP;
+csnp return CSNP;
+psnp return PSNP;
+
+clnp return CLNP;
+
+stp return STP;
+
+ipx return IPX;
+
+netbeui return NETBEUI;
+
+host return HOST;
+net return NET;
+mask return NETMASK;
+port return PORT;
+portrange return PORTRANGE;
+proto return PROTO;
+protochain return PROTOCHAIN;
+
+gateway return GATEWAY;
+
+type return TYPE;
+subtype return SUBTYPE;
+direction|dir return DIR;
+address1|addr1 return ADDR1;
+address2|addr2 return ADDR2;
+address3|addr3 return ADDR3;
+address4|addr4 return ADDR4;
+ra return RA;
+ta return TA;
+
+less return LESS;
+greater return GREATER;
+byte return CBYTE;
+broadcast return TK_BROADCAST;
+multicast return TK_MULTICAST;
+
+and|"&&" return AND;
+or|"||" return OR;
+not return '!';
+
+len|length return LEN;
+inbound return INBOUND;
+outbound return OUTBOUND;
+
+ifindex return IFINDEX;
+
+vlan return VLAN;
+mpls return MPLS;
+pppoed return PPPOED;
+pppoes return PPPOES;
+geneve return GENEVE;
+
+lane return LANE;
+llc return LLC;
+metac return METAC;
+bcc return BCC;
+oam return OAM;
+oamf4 return OAMF4;
+oamf4ec return OAMF4EC;
+oamf4sc return OAMF4SC;
+sc return SC;
+ilmic return ILMIC;
+vpi return VPI;
+vci return VCI;
+connectmsg return CONNECTMSG;
+metaconnect return METACONNECT;
+
+on|ifname return PF_IFNAME;
+rset|ruleset return PF_RSET;
+rnr|rulenum return PF_RNR;
+srnr|subrulenum return PF_SRNR;
+reason return PF_REASON;
+action return PF_ACTION;
+
+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 GEQ;
+"<=" return LEQ;
+"!=" return NEQ;
+"==" return '=';
+"<<" return LSH;
+">>" return RSH;
+${B} { yylval->s = sdup(yyextra, yytext); return AID; }
+{MAC} { yylval->s = sdup(yyextra, yytext); return EID; }
+{N} { return stou(yytext, yylval, yyextra); }
+({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
+ yylval->s = sdup(yyextra, (char *)yytext); return HID; }
+{V6} {
+#ifdef INET6
+ struct addrinfo hints, *res;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(yytext, NULL, &hints, &res)) {
+ bpf_set_error(yyextra, "bogus IPv6 address %s", yytext);
+ yylval->s = NULL;
+ } else {
+ freeaddrinfo(res);
+ yylval->s = sdup(yyextra, (char *)yytext);
+ }
+#else
+ bpf_set_error(yyextra, "IPv6 address %s not supported", yytext);
+ yylval->s = NULL;
+#endif /*INET6*/
+ return HID6;
+ }
+{B}:+({B}:+)+ { bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; }
+icmptype { yylval->h = 0; return NUM; }
+icmpcode { yylval->h = 1; return NUM; }
+icmp-echoreply { yylval->h = 0; return NUM; }
+icmp-unreach { yylval->h = 3; return NUM; }
+icmp-sourcequench { yylval->h = 4; return NUM; }
+icmp-redirect { yylval->h = 5; return NUM; }
+icmp-echo { yylval->h = 8; return NUM; }
+icmp-routeradvert { yylval->h = 9; return NUM; }
+icmp-routersolicit { yylval->h = 10; return NUM; }
+icmp-timxceed { yylval->h = 11; return NUM; }
+icmp-paramprob { yylval->h = 12; return NUM; }
+icmp-tstamp { yylval->h = 13; return NUM; }
+icmp-tstampreply { yylval->h = 14; return NUM; }
+icmp-ireq { yylval->h = 15; return NUM; }
+icmp-ireqreply { yylval->h = 16; return NUM; }
+icmp-maskreq { yylval->h = 17; return NUM; }
+icmp-maskreply { yylval->h = 18; return NUM; }
+
+icmp6type { yylval->h = 0; return NUM; }
+icmp6code { yylval->h = 1; return NUM; }
+
+icmp6-destinationunreach { yylval->h = 1; return NUM; }
+icmp6-packettoobig { yylval->h = 2; return NUM; }
+icmp6-timeexceeded { yylval->h = 3; return NUM; }
+icmp6-parameterproblem { yylval->h = 4; return NUM; }
+icmp6-echo { yylval->h = 128; return NUM; }
+icmp6-echoreply { yylval->h = 129; return NUM; }
+icmp6-multicastlistenerquery { yylval->h = 130; return NUM; }
+icmp6-multicastlistenerreportv1 { yylval->h = 131; return NUM; }
+icmp6-multicastlistenerdone { yylval->h = 132; return NUM; }
+icmp6-routersolicit { yylval->h = 133; return NUM; }
+icmp6-routeradvert { yylval->h = 134; return NUM; }
+icmp6-neighborsolicit { yylval->h = 135; return NUM; }
+icmp6-neighboradvert { yylval->h = 136; return NUM; }
+icmp6-redirect { yylval->h = 137; return NUM; }
+icmp6-routerrenum { yylval->h = 138; return NUM; }
+icmp6-nodeinformationquery { yylval->h = 139; return NUM; }
+icmp6-nodeinformationresponse { yylval->h = 140; return NUM; }
+icmp6-ineighbordiscoverysolicit { yylval->h = 141; return NUM; }
+icmp6-ineighbordiscoveryadvert { yylval->h = 142; return NUM; }
+icmp6-multicastlistenerreportv2 { yylval->h = 143; return NUM; }
+icmp6-homeagentdiscoveryrequest { yylval->h = 144; return NUM; }
+icmp6-homeagentdiscoveryreply { yylval->h = 145; return NUM; }
+icmp6-mobileprefixsolicit { yylval->h = 146; return NUM; }
+icmp6-mobileprefixadvert { yylval->h = 147; return NUM; }
+icmp6-certpathsolicit { yylval->h = 148; return NUM; }
+icmp6-certpathadvert { yylval->h = 149; return NUM; }
+icmp6-multicastrouteradvert { yylval->h = 151; return NUM; }
+icmp6-multicastroutersolicit { yylval->h = 152; return NUM; }
+icmp6-multicastrouterterm { yylval->h = 153; return NUM; }
+
+tcpflags { yylval->h = 13; return NUM; }
+tcp-fin { yylval->h = 0x01; return NUM; }
+tcp-syn { yylval->h = 0x02; return NUM; }
+tcp-rst { yylval->h = 0x04; return NUM; }
+tcp-push { yylval->h = 0x08; return NUM; }
+tcp-ack { yylval->h = 0x10; return NUM; }
+tcp-urg { yylval->h = 0x20; return NUM; }
+tcp-ece { yylval->h = 0x40; return NUM; }
+tcp-cwr { yylval->h = 0x80; return NUM; }
+[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? {
+ yylval->s = sdup(yyextra, (char *)yytext); return ID; }
+"\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; }
+. { return LEX_ERROR; }
+%%
+
+/*
+ * Turn diagnostics back on, so we check the code that we've written.
+ */
+DIAG_ON_FLEX
+
+/*
+ * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ *
+ * On success, sets yylval->h to the value and returns NUM.
+ * On failure, sets the BPF error string and returns LEX_ERROR, to force
+ * the parse to stop.
+ */
+static int
+stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+{
+ bpf_u_int32 n = 0;
+ unsigned int digit;
+ char *s = yytext_arg;
+
+ /*
+ * yytext_arg is guaranteed either to be a string of decimal digits
+ * or 0[xX] followed by a string of hex digits.
+ */
+ if (*s == '0') {
+ if (s[1] == 'x' || s[1] == 'X') {
+ /*
+ * Begins with 0x or 0X, so hex.
+ * Guaranteed to be all hex digits following the
+ * prefix, so anything that's not 0-9 or a-f is
+ * A-F.
+ */
+ s += 2; /* skip the prefix */
+ while ((digit = *s++) != '\0') {
+ if (digit >= '0' && digit <= '9')
+ digit = digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ digit = digit - 'a' + 10;
+ else
+ digit = digit - 'A' + 10;
+
+ /*
+ * Check for overflow.
+ */
+ if (n > 0xFFFFFFFU) {
+ /*
+ * We have more than 28 bits of
+ * number, and are about to
+ * add 4 more; that won't fit
+ * in 32 bits.
+ */
+ bpf_set_error(yyextra_arg,
+ "number %s overflows 32 bits",
+ yytext_arg);
+ return LEX_ERROR;
+ }
+ n = (n << 4) + digit;
+ }
+ } else {
+ /*
+ * Begins with 0, but not 0x or 0X, so octal.
+ * Guaranteed to be all *decimal* digits following
+ * the prefix, so we need to catch 8 and 9 and
+ * report an error.
+ */
+ s += 1;
+ while ((digit = *s++) != '\0') {
+ if (digit >= '0' && digit <= '7')
+ digit = digit - '0';
+ else {
+ bpf_set_error(yyextra_arg,
+ "number %s contains non-octal digit",
+ yytext_arg);
+ return LEX_ERROR;
+ }
+ if (n > 03777777777U) {
+ /*
+ * We have more than 29 bits of
+ * number, and are about to add
+ * 3 more; that won't fit in
+ * 32 bits.
+ */
+ bpf_set_error(yyextra_arg,
+ "number %s overflows 32 bits",
+ yytext_arg);
+ return LEX_ERROR;
+ }
+ n = (n << 3) + digit;
+ }
+ }
+ } else {
+ /*
+ * Decimal.
+ */
+ while ((digit = *s++) != '\0') {
+ digit = digit - '0';
+#define CUTOFF_DEC (0xFFFFFFFFU / 10U)
+#define CUTLIM_DEC (0xFFFFFFFFU % 10U)
+ if (n > CUTOFF_DEC ||
+ (n == CUTOFF_DEC && digit > CUTLIM_DEC)) {
+ bpf_set_error(yyextra_arg,
+ "number %s overflows 32 bits",
+ yytext_arg);
+ return LEX_ERROR;
+ }
+ n = (n * 10) + digit;
+ }
+ }
+
+ yylval_arg->h = n;
+ return NUM;
+}
diff --git a/sf-pcap.c b/sf-pcap.c
new file mode 100644
index 0000000..d8443e9
--- /dev/null
+++ b/sf-pcap.c
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcap.c - libpcap-file-format-specific code from savefile.c
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ * Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif /* _WIN32 */
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* for INT_MAX */
+
+#include "pcap-int.h"
+
+#include "pcap-common.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcap.h"
+
+/*
+ * Setting O_BINARY on DOS/Windows is a bit tricky
+ */
+#if defined(_WIN32)
+ #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
+#elif defined(MSDOS)
+ #if defined(__HIGHC__)
+ #define SET_BINMODE(f) setmode(f, O_BINARY)
+ #else
+ #define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
+ #endif
+#endif
+
+/*
+ * Standard libpcap format.
+ */
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+/*
+ * Alexey Kuznetzov's modified libpcap format.
+ */
+#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34
+
+/*
+ * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
+ * for another modified format.
+ */
+#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd
+
+/*
+ * Navtel Communcations' format, with nanosecond timestamps,
+ * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
+ */
+#define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d
+
+/*
+ * Normal libpcap format, except for seconds/nanoseconds timestamps,
+ * as per a request by Ulf Lamping <ulf.lamping@web.de>
+ */
+#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d
+
+/*
+ * Mechanism for storing information about a capture in the upper
+ * 6 bits of a linktype value in a capture file.
+ *
+ * LT_LINKTYPE_EXT(x) extracts the additional information.
+ *
+ * The rest of the bits are for a value describing the link-layer
+ * value. LT_LINKTYPE(x) extracts that value.
+ */
+#define LT_LINKTYPE(x) ((x) & 0x03FFFFFF)
+#define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000)
+
+static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
+
+#ifdef _WIN32
+/*
+ * This isn't exported on Windows, because it would only work if both
+ * libpcap and the code using it were using the same C runtime; otherwise they
+ * would be using different definitions of a FILE structure.
+ *
+ * Instead we define this as a macro in pcap/pcap.h that wraps the hopen
+ * version that we do export, passing it a raw OS HANDLE, as defined by the
+ * Win32 / Win64 ABI, obtained from the _fileno() and _get_osfhandle()
+ * functions of the appropriate CRT.
+ */
+static pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *f);
+#endif /* _WIN32 */
+
+/*
+ * 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.
+ */
+pcap_t *
+pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
+ int *err)
+{
+ bpf_u_int32 magic_int;
+ 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.
+ */
+ memcpy(&magic_int, magic, sizeof(magic_int));
+ if (magic_int != TCPDUMP_MAGIC &&
+ magic_int != KUZNETZOV_TCPDUMP_MAGIC &&
+ magic_int != NSEC_TCPDUMP_MAGIC) {
+ magic_int = SWAPLONG(magic_int);
+ if (magic_int != TCPDUMP_MAGIC &&
+ magic_int != KUZNETZOV_TCPDUMP_MAGIC &&
+ magic_int != NSEC_TCPDUMP_MAGIC)
+ return (NULL); /* nope */
+ swapped = 1;
+ }
+
+ /*
+ * They are. Put the magic number in the header, and read
+ * the rest of the header.
+ */
+ hdr.magic = magic_int;
+ amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
+ sizeof(hdr) - sizeof(hdr.magic), fp);
+ if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu file header bytes, only got %zu",
+ sizeof(hdr), amt_read);
+ }
+ *err = 1;
+ return (NULL);
+ }
+
+ /*
+ * If it's a byte-swapped capture file, byte-swap the header.
+ */
+ if (swapped) {
+ hdr.version_major = SWAPSHORT(hdr.version_major);
+ hdr.version_minor = SWAPSHORT(hdr.version_minor);
+ hdr.thiszone = SWAPLONG(hdr.thiszone);
+ hdr.sigfigs = SWAPLONG(hdr.sigfigs);
+ hdr.snaplen = SWAPLONG(hdr.snaplen);
+ hdr.linktype = SWAPLONG(hdr.linktype);
+ }
+
+ if (hdr.version_major < PCAP_VERSION_MAJOR) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "archaic pcap savefile format");
+ *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))) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unsupported pcap savefile version %u.%u",
+ hdr.version_major, hdr.version_minor);
+ *err = 1;
+ return NULL;
+ }
+
+ /*
+ * OK, this is a good pcap file.
+ * Allocate a pcap_t for it.
+ */
+ p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf);
+ if (p == NULL) {
+ /* Allocation failed. */
+ *err = 1;
+ return (NULL);
+ }
+ p->swapped = swapped;
+ p->version_major = hdr.version_major;
+ p->version_minor = hdr.version_minor;
+ p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
+ p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
+ p->snapshot = pcap_adjust_snapshot(p->linktype, hdr.snaplen);
+
+ 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_int == 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_int == NSEC_TCPDUMP_MAGIC) {
+ /*
+ * The file has nanoseconds, the
+ * user wants nanoseconds; nothing to do.
+ */
+ ps->scale_type = PASS_THROUGH;
+ } else {
+ /*
+ * The file has microseconds, the user
+ * wants nanoseconds; scale the
+ * precision up.
+ */
+ ps->scale_type = SCALE_UP;
+ }
+ break;
+
+ default:
+ 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,
+ * in order to match the bpf header layout. But unfortunately
+ * some files were written with version 2.3 in their headers
+ * but without the interchanged fields.
+ *
+ * In addition, DG/UX tcpdump writes out files with a version
+ * number of 543.0, and with the caplen and len fields in the
+ * pre-2.3 order.
+ */
+ switch (hdr.version_major) {
+
+ case 2:
+ if (hdr.version_minor < 3)
+ ps->lengths_swapped = SWAPPED;
+ else if (hdr.version_minor == 3)
+ ps->lengths_swapped = MAYBE_SWAPPED;
+ else
+ ps->lengths_swapped = NOT_SWAPPED;
+ break;
+
+ case 543:
+ ps->lengths_swapped = SWAPPED;
+ break;
+
+ default:
+ ps->lengths_swapped = NOT_SWAPPED;
+ break;
+ }
+
+ if (magic_int == KUZNETZOV_TCPDUMP_MAGIC) {
+ /*
+ * XXX - the patch that's in some versions of libpcap
+ * changes the packet header but not the magic number,
+ * and some other versions with this magic number have
+ * some extra debugging information in the packet header;
+ * we'd have to use some hacks^H^H^H^H^Hheuristics to
+ * detect those variants.
+ *
+ * Ethereal does that, but it does so by trying to read
+ * the first two packets of the file with each of the
+ * record header formats. That currently means it seeks
+ * backwards and retries the reads, which doesn't work
+ * on pipes. We want to be able to read from a pipe, so
+ * that strategy won't work; we'd have to buffer some
+ * data ourselves and read from that buffer in order to
+ * make that work.
+ */
+ ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
+
+ if (p->linktype == DLT_EN10MB) {
+ /*
+ * This capture might have been done in raw mode
+ * or cooked mode.
+ *
+ * If it was done in cooked mode, p->snapshot was
+ * passed to recvfrom() as the buffer size, meaning
+ * that the most packet data that would be copied
+ * would be p->snapshot. However, a faked Ethernet
+ * header would then have been added to it, so the
+ * most data that would be in a packet in the file
+ * would be p->snapshot + 14.
+ *
+ * We can't easily tell whether the capture was done
+ * in raw mode or cooked mode, so we'll assume it was
+ * cooked mode, and add 14 to the snapshot length.
+ * That means that, for a raw capture, the snapshot
+ * length will be misleading if you use it to figure
+ * out why a capture doesn't have all the packet data,
+ * but there's not much we can do to avoid that.
+ *
+ * But don't grow the snapshot length past the
+ * maximum value of an int.
+ */
+ if (p->snapshot <= INT_MAX - 14)
+ p->snapshot += 14;
+ else
+ p->snapshot = INT_MAX;
+ }
+ } else
+ ps->hdrsize = sizeof(struct pcap_sf_pkthdr);
+
+ /*
+ * Allocate a buffer for the packet data.
+ * Choose the minimum of the file's snapshot length and 2K bytes;
+ * that should be enough for most network packets - we'll grow it
+ * if necessary. That way, we don't allocate a huge chunk of
+ * memory just because there's a huge snapshot length, as the
+ * snapshot length might be larger than the size of the largest
+ * packet.
+ */
+ p->bufsize = p->snapshot;
+ if (p->bufsize > 2048)
+ p->bufsize = 2048;
+ p->buffer = malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ free(p);
+ *err = 1;
+ return (NULL);
+ }
+
+ p->cleanup_op = sf_cleanup;
+
+ return (p);
+}
+
+/*
+ * Grow the packet buffer to the specified size.
+ */
+static int
+grow_buffer(pcap_t *p, u_int bufsize)
+{
+ void *bigger_buffer;
+
+ bigger_buffer = realloc(p->buffer, bufsize);
+ if (bigger_buffer == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ return (0);
+ }
+ p->buffer = bigger_buffer;
+ p->bufsize = bufsize;
+ return (1);
+}
+
+/*
+ * Read and return the next packet from the savefile. Return the header
+ * in hdr and a pointer to the contents in data. Return 0 on success, 1
+ * if there were no more packets, and -1 on an error.
+ */
+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->rfile;
+ size_t amt_read;
+ bpf_u_int32 t;
+
+ /*
+ * Read the packet header; the structure we use as a buffer
+ * is the longer structure for files generated by the patched
+ * libpcap, but if the file has the magic number for an
+ * unpatched libpcap we only read as many bytes as the regular
+ * header has.
+ */
+ amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);
+ if (amt_read != ps->hdrsize) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ return (-1);
+ } else {
+ if (amt_read != 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu header bytes, only got %zu",
+ ps->hdrsize, amt_read);
+ return (-1);
+ }
+ /* EOF */
+ return (1);
+ }
+ }
+
+ if (p->swapped) {
+ /* these were written in opposite byte order */
+ hdr->caplen = SWAPLONG(sf_hdr.caplen);
+ hdr->len = SWAPLONG(sf_hdr.len);
+ hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
+ hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
+ } else {
+ hdr->caplen = sf_hdr.caplen;
+ hdr->len = sf_hdr.len;
+ 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 (ps->lengths_swapped) {
+
+ case NOT_SWAPPED:
+ break;
+
+ case MAYBE_SWAPPED:
+ if (hdr->caplen <= hdr->len) {
+ /*
+ * The captured length is <= the actual length,
+ * so presumably they weren't swapped.
+ */
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case SWAPPED:
+ t = hdr->caplen;
+ hdr->caplen = hdr->len;
+ hdr->len = t;
+ break;
+ }
+
+ /*
+ * Is the packet bigger than we consider sane?
+ */
+ if (hdr->caplen > max_snaplen_for_dlt(p->linktype)) {
+ /*
+ * Yes. This may be a damaged or fuzzed file.
+ *
+ * Is it bigger than the snapshot length?
+ * (We don't treat that as an error if it's not
+ * bigger than the maximum we consider sane; see
+ * below.)
+ */
+ if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "invalid packet capture length %u, bigger than "
+ "snaplen of %d", hdr->caplen, p->snapshot);
+ } else {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "invalid packet capture length %u, bigger than "
+ "maximum of %u", hdr->caplen,
+ max_snaplen_for_dlt(p->linktype));
+ }
+ return (-1);
+ }
+
+ if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+ /*
+ * The packet is bigger than the snapshot length
+ * for this file.
+ *
+ * This can happen due to Solaris 2.3 systems tripping
+ * over the BUFMOD problem and not setting the snapshot
+ * length correctly in the savefile header.
+ *
+ * libpcap 0.4 and later on Solaris 2.3 should set the
+ * snapshot length correctly in the pcap file header,
+ * even though they don't set a snapshot length in bufmod
+ * (the buggy bufmod chops off the *beginning* of the
+ * packet if a snapshot length is specified); they should
+ * also reduce the captured length, as supplied to the
+ * per-packet callback, to the snapshot length if it's
+ * greater than the snapshot length, so the code using
+ * libpcap should see the packet cut off at the snapshot
+ * length, even though the full packet is copied up to
+ * userland.
+ *
+ * However, perhaps some versions of libpcap failed to
+ * set the snapshot length currectly in the file header
+ * or the per-packet header, or perhaps this is a
+ * corrupted safefile or a savefile built/modified by a
+ * fuzz tester, so we check anyway. We grow the buffer
+ * to be big enough for the snapshot length, read up
+ * to the snapshot length, discard the rest of the
+ * packet, and report the snapshot length as the captured
+ * length; we don't want to hand our caller a packet
+ * bigger than the snapshot length, because they might
+ * be assuming they'll never be handed such a packet,
+ * and might copy the packet into a snapshot-length-
+ * sized buffer, assuming it'll fit.
+ */
+ size_t bytes_to_discard;
+ size_t bytes_to_read, bytes_read;
+ char discard_buf[4096];
+
+ if (hdr->caplen > p->bufsize) {
+ /*
+ * Grow the buffer to the snapshot length.
+ */
+ if (!grow_buffer(p, p->snapshot))
+ return (-1);
+ }
+
+ /*
+ * Read the first p->snapshot bytes into the buffer.
+ */
+ amt_read = fread(p->buffer, 1, p->snapshot, fp);
+ if (amt_read != (bpf_u_int32)p->snapshot) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "error reading dump file");
+ } else {
+ /*
+ * 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.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
+ p->snapshot, amt_read);
+ }
+ return (-1);
+ }
+
+ /*
+ * Now read and discard what's left.
+ */
+ bytes_to_discard = hdr->caplen - p->snapshot;
+ 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_fmt_errmsg_for_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "error reading dump file");
+ } else {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
+ hdr->caplen, 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->snapshot;
+ } else {
+ /*
+ * The packet is within the snapshot length for this file.
+ */
+ if (hdr->caplen > p->bufsize) {
+ /*
+ * Grow the buffer to the next power of 2, or
+ * the snaplen, whichever is lower.
+ */
+ u_int new_bufsize;
+
+ new_bufsize = hdr->caplen;
+ /*
+ * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ */
+ new_bufsize--;
+ new_bufsize |= new_bufsize >> 1;
+ new_bufsize |= new_bufsize >> 2;
+ new_bufsize |= new_bufsize >> 4;
+ new_bufsize |= new_bufsize >> 8;
+ new_bufsize |= new_bufsize >> 16;
+ new_bufsize++;
+
+ if (new_bufsize > (u_int)p->snapshot)
+ new_bufsize = p->snapshot;
+
+ if (!grow_buffer(p, new_bufsize))
+ return (-1);
+ }
+
+ /* read the packet itself */
+ amt_read = fread(p->buffer, 1, hdr->caplen, fp);
+ if (amt_read != hdr->caplen) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "error reading dump file");
+ } else {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
+ hdr->caplen, amt_read);
+ }
+ return (-1);
+ }
+ }
+ *data = p->buffer;
+
+ if (p->swapped)
+ swap_pseudo_headers(p->linktype, hdr, *data);
+
+ return (0);
+}
+
+static int
+sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen)
+{
+ struct pcap_file_header hdr;
+
+ 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;
+
+ /*
+ * https://www.tcpdump.org/manpages/pcap-savefile.5.txt states:
+ * thiszone: 4-byte time zone offset; this is always 0.
+ * sigfigs: 4-byte number giving the accuracy of time stamps
+ * in the file; this is always 0.
+ */
+ hdr.thiszone = 0;
+ hdr.sigfigs = 0;
+ hdr.snaplen = snaplen;
+ hdr.linktype = linktype;
+
+ if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Output a packet to the initialized dump file.
+ */
+void
+pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
+{
+ register FILE *f;
+ struct pcap_sf_pkthdr sf_hdr;
+
+ f = (FILE *)user;
+ /*
+ * Better not try writing pcap files after
+ * 2038-01-19 03:14:07 UTC; switch to pcapng.
+ */
+ sf_hdr.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
+ sf_hdr.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
+ sf_hdr.caplen = h->caplen;
+ sf_hdr.len = h->len;
+ /* XXX we should check the return status */
+ (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
+ (void)fwrite(sp, h->caplen, 1, f);
+}
+
+static pcap_dumper_t *
+pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
+{
+
+#if defined(_WIN32) || defined(MSDOS)
+ /*
+ * If we're writing to the standard output, put it in binary
+ * mode, as savefiles are binary files.
+ *
+ * Otherwise, we turn off buffering.
+ * XXX - why? And why not on the standard output?
+ */
+ if (f == stdout)
+ SET_BINMODE(f);
+ else
+ setvbuf(f, NULL, _IONBF, 0);
+#endif
+ if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "Can't write to %s", fname);
+ if (f != stdout)
+ (void)fclose(f);
+ return (NULL);
+ }
+ return ((pcap_dumper_t *)f);
+}
+
+/*
+ * Initialize so that sf_write() will output to the file named 'fname'.
+ */
+pcap_dumper_t *
+pcap_dump_open(pcap_t *p, const char *fname)
+{
+ FILE *f;
+ int linktype;
+
+ /*
+ * 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,
+ "%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,
+ "%s: link-layer type %d isn't supported in savefiles",
+ fname, p->linktype);
+ return (NULL);
+ }
+ linktype |= p->linktype_ext;
+
+ if (fname == NULL) {
+ 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 {
+ /*
+ * "b" is supported as of C90, so *all* UN*Xes should
+ * support it, even though it does nothing. It's
+ * required on Windows, as the file is a binary file
+ * and must be written in binary mode.
+ */
+ f = charset_fopen(fname, "wb");
+ if (f == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "%s", fname);
+ return (NULL);
+ }
+ }
+ return (pcap_setup_dump(p, linktype, f, fname));
+}
+
+#ifdef _WIN32
+/*
+ * Initialize so that sf_write() will output to a stream wrapping the given raw
+ * OS file HANDLE.
+ */
+pcap_dumper_t *
+pcap_dump_hopen(pcap_t *p, intptr_t osfd)
+{
+ int fd;
+ FILE *file;
+
+ fd = _open_osfhandle(osfd, _O_APPEND);
+ if (fd < 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "_open_osfhandle");
+ return NULL;
+ }
+
+ file = _fdopen(fd, "wb");
+ if (file == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "_fdopen");
+ _close(fd);
+ return NULL;
+ }
+
+ return pcap_dump_fopen(p, file);
+}
+#endif /* _WIN32 */
+
+/*
+ * Initialize so that sf_write() will output to the given stream.
+ */
+#ifdef _WIN32
+static
+#endif /* _WIN32 */
+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,
+ "stream: link-layer type %d isn't supported in savefiles",
+ p->linktype);
+ return (NULL);
+ }
+ linktype |= p->linktype_ext;
+
+ 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) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: link-layer type %d isn't supported in savefiles",
+ fname, linktype);
+ return (NULL);
+ }
+
+ if (fname == NULL) {
+ 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"));
+
+ /*
+ * "a" will cause the file *not* to be truncated if it exists
+ * but will cause it to be created if it doesn't. It will
+ * also cause all writes to be done at the end of the file,
+ * but will allow reads to be done anywhere in the file. This
+ * is what we need, because we need to read from the beginning
+ * of the file to see if it already has a header and packets
+ * or if it doesn't.
+ *
+ * "b" is supported as of C90, so *all* UN*Xes should support it,
+ * even though it does nothing. It's required on Windows, as the
+ * file is a binary file and must be read in binary mode.
+ */
+ f = charset_fopen(fname, "ab+");
+ if (f == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "%s", fname);
+ return (NULL);
+ }
+
+ /*
+ * Try to read a pcap header.
+ *
+ * We do not assume that the file will be positioned at the
+ * beginning immediately after we've opened it - we seek to
+ * the beginning. ISO C says it's implementation-defined
+ * whether the file position indicator is at the beginning
+ * or the end of the file after an append-mode open, and
+ * it wasn't obvious from the Single UNIX Specification
+ * or the Microsoft documentation how that works on SUS-
+ * compliant systems or on Windows.
+ */
+ if (fseek(f, 0, SEEK_SET) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "Can't seek to the beginning of %s", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ amt_read = fread(&ph, 1, sizeof (ph), f);
+ if (amt_read != sizeof (ph)) {
+ if (ferror(f)) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "%s", fname);
+ (void)fclose(f);
+ return (NULL);
+ } else if (feof(f) && amt_read > 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: truncated pcap file header", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ }
+
+#if defined(_WIN32) || defined(MSDOS)
+ /*
+ * We turn off buffering.
+ * XXX - why? And why not on the standard output?
+ */
+ setvbuf(f, NULL, _IONBF, 0);
+#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) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: different time stamp precision, cannot append to file", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ break;
+
+ case NSEC_TCPDUMP_MAGIC:
+ if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: different time stamp precision, cannot append to file", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ break;
+
+ case SWAPLONG(TCPDUMP_MAGIC):
+ case SWAPLONG(NSEC_TCPDUMP_MAGIC):
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: different byte order, cannot append to file", fname);
+ (void)fclose(f);
+ return (NULL);
+
+ case KUZNETZOV_TCPDUMP_MAGIC:
+ case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC):
+ case NAVTEL_TCPDUMP_MAGIC:
+ case SWAPLONG(NAVTEL_TCPDUMP_MAGIC):
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: not a pcap file to which we can append", fname);
+ (void)fclose(f);
+ return (NULL);
+
+ default:
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: not a pcap file", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+
+ /*
+ * Good version?
+ */
+ if (ph.version_major != PCAP_VERSION_MAJOR ||
+ ph.version_minor != PCAP_VERSION_MINOR) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: version is %u.%u, cannot append to file", fname,
+ ph.version_major, ph.version_minor);
+ (void)fclose(f);
+ return (NULL);
+ }
+ if ((bpf_u_int32)linktype != ph.linktype) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: different linktype, cannot append to file", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ if ((bpf_u_int32)p->snapshot != ph.snaplen) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: different snaplen, cannot append to file", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ } else {
+ /*
+ * A header isn't present; attempt to write it.
+ */
+ if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "Can't write to %s", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ }
+
+ /*
+ * Start writing at the end of the file.
+ *
+ * XXX - this shouldn't be necessary, given that we're opening
+ * the file in append mode, and ISO C specifies that all writes
+ * are done at the end of the file in that mode.
+ */
+ if (fseek(f, 0, SEEK_END) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "Can't seek to the end of %s", fname);
+ (void)fclose(f);
+ return (NULL);
+ }
+ return ((pcap_dumper_t *)f);
+}
+
+FILE *
+pcap_dump_file(pcap_dumper_t *p)
+{
+ return ((FILE *)p);
+}
+
+long
+pcap_dump_ftell(pcap_dumper_t *p)
+{
+ return (ftell((FILE *)p));
+}
+
+#if defined(HAVE_FSEEKO)
+/*
+ * We have fseeko(), so we have ftello().
+ * If we have large file support (files larger than 2^31-1 bytes),
+ * ftello() will give us a current file position with more than 32
+ * bits.
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+ return (ftello((FILE *)p));
+}
+#elif defined(_MSC_VER)
+/*
+ * We have Visual Studio; we support only 2005 and later, so we have
+ * _ftelli64().
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+ return (_ftelli64((FILE *)p));
+}
+#else
+/*
+ * We don't have ftello() or _ftelli64(), so fall back on ftell().
+ * Either long is 64 bits, in which case ftell() should suffice,
+ * or this is probably an older 32-bit UN*X without large file
+ * support, which means you'll probably get errors trying to
+ * write files > 2^31-1, so it won't matter anyway.
+ *
+ * XXX - what about MinGW?
+ */
+int64_t
+pcap_dump_ftell64(pcap_dumper_t *p)
+{
+ return (ftell((FILE *)p));
+}
+#endif
+
+int
+pcap_dump_flush(pcap_dumper_t *p)
+{
+
+ if (fflush((FILE *)p) == EOF)
+ return (-1);
+ else
+ return (0);
+}
+
+void
+pcap_dump_close(pcap_dumper_t *p)
+{
+
+#ifdef notyet
+ if (ferror((FILE *)p))
+ return-an-error;
+ /* XXX should check return from fclose() too */
+#endif
+ (void)fclose((FILE *)p);
+}
diff --git a/sf-pcap.h b/sf-pcap.h
new file mode 100644
index 0000000..bc7150f
--- /dev/null
+++ b/sf-pcap.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcap.h - libpcap-file-format-specific routines
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ * Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#ifndef sf_pcap_h
+#define sf_pcap_h
+
+extern pcap_t *pcap_check_header(const uint8_t *magic, FILE *fp,
+ u_int precision, char *errbuf, int *err);
+
+#endif
diff --git a/sf-pcapng.c b/sf-pcapng.c
new file mode 100644
index 0000000..3fd366c
--- /dev/null
+++ b/sf-pcapng.c
@@ -0,0 +1,1518 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcapng.c - pcapng-file-format-specific code from savefile.c
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap/pcap-inttypes.h>
+
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcap-int.h"
+
+#include "pcap-common.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "sf-pcapng.h"
+
+/*
+ * Block types.
+ */
+
+/*
+ * Common part at the beginning of all blocks.
+ */
+struct block_header {
+ bpf_u_int32 block_type;
+ bpf_u_int32 total_length;
+};
+
+/*
+ * Common trailer at the end of all blocks.
+ */
+struct block_trailer {
+ bpf_u_int32 total_length;
+};
+
+/*
+ * Common options.
+ */
+#define OPT_ENDOFOPT 0 /* end of options */
+#define OPT_COMMENT 1 /* comment string */
+
+/*
+ * Option header.
+ */
+struct option_header {
+ u_short option_code;
+ u_short option_length;
+};
+
+/*
+ * Structures for the part of each block type following the common
+ * part.
+ */
+
+/*
+ * Section Header Block.
+ */
+#define BT_SHB 0x0A0D0D0A
+#define BT_SHB_INSANE_MAX 1024U*1024U*1U /* 1MB should be enough */
+struct section_header_block {
+ bpf_u_int32 byte_order_magic;
+ u_short major_version;
+ u_short minor_version;
+ uint64_t section_length;
+ /* followed by options and trailer */
+};
+
+/*
+ * Byte-order magic value.
+ */
+#define BYTE_ORDER_MAGIC 0x1A2B3C4D
+
+/*
+ * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR,
+ * or if minor_version isn't PCAP_NG_VERSION_MINOR or 2, 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.
+ */
+#define BT_IDB 0x00000001
+
+struct interface_description_block {
+ u_short linktype;
+ u_short reserved;
+ bpf_u_int32 snaplen;
+ /* followed by options and trailer */
+};
+
+/*
+ * Options in the IDB.
+ */
+#define IF_NAME 2 /* interface name string */
+#define IF_DESCRIPTION 3 /* interface description string */
+#define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */
+#define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */
+#define IF_MACADDR 6 /* interface's MAC address */
+#define IF_EUIADDR 7 /* interface's EUI address */
+#define IF_SPEED 8 /* interface's speed, in bits/s */
+#define IF_TSRESOL 9 /* interface's time stamp resolution */
+#define IF_TZONE 10 /* interface's time zone */
+#define IF_FILTER 11 /* filter used when capturing on interface */
+#define IF_OS 12 /* string OS on which capture on this interface was done */
+#define IF_FCSLEN 13 /* FCS length for this interface */
+#define IF_TSOFFSET 14 /* time stamp offset for this interface */
+
+/*
+ * Enhanced Packet Block.
+ */
+#define BT_EPB 0x00000006
+
+struct enhanced_packet_block {
+ bpf_u_int32 interface_id;
+ bpf_u_int32 timestamp_high;
+ bpf_u_int32 timestamp_low;
+ bpf_u_int32 caplen;
+ bpf_u_int32 len;
+ /* followed by packet data, options, and trailer */
+};
+
+/*
+ * Simple Packet Block.
+ */
+#define BT_SPB 0x00000003
+
+struct simple_packet_block {
+ bpf_u_int32 len;
+ /* followed by packet data and trailer */
+};
+
+/*
+ * Packet Block.
+ */
+#define BT_PB 0x00000002
+
+struct packet_block {
+ u_short interface_id;
+ u_short drops_count;
+ bpf_u_int32 timestamp_high;
+ bpf_u_int32 timestamp_low;
+ bpf_u_int32 caplen;
+ bpf_u_int32 len;
+ /* followed by packet data, options, and trailer */
+};
+
+/*
+ * Block cursor - used when processing the contents of a block.
+ * Contains a pointer into the data being processed and a count
+ * of bytes remaining in the block.
+ */
+struct block_cursor {
+ u_char *data;
+ size_t data_remaining;
+ 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 {
+ uint32_t snaplen; /* snapshot length */
+ uint64_t tsresol; /* time stamp resolution */
+ tstamp_scale_type_t scale_type; /* how to scale */
+ uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */
+ uint64_t tsoffset; /* time stamp offset */
+};
+
+/*
+ * Per-pcap_t private data.
+ *
+ * max_blocksize is the maximum size of a block that we'll accept. We
+ * reject blocks bigger than this, so we don't consume too much memory
+ * with a truly huge block. It can change as we see IDBs with different
+ * link-layer header types. (Currently, we don't support IDBs with
+ * different link-layer header types, but we will support it in the
+ * future, when we offer file-reading APIs that support it.)
+ *
+ * XXX - that's an issue on ILP32 platforms, where the maximum block
+ * size of 2^31-1 would eat all but one byte of the entire address space.
+ * It's less of an issue on ILP64/LLP64 platforms, but the actual size
+ * of the address space may be limited by 1) the number of *significant*
+ * address bits (currently, x86-64 only supports 48 bits of address), 2)
+ * any limitations imposed by the operating system; 3) any limitations
+ * imposed by the amount of available backing store for anonymous pages,
+ * so we impose a limit regardless of the size of a pointer.
+ */
+struct pcap_ng_sf {
+ uint64_t user_tsresol; /* time stamp resolution requested by the user */
+ u_int max_blocksize; /* don't grow buffer size past this */
+ 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 */
+};
+
+/*
+ * The maximum block size we start with; we use an arbitrary value of
+ * 16 MiB.
+ */
+#define INITIAL_MAX_BLOCKSIZE (16*1024*1024)
+
+/*
+ * Maximum block size for a given maximum snapshot length; we define it
+ * as the size of an EPB with a max_snaplen-sized packet and 128KB of
+ * options.
+ */
+#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \
+ (sizeof (struct block_header) + \
+ sizeof (struct enhanced_packet_block) + \
+ (max_snaplen) + 131072 + \
+ sizeof (struct block_trailer))
+
+static void pcap_ng_cleanup(pcap_t *p);
+static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
+ u_char **data);
+
+static int
+read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
+ char *errbuf)
+{
+ size_t amt_read;
+
+ amt_read = fread(buf, 1, bytes_to_read, fp);
+ if (amt_read != bytes_to_read) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ } else {
+ if (amt_read == 0 && !fail_on_eof)
+ return (0); /* EOF */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated pcapng dump file; tried to read %zu bytes, only got %zu",
+ bytes_to_read, amt_read);
+ }
+ return (-1);
+ }
+ return (1);
+}
+
+static int
+read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
+{
+ struct pcap_ng_sf *ps;
+ int status;
+ struct block_header bhdr;
+ struct block_trailer *btrlr;
+ u_char *bdata;
+ size_t data_remaining;
+
+ ps = p->priv;
+
+ status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf);
+ if (status <= 0)
+ return (status); /* error or EOF */
+
+ if (p->swapped) {
+ bhdr.block_type = SWAPLONG(bhdr.block_type);
+ bhdr.total_length = SWAPLONG(bhdr.total_length);
+ }
+
+ /*
+ * Is this block "too small" - i.e., is it shorter than a block
+ * header plus a block trailer?
+ */
+ if (bhdr.total_length < sizeof(struct block_header) +
+ sizeof(struct block_trailer)) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block in pcapng dump file has a length of %u < %zu",
+ bhdr.total_length,
+ sizeof(struct block_header) + sizeof(struct block_trailer));
+ return (-1);
+ }
+
+ /*
+ * Is the block total length a multiple of 4?
+ */
+ if ((bhdr.total_length % 4) != 0) {
+ /*
+ * No. Report that as an error.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block in pcapng dump file has a length of %u that is not a multiple of 4",
+ bhdr.total_length);
+ return (-1);
+ }
+
+ /*
+ * Is the buffer big enough?
+ */
+ if (p->bufsize < bhdr.total_length) {
+ /*
+ * No - make it big enough, unless it's too big, in
+ * which case we fail.
+ */
+ void *bigger_buffer;
+
+ if (bhdr.total_length > ps->max_blocksize) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
+ ps->max_blocksize);
+ return (-1);
+ }
+ bigger_buffer = realloc(p->buffer, bhdr.total_length);
+ if (bigger_buffer == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ return (-1);
+ }
+ p->buffer = bigger_buffer;
+ }
+
+ /*
+ * Copy the stuff we've read to the buffer, and read the rest
+ * of the block.
+ */
+ memcpy(p->buffer, &bhdr, sizeof(bhdr));
+ 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);
+
+ /*
+ * Get the block size from the trailer.
+ */
+ btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer));
+ if (p->swapped)
+ btrlr->total_length = SWAPLONG(btrlr->total_length);
+
+ /*
+ * Is the total length from the trailer the same as the total
+ * length from the header?
+ */
+ if (bhdr.total_length != btrlr->total_length) {
+ /*
+ * No.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block total length in header and trailer don't match");
+ return (-1);
+ }
+
+ /*
+ * Initialize the cursor.
+ */
+ cursor->data = bdata;
+ cursor->data_remaining = data_remaining - sizeof(struct block_trailer);
+ cursor->block_type = bhdr.block_type;
+ return (1);
+}
+
+static void *
+get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
+ char *errbuf)
+{
+ void *data;
+
+ /*
+ * Make sure we have the specified amount of data remaining in
+ * the block data.
+ */
+ if (cursor->data_remaining < chunk_size) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block of type %u in pcapng dump file is too short",
+ cursor->block_type);
+ return (NULL);
+ }
+
+ /*
+ * Return the current pointer, and skip past the chunk.
+ */
+ data = cursor->data;
+ cursor->data += chunk_size;
+ cursor->data_remaining -= chunk_size;
+ return (data);
+}
+
+static struct option_header *
+get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+{
+ struct option_header *opthdr;
+
+ opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf);
+ if (opthdr == NULL) {
+ /*
+ * Option header is cut short.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ opthdr->option_code = SWAPSHORT(opthdr->option_code);
+ opthdr->option_length = SWAPSHORT(opthdr->option_length);
+ }
+
+ return (opthdr);
+}
+
+static void *
+get_optvalue_from_block_data(struct block_cursor *cursor,
+ struct option_header *opthdr, char *errbuf)
+{
+ size_t padded_option_len;
+ void *optvalue;
+
+ /* Pad option length to 4-byte boundary */
+ padded_option_len = opthdr->option_length;
+ padded_option_len = ((padded_option_len + 3)/4)*4;
+
+ optvalue = get_from_block_data(cursor, padded_option_len, errbuf);
+ if (optvalue == NULL) {
+ /*
+ * Option value is cut short.
+ */
+ return (NULL);
+ }
+
+ return (optvalue);
+}
+
+static int
+process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
+ uint64_t *tsoffset, int *is_binary, char *errbuf)
+{
+ struct option_header *opthdr;
+ void *optvalue;
+ int saw_tsresol, saw_tsoffset;
+ uint8_t tsresol_opt;
+ u_int i;
+
+ saw_tsresol = 0;
+ saw_tsoffset = 0;
+ while (cursor->data_remaining != 0) {
+ /*
+ * Get the option header.
+ */
+ opthdr = get_opthdr_from_block_data(p, cursor, errbuf);
+ if (opthdr == NULL) {
+ /*
+ * Option header is cut short.
+ */
+ return (-1);
+ }
+
+ /*
+ * Get option value.
+ */
+ optvalue = get_optvalue_from_block_data(cursor, opthdr,
+ errbuf);
+ if (optvalue == NULL) {
+ /*
+ * Option value is cut short.
+ */
+ return (-1);
+ }
+
+ switch (opthdr->option_code) {
+
+ case OPT_ENDOFOPT:
+ if (opthdr->option_length != 0) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Interface Description Block has opt_endofopt option with length %u != 0",
+ opthdr->option_length);
+ return (-1);
+ }
+ goto done;
+
+ case IF_TSRESOL:
+ if (opthdr->option_length != 1) {
+ 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,
+ "Interface Description Block has more than one if_tsresol option");
+ return (-1);
+ }
+ saw_tsresol = 1;
+ memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt));
+ if (tsresol_opt & 0x80) {
+ /*
+ * Resolution is negative power of 2.
+ */
+ uint8_t tsresol_shift = (tsresol_opt & 0x7F);
+
+ if (tsresol_shift > 63) {
+ /*
+ * Resolution is too high; 2^-{res}
+ * won't fit in a 64-bit value.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Interface Description Block if_tsresol option resolution 2^-%u is too high",
+ tsresol_shift);
+ return (-1);
+ }
+ *is_binary = 1;
+ *tsresol = ((uint64_t)1) << tsresol_shift;
+ } else {
+ /*
+ * Resolution is negative power of 10.
+ */
+ if (tsresol_opt > 19) {
+ /*
+ * Resolution is too high; 2^-{res}
+ * won't fit in a 64-bit value (the
+ * largest power of 10 that fits
+ * in a 64-bit value is 10^19, as
+ * the largest 64-bit unsigned
+ * value is ~1.8*10^19).
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Interface Description Block if_tsresol option resolution 10^-%u is too high",
+ tsresol_opt);
+ return (-1);
+ }
+ *is_binary = 0;
+ *tsresol = 1;
+ for (i = 0; i < tsresol_opt; i++)
+ *tsresol *= 10;
+ }
+ break;
+
+ case IF_TSOFFSET:
+ if (opthdr->option_length != 8) {
+ 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,
+ "Interface Description Block has more than one if_tsoffset option");
+ return (-1);
+ }
+ saw_tsoffset = 1;
+ memcpy(tsoffset, optvalue, sizeof(*tsoffset));
+ if (p->swapped)
+ *tsoffset = SWAPLL(*tsoffset);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+done:
+ return (0);
+}
+
+static int
+add_interface(pcap_t *p, struct interface_description_block *idbp,
+ struct block_cursor *cursor, char *errbuf)
+{
+ struct pcap_ng_sf *ps;
+ uint64_t tsresol;
+ uint64_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 pcapng 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.
+ */
+ 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).
+ */
+ 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.
+ */
+ 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;
+ }
+
+ ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen;
+
+ /*
+ * 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 pcapng savefile and, if it is, extract the
+ * relevant information from the header.
+ */
+pcap_t *
+pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
+ char *errbuf, int *err)
+{
+ bpf_u_int32 magic_int;
+ 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 pcapng savefile.
+ */
+ memcpy(&magic_int, magic, sizeof(magic_int));
+ if (magic_int != BT_SHB) {
+ /*
+ * XXX - check whether this looks like what the block
+ * type would be after being munged by mapping between
+ * UN*X and DOS/Windows text file format and, if it
+ * does, look for the byte-order magic number in
+ * the appropriate place and, if we find it, report
+ * this as possibly being a pcapng file transferred
+ * between UN*X and Windows in text file format?
+ */
+ return (NULL); /* nope */
+ }
+
+ /*
+ * OK, they are. However, that's just \n\r\r\n, so it could,
+ * conceivably, be an ordinary text file.
+ *
+ * It could not, however, conceivably be any other type of
+ * capture file, so we can read the rest of the putative
+ * Section Header Block; put the block type in the common
+ * header, read the rest of the common header and the
+ * fixed-length portion of the SHB, and look for the byte-order
+ * magic value.
+ */
+ amt_read = fread(&total_length, 1, sizeof(total_length), fp);
+ if (amt_read < sizeof(total_length)) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ *err = 1;
+ return (NULL); /* fail */
+ }
+
+ /*
+ * Possibly a weird short text file, so just say
+ * "not pcapng".
+ */
+ return (NULL);
+ }
+ amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp);
+ if (amt_read < sizeof(byte_order_magic)) {
+ if (ferror(fp)) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "error reading dump file");
+ *err = 1;
+ return (NULL); /* fail */
+ }
+
+ /*
+ * Possibly a weird short text file, so just say
+ * "not pcapng".
+ */
+ return (NULL);
+ }
+ if (byte_order_magic != BYTE_ORDER_MAGIC) {
+ byte_order_magic = SWAPLONG(byte_order_magic);
+ if (byte_order_magic != BYTE_ORDER_MAGIC) {
+ /*
+ * Not a pcapng file.
+ */
+ return (NULL);
+ }
+ swapped = 1;
+ total_length = SWAPLONG(total_length);
+ }
+
+ /*
+ * Check the sanity of the total length.
+ */
+ if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) ||
+ (total_length > BT_SHB_INSANE_MAX)) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Section Header Block in pcapng dump file has invalid length %zu < _%u_ < %u (BT_SHB_INSANE_MAX)",
+ sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer),
+ total_length,
+ BT_SHB_INSANE_MAX);
+
+ *err = 1;
+ return (NULL);
+ }
+
+ /*
+ * OK, this is a good pcapng file.
+ * Allocate a pcap_t for it.
+ */
+ p = PCAP_OPEN_OFFLINE_COMMON(errbuf, 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:
+ 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
+ * the maximum of:
+ *
+ * the total length of the SHB for which we read the header;
+ *
+ * 2K, which should be more than large enough for an Enhanced
+ * Packet Block containing a full-size Ethernet frame, and
+ * leaving room for some options.
+ *
+ * If we find a bigger block, we reallocate the buffer, up to
+ * the maximum size. We start out with a maximum size of
+ * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types
+ * with a maximum snapshot that results in a larger maximum
+ * block length, we boost the maximum.
+ */
+ p->bufsize = 2048;
+ if (p->bufsize < total_length)
+ p->bufsize = total_length;
+ p->buffer = malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ free(p);
+ *err = 1;
+ return (NULL);
+ }
+ ps->max_blocksize = INITIAL_MAX_BLOCKSIZE;
+
+ /*
+ * Copy the stuff we've read to the buffer, and read the rest
+ * of the SHB.
+ */
+ bhdrp = (struct block_header *)p->buffer;
+ shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header));
+ bhdrp->block_type = magic_int;
+ bhdrp->total_length = total_length;
+ shbp->byte_order_magic = byte_order_magic;
+ if (read_bytes(fp,
+ (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
+ total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)),
+ 1, errbuf) == -1)
+ goto fail;
+
+ if (p->swapped) {
+ /*
+ * Byte-swap the fields we've read.
+ */
+ shbp->major_version = SWAPSHORT(shbp->major_version);
+ shbp->minor_version = SWAPSHORT(shbp->minor_version);
+
+ /*
+ * XXX - we don't care about the section length.
+ */
+ }
+ /* Currently only SHB versions 1.0 and 1.2 are supported;
+ version 1.2 is treated as being the same as version 1.0.
+ See the current version of the pcapng specification.
+
+ Version 1.2 is written by some programs that write additional
+ block types (which can be read by any code that handles them,
+ regardless of whether the minor version if 0 or 2, so that's
+ not a reason to change the minor version number).
+
+ XXX - the pcapng specification says that readers should
+ just ignore sections with an unsupported version number;
+ presumably they can also report an error if they skip
+ all the way to the end of the file without finding
+ any versions that they support. */
+ if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
+ (shbp->minor_version == PCAP_NG_VERSION_MINOR ||
+ shbp->minor_version == 2))) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unsupported pcapng savefile version %u.%u",
+ shbp->major_version, shbp->minor_version);
+ goto fail;
+ }
+ p->version_major = shbp->major_version;
+ p->version_minor = shbp->minor_version;
+
+ /*
+ * Save the time stamp resolution the user requested.
+ */
+ p->opt.tstamp_precision = precision;
+
+ /*
+ * Now start looking for an Interface Description Block.
+ */
+ for (;;) {
+ /*
+ * Read the next block.
+ */
+ status = read_block(fp, p, &cursor, errbuf);
+ if (status == 0) {
+ /* EOF - no IDB in this file */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "the capture file has no Interface Description Blocks");
+ goto fail;
+ }
+ if (status == -1)
+ goto fail; /* error */
+ switch (cursor.block_type) {
+
+ case BT_IDB:
+ /*
+ * Get a pointer to the fixed-length portion of the
+ * IDB.
+ */
+ idbp = get_from_block_data(&cursor, sizeof(*idbp),
+ errbuf);
+ if (idbp == NULL)
+ goto fail; /* error */
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ idbp->linktype = SWAPSHORT(idbp->linktype);
+ idbp->snaplen = SWAPLONG(idbp->snaplen);
+ }
+
+ /*
+ * Try to add this interface.
+ */
+ if (!add_interface(p, idbp, &cursor, errbuf))
+ goto fail;
+
+ goto done;
+
+ case BT_EPB:
+ case BT_SPB:
+ case BT_PB:
+ /*
+ * Saw a packet before we saw any IDBs. That's
+ * not valid, as we don't know what link-layer
+ * encapsulation the packet has.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "the capture file has a packet block before any Interface Description Blocks");
+ goto fail;
+
+ default:
+ /*
+ * Just ignore it.
+ */
+ break;
+ }
+ }
+
+done:
+ p->linktype = linktype_to_dlt(idbp->linktype);
+ p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen);
+ p->linktype_ext = 0;
+
+ /*
+ * If the maximum block size for a packet with the maximum
+ * snapshot length for this DLT_ is bigger than the current
+ * maximum block size, increase the maximum.
+ */
+ if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize)
+ ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype));
+
+ p->next_packet_op = pcap_ng_next_packet;
+ p->cleanup_op = pcap_ng_cleanup;
+
+ return (p);
+
+fail:
+ free(ps->ifaces);
+ free(p->buffer);
+ 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);
+}
+
+/*
+ * Read and return the next packet from the savefile. Return the header
+ * in hdr and a pointer to the contents in data. Return 0 on success, 1
+ * if there were no more packets, and -1 on an error.
+ */
+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;
+ struct simple_packet_block *spbp;
+ struct packet_block *pbp;
+ bpf_u_int32 interface_id = 0xFFFFFFFF;
+ struct interface_description_block *idbp;
+ struct section_header_block *shbp;
+ FILE *fp = p->rfile;
+ uint64_t t, sec, frac;
+
+ /*
+ * Look for an Enhanced Packet Block, a Simple Packet Block,
+ * or a Packet Block.
+ */
+ for (;;) {
+ /*
+ * Read the block type and length; those are common
+ * to all blocks.
+ */
+ status = read_block(fp, p, &cursor, p->errbuf);
+ if (status == 0)
+ return (1); /* EOF */
+ if (status == -1)
+ return (-1); /* error */
+ switch (cursor.block_type) {
+
+ case BT_EPB:
+ /*
+ * Get a pointer to the fixed-length portion of the
+ * EPB.
+ */
+ epbp = get_from_block_data(&cursor, sizeof(*epbp),
+ p->errbuf);
+ if (epbp == NULL)
+ return (-1); /* error */
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ /* these were written in opposite byte order */
+ interface_id = SWAPLONG(epbp->interface_id);
+ hdr->caplen = SWAPLONG(epbp->caplen);
+ hdr->len = SWAPLONG(epbp->len);
+ t = ((uint64_t)SWAPLONG(epbp->timestamp_high)) << 32 |
+ SWAPLONG(epbp->timestamp_low);
+ } else {
+ interface_id = epbp->interface_id;
+ hdr->caplen = epbp->caplen;
+ hdr->len = epbp->len;
+ t = ((uint64_t)epbp->timestamp_high) << 32 |
+ epbp->timestamp_low;
+ }
+ goto found;
+
+ case BT_SPB:
+ /*
+ * Get a pointer to the fixed-length portion of the
+ * SPB.
+ */
+ spbp = get_from_block_data(&cursor, sizeof(*spbp),
+ p->errbuf);
+ if (spbp == NULL)
+ return (-1); /* error */
+
+ /*
+ * SPB packets are assumed to have arrived on
+ * the first interface.
+ */
+ interface_id = 0;
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ /* these were written in opposite byte order */
+ hdr->len = SWAPLONG(spbp->len);
+ } else
+ hdr->len = spbp->len;
+
+ /*
+ * The SPB doesn't give the captured length;
+ * it's the minimum of the snapshot length
+ * and the packet length.
+ */
+ hdr->caplen = hdr->len;
+ if (hdr->caplen > (bpf_u_int32)p->snapshot)
+ hdr->caplen = p->snapshot;
+ t = 0; /* no time stamps */
+ goto found;
+
+ case BT_PB:
+ /*
+ * Get a pointer to the fixed-length portion of the
+ * PB.
+ */
+ pbp = get_from_block_data(&cursor, sizeof(*pbp),
+ p->errbuf);
+ if (pbp == NULL)
+ return (-1); /* error */
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ /* these were written in opposite byte order */
+ interface_id = SWAPSHORT(pbp->interface_id);
+ hdr->caplen = SWAPLONG(pbp->caplen);
+ hdr->len = SWAPLONG(pbp->len);
+ t = ((uint64_t)SWAPLONG(pbp->timestamp_high)) << 32 |
+ SWAPLONG(pbp->timestamp_low);
+ } else {
+ interface_id = pbp->interface_id;
+ hdr->caplen = pbp->caplen;
+ hdr->len = pbp->len;
+ t = ((uint64_t)pbp->timestamp_high) << 32 |
+ pbp->timestamp_low;
+ }
+ goto found;
+
+ case BT_IDB:
+ /*
+ * Interface Description Block. Get a pointer
+ * to its fixed-length portion.
+ */
+ idbp = get_from_block_data(&cursor, sizeof(*idbp),
+ p->errbuf);
+ if (idbp == NULL)
+ return (-1); /* error */
+
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (p->swapped) {
+ idbp->linktype = SWAPSHORT(idbp->linktype);
+ idbp->snaplen = SWAPLONG(idbp->snaplen);
+ }
+
+ /*
+ * If the link-layer type or snapshot length
+ * differ from the ones for the first IDB we
+ * saw, quit.
+ *
+ * XXX - just discard packets from those
+ * interfaces?
+ */
+ if (p->linktype != idbp->linktype) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "an interface has a type %u different from the type of the first interface",
+ idbp->linktype);
+ return (-1);
+ }
+
+ /*
+ * Check against the *adjusted* value of this IDB's
+ * snapshot length.
+ */
+ if ((bpf_u_int32)p->snapshot !=
+ pcap_adjust_snapshot(p->linktype, idbp->snaplen)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "an interface has a snapshot length %u different from the snapshot length of the first interface",
+ idbp->snaplen);
+ return (-1);
+ }
+
+ /*
+ * Try to add this interface.
+ */
+ if (!add_interface(p, idbp, &cursor, p->errbuf))
+ return (-1);
+ break;
+
+ case BT_SHB:
+ /*
+ * Section Header Block. Get a pointer
+ * to its fixed-length portion.
+ */
+ shbp = get_from_block_data(&cursor, sizeof(*shbp),
+ p->errbuf);
+ if (shbp == NULL)
+ return (-1); /* error */
+
+ /*
+ * Assume the byte order of this section is
+ * the same as that of the previous section.
+ * We'll check for that later.
+ */
+ if (p->swapped) {
+ shbp->byte_order_magic =
+ SWAPLONG(shbp->byte_order_magic);
+ shbp->major_version =
+ SWAPSHORT(shbp->major_version);
+ }
+
+ /*
+ * Make sure the byte order doesn't change;
+ * pcap_is_swapped() shouldn't change its
+ * return value in the middle of reading a capture.
+ */
+ switch (shbp->byte_order_magic) {
+
+ case BYTE_ORDER_MAGIC:
+ /*
+ * OK.
+ */
+ break;
+
+ case SWAPLONG(BYTE_ORDER_MAGIC):
+ /*
+ * Byte order changes.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "the file has sections with different byte orders");
+ return (-1);
+
+ default:
+ /*
+ * Not a valid SHB.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "the file has a section with a bad byte order magic field");
+ return (-1);
+ }
+
+ /*
+ * Make sure the major version is the version
+ * we handle.
+ */
+ if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "unknown pcapng savefile major version number %u",
+ shbp->major_version);
+ return (-1);
+ }
+
+ /*
+ * Reset the interface count; this section should
+ * have its own set of IDBs. If any of them
+ * don't have the same interface type, snapshot
+ * length, or resolution as the first interface
+ * we saw, we'll fail. (And if we don't see
+ * any IDBs, we'll fail when we see a packet
+ * block.)
+ */
+ ps->ifcount = 0;
+ break;
+
+ default:
+ /*
+ * Not a packet block, IDB, or SHB; ignore it.
+ */
+ break;
+ }
+ }
+
+found:
+ /*
+ * Is the interface ID an interface we know?
+ */
+ if (interface_id >= ps->ifcount) {
+ /*
+ * Yes. Fail.
+ */
+ 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);
+ }
+
+ if (hdr->caplen > (bpf_u_int32)p->snapshot) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "invalid packet capture length %u, bigger than "
+ "snaplen of %d", hdr->caplen, p->snapshot);
+ return (-1);
+ }
+
+ /*
+ * Convert the time stamp to seconds and fractions of a second,
+ * with the fractions being in units of the file-supplied resolution.
+ */
+ 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:
+ /*
+ * The interface resolution is what the user wants,
+ * so we're done.
+ */
+ 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:
+ /*
+ * 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 *= 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;
+ }
+#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.
+ */
+ *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf);
+ if (*data == NULL)
+ return (-1);
+
+ if (p->swapped)
+ swap_pseudo_headers(p->linktype, hdr, *data);
+
+ return (0);
+}
diff --git a/sf-pcapng.h b/sf-pcapng.h
new file mode 100644
index 0000000..835082a
--- /dev/null
+++ b/sf-pcapng.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * sf-pcapng.h - pcapng-file-format-specific routines
+ *
+ * Used to read pcapng savefiles.
+ */
+
+#ifndef sf_pcapng_h
+#define sf_pcapng_h
+
+extern pcap_t *pcap_ng_check_header(const uint8_t *magic, FILE *fp,
+ u_int precision, char *errbuf, int *err);
+
+#endif
diff --git a/sunatmpos.h b/sunatmpos.h
new file mode 100644
index 0000000..787de85
--- /dev/null
+++ b/sunatmpos.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1997 Yen Yen Lim and North Dakota State University
+ * 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 Yen Yen Lim and
+ North Dakota State University
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* SunATM header for ATM packet */
+#define SUNATM_DIR_POS 0
+#define SUNATM_VPI_POS 1
+#define SUNATM_VCI_POS 2
+#define SUNATM_PKT_BEGIN_POS 4 /* Start of ATM packet */
+
+/* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */
+#define PT_LANE 0x01 /* LANE */
+#define PT_LLC 0x02 /* LLC encapsulation */
+#define PT_ILMI 0x05 /* ILMI */
+#define PT_QSAAL 0x06 /* Q.SAAL */
diff --git a/varattrs.h b/varattrs.h
new file mode 100644
index 0000000..05bfe8c
--- /dev/null
+++ b/varattrs.h
@@ -0,0 +1,59 @@
+/* -*- 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 varattrs_h
+#define varattrs_h
+
+#include <pcap/compiler-tests.h>
+
+/*
+ * Attributes to apply to variables, using various compiler-specific
+ * extensions.
+ */
+
+#if __has_attribute(unused) \
+ || PCAP_IS_AT_LEAST_GNUC_VERSION(2,0)
+ /*
+ * Compiler with support for __attribute__((unused)), or GCC 2.0 and
+ * later, so it supports __attribute__((unused)).
+ */
+ #define _U_ __attribute__((unused))
+#else
+ /*
+ * We don't know of any way to mark a variable as unused.
+ */
+ #define _U_
+#endif
+
+#endif