blob: 681745a1b34b968d7521875f5df30e0d603bf800 [file] [log] [blame]
--- gencode.c.cvs 2007-06-14 13:54:12.000000000 -0700
+++ gencode.c 2007-06-14 13:56:27.531250000 -0700
@@ -24,6 +24,8 @@
"@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.51 2007/06/14 20:54:12 gianluca Exp $ (LBL)";
#endif
+#define ENABLE_WLAN_FILTERING_PATCH
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -144,7 +146,8 @@
OR_NET, /* relative to the network-layer header */
OR_NET_NOSNAP, /* relative to the network-layer header, with no SNAP header at the link layer */
OR_TRAN_IPV4, /* relative to the transport-layer header, with IPv4 network layer */
- OR_TRAN_IPV6 /* relative to the transport-layer header, with IPv6 network layer */
+ OR_TRAN_IPV6, /* relative to the transport-layer header, with IPv6 network layer */
+ OR_LINK_AFTER_WIRELESS_HDR /* After the 802.11 variable length header */
};
/*
@@ -199,6 +202,7 @@
static struct block *gen_linktype(int);
static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int);
static struct block *gen_llc_linktype(int);
+static struct block *gen_802_11_llc_linktype(int);
static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
#ifdef INET6
static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int);
@@ -242,6 +246,7 @@
static struct slist *xfer_to_a(struct arth *);
static struct block *gen_mac_multicast(int);
static struct block *gen_len(int, int);
+static struct block *gen_check_802_11_data_frame();
static struct block *gen_ppi_dlt_check();
static struct block *gen_msg_abbrev(int type);
@@ -1345,6 +1350,138 @@
return s;
}
+/*
+ * 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_ll_after_802_11_rel(offset, size)
+ u_int offset, size;
+{
+ struct slist *s, *s_load_fc;
+ struct slist *sjset_qos;
+ struct slist *s_load;
+ struct slist *s_ld_a_2;
+ struct slist *s_add_a_x;
+ struct slist *s_a_to_x;
+ struct slist *sjset_data_frame_1;
+ struct slist *sjset_data_frame_2;
+ struct slist *s_load_x_0;
+
+ /*
+ * This code is not compatible with the optimizer, as
+ * we are generating jmp instructions within a normal
+ * slist of instructions
+ *
+ */
+ no_optimize = 1;
+
+ s = gen_llprefixlen();
+
+ /*
+ * If "s" is non-null, it has code to arrange that the X register
+ * contains the length of the prefix preceding the link-layer
+ * header.
+ *
+ * Otherwise, the length of the prefix preceding the link-layer
+ * header is "off_ll".
+ */
+ if (s != NULL) {
+ /*
+ * There's a variable-length prefix preceding the
+ * link-layer header. "s" points to a list of statements
+ * that put the length of that prefix into the X register.
+ * do an indirect load, to use the X register as an offset.
+ */
+
+ /*
+ * Load the Frame Control field
+ */
+ s_load_fc = new_stmt(BPF_LD|BPF_IND|BPF_B);
+ s_load_fc->s.k = 0;
+ } else {
+ /*
+ * There is no variable-length header preceding the
+ * link-layer header; add in off_ll, which, if there's
+ * a fixed-length header preceding the link-layer header,
+ * is the length of that header.
+ */
+
+ /*
+ * We need to load the Frame control directly, and
+ * then load X with a fake 0, i.e. the length of the
+ * non-existing prepended header
+ */
+
+ /*
+ * TODO GV: I'm not sure if 0 is the right constant in this
+ * case. If the link layer has a fixed length prepended header,
+ * that should be the value that we put here
+ */
+
+ /* Load 0 into X */
+ s_load_x_0 = new_stmt(BPF_LDX|BPF_IMM);
+ s_load_x_0->s.k = 0;
+
+ /*
+ * TODO GV: I'm not sure if 0 is the right constant in this
+ * case. If the link layer has a fixed length prepended header,
+ * that should be the value that we put here
+ */
+
+ /*
+ * load the Frame Control with absolute access
+ */
+ s_load_fc = new_stmt(BPF_LD|BPF_ABS|BPF_B);
+ s_load_fc->s.k = 0;
+ s = s_load_x_0;
+ }
+
+ /*
+ * Generate the common instructions to check if it's a data frame
+ * and if so compute the 802.11 header length
+ */
+ sjset_data_frame_1 = new_stmt(JMP(BPF_JSET)); // b3 should be 1
+ sjset_data_frame_1->s.k = 0x8;
+
+ sjset_data_frame_2 = new_stmt(JMP(BPF_JSET)); // b2 should be 0
+ sjset_data_frame_2->s.k = 0x04;
+
+ sjset_qos = new_stmt(JMP(BPF_JSET));
+ sjset_qos->s.k = 0x80; //QOS bit
+
+ s_ld_a_2 = new_stmt(BPF_LD|BPF_IMM);
+ s_ld_a_2->s.k = 2;
+
+ s_add_a_x = new_stmt(BPF_ALU|BPF_ADD|BPF_X);
+ s_a_to_x = new_stmt(BPF_MISC|BPF_TAX);
+
+ s_load = new_stmt(BPF_LD|BPF_IND|size);
+ s_load->s.k = offset;
+
+ sjset_data_frame_1->s.jt = sjset_data_frame_2;
+ sjset_data_frame_1->s.jf = s_load;
+
+ sjset_data_frame_2->s.jt = s_load;
+ sjset_data_frame_2->s.jf = sjset_qos;
+
+ sjset_qos->s.jt = s_ld_a_2;
+ sjset_qos->s.jf = s_load;
+
+ sappend(s, s_load_fc);
+ sappend(s_load_fc, sjset_data_frame_1);
+ sappend(sjset_data_frame_1, sjset_data_frame_2);
+ sappend(sjset_data_frame_2, sjset_qos);
+ sappend(sjset_qos, s_ld_a_2);
+ sappend(s_ld_a_2, s_add_a_x);
+ sappend(s_add_a_x,s_a_to_x);
+ sappend(s_a_to_x, s_load);
+
+ return s;
+}
/*
* Load a value relative to the beginning of the specified header.
@@ -1367,6 +1504,22 @@
s = gen_load_llrel(offset, size);
break;
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+
+ case OR_LINK_AFTER_WIRELESS_HDR:
+ if (linktype != DLT_IEEE802_11_RADIO
+ && linktype != DLT_PPI
+ && linktype != DLT_IEEE802_11
+ && linktype != DLT_PRISM_HEADER
+ && linktype != DLT_IEEE802_11_RADIO_AVS)
+ {
+ abort();
+ return NULL;
+ }
+ s = gen_load_ll_after_802_11_rel(offset + 24, size);
+ break;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
case OR_NET:
s = gen_load_llrel(off_nl + offset, size);
break;
@@ -2163,11 +2316,17 @@
break;
case DLT_PPI:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_IEEE802_11:
+#ifdef ENABLE_WLAN_FILTERING_PATCH
+ return gen_802_11_llc_linktype(proto);
+ /*NOTREACHED*/
+ break;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
case DLT_FDDI:
case DLT_IEEE802:
- case DLT_IEEE802_11:
case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
case DLT_PRISM_HEADER:
case DLT_ATM_RFC1483:
case DLT_ATM_CLIP:
@@ -2711,6 +2870,113 @@
}
}
+/*
+ * 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_802_11_llc_linktype(proto)
+ int proto;
+{
+ struct block *b_check_data_frame;
+ struct block *b_check_linktype;
+
+ b_check_data_frame = gen_check_802_11_data_frame();
+
+ /*
+ * XXX - generate the code that discards non data frames
+ */
+ switch (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 types <= ETHERMTU
+ * (i.e., other SAP values)?
+ */
+ b_check_linktype = gen_cmp(OR_LINK_AFTER_WIRELESS_HDR, 0, BPF_H, (bpf_u_int32)
+ ((proto << 8) | proto));
+ break;
+
+ case LLCSAP_IPX:
+ /*
+ * XXX - are there ever SNAP frames for IPX on
+ * non-Ethernet 802.x networks?
+ */
+ b_check_linktype = gen_cmp(OR_LINK_AFTER_WIRELESS_HDR, 0, BPF_B,
+ (bpf_int32)LLCSAP_IPX);
+
+ break;
+
+#if 0
+ 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(0x080007, ETHERTYPE_ATALK, off_linktype);
+#endif
+ default:
+ /*
+ * XXX - we don't have to check for IPX 802.3
+ * here, but should we check for the IPX Ethertype?
+ */
+ if (proto <= ETHERMTU) {
+ /*
+ * This is an LLC SAP value, so check
+ * the DSAP.
+ */
+ b_check_linktype = gen_cmp(OR_LINK_AFTER_WIRELESS_HDR, 0, BPF_B,
+ (bpf_int32)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(0x000000, proto,
+ * off_linktype);
+ *
+ * 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.
+ */
+ b_check_linktype = gen_cmp(OR_LINK_AFTER_WIRELESS_HDR, 0+6, BPF_H,
+ (bpf_int32)proto);
+ }
+ }
+
+ gen_and(b_check_data_frame, b_check_linktype);
+ return b_check_linktype;
+
+}
+
+
+
static struct block *
gen_hostop(addr, mask, dir, proto, src_off, dst_off)
bpf_u_int32 addr;
@@ -2925,6 +3191,17 @@
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
+ *
+ */
+ no_optimize = 1;
+#endif /* ENABLE_WLAN_FILTERING_PATCH */
+
switch (dir) {
case Q_SRC:
/*
@@ -4713,6 +4990,32 @@
#endif
}
+static struct block *
+gen_check_802_11_data_frame()
+{
+ struct slist *s;
+ struct block *b0, *b1;
+ /*
+ * Now check for a data frame.
+ * I.e, check "link[0] & 0x08".
+ */
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b0 = new_block(JMP(BPF_JSET));
+ b0->s.k = 0x08;
+ b0->stmts = s;
+
+ s = gen_load_a(OR_LINK, 0, BPF_B);
+ b1 = new_block(JMP(BPF_JSET));
+ 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