/libpcap/gencode.c
C | 8501 lines | 5198 code | 1062 blank | 2241 comment | 529 complexity | 44fe5c8211cd324861364c01828d4ed0 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
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.
- */
- #ifndef lint
- static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.309 2008-12-23 20:13:29 guy Exp $ (LBL)";
- #endif
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #ifdef WIN32
- #include <pcap-stdinc.h>
- #else /* WIN32 */
- #if HAVE_INTTYPES_H
- #include <inttypes.h>
- #elif HAVE_STDINT_H
- #include <stdint.h>
- #endif
- #ifdef HAVE_SYS_BITYPES_H
- #include <sys/bitypes.h>
- #endif
- #include <sys/types.h>
- #include <sys/socket.h>
- #endif /* WIN32 */
- /*
- * XXX - why was this included even on UNIX?
- */
- #ifdef __MINGW32__
- #include "ip6_misc.h"
- #endif
- #ifndef WIN32
- #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 "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"
- #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 INET6
- #ifndef WIN32
- #include <netdb.h> /* for "struct addrinfo" */
- #endif /* WIN32 */
- #endif /*INET6*/
- #include <pcap/namedb.h>
- #define ETHERMTU 1500
- #ifndef IPPROTO_SCTP
- #define IPPROTO_SCTP 132
- #endif
- #ifdef HAVE_OS_PROTO_H
- #include "os-proto.h"
- #endif
- #define JMP(c) ((c)|BPF_JMP|BPF_K)
- /* Locals */
- static jmp_buf top_ctx;
- static pcap_t *bpf_pcap;
- /* Hack for updating VLAN, MPLS, and PPPoE offsets. */
- #ifdef WIN32
- static u_int orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1;
- #else
- static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
- #endif
- /* XXX */
- #ifdef PCAP_FDDIPAD
- static int pcap_fddipad;
- #endif
- /* VARARGS */
- void
- bpf_error(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- if (bpf_pcap != NULL)
- (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE,
- fmt, ap);
- va_end(ap);
- longjmp(top_ctx, 1);
- /* NOTREACHED */
- }
- static void init_linktype(pcap_t *);
- static void init_regs(void);
- static int alloc_reg(void);
- static void free_reg(int);
- static struct block *root;
- /*
- * Value passed to gen_load_a() to indicate what the offset argument
- * is relative to.
- */
- enum e_offrel {
- OR_PACKET, /* relative to the beginning of the packet */
- OR_LINK, /* relative to the beginning of the link-layer header */
- OR_MACPL, /* relative to the end of the MAC-layer header */
- OR_NET, /* relative to the network-layer header */
- OR_NET_NOSNAP, /* relative to the network-layer header, with no SNAP header at the link layer */
- OR_TRAN_IPV4, /* relative to the transport-layer header, with IPv4 network layer */
- OR_TRAN_IPV6 /* relative to the transport-layer header, with IPv6 network layer */
- };
- #ifdef INET6
- /*
- * 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.
- */
- static struct addrinfo *ai;
- #endif
- /*
- * 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 {
- u_int n_left;
- void *m;
- };
- static struct chunk chunks[NCHUNKS];
- static int cur_chunk;
- static void *newchunk(u_int);
- static void freechunks(void);
- static inline struct block *new_block(int);
- static inline struct slist *new_stmt(int);
- static struct block *gen_retblk(int);
- static inline void syntax(void);
- static void backpatch(struct block *, struct block *);
- static void merge(struct block *, struct block *);
- static struct block *gen_cmp(enum e_offrel, u_int, u_int, bpf_int32);
- static struct block *gen_cmp_gt(enum e_offrel, u_int, u_int, bpf_int32);
- static struct block *gen_cmp_ge(enum e_offrel, u_int, u_int, bpf_int32);
- static struct block *gen_cmp_lt(enum e_offrel, u_int, u_int, bpf_int32);
- static struct block *gen_cmp_le(enum e_offrel, u_int, u_int, bpf_int32);
- static struct block *gen_mcmp(enum e_offrel, u_int, u_int, bpf_int32,
- bpf_u_int32);
- static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *);
- static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32,
- bpf_u_int32, bpf_u_int32, int, bpf_int32);
- static struct slist *gen_load_llrel(u_int, u_int);
- static struct slist *gen_load_macplrel(u_int, u_int);
- static struct slist *gen_load_a(enum e_offrel, u_int, u_int);
- static struct slist *gen_loadx_iphdrlen(void);
- static struct block *gen_uncond(int);
- static inline struct block *gen_true(void);
- static inline struct block *gen_false(void);
- static struct block *gen_ether_linktype(int);
- static struct block *gen_ipnet_linktype(int);
- static struct block *gen_linux_sll_linktype(int);
- static struct slist *gen_load_prism_llprefixlen(void);
- static struct slist *gen_load_avs_llprefixlen(void);
- static struct slist *gen_load_radiotap_llprefixlen(void);
- static struct slist *gen_load_ppi_llprefixlen(void);
- static void insert_compute_vloffsets(struct block *);
- static struct slist *gen_llprefixlen(void);
- static struct slist *gen_off_macpl(void);
- static int ethertype_to_ppptype(int);
- static struct block *gen_linktype(int);
- static struct block *gen_snap(bpf_u_int32, bpf_u_int32);
- static struct block *gen_llc_linktype(int);
- static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
- #ifdef INET6
- static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int);
- #endif
- static struct block *gen_ahostop(const u_char *, int);
- static struct block *gen_ehostop(const u_char *, int);
- static struct block *gen_fhostop(const u_char *, int);
- static struct block *gen_thostop(const u_char *, int);
- static struct block *gen_wlanhostop(const u_char *, int);
- static struct block *gen_ipfchostop(const u_char *, int);
- static struct block *gen_dnhostop(bpf_u_int32, int);
- static struct block *gen_mpls_linktype(int);
- static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int);
- #ifdef INET6
- static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int);
- #endif
- #ifndef INET6
- static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);
- #endif
- static struct block *gen_ipfrag(void);
- static struct block *gen_portatom(int, bpf_int32);
- static struct block *gen_portrangeatom(int, bpf_int32, bpf_int32);
- #ifdef INET6
- static struct block *gen_portatom6(int, bpf_int32);
- static struct block *gen_portrangeatom6(int, bpf_int32, bpf_int32);
- #endif
- struct block *gen_portop(int, int, int);
- static struct block *gen_port(int, int, int);
- struct block *gen_portrangeop(int, int, int, int);
- static struct block *gen_portrange(int, int, int, int);
- #ifdef INET6
- struct block *gen_portop6(int, int, int);
- static struct block *gen_port6(int, int, int);
- struct block *gen_portrangeop6(int, int, int, int);
- static struct block *gen_portrange6(int, int, int, int);
- #endif
- static int lookup_proto(const char *, int);
- static struct block *gen_protochain(int, int, int);
- static struct block *gen_proto(int, int, int);
- static struct slist *xfer_to_x(struct arth *);
- static struct slist *xfer_to_a(struct arth *);
- static struct block *gen_mac_multicast(int);
- static struct block *gen_len(int, int);
- static struct block *gen_check_802_11_data_frame(void);
- static struct block *gen_ppi_dlt_check(void);
- static struct block *gen_msg_abbrev(int type);
- static void *
- newchunk(n)
- u_int 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 = &chunks[cur_chunk];
- if (n > cp->n_left) {
- ++cp, k = ++cur_chunk;
- if (k >= NCHUNKS)
- bpf_error("out of memory");
- size = CHUNK0SIZE << k;
- cp->m = (void *)malloc(size);
- if (cp->m == NULL)
- bpf_error("out of memory");
- memset((char *)cp->m, 0, size);
- cp->n_left = size;
- if (n > size)
- bpf_error("out of memory");
- }
- cp->n_left -= n;
- return (void *)((char *)cp->m + cp->n_left);
- }
- static void
- freechunks()
- {
- int i;
- cur_chunk = 0;
- for (i = 0; i < NCHUNKS; ++i)
- if (chunks[i].m != NULL) {
- free(chunks[i].m);
- chunks[i].m = NULL;
- }
- }
- /*
- * A strdup whose allocations are freed after code generation is over.
- */
- char *
- sdup(s)
- register const char *s;
- {
- int n = strlen(s) + 1;
- char *cp = newchunk(n);
- strlcpy(cp, s, n);
- return (cp);
- }
- static inline struct block *
- new_block(code)
- int code;
- {
- struct block *p;
- p = (struct block *)newchunk(sizeof(*p));
- p->s.code = code;
- p->head = p;
- return p;
- }
- static inline struct slist *
- new_stmt(code)
- int code;
- {
- struct slist *p;
- p = (struct slist *)newchunk(sizeof(*p));
- p->s.code = code;
- return p;
- }
- static struct block *
- gen_retblk(v)
- int v;
- {
- struct block *b = new_block(BPF_RET|BPF_K);
- b->s.k = v;
- return b;
- }
- static inline void
- syntax()
- {
- bpf_error("syntax error in filter expression");
- }
- static bpf_u_int32 netmask;
- static int snaplen;
- int no_optimize;
- #ifdef WIN32
- static int
- pcap_compile_unsafe(pcap_t *p, struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask);
- int
- pcap_compile(pcap_t *p, struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask)
- {
- int result;
- EnterCriticalSection(&g_PcapCompileCriticalSection);
- result = pcap_compile_unsafe(p, program, buf, optimize, mask);
- LeaveCriticalSection(&g_PcapCompileCriticalSection);
-
- return result;
- }
- static int
- pcap_compile_unsafe(pcap_t *p, struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask)
- #else /* WIN32 */
- int
- pcap_compile(pcap_t *p, struct bpf_program *program,
- const char *buf, int optimize, bpf_u_int32 mask)
- #endif /* WIN32 */
- {
- extern int n_errors;
- const char * volatile xbuf = buf;
- int len;
- no_optimize = 0;
- n_errors = 0;
- root = NULL;
- bpf_pcap = p;
- init_regs();
- if (setjmp(top_ctx)) {
- #ifdef INET6
- if (ai != NULL) {
- freeaddrinfo(ai);
- ai = NULL;
- }
- #endif
- lex_cleanup();
- freechunks();
- return (-1);
- }
- netmask = mask;
- snaplen = pcap_snapshot(p);
- if (snaplen == 0) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "snaplen of 0 rejects all packets");
- return -1;
- }
- lex_init(xbuf ? xbuf : "");
- init_linktype(p);
- (void)pcap_parse();
- if (n_errors)
- syntax();
- if (root == NULL)
- root = gen_retblk(snaplen);
- if (optimize && !no_optimize) {
- bpf_optimize(&root);
- if (root == NULL ||
- (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
- bpf_error("expression rejects all packets");
- }
- program->bf_insns = icode_to_fcode(root, &len);
- program->bf_len = len;
- lex_cleanup();
- freechunks();
- return (0);
- }
- /*
- * 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(list, target)
- struct block *list, *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(b0, b1)
- struct block *b0, *b1;
- {
- register struct block **p = &b0;
- /* Find end of list. */
- while (*p)
- p = !((*p)->sense) ? &JT(*p) : &JF(*p);
- /* Concatenate the lists. */
- *p = b1;
- }
- void
- finish_parse(p)
- struct block *p;
- {
- struct block *ppi_dlt_check;
- /*
- * 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(p->head);
-
- /*
- * For DLT_PPI captures, generate a check of the per-packet
- * DLT value to make sure it's DLT_IEEE802_11.
- */
- ppi_dlt_check = gen_ppi_dlt_check();
- if (ppi_dlt_check != NULL)
- gen_and(ppi_dlt_check, p);
- backpatch(p, gen_retblk(snaplen));
- p->sense = !p->sense;
- backpatch(p, gen_retblk(0));
- root = p->head;
- }
- void
- gen_and(b0, b1)
- struct block *b0, *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(b0, b1)
- struct block *b0, *b1;
- {
- b0->sense = !b0->sense;
- backpatch(b0, b1->head);
- b0->sense = !b0->sense;
- merge(b1, b0);
- b1->head = b0->head;
- }
- void
- gen_not(b)
- struct block *b;
- {
- b->sense = !b->sense;
- }
- static struct block *
- gen_cmp(offrel, offset, size, v)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- {
- return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
- }
- static struct block *
- gen_cmp_gt(offrel, offset, size, v)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- {
- return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
- }
- static struct block *
- gen_cmp_ge(offrel, offset, size, v)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- {
- return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
- }
- static struct block *
- gen_cmp_lt(offrel, offset, size, v)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- {
- return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
- }
- static struct block *
- gen_cmp_le(offrel, offset, size, v)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- {
- return gen_ncmp(offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
- }
- static struct block *
- gen_mcmp(offrel, offset, size, v, mask)
- enum e_offrel offrel;
- u_int offset, size;
- bpf_int32 v;
- bpf_u_int32 mask;
- {
- return gen_ncmp(offrel, offset, size, mask, BPF_JEQ, 0, v);
- }
- static struct block *
- gen_bcmp(offrel, offset, size, v)
- enum e_offrel offrel;
- register u_int offset, size;
- register const u_char *v;
- {
- register struct block *b, *tmp;
- b = NULL;
- while (size >= 4) {
- register const u_char *p = &v[size - 4];
- bpf_int32 w = ((bpf_int32)p[0] << 24) |
- ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3];
- tmp = gen_cmp(offrel, offset + size - 4, BPF_W, w);
- if (b != NULL)
- gen_and(b, tmp);
- b = tmp;
- size -= 4;
- }
- while (size >= 2) {
- register const u_char *p = &v[size - 2];
- bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1];
- tmp = gen_cmp(offrel, offset + size - 2, BPF_H, w);
- if (b != NULL)
- gen_and(b, tmp);
- b = tmp;
- size -= 2;
- }
- if (size > 0) {
- tmp = gen_cmp(offrel, offset, BPF_B, (bpf_int32)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(offrel, offset, size, mask, jtype, reverse, v)
- enum e_offrel offrel;
- bpf_int32 v;
- bpf_u_int32 offset, size, mask, jtype;
- int reverse;
- {
- struct slist *s, *s2;
- struct block *b;
- s = gen_load_a(offrel, offset, size);
- if (mask != 0xffffffff) {
- s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
- s2->s.k = mask;
- sappend(s, s2);
- }
- b = new_block(JMP(jtype));
- b->stmts = s;
- b->s.k = v;
- if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE))
- gen_not(b);
- return b;
- }
- /*
- * Various code constructs need to know the layout of the data link
- * layer. These variables give the necessary offsets from the beginning
- * of the packet data.
- */
- /*
- * 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.)
- */
- static u_int off_ll;
- /*
- * If there's a variable-length header preceding the link-layer header,
- * "reg_off_ll" is the register number for a register containing the
- * length of that header, and therefore the offset of the link-layer
- * header from the beginning of the raw packet data. Otherwise,
- * "reg_off_ll" is -1.
- */
- static int reg_off_ll;
- /*
- * This is the offset of the beginning of the MAC-layer header from
- * the beginning of the link-layer header.
- * It's usually 0, except for ATM LANE, where it's the offset, relative
- * to the beginning of the raw packet data, of the Ethernet header, and
- * for Ethernet with various additional information.
- */
- static u_int off_mac;
- /*
- * This is the offset of the beginning of the MAC-layer payload,
- * from the beginning of the raw packet data.
- *
- * I.e., it's the sum of the length of the link-layer header (without,
- * for example, any 802.2 LLC header, so it's the MAC-layer
- * portion of that header), plus any prefix preceding the
- * link-layer header.
- */
- static u_int off_macpl;
- /*
- * This is 1 if the offset of the beginning of the MAC-layer payload
- * from the beginning of the link-layer header is variable-length.
- */
- static int off_macpl_is_variable;
- /*
- * If the link layer has variable_length headers, "reg_off_macpl"
- * is the register number for a register containing the length of the
- * link-layer header plus the length of any variable-length header
- * preceding the link-layer header. Otherwise, "reg_off_macpl"
- * is -1.
- */
- static int reg_off_macpl;
- /*
- * "off_linktype" is the offset to information in the link-layer header
- * giving the packet type. This offset is relative to the beginning
- * of the link-layer header (i.e., it doesn't include off_ll).
- *
- * For Ethernet, it's the offset of the Ethernet type field.
- *
- * For link-layer types that always use 802.2 headers, it's the
- * offset of the LLC header.
- *
- * 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.
- *
- * It's 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;
- /*
- * 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.
- */
- static u_int off_vpi;
- static u_int off_vci;
- static u_int off_proto;
- /*
- * These are offsets for the MTP2 fields.
- */
- static u_int off_li;
- /*
- * These are offsets for the MTP3 fields.
- */
- static u_int off_sio;
- static u_int off_opc;
- static u_int off_dpc;
- static 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.
- */
- static u_int off_payload;
- /*
- * These are offsets to the beginning of the network-layer header.
- * They are relative to the beginning of the MAC-layer payload (i.e.,
- * they don't include off_ll or off_macpl).
- *
- * If the link layer never uses 802.2 LLC:
- *
- * "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.
- */
- static u_int off_nl;
- static u_int off_nl_nosnap;
- static int linktype;
- static void
- init_linktype(p)
- pcap_t *p;
- {
- linktype = pcap_datalink(p);
- #ifdef PCAP_FDDIPAD
- pcap_fddipad = p->fddipad;
- #endif
- /*
- * 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_li = -1;
- off_sio = -1;
- off_opc = -1;
- off_dpc = -1;
- off_sls = -1;
- /*
- * Also assume it's not 802.11.
- */
- off_ll = 0;
- off_macpl = 0;
- off_macpl_is_variable = 0;
- orig_linktype = -1;
- orig_nl = -1;
- label_stack_depth = 0;
- reg_off_ll = -1;
- reg_off_macpl = -1;
- switch (linktype) {
- case DLT_ARCNET:
- off_linktype = 2;
- off_macpl = 6;
- off_nl = 0; /* XXX in reality, variable! */
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_ARCNET_LINUX:
- off_linktype = 4;
- off_macpl = 8;
- off_nl = 0; /* XXX in reality, variable! */
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_EN10MB:
- off_linktype = 12;
- off_macpl = 14; /* Ethernet header length */
- off_nl = 0; /* Ethernet II */
- off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
- 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_macpl = 16;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_SLIP_BSDOS:
- /* XXX this may be the same as the DLT_PPP_BSDOS case */
- off_linktype = -1;
- /* XXX end */
- off_macpl = 24;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_NULL:
- case DLT_LOOP:
- off_linktype = 0;
- off_macpl = 4;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_ENC:
- off_linktype = 0;
- off_macpl = 12;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- 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_macpl = 4;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_PPP_ETHER:
- /*
- * This does no include the Ethernet header, and
- * only covers session state.
- */
- off_linktype = 6;
- off_macpl = 8;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_PPP_BSDOS:
- off_linktype = 5;
- off_macpl = 24;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- 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?
- */
- off_linktype = 13;
- #ifdef PCAP_FDDIPAD
- off_linktype += pcap_fddipad;
- #endif
- off_macpl = 13; /* FDDI MAC header length */
- #ifdef PCAP_FDDIPAD
- off_macpl += pcap_fddipad;
- #endif
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- 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).
- */
- off_linktype = 14;
- off_macpl = 14; /* Token Ring MAC header length */
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_IEEE802_11:
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- /*
- * 802.11 doesn't really have a link-level type field.
- * We set "off_linktype" to the offset of the LLC header.
- *
- * 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.
- */
- off_linktype = 24;
- off_macpl = 0; /* link-layer header is variable-length */
- off_macpl_is_variable = 1;
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_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.
- */
- off_linktype = 24;
- off_macpl = 0; /* link-layer header is variable-length */
- off_macpl_is_variable = 1;
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_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....
- */
- off_linktype = 0;
- off_macpl = 0; /* packet begins with LLC header */
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_SUNATM:
- /*
- * Full Frontal ATM; you get AALn PDUs with an ATM
- * pseudo-header.
- */
- is_atm = 1;
- 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_macpl = off_payload; /* if LLC-encapsulated */
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_RAW:
- case DLT_IPV4:
- case DLT_IPV6:
- off_linktype = -1;
- off_macpl = 0;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_LINUX_SLL: /* fake header for Linux cooked socket */
- off_linktype = 14;
- off_macpl = 16;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- 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.
- */
- off_linktype = -1;
- off_macpl = 0;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- 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.
- */
- off_linktype = 16;
- off_macpl = 16;
- off_nl = 8; /* 802.2+SNAP */
- off_nl_nosnap = 3; /* 802.2 */
- return;
- case DLT_FRELAY:
- /*
- * XXX - we should set this to handle SNAP-encapsulated
- * frames (NLPID of 0x80).
- */
- off_linktype = -1;
- off_macpl = 0;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- /*
- * 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:
- off_linktype = -1;
- off_macpl = 0;
- off_nl = 4;
- off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */
- return;
- case DLT_APPLE_IP_OVER_IEEE1394:
- off_linktype = 16;
- off_macpl = 18;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- case DLT_SYMANTEC_FIREWALL:
- off_linktype = 6;
- off_macpl = 44;
- off_nl = 0; /* Ethernet II */
- off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */
- return;
- #ifdef HAVE_NET_PFVAR_H
- case DLT_PFLOG:
- off_linktype = 0;
- off_macpl = PFLOG_HDRLEN;
- off_nl = 0;
- off_nl_nosnap = 0; /* no 802.2 LLC */
- return;
- #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:
- off_linktype = 4;
- off_macpl = 4;
- off_nl = 0;
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_ATM1:
- off_linktype = 4; /* in reality variable between 4-8 */
- off_macpl = 4; /* in reality variable between 4-8 */
- off_nl = 0;
- off_nl_nosnap = 10;
- return;
- case DLT_JUNIPER_ATM2:
- off_linktype = 8; /* in reality variable between 8-12 */
- off_macpl = 8; /* in reality variable between 8-12 */
- off_nl = 0;
- off_nl_nosnap = 10;
- return;
- /* frames captured on a Juniper PPPoE service PIC
- * contain raw ethernet frames */
- case DLT_JUNIPER_PPPOE:
- case DLT_JUNIPER_ETHER:
- off_macpl = 14;
- off_linktype = 16;
- off_nl = 18; /* Ethernet II */
- off_nl_nosnap = 21; /* 802.3+802.2 */
- return;
- case DLT_JUNIPER_PPPOE_ATM:
- off_linktype = 4;
- off_macpl = 6;
- off_nl = 0;
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_GGSN:
- off_linktype = 6;
- off_macpl = 12;
- off_nl = 0;
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_ES:
- off_linktype = 6;
- off_macpl = -1; /* not really a network layer but raw IP addresses */
- off_nl = -1; /* not really a network layer but raw IP addresses */
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_MONITOR:
- off_linktype = 12;
- off_macpl = 12;
- off_nl = 0; /* raw IP/IP6 header */
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_SERVICES:
- off_linktype = 12;
- off_macpl = -1; /* L3 proto location dep. on cookie type */
- off_nl = -1; /* L3 proto location dep. on cookie type */
- off_nl_nosnap = -1; /* no 802.2 LLC */
- return;
- case DLT_JUNIPER_VP:
- off_linktype = 18;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_JUNIPER_ST:
- off_linktype = 18;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_JUNIPER_ISM:
- off_linktype = 8;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_JUNIPER_VS:
- case DLT_JUNIPER_SRX_E2E:
- case DLT_JUNIPER_FIBRECHANNEL:
- case DLT_JUNIPER_ATM_CEMIC:
- off_linktype = 8;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_MTP2:
- off_li = 2;
- off_sio = 3;
- off_opc = 4;
- off_dpc = 4;
- off_sls = 7;
- off_linktype = -1;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_MTP2_WITH_PHDR:
- off_li = 6;
- off_sio = 7;
- off_opc = 8;
- off_dpc = 8;
- off_sls = 11;
- off_linktype = -1;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- case DLT_ERF:
- off_li = 22;
- off_sio = 23;
- off_opc = 24;
- off_dpc = 24;
- off_sls = 27;
- off_linktype = -1;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- #ifdef DLT_PFSYNC
- case DLT_PFSYNC:
- off_linktype = -1;
- off_macpl = 4;
- off_nl = 0;
- off_nl_nosnap = 0;
- return;
- #endif
- 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_macpl = -1;
- off_nl = -1; /* variable, min 16, max 71 steps of 7 */
- off_nl_nosnap = -1; /* no 802.2 LLC */
- off_mac = 1; /* step over the kiss length byte */
- return;
- case DLT_IPNET:
- off_linktype = 1;
- off_macpl = 24; /* ipnet header length */
- off_nl = 0;
- off_nl_nosnap = -1;
- return;
- case DLT_NETANALYZER:
- off_mac = 4; /* MAC header is past 4-byte pseudo-header */
- off_linktype = 16; /* includes 4-byte pseudo-header */
- off_macpl = 18; /* pseudo-header+Ethernet header length */
- off_nl = 0; /* Ethernet II */
- off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
- 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_macpl = 26; /* pseudo-header+preamble+SFD+Ethernet header length */
- off_nl = 0; /* Ethernet II */
- off_nl_nosnap = 3; /* 802.3+802.2 */
- return;
- default:
- /*
- * For values in the range in which we've assigned new
- * DLT_ values, only raw "link[N:M]" filtering is supported.
- */
- if (linktype >= DLT_MATCHING_MIN &&
- linktype <= DLT_MATCHING_MAX) {
- off_linktype = -1;
- off_macpl = -1;
- off_nl = -1;
- off_nl_nosnap = -1;
- return;
- }
- }
- 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;
- }
- /*
- * Load a value relative to the beginning of the MAC-layer payload.
- */
- static struct slist *
- gen_load_macplrel(offset, size)
- u_int offset, size;
- {
- struct slist *s, *s2;
- s = gen_off_macpl();
- /*
- * If s is non-null, the offset of the MAC-layer payload is
- * variable, and s points to a list of instructions that
- * arrange that the X register contains that offset.
- *
- * Otherwise, the offset of the MAC-layer payload is constant,
- * and is in off_macpl.
- */
- if (s != NULL) {
- /*
- * The offset of the MAC-layer payload is in the X
- * register. Do an indirect load, to use the X register
- * as an offset.
- */
- s2 = new_stmt(BPF_LD|BPF_IND|size);
- s2->s.k = offset;
- sappend(s, s2);
- } else {
- /*
- * The offset of the MAC-layer payload is constant,
- * and is in off_macpl; load the value at that offset
- * plus the specified offset.
- */
- s = new_stmt(BPF_LD|BPF_ABS|size);
- s->s.k = off_macpl + offset;
- }
- return s;
- }
- /*
- * Load a value relative to the beginning of the specified header.
- */
- static struct slist *
- gen_load_a(offrel, offset, size)
- enum e_offrel offrel;
- u_int offset, size;
- {
- struct slist *s, *s2;
- switch (offrel) {
- case OR_PACKET:
- s = new_stmt(BPF_LD|BPF_ABS|size);
- s->s.k = offset;
- break;
- case OR_LINK:
- s = gen_load_llrel(offset, size);
- break;
- case OR_MACPL:
- s = gen_load_macplrel(offset, size);
- break;
- case OR_NET:
- s = gen_load_macplrel(off_nl + offset, size);
- break;
- case OR_NET_NOSNAP:
- s = gen_load_macplrel(off_nl_nosnap + offset, size);
- break;
- case OR_TRAN_IPV4:
- /*
- * Load the X register with the length of the IPv4 header
- * (plus the offset of the link-layer header, if it's
- * preceded by a variable-length header such as a radio
- * header), in bytes.
- */
- s = gen_loadx_iphdrlen();
- /*
- * Load the item at {offset of the MAC-layer payload} +
- * {offset, relative to the start of the MAC-layer
- * paylod, of the IPv4 header} + {length of the IPv4 header} +
- * {specified offset}.
- *
- * (If the offset of the MAC-layer payload is variable,
- * it's included in the value in the X register, and
- * off_macpl is 0.)
- */
- s2 = new_stmt(BPF_LD|BPF_IND|size);
- s2->s.k = off_macpl + off_nl + offset;
- sappend(s, s2);
- break;
- case OR_TRAN_IPV6:
- s = gen_load_macplrel(off_nl + 40 + offset, size);
- break;
- default:
- abort();
- return NULL;
- }
- return s;
- }
- /*
- * Generate code to load into the X register the sum of the length of
- * the IPv4 header and any variable-length header preceding the link-layer
- * header.
- */
- static struct slist *
- gen_loadx_iphdrlen()
- {
- struct slist *s, *s2;
- s = gen_off_macpl();
- if (s != NULL) {
- /*
- * There's a variable-length prefix preceding the
- * link-layer header, or the link-layer header is itself
- * variable-length. "s" points to a list of statements
- * that put the offset of the MAC-layer payload into
- * the X register.
- *
- * The 4*([k]&0xf) addressing mode can't be used, as we
- * don't have a constant offset, so we have to load the
- * value in question into the A register and add to it
- * the value from the X register.
- */
- s2 = new_stmt(BPF_LD|BPF_IND|BPF_B);
- s2->s.k = off_nl;
- sappend(s, s2);
- s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
- s2->s.k = 0xf;
- sappend(s, s2);
- s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K);
- s2->s.k = 2;
- sappend(s, s2);
- /*
- * The A register now contains the length of the
- * IP header. We need to add to it the offset of
- * the MAC-layer payload, which is still in the X
- * register, and move the result into the X register.
- */
- sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
- sappend(s, new_stmt(BPF_MISC|BPF_TAX));
- } else {
- /*
- * There is no variable-length header preceding the
- * link-layer header, and the link-layer header is
- * fixed-length; load the length of the IPv4 header,
- * which is at an offset of off_nl from the beginning
- * of the MAC-layer payload, and thus at an offset
- * of off_mac_pl + off_nl from the beginning of the
- * raw packet data.
- */
- s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
- s->s.k = off_macpl + off_nl;
- }
- return s;
- }
- static struct block *
- gen_uncond(rsense)
- int rsense;
- {
- struct block *b;
- struct slist *s;
- s = new_stmt(BPF_LD|BPF_IMM);
- s->s.k = !rsense;
- b = new_block(JMP(BPF_JEQ));
- b->stmts = s;
- return b;
- }
- static inline struct block *
- gen_true()
- {
- return gen_uncond(1);
- }
- static inline struct block *
- gen_false()
- {
- return gen_uncond(0);
- }
- /*
- * Byte-swap a 32-bit number.
- * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on
- * big-endian platforms.)
- */
- #define SWAPLONG(y) \
- ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
- /*
- * Generate code to match a particular packet type.
- *
- * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
- * value, if <= ETHERMTU. We use that to determine whether to
- * match the type/length field or to check the type/length field for
- * a value <= ETHERMTU to see whether it's a type field and then do
- * the appropriate test.
- */
- static struct block *
- gen_ether_linktype(proto)
- register int proto;
- {
- struct block *b0, *b1;
- switch (proto) {
- case LLCSAP_ISONS:
- case LLCSAP_IP:
- case LLCSAP_NETBEUI:
- /*
- * OSI protocols and NetBEUI always use 802.2 encapsulation,
- * so we check the DSAP and SSAP.
- *
- * LLCSAP_IP checks for IP-over-802.2, rather
- * than IP-over-Ethernet or IP-over-SNAP.
- *
- * XXX - should we check both the DSAP and the
- * SSAP, like this, or should we check just the
- * DSAP, as we do for other types <= ETHERMTU
- * (i.e., other SAP values)?
- */
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
- gen_not(b0);
- b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
- ((proto << 8) | proto));
- gen_and(b0, b1);
- return b1;
- case LLCSAP_IPX:
- /*
- * Check for;
- *
- * Ethernet_II frames, which are Ethernet
- * frames with a frame type of ETHERTYPE_IPX;
- *
- * Ethernet_802.3 frames, which are 802.3
- * frames (i.e., the type/length field is
- * a length field, <= ETHERMTU, rather than
- * a type field) with the first two bytes
- * after the Ethernet/802.3 header being
- * 0xFFFF;
- *
- * Ethernet_802.2 frames, which are 802.3
- * frames with an 802.2 LLC header and
- * with the IPX LSAP as the DSAP in the LLC
- * header;
- *
- * Ethernet_SNAP frames, which are 802.3
- * frames with an LLC header and a SNAP
- * header and with an OUI of 0x000000
- * (encapsulated Ethernet) and a protocol
- * ID of ETHERTYPE_IPX in the SNAP header.
- *
- * XXX - should we generate the same code both
- * for tests for LLCSAP_IPX and for ETHERTYPE_IPX?
- */
- /*
- * This generates code to check both for the
- * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
- */
- b0 = gen_cmp(OR_MACPL, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
- b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)0xFFFF);
- gen_or(b0, b1);
- /*
- * Now we add code to check for SNAP frames with
- * ETHERTYPE_IPX, i.e. Ethernet_SNAP.
- */
- b0 = gen_snap(0x000000, ETHERTYPE_IPX);
- gen_or(b0, b1);
- /*
- * Now we generate code to check for 802.3
- * frames in general.
- */
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
- gen_not(b0);
- /*
- * Now add the check for 802.3 frames before the
- * check for Ethernet_802.2 and Ethernet_802.3,
- * as those checks should only be done on 802.3
- * frames, not on Ethernet frames.
- */
- gen_and(b0, b1);
- /*
- * Now add the check for Ethernet_II frames, and
- * do that before checking for the other frame
- * types.
- */
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
- (bpf_int32)ETHERTYPE_IPX);
- gen_or(b0, b1);
- return b1;
- case ETHERTYPE_ATALK:
- case ETHERTYPE_AARP:
- /*
- * EtherTalk (AppleTalk protocols on Ethernet link
- * layer) may use 802.2 encapsulation.
- */
- /*
- * Check for 802.2 encapsulation (EtherTalk phase 2?);
- * 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);
- gen_not(b0);
- /*
- * 802.2-encapsulated ETHERTYPE_ATALK packets are
- * SNAP packets with an organization code of
- * 0x080007 (Apple, for Appletalk) and a protocol
- * type of ETHERTYPE_ATALK (Appletalk).
- *
- * 802.2-encapsulated ETHERTYPE_AARP packets are
- * SNAP packets with an organization code of
- * 0x000000 (encapsulated Ethernet) and a protocol
- * type of ETHERTYPE_AARP (Appletalk ARP).
- */
- if (proto == ETHERTYPE_ATALK)
- b1 = gen_snap(0x080007, ETHERTYPE_ATALK);
- else /* proto == ETHERTYPE_AARP */
- b1 = gen_snap(0x000000, ETHERTYPE_AARP);
- gen_and(b0, b1);
- /*
- * Check for Ethernet encapsulation (Ethertalk
- * phase 1?); we just check for the Ethernet
- * protocol type.
- */
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);
- gen_or(b0, b1);
- return b1;
- default:
- if (proto <= ETHERMTU) {
- /*
- * This is an LLC SAP value, so the frames
- * that match would be 802.2 frames.
- * Check that the frame is an 802.2 frame
- * (i.e., that the length/type field is
- * a length field, <= ETHERMTU) and
- * then check the DSAP.
- */
- b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU);
- gen_not(b0);
- b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,
- (bpf_int32)proto);
- gen_and(b0, b1);
- return b1;
- } else {
- /*
- * This is an Ethernet type, so compare
- * the length/type field with it (if
- * the frame is an 802.2 frame, the length
- * field will be <= ETHERMTU, and, as
- * "proto" is > ETHERMTU, this test
- * 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);
- }
- }
- }
- /*
- * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
- * or IPv6 then we have an error.
- */
- static struct block *
- gen_ipnet_linktype(proto)
- register int proto;
- {
- switch (proto) {
- case ETHERTYPE_IP:
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
- (bpf_int32)IPH_AF_INET);
- /* NOTREACHED */
- case ETHERTYPE_IPV6:
- return gen_cmp(OR_LINK, off_linktype, BPF_B,
- (bpf_int32)IPH_AF_INET6);
- /* NOTREACHED */
- default:
- break;
- }
- return gen_false();
- }
- /*
- * Generate code to match a particular packet type.
- *
- * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
- * value, if <= ETHERMTU. We use that to determine whether to
- * match the type field or to check the type field for the special
- * LINUX_SLL_P_802_2 value and then do the appropriate test.
- */
- static struct block *
- gen_linux_sll_linktype(proto)
- register int proto;
- {
- struct block *b0, *b1;
- switch (proto) {
- case LLCSAP_ISONS:
- case LLCSAP_IP:
- case LLCSAP_NETBEUI:
- /*
- * OSI protocols and NetBEUI always use 802.2 encapsulation,
- * so we check the DSAP and SSAP.
- *
- * LLCSAP_IP checks for IP-over-802.2, rather
- * than IP-over-Ethernet or IP-over-SNAP.
- *
- * XXX - should we check both the DSAP and the
- * SSAP, like this, or should we check just the
- * DSAP, as we do for other types <= ETHERMTU
- * (i.e., other SAP values)?
- */
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);
- b1 = gen_cmp(OR_MACPL, 0, BPF_H, (bpf_int32)
- ((proto << 8) | proto));
- gen_and(b0, b1);
- return b1;
- case LLCSAP_IPX:
- /*
- * Ethernet_II frames, which are Ethernet
- * frames with a frame type of ETHERTYPE_IPX;
- *
- * Ethernet_802.3 frames, which have a frame
- * type of LINUX_SLL_P_802_3;
- *
- * Ethernet_802.2 frames, which are 802.3
- * frames with an 802.2 LLC header (i.e, have
- * a frame type of LINUX_SLL_P_802_2) and
- * with the IPX LSAP as the DSAP in the LLC
- * header;
- *
- * Ethernet_SNAP frames, which are 802.3
- * frames with an LLC header and a SNAP
- * header and with an OUI of 0x000000
- * (encapsulated Ethernet) and a protocol
- * ID of ETHERTYPE_IPX in the SNAP header.
- *
- * First, do the checks on LINUX_SLL_P_802_2
- * frames; generate the check for either
- * Ethernet_802.2 or Ethernet_SNAP frames, and
- * then put a check for LINUX_SLL_P_…
Large files files are truncated, but you can click here to view the full file