summaryrefslogtreecommitdiffstats
path: root/freebsd/contrib/libpcap/gencode.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/contrib/libpcap/gencode.c')
-rw-r--r--freebsd/contrib/libpcap/gencode.c809
1 files changed, 536 insertions, 273 deletions
diff --git a/freebsd/contrib/libpcap/gencode.c b/freebsd/contrib/libpcap/gencode.c
index 8c303415..df75cacd 100644
--- a/freebsd/contrib/libpcap/gencode.c
+++ b/freebsd/contrib/libpcap/gencode.c
@@ -20,38 +20,24 @@
* 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.
- *
- * $FreeBSD$
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
#endif
+#include <pcap-types.h>
#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 */
-
-#ifndef _WIN32
-
-#ifdef __NetBSD__
-#include <sys/param.h>
-#endif
+ #include <ws2tcpip.h>
+#else
+ #include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+ #ifdef __NetBSD__
+ #include <sys/param.h>
+ #endif
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
#endif /* _WIN32 */
#include <stdlib.h>
@@ -98,17 +84,17 @@
#define offsetof(s, e) ((size_t)&((s *)0)->e)
#endif
-#ifdef INET6
#ifdef _WIN32
-#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+ #ifdef INET6
+ #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
/* IPv6 address */
struct in6_addr
{
union
{
- u_int8_t u6_addr8[16];
- u_int16_t u6_addr16[8];
- u_int32_t u6_addr32[4];
+ 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
@@ -125,12 +111,12 @@ typedef unsigned short sa_family_t;
struct sockaddr_in6
{
__SOCKADDR_COMMON (sin6_);
- u_int16_t sin6_port; /* Transport layer port # */
- u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ uint16_t sin6_port; /* Transport layer port # */
+ uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
};
-#ifndef EAI_ADDRFAMILY
+ #ifndef EAI_ADDRFAMILY
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */
@@ -141,12 +127,12 @@ struct addrinfo {
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 /* EAI_ADDRFAMILY */
+ #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */
+ #endif /* INET6 */
#else /* _WIN32 */
-#include <netdb.h> /* for "struct addrinfo" */
+ #include <netdb.h> /* for "struct addrinfo" */
#endif /* _WIN32 */
-#endif /* INET6 */
#include <pcap/namedb.h>
#include "nametoaddr.h"
@@ -281,7 +267,6 @@ struct _compiler_state {
/* XXX */
u_int pcap_fddipad;
-#ifdef INET6
/*
* As errors are handled by a longjmp, anything allocated must
* be freed in the longjmp handler, so it must be reachable
@@ -292,7 +277,6 @@ struct _compiler_state {
* any addrinfo structure that would need to be freed.
*/
struct addrinfo *ai;
-#endif
/*
* Various code constructs need to know the layout of the packet.
@@ -362,6 +346,11 @@ struct _compiler_state {
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;
@@ -430,7 +419,7 @@ struct _compiler_state {
int cur_chunk;
};
-void
+void PCAP_NORETURN
bpf_syntax_error(compiler_state_t *cstate, const char *msg)
{
bpf_error(cstate, "syntax error in filter expression: %s", msg);
@@ -438,7 +427,7 @@ bpf_syntax_error(compiler_state_t *cstate, const char *msg)
}
/* VARARGS */
-void
+void PCAP_NORETURN
bpf_error(compiler_state_t *cstate, const char *fmt, ...)
{
va_list ap;
@@ -528,7 +517,7 @@ static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
#endif
#ifndef INET6
static struct block *gen_gateway(compiler_state_t *, const u_char *,
- bpf_u_int32 **, int, int);
+ struct addrinfo *, int, int);
#endif
static struct block *gen_ipfrag(compiler_state_t *);
static struct block *gen_portatom(compiler_state_t *, int, bpf_int32);
@@ -587,7 +576,8 @@ newchunk(compiler_state_t *cstate, size_t n)
cp = &cstate->chunks[cstate->cur_chunk];
if (n > cp->n_left) {
- ++cp, k = ++cstate->cur_chunk;
+ ++cp;
+ k = ++cstate->cur_chunk;
if (k >= NCHUNKS)
bpf_error(cstate, "out of memory");
size = CHUNK0SIZE << k;
@@ -658,7 +648,7 @@ gen_retblk(compiler_state_t *cstate, int v)
return b;
}
-static inline void
+static inline PCAP_NORETURN_DEF void
syntax(compiler_state_t *cstate)
{
bpf_error(cstate, "syntax error in filter expression");
@@ -668,6 +658,9 @@ 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;
@@ -675,14 +668,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
u_int len;
int rc;
-#ifdef _WIN32
- static int done = 0;
-
- if (!done)
- pcap_wsockinit();
- done = 1;
-#endif
-
/*
* If this pcap_t hasn't been activated, it doesn't have a
* link-layer type, so we can't use it.
@@ -690,9 +675,36 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
if (!p->activated) {
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"not-yet-activated pcap_t passed to pcap_compile");
- rc = -1;
- goto quit;
+ 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 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
@@ -723,7 +735,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
}
if (pcap_lex_init(&scanner) != 0)
- bpf_error(&cstate, "can't initialize scanner: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "can't initialize scanner");
in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
/*
@@ -807,8 +820,7 @@ pcap_freecode(struct bpf_program *program)
* in each block is already resolved.
*/
static void
-backpatch(list, target)
- struct block *list, *target;
+backpatch(struct block *list, struct block *target)
{
struct block *next;
@@ -829,8 +841,7 @@ backpatch(list, target)
* which of jt and jf is the link.
*/
static void
-merge(b0, b1)
- struct block *b0, *b1;
+merge(struct block *b0, struct block *b1)
{
register struct block **p = &b0;
@@ -892,8 +903,7 @@ finish_parse(compiler_state_t *cstate, struct block *p)
}
void
-gen_and(b0, b1)
- struct block *b0, *b1;
+gen_and(struct block *b0, struct block *b1)
{
backpatch(b0, b1->head);
b0->sense = !b0->sense;
@@ -904,8 +914,7 @@ gen_and(b0, b1)
}
void
-gen_or(b0, b1)
- struct block *b0, *b1;
+gen_or(struct block *b0, struct block *b1)
{
b0->sense = !b0->sense;
backpatch(b0, b1->head);
@@ -915,8 +924,7 @@ gen_or(b0, b1)
}
void
-gen_not(b)
- struct block *b;
+gen_not(struct block *b)
{
b->sense = !b->sense;
}
@@ -1068,10 +1076,10 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
* Assume it's not raw ATM with a pseudo-header, for now.
*/
cstate->is_atm = 0;
- cstate->off_vpi = -1;
- cstate->off_vci = -1;
- cstate->off_proto = -1;
- cstate->off_payload = -1;
+ 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.
@@ -1079,14 +1087,19 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
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 = -1;
- cstate->off_li_hsl = -1;
- cstate->off_sio = -1;
- cstate->off_opc = -1;
- cstate->off_dpc = -1;
- cstate->off_sls = -1;
+ 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;
@@ -1096,7 +1109,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
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 = 0; /* XXX in reality, variable! */
cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
break;
@@ -1410,7 +1423,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->off_linktype.constant_part = 4;
cstate->off_linkpl.constant_part = 4;
cstate->off_nl = 0;
- cstate->off_nl_nosnap = -1; /* no 802.2 LLC */
+ cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */
break;
case DLT_JUNIPER_ATM1:
@@ -1441,63 +1454,63 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->off_linktype.constant_part = 4;
cstate->off_linkpl.constant_part = 6;
cstate->off_nl = 0;
- cstate->off_nl_nosnap = -1; /* no 802.2 LLC */
+ 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 = -1; /* no 802.2 LLC */
+ 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 = -1; /* not really a network layer but raw IP addresses */
- cstate->off_nl_nosnap = -1; /* no 802.2 LLC */
+ 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 = -1; /* no 802.2 LLC */
+ 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 = -1;
- cstate->off_nl_nosnap = -1;
+ 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 = -1; /* L3 proto location dep. on cookie type */
- cstate->off_nl_nosnap = -1; /* no 802.2 LLC */
+ 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 = -1;
- cstate->off_nl_nosnap = -1;
+ 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 = -1;
- cstate->off_nl_nosnap = -1;
+ 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 = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_JUNIPER_VS:
@@ -1506,8 +1519,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
case DLT_JUNIPER_ATM_CEMIC:
cstate->off_linktype.constant_part = 8;
cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_MTP2:
@@ -1519,8 +1532,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->off_sls = 7;
cstate->off_linktype.constant_part = OFFSET_NOT_SET;
cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_MTP2_WITH_PHDR:
@@ -1532,8 +1545,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->off_sls = 11;
cstate->off_linktype.constant_part = OFFSET_NOT_SET;
cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_ERF:
@@ -1545,8 +1558,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->off_sls = 27;
cstate->off_linktype.constant_part = OFFSET_NOT_SET;
cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_PFSYNC:
@@ -1562,15 +1575,15 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
*/
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 = -1; /* variable, min 16, max 71 steps of 7 */
- cstate->off_nl_nosnap = -1; /* no 802.2 LLC */
+ 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 = -1;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
break;
case DLT_NETANALYZER:
@@ -1598,8 +1611,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
cstate->linktype <= DLT_MATCHING_MAX) {
cstate->off_linktype.constant_part = OFFSET_NOT_SET;
cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
- cstate->off_nl = -1;
- cstate->off_nl_nosnap = -1;
+ cstate->off_nl = OFFSET_NOT_SET;
+ cstate->off_nl_nosnap = OFFSET_NOT_SET;
} else {
bpf_error(cstate, "unknown data link type %d", cstate->linktype);
}
@@ -1724,7 +1737,7 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
default:
abort();
- return NULL;
+ /* NOTREACHED */
}
return s;
}
@@ -1788,6 +1801,7 @@ gen_loadx_iphdrlen(compiler_state_t *cstate)
return s;
}
+
static struct block *
gen_uncond(compiler_state_t *cstate, int rsense)
{
@@ -2805,6 +2819,28 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
}
/*
+ * If there there is no initialization yet and we need variable
+ * length offsets for VLAN, initialize them to zero
+ */
+ if (s == NULL && cstate->is_vlan_vloffset) {
+ struct slist *s2;
+
+ if (cstate->off_linkpl.reg == -1)
+ cstate->off_linkpl.reg = alloc_reg(cstate);
+ if (cstate->off_linktype.reg == -1)
+ cstate->off_linktype.reg = alloc_reg(cstate);
+
+ s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM);
+ s->s.k = 0;
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linkpl.reg;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = cstate->off_linktype.reg;
+ sappend(s, s2);
+ }
+
+ /*
* If we have any offset-loading code, append all the
* existing statements in the block to those statements,
* and make the resulting list the list of statements
@@ -2890,8 +2926,7 @@ gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
* Map an Ethernet type to the equivalent PPP type.
*/
static int
-ethertype_to_ppptype(proto)
- int proto;
+ethertype_to_ppptype(int proto)
{
switch (proto) {
@@ -2978,7 +3013,7 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
*/
#define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */
#define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */
-#define BSD_AFNUM_INET6_DARWIN 30 /* OS X, iOS, other Darwin-based OSes */
+#define BSD_AFNUM_INET6_DARWIN 30 /* macOS, iOS, other Darwin-based OSes */
/*
* Generate code to match a particular packet type by matching the
@@ -3534,14 +3569,14 @@ gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype)
{
u_char snapblock[8];
- snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */
- snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */
- snapblock[2] = 0x03; /* control = UI */
- snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */
- snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */
- snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */
- snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */
- snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */
+ snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */
+ snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */
+ snapblock[2] = 0x03; /* control = UI */
+ snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */
+ snapblock[4] = (u_char)(orgcode >> 8); /* middle 8 bits of organization code */
+ snapblock[5] = (u_char)(orgcode >> 0); /* lower 8 bits of organization code */
+ snapblock[6] = (u_char)(ptype >> 8); /* upper 8 bits of protocol type */
+ snapblock[7] = (u_char)(ptype >> 0); /* lower 8 bits of protocol type */
return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock);
}
@@ -3834,6 +3869,30 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
gen_or(b0, b1);
return b1;
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ break;
+
default:
abort();
}
@@ -3850,7 +3909,7 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
{
struct block *b0, *b1;
u_int offset;
- u_int32_t *a, *m;
+ uint32_t *a, *m;
switch (dir) {
@@ -3875,12 +3934,36 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
gen_or(b0, b1);
return b1;
+ case Q_ADDR1:
+ bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR2:
+ bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR3:
+ bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_ADDR4:
+ bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_RA:
+ bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ break;
+
+ case Q_TA:
+ bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses");
+ break;
+
default:
abort();
}
/* this order is important */
- a = (u_int32_t *)addr;
- m = (u_int32_t *)mask;
+ a = (uint32_t *)addr;
+ m = (uint32_t *)mask;
b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
gen_and(b0, b1);
@@ -3920,19 +4003,19 @@ gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
return b1;
case Q_ADDR1:
- bpf_error(cstate, "'addr1' is only supported on 802.11 with 802.11 headers");
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers");
break;
case Q_ADDR2:
- bpf_error(cstate, "'addr2' is only supported on 802.11 with 802.11 headers");
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers");
break;
case Q_ADDR3:
- bpf_error(cstate, "'addr3' is only supported on 802.11 with 802.11 headers");
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers");
break;
case Q_ADDR4:
- bpf_error(cstate, "'addr4' is only supported on 802.11 with 802.11 headers");
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers");
break;
case Q_RA:
@@ -3976,19 +4059,19 @@ gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
return b1;
case Q_ADDR1:
- bpf_error(cstate, "'addr1' is only supported on 802.11");
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
break;
case Q_ADDR2:
- bpf_error(cstate, "'addr2' is only supported on 802.11");
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
break;
case Q_ADDR3:
- bpf_error(cstate, "'addr3' is only supported on 802.11");
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
break;
case Q_ADDR4:
- bpf_error(cstate, "'addr4' is only supported on 802.11");
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
break;
case Q_RA:
@@ -4032,19 +4115,19 @@ gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
return b1;
case Q_ADDR1:
- bpf_error(cstate, "'addr1' is only supported on 802.11");
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
break;
case Q_ADDR2:
- bpf_error(cstate, "'addr2' is only supported on 802.11");
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
break;
case Q_ADDR3:
- bpf_error(cstate, "'addr3' is only supported on 802.11");
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
break;
case Q_ADDR4:
- bpf_error(cstate, "'addr4' is only supported on 802.11");
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
break;
case Q_RA:
@@ -4513,19 +4596,19 @@ gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
return b1;
case Q_ADDR1:
- bpf_error(cstate, "'addr1' is only supported on 802.11");
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
break;
case Q_ADDR2:
- bpf_error(cstate, "'addr2' is only supported on 802.11");
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
break;
case Q_ADDR3:
- bpf_error(cstate, "'addr3' is only supported on 802.11");
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
break;
case Q_ADDR4:
- bpf_error(cstate, "'addr4' is only supported on 802.11");
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
break;
case Q_RA:
@@ -4641,7 +4724,7 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto)
case Q_IP:
/* match the bottom-of-stack bit */
- b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01);
+ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0);
gen_and(b0, b1);
@@ -4649,7 +4732,7 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto)
case Q_IPV6:
/* match the bottom-of-stack bit */
- b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01);
+ b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0);
gen_and(b0, b1);
@@ -4909,10 +4992,12 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr,
#ifndef INET6
static struct block *
-gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist,
- int proto, int dir)
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr,
+ struct addrinfo *alist, int proto, int dir)
{
struct block *b0, *b1, *tmp;
+ struct addrinfo *ai;
+ struct sockaddr_in *sin;
if (dir != 0)
bpf_error(cstate, "direction applied to 'gateway'");
@@ -4960,12 +5045,48 @@ gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist,
bpf_error(cstate,
"'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
}
- b1 = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST);
- while (*alist) {
- tmp = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR,
- Q_HOST);
- gen_or(b1, tmp);
- b1 = tmp;
+ b1 = NULL;
+ for (ai = alist; ai != NULL; ai = ai->ai_next) {
+ /*
+ * Does it have an address?
+ */
+ if (ai->ai_addr != NULL) {
+ /*
+ * Yes. Is it an IPv4 address?
+ */
+ if (ai->ai_addr->sa_family == AF_INET) {
+ /*
+ * Generate an entry for it.
+ */
+ sin = (struct sockaddr_in *)ai->ai_addr;
+ tmp = gen_host(cstate,
+ ntohl(sin->sin_addr.s_addr),
+ 0xffffffff, proto, Q_OR, Q_HOST);
+ /*
+ * Is it the *first* IPv4 address?
+ */
+ if (b1 == NULL) {
+ /*
+ * Yes, so start with it.
+ */
+ b1 = tmp;
+ } else {
+ /*
+ * No, so OR it into the
+ * existing set of
+ * addresses.
+ */
+ gen_or(b1, tmp);
+ b1 = tmp;
+ }
+ }
+ }
+ }
+ if (b1 == NULL) {
+ /*
+ * No IPv4 addresses found.
+ */
+ return (NULL);
}
gen_not(b1);
gen_and(b0, b1);
@@ -5647,9 +5768,7 @@ lookup_proto(compiler_state_t *cstate, const char *name, int proto)
#if 0
struct stmt *
-gen_joinsp(s, n)
- struct stmt **s;
- int n;
+gen_joinsp(struct stmt **s, int n)
{
return NULL;
}
@@ -5699,7 +5818,7 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
if (cstate->off_linkpl.is_variable)
bpf_error(cstate, "'protochain' not supported with variable length headers");
- cstate->no_optimize = 1; /*this code is not compatible with optimzer yet */
+ cstate->no_optimize = 1; /* this code is not compatible with optimizer yet */
/*
* s[0] is a dummy entry to protect other BPF insn from damage
@@ -6203,13 +6322,11 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
int tproto;
u_char *eaddr;
bpf_u_int32 mask, addr;
-#ifndef INET6
- bpf_u_int32 **alist;
-#else
- int tproto6;
+ struct addrinfo *res, *res0;
struct sockaddr_in *sin4;
+#ifdef INET6
+ int tproto6;
struct sockaddr_in6 *sin6;
- struct addrinfo *res, *res0;
struct in6_addr mask128;
#endif /*INET6*/
struct block *b, *tmp;
@@ -6308,46 +6425,39 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
*/
return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr));
} else {
-#ifndef INET6
- alist = pcap_nametoaddr(name);
- if (alist == NULL || *alist == NULL)
- bpf_error(cstate, "unknown host '%s'", name);
- tproto = proto;
- if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
- tproto == Q_DEFAULT)
- tproto = Q_IP;
- b = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr);
- while (*alist) {
- tmp = gen_host(cstate, **alist++, 0xffffffff,
- tproto, dir, q.addr);
- gen_or(b, tmp);
- b = tmp;
- }
- return b;
-#else
+#ifdef INET6
memset(&mask128, 0xff, sizeof(mask128));
+#endif
res0 = res = pcap_nametoaddrinfo(name);
if (res == NULL)
bpf_error(cstate, "unknown host '%s'", name);
cstate->ai = res;
b = tmp = NULL;
- tproto = tproto6 = proto;
+ tproto = proto;
+#ifdef INET6
+ tproto6 = proto;
+#endif
if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
tproto == Q_DEFAULT) {
tproto = Q_IP;
+#ifdef INET6
tproto6 = Q_IPV6;
+#endif
}
for (res = res0; res; res = res->ai_next) {
switch (res->ai_family) {
case AF_INET:
+#ifdef INET6
if (tproto == Q_IPV6)
continue;
+#endif
sin4 = (struct sockaddr_in *)
res->ai_addr;
tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr),
0xffffffff, tproto, dir, q.addr);
break;
+#ifdef INET6
case AF_INET6:
if (tproto6 == Q_IP)
continue;
@@ -6357,6 +6467,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
tmp = gen_host6(cstate, &sin6->sin6_addr,
&mask128, tproto6, dir, q.addr);
break;
+#endif
default:
continue;
}
@@ -6373,7 +6484,6 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
: " for specified address family");
}
return b;
-#endif /*INET6*/
}
case Q_PORT:
@@ -6471,11 +6581,15 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
if (eaddr == NULL)
bpf_error(cstate, "unknown ether host: %s", name);
- alist = pcap_nametoaddr(name);
- if (alist == NULL || *alist == NULL)
+ res = pcap_nametoaddrinfo(name);
+ cstate->ai = res;
+ if (res == NULL)
+ bpf_error(cstate, "unknown host '%s'", name);
+ b = gen_gateway(cstate, eaddr, res, proto, dir);
+ cstate->ai = NULL;
+ freeaddrinfo(res);
+ if (b == NULL)
bpf_error(cstate, "unknown host '%s'", name);
- b = gen_gateway(cstate, eaddr, alist, proto, dir);
- free(eaddr);
return b;
#else
bpf_error(cstate, "'gateway' not supported in this configuration");
@@ -6548,7 +6662,6 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
/* NOTREACHED */
}
/* NOTREACHED */
- return NULL;
}
struct block *
@@ -6667,7 +6780,7 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
struct in6_addr *addr;
struct in6_addr mask;
struct block *b;
- u_int32_t *a, *m;
+ uint32_t *a, *m;
if (s2)
bpf_error(cstate, "no mask %s supported", s2);
@@ -6689,8 +6802,8 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
(0xff << (8 - masklen % 8)) & 0xff;
}
- a = (u_int32_t *)addr;
- m = (u_int32_t *)&mask;
+ a = (uint32_t *)addr;
+ m = (uint32_t *)&mask;
if ((a[0] & ~m[0]) || (a[1] & ~m[1])
|| (a[2] & ~m[2]) || (a[3] & ~m[3])) {
bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
@@ -6714,7 +6827,6 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
bpf_error(cstate, "invalid qualifier against IPv6 address");
/* NOTREACHED */
}
- return NULL;
}
#endif /*INET6*/
@@ -6752,12 +6864,10 @@ gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q)
}
bpf_error(cstate, "ethernet address used in non-ether expression");
/* NOTREACHED */
- return NULL;
}
void
-sappend(s0, s1)
- struct slist *s0, *s1;
+sappend(struct slist *s0, struct slist *s1)
{
/*
* This is definitely not the best way to do this, but the
@@ -7007,8 +7117,58 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
inst->b = b;
break;
case Q_ICMPV6:
- bpf_error(cstate, "IPv6 upper-layer protocol is not supported by proto[x]");
- /*NOTREACHED*/
+ /*
+ * Do the computation only if the packet contains
+ * the protocol in question.
+ */
+ b = gen_proto_abbrev(cstate, Q_IPV6);
+ if (inst->b) {
+ gen_and(inst->b, b);
+ }
+ inst->b = b;
+
+ /*
+ * Check if we have an icmp6 next header
+ */
+ b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58);
+ if (inst->b) {
+ gen_and(inst->b, b);
+ }
+ inst->b = b;
+
+
+ s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl);
+ /*
+ * If "s" is non-null, it has code to arrange that the
+ * X register contains the variable part of the offset
+ * of the link-layer payload. Add to it the offset
+ * computed into the register specified by "index",
+ * and move that into the X register. Otherwise, just
+ * load into the X register the offset computed into
+ * the register specified by "index".
+ */
+ if (s != NULL) {
+ sappend(s, xfer_to_a(cstate, inst));
+ sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
+ } else {
+ s = xfer_to_x(cstate, inst);
+ }
+
+ /*
+ * Load the item at the sum of the offset we've put in the
+ * X register, the offset of the start of the network
+ * layer header from the beginning of the link-layer
+ * payload, and the constant part of the offset of the
+ * start of the link-layer payload.
+ */
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
+
+ sappend(s, tmp);
+ sappend(inst->s, s);
+
+ break;
}
inst->regno = regno;
s = new_stmt(cstate, BPF_ST);
@@ -7180,7 +7340,6 @@ alloc_reg(compiler_state_t *cstate)
}
bpf_error(cstate, "too many registers needed to evaluate expression");
/* NOTREACHED */
- return 0;
}
/*
@@ -7335,7 +7494,6 @@ gen_broadcast(compiler_state_t *cstate, int proto)
}
bpf_error(cstate, "only link-layer/IP broadcast filters supported");
/* NOTREACHED */
- return NULL;
}
/*
@@ -7531,7 +7689,6 @@ gen_multicast(compiler_state_t *cstate, int proto)
}
bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
/* NOTREACHED */
- return NULL;
}
/*
@@ -7632,8 +7789,18 @@ gen_inbound(compiler_state_t *cstate, int dir)
default:
/*
* If we have packet meta-data indicating a direction,
- * check it, otherwise give up as this link-layer type
- * has nothing in the packet data.
+ * and that metadata can be checked by BPF code, check
+ * it. Otherwise, give up, as this link-layer type has
+ * nothing in the packet data.
+ *
+ * Currently, the only platform where a BPF filter can
+ * check that metadata is Linux with the in-kernel
+ * BPF interpreter. If other packet capture mechanisms
+ * and BPF filters also supported this, it would be
+ * nice. It would be even better if they made that
+ * metadata available so that we could provide it
+ * with newer capture APIs, allowing it to be saved
+ * in pcapng files.
*/
#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
/*
@@ -7659,7 +7826,6 @@ gen_inbound(compiler_state_t *cstate, int dir)
#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
bpf_error(cstate, "inbound/outbound not supported on linktype %d",
cstate->linktype);
- b0 = NULL;
/* NOTREACHED */
#endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
}
@@ -7776,51 +7942,45 @@ gen_pf_action(compiler_state_t *cstate, int action)
}
#else /* !HAVE_NET_PFVAR_H */
struct block *
-gen_pf_ifname(compiler_state_t *cstate, const char *ifname)
+gen_pf_ifname(compiler_state_t *cstate, const char *ifname _U_)
{
bpf_error(cstate, "libpcap was compiled without pf support");
/* NOTREACHED */
- return (NULL);
}
struct block *
-gen_pf_ruleset(compiler_state_t *cstate, char *ruleset)
+gen_pf_ruleset(compiler_state_t *cstate, char *ruleset _U_)
{
bpf_error(cstate, "libpcap was compiled on a machine without pf support");
/* NOTREACHED */
- return (NULL);
}
struct block *
-gen_pf_rnr(compiler_state_t *cstate, int rnr)
+gen_pf_rnr(compiler_state_t *cstate, int rnr _U_)
{
bpf_error(cstate, "libpcap was compiled on a machine without pf support");
/* NOTREACHED */
- return (NULL);
}
struct block *
-gen_pf_srnr(compiler_state_t *cstate, int srnr)
+gen_pf_srnr(compiler_state_t *cstate, int srnr _U_)
{
bpf_error(cstate, "libpcap was compiled on a machine without pf support");
/* NOTREACHED */
- return (NULL);
}
struct block *
-gen_pf_reason(compiler_state_t *cstate, int reason)
+gen_pf_reason(compiler_state_t *cstate, int reason _U_)
{
bpf_error(cstate, "libpcap was compiled on a machine without pf support");
/* NOTREACHED */
- return (NULL);
}
struct block *
-gen_pf_action(compiler_state_t *cstate, int action)
+gen_pf_action(compiler_state_t *cstate, int action _U_)
{
bpf_error(cstate, "libpcap was compiled on a machine without pf support");
/* NOTREACHED */
- return (NULL);
}
#endif /* HAVE_NET_PFVAR_H */
@@ -7892,9 +8052,6 @@ gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q)
bpf_error(cstate, "aid supported only on ARCnet");
/* NOTREACHED */
}
- bpf_error(cstate, "ARCnet address used in non-arc expression");
- /* NOTREACHED */
- return NULL;
}
static struct block *
@@ -7924,19 +8081,19 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
return b1;
case Q_ADDR1:
- bpf_error(cstate, "'addr1' is only supported on 802.11");
+ bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11");
break;
case Q_ADDR2:
- bpf_error(cstate, "'addr2' is only supported on 802.11");
+ bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11");
break;
case Q_ADDR3:
- bpf_error(cstate, "'addr3' is only supported on 802.11");
+ bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11");
break;
case Q_ADDR4:
- bpf_error(cstate, "'addr4' is only supported on 802.11");
+ bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11");
break;
case Q_RA:
@@ -7951,74 +8108,181 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
/* NOTREACHED */
}
-#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
static struct block *
-gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
+gen_vlan_tpid_test(compiler_state_t *cstate)
{
- struct block *b0, *b1;
- struct slist *s;
-
- /* generate new filter code based on extracting packet
- * metadata */
- s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
- s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
-
- b0 = new_block(cstate, JMP(BPF_JEQ));
- b0->stmts = s;
- b0->s.k = 1;
-
- if (vlan_num >= 0) {
- s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
- s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+ struct block *b0, *b1;
- b1 = new_block(cstate, JMP(BPF_JEQ));
- b1->stmts = s;
- b1->s.k = (bpf_int32) vlan_num;
+ /* check for VLAN, including QinQ */
+ b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
+ b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
+ gen_or(b0,b1);
+ b0 = b1;
+ b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ);
+ gen_or(b0,b1);
- gen_and(b0,b1);
- b0 = b1;
- }
+ return b1;
+}
- return b0;
+static struct block *
+gen_vlan_vid_test(compiler_state_t *cstate, int vlan_num)
+{
+ return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff);
}
-#endif
static struct block *
gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num)
{
- struct block *b0, *b1;
-
- /* check for VLAN, including QinQ */
- b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
- b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
- gen_or(b0,b1);
- b0 = b1;
- b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ);
- gen_or(b0,b1);
- b0 = b1;
-
- /* If a specific VLAN is requested, check VLAN id */
- if (vlan_num >= 0) {
- b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_H,
- (bpf_int32)vlan_num, 0x0fff);
- gen_and(b0, b1);
- b0 = b1;
- }
+ struct block *b0, *b1;
+
+ b0 = gen_vlan_tpid_test(cstate);
+
+ if (vlan_num >= 0) {
+ b1 = gen_vlan_vid_test(cstate, vlan_num);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
/*
- * The payload follows the full header, including the
- * VLAN tags, so skip past this VLAN tag.
+ * Both payload and link header type follow the VLAN tags so that
+ * both need to be updated.
*/
- cstate->off_linkpl.constant_part += 4;
+ cstate->off_linkpl.constant_part += 4;
+ cstate->off_linktype.constant_part += 4;
+
+ return b0;
+}
+
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
+/* add v to variable part of off */
+static void
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s)
+{
+ struct slist *s2;
+
+ if (!off->is_variable)
+ off->is_variable = 1;
+ if (off->reg == -1)
+ off->reg = alloc_reg(cstate);
+
+ s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+ s2->s.k = off->reg;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+ s2->s.k = v;
+ sappend(s, s2);
+ s2 = new_stmt(cstate, BPF_ST);
+ s2->s.k = off->reg;
+ sappend(s, s2);
+}
+
+/*
+ * patch block b_tpid (VLAN TPID test) to update variable parts of link payload
+ * and link type offsets first
+ */
+static void
+gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid)
+{
+ struct slist s;
+
+ /* offset determined at run time, shift variable part */
+ s.next = NULL;
+ cstate->is_vlan_vloffset = 1;
+ gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s);
+ gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s);
+
+ /* we get a pointer to a chain of or-ed blocks, patch first of them */
+ sappend(s.next, b_tpid->head->stmts);
+ b_tpid->head->stmts = s.next;
+}
+
+/*
+ * patch block b_vid (VLAN id test) to load VID value either from packet
+ * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true
+ */
+static void
+gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
+{
+ struct slist *s, *s2, *sjeq;
+ unsigned cnt;
+
+ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+ /* true -> next instructions, false -> beginning of b_vid */
+ sjeq = new_stmt(cstate, JMP(BPF_JEQ));
+ sjeq->s.k = 1;
+ sjeq->s.jf = b_vid->stmts;
+ sappend(s, sjeq);
+
+ s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+ sappend(s, s2);
+ sjeq->s.jt = s2;
+
+ /* jump to the test in b_vid (bypass loading VID from packet data) */
+ cnt = 0;
+ for (s2 = b_vid->stmts; s2; s2 = s2->next)
+ cnt++;
+ s2 = new_stmt(cstate, JMP(BPF_JA));
+ s2->s.k = cnt;
+ sappend(s, s2);
+
+ /* insert our statements at the beginning of b_vid */
+ sappend(s, b_vid->stmts);
+ b_vid->stmts = s;
+}
+
+/*
+ * Generate check for "vlan" or "vlan <id>" on systems with support for BPF
+ * extensions. Even if kernel supports VLAN BPF extensions, (outermost) VLAN
+ * tag can be either in metadata or in packet data; therefore if the
+ * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link
+ * header for VLAN tag. As the decision is done at run time, we need
+ * update variable part of the offsets
+ */
+static struct block *
+gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
+{
+ struct block *b0, *b_tpid, *b_vid = NULL;
+ struct slist *s;
+
+ /* generate new filter code based on extracting packet
+ * metadata */
+ s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+ b0 = new_block(cstate, JMP(BPF_JEQ));
+ b0->stmts = s;
+ b0->s.k = 1;
/*
- * The link-layer type information follows the VLAN tags, so
- * skip past this VLAN tag.
+ * This is tricky. We need to insert the statements updating variable
+ * parts of offsets before the the traditional TPID and VID tests so
+ * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
+ * we do not want this update to affect those checks. That's why we
+ * generate both test blocks first and insert the statements updating
+ * variable parts of both offsets after that. This wouldn't work if
+ * there already were variable length link header when entering this
+ * function but gen_vlan_bpf_extensions() isn't called in that case.
*/
- cstate->off_linktype.constant_part += 4;
+ b_tpid = gen_vlan_tpid_test(cstate);
+ if (vlan_num >= 0)
+ b_vid = gen_vlan_vid_test(cstate, vlan_num);
+
+ gen_vlan_patch_tpid_test(cstate, b_tpid);
+ gen_or(b0, b_tpid);
+ b0 = b_tpid;
+
+ if (vlan_num >= 0) {
+ gen_vlan_patch_vid_test(cstate, b_vid);
+ gen_and(b0, b_vid);
+ b0 = b_vid;
+ }
return b0;
}
+#endif
/*
* support IEEE 802.1Q VLAN trunk over ethernet
@@ -8068,7 +8332,7 @@ gen_vlan(compiler_state_t *cstate, int vlan_num)
case DLT_EN10MB:
case DLT_NETANALYZER:
case DLT_NETANALYZER_TRANSPARENT:
-#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
/* Verify that this is the outer part of the packet and
* not encapsulated somehow. */
if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable &&
@@ -8140,7 +8404,6 @@ gen_mpls(compiler_state_t *cstate, int label_num)
default:
bpf_error(cstate, "no MPLS support for data link type %d",
cstate->linktype);
- b0 = NULL;
/*NOTREACHED*/
break;
}
@@ -8561,7 +8824,7 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue,
case A_VPI:
if (!cstate->is_atm)
bpf_error(cstate, "'vpi' supported only on raw ATM");
- if (cstate->off_vpi == (u_int)-1)
+ if (cstate->off_vpi == OFFSET_NOT_SET)
abort();
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype,
reverse, jvalue);
@@ -8570,21 +8833,21 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue,
case A_VCI:
if (!cstate->is_atm)
bpf_error(cstate, "'vci' supported only on raw ATM");
- if (cstate->off_vci == (u_int)-1)
+ if (cstate->off_vci == OFFSET_NOT_SET)
abort();
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype,
reverse, jvalue);
break;
case A_PROTOTYPE:
- if (cstate->off_proto == (u_int)-1)
+ if (cstate->off_proto == OFFSET_NOT_SET)
abort(); /* XXX - this isn't on FreeBSD */
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype,
reverse, jvalue);
break;
case A_MSGTYPE:
- if (cstate->off_payload == (u_int)-1)
+ if (cstate->off_payload == OFFSET_NOT_SET)
abort();
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
0xffffffff, jtype, reverse, jvalue);
@@ -8593,7 +8856,7 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue,
case A_CALLREFTYPE:
if (!cstate->is_atm)
bpf_error(cstate, "'callref' supported only on raw ATM");
- if (cstate->off_proto == (u_int)-1)
+ if (cstate->off_proto == OFFSET_NOT_SET)
abort();
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff,
jtype, reverse, jvalue);
@@ -8795,7 +9058,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue,
/* FALLTHROUGH */
case M_SIO:
- if (cstate->off_sio == (u_int)-1)
+ if (cstate->off_sio == OFFSET_NOT_SET)
bpf_error(cstate, "'sio' supported only on SS7");
/* sio coded on 1 byte so max value 255 */
if(jvalue > 255)
@@ -8808,7 +9071,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue,
case MH_OPC:
newoff_opc+=3;
case M_OPC:
- if (cstate->off_opc == (u_int)-1)
+ if (cstate->off_opc == OFFSET_NOT_SET)
bpf_error(cstate, "'opc' supported only on SS7");
/* opc coded on 14 bits so max value 16383 */
if (jvalue > 16383)
@@ -8832,7 +9095,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue,
/* FALLTHROUGH */
case M_DPC:
- if (cstate->off_dpc == (u_int)-1)
+ if (cstate->off_dpc == OFFSET_NOT_SET)
bpf_error(cstate, "'dpc' supported only on SS7");
/* dpc coded on 14 bits so max value 16383 */
if (jvalue > 16383)
@@ -8852,7 +9115,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue,
case MH_SLS:
newoff_sls+=3;
case M_SLS:
- if (cstate->off_sls == (u_int)-1)
+ if (cstate->off_sls == OFFSET_NOT_SET)
bpf_error(cstate, "'sls' supported only on SS7");
/* sls coded on 4 bits so max value 15 */
if (jvalue > 15)