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