static struct block *root;
+/*
+ * Absolute offsets, which are offsets from the beginning of the raw
+ * packet data, are, in the general case, the sum of a variable value
+ * and a constant value; the variable value may be absent, in which
+ * case the offset is only the constant value, and the constant value
+ * may be zero, in which case the offset is only the variable value.
+ *
+ * bpf_abs_offset is a structure containing all that information:
+ *
+ * is_variable is 1 if there's a variable part.
+ *
+ * constant_part is the constant part of the value, possibly zero;
+ *
+ * if is_variable is 1, reg is the register number for a register
+ * containing the variable value if the register has been assigned,
+ * and -1 otherwise.
+ */
+typedef struct {
+ int is_variable;
+ u_int constant_part;
+ int reg;
+} bpf_abs_offset;
+
/*
* Value passed to gen_load_a() to indicate what the offset argument
* is relative to the beginning of.
*/
enum e_offrel {
- OR_PACKET, /* full packet data */
- OR_LINK, /* link-layer header */
- OR_LLC, /* 802.2 LLC header */
- OR_LINKPL, /* link-layer payload */
- OR_MPLSPL, /* MPLS payload */
- OR_NET, /* network-layer header */
- OR_NET_NOSNAP, /* network-layer header, with no SNAP header at the link layer */
- OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */
- OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */
+ OR_PACKET, /* full packet data */
+ OR_LINKHDR, /* link-layer header */
+ OR_PREVLINKHDR, /* previous link-layer header */
+ OR_LLC, /* 802.2 LLC header */
+ OR_PREVMPLSHDR, /* previous MPLS header */
+ OR_LINKTYPE, /* link-layer type */
+ OR_LINKPL, /* link-layer payload */
+ OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */
+ OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */
+ OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */
};
#ifdef INET6
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_linkplrel(u_int, u_int);
+static struct slist *gen_load_absoffsetrel(bpf_abs_offset *, 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);
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_linkpl(void);
+static struct slist *gen_abs_offset_varpart(bpf_abs_offset *);
static int ethertype_to_ppptype(int);
static struct block *gen_linktype(int);
static struct block *gen_snap(bpf_u_int32, bpf_u_int32);
}
/*
- * Various code constructs need to know the layout of the data link
- * layer. These variables give the necessary offsets from the beginning
+ * Various code constructs need to know the layout of the packet.
+ * These variables give the necessary offsets from the beginning
* of the packet data.
*/
/*
- * This is the offset of the beginning of the link-layer header from
- * the beginning of the raw packet data.
- *
- * It's usually 0, except for 802.11 with a fixed-length radio header.
- * (For 802.11 with a variable-length radio header, we have to generate
- * code to compute that offset; off_ll is 0 in that case.)
+ * Absolute offset of the beginning of the link-layer header.
*/
-static u_int off_ll;
+static bpf_abs_offset off_linkhdr;
/*
- * 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.
+ * If we're checking a link-layer header for a packet encapsulated in
+ * another protocol layer, this is the equivalent information for the
+ * previous layers' link-layer header from the beginning of the raw
+ * packet data.
*/
-static int reg_off_ll;
+static bpf_abs_offset off_prevlinkhdr;
/*
- * 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, and
- * for Ethernet with various additional information.
+ * This is the equivalent information for the outermost layers' link-layer
+ * header.
*/
-static u_int off_mac;
+static bpf_abs_offset off_outermostlinkhdr;
/*
- * The offset of the beginning of the link-layer payload, from the beginning
- * of the raw packet data, is, in the general case, the sum of a variable
- * value and a constant value; the variable value may be absent, in which
- * case the offset is only the constant value, and the constant value may
- * be zero, in which case the offset is only the variable value.
- *
- * off_linkpl_constant_part is the constant value.
- *
- * reg_off_linkpl is the register number for a register containing the
- * variable value, and -1 otherwise.
- *
- * off_linkpl_is_variable is 1 if there's a variable part.
+ * "Push" the current value of the link-layer header type and link-layer
+ * header offset onto a "stack", and set a new value. (It's not a
+ * full-blown stack; we keep only the top two items.)
+ */
+#define PUSH_LINKHDR(new_linktype, new_is_variable, new_constant_part, new_reg) \
+{ \
+ prevlinktype = new_linktype; \
+ off_prevlinkhdr = off_linkhdr; \
+ linktype = new_linktype; \
+ off_linkhdr.is_variable = new_is_variable; \
+ off_linkhdr.constant_part = new_constant_part; \
+ off_linkhdr.reg = new_reg; \
+}
+
+/*
+ * Absolute offset of the beginning of the link-layer payload.
*/
-static u_int off_linkpl_constant_part;
-static int off_linkpl_is_variable;
-static int reg_off_linkpl;
+static bpf_abs_offset off_linkpl;
/*
* "off_linktype" is the offset to information in the link-layer header
- * giving the packet type. This offset is relative to the beginning
- * of the link-layer header - i.e., it doesn't include off_ll - so
- * loads with an offset that includes "off_linktype" should use
- * OR_LINK.
+ * giving the packet type. This is an absolute offset from the beginning
+ * of the packet.
*
* For Ethernet, it's the offset of the Ethernet type field; this
* means that it must have a value that skips VLAN tags.
*
* For Linux cooked sockets, it's the offset of the type field.
*
- * It's set to -1 for no encapsulation, in which case, IP is assumed.
+ * off_linktype.constant_part is set to -1 for no encapsulation,
+ * in which case, IP is assumed.
*/
-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;
+static bpf_abs_offset off_linktype;
/*
* TRUE if the link layer includes an ATM pseudo-header.
*/
static int is_atm = 0;
-/*
- * TRUE if "lane" appeared in the filter; it causes us to generate
- * code that assumes LANE rather than LLC-encapsulated traffic in SunATM.
- */
-static int is_lane = 0;
-
/*
* These are offsets for the ATM pseudo-header.
*/
/*
* These are offsets to the beginning of the network-layer header.
* They are relative to the beginning of the link-layer payload (i.e.,
- * they don't include off_ll or off_linkpl).
+ * they don't include off_linkhdr.constant_part or off_linkpl.constant_part).
*
* If the link layer never uses 802.2 LLC:
*
static u_int off_nl_nosnap;
static int linktype;
+static int prevlinktype;
+static int outermostlinktype;
static void
init_linktype(p)
pcap_t *p;
{
- linktype = pcap_datalink(p);
pcap_fddipad = p->fddipad;
+ /*
+ * We start out with only one link-layer header.
+ */
+ outermostlinktype = pcap_datalink(p);
+ off_outermostlinkhdr.constant_part = 0;
+ off_outermostlinkhdr.is_variable = 0;
+ off_outermostlinkhdr.reg = -1;
+
+ prevlinktype = outermostlinktype;
+ off_prevlinkhdr.constant_part = 0;
+ off_prevlinkhdr.is_variable = 0;
+ off_prevlinkhdr.reg = -1;
+
+ linktype = outermostlinktype;
+ off_linkhdr.constant_part = 0;
+ off_linkhdr.is_variable = 0;
+ off_linkhdr.reg = -1;
+
+ /*
+ * XXX
+ */
+ off_linkpl.constant_part = 0;
+ off_linkpl.is_variable = 0;
+ off_linkpl.reg = -1;
+
+ off_linktype.constant_part = 0;
+ off_linktype.is_variable = 0;
+ off_linktype.reg = -1;
+
/*
* Assume it's not raw ATM with a pseudo-header, for now.
*/
- off_mac = 0;
is_atm = 0;
- is_lane = 0;
off_vpi = -1;
off_vci = -1;
off_proto = -1;
off_payload = -1;
- /*
- * And that we're not doing PPPoE.
- */
- is_pppoes = 0;
-
/*
* And assume we're not doing SS7.
*/
off_dpc = -1;
off_sls = -1;
- /*
- * Also assume it's not 802.11.
- */
- off_ll = 0;
- off_linkpl_constant_part = 0;
- off_linkpl_is_variable = 0;
-
label_stack_depth = 0;
vlan_stack_depth = 0;
- reg_off_ll = -1;
- reg_off_linkpl = -1;
-
switch (linktype) {
case DLT_ARCNET:
- off_linktype = 2;
- off_linkpl_constant_part = 6;
+ off_linktype.constant_part = 2;
+ off_linkpl.constant_part = 6;
off_nl = 0; /* XXX in reality, variable! */
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_ARCNET_LINUX:
- off_linktype = 4;
- off_linkpl_constant_part = 8;
+ off_linktype.constant_part = 4;
+ off_linkpl.constant_part = 8;
off_nl = 0; /* XXX in reality, variable! */
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_EN10MB:
- off_linktype = 12;
- off_linkpl_constant_part = 14; /* Ethernet header length */
+ off_linktype.constant_part = 12;
+ off_linkpl.constant_part = 14; /* Ethernet header length */
off_nl = 0; /* Ethernet II */
off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
+ break;
case DLT_SLIP:
/*
* SLIP doesn't have a link level type. The 16 byte
* header is hacked into our SLIP driver.
*/
- off_linktype = -1;
- off_linkpl_constant_part = 16;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 16;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_SLIP_BSDOS:
/* XXX this may be the same as the DLT_PPP_BSDOS case */
- off_linktype = -1;
+ off_linktype.constant_part = -1;
/* XXX end */
- off_linkpl_constant_part = 24;
+ off_linkpl.constant_part = 24;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_NULL:
case DLT_LOOP:
- off_linktype = 0;
- off_linkpl_constant_part = 4;
+ off_linktype.constant_part = 0;
+ off_linkpl.constant_part = 4;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_ENC:
- off_linktype = 0;
- off_linkpl_constant_part = 12;
+ off_linktype.constant_part = 0;
+ off_linkpl.constant_part = 12;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_PPP:
case DLT_PPP_PPPD:
case DLT_C_HDLC: /* BSD/OS Cisco HDLC */
case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */
- off_linktype = 2;
- off_linkpl_constant_part = 4;
+ off_linktype.constant_part = 2; /* skip HDLC-like framing */
+ off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_PPP_ETHER:
/*
* This does no include the Ethernet header, and
* only covers session state.
*/
- off_linktype = 6;
- off_linkpl_constant_part = 8;
+ off_linktype.constant_part = 6;
+ off_linkpl.constant_part = 8;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_PPP_BSDOS:
- off_linktype = 5;
- off_linkpl_constant_part = 24;
+ off_linktype.constant_part = 5;
+ off_linkpl.constant_part = 24;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_FDDI:
/*
* is being used and pick out the encapsulated Ethernet type.
* XXX - should we generate code to check for SNAP?
*/
- off_linktype = 13;
- off_linktype += pcap_fddipad;
- off_linkpl_constant_part = 13; /* FDDI MAC header length */
- off_linkpl_constant_part += pcap_fddipad;
+ off_linktype.constant_part = 13;
+ off_linktype.constant_part += pcap_fddipad;
+ off_linkpl.constant_part = 13; /* FDDI MAC header length */
+ off_linkpl.constant_part += pcap_fddipad;
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_IEEE802:
/*
* the 16-bit value at an offset of 14 (shifted right
* 8 - figure out which byte that is).
*/
- off_linktype = 14;
- off_linkpl_constant_part = 14; /* Token Ring MAC header length */
+ off_linktype.constant_part = 14;
+ off_linkpl.constant_part = 14; /* Token Ring MAC header length */
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
- case DLT_IEEE802_11:
case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
+ off_linkhdr.is_variable = 1;
+ /* Fall through, 802.11 doesn't have a variable link
+ * prefix but is otherwise the same. */
+
+ case DLT_IEEE802_11:
/*
* 802.11 doesn't really have a link-level type field.
- * We set "off_linktype" to the offset of the LLC header.
+ * We set "off_linktype.constant_part" to the offset of
+ * the LLC header.
*
* To check for Ethernet types, we assume that SSAP = SNAP
* is being used and pick out the encapsulated Ethernet type.
* header or an AVS header, so, in practice, it's
* variable-length.
*/
- off_linktype = 24;
- off_linkpl_constant_part = 0; /* link-layer header is variable-length */
- off_linkpl_is_variable = 1;
+ off_linktype.constant_part = 24;
+ off_linkpl.constant_part = 0; /* link-layer header is variable-length */
+ off_linkpl.is_variable = 1;
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_PPI:
/*
* the encapsulated DLT should be DLT_IEEE802_11) we
* generate code to check for this too.
*/
- off_linktype = 24;
- off_linkpl_constant_part = 0; /* link-layer header is variable-length */
- off_linkpl_is_variable = 1;
+ off_linktype.constant_part = 24;
+ off_linkpl.constant_part = 0; /* link-layer header is variable-length */
+ off_linkpl.is_variable = 1;
+ off_linkhdr.is_variable = 1;
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_ATM_RFC1483:
case DLT_ATM_CLIP: /* Linux ATM defines this */
* or "pppoa and tcp port 80" and have it check for
* PPPo{A,E} and a PPP protocol of IP and....
*/
- off_linktype = 0;
- off_linkpl_constant_part = 0; /* packet begins with LLC header */
+ off_linktype.constant_part = 0;
+ off_linkpl.constant_part = 0; /* packet begins with LLC header */
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_SUNATM:
/*
off_vpi = SUNATM_VPI_POS;
off_vci = SUNATM_VCI_POS;
off_proto = PROTO_POS;
- off_mac = -1; /* assume LLC-encapsulated, so no MAC-layer header */
off_payload = SUNATM_PKT_BEGIN_POS;
- off_linktype = off_payload;
- off_linkpl_constant_part = off_payload; /* if LLC-encapsulated */
+ off_linktype.constant_part = off_payload;
+ off_linkpl.constant_part = off_payload; /* if LLC-encapsulated */
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_RAW:
case DLT_IPV4:
case DLT_IPV6:
- off_linktype = -1;
- off_linkpl_constant_part = 0;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_LINUX_SLL: /* fake header for Linux cooked socket */
- off_linktype = 14;
- off_linkpl_constant_part = 16;
+ off_linktype.constant_part = 14;
+ off_linkpl.constant_part = 16;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_LTALK:
/*
* but really it just indicates whether there is a "short" or
* "long" DDP packet following.
*/
- off_linktype = -1;
- off_linkpl_constant_part = 0;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_IP_OVER_FC:
/*
* XXX - should we generate code to check for SNAP? RFC
* 2625 says SNAP should be used.
*/
- off_linktype = 16;
- off_linkpl_constant_part = 16;
+ off_linktype.constant_part = 16;
+ off_linkpl.constant_part = 16;
off_nl = 8; /* 802.2+SNAP */
off_nl_nosnap = 3; /* 802.2 */
- return;
+ break;
case DLT_FRELAY:
/*
* XXX - we should set this to handle SNAP-encapsulated
* frames (NLPID of 0x80).
*/
- off_linktype = -1;
- off_linkpl_constant_part = 0;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 0;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
/*
* the only BPF-interesting FRF.16 frames are non-control frames;
* so lets start with offset 4 for now and increments later on (FIXME);
*/
case DLT_MFR:
- off_linktype = -1;
- off_linkpl_constant_part = 0;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 0;
off_nl = 4;
off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */
- return;
+ break;
case DLT_APPLE_IP_OVER_IEEE1394:
- off_linktype = 16;
- off_linkpl_constant_part = 18;
+ off_linktype.constant_part = 16;
+ off_linkpl.constant_part = 18;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
case DLT_SYMANTEC_FIREWALL:
- off_linktype = 6;
- off_linkpl_constant_part = 44;
+ off_linktype.constant_part = 6;
+ off_linkpl.constant_part = 44;
off_nl = 0; /* Ethernet II */
off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */
- return;
+ break;
#ifdef HAVE_NET_PFVAR_H
case DLT_PFLOG:
- off_linktype = 0;
- off_linkpl_constant_part = PFLOG_HDRLEN;
+ off_linktype.constant_part = 0;
+ off_linkpl.constant_part = PFLOG_HDRLEN;
off_nl = 0;
off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
+ break;
#endif
case DLT_JUNIPER_MFR:
case DLT_JUNIPER_PPP:
case DLT_JUNIPER_CHDLC:
case DLT_JUNIPER_FRELAY:
- off_linktype = 4;
- off_linkpl_constant_part = 4;
+ off_linktype.constant_part = 4;
+ off_linkpl.constant_part = 4;
off_nl = 0;
off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
+ break;
case DLT_JUNIPER_ATM1:
- off_linktype = 4; /* in reality variable between 4-8 */
- off_linkpl_constant_part = 4; /* in reality variable between 4-8 */
+ off_linktype.constant_part = 4; /* in reality variable between 4-8 */
+ off_linkpl.constant_part = 4; /* in reality variable between 4-8 */
off_nl = 0;
off_nl_nosnap = 10;
- return;
+ break;
case DLT_JUNIPER_ATM2:
- off_linktype = 8; /* in reality variable between 8-12 */
- off_linkpl_constant_part = 8; /* in reality variable between 8-12 */
+ off_linktype.constant_part = 8; /* in reality variable between 8-12 */
+ off_linkpl.constant_part = 8; /* in reality variable between 8-12 */
off_nl = 0;
off_nl_nosnap = 10;
- return;
+ break;
/* frames captured on a Juniper PPPoE service PIC
* contain raw ethernet frames */
case DLT_JUNIPER_PPPOE:
case DLT_JUNIPER_ETHER:
- off_linkpl_constant_part = 14;
- off_linktype = 16;
+ off_linkpl.constant_part = 14;
+ off_linktype.constant_part = 16;
off_nl = 18; /* Ethernet II */
off_nl_nosnap = 21; /* 802.3+802.2 */
- return;
+ break;
case DLT_JUNIPER_PPPOE_ATM:
- off_linktype = 4;
- off_linkpl_constant_part = 6;
+ off_linktype.constant_part = 4;
+ off_linkpl.constant_part = 6;
off_nl = 0;
off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
+ break;
case DLT_JUNIPER_GGSN:
- off_linktype = 6;
- off_linkpl_constant_part = 12;
+ off_linktype.constant_part = 6;
+ off_linkpl.constant_part = 12;
off_nl = 0;
off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
+ break;
case DLT_JUNIPER_ES:
- off_linktype = 6;
- off_linkpl_constant_part = -1; /* not really a network layer but raw IP addresses */
+ off_linktype.constant_part = 6;
+ off_linkpl.constant_part = -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;
+ break;
case DLT_JUNIPER_MONITOR:
- off_linktype = 12;
- off_linkpl_constant_part = 12;
+ off_linktype.constant_part = 12;
+ off_linkpl.constant_part = 12;
off_nl = 0; /* raw IP/IP6 header */
off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
+ break;
case DLT_BACNET_MS_TP:
- off_linktype = -1;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_JUNIPER_SERVICES:
- off_linktype = 12;
- off_linkpl_constant_part = -1; /* L3 proto location dep. on cookie type */
+ off_linktype.constant_part = 12;
+ off_linkpl.constant_part = -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;
+ break;
case DLT_JUNIPER_VP:
- off_linktype = 18;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = 18;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_JUNIPER_ST:
- off_linktype = 18;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = 18;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_JUNIPER_ISM:
- off_linktype = 8;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = 8;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_JUNIPER_VS:
case DLT_JUNIPER_SRX_E2E:
case DLT_JUNIPER_FIBRECHANNEL:
case DLT_JUNIPER_ATM_CEMIC:
- off_linktype = 8;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = 8;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_MTP2:
off_li = 2;
off_opc = 4;
off_dpc = 4;
off_sls = 7;
- off_linktype = -1;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_MTP2_WITH_PHDR:
off_li = 6;
off_opc = 8;
off_dpc = 8;
off_sls = 11;
- off_linktype = -1;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_ERF:
off_li = 22;
off_opc = 24;
off_dpc = 24;
off_sls = 27;
- off_linktype = -1;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_PFSYNC:
- off_linktype = -1;
- off_linkpl_constant_part = 4;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = 4;
off_nl = 0;
off_nl_nosnap = 0;
- return;
+ break;
case DLT_AX25_KISS:
/*
* Currently, only raw "link[N:M]" filtering is supported.
*/
- off_linktype = -1; /* variable, min 15, max 71 steps of 7 */
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1; /* variable, min 15, max 71 steps of 7 */
+ off_linkpl.constant_part = -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;
+ break;
case DLT_IPNET:
- off_linktype = 1;
- off_linkpl_constant_part = 24; /* ipnet header length */
+ off_linktype.constant_part = 1;
+ off_linkpl.constant_part = 24; /* ipnet header length */
off_nl = 0;
off_nl_nosnap = -1;
- return;
+ break;
case DLT_NETANALYZER:
- off_mac = 4; /* MAC header is past 4-byte pseudo-header */
- off_linktype = 16; /* includes 4-byte pseudo-header */
- off_linkpl_constant_part = 18; /* pseudo-header+Ethernet header length */
+ off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */
+ off_linktype.constant_part = off_linkhdr.constant_part + 12;
+ off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */
off_nl = 0; /* Ethernet II */
off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
+ break;
case DLT_NETANALYZER_TRANSPARENT:
- off_mac = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */
- off_linktype = 24; /* includes 4-byte pseudo-header+preamble+SFD */
- off_linkpl_constant_part = 26; /* pseudo-header+preamble+SFD+Ethernet header length */
+ off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */
+ off_linktype.constant_part = off_linkhdr.constant_part + 12;
+ off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */
off_nl = 0; /* Ethernet II */
off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
+ break;
default:
/*
*/
if (linktype >= DLT_MATCHING_MIN &&
linktype <= DLT_MATCHING_MAX) {
- off_linktype = -1;
- off_linkpl_constant_part = -1;
+ off_linktype.constant_part = -1;
+ off_linkpl.constant_part = -1;
off_nl = -1;
off_nl_nosnap = -1;
- return;
+ } else {
+ bpf_error("unknown data link type %d", linktype);
}
-
+ break;
}
- bpf_error("unknown data link type %d", linktype);
- /* NOTREACHED */
-}
-/*
- * Load a value relative to the beginning of the link-layer header.
- * 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_llrel(offset, size)
- u_int offset, size;
-{
- struct slist *s, *s2;
-
- 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.
- */
- s2 = new_stmt(BPF_LD|BPF_IND|size);
- s2->s.k = offset;
- sappend(s, s2);
- } 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.
- */
- s = new_stmt(BPF_LD|BPF_ABS|size);
- s->s.k = offset + off_ll;
- }
- return s;
+ off_outermostlinkhdr = off_prevlinkhdr = off_linkhdr;
}
/*
- * Load a value relative to the beginning of the link-layer payload.
+ * Load a value relative to the specified absolute offset.
*/
static struct slist *
-gen_load_linkplrel(offset, size)
- u_int offset, size;
+gen_load_absoffsetrel(bpf_abs_offset *abs_offset, u_int offset, u_int size)
{
struct slist *s, *s2;
- s = gen_off_linkpl();
+ s = gen_abs_offset_varpart(abs_offset);
/*
- * If s is non-null, the offset of the link-layer payload is
- * variable, and s points to a list of instructions that
- * arrange that the X register contains the variable part
- * of that offset. The sum of that variable part and
- * off_linkpl_constant_part is the offset.
+ * If "s" is non-null, it has code to arrange that the X register
+ * contains the variable part of the absolute offset, so we
+ * generate a load relative to that, with an offset of
+ * abs_offset->constant_part + offset.
*
- * Otherwise, the offset of the link-layer payload is constant,
- * and is in off_linkpl_constant_part.
+ * Otherwise, we can do an absolute load with an offset of
+ * abs_offset->constant_part + offset.
*/
if (s != NULL) {
/*
- * The variable part of the offset of the link-layer payload
- * is in the X register. Do an indirect load, to use the X
- * register as part of the offset of the load.
+ * "s" points to a list of statements that puts the
+ * variable part of the absolute offset into 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 = off_linkpl_constant_part + offset;
+ s2->s.k = abs_offset->constant_part + offset;
sappend(s, s2);
} else {
/*
- * The offset of the link-layer payload is constant,
- * and is in off_linkpl_constant_part; load the value
- * at that offset plus the specified offset.
+ * There is no variable part of the absolute offset, so
+ * just do an absolute load.
*/
s = new_stmt(BPF_LD|BPF_ABS|size);
- s->s.k = off_linkpl_constant_part + offset;
+ s->s.k = abs_offset->constant_part + offset;
}
return s;
}
s->s.k = offset;
break;
- case OR_LINK:
- s = gen_load_llrel(offset, size);
+ case OR_LINKHDR:
+ s = gen_load_absoffsetrel(&off_linkhdr, offset, size);
+ break;
+
+ case OR_PREVLINKHDR:
+ s = gen_load_absoffsetrel(&off_prevlinkhdr, offset, size);
break;
case OR_LLC:
+ s = gen_load_absoffsetrel(&off_linkpl, offset, size);
+ break;
+
+ case OR_PREVMPLSHDR:
+ s = gen_load_absoffsetrel(&off_linkpl, off_nl - 4 + offset, size);
+ break;
+
case OR_LINKPL:
- case OR_MPLSPL:
- s = gen_load_linkplrel(offset, size);
+ s = gen_load_absoffsetrel(&off_linkpl, off_nl + offset, size);
break;
- case OR_NET:
- s = gen_load_linkplrel(off_nl + offset, size);
+ case OR_LINKPL_NOSNAP:
+ s = gen_load_absoffsetrel(&off_linkpl, off_nl_nosnap + offset, size);
break;
- case OR_NET_NOSNAP:
- s = gen_load_linkplrel(off_nl_nosnap + offset, size);
+ case OR_LINKTYPE:
+ s = gen_load_absoffsetrel(&off_linktype, offset, size);
break;
case OR_TRAN_IPV4:
* part in the offset of the load.
*/
s2 = new_stmt(BPF_LD|BPF_IND|size);
- s2->s.k = off_linkpl_constant_part + off_nl + offset;
+ s2->s.k = off_linkpl.constant_part + off_nl + offset;
sappend(s, s2);
break;
case OR_TRAN_IPV6:
- s = gen_load_linkplrel(off_nl + 40 + offset, size);
+ s = gen_load_absoffsetrel(&off_linkpl, off_nl + 40 + offset, size);
break;
default:
{
struct slist *s, *s2;
- s = gen_off_linkpl();
+ s = gen_abs_offset_varpart(&off_linkpl);
if (s != NULL) {
/*
* The offset of the link-layer payload has a variable
* the value from the X register.
*/
s2 = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s2->s.k = off_nl;
+ s2->s.k = off_linkpl.constant_part + off_nl;
sappend(s, s2);
s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
s2->s.k = 0xf;
* mode. Load the length of the IPv4 header, which
* is at an offset of off_nl from the beginning of
* the link-layer payload, and thus at an offset of
- * off_linkpl_constant_part + off_nl from the beginning
+ * off_linkpl.constant_part + off_nl from the beginning
* of the raw packet data, using that addressing mode.
*/
s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
- s->s.k = off_linkpl_constant_part + off_nl;
+ s->s.k = off_linkpl.constant_part + off_nl;
}
return s;
}
* DSAP, as we do for other types <= ETHERMTU
* (i.e., other SAP values)?
*/
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
+ b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32)
((proto << 8) | proto));
* Now we generate code to check for 802.3
* frames in general.
*/
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
+ b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
/*
* do that before checking for the other frame
* types.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
- (bpf_int32)ETHERTYPE_IPX);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
gen_or(b0, b1);
return b1;
* we check for an Ethernet type field less than
* 1500, which means it's an 802.3 length field.
*/
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
+ b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
/*
* phase 1?); we just check for the Ethernet
* protocol type.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
gen_or(b0, b1);
return b1;
* a length field, <= ETHERMTU) and
* then check the DSAP.
*/
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
+ b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
- (bpf_int32)proto);
+ b1 = gen_cmp(OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto);
gen_and(b0, b1);
return b1;
} else {
* will fail and the frame won't match,
* which is what we want).
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_H,
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H,
(bpf_int32)proto);
}
}
switch (proto) {
case ETHERTYPE_IP:
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
- (bpf_int32)IPH_AF_INET);
+ return gen_cmp(OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET);
/* NOTREACHED */
case ETHERTYPE_IPV6:
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
+ return gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)IPH_AF_INET6);
/* NOTREACHED */
* DSAP, as we do for other types <= ETHERMTU
* (i.e., other SAP values)?
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
b1 = gen_cmp(OR_LLC, 0, BPF_H, (bpf_int32)
((proto << 8) | proto));
gen_and(b0, b1);
b0 = gen_cmp(OR_LLC, 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);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
gen_and(b0, b1);
/*
* Now check for 802.3 frames and OR that with
* the previous test.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_3);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3);
gen_or(b0, b1);
/*
* do that before checking for the other frame
* types.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
- (bpf_int32)ETHERTYPE_IPX);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
gen_or(b0, b1);
return b1;
* we check for the 802.2 protocol type in the
* "Ethernet type" field.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
/*
* 802.2-encapsulated ETHERTYPE_ATALK packets are
* phase 1?); we just check for the Ethernet
* protocol type.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
gen_or(b0, b1);
return b1;
* in the "Ethernet type" field, and
* then check the DSAP.
*/
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
- LINUX_SLL_P_802_2);
- b1 = gen_cmp(OR_LINK, off_linkpl_constant_part, BPF_B,
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
+ b1 = gen_cmp(OR_LINKHDR, off_linkpl.constant_part, BPF_B,
(bpf_int32)proto);
gen_and(b0, b1);
return b1;
* will fail and the frame won't match,
* which is what we want).
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_H,
- (bpf_int32)proto);
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
}
}
}
* but no known software generates headers that aren't 144
* bytes long.
*/
- if (reg_off_ll != -1) {
+ if (off_linkhdr.reg != -1) {
/*
* Load the cookie.
*/
* loading the length of the AVS header.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_ll;
+ s2->s.k = off_linkhdr.reg;
sappend(s1, s2);
sjcommon->s.jf = s2;
* generated uses that prefix, so we don't need to generate any
* code to load it.)
*/
- if (reg_off_ll != -1) {
+ if (off_linkhdr.reg != -1) {
/*
* The 4 bytes at an offset of 4 from the beginning of
* the AVS header are the length of the AVS header.
* it.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_ll;
+ s2->s.k = off_linkhdr.reg;
sappend(s1, s2);
/*
* generated uses that prefix, so we don't need to generate any
* code to load it.)
*/
- if (reg_off_ll != -1) {
+ if (off_linkhdr.reg != -1) {
/*
* The 2 bytes at offsets of 2 and 3 from the beginning
* of the radiotap header are the length of the radiotap
* it.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_ll;
+ s2->s.k = off_linkhdr.reg;
sappend(s1, s2);
/*
* into the register assigned to hold that length, if one has
* been assigned.
*/
- if (reg_off_ll != -1) {
+ if (off_linkhdr.reg != -1) {
/*
* The 2 bytes at offsets of 2 and 3 from the beginning
* of the radiotap header are the length of the radiotap
* it.
*/
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_ll;
+ s2->s.k = off_linkhdr.reg;
sappend(s1, s2);
/*
struct slist *sjset_tsft_datapad, *sjset_notsft_datapad;
struct slist *s_roundup;
- if (reg_off_linkpl == -1) {
+ if (off_linkpl.reg == -1) {
/*
* No register has been assigned to the offset of
* the link-layer payload, which means nobody needs
* header.
*
* Otherwise, the length of the prefix preceding the link-layer
- * header is "off_ll".
+ * header is "off_outermostlinkhdr.constant_part".
*/
if (s == NULL) {
/*
*
* 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_linkpl register.
- * That length is off_ll.
+ * and store it in the off_linkpl.reg register.
+ * That length is off_outermostlinkhdr.constant_part.
*/
s = new_stmt(BPF_LDX|BPF_IMM);
- s->s.k = off_ll;
+ s->s.k = off_outermostlinkhdr.constant_part;
}
/*
* 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_linkpl, and then load the Frame Control field,
+ * in off_linkpl.reg, 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);
s2->s.k = 24;
sappend(s, s2);
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_linkpl;
+ s2->s.k = off_linkpl.reg;
sappend(s, s2);
s2 = new_stmt(BPF_LD|BPF_IND|BPF_B);
sappend(s, sjset_qos);
/*
- * If it's set, add 2 to reg_off_linkpl, to skip the QoS
+ * If it's set, add 2 to off_linkpl.reg, 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_linkpl;
+ s2->s.k = off_linkpl.reg;
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_linkpl;
+ s2->s.k = off_linkpl.reg;
sappend(s, s2);
/*
* ANDing with ~3.
*/
s_roundup = new_stmt(BPF_LD|BPF_MEM);
- s_roundup->s.k = reg_off_linkpl;
+ s_roundup->s.k = off_linkpl.reg;
sappend(s, s_roundup);
s2 = new_stmt(BPF_ALU|BPF_ADD|BPF_IMM);
s2->s.k = 3;
s2->s.k = ~3;
sappend(s, s2);
s2 = new_stmt(BPF_ST);
- s2->s.k = reg_off_linkpl;
+ s2->s.k = off_linkpl.reg;
sappend(s, s2);
sjset_tsft_datapad->s.jt = s_roundup;
{
struct slist *s;
+ /* There is an implicit dependency between the link
+ * payload and link header since the payload computation
+ * includes the variable part of the header. Therefore,
+ * if nobody else has allocated a register for the link
+ * header and we need it, do it now. */
+ if (off_linkpl.reg != -1 && off_linkhdr.is_variable &&
+ off_linkhdr.reg == -1)
+ off_linkhdr.reg = alloc_reg();
+
/*
* 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.
+ *
+ * XXX - this, and the next switch statement, won't handle
+ * encapsulation of 802.11 or 802.11+radio information in
+ * some other protocol stack. That's significantly more
+ * complicated.
*/
- switch (linktype) {
+ switch (outermostlinktype) {
case DLT_PRISM_HEADER:
s = gen_load_prism_llprefixlen();
* header, generate code to load the offset of the link-layer
* payload into the register assigned to that offset, if any.
*/
- switch (linktype) {
+ switch (outermostlinktype) {
case DLT_IEEE802_11:
case DLT_PRISM_HEADER:
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)
-{
- struct slist *s;
-
- if (reg_off_ll == -1) {
- /*
- * We haven't yet assigned a register for the length
- * of the radiotap header; allocate one.
- */
- reg_off_ll = alloc_reg();
- }
-
- /*
- * Load the register containing the radiotap length
- * into the X register.
- */
- s = new_stmt(BPF_LDX|BPF_MEM);
- s->s.k = reg_off_ll;
- return s;
-}
-
/*
- * 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.
- */
-static struct slist *
-gen_ppi_llprefixlen(void)
-{
- struct slist *s;
-
- if (reg_off_ll == -1) {
- /*
- * We haven't yet assigned a register for the length
- * of the radiotap header; allocate one.
- */
- 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 variable part of
- * the offset of the link-layer payload into the X register; if no
- * register for that offset has been allocated, allocate it first.
+ * Take an absolute offset, and:
+ *
+ * if it has no variable part, return NULL;
+ *
+ * if it has a variable part, generate code to load the register
+ * containing that variable part into the X register, returning
+ * a pointer to that code - if no register for that offset has
+ * been allocated, allocate it first.
+ *
* (The code to set that register will be generated later, but will
* be placed earlier in the code sequence.)
*/
static struct slist *
-gen_off_linkpl(void)
+gen_abs_offset_varpart(bpf_abs_offset *off)
{
struct slist *s;
- if (off_linkpl_is_variable) {
- if (reg_off_linkpl == -1) {
+ if (off->is_variable) {
+ if (off->reg == -1) {
/*
* We haven't yet assigned a register for the
* variable part of the offset of the link-layer
- * payload; allocate one.
+ * header; allocate one.
*/
- reg_off_linkpl = alloc_reg();
+ off->reg = alloc_reg();
}
/*
* Load the register containing the variable part of the
- * offset of the link-layer payload into the X register.
+ * offset of the link-layer header into the X register.
*/
s = new_stmt(BPF_LDX|BPF_MEM);
- s->s.k = reg_off_linkpl;
+ s->s.k = off->reg;
return s;
} else {
/*
return (proto);
}
+/*
+ * Generate any tests that, for encapsulation of a link-layer packet
+ * inside another protocol stack, need to be done to check for those
+ * link-layer packets (and that haven't already been done by a check
+ * for that encapsulation).
+ */
+static struct block *
+gen_prevlinkhdr_check(void)
+{
+ struct block *b0;
+
+ switch (prevlinktype) {
+
+ case DLT_SUNATM:
+ /*
+ * This is LANE-encapsulated Ethernet; check that the LANE
+ * packet doesn't begin with an LE Control marker, i.e.
+ * that it's data, not a control message.
+ *
+ * (We've already generated a test for LANE.)
+ */
+ b0 = gen_cmp(OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00);
+ gen_not(b0);
+ return b0;
+
+ default:
+ /*
+ * No such tests are necessary.
+ */
+ return NULL;
+ }
+ /*NOTREACHED*/
+}
+
/*
* Generate code to match a particular packet type by matching the
* link-layer type field or fields in the 802.2 LLC header.
}
}
- /*
- * Are we testing PPPoE packets?
- */
- if (is_pppoes) {
- /*
- * The PPPoE session header is part of the
- * link-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_LINKPL, off_linktype, BPF_H, (bpf_int32)proto);
- }
-
switch (linktype) {
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
- return gen_ether_linktype(proto);
+ b0 = gen_prevlinkhdr_check();
+ b1 = gen_ether_linktype(proto);
+ if (b0 != NULL)
+ gen_and(b0, b1);
+ return b1;
/*NOTREACHED*/
break;
/* fall through */
default:
- return gen_cmp(OR_LINK, off_linktype, BPF_H,
- (bpf_int32)proto);
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
/*NOTREACHED*/
break;
}
case DLT_SUNATM:
/*
- * If "is_lane" is set, check for a LANE-encapsulated
- * version of this protocol, otherwise check for an
- * LLC-encapsulated version of this protocol.
+ * Check for an LLC-encapsulated version of this protocol;
+ * if we were checking for LANE, linktype would no longer
+ * be DLT_SUNATM.
*
- * We assume LANE means Ethernet, not Token Ring.
+ * Check for LLC encapsulation and then check the protocol.
*/
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- b0 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
- gen_not(b0);
-
- /*
- * Now generate an Ethernet test.
- */
- b1 = gen_ether_linktype(proto);
- gen_and(b0, b1);
- return b1;
- } else {
- /*
- * Check for LLC encapsulation and then check the
- * protocol.
- */
- b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
- b1 = gen_llc_linktype(proto);
- gen_and(b0, b1);
- return b1;
- }
+ b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+ b1 = gen_llc_linktype(proto);
+ gen_and(b0, b1);
+ return b1;
/*NOTREACHED*/
break;
case ETHERTYPE_IP:
/* Check for a version number of 4. */
- return gen_mcmp(OR_LINK, 0, BPF_B, 0x40, 0xF0);
+ return gen_mcmp(OR_LINKHDR, 0, BPF_B, 0x40, 0xF0);
case ETHERTYPE_IPV6:
/* Check for a version number of 6. */
- return gen_mcmp(OR_LINK, 0, BPF_B, 0x60, 0xF0);
+ return gen_mcmp(OR_LINKHDR, 0, BPF_B, 0x60, 0xF0);
default:
return gen_false(); /* always false */
* map them to the corresponding PPP protocol types.
*/
proto = ethertype_to_ppptype(proto);
- return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
/*NOTREACHED*/
break;
* 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);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_IP);
+ b1 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_VJC);
gen_or(b0, b1);
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJNC);
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_H, PPP_VJNC);
gen_or(b1, b0);
return b0;
default:
proto = ethertype_to_ppptype(proto);
- return gen_cmp(OR_LINK, off_linktype, BPF_H,
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H,
(bpf_int32)proto);
}
/*NOTREACHED*/
proto = SWAPLONG(proto);
proto = htonl(proto);
}
- return (gen_cmp(OR_LINK, 0, BPF_W, (bpf_int32)proto));
+ return (gen_cmp(OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
#ifdef HAVE_NET_PFVAR_H
case DLT_PFLOG:
* the packet.
*/
if (proto == ETHERTYPE_IP)
- return (gen_cmp(OR_LINK, offsetof(struct pfloghdr, af),
+ return (gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, af),
BPF_B, (bpf_int32)AF_INET));
else if (proto == ETHERTYPE_IPV6)
- return (gen_cmp(OR_LINK, offsetof(struct pfloghdr, af),
+ return (gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, af),
BPF_B, (bpf_int32)AF_INET6));
else
return gen_false();
return gen_false();
case ETHERTYPE_IPV6:
- return (gen_cmp(OR_LINK, off_linktype, BPF_B,
+ return (gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_INET6));
case ETHERTYPE_IP:
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_B,
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_IP);
- b1 = gen_cmp(OR_LINK, off_linktype, BPF_B,
+ b1 = gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_IP_OLD);
gen_or(b0, b1);
return (b1);
case ETHERTYPE_ARP:
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_B,
+ b0 = gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_ARP);
- b1 = gen_cmp(OR_LINK, off_linktype, BPF_B,
+ b1 = gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_ARP_OLD);
gen_or(b0, b1);
return (b1);
case ETHERTYPE_REVARP:
- return (gen_cmp(OR_LINK, off_linktype, BPF_B,
+ return (gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_REVARP));
case ETHERTYPE_ATALK:
- return (gen_cmp(OR_LINK, off_linktype, BPF_B,
+ return (gen_cmp(OR_LINKTYPE, 0, BPF_B,
(bpf_int32)ARCTYPE_ATALK));
}
/*NOTREACHED*/
/*
* Check for the special NLPID for IP.
*/
- return gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | 0xcc);
+ return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc);
case ETHERTYPE_IPV6:
/*
* Check for the special NLPID for IPv6.
*/
- return gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | 0x8e);
+ return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e);
case LLCSAP_ISONS:
/*
* control field of UI, i.e. 0x03 followed
* by the NLPID.
*/
- b0 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO8473_CLNP);
- b1 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO9542_ESIS);
- b2 = gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | ISO10589_ISIS);
+ b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP);
+ b1 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS);
+ b2 = gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS);
gen_or(b1, b2);
gen_or(b0, b2);
return b2;
*
* FIXME encapsulation specific BPF_ filters
*/
- return gen_mcmp(OR_LINK, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */
+ return gen_mcmp(OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */
case DLT_BACNET_MS_TP:
- return gen_mcmp(OR_LINK, 0, BPF_W, 0x55FF0000, 0xffff0000);
+ return gen_mcmp(OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
case DLT_IPNET:
return gen_ipnet_linktype(proto);
/*
* Does this link-layer header type have a field
* indicating the type of the next protocol? If
- * so, off_linktype will be the offset of that
+ * so, off_linktype.constant_part will be the offset of that
* field in the packet; if not, it will be -1.
*/
- if (off_linktype != (u_int)-1) {
+ if (off_linktype.constant_part != (u_int)-1) {
/*
* Yes; assume it's an Ethernet type. (If
* it's not, it needs to be handled specially
* above.)
*/
- return gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
+ return gen_cmp(OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
} else {
/*
* No; report an error.
* We check for an Ethernet type field less than
* 1500, which means it's an 802.3 length field.
*/
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
+ b0 = gen_cmp_gt(OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
/*
abort();
}
b0 = gen_linktype(proto);
- b1 = gen_mcmp(OR_NET, offset, BPF_W, (bpf_int32)addr, mask);
+ b1 = gen_mcmp(OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask);
gen_and(b0, b1);
return b1;
}
/* this order is important */
a = (u_int32_t *)addr;
m = (u_int32_t *)mask;
- b1 = gen_mcmp(OR_NET, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
- b0 = gen_mcmp(OR_NET, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
+ b1 = gen_mcmp(OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
+ b0 = gen_mcmp(OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
gen_and(b0, b1);
- b0 = gen_mcmp(OR_NET, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
+ b0 = gen_mcmp(OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
gen_and(b0, b1);
- b0 = gen_mcmp(OR_NET, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
+ b0 = gen_mcmp(OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
gen_and(b0, b1);
b0 = gen_linktype(proto);
gen_and(b0, b1);
switch (dir) {
case Q_SRC:
- return gen_bcmp(OR_LINK, off_mac + 6, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 6, 6, eaddr);
case Q_DST:
- return gen_bcmp(OR_LINK, off_mac + 0, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 0, 6, eaddr);
case Q_AND:
b0 = gen_ehostop(eaddr, Q_SRC);
switch (dir) {
case Q_SRC:
- return gen_bcmp(OR_LINK, 6 + 1 + pcap_fddipad, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 6 + 1 + pcap_fddipad, 6, eaddr);
case Q_DST:
- return gen_bcmp(OR_LINK, 0 + 1 + pcap_fddipad, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 0 + 1 + pcap_fddipad, 6, eaddr);
case Q_AND:
b0 = gen_fhostop(eaddr, Q_SRC);
switch (dir) {
case Q_SRC:
- return gen_bcmp(OR_LINK, 8, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 8, 6, eaddr);
case Q_DST:
- return gen_bcmp(OR_LINK, 2, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 2, 6, eaddr);
case Q_AND:
b0 = gen_thostop(eaddr, Q_SRC);
*
* First, check for To DS set, i.e. check "link[1] & 0x01".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x01; /* To DS */
b1->stmts = s;
/*
* If To DS is set, the SA is at 24.
*/
- b0 = gen_bcmp(OR_LINK, 24, 6, eaddr);
+ b0 = gen_bcmp(OR_LINKHDR, 24, 6, eaddr);
gen_and(b1, b0);
/*
* Now, check for To DS not set, i.e. check
* "!(link[1] & 0x01)".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x01; /* To DS */
b2->stmts = s;
/*
* If To DS is not set, the SA is at 16.
*/
- b1 = gen_bcmp(OR_LINK, 16, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr);
gen_and(b2, b1);
/*
* Now check for From DS being set, and AND that with
* the ORed-together checks.
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x02; /* From DS */
b1->stmts = s;
/*
* Now check for data frames with From DS not set.
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x02; /* From DS */
b2->stmts = s;
/*
* If From DS isn't set, the SA is at 10.
*/
- b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr);
gen_and(b2, b1);
/*
* Now check for a data frame.
* I.e, check "link[0] & 0x08".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
* is a management frame.
* I.e, check "!(link[0] & 0x08)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x08;
b2->stmts = s;
/*
* For management frames, the SA is at 10.
*/
- b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr);
gen_and(b2, b1);
/*
*
* I.e., check "!(link[0] & 0x04)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x04;
b1->stmts = s;
*
* First, check for To DS set, i.e. "link[1] & 0x01".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x01; /* To DS */
b1->stmts = s;
/*
* If To DS is set, the DA is at 16.
*/
- b0 = gen_bcmp(OR_LINK, 16, 6, eaddr);
+ b0 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr);
gen_and(b1, b0);
/*
* Now, check for To DS not set, i.e. check
* "!(link[1] & 0x01)".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x01; /* To DS */
b2->stmts = s;
/*
* If To DS is not set, the DA is at 4.
*/
- b1 = gen_bcmp(OR_LINK, 4, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr);
gen_and(b2, b1);
/*
* Now check for a data frame.
* I.e, check "link[0] & 0x08".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
* is a management frame.
* I.e, check "!(link[0] & 0x08)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x08;
b2->stmts = s;
/*
* For management frames, the DA is at 4.
*/
- b1 = gen_bcmp(OR_LINK, 4, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr);
gen_and(b2, b1);
/*
*
* I.e., check "!(link[0] & 0x04)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x04;
b1->stmts = s;
* is a management frame.
* I.e, check "(link[0] & 0x08)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
/*
* Check addr1.
*/
- b0 = gen_bcmp(OR_LINK, 4, 6, eaddr);
+ b0 = gen_bcmp(OR_LINKHDR, 4, 6, eaddr);
/*
* AND that with the check of addr1.
/*
* Not present in CTS or ACK control frames.
*/
- b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ b0 = gen_mcmp(OR_LINKHDR, 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,
+ b1 = gen_mcmp(OR_LINKHDR, 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,
+ b2 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK,
IEEE80211_FC0_SUBTYPE_MASK);
gen_not(b2);
gen_and(b1, b2);
* is a management frame.
* I.e, check "(link[0] & 0x08)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
/*
* Check addr2.
*/
- b1 = gen_bcmp(OR_LINK, 10, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr);
gen_and(b2, b1);
return b1;
* XXX - add BSSID keyword?
*/
case Q_ADDR1:
- return (gen_bcmp(OR_LINK, 4, 6, eaddr));
+ return (gen_bcmp(OR_LINKHDR, 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,
+ b0 = gen_mcmp(OR_LINKHDR, 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,
+ b1 = gen_mcmp(OR_LINKHDR, 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,
+ b2 = gen_mcmp(OR_LINKHDR, 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);
+ b1 = gen_bcmp(OR_LINKHDR, 10, 6, eaddr);
gen_and(b2, b1);
return b1;
/*
* Not present in control frames.
*/
- b0 = gen_mcmp(OR_LINK, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
+ b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL,
IEEE80211_FC0_TYPE_MASK);
gen_not(b0);
- b1 = gen_bcmp(OR_LINK, 16, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 16, 6, eaddr);
gen_and(b0, b1);
return b1;
* frames should have both of those set, so we don't
* check the frame type.
*/
- b0 = gen_mcmp(OR_LINK, 1, BPF_B,
+ b0 = gen_mcmp(OR_LINKHDR, 1, BPF_B,
IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK);
- b1 = gen_bcmp(OR_LINK, 24, 6, eaddr);
+ b1 = gen_bcmp(OR_LINKHDR, 24, 6, eaddr);
gen_and(b0, b1);
return b1;
switch (dir) {
case Q_SRC:
- return gen_bcmp(OR_LINK, 10, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 10, 6, eaddr);
case Q_DST:
- return gen_bcmp(OR_LINK, 2, 6, eaddr);
+ return gen_bcmp(OR_LINKHDR, 2, 6, eaddr);
case Q_AND:
b0 = gen_ipfchostop(eaddr, Q_SRC);
}
b0 = gen_linktype(ETHERTYPE_DN);
/* Check for pad = 1, long header case */
- tmp = gen_mcmp(OR_NET, 2, BPF_H,
+ tmp = gen_mcmp(OR_LINKPL, 2, BPF_H,
(bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
- b1 = gen_cmp(OR_NET, 2 + 1 + offset_lh,
+ b1 = gen_cmp(OR_LINKPL, 2 + 1 + offset_lh,
BPF_H, (bpf_int32)ntohs((u_short)addr));
gen_and(tmp, b1);
/* Check for pad = 0, long header case */
- tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
- b2 = gen_cmp(OR_NET, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ tmp = gen_mcmp(OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
+ b2 = gen_cmp(OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
/* Check for pad = 1, short header case */
- tmp = gen_mcmp(OR_NET, 2, BPF_H,
+ tmp = gen_mcmp(OR_LINKPL, 2, BPF_H,
(bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
- b2 = gen_cmp(OR_NET, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ b2 = gen_cmp(OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
/* Check for pad = 0, short header case */
- tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
- b2 = gen_cmp(OR_NET, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ tmp = gen_mcmp(OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
+ b2 = gen_cmp(OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
case Q_IP:
/* match the bottom-of-stack bit */
- b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+ b0 = gen_mcmp(OR_LINKPL, -2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
- b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x40, 0xf0);
+ b1 = gen_mcmp(OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
gen_and(b0, b1);
return b1;
case Q_IPV6:
/* match the bottom-of-stack bit */
- b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+ b0 = gen_mcmp(OR_LINKPL, -2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
- b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x60, 0xf0);
+ b1 = gen_mcmp(OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
gen_and(b0, b1);
return b1;
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check();
b0 = gen_ehostop(eaddr, Q_OR);
+ if (b1 != NULL)
+ gen_and(b1, b0);
break;
case DLT_FDDI:
b0 = gen_fhostop(eaddr, Q_OR);
b0 = gen_wlanhostop(eaddr, Q_OR);
break;
case DLT_SUNATM:
- if (!is_lane)
- bpf_error(
- "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
/*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
+ * This is LLC-multiplexed traffic; if it were
+ * LANE, linktype would have been set to
+ * DLT_EN10MB.
*/
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
- BPF_H, 0xFF00);
- gen_not(b1);
-
- /*
- * Now check the MAC address.
- */
- b0 = gen_ehostop(eaddr, Q_OR);
- gen_and(b1, b0);
+ bpf_error(
+ "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
break;
case DLT_IP_OVER_FC:
b0 = gen_ipfchostop(eaddr, Q_OR);
struct block *b;
/* not IPv4 frag other than the first frag */
- s = gen_load_a(OR_NET, 6, BPF_H);
+ s = gen_load_a(OR_LINKPL, 6, BPF_H);
b = new_block(JMP(BPF_JSET));
b->s.k = 0x1fff;
b->stmts = s;
struct block *b0, *b1, *tmp;
/* ip proto 'proto' and not a fragment other than the first fragment */
- tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto);
+ tmp = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)proto);
b0 = gen_ipfrag();
gen_and(tmp, b0);
/* ip6 proto 'proto' */
/* XXX - catch the first fragment of a fragmented packet? */
- b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto);
+ b0 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)proto);
switch (dir) {
case Q_SRC:
struct block *b0, *b1, *tmp;
/* ip proto 'proto' and not a fragment other than the first fragment */
- tmp = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)proto);
+ tmp = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)proto);
b0 = gen_ipfrag();
gen_and(tmp, b0);
/* ip6 proto 'proto' */
/* XXX - catch the first fragment of a fragmented packet? */
- b0 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)proto);
+ b0 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)proto);
switch (dir) {
case Q_SRC:
* branches, and backward branch support is unlikely to appear
* in kernel BPF engines.)
*/
- switch (linktype) {
-
- 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");
- }
+ if (off_linkpl.is_variable)
+ bpf_error("'protochain' not supported with variable length headers");
no_optimize = 1; /*this code is not compatible with optimzer yet */
/* A = ip->ip_p */
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl + 9;
+ s[i]->s.k = off_linkpl.constant_part + off_nl + 9;
i++;
/* X = ip->ip_hl << 2 */
s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl;
+ s[i]->s.k = off_linkpl.constant_part + off_nl;
i++;
break;
/* A = ip6->ip_nxt */
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl + 6;
+ s[i]->s.k = off_linkpl.constant_part + off_nl + 6;
i++;
/* X = sizeof(struct ip6_hdr) */
s[i] = new_stmt(BPF_LDX|BPF_IMM);
*/
/* A = P[X + packet head] */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl;
+ s[i]->s.k = off_linkpl.constant_part + off_nl;
i++;
/* MEM[reg2] = A */
s[i] = new_stmt(BPF_ST);
i++;
/* A = P[X + packet head + 1]; */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl + 1;
+ s[i]->s.k = off_linkpl.constant_part + off_nl + 1;
i++;
/* A += 1 */
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
i++;
/* A = P[X + packet head]; */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl;
+ s[i]->s.k = off_linkpl.constant_part + off_nl;
i++;
/* MEM[reg2] = A */
s[i] = new_stmt(BPF_ST);
i++;
/* A = P[X + packet head] */
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s[i]->s.k = off_linkpl_constant_part + off_nl;
+ s[i]->s.k = off_linkpl.constant_part + off_nl;
i++;
/* A += 2 */
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
* 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);
+ s = gen_load_a(OR_LINKHDR, 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);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x04;
b1->stmts = s;
*/
b0 = gen_linktype(ETHERTYPE_IP);
#ifndef CHASE_CHAIN
- b1 = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)v);
+ b1 = gen_cmp(OR_LINKPL, 9, BPF_B, (bpf_int32)v);
#else
b1 = gen_protochain(v, Q_IP);
#endif
*
* XXX - what about SNAP-encapsulated frames?
*/
- return gen_cmp(OR_LINK, 2, BPF_H, (0x03<<8) | v);
+ return gen_cmp(OR_LINKHDR, 2, BPF_H, (0x03<<8) | v);
/*NOTREACHED*/
break;
*/
b0 = gen_linktype(LLCSAP_ISONS<<8 | LLCSAP_ISONS);
/* OSI in C-HDLC is stuffed with a fudge byte */
- b1 = gen_cmp(OR_NET_NOSNAP, 1, BPF_B, (long)v);
+ b1 = gen_cmp(OR_LINKPL_NOSNAP, 1, BPF_B, (long)v);
gen_and(b0, b1);
return b1;
default:
b0 = gen_linktype(LLCSAP_ISONS);
- b1 = gen_cmp(OR_NET_NOSNAP, 0, BPF_B, (long)v);
+ b1 = gen_cmp(OR_LINKPL_NOSNAP, 0, BPF_B, (long)v);
gen_and(b0, b1);
return b1;
}
* 4 is the offset of the PDU type relative to the IS-IS
* header.
*/
- b1 = gen_cmp(OR_NET_NOSNAP, 4, BPF_B, (long)v);
+ b1 = gen_cmp(OR_LINKPL_NOSNAP, 4, BPF_B, (long)v);
gen_and(b0, b1);
return b1;
* Also check for a fragment header before the final
* header.
*/
- b2 = gen_cmp(OR_NET, 6, BPF_B, IPPROTO_FRAGMENT);
- b1 = gen_cmp(OR_NET, 40, BPF_B, (bpf_int32)v);
+ b2 = gen_cmp(OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
+ b1 = gen_cmp(OR_LINKPL, 40, BPF_B, (bpf_int32)v);
gen_and(b2, b1);
- b2 = gen_cmp(OR_NET, 6, BPF_B, (bpf_int32)v);
+ b2 = gen_cmp(OR_LINKPL, 6, BPF_B, (bpf_int32)v);
gen_or(b2, b1);
#else
b1 = gen_protochain(v, Q_IPV6);
if (eaddr == NULL)
bpf_error(
"unknown ether host '%s'", name);
+ tmp = gen_prevlinkhdr_check();
b = gen_ehostop(eaddr, dir);
+ if (tmp != NULL)
+ gen_and(tmp, b);
free(eaddr);
return b;
b = gen_ipfchostop(eaddr, dir);
free(eaddr);
return b;
-
- case DLT_SUNATM:
- if (!is_lane)
- break;
-
- /*
- * Check that the packet doesn't begin
- * with an LE Control marker. (We've
- * already generated a test for LANE.)
- */
- tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
- BPF_H, 0xFF00);
- gen_not(tmp);
-
- eaddr = pcap_ether_hostton(name);
- if (eaddr == NULL)
- bpf_error(
- "unknown ether host '%s'", name);
- b = gen_ehostop(eaddr, dir);
- gen_and(tmp, b);
- free(eaddr);
- return b;
}
bpf_error("only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name");
if (alist == NULL || *alist == NULL)
bpf_error("unknown host '%s'", name);
tproto = proto;
- if (off_linktype == (u_int)-1 && tproto == Q_DEFAULT)
+ if (off_linktype.constant_part == (u_int)-1 &&
+ tproto == Q_DEFAULT)
tproto = Q_IP;
b = gen_host(**alist++, 0xffffffff, tproto, dir, q.addr);
while (*alist) {
ai = res;
b = tmp = NULL;
tproto = tproto6 = proto;
- if (off_linktype == -1 && tproto == Q_DEFAULT) {
+ if (off_linktype.constant_part == -1 &&
+ tproto == Q_DEFAULT) {
tproto = Q_IP;
tproto6 = Q_IPV6;
}
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
- return gen_ehostop(eaddr, (int)q.dir);
+ tmp = gen_prevlinkhdr_check();
+ b = gen_ehostop(eaddr, (int)q.dir);
+ if (tmp != NULL)
+ gen_and(tmp, b);
+ return b;
case DLT_FDDI:
return gen_fhostop(eaddr, (int)q.dir);
case DLT_IEEE802:
case DLT_IEEE802_11_RADIO:
case DLT_PPI:
return gen_wlanhostop(eaddr, (int)q.dir);
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
- 0xFF00);
- gen_not(tmp);
-
- /*
- * Now check the MAC address.
- */
- b = gen_ehostop(eaddr, (int)q.dir);
- gen_and(tmp, b);
- return b;
- }
- break;
case DLT_IP_OVER_FC:
return gen_ipfchostop(eaddr, (int)q.dir);
default:
* frame, so that 0 refers, for Ethernet LANE, to
* the beginning of the destination address?
*/
- s = gen_llprefixlen();
+ s = gen_abs_offset_varpart(&off_linkhdr);
/*
* If "s" is non-null, it has code to arrange that the
* into the X register and then added to the index).
*/
tmp = new_stmt(BPF_LD|BPF_IND|size);
- tmp->s.k = off_ll;
+ tmp->s.k = off_linkhdr.constant_part;
sappend(s, tmp);
sappend(inst->s, s);
break;
* XXX - are there any cases where we want
* off_nl_nosnap?
*/
- s = gen_off_linkpl();
+ s = gen_abs_offset_varpart(&off_linkpl);
/*
* If "s" is non-null, it has code to arrange that the
* start of the link-layer payload.
*/
tmp = new_stmt(BPF_LD|BPF_IND|size);
- tmp->s.k = off_linkpl_constant_part + off_nl;
+ tmp->s.k = off_linkpl.constant_part + off_nl;
sappend(s, tmp);
sappend(inst->s, s);
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_linkpl_constant_part + off_nl;
+ tmp->s.k = off_linkpl.constant_part + off_nl;
sappend(inst->s, s);
/*
abort();
case '=':
- return gen_cmp(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val);
+ return gen_cmp(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
case '<':
- b = gen_cmp_lt(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val);
+ b = gen_cmp_lt(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
return b;
case '>':
- b = gen_cmp_gt(OR_LINK, (u_int)idx, BPF_B, (bpf_int32)val);
+ b = gen_cmp_gt(OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
return b;
case '|':
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
- return gen_ehostop(ebroadcast, Q_DST);
+ b1 = gen_prevlinkhdr_check();
+ b0 = gen_ehostop(ebroadcast, Q_DST);
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ return b0;
case DLT_FDDI:
return gen_fhostop(ebroadcast, Q_DST);
case DLT_IEEE802:
return gen_wlanhostop(ebroadcast, Q_DST);
case DLT_IP_OVER_FC:
return gen_ipfchostop(ebroadcast, Q_DST);
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
- BPF_H, 0xFF00);
- gen_not(b1);
-
- /*
- * Now check the MAC address.
- */
- b0 = gen_ehostop(ebroadcast, Q_DST);
- gen_and(b1, b0);
- return b0;
- }
- break;
default:
bpf_error("not a broadcast link");
}
bpf_error("netmask not known, so 'ip broadcast' not supported");
b0 = gen_linktype(ETHERTYPE_IP);
hostmask = ~netmask;
- b1 = gen_mcmp(OR_NET, 16, BPF_W, (bpf_int32)0, hostmask);
- b2 = gen_mcmp(OR_NET, 16, BPF_W,
+ b1 = gen_mcmp(OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask);
+ b2 = gen_mcmp(OR_LINKPL, 16, BPF_W,
(bpf_int32)(~0 & hostmask), hostmask);
gen_or(b1, b2);
gen_and(b0, b2);
register struct slist *s;
/* link[offset] & 1 != 0 */
- s = gen_load_a(OR_LINK, offset, BPF_B);
+ s = gen_load_a(OR_LINKHDR, offset, BPF_B);
b0 = new_block(JMP(BPF_JSET));
b0->s.k = 1;
b0->stmts = s;
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check();
/* ether[0] & 1 != 0 */
- return gen_mac_multicast(0);
+ b0 = gen_mac_multicast(0);
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ return b0;
case DLT_FDDI:
/*
* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX
*
* First, check for To DS set, i.e. "link[1] & 0x01".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x01; /* To DS */
b1->stmts = s;
* Now, check for To DS not set, i.e. check
* "!(link[1] & 0x01)".
*/
- s = gen_load_a(OR_LINK, 1, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 1, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x01; /* To DS */
b2->stmts = s;
* Now check for a data frame.
* I.e, check "link[0] & 0x08".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x08;
b1->stmts = s;
* is a management frame.
* I.e, check "!(link[0] & 0x08)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b2 = new_block(JMP(BPF_JSET));
b2->s.k = 0x08;
b2->stmts = s;
*
* I.e., check "!(link[0] & 0x04)".
*/
- s = gen_load_a(OR_LINK, 0, BPF_B);
+ s = gen_load_a(OR_LINKHDR, 0, BPF_B);
b1 = new_block(JMP(BPF_JSET));
b1->s.k = 0x04;
b1->stmts = s;
case DLT_IP_OVER_FC:
b0 = gen_mac_multicast(2);
return b0;
- case DLT_SUNATM:
- if (is_lane) {
- /*
- * Check that the packet doesn't begin with an
- * LE Control marker. (We've already generated
- * a test for LANE.)
- */
- b1 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS,
- BPF_H, 0xFF00);
- gen_not(b1);
-
- /* ether[off_mac] & 1 != 0 */
- b0 = gen_mac_multicast(off_mac);
- gen_and(b1, b0);
- return b0;
- }
- break;
default:
break;
}
case Q_IP:
b0 = gen_linktype(ETHERTYPE_IP);
- b1 = gen_cmp_ge(OR_NET, 16, BPF_B, (bpf_int32)224);
+ b1 = gen_cmp_ge(OR_LINKPL, 16, BPF_B, (bpf_int32)224);
gen_and(b0, b1);
return b1;
case Q_IPV6:
b0 = gen_linktype(ETHERTYPE_IPV6);
- b1 = gen_cmp(OR_NET, 24, BPF_B, (bpf_int32)255);
+ b1 = gen_cmp(OR_LINKPL, 24, BPF_B, (bpf_int32)255);
gen_and(b0, b1);
return b1;
}
case DLT_IPNET:
if (dir) {
/* match outgoing packets */
- b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_OUTBOUND);
+ b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND);
} else {
/* match incoming packets */
- b0 = gen_cmp(OR_LINK, 2, BPF_H, IPNET_INBOUND);
+ b0 = gen_cmp(OR_LINKHDR, 2, BPF_H, IPNET_INBOUND);
}
break;
case DLT_LINUX_SLL:
/* match outgoing packets */
- b0 = gen_cmp(OR_LINK, 0, BPF_H, LINUX_SLL_OUTGOING);
+ b0 = gen_cmp(OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING);
if (!dir) {
/* to filter on inbound traffic, invert the match */
gen_not(b0);
#ifdef HAVE_NET_PFVAR_H
case DLT_PFLOG:
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, dir), BPF_B,
+ b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
(bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
break;
#endif
case DLT_PPP_PPPD:
if (dir) {
/* match outgoing packets */
- b0 = gen_cmp(OR_LINK, 0, BPF_B, PPP_PPPD_OUT);
+ b0 = gen_cmp(OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT);
} else {
/* match incoming packets */
- b0 = gen_cmp(OR_LINK, 0, BPF_B, PPP_PPPD_IN);
+ b0 = gen_cmp(OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN);
}
break;
* the byte after the 3-byte magic number */
if (dir) {
/* match outgoing packets */
- b0 = gen_mcmp(OR_LINK, 3, BPF_B, 0, 0x01);
+ b0 = gen_mcmp(OR_LINKHDR, 3, BPF_B, 0, 0x01);
} else {
/* match incoming packets */
- b0 = gen_mcmp(OR_LINK, 3, BPF_B, 1, 0x01);
+ b0 = gen_mcmp(OR_LINKHDR, 3, BPF_B, 1, 0x01);
}
break;
/* NOTREACHED */
}
/* match outgoing packets */
- b0 = gen_cmp(OR_LINK, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H,
+ b0 = gen_cmp(OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H,
PACKET_OUTGOING);
if (!dir) {
/* to filter on inbound traffic, invert the match */
len-1);
/* NOTREACHED */
}
- b0 = gen_bcmp(OR_LINK, off, strlen(ifname), (const u_char *)ifname);
+ b0 = gen_bcmp(OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname);
return (b0);
}
/* NOTREACHED */
}
- b0 = gen_bcmp(OR_LINK, offsetof(struct pfloghdr, ruleset),
+ b0 = gen_bcmp(OR_LINKHDR, offsetof(struct pfloghdr, ruleset),
strlen(ruleset), (const u_char *)ruleset);
return (b0);
}
/* NOTREACHED */
}
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, rulenr), BPF_W,
+ b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
(bpf_int32)rnr);
return (b0);
}
/* NOTREACHED */
}
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, subrulenr), BPF_W,
+ b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
(bpf_int32)srnr);
return (b0);
}
/* NOTREACHED */
}
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, reason), BPF_B,
+ b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
(bpf_int32)reason);
return (b0);
}
/* NOTREACHED */
}
- b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, action), BPF_B,
+ b0 = gen_cmp(OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
(bpf_int32)action);
return (b0);
}
case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- b0 = gen_mcmp(OR_LINK, 0, BPF_B, (bpf_int32)type,
+ b0 = gen_mcmp(OR_LINKHDR, 0, BPF_B, (bpf_int32)type,
(bpf_int32)mask);
break;
/* NOTREACHED */
}
- b0 = gen_mcmp(OR_LINK, 1, BPF_B, (bpf_int32)fcdir,
+ b0 = gen_mcmp(OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir,
(bpf_u_int32)IEEE80211_FC1_DIR_MASK);
return (b0);
switch (dir) {
/* src comes first, different from Ethernet */
case Q_SRC:
- return gen_bcmp(OR_LINK, 0, 1, eaddr);
+ return gen_bcmp(OR_LINKHDR, 0, 1, eaddr);
case Q_DST:
- return gen_bcmp(OR_LINK, 1, 1, eaddr);
+ return gen_bcmp(OR_LINKHDR, 1, 1, eaddr);
case Q_AND:
b0 = gen_ahostop(eaddr, Q_SRC);
* The payload follows the full header, including the
* VLAN tags, so skip past this VLAN tag.
*/
- off_linkpl_constant_part += 4;
+ off_linkpl.constant_part += 4;
/*
* The link-layer type information follows the VLAN tags, so
* skip past this VLAN tag.
*/
- off_linktype += 4;
+ off_linktype.constant_part += 4;
return b0;
}
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
- if (vlan_stack_depth == 0) {
+ /* Verify that this is the outer part of the packet and
+ * not encapsulated somehow. */
+ if (vlan_stack_depth == 0 && !off_linkhdr.is_variable &&
+ off_linkhdr.constant_part ==
+ off_outermostlinkhdr.constant_part) {
/*
* Do we need special VLAN handling?
*/
#endif
b0 = gen_vlan_no_bpf_extensions(vlan_num);
break;
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ b0 = gen_vlan_no_bpf_extensions(vlan_num);
+ break;
+
default:
bpf_error("no VLAN support for data link type %d",
linktype);
if (label_stack_depth > 0) {
/* just match the bottom-of-stack bit clear */
- b0 = gen_mcmp(OR_MPLSPL, off_nl-2, BPF_B, 0, 0x01);
+ b0 = gen_mcmp(OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01);
} else {
/*
* We're not in an MPLS stack yet, so check the link-layer
/* 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_MPLSPL, off_nl, BPF_W, (bpf_int32)label_num,
+ b1 = gen_mcmp(OR_LINKPL, 0, BPF_W, (bpf_int32)label_num,
0xfffff000); /* only compare the first 20 bits */
gen_and(b0, b1);
b0 = b1;
/* If a specific session is requested, check PPPoE session id */
if (sess_num >= 0) {
- b1 = gen_mcmp(OR_LINKPL, off_nl, BPF_W,
+ b1 = gen_mcmp(OR_LINKPL, 0, BPF_W,
(bpf_int32)sess_num, 0x0000ffff);
gen_and(b0, b1);
b0 = b1;
}
- is_pppoes = 1;
-
/*
* Change the offsets to point to the type and data fields within
* the PPP packet, and note that this is PPPoE rather than
* link-layer payload, including any 802.2 LLC header, so
* it's 6 bytes past off_nl.
*/
- off_linktype = off_nl + 6;
+ PUSH_LINKHDR(DLT_PPP, off_linkpl.is_variable,
+ off_linkpl.constant_part + off_nl + 6, /* 6 bytes past the PPPoE header */
+ off_linkpl.reg);
- /*
- * The network-layer offsets are relative to the beginning
- * of the link-layer payload; that's past the 6-byte
- * PPPoE header and the 2-byte PPP header.
- */
- off_nl = 6+2;
- off_nl_nosnap = 6+2;
+ off_linktype = off_linkhdr;
+ off_linkpl.constant_part = off_linkhdr.constant_part + 2;
+
+ off_nl = 0;
+ off_nl_nosnap = 0; /* no 802.2 LLC */
return b0;
}
bpf_error("'vpi' supported only on raw ATM");
if (off_vpi == (u_int)-1)
abort();
- b0 = gen_ncmp(OR_LINK, off_vpi, BPF_B, 0xffffffff, jtype,
+ b0 = gen_ncmp(OR_LINKHDR, off_vpi, BPF_B, 0xffffffff, jtype,
reverse, jvalue);
break;
bpf_error("'vci' supported only on raw ATM");
if (off_vci == (u_int)-1)
abort();
- b0 = gen_ncmp(OR_LINK, off_vci, BPF_H, 0xffffffff, jtype,
+ b0 = gen_ncmp(OR_LINKHDR, off_vci, BPF_H, 0xffffffff, jtype,
reverse, jvalue);
break;
case A_PROTOTYPE:
if (off_proto == (u_int)-1)
abort(); /* XXX - this isn't on FreeBSD */
- b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0x0f, jtype,
+ b0 = gen_ncmp(OR_LINKHDR, off_proto, BPF_B, 0x0f, jtype,
reverse, jvalue);
break;
case A_MSGTYPE:
if (off_payload == (u_int)-1)
abort();
- b0 = gen_ncmp(OR_LINK, off_payload + MSG_TYPE_POS, BPF_B,
+ b0 = gen_ncmp(OR_LINKHDR, off_payload + MSG_TYPE_POS, BPF_B,
0xffffffff, jtype, reverse, jvalue);
break;
bpf_error("'callref' supported only on raw ATM");
if (off_proto == (u_int)-1)
abort();
- b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0xffffffff,
+ b0 = gen_ncmp(OR_LINKHDR, off_proto, BPF_B, 0xffffffff,
jtype, reverse, jvalue);
break;
* the offsets appropriately for LANE-encapsulated
* Ethernet.
*
- * "off_mac" is the offset of the Ethernet header,
- * which is 2 bytes past the ATM pseudo-header
- * (skipping the pseudo-header and 2-byte LE Client
- * field). The other offsets are Ethernet offsets
- * relative to "off_mac".
- */
- is_lane = 1;
- off_mac = off_payload + 2; /* MAC header */
- off_linktype = off_mac + 12;
- off_linkpl_constant_part = off_mac + 14; /* Ethernet */
+ * We assume LANE means Ethernet, not Token Ring.
+ */
+ PUSH_LINKHDR(DLT_EN10MB, 0,
+ off_payload + 2, /* Ethernet header */
+ -1);
+ off_linktype.constant_part = off_linkhdr.constant_part + 12;
+ off_linkpl.constant_part = off_linkhdr.constant_part + 14; /* Ethernet */
off_nl = 0; /* Ethernet II */
off_nl_nosnap = 3; /* 802.3+802.2 */
break;
if (!is_atm)
bpf_error("'llc' supported only on raw ATM");
b1 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
- is_lane = 0;
+ linktype = prevlinktype;
break;
default: