--- 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