*************** *** 24,29 **** "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.51 2007/06/14 20:54:12 gianluca Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif --- 24,31 ---- "@(#) $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,150 **** 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 */ }; /* --- 146,153 ---- 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_LINK_AFTER_WIRELESS_HDR /* After the 802.11 variable length header */ }; /* *************** *** 199,204 **** 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_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); --- 202,208 ---- 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,247 **** 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_ppi_dlt_check(); static struct block *gen_msg_abbrev(int type); --- 246,252 ---- 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,1350 **** return s; } /* * Load a value relative to the beginning of the specified header. --- 1350,1487 ---- 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,1372 **** s = gen_load_llrel(offset, size); break; case OR_NET: s = gen_load_llrel(off_nl + offset, size); break; --- 1504,1525 ---- 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,2173 **** break; case DLT_PPI: 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: --- 2316,2332 ---- 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_RADIO_AVS: case DLT_PRISM_HEADER: case DLT_ATM_RFC1483: case DLT_ATM_CLIP: *************** *** 2711,2716 **** } } static struct block * gen_hostop(addr, mask, dir, proto, src_off, dst_off) bpf_u_int32 addr; --- 2870,2982 ---- } } + /* + * 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,2930 **** register struct block *b0, *b1, *b2; register struct slist *s; switch (dir) { case Q_SRC: /* --- 3191,3207 ---- 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,4718 **** #endif } /* * Generate code that checks whether the packet is a packet for protocol --- 4990,5021 ---- #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