/gencode.c
C | 9993 lines | 5829 code | 1325 blank | 2839 comment | 683 complexity | c2a712309eb78467a324c6dad6d65f1d MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*#define CHASE_CHAIN*/
- /*
- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that: (1) source code distributions
- * retain the above copyright notice and this paragraph in its entirety, (2)
- * distributions including binary code include the above copyright notice and
- * this paragraph in its entirety in the documentation or other materials
- * provided with the distribution, and (3) all advertising materials mentioning
- * features or use of this software display the following acknowledgement:
- * ``This product includes software developed by the University of California,
- * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
- * the University nor the names of its contributors may be used to endorse
- * or promote products derived from this software without specific prior
- * written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <pcap-types.h>
- #ifdef _WIN32
- #include <ws2tcpip.h>
- #else
- #include <sys/socket.h>
- #ifdef __NetBSD__
- #include <sys/param.h>
- #endif
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #endif /* _WIN32 */
- #include <stdlib.h>
- #include <string.h>
- #include <memory.h>
- #include <setjmp.h>
- #include <stdarg.h>
- #ifdef MSDOS
- #include "pcap-dos.h"
- #endif
- #include "pcap-int.h"
- #include "extract.h"
- #include "ethertype.h"
- #include "nlpid.h"
- #include "llc.h"
- #include "gencode.h"
- #include "ieee80211.h"
- #include "atmuni31.h"
- #include "sunatmpos.h"
- #include "ppp.h"
- #include "pcap/sll.h"
- #include "pcap/ipnet.h"
- #include "arcnet.h"
- #include "grammar.h"
- #include "scanner.h"
- #if defined(linux)
- #include <linux/types.h>
- #include <linux/if_packet.h>
- #include <linux/filter.h>
- #endif
- #ifdef HAVE_NET_PFVAR_H
- #include <sys/socket.h>
- #include <net/if.h>
- #include <net/pfvar.h>
- #include <net/if_pflog.h>
- #endif
- #ifndef offsetof
- #define offsetof(s, e) ((size_t)&((s *)0)->e)
- #endif
- #ifdef _WIN32
- #ifdef INET6
- #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
- /* IPv6 address */
- struct in6_addr
- {
- union
- {
- uint8_t u6_addr8[16];
- uint16_t u6_addr16[8];
- uint32_t u6_addr32[4];
- } in6_u;
- #define s6_addr in6_u.u6_addr8
- #define s6_addr16 in6_u.u6_addr16
- #define s6_addr32 in6_u.u6_addr32
- #define s6_addr64 in6_u.u6_addr64
- };
- typedef unsigned short sa_family_t;
- #define __SOCKADDR_COMMON(sa_prefix) \
- sa_family_t sa_prefix##family
- /* Ditto, for IPv6. */
- struct sockaddr_in6
- {
- __SOCKADDR_COMMON (sin6_);
- uint16_t sin6_port; /* Transport layer port # */
- uint32_t sin6_flowinfo; /* IPv6 flow information */
- struct in6_addr sin6_addr; /* IPv6 address */
- };
- #ifndef EAI_ADDRFAMILY
- struct addrinfo {
- int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
- int ai_family; /* PF_xxx */
- int ai_socktype; /* SOCK_xxx */
- int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
- size_t ai_addrlen; /* length of ai_addr */
- char *ai_canonname; /* canonical name for hostname */
- struct sockaddr *ai_addr; /* binary address */
- struct addrinfo *ai_next; /* next structure in linked list */
- };
- #endif /* EAI_ADDRFAMILY */
- #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
- #endif /* INET6 */
- #else /* _WIN32 */
- #include <netdb.h> /* for "struct addrinfo" */
- #endif /* _WIN32 */
- #include <pcap/namedb.h>
- #include "nametoaddr.h"
- #define ETHERMTU 1500
- #ifndef IPPROTO_HOPOPTS
- #define IPPROTO_HOPOPTS 0
- #endif
- #ifndef IPPROTO_ROUTING
- #define IPPROTO_ROUTING 43
- #endif
- #ifndef IPPROTO_FRAGMENT
- #define IPPROTO_FRAGMENT 44
- #endif
- #ifndef IPPROTO_DSTOPTS
- #define IPPROTO_DSTOPTS 60
- #endif
- #ifndef IPPROTO_SCTP
- #define IPPROTO_SCTP 132
- #endif
- #define GENEVE_PORT 6081
- #ifdef HAVE_OS_PROTO_H
- #include "os-proto.h"
- #endif
- #define JMP(c) ((c)|BPF_JMP|BPF_K)
- /*
- * "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(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \
- { \
- (cs)->prevlinktype = (cs)->linktype; \
- (cs)->off_prevlinkhdr = (cs)->off_linkhdr; \
- (cs)->linktype = (new_linktype); \
- (cs)->off_linkhdr.is_variable = (new_is_variable); \
- (cs)->off_linkhdr.constant_part = (new_constant_part); \
- (cs)->off_linkhdr.reg = (new_reg); \
- (cs)->is_geneve = 0; \
- }
- /*
- * Offset "not set" value.
- */
- #define OFFSET_NOT_SET 0xffffffffU
- /*
- * 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_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 */
- };
- /*
- * We divy out chunks of memory rather than call malloc each time so
- * we don't have to worry about leaking memory. It's probably
- * not a big deal if all this memory was wasted but if this ever
- * goes into a library that would probably not be a good idea.
- *
- * XXX - this *is* in a library....
- */
- #define NCHUNKS 16
- #define CHUNK0SIZE 1024
- struct chunk {
- size_t n_left;
- void *m;
- };
- /* Code generator state */
- struct _compiler_state {
- jmp_buf top_ctx;
- pcap_t *bpf_pcap;
- int error_set;
- struct icode ic;
- int snaplen;
- int linktype;
- int prevlinktype;
- int outermostlinktype;
- bpf_u_int32 netmask;
- int no_optimize;
- /* Hack for handling VLAN and MPLS stacks. */
- u_int label_stack_depth;
- u_int vlan_stack_depth;
- /* XXX */
- u_int pcap_fddipad;
- /*
- * As errors are handled by a longjmp, anything allocated must
- * be freed in the longjmp handler, so it must be reachable
- * from that handler.
- *
- * One thing that's allocated is the result of pcap_nametoaddrinfo();
- * it must be freed with freeaddrinfo(). This variable points to
- * any addrinfo structure that would need to be freed.
- */
- struct addrinfo *ai;
- /*
- * Another thing that's allocated is the result of pcap_ether_aton();
- * it must be freed with free(). This variable points to any
- * address that would need to be freed.
- */
- u_char *e;
- /*
- * Various code constructs need to know the layout of the packet.
- * These values give the necessary offsets from the beginning
- * of the packet data.
- */
- /*
- * Absolute offset of the beginning of the link-layer header.
- */
- bpf_abs_offset off_linkhdr;
- /*
- * 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.
- */
- bpf_abs_offset off_prevlinkhdr;
- /*
- * This is the equivalent information for the outermost layers'
- * link-layer header.
- */
- bpf_abs_offset off_outermostlinkhdr;
- /*
- * Absolute offset of the beginning of the link-layer payload.
- */
- bpf_abs_offset off_linkpl;
- /*
- * "off_linktype" is the offset to information in the link-layer
- * header 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 link-layer types that always use 802.2 headers, it's the
- * offset of the LLC header; this means that it must have a value
- * that skips VLAN tags.
- *
- * For PPP, it's the offset of the PPP type field.
- *
- * For Cisco HDLC, it's the offset of the CHDLC type field.
- *
- * For BSD loopback, it's the offset of the AF_ value.
- *
- * For Linux cooked sockets, it's the offset of the type field.
- *
- * off_linktype.constant_part is set to OFFSET_NOT_SET for no
- * encapsulation, in which case, IP is assumed.
- */
- bpf_abs_offset off_linktype;
- /*
- * TRUE if the link layer includes an ATM pseudo-header.
- */
- int is_atm;
- /*
- * TRUE if "geneve" appeared in the filter; it causes us to
- * generate code that checks for a Geneve header and assume
- * that later filters apply to the encapsulated payload.
- */
- int is_geneve;
- /*
- * TRUE if we need variable length part of VLAN offset
- */
- int is_vlan_vloffset;
- /*
- * These are offsets for the ATM pseudo-header.
- */
- u_int off_vpi;
- u_int off_vci;
- u_int off_proto;
- /*
- * These are offsets for the MTP2 fields.
- */
- u_int off_li;
- u_int off_li_hsl;
- /*
- * These are offsets for the MTP3 fields.
- */
- u_int off_sio;
- u_int off_opc;
- u_int off_dpc;
- u_int off_sls;
- /*
- * This is the offset of the first byte after the ATM pseudo_header,
- * or -1 if there is no ATM pseudo-header.
- */
- u_int off_payload;
- /*
- * These are offsets to the beginning of the network-layer header.
- * They are relative to the beginning of the link-layer payload
- * (i.e., they don't include off_linkhdr.constant_part or
- * off_linkpl.constant_part).
- *
- * If the link layer never uses 802.2 LLC:
- *
- * "off_nl" and "off_nl_nosnap" are the same.
- *
- * If the link layer always uses 802.2 LLC:
- *
- * "off_nl" is the offset if there's a SNAP header following
- * the 802.2 header;
- *
- * "off_nl_nosnap" is the offset if there's no SNAP header.
- *
- * If the link layer is Ethernet:
- *
- * "off_nl" is the offset if the packet is an Ethernet II packet
- * (we assume no 802.3+802.2+SNAP);
- *
- * "off_nl_nosnap" is the offset if the packet is an 802.3 packet
- * with an 802.2 header following it.
- */
- u_int off_nl;
- u_int off_nl_nosnap;
- /*
- * Here we handle simple allocation of the scratch registers.
- * If too many registers are alloc'd, the allocator punts.
- */
- int regused[BPF_MEMWORDS];
- int curreg;
- /*
- * Memory chunks.
- */
- struct chunk chunks[NCHUNKS];
- int cur_chunk;
- };
- /*
- * For use by routines outside this file.
- */
- /* VARARGS */
- void
- bpf_set_error(compiler_state_t *cstate, const char *fmt, ...)
- {
- va_list ap;
- /*
- * If we've already set an error, don't override it.
- * The lexical analyzer reports some errors by setting
- * the error and then returning a LEX_ERROR token, which
- * is not recognized by any grammar rule, and thus forces
- * the parse to stop. We don't want the error reported
- * by the lexical analyzer to be overwritten by the syntax
- * error.
- */
- if (!cstate->error_set) {
- va_start(ap, fmt);
- (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
- fmt, ap);
- va_end(ap);
- cstate->error_set = 1;
- }
- }
- /*
- * For use *ONLY* in routines in this file.
- */
- static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...)
- PCAP_PRINTFLIKE(2, 3);
- /* VARARGS */
- static void PCAP_NORETURN
- bpf_error(compiler_state_t *cstate, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
- fmt, ap);
- va_end(ap);
- longjmp(cstate->top_ctx, 1);
- /*NOTREACHED*/
- }
- static int init_linktype(compiler_state_t *, pcap_t *);
- static void init_regs(compiler_state_t *);
- static int alloc_reg(compiler_state_t *);
- static void free_reg(compiler_state_t *, int);
- static void initchunks(compiler_state_t *cstate);
- static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t);
- static void *newchunk(compiler_state_t *cstate, size_t);
- static void freechunks(compiler_state_t *cstate);
- static inline struct block *new_block(compiler_state_t *cstate, int);
- static inline struct slist *new_stmt(compiler_state_t *cstate, int);
- static struct block *gen_retblk(compiler_state_t *cstate, int);
- static inline void syntax(compiler_state_t *cstate);
- static void backpatch(struct block *, struct block *);
- static void merge(struct block *, struct block *);
- static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32);
- static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32);
- static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32);
- static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32);
- static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32);
- static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32, bpf_u_int32);
- static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, const u_char *);
- static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_u_int32, int, int, bpf_u_int32);
- static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
- u_int, u_int);
- static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
- u_int);
- static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
- static struct block *gen_uncond(compiler_state_t *, int);
- static inline struct block *gen_true(compiler_state_t *);
- static inline struct block *gen_false(compiler_state_t *);
- static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
- static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
- static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
- static struct slist *gen_load_prism_llprefixlen(compiler_state_t *);
- static struct slist *gen_load_avs_llprefixlen(compiler_state_t *);
- static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *);
- static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *);
- static void insert_compute_vloffsets(compiler_state_t *, struct block *);
- static struct slist *gen_abs_offset_varpart(compiler_state_t *,
- bpf_abs_offset *);
- static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32);
- static struct block *gen_linktype(compiler_state_t *, bpf_u_int32);
- static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32);
- static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
- static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
- int, bpf_u_int32, u_int, u_int);
- #ifdef INET6
- static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
- struct in6_addr *, int, bpf_u_int32, u_int, u_int);
- #endif
- static struct block *gen_ahostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_fhostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
- static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
- static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
- static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
- int, int, int);
- #ifdef INET6
- static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
- struct in6_addr *, int, int, int);
- #endif
- #ifndef INET6
- static struct block *gen_gateway(compiler_state_t *, const u_char *,
- struct addrinfo *, int, int);
- #endif
- static struct block *gen_ipfrag(compiler_state_t *);
- static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32);
- static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32,
- bpf_u_int32);
- static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32);
- static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32,
- bpf_u_int32);
- static struct block *gen_portop(compiler_state_t *, u_int, u_int, int);
- static struct block *gen_port(compiler_state_t *, u_int, int, int);
- static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int,
- bpf_u_int32, int);
- static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int);
- struct block *gen_portop6(compiler_state_t *, u_int, u_int, int);
- static struct block *gen_port6(compiler_state_t *, u_int, int, int);
- static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int,
- bpf_u_int32, int);
- static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int);
- static int lookup_proto(compiler_state_t *, const char *, int);
- static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int);
- static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int);
- static struct slist *xfer_to_x(compiler_state_t *, struct arth *);
- static struct slist *xfer_to_a(compiler_state_t *, struct arth *);
- static struct block *gen_mac_multicast(compiler_state_t *, int);
- static struct block *gen_len(compiler_state_t *, int, int);
- static struct block *gen_check_802_11_data_frame(compiler_state_t *);
- static struct block *gen_geneve_ll_check(compiler_state_t *cstate);
- static struct block *gen_ppi_dlt_check(compiler_state_t *);
- static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
- bpf_u_int32, int, int);
- static struct block *gen_atmtype_llc(compiler_state_t *);
- static struct block *gen_msg_abbrev(compiler_state_t *, int type);
- static void
- initchunks(compiler_state_t *cstate)
- {
- int i;
- for (i = 0; i < NCHUNKS; i++) {
- cstate->chunks[i].n_left = 0;
- cstate->chunks[i].m = NULL;
- }
- cstate->cur_chunk = 0;
- }
- static void *
- newchunk_nolongjmp(compiler_state_t *cstate, size_t n)
- {
- struct chunk *cp;
- int k;
- size_t size;
- #ifndef __NetBSD__
- /* XXX Round up to nearest long. */
- n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
- #else
- /* XXX Round up to structure boundary. */
- n = ALIGN(n);
- #endif
- cp = &cstate->chunks[cstate->cur_chunk];
- if (n > cp->n_left) {
- ++cp;
- k = ++cstate->cur_chunk;
- if (k >= NCHUNKS) {
- bpf_set_error(cstate, "out of memory");
- return (NULL);
- }
- size = CHUNK0SIZE << k;
- cp->m = (void *)malloc(size);
- if (cp->m == NULL) {
- bpf_set_error(cstate, "out of memory");
- return (NULL);
- }
- memset((char *)cp->m, 0, size);
- cp->n_left = size;
- if (n > size) {
- bpf_set_error(cstate, "out of memory");
- return (NULL);
- }
- }
- cp->n_left -= n;
- return (void *)((char *)cp->m + cp->n_left);
- }
- static void *
- newchunk(compiler_state_t *cstate, size_t n)
- {
- void *p;
- p = newchunk_nolongjmp(cstate, n);
- if (p == NULL) {
- longjmp(cstate->top_ctx, 1);
- /*NOTREACHED*/
- }
- return (p);
- }
- static void
- freechunks(compiler_state_t *cstate)
- {
- int i;
- for (i = 0; i < NCHUNKS; ++i)
- if (cstate->chunks[i].m != NULL)
- free(cstate->chunks[i].m);
- }
- /*
- * A strdup whose allocations are freed after code generation is over.
- * This is used by the lexical analyzer, so it can't longjmp; it just
- * returns NULL on an allocation error, and the callers must check
- * for it.
- */
- char *
- sdup(compiler_state_t *cstate, const char *s)
- {
- size_t n = strlen(s) + 1;
- char *cp = newchunk_nolongjmp(cstate, n);
- if (cp == NULL)
- return (NULL);
- pcap_strlcpy(cp, s, n);
- return (cp);
- }
- static inline struct block *
- new_block(compiler_state_t *cstate, int code)
- {
- struct block *p;
- p = (struct block *)newchunk(cstate, sizeof(*p));
- p->s.code = code;
- p->head = p;
- return p;
- }
- static inline struct slist *
- new_stmt(compiler_state_t *cstate, int code)
- {
- struct slist *p;
- p = (struct slist *)newchunk(cstate, sizeof(*p));
- p->s.code = code;
- return p;
- }
- static struct block *
- gen_retblk(compiler_state_t *cstate, int v)
- {
- struct block *b = new_block(cstate, BPF_RET|BPF_K);
- b->s.k = v;
- return b;
- }
- static inline PCAP_NORETURN_DEF void
- syntax(compiler_state_t *cstate)
- {
- bpf_error(cstate, "syntax error in filter expression");
- }
- int
- pcap_compile(pcap_t *p, struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask)
- {
- #ifdef _WIN32
- static int done = 0;
- #endif
- compiler_state_t cstate;
- const char * volatile xbuf = buf;
- yyscan_t scanner = NULL;
- volatile YY_BUFFER_STATE in_buffer = NULL;
- u_int len;
- int rc;
- /*
- * If this pcap_t hasn't been activated, it doesn't have a
- * link-layer type, so we can't use it.
- */
- if (!p->activated) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "not-yet-activated pcap_t passed to pcap_compile");
- return (-1);
- }
- #ifdef _WIN32
- if (!done)
- pcap_wsockinit();
- done = 1;
- #endif
- #ifdef ENABLE_REMOTE
- /*
- * If the device on which we're capturing need to be notified
- * that a new filter is being compiled, do so.
- *
- * This allows them to save a copy of it, in case, for example,
- * they're implementing a form of remote packet capture, and
- * want the remote machine to filter out the packets in which
- * it's sending the packets it's captured.
- *
- * XXX - the fact that we happen to be compiling a filter
- * doesn't necessarily mean we'll be installing it as the
- * filter for this pcap_t; we might be running it from userland
- * on captured packets to do packet classification. We really
- * need a better way of handling this, but this is all that
- * the WinPcap remote capture code did.
- */
- if (p->save_current_filter_op != NULL)
- (p->save_current_filter_op)(p, buf);
- #endif
- initchunks(&cstate);
- cstate.no_optimize = 0;
- #ifdef INET6
- cstate.ai = NULL;
- #endif
- cstate.e = NULL;
- cstate.ic.root = NULL;
- cstate.ic.cur_mark = 0;
- cstate.bpf_pcap = p;
- cstate.error_set = 0;
- init_regs(&cstate);
- cstate.netmask = mask;
- cstate.snaplen = pcap_snapshot(p);
- if (cstate.snaplen == 0) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "snaplen of 0 rejects all packets");
- rc = -1;
- goto quit;
- }
- if (pcap_lex_init(&scanner) != 0)
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "can't initialize scanner");
- in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
- /*
- * Associate the compiler state with the lexical analyzer
- * state.
- */
- pcap_set_extra(&cstate, scanner);
- if (init_linktype(&cstate, p) == -1) {
- rc = -1;
- goto quit;
- }
- if (pcap_parse(scanner, &cstate) != 0) {
- #ifdef INET6
- if (cstate.ai != NULL)
- freeaddrinfo(cstate.ai);
- #endif
- if (cstate.e != NULL)
- free(cstate.e);
- rc = -1;
- goto quit;
- }
- if (cstate.ic.root == NULL) {
- /*
- * Catch errors reported by gen_retblk().
- */
- if (setjmp(cstate.top_ctx)) {
- rc = -1;
- goto quit;
- }
- cstate.ic.root = gen_retblk(&cstate, cstate.snaplen);
- }
- if (optimize && !cstate.no_optimize) {
- if (bpf_optimize(&cstate.ic, p->errbuf) == -1) {
- /* Failure */
- rc = -1;
- goto quit;
- }
- if (cstate.ic.root == NULL ||
- (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
- (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "expression rejects all packets");
- rc = -1;
- goto quit;
- }
- }
- program->bf_insns = icode_to_fcode(&cstate.ic,
- cstate.ic.root, &len, p->errbuf);
- if (program->bf_insns == NULL) {
- /* Failure */
- rc = -1;
- goto quit;
- }
- program->bf_len = len;
- rc = 0; /* We're all okay */
- quit:
- /*
- * Clean up everything for the lexical analyzer.
- */
- if (in_buffer != NULL)
- pcap__delete_buffer(in_buffer, scanner);
- if (scanner != NULL)
- pcap_lex_destroy(scanner);
- /*
- * Clean up our own allocated memory.
- */
- freechunks(&cstate);
- return (rc);
- }
- /*
- * entry point for using the compiler with no pcap open
- * pass in all the stuff that is needed explicitly instead.
- */
- int
- pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
- struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask)
- {
- pcap_t *p;
- int ret;
- p = pcap_open_dead(linktype_arg, snaplen_arg);
- if (p == NULL)
- return (-1);
- ret = pcap_compile(p, program, buf, optimize, mask);
- pcap_close(p);
- return (ret);
- }
- /*
- * Clean up a "struct bpf_program" by freeing all the memory allocated
- * in it.
- */
- void
- pcap_freecode(struct bpf_program *program)
- {
- program->bf_len = 0;
- if (program->bf_insns != NULL) {
- free((char *)program->bf_insns);
- program->bf_insns = NULL;
- }
- }
- /*
- * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates
- * which of the jt and jf fields has been resolved and which is a pointer
- * back to another unresolved block (or nil). At least one of the fields
- * in each block is already resolved.
- */
- static void
- backpatch(struct block *list, struct block *target)
- {
- struct block *next;
- while (list) {
- if (!list->sense) {
- next = JT(list);
- JT(list) = target;
- } else {
- next = JF(list);
- JF(list) = target;
- }
- list = next;
- }
- }
- /*
- * Merge the lists in b0 and b1, using the 'sense' field to indicate
- * which of jt and jf is the link.
- */
- static void
- merge(struct block *b0, struct block *b1)
- {
- register struct block **p = &b0;
- /* Find end of list. */
- while (*p)
- p = !((*p)->sense) ? &JT(*p) : &JF(*p);
- /* Concatenate the lists. */
- *p = b1;
- }
- int
- finish_parse(compiler_state_t *cstate, struct block *p)
- {
- struct block *ppi_dlt_check;
- /*
- * Catch errors reported by us and routines below us, and return -1
- * on an error.
- */
- if (setjmp(cstate->top_ctx))
- return (-1);
- /*
- * Insert before the statements of the first (root) block any
- * statements needed to load the lengths of any variable-length
- * headers into registers.
- *
- * XXX - a fancier strategy would be to insert those before the
- * statements of all blocks that use those lengths and that
- * have no predecessors that use them, so that we only compute
- * the lengths if we need them. There might be even better
- * approaches than that.
- *
- * However, those strategies would be more complicated, and
- * as we don't generate code to compute a length if the
- * program has no tests that use the length, and as most
- * tests will probably use those lengths, we would just
- * postpone computing the lengths so that it's not done
- * for tests that fail early, and it's not clear that's
- * worth the effort.
- */
- insert_compute_vloffsets(cstate, p->head);
- /*
- * For DLT_PPI captures, generate a check of the per-packet
- * DLT value to make sure it's DLT_IEEE802_11.
- *
- * XXX - TurboCap cards use DLT_PPI for Ethernet.
- * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header
- * with appropriate Ethernet information and use that rather
- * than using something such as DLT_PPI where you don't know
- * the link-layer header type until runtime, which, in the
- * general case, would force us to generate both Ethernet *and*
- * 802.11 code (*and* anything else for which PPI is used)
- * and choose between them early in the BPF program?
- */
- ppi_dlt_check = gen_ppi_dlt_check(cstate);
- if (ppi_dlt_check != NULL)
- gen_and(ppi_dlt_check, p);
- backpatch(p, gen_retblk(cstate, cstate->snaplen));
- p->sense = !p->sense;
- backpatch(p, gen_retblk(cstate, 0));
- cstate->ic.root = p->head;
- return (0);
- }
- void
- gen_and(struct block *b0, struct block *b1)
- {
- backpatch(b0, b1->head);
- b0->sense = !b0->sense;
- b1->sense = !b1->sense;
- merge(b1, b0);
- b1->sense = !b1->sense;
- b1->head = b0->head;
- }
- void
- gen_or(struct block *b0, struct block *b1)
- {
- b0->sense = !b0->sense;
- backpatch(b0, b1->head);
- b0->sense = !b0->sense;
- merge(b1, b0);
- b1->head = b0->head;
- }
- void
- gen_not(struct block *b)
- {
- b->sense = !b->sense;
- }
- static struct block *
- gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v)
- {
- return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
- }
- static struct block *
- gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v)
- {
- return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
- }
- static struct block *
- gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v)
- {
- return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
- }
- static struct block *
- gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v)
- {
- return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
- }
- static struct block *
- gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v)
- {
- return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
- }
- static struct block *
- gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 v, bpf_u_int32 mask)
- {
- return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
- }
- static struct block *
- gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, const u_char *v)
- {
- register struct block *b, *tmp;
- b = NULL;
- while (size >= 4) {
- register const u_char *p = &v[size - 4];
- tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
- EXTRACT_BE_U_4(p));
- if (b != NULL)
- gen_and(b, tmp);
- b = tmp;
- size -= 4;
- }
- while (size >= 2) {
- register const u_char *p = &v[size - 2];
- tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
- EXTRACT_BE_U_2(p));
- if (b != NULL)
- gen_and(b, tmp);
- b = tmp;
- size -= 2;
- }
- if (size > 0) {
- tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
- if (b != NULL)
- gen_and(b, tmp);
- b = tmp;
- }
- return b;
- }
- /*
- * AND the field of size "size" at offset "offset" relative to the header
- * specified by "offrel" with "mask", and compare it with the value "v"
- * with the test specified by "jtype"; if "reverse" is true, the test
- * should test the opposite of "jtype".
- */
- static struct block *
- gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_u_int32 mask, int jtype, int reverse,
- bpf_u_int32 v)
- {
- struct slist *s, *s2;
- struct block *b;
- s = gen_load_a(cstate, offrel, offset, size);
- if (mask != 0xffffffff) {
- s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
- s2->s.k = mask;
- sappend(s, s2);
- }
- b = new_block(cstate, JMP(jtype));
- b->stmts = s;
- b->s.k = v;
- if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE))
- gen_not(b);
- return b;
- }
- static int
- init_linktype(compiler_state_t *cstate, pcap_t *p)
- {
- cstate->pcap_fddipad = p->fddipad;
- /*
- * We start out with only one link-layer header.
- */
- cstate->outermostlinktype = pcap_datalink(p);
- cstate->off_outermostlinkhdr.constant_part = 0;
- cstate->off_outermostlinkhdr.is_variable = 0;
- cstate->off_outermostlinkhdr.reg = -1;
- cstate->prevlinktype = cstate->outermostlinktype;
- cstate->off_prevlinkhdr.constant_part = 0;
- cstate->off_prevlinkhdr.is_variable = 0;
- cstate->off_prevlinkhdr.reg = -1;
- cstate->linktype = cstate->outermostlinktype;
- cstate->off_linkhdr.constant_part = 0;
- cstate->off_linkhdr.is_variable = 0;
- cstate->off_linkhdr.reg = -1;
- /*
- * XXX
- */
- cstate->off_linkpl.constant_part = 0;
- cstate->off_linkpl.is_variable = 0;
- cstate->off_linkpl.reg = -1;
- cstate->off_linktype.constant_part = 0;
- cstate->off_linktype.is_variable = 0;
- cstate->off_linktype.reg = -1;
- /*
- * Assume it's not raw ATM with a pseudo-header, for now.
- */
- cstate->is_atm = 0;
- cstate->off_vpi = OFFSET_NOT_SET;
- cstate->off_vci = OFFSET_NOT_SET;
- cstate->off_proto = OFFSET_NOT_SET;
- cstate->off_payload = OFFSET_NOT_SET;
- /*
- * And not Geneve.
- */
- cstate->is_geneve = 0;
- /*
- * No variable length VLAN offset by default
- */
- cstate->is_vlan_vloffset = 0;
- /*
- * And assume we're not doing SS7.
- */
- cstate->off_li = OFFSET_NOT_SET;
- cstate->off_li_hsl = OFFSET_NOT_SET;
- cstate->off_sio = OFFSET_NOT_SET;
- cstate->off_opc = OFFSET_NOT_SET;
- cstate->off_dpc = OFFSET_NOT_SET;
- cstate->off_sls = OFFSET_NOT_SET;
- cstate->label_stack_depth = 0;
- cstate->vlan_stack_depth = 0;
- switch (cstate->linktype) {
- case DLT_ARCNET:
- cstate->off_linktype.constant_part = 2;
- cstate->off_linkpl.constant_part = 6;
- cstate->off_nl = 0; /* XXX in reality, variable! */
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_ARCNET_LINUX:
- cstate->off_linktype.constant_part = 4;
- cstate->off_linkpl.constant_part = 8;
- cstate->off_nl = 0; /* XXX in reality, variable! */
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_EN10MB:
- cstate->off_linktype.constant_part = 12;
- cstate->off_linkpl.constant_part = 14; /* Ethernet header length */
- cstate->off_nl = 0; /* Ethernet II */
- cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
- break;
- case DLT_SLIP:
- /*
- * SLIP doesn't have a link level type. The 16 byte
- * header is hacked into our SLIP driver.
- */
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 16;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_SLIP_BSDOS:
- /* XXX this may be the same as the DLT_PPP_BSDOS case */
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- /* XXX end */
- cstate->off_linkpl.constant_part = 24;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_NULL:
- case DLT_LOOP:
- cstate->off_linktype.constant_part = 0;
- cstate->off_linkpl.constant_part = 4;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_ENC:
- cstate->off_linktype.constant_part = 0;
- cstate->off_linkpl.constant_part = 12;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- 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 */
- cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */
- cstate->off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_PPP_ETHER:
- /*
- * This does no include the Ethernet header, and
- * only covers session state.
- */
- cstate->off_linktype.constant_part = 6;
- cstate->off_linkpl.constant_part = 8;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_PPP_BSDOS:
- cstate->off_linktype.constant_part = 5;
- cstate->off_linkpl.constant_part = 24;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_FDDI:
- /*
- * FDDI doesn't really have a link-level type field.
- * We set "off_linktype" 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.
- * XXX - should we generate code to check for SNAP?
- */
- cstate->off_linktype.constant_part = 13;
- cstate->off_linktype.constant_part += cstate->pcap_fddipad;
- cstate->off_linkpl.constant_part = 13; /* FDDI MAC header length */
- cstate->off_linkpl.constant_part += cstate->pcap_fddipad;
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_IEEE802:
- /*
- * Token Ring doesn't really have a link-level type field.
- * We set "off_linktype" 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.
- * XXX - should we generate code to check for SNAP?
- *
- * XXX - the header is actually variable-length.
- * Some various Linux patched versions gave 38
- * as "off_linktype" and 40 as "off_nl"; however,
- * if a token ring packet has *no* routing
- * information, i.e. is not source-routed, the correct
- * values are 20 and 22, as they are in the vanilla code.
- *
- * A packet is source-routed iff the uppermost bit
- * of the first byte of the source address, at an
- * offset of 8, has the uppermost bit set. If the
- * packet is source-routed, the total number of bytes
- * of routing information is 2 plus bits 0x1F00 of
- * the 16-bit value at an offset of 14 (shifted right
- * 8 - figure out which byte that is).
- */
- cstate->off_linktype.constant_part = 14;
- cstate->off_linkpl.constant_part = 14; /* Token Ring MAC header length */
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- cstate->off_linkhdr.is_variable = 1;
- /* Fall through, 802.11 doesn't have a variable link
- * prefix but is otherwise the same. */
- /* FALLTHROUGH */
- case DLT_IEEE802_11:
- /*
- * 802.11 doesn't really have a link-level type field.
- * 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.
- * XXX - should we generate code to check for SNAP?
- *
- * 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.
- */
- cstate->off_linktype.constant_part = 24;
- cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */
- cstate->off_linkpl.is_variable = 1;
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_PPI:
- /*
- * 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.
- */
- cstate->off_linktype.constant_part = 24;
- cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */
- cstate->off_linkpl.is_variable = 1;
- cstate->off_linkhdr.is_variable = 1;
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_ATM_RFC1483:
- case DLT_ATM_CLIP: /* Linux ATM defines this */
- /*
- * assume routed, non-ISO PDUs
- * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00)
- *
- * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS,
- * or PPP with the PPP NLPID (e.g., PPPoA)? The
- * latter would presumably be treated the way PPPoE
- * should be, so you can do "pppoe and udp port 2049"
- * or "pppoa and tcp port 80" and have it check for
- * PPPo{A,E} and a PPP protocol of IP and....
- */
- cstate->off_linktype.constant_part = 0;
- cstate->off_linkpl.constant_part = 0; /* packet begins with LLC header */
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_SUNATM:
- /*
- * Full Frontal ATM; you get AALn PDUs with an ATM
- * pseudo-header.
- */
- cstate->is_atm = 1;
- cstate->off_vpi = SUNATM_VPI_POS;
- cstate->off_vci = SUNATM_VCI_POS;
- cstate->off_proto = PROTO_POS;
- cstate->off_payload = SUNATM_PKT_BEGIN_POS;
- cstate->off_linktype.constant_part = cstate->off_payload;
- cstate->off_linkpl.constant_part = cstate->off_payload; /* if LLC-encapsulated */
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_RAW:
- case DLT_IPV4:
- case DLT_IPV6:
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 0;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */
- cstate->off_linktype.constant_part = 14;
- cstate->off_linkpl.constant_part = 16;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */
- cstate->off_linktype.constant_part = 0;
- cstate->off_linkpl.constant_part = 20;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_LTALK:
- /*
- * LocalTalk does have a 1-byte type field in the LLAP header,
- * but really it just indicates whether there is a "short" or
- * "long" DDP packet following.
- */
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 0;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_IP_OVER_FC:
- /*
- * RFC 2625 IP-over-Fibre-Channel doesn't really have a
- * link-level type field. We set "off_linktype" 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.
- * XXX - should we generate code to check for SNAP? RFC
- * 2625 says SNAP should be used.
- */
- cstate->off_linktype.constant_part = 16;
- cstate->off_linkpl.constant_part = 16;
- cstate->off_nl = 8; /* 802.2+SNAP */
- cstate->off_nl_nosnap = 3; /* 802.2 */
- break;
- case DLT_FRELAY:
- /*
- * XXX - we should set this to handle SNAP-encapsulated
- * frames (NLPID of 0x80).
- */
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 0;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- /*
- * the only BPF-interesting FRF.16 frames are non-control frames;
- * Frame Relay has a variable length link-layer
- * so lets start with offset 4 for now and increments later on (FIXME);
- */
- case DLT_MFR:
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 0;
- cstate->off_nl = 4;
- cstate->off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */
- break;
- case DLT_APPLE_IP_OVER_IEEE1394:
- cstate->off_linktype.constant_part = 16;
- cstate->off_linkpl.constant_part = 18;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- case DLT_SYMANTEC_FIREWALL:
- cstate->off_linktype.constant_part = 6;
- cstate->off_linkpl.constant_part = 44;
- cstate->off_nl = 0; /* Ethernet II */
- cstate->off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */
- break;
- #ifdef HAVE_NET_PFVAR_H
- case DLT_PFLOG:
- cstate->off_linktype.constant_part = 0;
- cstate->off_linkpl.constant_part = PFLOG_HDRLEN;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
- break;
- #endif
- case DLT_JUNIPER_MFR:
- case DLT_JUNIPER_MLFR:
- case DLT_JUNIPER_MLPPP:
- case DLT_JUNIPER_PPP:
- case DLT_JUNIPER_CHDLC:
- case DLT_JUNIPER_FRELAY:
- cstate->off_linktype.constant_part = 4;
- cstate->off_linkpl.constant_part = 4;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_JUNIPER_ATM1:
- cstate->off_linktype.constant_part = 4; /* in reality variable between 4-8 */
- cstate->off_linkpl.constant_part = 4; /* in reality variable between 4-8 */
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 10;
- break;
- case DLT_JUNIPER_ATM2:
- cstate->off_linktype.constant_part = 8; /* in reality variable between 8-12 */
- cstate->off_linkpl.constant_part = 8; /* in reality variable between 8-12 */
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 10;
- break;
- /* frames captured on a Juniper PPPoE service PIC
- * contain raw ethernet frames */
- case DLT_JUNIPER_PPPOE:
- case DLT_JUNIPER_ETHER:
- cstate->off_linkpl.constant_part = 14;
- cstate->off_linktype.constant_part = 16;
- cstate->off_nl = 18; /* Ethernet II */
- cstate->off_nl_nosnap = 21; /* 802.3+802.2 */
- break;
- case DLT_JUNIPER_PPPOE_ATM:
- cstate->off_linktype.constant_part = 4;
- cstate->off_linkpl.constant_part = 6;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_JUNIPER_GGSN:
- cstate->off_linktype.constant_part = 6;
- cstate->off_linkpl.constant_part = 12;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_JUNIPER_ES:
- cstate->off_linktype.constant_part = 6;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */
- cstate->off_nl = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_JUNIPER_MONITOR:
- cstate->off_linktype.constant_part = 12;
- cstate->off_linkpl.constant_part = 12;
- cstate->off_nl = 0; /* raw IP/IP6 header */
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_BACNET_MS_TP:
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_JUNIPER_SERVICES:
- cstate->off_linktype.constant_part = 12;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */
- cstate->off_nl = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_JUNIPER_VP:
- cstate->off_linktype.constant_part = 18;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_JUNIPER_ST:
- cstate->off_linktype.constant_part = 18;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_JUNIPER_ISM:
- cstate->off_linktype.constant_part = 8;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_JUNIPER_VS:
- case DLT_JUNIPER_SRX_E2E:
- case DLT_JUNIPER_FIBRECHANNEL:
- case DLT_JUNIPER_ATM_CEMIC:
- cstate->off_linktype.constant_part = 8;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_MTP2:
- cstate->off_li = 2;
- cstate->off_li_hsl = 4;
- cstate->off_sio = 3;
- cstate->off_opc = 4;
- cstate->off_dpc = 4;
- cstate->off_sls = 7;
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_MTP2_WITH_PHDR:
- cstate->off_li = 6;
- cstate->off_li_hsl = 8;
- cstate->off_sio = 7;
- cstate->off_opc = 8;
- cstate->off_dpc = 8;
- cstate->off_sls = 11;
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_ERF:
- cstate->off_li = 22;
- cstate->off_li_hsl = 24;
- cstate->off_sio = 23;
- cstate->off_opc = 24;
- cstate->off_dpc = 24;
- cstate->off_sls = 27;
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_PFSYNC:
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = 4;
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = 0;
- break;
- case DLT_AX25_KISS:
- /*
- * Currently, only raw "link[N:M]" filtering is supported.
- */
- cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET; /* variable, min 16, max 71 steps of 7 */
- cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
- break;
- case DLT_IPNET:
- cstate->off_linktype.constant_part = 1;
- cstate->off_linkpl.constant_part = 24; /* ipnet header length */
- cstate->off_nl = 0;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- break;
- case DLT_NETANALYZER:
- cstate->off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */
- cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
- cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */
- cstate->off_nl = 0; /* Ethernet II */
- cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
- break;
- case DLT_NETANALYZER_TRANSPARENT:
- cstate->off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */
- cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12;
- cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */
- cstate->off_nl = 0; /* Ethernet II */
- cstate->off_nl_nosnap = 3; /* 802.3+802.2 */
- break;
- default:
- /*
- * For values in the range in which we've assigned new
- * DLT_ values, only raw "link[N:M]" filtering is supported.
- */
- if (cstate->linktype >= DLT_MATCHING_MIN &&
- cstate->linktype <= DLT_MATCHING_MAX) {
- cstate->off_linktype.constant_part = OFFSET_NOT_SET;
- cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = OFFSET_NOT_SET;
- cstate->off_nl_nosnap = OFFSET_NOT_SET;
- } else {
- bpf_set_error(cstate, "unknown data link type %d", cstate->linktype);
- …
Large files files are truncated, but you can click here to view the full file