*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.14 2007-12-29 02:35:16 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.19 2008-12-23 20:14:12 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
static inline struct block *gen_false(void);
static struct block *gen_ether_linktype(int);
static struct block *gen_linux_sll_linktype(int);
+static struct slist *gen_load_prism_llprefixlen(void);
+static struct slist *gen_load_avs_llprefixlen(void);
static struct slist *gen_load_radiotap_llprefixlen(void);
static struct slist *gen_load_ppi_llprefixlen(void);
-static struct slist *gen_load_avs_llprefixlen(void);
static void insert_compute_vloffsets(struct block *);
static struct slist *gen_llprefixlen(void);
static struct slist *gen_off_macpl(void);
return;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
/*
* 802.11 doesn't really have a link-level type field.
* We set "off_linktype" to the offset of the LLC header.
* 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. We
- * assume a 24-byte link-layer header, as appears in
- * data frames in networks with no bridges. If the
- * fromds and tods 802.11 header bits are both set,
- * it's actually supposed to be 30 bytes.
- */
- off_linktype = 24;
- off_macpl = 0; /* link-layer header is variable-length */
- off_macpl_is_variable = 1;
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
-
- case DLT_PRISM_HEADER:
- /*
- * Same as 802.11, but with an additional header before
- * the 802.11 header, containing a bunch of additional
- * information including radio-level information.
- *
- * The header is 144 bytes long.
- *
- * XXX - same variable-length header problem; at least
- * the Prism header is fixed-length.
+ * 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.
*/
- off_ll = 144;
off_linktype = 24;
off_macpl = 0; /* link-layer header is variable-length */
off_macpl_is_variable = 1;
off_nl_nosnap = 3; /* 802.2 */
return;
- case DLT_IEEE802_11_RADIO_AVS:
- /*
- * Same as 802.11, but with an additional header before
- * the 802.11 header, containing a bunch of additional
- * information including radio-level information.
- *
- * The radiotap header is variable length, and we
- * generate code to compute its length and store it
- * in a register. These offsets are relative to the
- * beginning of the 802.11 header.
- *
- * XXX - in Linux, do any drivers that supply an AVS
- * header supply a link-layer type other than
- * ARPHRD_IEEE80211_PRISM? If so, we should map that
- * to DLT_IEEE802_11_RADIO_AVS; if not, or if there are
- * any drivers that supply an AVS header but supply
- * an ARPHRD value of ARPHRD_IEEE80211_PRISM, we'll
- * have to check the header in the generated code to
- * determine whether it's Prism or AVS.
- */
- off_linktype = 24;
- off_macpl = 0; /* link-layer header is variable-length */
- off_macpl_is_variable = 1;
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
-
- /*
- * 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.
- */
case DLT_PPI:
- case DLT_IEEE802_11_RADIO:
- /*
- * Same as 802.11, but with an additional header before
- * the 802.11 header, containing a bunch of additional
- * information including radio-level information.
- *
- * The radiotap header is variable length, and we
- * generate code to compute its length and store it
- * in a register. These offsets are relative to the
- * beginning of the 802.11 header.
+ /*
+ * 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.
*/
off_linktype = 24;
off_macpl = 0; /* link-layer header is variable-length */
off_nl_nosnap = -1; /* no 802.2 LLC */
off_mac = 1; /* step over the kiss length byte */
return;
+
+ case DLT_IEEE802_15_4_NONASK_PHY:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_MPLS:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
+
+ case DLT_USB_LINUX_MMAPPED:
+ /*
+ * Currently, only raw "link[N:M]" filtering is supported.
+ */
+ off_linktype = -1;
+ off_macpl = -1;
+ off_nl = -1;
+ off_nl_nosnap = -1;
+ return;
}
bpf_error("unknown data link type %d", linktype);
/* NOTREACHED */
}
}
+static struct slist *
+gen_load_prism_llprefixlen()
+{
+ 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
+ */
+ 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 (reg_off_ll != -1) {
+ /*
+ * Load the cookie.
+ */
+ s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 0;
+
+ /*
+ * AND it with 0xFFFFF000.
+ */
+ s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ s2->s.k = 0xFFFFF000;
+ sappend(s1, s2);
+
+ /*
+ * Compare with 0x80211000.
+ */
+ sjeq_avs_cookie = new_stmt(JMP(BPF_JEQ));
+ sjeq_avs_cookie->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(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(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(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(BPF_ST);
+ s2->s.k = reg_off_ll;
+ sappend(s1, s2);
+ sjcommon->s.jf = s2;
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
+static struct slist *
+gen_load_avs_llprefixlen()
+{
+ 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 (reg_off_ll != -1) {
+ /*
+ * The 4 bytes at an offset of 4 from the beginning of
+ * the AVS header are the length of the AVS header.
+ * That field is big-endian.
+ */
+ s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+ s1->s.k = 4;
+
+ /*
+ * Now allocate a register to hold that value and store
+ * it.
+ */
+ s2 = new_stmt(BPF_ST);
+ s2->s.k = reg_off_ll;
+ sappend(s1, s2);
+
+ /*
+ * Now move it into the X register.
+ */
+ s2 = new_stmt(BPF_MISC|BPF_TAX);
+ sappend(s1, s2);
+
+ return (s1);
+ } else
+ return (NULL);
+}
+
static struct slist *
gen_load_radiotap_llprefixlen()
{
return (NULL);
}
-static struct slist *
-gen_load_avs_llprefixlen()
-{
- 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 (reg_off_ll != -1) {
- /*
- * The 4 bytes at an offset of 4 from the beginning of
- * the AVS header are the length of the AVS header.
- * That field is big-endian.
- */
- s1 = new_stmt(BPF_LD|BPF_W|BPF_ABS);
- s1->s.k = 4;
-
- /*
- * Now allocate a register to hold that value and store
- * it.
- */
- s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_ll;
- sappend(s1, s2);
-
- /*
- * Now move it into the X register.
- */
- s2 = new_stmt(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.
*/
switch (linktype) {
+ case DLT_PRISM_HEADER:
+ s = gen_load_prism_llprefixlen();
+ break;
+
+ case DLT_IEEE802_11_RADIO_AVS:
+ s = gen_load_avs_llprefixlen();
+ break;
+
case DLT_IEEE802_11_RADIO:
s = gen_load_radiotap_llprefixlen();
break;
s = gen_load_ppi_llprefixlen();
break;
- case DLT_IEEE802_11_RADIO_AVS:
- s = gen_load_avs_llprefixlen();
- break;
-
default:
s = NULL;
break;
switch (linktype) {
case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO:
- case DLT_IEEE802_11_RADIO_AVS:
case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
case DLT_PPI:
s = gen_load_802_11_header_len(s, b->stmts);
break;
}
static struct slist *
-gen_radiotap_llprefixlen(void)
+gen_prism_llprefixlen(void)
{
struct slist *s;
if (reg_off_ll == -1) {
/*
* We haven't yet assigned a register for the length
- * of the radiotap header; allocate one.
+ * of the radio header; allocate one.
*/
reg_off_ll = alloc_reg();
}
/*
- * Load the register containing the radiotap length
+ * Load the register containing the radio length
* into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
return s;
}
-/*
- * At the moment we treat PPI as normal Radiotap encoded
- * packets. The difference is in the function that generates
- * the code at the beginning to compute the header length.
- * Since this code generator of PPI supports bare 802.11
- * encapsulation only (i.e. the encapsulated DLT should be
- * DLT_IEEE802_11) we generate code to check for this too.
- */
static struct slist *
-gen_ppi_llprefixlen(void)
+gen_avs_llprefixlen(void)
+{
+ struct slist *s;
+
+ if (reg_off_ll == -1) {
+ /*
+ * We haven't yet assigned a register for the length
+ * of the AVS header; allocate one.
+ */
+ reg_off_ll = alloc_reg();
+ }
+
+ /*
+ * Load the register containing the AVS length
+ * into the X register.
+ */
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = reg_off_ll;
+ return s;
+}
+
+static struct slist *
+gen_radiotap_llprefixlen(void)
{
struct slist *s;
}
/*
- * Load the register containing the PPI length
+ * Load the register containing the radiotap length
* into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
return s;
}
+/*
+ * At the moment we treat PPI as normal Radiotap encoded
+ * packets. The difference is in the function that generates
+ * the code at the beginning to compute the header length.
+ * Since this code generator of PPI supports bare 802.11
+ * encapsulation only (i.e. the encapsulated DLT should be
+ * DLT_IEEE802_11) we generate code to check for this too.
+ */
static struct slist *
-gen_avs_llprefixlen(void)
+gen_ppi_llprefixlen(void)
{
struct slist *s;
}
/*
- * Load the register containing the AVS length
+ * Load the register containing the PPI length
* into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
{
switch (linktype) {
- case DLT_PPI:
- return gen_ppi_llprefixlen();
+ case DLT_PRISM_HEADER:
+ return gen_prism_llprefixlen();
+
+ case DLT_IEEE802_11_RADIO_AVS:
+ return gen_avs_llprefixlen();
case DLT_IEEE802_11_RADIO:
return gen_radiotap_llprefixlen();
- case DLT_IEEE802_11_RADIO_AVS:
- return gen_avs_llprefixlen();
+ case DLT_PPI:
+ return gen_ppi_llprefixlen();
default:
return NULL;
}
break;
- case DLT_PPI:
case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO:
- case DLT_IEEE802_11_RADIO_AVS:
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.
*/
case DLT_USB:
case DLT_USB_LINUX:
+ case DLT_USB_LINUX_MMAPPED:
bpf_error("USB link-layer type filtering not implemented");
case DLT_BLUETOOTH_HCI_H4:
case DLT_IEEE802_15_4:
case DLT_IEEE802_15_4_LINUX:
+ case DLT_IEEE802_15_4_NONASK_PHY:
bpf_error("IEEE 802.15.4 link-layer type filtering not implemented");
case DLT_IEEE802_16_MAC_CPS_RADIO:
b0 = gen_thostop(eaddr, Q_OR);
break;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
- case DLT_PPI:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
+ case DLT_PPI:
b0 = gen_wlanhostop(eaddr, Q_OR);
break;
case DLT_SUNATM:
switch (linktype) {
case DLT_IEEE802_11:
- case DLT_IEEE802_11_RADIO:
- case DLT_IEEE802_11_RADIO_AVS:
case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
case DLT_PPI:
bpf_error("'protochain' not supported with 802.11");
}
return b;
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
case DLT_PPI:
eaddr = pcap_ether_hostton(name);
if (eaddr == NULL)
case DLT_IEEE802:
return gen_thostop(eaddr, (int)q.dir);
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
case DLT_PPI:
return gen_wlanhostop(eaddr, (int)q.dir);
case DLT_SUNATM:
case DLT_IEEE802:
return gen_thostop(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:
- case DLT_PRISM_HEADER:
return gen_wlanhostop(ebroadcast, Q_DST);
case DLT_IP_OVER_FC:
return gen_ipfchostop(ebroadcast, Q_DST);
/* tr[2] & 1 != 0 */
return gen_mac_multicast(2);
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
- case DLT_PPI:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
+ case DLT_PPI:
/*
* Oh, yuk.
*
switch (linktype) {
case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- case DLT_PRISM_HEADER:
break;
default: