X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/d7a1afffd2d5133c96325cc1e9dbeb086aaddae7..refs/heads/libpcap-1.0:/gencode.c?ds=sidebyside diff --git a/gencode.c b/gencode.c index aefe394e..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.13 2007-11-26 21:12:06 gianluca 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 @@ -201,6 +201,8 @@ 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 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 *); @@ -1029,6 +1031,9 @@ init_linktype(p) 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. @@ -1037,31 +1042,15 @@ 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_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_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_macpl = 0; /* link-layer header is variable-length */ off_macpl_is_variable = 1; @@ -1069,59 +1058,15 @@ init_linktype(p) off_nl_nosnap = 3; /* 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_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_macpl = 0; /* link-layer header is variable-length */ @@ -1542,6 +1487,36 @@ init_linktype(p) 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 */ @@ -2133,6 +2108,156 @@ gen_linux_sll_linktype(proto) } } +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; + + /* + * 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_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() { @@ -2497,6 +2622,14 @@ insert_compute_vloffsets(b) */ 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; @@ -2518,9 +2651,9 @@ insert_compute_vloffsets(b) switch (linktype) { case DLT_IEEE802_11: - case DLT_IEEE802_11_RADIO: - case DLT_IEEE802_11_RADIO_AVS: 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; @@ -2564,6 +2697,50 @@ gen_ppi_dlt_check(void) return b; } +static struct slist * +gen_prism_llprefixlen(void) +{ + 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(); + } + + /* + * Load the register containing the radio length + * into the X register. + */ + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = reg_off_ll; + return s; +} + +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) { @@ -2608,7 +2785,7 @@ gen_ppi_llprefixlen(void) } /* - * Load the register containing the radiotap length + * Load the register containing the PPI length * into the X register. */ s = new_stmt(BPF_LDX|BPF_MEM); @@ -2627,12 +2804,18 @@ gen_llprefixlen(void) { switch (linktype) { - case DLT_PPI: - return gen_ppi_llprefixlen(); - + 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; } @@ -2797,11 +2980,11 @@ gen_linktype(proto) } break; - case DLT_PPI: case DLT_IEEE802_11: - case DLT_IEEE802_11_RADIO: - case DLT_IEEE802_11_RADIO_AVS: case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: /* * Check that we have a data frame. */ @@ -3187,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: @@ -3198,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: @@ -4343,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: @@ -5151,9 +5336,9 @@ gen_protochain(v, proto, dir) switch (linktype) { case DLT_IEEE802_11: - case DLT_IEEE802_11_RADIO: - case DLT_IEEE802_11_RADIO_AVS: 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"); } @@ -5729,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) @@ -6204,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: @@ -6807,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); @@ -6903,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. * @@ -7352,9 +7537,9 @@ gen_p80211_fcdir(int fcdir) switch (linktype) { case DLT_IEEE802_11: + case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: - case DLT_PRISM_HEADER: break; default: