X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/53d0f571dc6892341a1dfa30f31aeddbbef303e3..refs/heads/libpcap-1.0:/gencode.c diff --git a/gencode.c b/gencode.c index 4a3fbf1e..5548e6fd 100644 --- a/gencode.c +++ b/gencode.c @@ -21,7 +21,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.290.2.5 2007-11-05 18:38:20 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 @@ -68,6 +68,7 @@ static const char rcsid[] _U_ = #include "nlpid.h" #include "llc.h" #include "gencode.h" +#include "ieee80211.h" #include "atmuni31.h" #include "sunatmpos.h" #include "ppp.h" @@ -146,7 +147,8 @@ static struct block *root; */ enum e_offrel { OR_PACKET, /* relative to the beginning of the packet */ - OR_LINK, /* relative to the link-layer header */ + OR_LINK, /* relative to the beginning of the link-layer header */ + OR_MACPL, /* relative to the end of the MAC-layer header */ 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 */ @@ -191,6 +193,7 @@ static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *); static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32); static struct slist *gen_load_llrel(u_int, u_int); +static struct slist *gen_load_macplrel(u_int, u_int); static struct slist *gen_load_a(enum e_offrel, u_int, u_int); static struct slist *gen_loadx_iphdrlen(void); static struct block *gen_uncond(int); @@ -198,12 +201,16 @@ static inline struct block *gen_true(void); static inline struct block *gen_false(void); static struct block *gen_ether_linktype(int); static struct block *gen_linux_sll_linktype(int); -static void insert_radiotap_load_llprefixlen(struct block *); -static void insert_ppi_load_llprefixlen(struct block *); -static void insert_load_llprefixlen(struct block *); +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 void insert_compute_vloffsets(struct block *); static struct slist *gen_llprefixlen(void); +static struct slist *gen_off_macpl(void); +static int ethertype_to_ppptype(int); static struct block *gen_linktype(int); -static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int); +static struct block *gen_snap(bpf_u_int32, bpf_u_int32); 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 @@ -248,6 +255,7 @@ static struct slist *xfer_to_x(struct arth *); 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(void); static struct block *gen_ppi_dlt_check(void); static struct block *gen_msg_abbrev(int type); @@ -491,18 +499,6 @@ finish_parse(p) struct block *p; { struct block *ppi_dlt_check; - - ppi_dlt_check = gen_ppi_dlt_check(); - - if (ppi_dlt_check != NULL) - { - gen_and(ppi_dlt_check, p); - } - - backpatch(p, gen_retblk(snaplen)); - p->sense = !p->sense; - backpatch(p, gen_retblk(0)); - root = p->head; /* * Insert before the statements of the first (root) block any @@ -513,13 +509,30 @@ finish_parse(p) * statements of all blocks that use those lengths and that * have no predecessors that use them, so that we only compute * the lengths if we need them. There might be even better - * approaches than that. However, as we're currently only - * handling variable-length radiotap headers, and as all - * filtering expressions other than raw link[M:N] tests - * require the length of that header, doing more for that - * header length isn't really worth the effort. + * approaches than that. + * + * However, those strategies would be more complicated, and + * as we don't generate code to compute a length if the + * program has no tests that use the length, and as most + * tests will probably use those lengths, we would just + * postpone computing the lengths so that it's not done + * for tests that fail early, and it's not clear that's + * worth the effort. + */ + insert_compute_vloffsets(p->head); + + /* + * For DLT_PPI captures, generate a check of the per-packet + * DLT value to make sure it's DLT_IEEE802_11. */ - insert_load_llprefixlen(root); + ppi_dlt_check = gen_ppi_dlt_check(); + if (ppi_dlt_check != NULL) + gen_and(ppi_dlt_check, p); + + backpatch(p, gen_retblk(snaplen)); + p->sense = !p->sense; + backpatch(p, gen_retblk(0)); + root = p->head; } void @@ -682,13 +695,7 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v) * Various code constructs need to know the layout of the data link * layer. These variables give the necessary offsets from the beginning * of the packet data. - * - * If the link layer has variable_length headers, the offsets are offsets - * from the end of the link-link-layer header, and "reg_ll_size" is - * the register number for a register containing the length of the - * link-layer header. Otherwise, "reg_ll_size" is -1. */ -static int reg_ll_size; /* * This is the offset of the beginning of the link-layer header from @@ -701,12 +708,48 @@ static int reg_ll_size; static u_int off_ll; /* - * This is the offset of the beginning of the MAC-layer header. + * If there's a variable-length header preceding the link-layer header, + * "reg_off_ll" is the register number for a register containing the + * length of that header, and therefore the offset of the link-layer + * header from the beginning of the raw packet data. Otherwise, + * "reg_off_ll" is -1. + */ +static int reg_off_ll; + +/* + * This is the offset of the beginning of the MAC-layer header from + * the beginning of the link-layer header. * It's usually 0, except for ATM LANE, where it's the offset, relative * to the beginning of the raw packet data, of the Ethernet header. */ static u_int off_mac; +/* + * This is the offset of the beginning of the MAC-layer payload, + * from the beginning of the raw packet data. + * + * I.e., it's the sum of the length of the link-layer header (without, + * for example, any 802.2 LLC header, so it's the MAC-layer + * portion of that header), plus any prefix preceding the + * link-layer header. + */ +static u_int off_macpl; + +/* + * This is 1 if the offset of the beginning of the MAC-layer payload + * from the beginning of the link-layer header is variable-length. + */ +static int off_macpl_is_variable; + +/* + * If the link layer has variable_length headers, "reg_off_macpl" + * is the register number for a register containing the length of the + * link-layer header plus the length of any variable-length header + * preceding the link-layer header. Otherwise, "reg_off_macpl" + * is -1. + */ +static int reg_off_macpl; + /* * "off_linktype" is the offset to information in the link-layer header * giving the packet type. This offset is relative to the beginning @@ -729,6 +772,13 @@ static u_int off_mac; */ static u_int off_linktype; +/* + * TRUE if "pppoes" appeared in the filter; it causes link-layer type + * checks to check the PPP header, assumed to follow a LAN-style link- + * layer header and a PPPoE session header. + */ +static int is_pppoes = 0; + /* * TRUE if the link layer includes an ATM pseudo-header. */ @@ -768,8 +818,8 @@ static u_int off_payload; /* * These are offsets to the beginning of the network-layer header. - * They are relative to the beginning of the link-layer header (i.e., - * they don't include off_ll). + * They are relative to the beginning of the MAC-layer payload (i.e., + * they don't include off_ll or off_macpl). * * If the link layer never uses 802.2 LLC: * @@ -815,6 +865,11 @@ init_linktype(p) off_proto = -1; off_payload = -1; + /* + * And that we're not doing PPPoE. + */ + is_pppoes = 0; + /* * And assume we're not doing SS7. */ @@ -825,34 +880,40 @@ init_linktype(p) off_sls = -1; /* - * Also assume it's not 802.11 with a fixed-length radio header. + * Also assume it's not 802.11. */ off_ll = 0; + off_macpl = 0; + off_macpl_is_variable = 0; orig_linktype = -1; orig_nl = -1; label_stack_depth = 0; - reg_ll_size = -1; + reg_off_ll = -1; + reg_off_macpl = -1; switch (linktype) { case DLT_ARCNET: off_linktype = 2; - off_nl = 6; /* XXX in reality, variable! */ - off_nl_nosnap = 6; /* no 802.2 LLC */ + off_macpl = 6; + off_nl = 0; /* XXX in reality, variable! */ + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_ARCNET_LINUX: off_linktype = 4; - off_nl = 8; /* XXX in reality, variable! */ - off_nl_nosnap = 8; /* no 802.2 LLC */ + off_macpl = 8; + off_nl = 0; /* XXX in reality, variable! */ + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_EN10MB: off_linktype = 12; - off_nl = 14; /* Ethernet II */ - off_nl_nosnap = 17; /* 802.3+802.2 */ + off_macpl = 14; /* Ethernet header length */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ return; case DLT_SLIP: @@ -861,29 +922,33 @@ init_linktype(p) * header is hacked into our SLIP driver. */ off_linktype = -1; - off_nl = 16; - off_nl_nosnap = 16; /* no 802.2 LLC */ + off_macpl = 16; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_SLIP_BSDOS: /* XXX this may be the same as the DLT_PPP_BSDOS case */ off_linktype = -1; /* XXX end */ - off_nl = 24; - off_nl_nosnap = 24; /* no 802.2 LLC */ + off_macpl = 24; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_NULL: case DLT_LOOP: off_linktype = 0; - off_nl = 4; - off_nl_nosnap = 4; /* no 802.2 LLC */ + off_macpl = 4; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_ENC: off_linktype = 0; - off_nl = 12; - off_nl_nosnap = 12; /* no 802.2 LLC */ + off_macpl = 12; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_PPP: @@ -891,8 +956,9 @@ init_linktype(p) case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ off_linktype = 2; - off_nl = 4; - off_nl_nosnap = 4; /* no 802.2 LLC */ + off_macpl = 4; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_PPP_ETHER: @@ -901,14 +967,16 @@ init_linktype(p) * only covers session state. */ off_linktype = 6; - off_nl = 8; - off_nl_nosnap = 8; /* no 802.2 LLC */ + off_macpl = 8; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_PPP_BSDOS: off_linktype = 5; - off_nl = 24; - off_nl_nosnap = 24; /* no 802.2 LLC */ + off_macpl = 24; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_FDDI: @@ -924,12 +992,12 @@ init_linktype(p) #ifdef PCAP_FDDIPAD off_linktype += pcap_fddipad; #endif - off_nl = 21; /* FDDI+802.2+SNAP */ - off_nl_nosnap = 16; /* FDDI+802.2 */ + off_macpl = 13; /* FDDI MAC header length */ #ifdef PCAP_FDDIPAD - off_nl += pcap_fddipad; - off_nl_nosnap += pcap_fddipad; + off_macpl += pcap_fddipad; #endif + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ return; case DLT_IEEE802: @@ -957,11 +1025,15 @@ init_linktype(p) * 8 - figure out which byte that is). */ off_linktype = 14; - off_nl = 22; /* Token Ring+802.2+SNAP */ - off_nl_nosnap = 17; /* Token Ring+802.2 */ + off_macpl = 14; /* Token Ring MAC header length */ + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ 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. @@ -970,90 +1042,37 @@ init_linktype(p) * 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_nl = 32; /* 802.11+802.2+SNAP */ - off_nl_nosnap = 27; /* 802.11+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_nl = 32; /* Prism+802.11+802.2+SNAP */ - off_nl_nosnap = 27; /* Prism+802.11+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 header is 64 bytes long, at least in its - * current incarnation. - * - * XXX - same variable-length header problem, only - * more so; this header is also variable-length, - * with the length being the 32-bit big-endian - * number at an offset of 4 from the beginning - * of the radio header. We should handle that the - * same way we handle the length at the beginning - * of the radiotap 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_ll = 64; - off_linktype = 24; - off_nl = 32; /* Radio+802.11+802.2+SNAP */ - off_nl_nosnap = 27; /* Radio+802.11+802.2 */ + 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_nl = 32; /* 802.11+802.2+SNAP */ - off_nl_nosnap = 27; /* 802.11+802.2 */ + 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_ATM_RFC1483: @@ -1070,6 +1089,7 @@ init_linktype(p) * PPPo{A,E} and a PPP protocol of IP and.... */ off_linktype = 0; + off_macpl = 0; /* packet begins with LLC header */ off_nl = 8; /* 802.2+SNAP */ off_nl_nosnap = 3; /* 802.2 */ return; @@ -1083,23 +1103,26 @@ init_linktype(p) off_vpi = SUNATM_VPI_POS; off_vci = SUNATM_VCI_POS; off_proto = PROTO_POS; - off_mac = -1; /* LLC-encapsulated, so no MAC-layer header */ + off_mac = -1; /* assume LLC-encapsulated, so no MAC-layer header */ off_payload = SUNATM_PKT_BEGIN_POS; off_linktype = off_payload; - off_nl = off_payload+8; /* 802.2+SNAP */ - off_nl_nosnap = off_payload+3; /* 802.2 */ + off_macpl = off_payload; /* if LLC-encapsulated */ + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ return; case DLT_RAW: off_linktype = -1; + off_macpl = 0; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ off_linktype = 14; - off_nl = 16; - off_nl_nosnap = 16; /* no 802.2 LLC */ + off_macpl = 16; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_LTALK: @@ -1109,6 +1132,7 @@ init_linktype(p) * "long" DDP packet following. */ off_linktype = -1; + off_macpl = 0; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; @@ -1125,8 +1149,9 @@ init_linktype(p) * 2625 says SNAP should be used. */ off_linktype = 16; - off_nl = 24; /* IPFC+802.2+SNAP */ - off_nl_nosnap = 19; /* IPFC+802.2 */ + off_macpl = 16; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ return; case DLT_FRELAY: @@ -1135,6 +1160,7 @@ init_linktype(p) * frames (NLPID of 0x80). */ off_linktype = -1; + off_macpl = 0; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; @@ -1146,14 +1172,16 @@ init_linktype(p) */ case DLT_MFR: off_linktype = -1; + off_macpl = 0; off_nl = 4; off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ return; case DLT_APPLE_IP_OVER_IEEE1394: off_linktype = 16; - off_nl = 18; - off_nl_nosnap = 18; /* no 802.2 LLC */ + off_macpl = 18; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_LINUX_IRDA: @@ -1161,6 +1189,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1170,21 +1199,24 @@ init_linktype(p) * 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_SYMANTEC_FIREWALL: off_linktype = 6; - off_nl = 44; /* Ethernet II */ - off_nl_nosnap = 44; /* XXX - what does it do with 802.3 packets? */ + off_macpl = 44; + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ return; #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: off_linktype = 0; - off_nl = PFLOG_HDRLEN; - off_nl_nosnap = PFLOG_HDRLEN; /* no 802.2 LLC */ + off_macpl = PFLOG_HDRLEN; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ return; #endif @@ -1195,26 +1227,30 @@ init_linktype(p) case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_FRELAY: off_linktype = 4; - off_nl = 4; + off_macpl = 4; + off_nl = 0; off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_ATM1: - off_linktype = 4; /* in reality variable between 4-8 */ - off_nl = 4; - off_nl_nosnap = 14; + off_linktype = 4; /* in reality variable between 4-8 */ + off_macpl = 4; /* in reality variable between 4-8 */ + off_nl = 0; + off_nl_nosnap = 10; return; case DLT_JUNIPER_ATM2: - off_linktype = 8; /* in reality variable between 8-12 */ - off_nl = 8; - off_nl_nosnap = 18; + off_linktype = 8; /* in reality variable between 8-12 */ + off_macpl = 8; /* in reality variable between 8-12 */ + off_nl = 0; + off_nl_nosnap = 10; return; /* frames captured on a Juniper PPPoE service PIC * contain raw ethernet frames */ case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_ETHER: + off_macpl = 14; off_linktype = 16; off_nl = 18; /* Ethernet II */ off_nl_nosnap = 21; /* 802.3+802.2 */ @@ -1222,48 +1258,56 @@ init_linktype(p) case DLT_JUNIPER_PPPOE_ATM: off_linktype = 4; - off_nl = 6; - off_nl_nosnap = -1; /* no 802.2 LLC */ + off_macpl = 6; + off_nl = 0; + off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_GGSN: off_linktype = 6; - off_nl = 12; - off_nl_nosnap = -1; /* no 802.2 LLC */ + off_macpl = 12; + off_nl = 0; + off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_ES: off_linktype = 6; - off_nl = -1; /* not really a network layer but raw IP adresses */ + off_macpl = -1; /* not really a network layer but raw IP addresses */ + off_nl = -1; /* not really a network layer but raw IP addresses */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_MONITOR: off_linktype = 12; - off_nl = 12; /* raw IP/IP6 header */ + off_macpl = 12; + off_nl = 0; /* raw IP/IP6 header */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_SERVICES: off_linktype = 12; + off_macpl = -1; /* L3 proto location dep. on cookie type */ off_nl = -1; /* L3 proto location dep. on cookie type */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_VP: off_linktype = 18; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; case DLT_JUNIPER_ST: off_linktype = 18; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; case DLT_JUNIPER_ISM: off_linktype = 8; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1275,6 +1319,7 @@ init_linktype(p) off_dpc = 4; off_sls = 7; off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1286,6 +1331,7 @@ init_linktype(p) off_dpc = 8; off_sls = 11; off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1297,6 +1343,7 @@ init_linktype(p) off_dpc = 24; off_sls = 27; off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1304,8 +1351,9 @@ init_linktype(p) #ifdef DLT_PFSYNC case DLT_PFSYNC: off_linktype = -1; - off_nl = 4; - off_nl_nosnap = 4; + off_macpl = 4; + off_nl = 0; + off_nl_nosnap = 0; return; #endif @@ -1314,6 +1362,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1323,6 +1372,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1332,6 +1382,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1341,6 +1392,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1350,6 +1402,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1359,6 +1412,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1368,6 +1422,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1377,6 +1432,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1386,6 +1442,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1395,6 +1452,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1404,6 +1462,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1413,6 +1472,7 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; + off_macpl = -1; off_nl = -1; off_nl_nosnap = -1; return; @@ -1422,10 +1482,41 @@ init_linktype(p) * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; /* variable, min 15, max 71 steps of 7 */ + off_macpl = -1; off_nl = -1; /* variable, min 16, max 71 steps of 7 */ 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 */ @@ -1476,6 +1567,46 @@ gen_load_llrel(offset, size) return s; } +/* + * Load a value relative to the beginning of the MAC-layer payload. + */ +static struct slist * +gen_load_macplrel(offset, size) + u_int offset, size; +{ + struct slist *s, *s2; + + s = gen_off_macpl(); + + /* + * If s is non-null, the offset of the MAC-layer payload is + * variable, and s points to a list of instructions that + * arrange that the X register contains that offset. + * + * Otherwise, the offset of the MAC-layer payload is constant, + * and is in off_macpl. + */ + if (s != NULL) { + /* + * The offset of the MAC-layer payload is in the X + * register. Do an indirect load, to use the X register + * as an offset. + */ + s2 = new_stmt(BPF_LD|BPF_IND|size); + s2->s.k = offset; + sappend(s, s2); + } else { + /* + * The offset of the MAC-layer payload is constant, + * and is in off_macpl; load the value at that offset + * plus the specified offset. + */ + s = new_stmt(BPF_LD|BPF_ABS|size); + s->s.k = off_macpl + offset; + } + return s; +} + /* * Load a value relative to the beginning of the specified header. */ @@ -1497,12 +1628,16 @@ gen_load_a(offrel, offset, size) s = gen_load_llrel(offset, size); break; + case OR_MACPL: + s = gen_load_macplrel(offset, size); + break; + case OR_NET: - s = gen_load_llrel(off_nl + offset, size); + s = gen_load_macplrel(off_nl + offset, size); break; case OR_NET_NOSNAP: - s = gen_load_llrel(off_nl_nosnap + offset, size); + s = gen_load_macplrel(off_nl_nosnap + offset, size); break; case OR_TRAN_IPV4: @@ -1515,21 +1650,22 @@ gen_load_a(offrel, offset, size) s = gen_loadx_iphdrlen(); /* - * Load the item at {offset of the link-layer header} + - * {offset, relative to the start of the link-layer - * header, of the IPv4 header} + {length of the IPv4 header} + + * Load the item at {offset of the MAC-layer payload} + + * {offset, relative to the start of the MAC-layer + * paylod, of the IPv4 header} + {length of the IPv4 header} + * {specified offset}. * - * (If the link-layer is variable-length, it's included - * in the value in the X register, and off_ll is 0.) + * (If the offset of the MAC-layer payload is variable, + * it's included in the value in the X register, and + * off_macpl is 0.) */ s2 = new_stmt(BPF_LD|BPF_IND|size); - s2->s.k = off_ll + off_nl + offset; + s2->s.k = off_macpl + off_nl + offset; sappend(s, s2); break; case OR_TRAN_IPV6: - s = gen_load_llrel(off_nl + 40 + offset, size); + s = gen_load_macplrel(off_nl + 40 + offset, size); break; default: @@ -1549,12 +1685,15 @@ gen_loadx_iphdrlen() { struct slist *s, *s2; - s = gen_llprefixlen(); + s = gen_off_macpl(); 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. + * link-layer header, or the link-layer header is itself + * variable-length. "s" points to a list of statements + * that put the offset of the MAC-layer payload into + * the X register. + * * The 4*([k]&0xf) addressing mode can't be used, as we * don't have a constant offset, so we have to load the * value in question into the A register and add to it @@ -1572,22 +1711,24 @@ gen_loadx_iphdrlen() /* * The A register now contains the length of the - * IP header. We need to add to it the length - * of the prefix preceding the link-layer - * header, which is still in the X register, and - * move the result into the X register. + * IP header. We need to add to it the offset of + * the MAC-layer payload, which is still in the X + * register, and move the result into the X register. */ sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(BPF_MISC|BPF_TAX)); } 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. + * link-layer header, and the link-layer header is + * fixed-length; load the length of the IPv4 header, + * which is at an offset of off_nl from the beginning + * of the MAC-layer payload, and thus at an offset + * of off_mac_pl + off_nl from the beginning of the + * raw packet data. */ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); - s->s.k = off_ll + off_nl; + s->s.k = off_macpl + off_nl; } return s; } @@ -1661,7 +1802,7 @@ gen_ether_linktype(proto) */ b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); gen_not(b0); - b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32) + b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; @@ -1699,17 +1840,15 @@ gen_ether_linktype(proto) * This generates code to check both for the * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. */ - b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B, - (bpf_int32)LLCSAP_IPX); - b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, - (bpf_int32)0xFFFF); + b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)0xFFFF); gen_or(b0, b1); /* * Now we add code to check for SNAP frames with * ETHERTYPE_IPX, i.e. Ethernet_SNAP. */ - b0 = gen_snap(0x000000, ETHERTYPE_IPX, off_linktype + 2); + b0 = gen_snap(0x000000, ETHERTYPE_IPX); gen_or(b0, b1); /* @@ -1764,11 +1903,9 @@ gen_ether_linktype(proto) * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) - b1 = gen_snap(0x080007, ETHERTYPE_ATALK, - off_linktype + 2); + b1 = gen_snap(0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ - b1 = gen_snap(0x000000, ETHERTYPE_AARP, - off_linktype + 2); + b1 = gen_snap(0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* @@ -1845,7 +1982,7 @@ gen_linux_sll_linktype(proto) * (i.e., other SAP values)? */ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); - b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32) + b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; @@ -1876,10 +2013,8 @@ gen_linux_sll_linktype(proto) * then put a check for LINUX_SLL_P_802_2 frames * before it. */ - b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B, - (bpf_int32)LLCSAP_IPX); - b1 = gen_snap(0x000000, ETHERTYPE_IPX, - off_linktype + 2); + b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_snap(0x000000, ETHERTYPE_IPX); gen_or(b0, b1); b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); gen_and(b0, b1); @@ -1927,11 +2062,9 @@ gen_linux_sll_linktype(proto) * type of ETHERTYPE_AARP (Appletalk ARP). */ if (proto == ETHERTYPE_ATALK) - b1 = gen_snap(0x080007, ETHERTYPE_ATALK, - off_linktype + 2); + b1 = gen_snap(0x080007, ETHERTYPE_ATALK); else /* proto == ETHERTYPE_AARP */ - b1 = gen_snap(0x000000, ETHERTYPE_AARP, - off_linktype + 2); + b1 = gen_snap(0x000000, ETHERTYPE_AARP); gen_and(b0, b1); /* @@ -1955,7 +2088,7 @@ gen_linux_sll_linktype(proto) */ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2); - b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B, + b1 = gen_cmp(OR_LINK, off_macpl, BPF_B, (bpf_int32)proto); gen_and(b0, b1); return b1; @@ -1975,18 +2108,169 @@ gen_linux_sll_linktype(proto) } } -static void -insert_radiotap_load_llprefixlen(b) - struct block *b; +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; /* - * Prepend to the statements in this block code to load the - * length of the radiotap header into the register assigned - * to hold that length, if one has been assigned. + * 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_ll_size != -1) { + 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() +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the radiotap 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 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap @@ -2021,7 +2305,7 @@ insert_radiotap_load_llprefixlen(b) * it. */ s2 = new_stmt(BPF_ST); - s2->s.k = reg_ll_size; + s2->s.k = reg_off_ll; sappend(s1, s2); /* @@ -2030,13 +2314,9 @@ insert_radiotap_load_llprefixlen(b) s2 = new_stmt(BPF_MISC|BPF_TAX); sappend(s1, s2); - /* - * Now append all the existing statements in this - * block to these statements. - */ - sappend(s1, b->stmts); - b->stmts = s1; - } + return (s1); + } else + return (NULL); } /* @@ -2045,21 +2325,21 @@ insert_radiotap_load_llprefixlen(b) * 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. + * DLT_IEEE802_11) we generate code to check for this too; + * that's done in finish_parse(). */ -static void -insert_ppi_load_llprefixlen(b) - struct block *b; +static struct slist * +gen_load_ppi_llprefixlen() { struct slist *s1, *s2; /* - * Prepend to the statements in this block code to load the - * length of the radiotap header into the register assigned - * to hold that length, if one has been assigned. + * Generate code to load the length of the radiotap header + * into the register assigned to hold that length, if one has + * been assigned. */ - if (reg_ll_size != -1) { - /* + if (reg_off_ll != -1) { + /* * The 2 bytes at offsets of 2 and 3 from the beginning * of the radiotap header are the length of the radiotap * header; unfortunately, it's little-endian, so we have @@ -2093,7 +2373,7 @@ insert_ppi_load_llprefixlen(b) * it. */ s2 = new_stmt(BPF_ST); - s2->s.k = reg_ll_size; + s2->s.k = reg_off_ll; sappend(s1, s2); /* @@ -2102,16 +2382,295 @@ insert_ppi_load_llprefixlen(b) 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. + * 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_802_11_header_len(struct slist *s, struct slist *snext) +{ + struct slist *s2; + struct slist *sjset_data_frame_1; + struct slist *sjset_data_frame_2; + struct slist *sjset_qos; + struct slist *sjset_radiotap_flags; + struct slist *sjset_radiotap_tsft; + struct slist *sjset_tsft_datapad, *sjset_notsft_datapad; + struct slist *s_roundup; + + if (reg_off_macpl == -1) { + /* + * No register has been assigned to the offset of + * the MAC-layer payload, which means nobody needs + * it; don't bother computing it - just return + * what we already have. + */ + return (s); + } + + /* + * This code is not compatible with the optimizer, as + * we are generating jmp instructions within a normal + * slist of instructions + */ + no_optimize = 1; + + /* + * 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) { /* - * Now append all the existing statements in this - * block to these statements. + * There is no variable-length header preceding the + * link-layer header. + * + * Load the length of the fixed-length prefix preceding + * the link-layer header (if any) into the X register, + * and store it in the reg_off_macpl register. + * That length is off_ll. */ - sappend(s1, b->stmts); - b->stmts = s1; + s = new_stmt(BPF_LDX|BPF_IMM); + s->s.k = off_ll; + } + + /* + * The X register contains the offset of the beginning of the + * link-layer header; add 24, which is the minimum length + * of the MAC header for a data frame, to that, and store it + * in reg_off_macpl, and then load the Frame Control field, + * which is at the offset in the X register, with an indexed load. + */ + s2 = new_stmt(BPF_MISC|BPF_TXA); + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s2->s.k = 24; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = reg_off_macpl; + sappend(s, s2); + + s2 = new_stmt(BPF_LD|BPF_IND|BPF_B); + s2->s.k = 0; + sappend(s, s2); + + /* + * Check the Frame Control field to see if this is a data frame; + * a data frame has the 0x08 bit (b3) in that field set and the + * 0x04 bit (b2) clear. + */ + sjset_data_frame_1 = new_stmt(JMP(BPF_JSET)); + sjset_data_frame_1->s.k = 0x08; + sappend(s, sjset_data_frame_1); + + /* + * If b3 is set, test b2, otherwise go to the first statement of + * the rest of the program. + */ + sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(JMP(BPF_JSET)); + sjset_data_frame_2->s.k = 0x04; + sappend(s, sjset_data_frame_2); + sjset_data_frame_1->s.jf = snext; + + /* + * If b2 is not set, this is a data frame; test the QoS bit. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_data_frame_2->s.jt = snext; + sjset_data_frame_2->s.jf = sjset_qos = new_stmt(JMP(BPF_JSET)); + sjset_qos->s.k = 0x80; /* QoS bit */ + sappend(s, sjset_qos); + + /* + * If it's set, add 2 to reg_off_macpl, to skip the QoS + * field. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_qos->s.jt = s2 = new_stmt(BPF_LD|BPF_MEM); + s2->s.k = reg_off_macpl; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 2; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = reg_off_macpl; + sappend(s, s2); + + /* + * If we have a radiotap header, look at it to see whether + * there's Atheros padding between the MAC-layer header + * and the payload. + * + * Note: all of the fields in the radiotap header are + * little-endian, so we byte-swap all of the values + * we test against, as they will be loaded as big-endian + * values. + */ + if (linktype == DLT_IEEE802_11_RADIO) { + /* + * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set + * in the presence flag? + */ + sjset_qos->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_W); + s2->s.k = 4; + sappend(s, s2); + + sjset_radiotap_flags = new_stmt(JMP(BPF_JSET)); + sjset_radiotap_flags->s.k = SWAPLONG(0x00000002); + sappend(s, sjset_radiotap_flags); + + /* + * If not, skip all of this. + */ + sjset_radiotap_flags->s.jf = snext; + + /* + * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set? + */ + sjset_radiotap_tsft = sjset_radiotap_flags->s.jt = + new_stmt(JMP(BPF_JSET)); + sjset_radiotap_tsft->s.k = SWAPLONG(0x00000001); + sappend(s, sjset_radiotap_tsft); + + /* + * If IEEE80211_RADIOTAP_TSFT is set, the flags field is + * at an offset of 16 from the beginning of the raw packet + * data (8 bytes for the radiotap header and 8 bytes for + * the TSFT field). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + sjset_radiotap_tsft->s.jt = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 16; + sappend(s, s2); + + sjset_tsft_datapad = new_stmt(JMP(BPF_JSET)); + sjset_tsft_datapad->s.k = 0x20; + sappend(s, sjset_tsft_datapad); + + /* + * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is + * at an offset of 8 from the beginning of the raw packet + * data (8 bytes for the radiotap header). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + sjset_radiotap_tsft->s.jf = s2 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 8; + sappend(s, s2); + + sjset_notsft_datapad = new_stmt(JMP(BPF_JSET)); + sjset_notsft_datapad->s.k = 0x20; + sappend(s, sjset_notsft_datapad); + + /* + * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is + * set, round the length of the 802.11 header to + * a multiple of 4. Do that by adding 3 and then + * dividing by and multiplying by 4, which we do by + * ANDing with ~3. + */ + s_roundup = new_stmt(BPF_LD|BPF_MEM); + s_roundup->s.k = reg_off_macpl; + sappend(s, s_roundup); + s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 3; + sappend(s, s2); + s2 = new_stmt(BPF_ALU|BPF_AND|BPF_IMM); + s2->s.k = ~3; + sappend(s, s2); + s2 = new_stmt(BPF_ST); + s2->s.k = reg_off_macpl; + sappend(s, s2); + + sjset_tsft_datapad->s.jt = s_roundup; + sjset_tsft_datapad->s.jf = snext; + sjset_notsft_datapad->s.jt = s_roundup; + sjset_notsft_datapad->s.jf = snext; + } else + sjset_qos->s.jf = snext; + + return s; +} + +static void +insert_compute_vloffsets(b) + struct block *b; +{ + struct slist *s; + + /* + * For link-layer types that have a variable-length header + * preceding the link-layer header, generate code to load + * the offset of the link-layer header into the register + * assigned to that offset, if any. + */ + 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; + + case DLT_PPI: + s = gen_load_ppi_llprefixlen(); + break; + + default: + s = NULL; + break; + } + + /* + * For link-layer types that have a variable-length link-layer + * header, generate code to load the offset of the MAC-layer + * payload into the register assigned to that offset, if any. + */ + switch (linktype) { + case DLT_IEEE802_11: + 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; + } + + /* + * If we have any offset-loading code, append all the + * existing statements in the block to those statements, + * and make the resulting list the list of statements + * for the block. + */ + if (s != NULL) { + sappend(s, b->stmts); + b->stmts = s; } } - + static struct block * gen_ppi_dlt_check(void) { @@ -2138,42 +2697,61 @@ gen_ppi_dlt_check(void) return b; } -static void -insert_load_llprefixlen(b) - struct block *b; +static struct slist * +gen_prism_llprefixlen(void) { - switch (linktype) { + struct slist *s; + + if (reg_off_ll == -1) { + /* + * We haven't yet assigned a register for the length + * of the radio header; allocate one. + */ + reg_off_ll = alloc_reg(); + } - /* - * 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. + /* + * Load the register containing the radio length + * into the X register. */ - case DLT_PPI: - insert_ppi_load_llprefixlen(b); - break; + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = reg_off_ll; + return s; +} - case DLT_IEEE802_11_RADIO: - insert_radiotap_load_llprefixlen(b); - break; +static struct slist * +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; - if (reg_ll_size == -1) { + if (reg_off_ll == -1) { /* * We haven't yet assigned a register for the length * of the radiotap header; allocate one. */ - reg_ll_size = alloc_reg(); + reg_off_ll = alloc_reg(); } /* @@ -2181,7 +2759,7 @@ gen_radiotap_llprefixlen(void) * into the X register. */ s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_ll_size; + s->s.k = reg_off_ll; return s; } @@ -2198,46 +2776,135 @@ gen_ppi_llprefixlen(void) { struct slist *s; - if (reg_ll_size == -1) { + if (reg_off_ll == -1) { /* * We haven't yet assigned a register for the length * of the radiotap header; allocate one. */ - reg_ll_size = alloc_reg(); + reg_off_ll = alloc_reg(); + } + + /* + * Load the register containing the PPI length + * into the X register. + */ + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = reg_off_ll; + return s; +} + +/* + * Generate code to compute the link-layer header length, if necessary, + * putting it into the X register, and to return either a pointer to a + * "struct slist" for the list of statements in that code, or NULL if + * no code is necessary. + */ +static struct slist * +gen_llprefixlen(void) +{ + switch (linktype) { + + 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_PPI: + return gen_ppi_llprefixlen(); + + default: + return NULL; + } +} + +/* + * Generate code to load the register containing the offset of the + * MAC-layer payload into the X register; if no register for that offset + * has been allocated, allocate it first. + */ +static struct slist * +gen_off_macpl(void) +{ + struct slist *s; + + if (off_macpl_is_variable) { + if (reg_off_macpl == -1) { + /* + * We haven't yet assigned a register for the offset + * of the MAC-layer payload; allocate one. + */ + reg_off_macpl = alloc_reg(); + } + + /* + * Load the register containing the offset of the MAC-layer + * payload into the X register. + */ + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = reg_off_macpl; + return s; + } else { + /* + * That offset isn't variable, so we don't need to + * generate any code. + */ + return NULL; } - - /* - * Load the register containing the radiotap length - * into the X register. - */ - s = new_stmt(BPF_LDX|BPF_MEM); - s->s.k = reg_ll_size; - return s; } - - /* - * Generate code to compute the link-layer header length, if necessary, - * putting it into the X register, and to return either a pointer to a - * "struct slist" for the list of statements in that code, or NULL if - * no code is necessary. + * Map an Ethernet type to the equivalent PPP type. */ -static struct slist * -gen_llprefixlen(void) +static int +ethertype_to_ppptype(proto) + int proto; { - switch (linktype) { + switch (proto) { - case DLT_PPI: - return gen_ppi_llprefixlen(); + case ETHERTYPE_IP: + proto = PPP_IP; + break; - - case DLT_IEEE802_11_RADIO: - return gen_radiotap_llprefixlen(); +#ifdef INET6 + case ETHERTYPE_IPV6: + proto = PPP_IPV6; + break; +#endif - default: - return NULL; + case ETHERTYPE_DN: + proto = PPP_DECNET; + break; + + case ETHERTYPE_ATALK: + proto = PPP_APPLE; + break; + + case ETHERTYPE_NS: + proto = PPP_NS; + break; + + case LLCSAP_ISONS: + proto = PPP_OSI; + break; + + case LLCSAP_8021D: + /* + * I'm assuming the "Bridging PDU"s that go + * over PPP are Spanning Tree Protocol + * Bridging PDUs. + */ + proto = PPP_BRPDU; + break; + + case LLCSAP_IPX: + proto = PPP_IPX; + break; } + return (proto); } /* @@ -2272,6 +2939,25 @@ gen_linktype(proto) } } + /* + * Are we testing PPPoE packets? + */ + if (is_pppoes) { + /* + * The PPPoE session header is part of the + * MAC-layer payload, so all references + * should be relative to the beginning of + * that payload. + */ + + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + proto = ethertype_to_ppptype(proto); + return gen_cmp(OR_MACPL, off_linktype, BPF_H, (bpf_int32)proto); + } + switch (linktype) { case DLT_EN10MB: @@ -2294,13 +2980,41 @@ gen_linktype(proto) } break; - case DLT_PPI: - case DLT_FDDI: - case DLT_IEEE802: 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: + /* + * Check that we have a data frame. + */ + b0 = gen_check_802_11_data_frame(); + + /* + * Now check for the specified link-layer type. + */ + b1 = gen_llc_linktype(proto); + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + break; + + case DLT_FDDI: + /* + * XXX - check for asynchronous frames, as per RFC 1103. + */ + return gen_llc_linktype(proto); + /*NOTREACHED*/ + break; + + case DLT_IEEE802: + /* + * XXX - check for LLC PDUs, as per IEEE 802.5. + */ + return gen_llc_linktype(proto); + /*NOTREACHED*/ + break; + case DLT_ATM_RFC1483: case DLT_ATM_CLIP: case DLT_IP_OVER_FC: @@ -2385,47 +3099,9 @@ gen_linktype(proto) * We use Ethernet protocol types inside libpcap; * map them to the corresponding PPP protocol types. */ - switch (proto) { - - case ETHERTYPE_IP: - proto = PPP_IP; - break; - -#ifdef INET6 - case ETHERTYPE_IPV6: - proto = PPP_IPV6; - break; -#endif - - case ETHERTYPE_DN: - proto = PPP_DECNET; - break; - - case ETHERTYPE_ATALK: - proto = PPP_APPLE; - break; - - case ETHERTYPE_NS: - proto = PPP_NS; - break; - - case LLCSAP_ISONS: - proto = PPP_OSI; - break; - - case LLCSAP_8021D: - /* - * I'm assuming the "Bridging PDU"s that go - * over PPP are Spanning Tree Protocol - * Bridging PDUs. - */ - proto = PPP_BRPDU; - break; - - case LLCSAP_IPX: - proto = PPP_IPX; - break; - } + proto = ethertype_to_ppptype(proto); + return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); + /*NOTREACHED*/ break; case DLT_PPP_BSDOS: @@ -2436,6 +3112,10 @@ gen_linktype(proto) switch (proto) { case ETHERTYPE_IP: + /* + * Also check for Van Jacobson-compressed IP. + * XXX - do this for other forms of PPP? + */ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_IP); b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJC); gen_or(b0, b1); @@ -2443,42 +3123,12 @@ gen_linktype(proto) gen_or(b1, b0); return b0; -#ifdef INET6 - case ETHERTYPE_IPV6: - proto = PPP_IPV6; - /* more to go? */ - break; -#endif - - case ETHERTYPE_DN: - proto = PPP_DECNET; - break; - - case ETHERTYPE_ATALK: - proto = PPP_APPLE; - break; - - case ETHERTYPE_NS: - proto = PPP_NS; - break; - - case LLCSAP_ISONS: - proto = PPP_OSI; - break; - - case LLCSAP_8021D: - /* - * I'm assuming the "Bridging PDU"s that go - * over PPP are Spanning Tree Protocol - * Bridging PDUs. - */ - proto = PPP_BRPDU; - break; - - case LLCSAP_IPX: - proto = PPP_IPX; - break; + default: + proto = ethertype_to_ppptype(proto); + return gen_cmp(OR_LINK, off_linktype, BPF_H, + (bpf_int32)proto); } + /*NOTREACHED*/ break; case DLT_NULL: @@ -2720,6 +3370,7 @@ gen_linktype(proto) 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: @@ -2731,6 +3382,7 @@ gen_linktype(proto) 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: @@ -2764,12 +3416,7 @@ gen_linktype(proto) /* * Any type not handled above should always have an Ethernet - * type at an offset of "off_linktype". (PPP is partially - * handled above - the protocol type is mapped from the - * Ethernet and LLC types we use internally to the corresponding - * PPP type - but the PPP type is always specified by a value - * at "off_linktype", so we don't have to do the code generation - * above.) + * type at an offset of "off_linktype". */ return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto); } @@ -2782,10 +3429,9 @@ gen_linktype(proto) * code and protocol type in the SNAP header. */ static struct block * -gen_snap(orgcode, ptype, offset) +gen_snap(orgcode, ptype) bpf_u_int32 orgcode; bpf_u_int32 ptype; - u_int offset; { u_char snapblock[8]; @@ -2797,7 +3443,7 @@ gen_snap(orgcode, ptype, offset) snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ - return gen_bcmp(OR_LINK, offset, 8, snapblock); + return gen_bcmp(OR_MACPL, 0, 8, snapblock); } /* @@ -2830,7 +3476,7 @@ gen_llc_linktype(proto) * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ - return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_u_int32) + return gen_cmp(OR_MACPL, 0, BPF_H, (bpf_u_int32) ((proto << 8) | proto)); case LLCSAP_IPX: @@ -2838,7 +3484,7 @@ gen_llc_linktype(proto) * XXX - are there ever SNAP frames for IPX on * non-Ethernet 802.x networks? */ - return gen_cmp(OR_LINK, off_linktype, BPF_B, + return gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX); case ETHERTYPE_ATALK: @@ -2851,7 +3497,7 @@ gen_llc_linktype(proto) * XXX - check for an organization code of * encapsulated Ethernet as well? */ - return gen_snap(0x080007, ETHERTYPE_ATALK, off_linktype); + return gen_snap(0x080007, ETHERTYPE_ATALK); default: /* @@ -2863,8 +3509,7 @@ gen_llc_linktype(proto) * This is an LLC SAP value, so check * the DSAP. */ - return gen_cmp(OR_LINK, off_linktype, BPF_B, - (bpf_int32)proto); + return gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)proto); } else { /* * This is an Ethernet type; we assume that it's @@ -2879,15 +3524,13 @@ gen_llc_linktype(proto) * organization code of 0x000000 (encapsulated * Ethernet), we'd do * - * return gen_snap(0x000000, proto, - * off_linktype); + * return gen_snap(0x000000, proto); * * 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. */ - return gen_cmp(OR_LINK, off_linktype+6, BPF_H, - (bpf_int32)proto); + return gen_cmp(OR_MACPL, 6, BPF_H, (bpf_int32)proto); } } } @@ -3096,7 +3739,8 @@ gen_thostop(eaddr, dir) } /* - * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) + * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and + * various 802.11 + radio headers. */ static struct block * gen_wlanhostop(eaddr, dir) @@ -3106,6 +3750,16 @@ gen_wlanhostop(eaddr, dir) 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: /* @@ -3203,7 +3857,7 @@ gen_wlanhostop(eaddr, dir) * Now check for a data frame. * I.e, check "link[0] & 0x08". */ - gen_load_a(OR_LINK, 0, BPF_B); + s = gen_load_a(OR_LINK, 0, BPF_B); b1 = new_block(JMP(BPF_JSET)); b1->s.k = 0x08; b1->stmts = s; @@ -3372,6 +4026,55 @@ gen_wlanhostop(eaddr, dir) gen_and(b1, b0); return b0; + /* + * XXX - add RA, TA, and BSSID keywords? + */ + case Q_ADDR1: + return (gen_bcmp(OR_LINK, 4, 6, eaddr)); + + case Q_ADDR2: + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + b1 = gen_bcmp(OR_LINK, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + case Q_ADDR3: + /* + * Not present in control frames. + */ + b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_bcmp(OR_LINK, 16, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_ADDR4: + /* + * Present only if the direction mask has both "From DS" + * and "To DS" set. Neither control frames nor management + * frames should have both of those set, so we don't + * check the frame type. + */ + b0 = gen_mcmp(OR_LINK, 1, BPF_B, + IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); + b1 = gen_bcmp(OR_LINK, 24, 6, eaddr); + gen_and(b0, b1); + return b1; + case Q_AND: b0 = gen_wlanhostop(eaddr, Q_SRC); b1 = gen_wlanhostop(eaddr, Q_DST); @@ -3825,10 +4528,10 @@ gen_gateway(eaddr, alist, proto, dir) 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: @@ -4620,7 +5323,8 @@ gen_protochain(v, proto, dir) } /* - * We don't handle variable-length radiotap here headers yet. + * We don't handle variable-length prefixes before the link-layer + * header, or variable-length link-layer headers, here yet. * We might want to add BPF instructions to do the protochain * work, to simplify that and, on platforms that have a BPF * interpreter with the new instructions, let the filtering @@ -4629,11 +5333,15 @@ gen_protochain(v, proto, dir) * branches, and backward branch support is unlikely to appear * in kernel BPF engines.) */ - if (linktype == DLT_IEEE802_11_RADIO) - bpf_error("'protochain' not supported with radiotap headers"); + switch (linktype) { - if (linktype == DLT_PPI) - bpf_error("'protochain' not supported with PPI headers"); + case DLT_IEEE802_11: + 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"); + } no_optimize = 1; /*this code is not compatible with optimzer yet */ @@ -4652,11 +5360,11 @@ gen_protochain(v, proto, dir) /* A = ip->ip_p */ s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); - s[i]->s.k = off_ll + off_nl + 9; + s[i]->s.k = off_macpl + off_nl + 9; i++; /* X = ip->ip_hl << 2 */ s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); - s[i]->s.k = off_ll + off_nl; + s[i]->s.k = off_macpl + off_nl; i++; break; #ifdef INET6 @@ -4665,7 +5373,7 @@ gen_protochain(v, proto, dir) /* A = ip6->ip_nxt */ s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); - s[i]->s.k = off_ll + off_nl + 6; + s[i]->s.k = off_macpl + off_nl + 6; i++; /* X = sizeof(struct ip6_hdr) */ s[i] = new_stmt(BPF_LDX|BPF_IMM); @@ -4745,7 +5453,7 @@ gen_protochain(v, proto, dir) i++; /* A = P[X + packet head] */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_ll + off_nl; + s[i]->s.k = off_macpl + off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(BPF_ST); @@ -4763,7 +5471,7 @@ gen_protochain(v, proto, dir) i++; /* A = P[X + packet head]; */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_ll + off_nl; + s[i]->s.k = off_macpl + off_nl; i++; /* A += 1 */ s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); @@ -4822,7 +5530,7 @@ gen_protochain(v, proto, dir) i++; /* A = P[X + packet head]; */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_ll + off_nl; + s[i]->s.k = off_macpl + off_nl; i++; /* MEM[reg2] = A */ s[i] = new_stmt(BPF_ST); @@ -4840,7 +5548,7 @@ gen_protochain(v, proto, dir) i++; /* A = P[X + packet head] */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_ll + off_nl; + s[i]->s.k = off_macpl + off_nl; i++; /* A += 2 */ s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); @@ -4894,6 +5602,32 @@ gen_protochain(v, proto, dir) #endif } +static struct block * +gen_check_802_11_data_frame() +{ + struct slist *s; + struct block *b0, *b1; + + /* + * A data frame has the 0x08 bit (b3) in the frame control field set + * and the 0x04 bit (b2) clear. + */ + 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 * and whether the type field in that protocol's header has @@ -5180,9 +5914,9 @@ gen_scode(name, q) 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) @@ -5411,7 +6145,6 @@ gen_scode(name, q) else bpf_error("unknown protocol: %s", name); - case Q_UNDEF: syntax(); /* NOTREACHED */ @@ -5656,9 +6389,9 @@ gen_ecode(eaddr, q) 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: @@ -5852,14 +6585,14 @@ gen_load(proto, inst, size) * XXX - are there any cases where we want * off_nl_nosnap? */ - s = gen_llprefixlen(); + s = gen_off_macpl(); /* * 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. Add to it the offset computed - * into the register specified by "index", and move that - * into the X register. Otherwise, just load into the X + * X register contains the offset of the MAC-layer + * payload. Add to it the offset computed into the + * register specified by "index", and move that into + * the X register. Otherwise, just load into the X * register the offset computed into the register specifed * by "index". */ @@ -5873,13 +6606,17 @@ gen_load(proto, inst, size) /* * Load the item at the sum of the offset we've put in the * X register, the offset of the start of the network - * layer header, and the offset of the start of the link - * layer header (which is 0 if the radio header is - * variable-length; that header length is what we put - * into the X register and then added to the index). + * layer header from the beginning of the MAC-layer + * payload, and the purported offset of the start of the + * MAC-layer payload (which might be 0 if there's a + * variable-length prefix before the link-layer header + * or the link-layer header itself is variable-length; + * the variable-length offset of the start of the + * MAC-layer payload is what we put into the X register + * and then added to the index). */ tmp = new_stmt(BPF_LD|BPF_IND|size); - tmp->s.k = off_ll + off_nl; + tmp->s.k = off_macpl + off_nl; sappend(s, tmp); sappend(inst->s, s); @@ -5920,22 +6657,24 @@ gen_load(proto, inst, size) /* * The X register now contains the sum of the length * of any variable-length header preceding the link-layer - * header and the length of the network-layer header. + * header, any variable-length link-layer header, and the + * length of the network-layer header. + * * Load into the A register the offset relative to * the beginning of the transport layer header, * add the X register to that, move that to the * X register, and load with an offset from the * X register equal to the offset of the network * layer header relative to the beginning of - * the link-layer header plus the length of any - * fixed-length header preceding the link-layer - * header. + * the MAC-layer payload plus the fixed-length + * portion of the offset of the MAC-layer payload + * from the beginning of the raw packet data. */ sappend(s, xfer_to_a(inst)); sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(BPF_MISC|BPF_TAX)); sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); - tmp->s.k = off_ll + off_nl; + tmp->s.k = off_macpl + off_nl; sappend(inst->s, s); /* @@ -6253,10 +6992,10 @@ gen_broadcast(proto) 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); @@ -6349,10 +7088,10 @@ gen_multicast(proto) /* 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. * @@ -6786,6 +7525,31 @@ gen_p80211_type(int type, int mask) bpf_error("802.11 link-layer types supported only on 802.11"); /* NOTREACHED */ } + + return (b0); +} + +struct block * +gen_p80211_fcdir(int fcdir) +{ + struct block *b0; + + switch (linktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + break; + + default: + bpf_error("frame direction supported only with 802.11 headers"); + /* NOTREACHED */ + } + + b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir, + (bpf_u_int32)IEEE80211_FC1_DIR_MASK); + return (b0); } @@ -6862,10 +7626,11 @@ gen_vlan(vlan_num) bpf_error("no VLAN match after MPLS"); /* - * Change the offsets to point to the type and data fields within - * the VLAN packet. Just increment the offsets, so that we - * can support a hierarchy, e.g. "vlan 300 && vlan 200" to - * capture VLAN 200 encapsulated within VLAN 100. + * Check for a VLAN packet, and then change the offsets to point + * to the type and data fields within the VLAN packet. Just + * increment the offsets, so that we can support a hierarchy, e.g. + * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within + * VLAN 100. * * XXX - this is a bit of a kludge. If we were to split the * compiler into a parser that parses an expression and @@ -6891,15 +7656,29 @@ gen_vlan(vlan_num) * be done assuming a VLAN, even though the "or" could be viewed * as meaning "or, if this isn't a VLAN packet...". */ - orig_linktype = off_linktype; /* save original values */ orig_nl = off_nl; switch (linktype) { case DLT_EN10MB: + /* check for VLAN */ + b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, + (bpf_int32)ETHERTYPE_8021Q); + + /* If a specific VLAN is requested, check VLAN id */ + if (vlan_num >= 0) { + b1 = gen_mcmp(OR_MACPL, 0, BPF_H, + (bpf_int32)vlan_num, 0x0fff); + gen_and(b0, b1); + b0 = b1; + } + + off_macpl += 4; off_linktype += 4; +#if 0 off_nl_nosnap += 4; off_nl += 4; +#endif break; default: @@ -6908,17 +7687,6 @@ gen_vlan(vlan_num) /*NOTREACHED*/ } - /* check for VLAN */ - b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q); - - /* If a specific VLAN is requested, check VLAN id */ - if (vlan_num >= 0) { - b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num, - 0x0fff); - gen_and(b0, b1); - b0 = b1; - } - return (b0); } @@ -6944,7 +7712,7 @@ gen_mpls(label_num) if (label_stack_depth > 0) { /* just match the bottom-of-stack bit clear */ - b0 = gen_mcmp(OR_LINK, orig_nl-2, BPF_B, 0, 0x01); + b0 = gen_mcmp(OR_MACPL, orig_nl-2, BPF_B, 0, 0x01); } else { /* * Indicate that we're checking MPLS-encapsulated headers, @@ -6979,7 +7747,7 @@ gen_mpls(label_num) /* If a specific MPLS label is requested, check it */ if (label_num >= 0) { label_num = label_num << 12; /* label is shifted 12 bits on the wire */ - b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num, + b1 = gen_mcmp(OR_MACPL, orig_nl, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ gen_and(b0, b1); b0 = b1; @@ -7013,7 +7781,8 @@ gen_pppoes() /* * Change the offsets to point to the type and data fields within - * the PPP packet. + * the PPP packet, and note that this is PPPoE rather than + * raw PPP. * * XXX - this is a bit of a kludge. If we were to split the * compiler into a parser that parses an expression and @@ -7041,24 +7810,28 @@ gen_pppoes() */ orig_linktype = off_linktype; /* save original values */ orig_nl = off_nl; + is_pppoes = 1; /* * The "network-layer" protocol is PPPoE, which has a 6-byte - * PPPoE header, followed by PPP payload, so we set the - * offsets to the network layer offset plus 6 bytes for - * the PPPoE header plus the values appropriate for PPP when - * encapsulated in Ethernet (which means there's no HDLC - * encapsulation). + * PPPoE header, followed by a PPP packet. + * + * There is no HDLC encapsulation for the PPP packet (it's + * encapsulated in PPPoES instead), so the link-layer type + * starts at the first byte of the PPP packet. For PPPoE, + * that offset is relative to the beginning of the total + * link-layer payload, including any 802.2 LLC header, so + * it's 6 bytes past off_nl. */ - off_linktype = orig_nl + 6; - off_nl = orig_nl + 6 + 2; - off_nl_nosnap = orig_nl + 6 + 2; + off_linktype = off_nl + 6; /* - * Set the link-layer type to PPP, as all subsequent tests will - * be on the encapsulated PPP header. + * The network-layer offsets are relative to the beginning + * of the MAC-layer payload; that's past the 6-byte + * PPPoE header and the 2-byte PPP header. */ - linktype = DLT_PPP; + off_nl = 6+2; + off_nl_nosnap = 6+2; return b0; } @@ -7204,8 +7977,9 @@ gen_atmtype_abbrev(type) is_lane = 1; off_mac = off_payload + 2; /* MAC header */ off_linktype = off_mac + 12; - off_nl = off_mac + 14; /* Ethernet II */ - off_nl_nosnap = off_mac + 17; /* 802.3+802.2 */ + off_macpl = off_mac + 14; /* Ethernet */ + off_nl = 0; /* Ethernet II */ + off_nl_nosnap = 3; /* 802.3+802.2 */ break; case A_LLC: