xref: /openbsd-src/lib/libpcap/gencode.c (revision f6e4162f05818bbc182b2d0e7e8682ece0079a77)
1*f6e4162fSjsg /*	$OpenBSD: gencode.c,v 1.67 2024/09/15 07:14:58 jsg Exp $	*/
2df930be7Sderaadt 
3df930be7Sderaadt /*
401efc7efSderaadt  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  *
7df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
8df930be7Sderaadt  * modification, are permitted provided that: (1) source code distributions
9df930be7Sderaadt  * retain the above copyright notice and this paragraph in its entirety, (2)
10df930be7Sderaadt  * distributions including binary code include the above copyright notice and
11df930be7Sderaadt  * this paragraph in its entirety in the documentation or other materials
12df930be7Sderaadt  * provided with the distribution, and (3) all advertising materials mentioning
13df930be7Sderaadt  * features or use of this software display the following acknowledgement:
14df930be7Sderaadt  * ``This product includes software developed by the University of California,
15df930be7Sderaadt  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16df930be7Sderaadt  * the University nor the names of its contributors may be used to endorse
17df930be7Sderaadt  * or promote products derived from this software without specific prior
18df930be7Sderaadt  * written permission.
19df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20df930be7Sderaadt  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21df930be7Sderaadt  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22df930be7Sderaadt  */
23df930be7Sderaadt 
249b113833Smickey #include <sys/types.h>
25df930be7Sderaadt #include <sys/socket.h>
26df930be7Sderaadt #include <sys/time.h>
27df930be7Sderaadt 
28df930be7Sderaadt #include <net/if.h>
29df930be7Sderaadt 
30df930be7Sderaadt #include <netinet/in.h>
31df930be7Sderaadt #include <netinet/if_ether.h>
32df930be7Sderaadt 
33e83aed87Sfrantzen #include <net/if_pflog.h>
34e83aed87Sfrantzen #include <net/pfvar.h>
35e83aed87Sfrantzen 
36ff52dd4aSdenis #include <netmpls/mpls.h>
37ff52dd4aSdenis 
38d42a50a0Sreyk #include <net80211/ieee80211.h>
39d42a50a0Sreyk #include <net80211/ieee80211_radiotap.h>
40d42a50a0Sreyk 
419b113833Smickey #include <stdlib.h>
42e83aed87Sfrantzen #include <stddef.h>
43df930be7Sderaadt #include <setjmp.h>
44df930be7Sderaadt #include <stdarg.h>
453a9b5ec4Smmcc #include <string.h>
46df930be7Sderaadt 
479b113833Smickey #include "pcap-int.h"
489b113833Smickey 
4901efc7efSderaadt #include "ethertype.h"
50f562933eSmpf #include "llc.h"
519b113833Smickey #include "gencode.h"
5201efc7efSderaadt #include "ppp.h"
5301efc7efSderaadt #include <pcap-namedb.h>
54a9b0695fSjakob #ifdef INET6
55a9b0695fSjakob #include <netdb.h>
56a9b0695fSjakob #endif /*INET6*/
579b113833Smickey 
5801efc7efSderaadt #ifdef HAVE_OS_PROTO_H
5901efc7efSderaadt #include "os-proto.h"
60df930be7Sderaadt #endif
61df930be7Sderaadt 
62df930be7Sderaadt #define JMP(c) ((c)|BPF_JMP|BPF_K)
63df930be7Sderaadt 
649b113833Smickey /* Locals */
65df930be7Sderaadt static jmp_buf top_ctx;
66df930be7Sderaadt static pcap_t *bpf_pcap;
67df930be7Sderaadt 
68febc6dcdSdtucker /* Hack for updating VLAN offsets. */
69febc6dcdSdtucker static u_int	orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
70ff52dd4aSdenis static u_int	mpls_stack = 0;
71febc6dcdSdtucker 
729b113833Smickey /* XXX */
739b113833Smickey #ifdef PCAP_FDDIPAD
749b113833Smickey int	pcap_fddipad = PCAP_FDDIPAD;
759b113833Smickey #else
769b113833Smickey int	pcap_fddipad;
779b113833Smickey #endif
789b113833Smickey 
799b113833Smickey __dead void
809b113833Smickey bpf_error(const char *fmt, ...)
81df930be7Sderaadt {
82df930be7Sderaadt 	va_list ap;
83df930be7Sderaadt 
84df930be7Sderaadt 	va_start(ap, fmt);
85df930be7Sderaadt 	if (bpf_pcap != NULL)
8613c7aa11Sderaadt 		(void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE,
8713c7aa11Sderaadt 		    fmt, ap);
88df930be7Sderaadt 	va_end(ap);
89df930be7Sderaadt 	longjmp(top_ctx, 1);
90df930be7Sderaadt 	/* NOTREACHED */
91df930be7Sderaadt }
92df930be7Sderaadt 
93df930be7Sderaadt static void init_linktype(int);
94df930be7Sderaadt 
95df930be7Sderaadt static int alloc_reg(void);
96df930be7Sderaadt static void free_reg(int);
97df930be7Sderaadt 
98df930be7Sderaadt static struct block *root;
99df930be7Sderaadt 
1008d8814c2Scanacar /* initialization code used for variable link header */
1018d8814c2Scanacar static struct slist *init_code = NULL;
1028d8814c2Scanacar 
1038d8814c2Scanacar /* Flags and registers for variable link type handling */
1048d8814c2Scanacar static int variable_nl;
1058d8814c2Scanacar static int nl_reg, iphl_reg;
1068d8814c2Scanacar 
107df930be7Sderaadt /*
1086c734e6eSderaadt  * Track memory allocations, for bulk freeing at the end
109df930be7Sderaadt  */
1106c734e6eSderaadt #define NMEMBAG 16
1116c734e6eSderaadt #define MEMBAG0SIZE (4096 / sizeof (void *))
1126c734e6eSderaadt struct membag {
1136c734e6eSderaadt 	u_int total;
1146c734e6eSderaadt 	u_int slot;
1156c734e6eSderaadt 	void **ptrs;	/* allocated array[total] to each malloc */
116df930be7Sderaadt };
117df930be7Sderaadt 
1186c734e6eSderaadt static struct membag membag[NMEMBAG];
1196c734e6eSderaadt static int cur_membag;
120df930be7Sderaadt 
1216c734e6eSderaadt static void *newchunk(size_t);
122df930be7Sderaadt static void freechunks(void);
1238df16311Stholo static __inline struct block *new_block(int);
1248df16311Stholo static __inline struct slist *new_stmt(int);
125df930be7Sderaadt static struct block *gen_retblk(int);
1268df16311Stholo static __inline void syntax(void);
127df930be7Sderaadt 
128df930be7Sderaadt static void backpatch(struct block *, struct block *);
129df930be7Sderaadt static void merge(struct block *, struct block *);
1309b113833Smickey static struct block *gen_cmp(u_int, u_int, bpf_int32);
131f562933eSmpf static struct block *gen_cmp_gt(u_int, u_int, bpf_int32);
1328d8814c2Scanacar static struct block *gen_cmp_nl(u_int, u_int, bpf_int32);
1339b113833Smickey static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32);
1348d8814c2Scanacar static struct block *gen_mcmp_nl(u_int, u_int, bpf_int32, bpf_u_int32);
13501efc7efSderaadt static struct block *gen_bcmp(u_int, u_int, const u_char *);
136df930be7Sderaadt static struct block *gen_uncond(int);
1378df16311Stholo static __inline struct block *gen_true(void);
1388df16311Stholo static __inline struct block *gen_false(void);
139df930be7Sderaadt static struct block *gen_linktype(int);
1409b113833Smickey static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);
141a9b0695fSjakob #ifdef INET6
142a9b0695fSjakob static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int);
143a9b0695fSjakob #endif
14401efc7efSderaadt static struct block *gen_ehostop(const u_char *, int);
14501efc7efSderaadt static struct block *gen_fhostop(const u_char *, int);
1469b113833Smickey static struct block *gen_dnhostop(bpf_u_int32, int, u_int);
147d42a50a0Sreyk static struct block *gen_p80211_hostop(const u_char *, int);
148d42a50a0Sreyk static struct block *gen_p80211_addr(int, u_int, const u_char *);
1499b113833Smickey static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int);
150a9b0695fSjakob #ifdef INET6
151a9b0695fSjakob static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int);
152a9b0695fSjakob #endif
153a9b0695fSjakob #ifndef INET6
15401efc7efSderaadt static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);
155a9b0695fSjakob #endif
156df930be7Sderaadt static struct block *gen_ipfrag(void);
1579b113833Smickey static struct block *gen_portatom(int, bpf_int32);
158a9b0695fSjakob #ifdef INET6
159a9b0695fSjakob static struct block *gen_portatom6(int, bpf_int32);
160a9b0695fSjakob #endif
161df930be7Sderaadt struct block *gen_portop(int, int, int);
162df930be7Sderaadt static struct block *gen_port(int, int, int);
163a9b0695fSjakob #ifdef INET6
164a9b0695fSjakob struct block *gen_portop6(int, int, int);
165a9b0695fSjakob static struct block *gen_port6(int, int, int);
166a9b0695fSjakob #endif
16701efc7efSderaadt static int lookup_proto(const char *, int);
168a9b0695fSjakob static struct block *gen_protochain(int, int, int);
169df930be7Sderaadt static struct block *gen_proto(int, int, int);
170df930be7Sderaadt static struct slist *xfer_to_x(struct arth *);
171df930be7Sderaadt static struct slist *xfer_to_a(struct arth *);
172df930be7Sderaadt static struct block *gen_len(int, int);
173df930be7Sderaadt 
174df930be7Sderaadt static void *
1756c734e6eSderaadt newchunk(size_t n)
176df930be7Sderaadt {
1776c734e6eSderaadt 	struct membag *m;
1786c734e6eSderaadt 	void *p;
179df930be7Sderaadt 
1806c734e6eSderaadt 	m = &membag[cur_membag];
1816c734e6eSderaadt 	if (m->total != 0 && m->total - m->slot == 0) {
1826c734e6eSderaadt 		if (++cur_membag == NMEMBAG)
183df930be7Sderaadt 			bpf_error("out of memory");
1846c734e6eSderaadt 		m = &membag[cur_membag];
185df930be7Sderaadt 	}
1866c734e6eSderaadt 	if (m->total - m->slot == 0) {
1876c734e6eSderaadt 		m->ptrs = calloc(sizeof (char *), MEMBAG0SIZE << cur_membag);
1886c734e6eSderaadt 		if (m->ptrs == NULL)
1896c734e6eSderaadt 			bpf_error("out of memory");
1906c734e6eSderaadt 		m->total = MEMBAG0SIZE << cur_membag;
1916c734e6eSderaadt 		m->slot = 0;
1926c734e6eSderaadt 	}
1936c734e6eSderaadt 
1946c734e6eSderaadt 	p = calloc(1, n);
1956c734e6eSderaadt 	if (p == NULL)
1966c734e6eSderaadt 		bpf_error("out of memory");
1976c734e6eSderaadt 	m->ptrs[m->slot++] = p;
1986c734e6eSderaadt 	return (p);
199df930be7Sderaadt }
200df930be7Sderaadt 
201df930be7Sderaadt static void
2026c734e6eSderaadt freechunks(void)
203df930be7Sderaadt {
2046c734e6eSderaadt 	int i, j;
205df930be7Sderaadt 
2066c734e6eSderaadt 	for (i = 0; i <= cur_membag; i++) {
2070931029aSotto 		if (membag[i].ptrs == NULL)
2080931029aSotto 			continue;
209c8ee1a74Sderaadt 		for (j = 0; j < membag[i].slot; j++)
2106c734e6eSderaadt 			free(membag[i].ptrs[j]);
2116c734e6eSderaadt 		free(membag[i].ptrs);
2126c734e6eSderaadt 		membag[i].ptrs = NULL;
2136c734e6eSderaadt 		membag[i].slot = membag[i].total = 0;
2149b113833Smickey 	}
2159aff5a10Sderaadt 	cur_membag = 0;
216df930be7Sderaadt }
217df930be7Sderaadt 
218df930be7Sderaadt /*
219df930be7Sderaadt  * A strdup whose allocations are freed after code generation is over.
220df930be7Sderaadt  */
221df930be7Sderaadt char *
22219fef815Sderaadt sdup(const char *s)
223df930be7Sderaadt {
224df930be7Sderaadt 	int n = strlen(s) + 1;
225df930be7Sderaadt 	char *cp = newchunk(n);
22601efc7efSderaadt 
22701efc7efSderaadt 	strlcpy(cp, s, n);
228df930be7Sderaadt 	return (cp);
229df930be7Sderaadt }
230df930be7Sderaadt 
2318df16311Stholo static __inline struct block *
23219fef815Sderaadt new_block(int code)
233df930be7Sderaadt {
234df930be7Sderaadt 	struct block *p;
235df930be7Sderaadt 
236df930be7Sderaadt 	p = (struct block *)newchunk(sizeof(*p));
237df930be7Sderaadt 	p->s.code = code;
238df930be7Sderaadt 	p->head = p;
239df930be7Sderaadt 
240df930be7Sderaadt 	return p;
241df930be7Sderaadt }
242df930be7Sderaadt 
2438df16311Stholo static __inline struct slist *
24419fef815Sderaadt new_stmt(int code)
245df930be7Sderaadt {
246df930be7Sderaadt 	struct slist *p;
247df930be7Sderaadt 
248df930be7Sderaadt 	p = (struct slist *)newchunk(sizeof(*p));
249df930be7Sderaadt 	p->s.code = code;
250df930be7Sderaadt 
251df930be7Sderaadt 	return p;
252df930be7Sderaadt }
253df930be7Sderaadt 
254df930be7Sderaadt static struct block *
25519fef815Sderaadt gen_retblk(int v)
256df930be7Sderaadt {
257df930be7Sderaadt 	struct block *b = new_block(BPF_RET|BPF_K);
258df930be7Sderaadt 
259df930be7Sderaadt 	b->s.k = v;
260df930be7Sderaadt 	return b;
261df930be7Sderaadt }
262df930be7Sderaadt 
2638df16311Stholo static __inline void
264146262eaSjsg syntax(void)
265df930be7Sderaadt {
266df930be7Sderaadt 	bpf_error("syntax error in filter expression");
267df930be7Sderaadt }
268df930be7Sderaadt 
2699b113833Smickey static bpf_u_int32 netmask;
270df930be7Sderaadt static int snaplen;
271a9b0695fSjakob int no_optimize;
272df930be7Sderaadt 
273df930be7Sderaadt int
274df930be7Sderaadt pcap_compile(pcap_t *p, struct bpf_program *program,
275aa4ed2b9Ssthen 	     const char *buf, int optimize, bpf_u_int32 mask)
276df930be7Sderaadt {
277df930be7Sderaadt 	extern int n_errors;
278df930be7Sderaadt 	int len;
279df930be7Sderaadt 
280a9b0695fSjakob 	no_optimize = 0;
2819b113833Smickey 	n_errors = 0;
2829b113833Smickey 	root = NULL;
283df930be7Sderaadt 	bpf_pcap = p;
2849b113833Smickey 	if (setjmp(top_ctx)) {
2859b113833Smickey 		freechunks();
286df930be7Sderaadt 		return (-1);
2879b113833Smickey 	}
288df930be7Sderaadt 
289df930be7Sderaadt 	netmask = mask;
290df930be7Sderaadt 	snaplen = pcap_snapshot(p);
291df930be7Sderaadt 
292df930be7Sderaadt 	lex_init(buf ? buf : "");
293df930be7Sderaadt 	init_linktype(pcap_datalink(p));
2949b113833Smickey 	(void)pcap_parse();
295df930be7Sderaadt 
296df930be7Sderaadt 	if (n_errors)
297df930be7Sderaadt 		syntax();
298df930be7Sderaadt 
299df930be7Sderaadt 	if (root == NULL)
300df930be7Sderaadt 		root = gen_retblk(snaplen);
301df930be7Sderaadt 
302a9b0695fSjakob 	if (optimize && !no_optimize) {
303a9b0695fSjakob 		bpf_optimize(&root);
304a9b0695fSjakob 		if (root == NULL ||
305a9b0695fSjakob 		    (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
306a9b0695fSjakob 			bpf_error("expression rejects all packets");
307a9b0695fSjakob 	}
308a9b0695fSjakob 	program->bf_insns = icode_to_fcode(root, &len);
309a9b0695fSjakob 	program->bf_len = len;
310a9b0695fSjakob 
311a9b0695fSjakob 	freechunks();
312a9b0695fSjakob 	return (0);
313a9b0695fSjakob }
314a9b0695fSjakob 
315a9b0695fSjakob /*
316a9b0695fSjakob  * entry point for using the compiler with no pcap open
317a9b0695fSjakob  * pass in all the stuff that is needed explicitly instead.
318a9b0695fSjakob  */
319a9b0695fSjakob int
320a9b0695fSjakob pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
321a9b0695fSjakob 		    struct bpf_program *program,
322aa4ed2b9Ssthen 	     const char *buf, int optimize, bpf_u_int32 mask)
323a9b0695fSjakob {
324a9b0695fSjakob 	extern int n_errors;
325a9b0695fSjakob 	int len;
326a9b0695fSjakob 
327a9b0695fSjakob 	n_errors = 0;
328a9b0695fSjakob 	root = NULL;
329a9b0695fSjakob 	bpf_pcap = NULL;
330a9b0695fSjakob 	if (setjmp(top_ctx)) {
331a9b0695fSjakob 		freechunks();
332a9b0695fSjakob 		return (-1);
333a9b0695fSjakob 	}
334a9b0695fSjakob 
335a9b0695fSjakob 	netmask = mask;
336a9b0695fSjakob 
337a9b0695fSjakob 	/* XXX needed? I don't grok the use of globals here. */
338a9b0695fSjakob 	snaplen = snaplen_arg;
339a9b0695fSjakob 
340a9b0695fSjakob 	lex_init(buf ? buf : "");
341a9b0695fSjakob 	init_linktype(linktype_arg);
342a9b0695fSjakob 	(void)pcap_parse();
343a9b0695fSjakob 
344a9b0695fSjakob 	if (n_errors)
345a9b0695fSjakob 		syntax();
346a9b0695fSjakob 
347a9b0695fSjakob 	if (root == NULL)
348a9b0695fSjakob 		root = gen_retblk(snaplen_arg);
349a9b0695fSjakob 
350df930be7Sderaadt 	if (optimize) {
351df930be7Sderaadt 		bpf_optimize(&root);
352df930be7Sderaadt 		if (root == NULL ||
353df930be7Sderaadt 		    (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
354df930be7Sderaadt 			bpf_error("expression rejects all packets");
355df930be7Sderaadt 	}
356df930be7Sderaadt 	program->bf_insns = icode_to_fcode(root, &len);
357df930be7Sderaadt 	program->bf_len = len;
358df930be7Sderaadt 
359df930be7Sderaadt 	freechunks();
360df930be7Sderaadt 	return (0);
361df930be7Sderaadt }
362df930be7Sderaadt 
363df930be7Sderaadt /*
36478871eb8Sdugsong  * Clean up a "struct bpf_program" by freeing all the memory allocated
36578871eb8Sdugsong  * in it.
36678871eb8Sdugsong  */
36778871eb8Sdugsong void
36878871eb8Sdugsong pcap_freecode(struct bpf_program *program)
36978871eb8Sdugsong {
37078871eb8Sdugsong 	program->bf_len = 0;
37178871eb8Sdugsong 	if (program->bf_insns != NULL) {
37278871eb8Sdugsong 		free((char *)program->bf_insns);
37378871eb8Sdugsong 		program->bf_insns = NULL;
37478871eb8Sdugsong 	}
37578871eb8Sdugsong }
37678871eb8Sdugsong 
37778871eb8Sdugsong /*
378df930be7Sderaadt  * Backpatch the blocks in 'list' to 'target'.  The 'sense' field indicates
379df930be7Sderaadt  * which of the jt and jf fields has been resolved and which is a pointer
380df930be7Sderaadt  * back to another unresolved block (or nil).  At least one of the fields
381df930be7Sderaadt  * in each block is already resolved.
382df930be7Sderaadt  */
383df930be7Sderaadt static void
38419fef815Sderaadt backpatch(struct block *list, struct block *target)
385df930be7Sderaadt {
386df930be7Sderaadt 	struct block *next;
387df930be7Sderaadt 
388df930be7Sderaadt 	while (list) {
389df930be7Sderaadt 		if (!list->sense) {
390df930be7Sderaadt 			next = JT(list);
391df930be7Sderaadt 			JT(list) = target;
392df930be7Sderaadt 		} else {
393df930be7Sderaadt 			next = JF(list);
394df930be7Sderaadt 			JF(list) = target;
395df930be7Sderaadt 		}
396df930be7Sderaadt 		list = next;
397df930be7Sderaadt 	}
398df930be7Sderaadt }
399df930be7Sderaadt 
400df930be7Sderaadt /*
401df930be7Sderaadt  * Merge the lists in b0 and b1, using the 'sense' field to indicate
402df930be7Sderaadt  * which of jt and jf is the link.
403df930be7Sderaadt  */
404df930be7Sderaadt static void
40519fef815Sderaadt merge(struct block *b0, struct block *b1)
406df930be7Sderaadt {
407d0438536Smmcc 	struct block **p = &b0;
408df930be7Sderaadt 
409df930be7Sderaadt 	/* Find end of list. */
410df930be7Sderaadt 	while (*p)
411df930be7Sderaadt 		p = !((*p)->sense) ? &JT(*p) : &JF(*p);
412df930be7Sderaadt 
413df930be7Sderaadt 	/* Concatenate the lists. */
414df930be7Sderaadt 	*p = b1;
415df930be7Sderaadt }
416df930be7Sderaadt 
417df930be7Sderaadt void
41819fef815Sderaadt finish_parse(struct block *p)
419df930be7Sderaadt {
420df930be7Sderaadt 	backpatch(p, gen_retblk(snaplen));
421df930be7Sderaadt 	p->sense = !p->sense;
422df930be7Sderaadt 	backpatch(p, gen_retblk(0));
423df930be7Sderaadt 	root = p->head;
4248d8814c2Scanacar 
4258d8814c2Scanacar 	/* prepend initialization code to root */
4268d8814c2Scanacar 	if (init_code != NULL && root != NULL) {
4278d8814c2Scanacar 		sappend(init_code, root->stmts);
4288d8814c2Scanacar 		root->stmts = init_code;
4298d8814c2Scanacar 		init_code = NULL;
4308d8814c2Scanacar 	}
4318d8814c2Scanacar 
4328d8814c2Scanacar 	if (iphl_reg != -1) {
4338d8814c2Scanacar 		free_reg(iphl_reg);
4348d8814c2Scanacar 		iphl_reg = -1;
4358d8814c2Scanacar 	}
4368d8814c2Scanacar 	if (nl_reg != -1) {
4378d8814c2Scanacar 		free_reg(nl_reg);
4388d8814c2Scanacar 		nl_reg = -1;
4398d8814c2Scanacar 	}
440df930be7Sderaadt }
441df930be7Sderaadt 
442df930be7Sderaadt void
44319fef815Sderaadt gen_and(struct block *b0, struct block *b1)
444df930be7Sderaadt {
445df930be7Sderaadt 	backpatch(b0, b1->head);
446df930be7Sderaadt 	b0->sense = !b0->sense;
447df930be7Sderaadt 	b1->sense = !b1->sense;
448df930be7Sderaadt 	merge(b1, b0);
449df930be7Sderaadt 	b1->sense = !b1->sense;
450df930be7Sderaadt 	b1->head = b0->head;
451df930be7Sderaadt }
452df930be7Sderaadt 
453df930be7Sderaadt void
45419fef815Sderaadt gen_or(struct block *b0, struct block *b1)
455df930be7Sderaadt {
456df930be7Sderaadt 	b0->sense = !b0->sense;
457df930be7Sderaadt 	backpatch(b0, b1->head);
458df930be7Sderaadt 	b0->sense = !b0->sense;
459df930be7Sderaadt 	merge(b1, b0);
460df930be7Sderaadt 	b1->head = b0->head;
461df930be7Sderaadt }
462df930be7Sderaadt 
463df930be7Sderaadt void
46419fef815Sderaadt gen_not(struct block *b)
465df930be7Sderaadt {
466df930be7Sderaadt 	b->sense = !b->sense;
467df930be7Sderaadt }
468df930be7Sderaadt 
469df930be7Sderaadt static struct block *
47019fef815Sderaadt gen_cmp(u_int offset, u_int size, bpf_int32 v)
471df930be7Sderaadt {
472df930be7Sderaadt 	struct slist *s;
473df930be7Sderaadt 	struct block *b;
474df930be7Sderaadt 
475df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_ABS|size);
476df930be7Sderaadt 	s->s.k = offset;
477df930be7Sderaadt 
478df930be7Sderaadt 	b = new_block(JMP(BPF_JEQ));
479df930be7Sderaadt 	b->stmts = s;
480df930be7Sderaadt 	b->s.k = v;
481df930be7Sderaadt 
482df930be7Sderaadt 	return b;
483df930be7Sderaadt }
484df930be7Sderaadt 
485df930be7Sderaadt static struct block *
48619fef815Sderaadt gen_cmp_gt(u_int offset, u_int size, bpf_int32 v)
487f562933eSmpf {
488f562933eSmpf 	struct slist *s;
489f562933eSmpf 	struct block *b;
490f562933eSmpf 
491f562933eSmpf 	s = new_stmt(BPF_LD|BPF_ABS|size);
492f562933eSmpf 	s->s.k = offset;
493f562933eSmpf 
494f562933eSmpf 	b = new_block(JMP(BPF_JGT));
495f562933eSmpf 	b->stmts = s;
496f562933eSmpf 	b->s.k = v;
497f562933eSmpf 
498f562933eSmpf 	return b;
499f562933eSmpf }
500f562933eSmpf 
501f562933eSmpf static struct block *
50219fef815Sderaadt gen_mcmp(u_int offset, u_int size, bpf_int32 v, bpf_u_int32 mask)
503df930be7Sderaadt {
504df930be7Sderaadt 	struct block *b = gen_cmp(offset, size, v);
505df930be7Sderaadt 	struct slist *s;
506df930be7Sderaadt 
507df930be7Sderaadt 	if (mask != 0xffffffff) {
508df930be7Sderaadt 		s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
509df930be7Sderaadt 		s->s.k = mask;
510d89ea119Skrw 		sappend(b->stmts, s);
511df930be7Sderaadt 	}
512df930be7Sderaadt 	return b;
513df930be7Sderaadt }
514df930be7Sderaadt 
5158d8814c2Scanacar /* Like gen_mcmp with 'dynamic off_nl' added to the offset */
5168d8814c2Scanacar static struct block *
51719fef815Sderaadt gen_mcmp_nl(u_int offset, u_int size, bpf_int32 v, bpf_u_int32 mask)
5188d8814c2Scanacar {
5198d8814c2Scanacar 	struct block *b = gen_cmp_nl(offset, size, v);
5208d8814c2Scanacar 	struct slist *s;
5218d8814c2Scanacar 
5228d8814c2Scanacar 	if (mask != 0xffffffff) {
5238d8814c2Scanacar 		s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
5248d8814c2Scanacar 		s->s.k = mask;
525d89ea119Skrw 		sappend(b->stmts, s);
5268d8814c2Scanacar 	}
5278d8814c2Scanacar 	return b;
5288d8814c2Scanacar }
5298d8814c2Scanacar 
530df930be7Sderaadt static struct block *
53119fef815Sderaadt gen_bcmp(u_int offset, u_int size, const u_char *v)
532df930be7Sderaadt {
533d0438536Smmcc 	struct block *b, *tmp;
534df930be7Sderaadt 
535df930be7Sderaadt 	b = NULL;
536df930be7Sderaadt 	while (size >= 4) {
537d0438536Smmcc 		const u_char *p = &v[size - 4];
53801efc7efSderaadt 		bpf_int32 w = ((bpf_int32)p[0] << 24) |
53901efc7efSderaadt 		    ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3];
54001efc7efSderaadt 
541df930be7Sderaadt 		tmp = gen_cmp(offset + size - 4, BPF_W, w);
542df930be7Sderaadt 		if (b != NULL)
543df930be7Sderaadt 			gen_and(b, tmp);
544df930be7Sderaadt 		b = tmp;
545df930be7Sderaadt 		size -= 4;
546df930be7Sderaadt 	}
547df930be7Sderaadt 	while (size >= 2) {
548d0438536Smmcc 		const u_char *p = &v[size - 2];
54901efc7efSderaadt 		bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1];
55001efc7efSderaadt 
551df930be7Sderaadt 		tmp = gen_cmp(offset + size - 2, BPF_H, w);
552df930be7Sderaadt 		if (b != NULL)
553df930be7Sderaadt 			gen_and(b, tmp);
554df930be7Sderaadt 		b = tmp;
555df930be7Sderaadt 		size -= 2;
556df930be7Sderaadt 	}
557df930be7Sderaadt 	if (size > 0) {
5589b113833Smickey 		tmp = gen_cmp(offset, BPF_B, (bpf_int32)v[0]);
559df930be7Sderaadt 		if (b != NULL)
560df930be7Sderaadt 			gen_and(b, tmp);
561df930be7Sderaadt 		b = tmp;
562df930be7Sderaadt 	}
563df930be7Sderaadt 	return b;
564df930be7Sderaadt }
565df930be7Sderaadt 
566df930be7Sderaadt /*
567df930be7Sderaadt  * Various code constructs need to know the layout of the data link
568df930be7Sderaadt  * layer.  These variables give the necessary offsets.  off_linktype
569df930be7Sderaadt  * is set to -1 for no encapsulation, in which case, IP is assumed.
570df930be7Sderaadt  */
571df930be7Sderaadt static u_int off_linktype;
572df930be7Sderaadt static u_int off_nl;
573febc6dcdSdtucker static u_int off_nl_nosnap;
574febc6dcdSdtucker 
575df930be7Sderaadt static int linktype;
576df930be7Sderaadt 
5778d8814c2Scanacar /* Generate code to load the dynamic 'off_nl' to the X register */
5788d8814c2Scanacar static struct slist *
5798d8814c2Scanacar nl2X_stmt(void)
5808d8814c2Scanacar {
5818d8814c2Scanacar 	struct slist *s, *tmp;
5828d8814c2Scanacar 
5838d8814c2Scanacar 	if (nl_reg == -1) {
5848d8814c2Scanacar 		switch (linktype) {
5858d8814c2Scanacar 		case DLT_PFLOG:
5868d8814c2Scanacar 			/* The pflog header contains PFLOG_REAL_HDRLEN
5878d8814c2Scanacar 			   which does NOT include the padding. Round
5888d8814c2Scanacar 			   up to the nearest dword boundary */
5898d8814c2Scanacar 			s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
5908d8814c2Scanacar 			s->s.k = 0;
5918d8814c2Scanacar 
5928d8814c2Scanacar 			tmp = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
5938d8814c2Scanacar 			tmp->s.k = 3;
5948d8814c2Scanacar 			sappend(s, tmp);
5958d8814c2Scanacar 
5968d8814c2Scanacar 			tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K);
597c266690cScanacar 			tmp->s.k = 0xfc;
5988d8814c2Scanacar 			sappend(s, tmp);
5998d8814c2Scanacar 
6008d8814c2Scanacar 			nl_reg = alloc_reg();
6018d8814c2Scanacar 			tmp = new_stmt(BPF_ST);
6028d8814c2Scanacar 			tmp->s.k = nl_reg;
6038d8814c2Scanacar 			sappend(s, tmp);
6048d8814c2Scanacar 
6058d8814c2Scanacar 			break;
6068d8814c2Scanacar 		default:
6078d8814c2Scanacar 			bpf_error("Unknown header size for link type 0x%x",
6088d8814c2Scanacar 				  linktype);
6098d8814c2Scanacar 		}
6108d8814c2Scanacar 
6118d8814c2Scanacar 		if (init_code == NULL)
6128d8814c2Scanacar 			init_code = s;
6138d8814c2Scanacar 		else
6148d8814c2Scanacar 			sappend(init_code, s);
6158d8814c2Scanacar 	}
6168d8814c2Scanacar 
6178d8814c2Scanacar 	s = new_stmt(BPF_LDX|BPF_MEM);
6188d8814c2Scanacar 	s->s.k = nl_reg;
6198d8814c2Scanacar 
6208d8814c2Scanacar 	return s;
6218d8814c2Scanacar }
6228d8814c2Scanacar 
6238d8814c2Scanacar /* Like gen_cmp but adds the dynamic 'off_nl' to the offset */
6248d8814c2Scanacar static struct block *
62519fef815Sderaadt gen_cmp_nl(u_int offset, u_int size, bpf_int32 v)
6268d8814c2Scanacar {
6278d8814c2Scanacar 	struct slist *s, *tmp;
6288d8814c2Scanacar 	struct block *b;
6298d8814c2Scanacar 
6308d8814c2Scanacar 	if (variable_nl) {
6318d8814c2Scanacar 		s = nl2X_stmt();
6328d8814c2Scanacar 		tmp = new_stmt(BPF_LD|BPF_IND|size);
6338d8814c2Scanacar 		tmp->s.k = offset;
6348d8814c2Scanacar 		sappend(s, tmp);
6358d8814c2Scanacar 	} else {
6368d8814c2Scanacar 		s = new_stmt(BPF_LD|BPF_ABS|size);
6378d8814c2Scanacar 		s->s.k = offset + off_nl;
6388d8814c2Scanacar 	}
6398d8814c2Scanacar 	b = new_block(JMP(BPF_JEQ));
6408d8814c2Scanacar 	b->stmts = s;
6418d8814c2Scanacar 	b->s.k = v;
6428d8814c2Scanacar 
6438d8814c2Scanacar 	return b;
6448d8814c2Scanacar }
6458d8814c2Scanacar 
646df930be7Sderaadt static void
64719fef815Sderaadt init_linktype(int type)
648df930be7Sderaadt {
649df930be7Sderaadt 	linktype = type;
6508d8814c2Scanacar 	init_code = NULL;
6518d8814c2Scanacar 	nl_reg = iphl_reg = -1;
652df930be7Sderaadt 
653df930be7Sderaadt 	switch (type) {
654df930be7Sderaadt 
655df930be7Sderaadt 	case DLT_EN10MB:
656df930be7Sderaadt 		off_linktype = 12;
657df930be7Sderaadt 		off_nl = 14;
658df930be7Sderaadt 		return;
659df930be7Sderaadt 
660df930be7Sderaadt 	case DLT_SLIP:
661df930be7Sderaadt 		/*
662df930be7Sderaadt 		 * SLIP doesn't have a link level type.  The 16 byte
663df930be7Sderaadt 		 * header is hacked into our SLIP driver.
664df930be7Sderaadt 		 */
665df930be7Sderaadt 		off_linktype = -1;
666df930be7Sderaadt 		off_nl = 16;
667df930be7Sderaadt 		return;
668df930be7Sderaadt 
66901efc7efSderaadt 	case DLT_SLIP_BSDOS:
67001efc7efSderaadt 		/* XXX this may be the same as the DLT_PPP_BSDOS case */
67101efc7efSderaadt 		off_linktype = -1;
67201efc7efSderaadt 		/* XXX end */
67301efc7efSderaadt 		off_nl = 24;
67401efc7efSderaadt 		return;
67501efc7efSderaadt 
676df930be7Sderaadt 	case DLT_NULL:
67701efc7efSderaadt 		off_linktype = 0;
678c164a838Sderaadt 		off_nl = 4;
679c164a838Sderaadt 		return;
680c164a838Sderaadt 
681df930be7Sderaadt 	case DLT_PPP:
682df930be7Sderaadt 		off_linktype = 2;
683df930be7Sderaadt 		off_nl = 4;
684df930be7Sderaadt 		return;
685df930be7Sderaadt 
6862524a2d3Sdlg 	case DLT_PPP_SERIAL:
6872524a2d3Sdlg 		off_linktype = -1;
6882524a2d3Sdlg 		off_nl = 2;
6892524a2d3Sdlg 		return;
6902524a2d3Sdlg 
691477f9f21Sbrad 	case DLT_PPP_ETHER:
692477f9f21Sbrad 		/*
693477f9f21Sbrad 		 * This does not include the Ethernet header, and
694477f9f21Sbrad 		 * only covers session state.
695477f9f21Sbrad  		 */
696477f9f21Sbrad 		off_linktype = 6;
697477f9f21Sbrad 		off_nl = 8;
698477f9f21Sbrad 		return;
699477f9f21Sbrad 
70001efc7efSderaadt 	case DLT_PPP_BSDOS:
70101efc7efSderaadt 		off_linktype = 5;
70201efc7efSderaadt 		off_nl = 24;
70301efc7efSderaadt 		return;
70401efc7efSderaadt 
705df930be7Sderaadt 	case DLT_FDDI:
706df930be7Sderaadt 		/*
707df930be7Sderaadt 		 * FDDI doesn't really have a link-level type field.
708df930be7Sderaadt 		 * We assume that SSAP = SNAP is being used and pick
709df930be7Sderaadt 		 * out the encapsulated Ethernet type.
710df930be7Sderaadt 		 */
7119b113833Smickey 		off_linktype = 19;
7129b113833Smickey #ifdef PCAP_FDDIPAD
7139b113833Smickey 		off_linktype += pcap_fddipad;
714df930be7Sderaadt #endif
7159b113833Smickey 		off_nl = 21;
7169b113833Smickey #ifdef PCAP_FDDIPAD
7179b113833Smickey 		off_nl += pcap_fddipad;
7189b113833Smickey #endif
7199b113833Smickey 		return;
720df930be7Sderaadt 
721df930be7Sderaadt 	case DLT_IEEE802:
722df930be7Sderaadt 		off_linktype = 20;
723df930be7Sderaadt 		off_nl = 22;
724df930be7Sderaadt 		return;
7259b113833Smickey 
72692f41fdeSfgsch 	case DLT_IEEE802_11:
72792f41fdeSfgsch 		off_linktype = 30; /* XXX variable */
72892f41fdeSfgsch 		off_nl = 32;
72992f41fdeSfgsch 		return;
73092f41fdeSfgsch 
731d42a50a0Sreyk 	case DLT_IEEE802_11_RADIO: /* XXX variable */
732d42a50a0Sreyk 		off_linktype = 30 + IEEE80211_RADIOTAP_HDRLEN;
733d42a50a0Sreyk 		off_nl = 32 + IEEE80211_RADIOTAP_HDRLEN;
734a97876cfSreyk 		return;
735a97876cfSreyk 
7369b113833Smickey 	case DLT_ATM_RFC1483:
7379b113833Smickey 		/*
7389b113833Smickey 		 * assume routed, non-ISO PDUs
7399b113833Smickey 		 * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00)
7409b113833Smickey 		 */
7419b113833Smickey 		off_linktype = 6;
7429b113833Smickey 		off_nl = 8;
7439b113833Smickey 		return;
74401efc7efSderaadt 
74501efc7efSderaadt 	case DLT_LOOP:
7460918526aSdlg 		off_linktype = 0;
74701efc7efSderaadt 		off_nl = 4;
74801efc7efSderaadt 		return;
74901efc7efSderaadt 
75001efc7efSderaadt 	case DLT_ENC:
75101efc7efSderaadt 		off_linktype = -1;
75201efc7efSderaadt 		off_nl = 12;
75301efc7efSderaadt 		return;
75401efc7efSderaadt 
755263bcd0cScanacar 	case DLT_PFLOG:
756263bcd0cScanacar 		off_linktype = 0;
7578d8814c2Scanacar 		variable_nl = 1;
7588d8814c2Scanacar 		off_nl = 0;
759263bcd0cScanacar 		return;
760263bcd0cScanacar 
76131f5fcb8Smickey 	case DLT_PFSYNC:
76231f5fcb8Smickey 		off_linktype = -1;
76331f5fcb8Smickey 		off_nl = 4;
76431f5fcb8Smickey 		return;
76531f5fcb8Smickey 
7667a61d4b0Sreyk 	case DLT_OPENFLOW:
7677a61d4b0Sreyk 		off_linktype = -1;
7688167ef46Sreyk 		off_nl = 12;
7697a61d4b0Sreyk 		return;
7707a61d4b0Sreyk 
771d00b8992Smpi 	case DLT_USBPCAP:
772d00b8992Smpi 		/* FALLTHROUGH */
77301efc7efSderaadt 	case DLT_RAW:
77401efc7efSderaadt 		off_linktype = -1;
77501efc7efSderaadt 		off_nl = 0;
77601efc7efSderaadt 		return;
777df930be7Sderaadt 	}
778df930be7Sderaadt 	bpf_error("unknown data link type 0x%x", linktype);
779df930be7Sderaadt 	/* NOTREACHED */
780df930be7Sderaadt }
781df930be7Sderaadt 
782df930be7Sderaadt static struct block *
78319fef815Sderaadt gen_uncond(int rsense)
784df930be7Sderaadt {
785df930be7Sderaadt 	struct block *b;
786df930be7Sderaadt 	struct slist *s;
787df930be7Sderaadt 
788df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_IMM);
789df930be7Sderaadt 	s->s.k = !rsense;
790df930be7Sderaadt 	b = new_block(JMP(BPF_JEQ));
791df930be7Sderaadt 	b->stmts = s;
792df930be7Sderaadt 
793df930be7Sderaadt 	return b;
794df930be7Sderaadt }
795df930be7Sderaadt 
7968df16311Stholo static __inline struct block *
797146262eaSjsg gen_true(void)
798df930be7Sderaadt {
799df930be7Sderaadt 	return gen_uncond(1);
800df930be7Sderaadt }
801df930be7Sderaadt 
8028df16311Stholo static __inline struct block *
803146262eaSjsg gen_false(void)
804df930be7Sderaadt {
805df930be7Sderaadt 	return gen_uncond(0);
806df930be7Sderaadt }
807df930be7Sderaadt 
808df930be7Sderaadt static struct block *
80919fef815Sderaadt gen_linktype(int proto)
810df930be7Sderaadt {
81101efc7efSderaadt 	struct block *b0, *b1;
81201efc7efSderaadt 
81301efc7efSderaadt 	/* If we're not using encapsulation and checking for IP, we're done */
814ff52dd4aSdenis 	if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP)
815df930be7Sderaadt 		return gen_true();
816a9b0695fSjakob #ifdef INET6
817a9b0695fSjakob 	/* this isn't the right thing to do, but sometimes necessary */
818ff52dd4aSdenis 	if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6)
819a9b0695fSjakob 		return gen_true();
820a9b0695fSjakob #endif
82101efc7efSderaadt 
82201efc7efSderaadt 	switch (linktype) {
82301efc7efSderaadt 
824f562933eSmpf 	case DLT_EN10MB:
825f562933eSmpf 		if (proto <= ETHERMTU) {
826f562933eSmpf 			/* This is an LLC SAP value */
827f562933eSmpf 			b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU);
828f562933eSmpf 			gen_not(b0);
829f562933eSmpf 			b1 = gen_cmp(off_linktype + 2, BPF_B, (bpf_int32)proto);
830f562933eSmpf 			gen_and(b0, b1);
831f562933eSmpf 			return b1;
832f562933eSmpf 		} else {
833f562933eSmpf 			/* This is an Ethernet type */
834f562933eSmpf 			return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
835f562933eSmpf 		}
836f562933eSmpf 		break;
837f562933eSmpf 
83801efc7efSderaadt 	case DLT_SLIP:
839df930be7Sderaadt 		return gen_false();
840df930be7Sderaadt 
841df930be7Sderaadt 	case DLT_PPP:
842477f9f21Sbrad 	case DLT_PPP_ETHER:
843df930be7Sderaadt 		if (proto == ETHERTYPE_IP)
84401efc7efSderaadt 			proto = PPP_IP;			/* XXX was 0x21 */
845a9b0695fSjakob #ifdef INET6
846a9b0695fSjakob 		else if (proto == ETHERTYPE_IPV6)
847a9b0695fSjakob 			proto = PPP_IPV6;
848a9b0695fSjakob #endif
84901efc7efSderaadt 		break;
85001efc7efSderaadt 
85101efc7efSderaadt 	case DLT_PPP_BSDOS:
85201efc7efSderaadt 		switch (proto) {
85301efc7efSderaadt 
85401efc7efSderaadt 		case ETHERTYPE_IP:
85501efc7efSderaadt 			b0 = gen_cmp(off_linktype, BPF_H, PPP_IP);
85601efc7efSderaadt 			b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC);
85701efc7efSderaadt 			gen_or(b0, b1);
85801efc7efSderaadt 			b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC);
85901efc7efSderaadt 			gen_or(b1, b0);
86001efc7efSderaadt 			return b0;
86101efc7efSderaadt 
862a9b0695fSjakob #ifdef INET6
863a9b0695fSjakob 		case ETHERTYPE_IPV6:
864a9b0695fSjakob 			proto = PPP_IPV6;
865a9b0695fSjakob 			/* more to go? */
866a9b0695fSjakob 			break;
867a9b0695fSjakob #endif /* INET6 */
868a9b0695fSjakob 
86901efc7efSderaadt 		case ETHERTYPE_DN:
87001efc7efSderaadt 			proto = PPP_DECNET;
87101efc7efSderaadt 			break;
87201efc7efSderaadt 
87301efc7efSderaadt 		case ETHERTYPE_ATALK:
87401efc7efSderaadt 			proto = PPP_APPLE;
87501efc7efSderaadt 			break;
87601efc7efSderaadt 
87701efc7efSderaadt 		case ETHERTYPE_NS:
87801efc7efSderaadt 			proto = PPP_NS;
87901efc7efSderaadt 			break;
88001efc7efSderaadt 		}
881df930be7Sderaadt 		break;
8829b113833Smickey 
883c164a838Sderaadt 	case DLT_LOOP:
8844c52d65cSderaadt 	case DLT_ENC:
8859b113833Smickey 	case DLT_NULL:
886fe3e795bSkn 	{
887fe3e795bSkn 		int v;
888fe3e795bSkn 
8899b113833Smickey 		if (proto == ETHERTYPE_IP)
890fe3e795bSkn 			v = AF_INET;
891a9b0695fSjakob #ifdef INET6
892a9b0695fSjakob 		else if (proto == ETHERTYPE_IPV6)
893fe3e795bSkn 			v = AF_INET6;
894a9b0695fSjakob #endif /* INET6 */
8959b113833Smickey 		else
8969b113833Smickey 			return gen_false();
897fe3e795bSkn 
898fe3e795bSkn 		/*
899fe3e795bSkn 		 * For DLT_NULL, the link-layer header is a 32-bit word
900fe3e795bSkn 		 * containing an AF_ value in *host* byte order, and for
901fe3e795bSkn 		 * DLT_ENC, the link-layer header begins with a 32-bit
902fe3e795bSkn 		 * word containing an AF_ value in host byte order.
903fe3e795bSkn 		 *
904fe3e795bSkn 		 * For DLT_LOOP, the link-layer header is a 32-bit
905fe3e795bSkn 		 * word containing an AF_ value in *network* byte order.
906fe3e795bSkn 		 */
907fe3e795bSkn 		if (linktype != DLT_LOOP)
908fe3e795bSkn 			v = htonl(v);
909fe3e795bSkn 
910fe3e795bSkn 		return (gen_cmp(0, BPF_W, (bpf_int32)v));
911a9b0695fSjakob 		break;
912fe3e795bSkn 	}
913263bcd0cScanacar 	case DLT_PFLOG:
914263bcd0cScanacar 		if (proto == ETHERTYPE_IP)
915263bcd0cScanacar 			return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,
916263bcd0cScanacar 			    (bpf_int32)AF_INET));
917263bcd0cScanacar #ifdef INET6
918263bcd0cScanacar 		else if (proto == ETHERTYPE_IPV6)
919263bcd0cScanacar 			return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,
920263bcd0cScanacar 			    (bpf_int32)AF_INET6));
921263bcd0cScanacar #endif /* INET6 */
922263bcd0cScanacar 		else
923263bcd0cScanacar 			return gen_false();
924263bcd0cScanacar 		break;
925263bcd0cScanacar 
926df930be7Sderaadt 	}
9279b113833Smickey 	return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
928df930be7Sderaadt }
929df930be7Sderaadt 
930df930be7Sderaadt static struct block *
93119fef815Sderaadt gen_hostop(bpf_u_int32 addr, bpf_u_int32 mask, int dir, int proto,
93219fef815Sderaadt     u_int src_off, u_int dst_off)
933df930be7Sderaadt {
934df930be7Sderaadt 	struct block *b0, *b1;
935df930be7Sderaadt 	u_int offset;
936df930be7Sderaadt 
937df930be7Sderaadt 	switch (dir) {
938df930be7Sderaadt 
939df930be7Sderaadt 	case Q_SRC:
940df930be7Sderaadt 		offset = src_off;
941df930be7Sderaadt 		break;
942df930be7Sderaadt 
943df930be7Sderaadt 	case Q_DST:
944df930be7Sderaadt 		offset = dst_off;
945df930be7Sderaadt 		break;
946df930be7Sderaadt 
947df930be7Sderaadt 	case Q_AND:
948df930be7Sderaadt 		b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
949df930be7Sderaadt 		b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
950df930be7Sderaadt 		gen_and(b0, b1);
951df930be7Sderaadt 		return b1;
952df930be7Sderaadt 
953df930be7Sderaadt 	case Q_OR:
954df930be7Sderaadt 	case Q_DEFAULT:
955df930be7Sderaadt 		b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
956df930be7Sderaadt 		b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
957df930be7Sderaadt 		gen_or(b0, b1);
958df930be7Sderaadt 		return b1;
959df930be7Sderaadt 
960df930be7Sderaadt 	default:
961d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
962d42a50a0Sreyk 		    linktype);
963df930be7Sderaadt 	}
964df930be7Sderaadt 	b0 = gen_linktype(proto);
9658d8814c2Scanacar 	b1 = gen_mcmp_nl(offset, BPF_W, (bpf_int32)addr, mask);
966df930be7Sderaadt 	gen_and(b0, b1);
967df930be7Sderaadt 	return b1;
968df930be7Sderaadt }
969df930be7Sderaadt 
970a9b0695fSjakob #ifdef INET6
971a9b0695fSjakob static struct block *
97219fef815Sderaadt gen_hostop6(struct in6_addr *addr, struct in6_addr *mask, int dir, int proto,
97319fef815Sderaadt     u_int src_off, u_int dst_off)
974a9b0695fSjakob {
975a9b0695fSjakob 	struct block *b0, *b1;
976a9b0695fSjakob 	u_int offset;
977a9b0695fSjakob 	u_int32_t *a, *m;
978a9b0695fSjakob 
979a9b0695fSjakob 	switch (dir) {
980a9b0695fSjakob 
981a9b0695fSjakob 	case Q_SRC:
982a9b0695fSjakob 		offset = src_off;
983a9b0695fSjakob 		break;
984a9b0695fSjakob 
985a9b0695fSjakob 	case Q_DST:
986a9b0695fSjakob 		offset = dst_off;
987a9b0695fSjakob 		break;
988a9b0695fSjakob 
989a9b0695fSjakob 	case Q_AND:
990a9b0695fSjakob 		b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off);
991a9b0695fSjakob 		b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off);
992a9b0695fSjakob 		gen_and(b0, b1);
993a9b0695fSjakob 		return b1;
994a9b0695fSjakob 
995a9b0695fSjakob 	case Q_OR:
996a9b0695fSjakob 	case Q_DEFAULT:
997a9b0695fSjakob 		b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off);
998a9b0695fSjakob 		b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off);
999a9b0695fSjakob 		gen_or(b0, b1);
1000a9b0695fSjakob 		return b1;
1001a9b0695fSjakob 
1002a9b0695fSjakob 	default:
1003d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
1004d42a50a0Sreyk 		    linktype);
1005a9b0695fSjakob 	}
1006a9b0695fSjakob 	/* this order is important */
1007a9b0695fSjakob 	a = (u_int32_t *)addr;
1008a9b0695fSjakob 	m = (u_int32_t *)mask;
10098d8814c2Scanacar 	b1 = gen_mcmp_nl(offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
10108d8814c2Scanacar 	b0 = gen_mcmp_nl(offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
1011a9b0695fSjakob 	gen_and(b0, b1);
10128d8814c2Scanacar 	b0 = gen_mcmp_nl(offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
1013a9b0695fSjakob 	gen_and(b0, b1);
10148d8814c2Scanacar 	b0 = gen_mcmp_nl(offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
1015a9b0695fSjakob 	gen_and(b0, b1);
1016a9b0695fSjakob 	b0 = gen_linktype(proto);
1017a9b0695fSjakob 	gen_and(b0, b1);
1018a9b0695fSjakob 	return b1;
1019a9b0695fSjakob }
1020a9b0695fSjakob #endif /*INET6*/
1021a9b0695fSjakob 
1022df930be7Sderaadt static struct block *
102319fef815Sderaadt gen_ehostop(const u_char *eaddr, int dir)
1024df930be7Sderaadt {
1025a9b0695fSjakob 	struct block *b0, *b1;
1026df930be7Sderaadt 
1027df930be7Sderaadt 	switch (dir) {
1028df930be7Sderaadt 	case Q_SRC:
1029df930be7Sderaadt 		return gen_bcmp(6, 6, eaddr);
1030df930be7Sderaadt 
1031df930be7Sderaadt 	case Q_DST:
1032df930be7Sderaadt 		return gen_bcmp(0, 6, eaddr);
1033df930be7Sderaadt 
1034df930be7Sderaadt 	case Q_AND:
1035df930be7Sderaadt 		b0 = gen_ehostop(eaddr, Q_SRC);
1036df930be7Sderaadt 		b1 = gen_ehostop(eaddr, Q_DST);
1037df930be7Sderaadt 		gen_and(b0, b1);
1038df930be7Sderaadt 		return b1;
1039df930be7Sderaadt 
1040df930be7Sderaadt 	case Q_DEFAULT:
1041df930be7Sderaadt 	case Q_OR:
1042df930be7Sderaadt 		b0 = gen_ehostop(eaddr, Q_SRC);
1043df930be7Sderaadt 		b1 = gen_ehostop(eaddr, Q_DST);
1044df930be7Sderaadt 		gen_or(b0, b1);
1045df930be7Sderaadt 		return b1;
1046d42a50a0Sreyk 	default:
1047d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
1048d42a50a0Sreyk 		    linktype);
1049df930be7Sderaadt 	}
1050df930be7Sderaadt 	/* NOTREACHED */
1051df930be7Sderaadt }
1052df930be7Sderaadt 
1053df930be7Sderaadt /*
1054df930be7Sderaadt  * Like gen_ehostop, but for DLT_FDDI
1055df930be7Sderaadt  */
1056df930be7Sderaadt static struct block *
105719fef815Sderaadt gen_fhostop(const u_char *eaddr, int dir)
1058df930be7Sderaadt {
1059df930be7Sderaadt 	struct block *b0, *b1;
1060df930be7Sderaadt 
1061df930be7Sderaadt 	switch (dir) {
1062df930be7Sderaadt 	case Q_SRC:
10639b113833Smickey #ifdef PCAP_FDDIPAD
10649b113833Smickey 		return gen_bcmp(6 + 1 + pcap_fddipad, 6, eaddr);
10659b113833Smickey #else
10669b113833Smickey 		return gen_bcmp(6 + 1, 6, eaddr);
10679b113833Smickey #endif
1068df930be7Sderaadt 
1069df930be7Sderaadt 	case Q_DST:
10709b113833Smickey #ifdef PCAP_FDDIPAD
10719b113833Smickey 		return gen_bcmp(0 + 1 + pcap_fddipad, 6, eaddr);
10729b113833Smickey #else
10739b113833Smickey 		return gen_bcmp(0 + 1, 6, eaddr);
10749b113833Smickey #endif
1075df930be7Sderaadt 
1076df930be7Sderaadt 	case Q_AND:
1077df930be7Sderaadt 		b0 = gen_fhostop(eaddr, Q_SRC);
1078df930be7Sderaadt 		b1 = gen_fhostop(eaddr, Q_DST);
1079df930be7Sderaadt 		gen_and(b0, b1);
1080df930be7Sderaadt 		return b1;
1081df930be7Sderaadt 
1082df930be7Sderaadt 	case Q_DEFAULT:
1083df930be7Sderaadt 	case Q_OR:
1084df930be7Sderaadt 		b0 = gen_fhostop(eaddr, Q_SRC);
1085df930be7Sderaadt 		b1 = gen_fhostop(eaddr, Q_DST);
1086df930be7Sderaadt 		gen_or(b0, b1);
1087df930be7Sderaadt 		return b1;
1088d42a50a0Sreyk 	default:
1089d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
1090d42a50a0Sreyk 		    linktype);
1091df930be7Sderaadt 	}
1092df930be7Sderaadt 	/* NOTREACHED */
1093df930be7Sderaadt }
1094df930be7Sderaadt 
1095df930be7Sderaadt /*
1096df930be7Sderaadt  * This is quite tricky because there may be pad bytes in front of the
1097df930be7Sderaadt  * DECNET header, and then there are two possible data packet formats that
1098df930be7Sderaadt  * carry both src and dst addresses, plus 5 packet types in a format that
1099df930be7Sderaadt  * carries only the src node, plus 2 types that use a different format and
1100df930be7Sderaadt  * also carry just the src node.
1101df930be7Sderaadt  *
1102df930be7Sderaadt  * Yuck.
1103df930be7Sderaadt  *
1104df930be7Sderaadt  * Instead of doing those all right, we just look for data packets with
1105df930be7Sderaadt  * 0 or 1 bytes of padding.  If you want to look at other packets, that
1106df930be7Sderaadt  * will require a lot more hacking.
1107df930be7Sderaadt  *
1108df930be7Sderaadt  * To add support for filtering on DECNET "areas" (network numbers)
1109df930be7Sderaadt  * one would want to add a "mask" argument to this routine.  That would
1110df930be7Sderaadt  * make the filter even more inefficient, although one could be clever
1111df930be7Sderaadt  * and not generate masking instructions if the mask is 0xFFFF.
1112df930be7Sderaadt  */
1113df930be7Sderaadt static struct block *
111419fef815Sderaadt gen_dnhostop(bpf_u_int32 addr, int dir, u_int base_off)
1115df930be7Sderaadt {
1116df930be7Sderaadt 	struct block *b0, *b1, *b2, *tmp;
1117df930be7Sderaadt 	u_int offset_lh;	/* offset if long header is received */
1118df930be7Sderaadt 	u_int offset_sh;	/* offset if short header is received */
1119df930be7Sderaadt 
1120df930be7Sderaadt 	switch (dir) {
1121df930be7Sderaadt 
1122df930be7Sderaadt 	case Q_DST:
1123df930be7Sderaadt 		offset_sh = 1;	/* follows flags */
1124df930be7Sderaadt 		offset_lh = 7;	/* flgs,darea,dsubarea,HIORD */
1125df930be7Sderaadt 		break;
1126df930be7Sderaadt 
1127df930be7Sderaadt 	case Q_SRC:
1128df930be7Sderaadt 		offset_sh = 3;	/* follows flags, dstnode */
1129df930be7Sderaadt 		offset_lh = 15;	/* flgs,darea,dsubarea,did,sarea,ssub,HIORD */
1130df930be7Sderaadt 		break;
1131df930be7Sderaadt 
1132df930be7Sderaadt 	case Q_AND:
1133df930be7Sderaadt 		/* Inefficient because we do our Calvinball dance twice */
1134df930be7Sderaadt 		b0 = gen_dnhostop(addr, Q_SRC, base_off);
1135df930be7Sderaadt 		b1 = gen_dnhostop(addr, Q_DST, base_off);
1136df930be7Sderaadt 		gen_and(b0, b1);
1137df930be7Sderaadt 		return b1;
1138df930be7Sderaadt 
1139df930be7Sderaadt 	case Q_OR:
1140df930be7Sderaadt 	case Q_DEFAULT:
1141df930be7Sderaadt 		/* Inefficient because we do our Calvinball dance twice */
1142df930be7Sderaadt 		b0 = gen_dnhostop(addr, Q_SRC, base_off);
1143df930be7Sderaadt 		b1 = gen_dnhostop(addr, Q_DST, base_off);
1144df930be7Sderaadt 		gen_or(b0, b1);
1145df930be7Sderaadt 		return b1;
1146df930be7Sderaadt 
1147df930be7Sderaadt 	default:
1148d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
1149d42a50a0Sreyk 		    linktype);
1150df930be7Sderaadt 	}
1151df930be7Sderaadt 	b0 = gen_linktype(ETHERTYPE_DN);
1152df930be7Sderaadt 	/* Check for pad = 1, long header case */
11538d8814c2Scanacar 	tmp = gen_mcmp_nl(base_off + 2, BPF_H,
11549b113833Smickey 		       (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
11558d8814c2Scanacar 	b1 = gen_cmp_nl(base_off + 2 + 1 + offset_lh,
11569b113833Smickey 	    BPF_H, (bpf_int32)ntohs(addr));
1157df930be7Sderaadt 	gen_and(tmp, b1);
1158df930be7Sderaadt 	/* Check for pad = 0, long header case */
11598d8814c2Scanacar 	tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
11608d8814c2Scanacar 	b2 = gen_cmp_nl(base_off + 2 + offset_lh, BPF_H, (bpf_int32)ntohs(addr));
1161df930be7Sderaadt 	gen_and(tmp, b2);
1162df930be7Sderaadt 	gen_or(b2, b1);
1163df930be7Sderaadt 	/* Check for pad = 1, short header case */
11648d8814c2Scanacar 	tmp = gen_mcmp_nl(base_off + 2, BPF_H,
11659b113833Smickey 		       (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
11668d8814c2Scanacar 	b2 = gen_cmp_nl(base_off + 2 + 1 + offset_sh,
11679b113833Smickey 	    BPF_H, (bpf_int32)ntohs(addr));
1168df930be7Sderaadt 	gen_and(tmp, b2);
1169df930be7Sderaadt 	gen_or(b2, b1);
1170df930be7Sderaadt 	/* Check for pad = 0, short header case */
11718d8814c2Scanacar 	tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
11728d8814c2Scanacar 	b2 = gen_cmp_nl(base_off + 2 + offset_sh, BPF_H, (bpf_int32)ntohs(addr));
1173df930be7Sderaadt 	gen_and(tmp, b2);
1174df930be7Sderaadt 	gen_or(b2, b1);
1175df930be7Sderaadt 
1176df930be7Sderaadt 	/* Combine with test for linktype */
1177df930be7Sderaadt 	gen_and(b0, b1);
1178df930be7Sderaadt 	return b1;
1179df930be7Sderaadt }
1180df930be7Sderaadt 
1181df930be7Sderaadt static struct block *
118219fef815Sderaadt gen_host(bpf_u_int32 addr, bpf_u_int32 mask, int proto, int dir)
1183df930be7Sderaadt {
1184df930be7Sderaadt 	struct block *b0, *b1;
1185df930be7Sderaadt 
1186df930be7Sderaadt 	switch (proto) {
1187df930be7Sderaadt 
1188df930be7Sderaadt 	case Q_DEFAULT:
1189df930be7Sderaadt 		b0 = gen_host(addr, mask, Q_IP, dir);
1190df930be7Sderaadt 		b1 = gen_host(addr, mask, Q_ARP, dir);
1191df930be7Sderaadt 		gen_or(b0, b1);
1192df930be7Sderaadt 		b0 = gen_host(addr, mask, Q_RARP, dir);
1193df930be7Sderaadt 		gen_or(b1, b0);
1194df930be7Sderaadt 		return b0;
1195df930be7Sderaadt 
1196df930be7Sderaadt 	case Q_IP:
1197df930be7Sderaadt 		return gen_hostop(addr, mask, dir, ETHERTYPE_IP,
11988d8814c2Scanacar 				  12, 16);
1199df930be7Sderaadt 
1200df930be7Sderaadt 	case Q_RARP:
1201df930be7Sderaadt 		return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP,
12028d8814c2Scanacar 				  14, 24);
1203df930be7Sderaadt 
1204df930be7Sderaadt 	case Q_ARP:
1205df930be7Sderaadt 		return gen_hostop(addr, mask, dir, ETHERTYPE_ARP,
12068d8814c2Scanacar 				  14, 24);
1207df930be7Sderaadt 
1208df930be7Sderaadt 	case Q_TCP:
1209df930be7Sderaadt 		bpf_error("'tcp' modifier applied to host");
1210df930be7Sderaadt 
1211df930be7Sderaadt 	case Q_UDP:
1212df930be7Sderaadt 		bpf_error("'udp' modifier applied to host");
1213df930be7Sderaadt 
1214df930be7Sderaadt 	case Q_ICMP:
1215df930be7Sderaadt 		bpf_error("'icmp' modifier applied to host");
1216df930be7Sderaadt 
12179b113833Smickey 	case Q_IGMP:
12189b113833Smickey 		bpf_error("'igmp' modifier applied to host");
12199b113833Smickey 
122001efc7efSderaadt 	case Q_IGRP:
122101efc7efSderaadt 		bpf_error("'igrp' modifier applied to host");
122201efc7efSderaadt 
1223a9b0695fSjakob 	case Q_PIM:
1224a9b0695fSjakob 		bpf_error("'pim' modifier applied to host");
1225a9b0695fSjakob 
1226f562933eSmpf 	case Q_STP:
1227f562933eSmpf 		bpf_error("'stp' modifier applied to host");
1228f562933eSmpf 
122901efc7efSderaadt 	case Q_ATALK:
123001efc7efSderaadt 		bpf_error("ATALK host filtering not implemented");
123101efc7efSderaadt 
1232df930be7Sderaadt 	case Q_DECNET:
12338d8814c2Scanacar 		return gen_dnhostop(addr, dir, 0);
1234df930be7Sderaadt 
123501efc7efSderaadt 	case Q_SCA:
123601efc7efSderaadt 		bpf_error("SCA host filtering not implemented");
123701efc7efSderaadt 
1238df930be7Sderaadt 	case Q_LAT:
1239df930be7Sderaadt 		bpf_error("LAT host filtering not implemented");
1240df930be7Sderaadt 
1241df930be7Sderaadt 	case Q_MOPDL:
1242df930be7Sderaadt 		bpf_error("MOPDL host filtering not implemented");
1243df930be7Sderaadt 
1244df930be7Sderaadt 	case Q_MOPRC:
1245df930be7Sderaadt 		bpf_error("MOPRC host filtering not implemented");
1246df930be7Sderaadt 
1247a9b0695fSjakob #ifdef INET6
1248a9b0695fSjakob 	case Q_IPV6:
1249a9b0695fSjakob 		bpf_error("'ip6' modifier applied to ip host");
1250a9b0695fSjakob 
1251a9b0695fSjakob 	case Q_ICMPV6:
1252a9b0695fSjakob 		bpf_error("'icmp6' modifier applied to host");
1253a9b0695fSjakob #endif /* INET6 */
1254a9b0695fSjakob 
1255a9b0695fSjakob 	case Q_AH:
1256a9b0695fSjakob 		bpf_error("'ah' modifier applied to host");
1257a9b0695fSjakob 
1258a9b0695fSjakob 	case Q_ESP:
1259a9b0695fSjakob 		bpf_error("'esp' modifier applied to host");
1260a9b0695fSjakob 
1261df930be7Sderaadt 	default:
1262d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
1263d42a50a0Sreyk 		    linktype);
1264df930be7Sderaadt 	}
1265df930be7Sderaadt 	/* NOTREACHED */
1266df930be7Sderaadt }
1267df930be7Sderaadt 
1268a9b0695fSjakob #ifdef INET6
1269a9b0695fSjakob static struct block *
127019fef815Sderaadt gen_host6(struct in6_addr *addr, struct in6_addr *mask, int proto, int dir)
1271a9b0695fSjakob {
1272a9b0695fSjakob 	switch (proto) {
1273a9b0695fSjakob 
1274a9b0695fSjakob 	case Q_DEFAULT:
1275a9b0695fSjakob 		return gen_host6(addr, mask, Q_IPV6, dir);
1276a9b0695fSjakob 
1277a9b0695fSjakob 	case Q_IP:
1278a9b0695fSjakob 		bpf_error("'ip' modifier applied to ip6 host");
1279a9b0695fSjakob 
1280a9b0695fSjakob 	case Q_RARP:
1281a9b0695fSjakob 		bpf_error("'rarp' modifier applied to ip6 host");
1282a9b0695fSjakob 
1283a9b0695fSjakob 	case Q_ARP:
1284a9b0695fSjakob 		bpf_error("'arp' modifier applied to ip6 host");
1285a9b0695fSjakob 
1286a9b0695fSjakob 	case Q_TCP:
1287a9b0695fSjakob 		bpf_error("'tcp' modifier applied to host");
1288a9b0695fSjakob 
1289a9b0695fSjakob 	case Q_UDP:
1290a9b0695fSjakob 		bpf_error("'udp' modifier applied to host");
1291a9b0695fSjakob 
1292a9b0695fSjakob 	case Q_ICMP:
1293a9b0695fSjakob 		bpf_error("'icmp' modifier applied to host");
1294a9b0695fSjakob 
1295a9b0695fSjakob 	case Q_IGMP:
1296a9b0695fSjakob 		bpf_error("'igmp' modifier applied to host");
1297a9b0695fSjakob 
1298a9b0695fSjakob 	case Q_IGRP:
1299a9b0695fSjakob 		bpf_error("'igrp' modifier applied to host");
1300a9b0695fSjakob 
1301a9b0695fSjakob 	case Q_PIM:
1302a9b0695fSjakob 		bpf_error("'pim' modifier applied to host");
1303a9b0695fSjakob 
1304f562933eSmpf 	case Q_STP:
1305f562933eSmpf 		bpf_error("'stp' modifier applied to host");
1306f562933eSmpf 
1307a9b0695fSjakob 	case Q_ATALK:
1308a9b0695fSjakob 		bpf_error("ATALK host filtering not implemented");
1309a9b0695fSjakob 
1310a9b0695fSjakob 	case Q_DECNET:
1311a9b0695fSjakob 		bpf_error("'decnet' modifier applied to ip6 host");
1312a9b0695fSjakob 
1313a9b0695fSjakob 	case Q_SCA:
1314a9b0695fSjakob 		bpf_error("SCA host filtering not implemented");
1315a9b0695fSjakob 
1316a9b0695fSjakob 	case Q_LAT:
1317a9b0695fSjakob 		bpf_error("LAT host filtering not implemented");
1318a9b0695fSjakob 
1319a9b0695fSjakob 	case Q_MOPDL:
1320a9b0695fSjakob 		bpf_error("MOPDL host filtering not implemented");
1321a9b0695fSjakob 
1322a9b0695fSjakob 	case Q_MOPRC:
1323a9b0695fSjakob 		bpf_error("MOPRC host filtering not implemented");
1324a9b0695fSjakob 
1325a9b0695fSjakob 	case Q_IPV6:
1326a9b0695fSjakob 		return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6,
13278d8814c2Scanacar 				   8, 24);
1328a9b0695fSjakob 
1329a9b0695fSjakob 	case Q_ICMPV6:
1330a9b0695fSjakob 		bpf_error("'icmp6' modifier applied to host");
1331a9b0695fSjakob 
1332a9b0695fSjakob 	case Q_AH:
1333a9b0695fSjakob 		bpf_error("'ah' modifier applied to host");
1334a9b0695fSjakob 
1335a9b0695fSjakob 	case Q_ESP:
1336a9b0695fSjakob 		bpf_error("'esp' modifier applied to host");
1337a9b0695fSjakob 
1338a9b0695fSjakob 	default:
1339a9b0695fSjakob 		abort();
1340a9b0695fSjakob 	}
1341a9b0695fSjakob 	/* NOTREACHED */
1342a9b0695fSjakob }
1343a9b0695fSjakob #endif /*INET6*/
1344a9b0695fSjakob 
1345a9b0695fSjakob #ifndef INET6
1346df930be7Sderaadt static struct block *
1347146262eaSjsg gen_gateway(const u_char *eaddr, bpf_u_int32 **alist, int proto, int dir)
1348df930be7Sderaadt {
1349df930be7Sderaadt 	struct block *b0, *b1, *tmp;
1350df930be7Sderaadt 
1351df930be7Sderaadt 	if (dir != 0)
1352df930be7Sderaadt 		bpf_error("direction applied to 'gateway'");
1353df930be7Sderaadt 
1354df930be7Sderaadt 	switch (proto) {
1355df930be7Sderaadt 	case Q_DEFAULT:
1356df930be7Sderaadt 	case Q_IP:
1357df930be7Sderaadt 	case Q_ARP:
1358df930be7Sderaadt 	case Q_RARP:
1359df930be7Sderaadt 		if (linktype == DLT_EN10MB)
1360df930be7Sderaadt 			b0 = gen_ehostop(eaddr, Q_OR);
1361df930be7Sderaadt 		else if (linktype == DLT_FDDI)
1362df930be7Sderaadt 			b0 = gen_fhostop(eaddr, Q_OR);
1363df930be7Sderaadt 		else
13649b113833Smickey 			bpf_error(
13659b113833Smickey 			    "'gateway' supported only on ethernet or FDDI");
1366df930be7Sderaadt 
136701efc7efSderaadt 		b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR);
1368df930be7Sderaadt 		while (*alist) {
136901efc7efSderaadt 			tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR);
1370df930be7Sderaadt 			gen_or(b1, tmp);
1371df930be7Sderaadt 			b1 = tmp;
1372df930be7Sderaadt 		}
1373df930be7Sderaadt 		gen_not(b1);
1374df930be7Sderaadt 		gen_and(b0, b1);
1375df930be7Sderaadt 		return b1;
1376df930be7Sderaadt 	}
1377df930be7Sderaadt 	bpf_error("illegal modifier of 'gateway'");
1378df930be7Sderaadt 	/* NOTREACHED */
1379df930be7Sderaadt }
1380a9b0695fSjakob #endif	/*INET6*/
1381df930be7Sderaadt 
1382df930be7Sderaadt struct block *
138319fef815Sderaadt gen_proto_abbrev(int proto)
1384df930be7Sderaadt {
1385a9b0695fSjakob 	struct block *b0 = NULL, *b1;
1386df930be7Sderaadt 
1387df930be7Sderaadt 	switch (proto) {
1388df930be7Sderaadt 
1389df930be7Sderaadt 	case Q_TCP:
1390a9b0695fSjakob 		b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT);
1391a9b0695fSjakob #ifdef INET6
1392a9b0695fSjakob 		b0 = gen_proto(IPPROTO_TCP, Q_IPV6, Q_DEFAULT);
1393a9b0695fSjakob 		gen_or(b0, b1);
1394a9b0695fSjakob #endif
1395df930be7Sderaadt 		break;
1396df930be7Sderaadt 
1397df930be7Sderaadt 	case Q_UDP:
1398a9b0695fSjakob 		b1 = gen_proto(IPPROTO_UDP, Q_IP, Q_DEFAULT);
1399a9b0695fSjakob #ifdef INET6
1400a9b0695fSjakob 		b0 = gen_proto(IPPROTO_UDP, Q_IPV6, Q_DEFAULT);
1401a9b0695fSjakob 		gen_or(b0, b1);
1402a9b0695fSjakob #endif
1403df930be7Sderaadt 		break;
1404df930be7Sderaadt 
1405df930be7Sderaadt 	case Q_ICMP:
1406a9b0695fSjakob 		b1 = gen_proto(IPPROTO_ICMP, Q_IP, Q_DEFAULT);
14079b113833Smickey 		break;
14089b113833Smickey 
1409a9b0695fSjakob #ifndef	IPPROTO_IGMP
1410a9b0695fSjakob #define	IPPROTO_IGMP	2
1411a9b0695fSjakob #endif
1412a9b0695fSjakob 
14139b113833Smickey 	case Q_IGMP:
1414a9b0695fSjakob 		b1 = gen_proto(IPPROTO_IGMP, Q_IP, Q_DEFAULT);
1415df930be7Sderaadt 		break;
1416df930be7Sderaadt 
141701efc7efSderaadt #ifndef	IPPROTO_IGRP
141801efc7efSderaadt #define	IPPROTO_IGRP	9
141901efc7efSderaadt #endif
142001efc7efSderaadt 	case Q_IGRP:
1421a9b0695fSjakob 		b1 = gen_proto(IPPROTO_IGRP, Q_IP, Q_DEFAULT);
1422a9b0695fSjakob 		break;
1423a9b0695fSjakob 
1424a9b0695fSjakob #ifndef IPPROTO_PIM
1425a9b0695fSjakob #define IPPROTO_PIM	103
1426a9b0695fSjakob #endif
1427a9b0695fSjakob 
1428a9b0695fSjakob 	case Q_PIM:
1429a9b0695fSjakob 		b1 = gen_proto(IPPROTO_PIM, Q_IP, Q_DEFAULT);
1430a9b0695fSjakob #ifdef INET6
1431a9b0695fSjakob 		b0 = gen_proto(IPPROTO_PIM, Q_IPV6, Q_DEFAULT);
1432a9b0695fSjakob 		gen_or(b0, b1);
1433a9b0695fSjakob #endif
143401efc7efSderaadt 		break;
143501efc7efSderaadt 
1436df930be7Sderaadt 	case Q_IP:
1437df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_IP);
1438df930be7Sderaadt 		break;
1439df930be7Sderaadt 
1440df930be7Sderaadt 	case Q_ARP:
1441df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_ARP);
1442df930be7Sderaadt 		break;
1443df930be7Sderaadt 
1444df930be7Sderaadt 	case Q_RARP:
1445df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_REVARP);
1446df930be7Sderaadt 		break;
1447df930be7Sderaadt 
1448df930be7Sderaadt 	case Q_LINK:
1449df930be7Sderaadt 		bpf_error("link layer applied in wrong context");
1450df930be7Sderaadt 
145101efc7efSderaadt 	case Q_ATALK:
145201efc7efSderaadt 		b1 =  gen_linktype(ETHERTYPE_ATALK);
145301efc7efSderaadt 		break;
145401efc7efSderaadt 
1455df930be7Sderaadt 	case Q_DECNET:
1456df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_DN);
1457df930be7Sderaadt 		break;
1458df930be7Sderaadt 
145901efc7efSderaadt 	case Q_SCA:
146001efc7efSderaadt 		b1 =  gen_linktype(ETHERTYPE_SCA);
146101efc7efSderaadt 		break;
146201efc7efSderaadt 
1463df930be7Sderaadt 	case Q_LAT:
1464df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_LAT);
1465df930be7Sderaadt 		break;
1466df930be7Sderaadt 
1467df930be7Sderaadt 	case Q_MOPDL:
1468df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_MOPDL);
1469df930be7Sderaadt 		break;
1470df930be7Sderaadt 
1471df930be7Sderaadt 	case Q_MOPRC:
1472df930be7Sderaadt 		b1 =  gen_linktype(ETHERTYPE_MOPRC);
1473df930be7Sderaadt 		break;
1474df930be7Sderaadt 
1475f562933eSmpf 	case Q_STP:
1476f562933eSmpf 		b1 = gen_linktype(LLCSAP_8021D);
1477f562933eSmpf 		break;
1478f562933eSmpf 
1479a9b0695fSjakob #ifdef INET6
1480a9b0695fSjakob 	case Q_IPV6:
1481a9b0695fSjakob 		b1 = gen_linktype(ETHERTYPE_IPV6);
1482a9b0695fSjakob 		break;
1483a9b0695fSjakob 
1484a9b0695fSjakob #ifndef IPPROTO_ICMPV6
1485a9b0695fSjakob #define IPPROTO_ICMPV6	58
1486a9b0695fSjakob #endif
1487a9b0695fSjakob 	case Q_ICMPV6:
1488a9b0695fSjakob 		b1 = gen_proto(IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT);
1489a9b0695fSjakob 		break;
1490a9b0695fSjakob #endif /* INET6 */
1491a9b0695fSjakob 
1492a9b0695fSjakob #ifndef IPPROTO_AH
1493a9b0695fSjakob #define IPPROTO_AH	51
1494a9b0695fSjakob #endif
1495a9b0695fSjakob 	case Q_AH:
1496a9b0695fSjakob 		b1 = gen_proto(IPPROTO_AH, Q_IP, Q_DEFAULT);
1497a9b0695fSjakob #ifdef INET6
1498a9b0695fSjakob 		b0 = gen_proto(IPPROTO_AH, Q_IPV6, Q_DEFAULT);
1499a9b0695fSjakob 		gen_or(b0, b1);
1500a9b0695fSjakob #endif
1501a9b0695fSjakob 		break;
1502a9b0695fSjakob 
1503a9b0695fSjakob #ifndef IPPROTO_ESP
1504a9b0695fSjakob #define IPPROTO_ESP	50
1505a9b0695fSjakob #endif
1506a9b0695fSjakob 	case Q_ESP:
1507a9b0695fSjakob 		b1 = gen_proto(IPPROTO_ESP, Q_IP, Q_DEFAULT);
1508a9b0695fSjakob #ifdef INET6
1509a9b0695fSjakob 		b0 = gen_proto(IPPROTO_ESP, Q_IPV6, Q_DEFAULT);
1510a9b0695fSjakob 		gen_or(b0, b1);
1511a9b0695fSjakob #endif
1512a9b0695fSjakob 		break;
1513a9b0695fSjakob 
1514df930be7Sderaadt 	default:
1515df930be7Sderaadt 		abort();
1516df930be7Sderaadt 	}
1517df930be7Sderaadt 	return b1;
1518df930be7Sderaadt }
1519df930be7Sderaadt 
1520df930be7Sderaadt static struct block *
1521146262eaSjsg gen_ipfrag(void)
1522df930be7Sderaadt {
15238d8814c2Scanacar 	struct slist *s, *tmp;
1524df930be7Sderaadt 	struct block *b;
1525df930be7Sderaadt 
1526df930be7Sderaadt 	/* not ip frag */
15278d8814c2Scanacar 	if (variable_nl) {
15288d8814c2Scanacar 		s = nl2X_stmt();
15298d8814c2Scanacar 		tmp = new_stmt(BPF_LD|BPF_H|BPF_IND);
15308d8814c2Scanacar 		tmp->s.k = 6;
15318d8814c2Scanacar 		sappend(s, tmp);
15328d8814c2Scanacar 	} else {
1533df930be7Sderaadt 		s = new_stmt(BPF_LD|BPF_H|BPF_ABS);
1534df930be7Sderaadt 		s->s.k = off_nl + 6;
15358d8814c2Scanacar 	}
1536df930be7Sderaadt 	b = new_block(JMP(BPF_JSET));
1537df930be7Sderaadt 	b->s.k = 0x1fff;
1538df930be7Sderaadt 	b->stmts = s;
1539df930be7Sderaadt 	gen_not(b);
1540df930be7Sderaadt 
1541df930be7Sderaadt 	return b;
1542df930be7Sderaadt }
1543df930be7Sderaadt 
15448d8814c2Scanacar /* For dynamic off_nl, the BPF_LDX|BPF_MSH instruction does not work
15458d8814c2Scanacar    This function generates code to set X to the start of the IP payload
15468d8814c2Scanacar    X = off_nl + IP header_len.
15478d8814c2Scanacar */
15488d8814c2Scanacar static struct slist *
15498d8814c2Scanacar iphl_to_x(void)
15508d8814c2Scanacar {
15518d8814c2Scanacar 	struct slist *s, *tmp;
15528d8814c2Scanacar 
15538d8814c2Scanacar 	/* XXX clobbers A if variable_nl*/
15548d8814c2Scanacar 	if (variable_nl) {
15558d8814c2Scanacar 		if (iphl_reg == -1) {
15568d8814c2Scanacar 			/* X <- off_nl */
15578d8814c2Scanacar 			s = nl2X_stmt();
15588d8814c2Scanacar 
15598d8814c2Scanacar 			/* A = p[X+0] */
15608d8814c2Scanacar 			tmp = new_stmt(BPF_LD|BPF_B|BPF_IND);
15618d8814c2Scanacar 			tmp->s.k = 0;
15628d8814c2Scanacar 			sappend(s, tmp);
15638d8814c2Scanacar 
15648d8814c2Scanacar 			/* A = A & 0x0f */
15658d8814c2Scanacar 			tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K);
15668d8814c2Scanacar 			tmp->s.k = 0x0f;
15678d8814c2Scanacar 			sappend(s, tmp);
15688d8814c2Scanacar 
15698d8814c2Scanacar 			/* A = A << 2 */
15708d8814c2Scanacar 			tmp = new_stmt(BPF_ALU|BPF_LSH|BPF_K);
15718d8814c2Scanacar 			tmp->s.k = 2;
15728d8814c2Scanacar 			sappend(s, tmp);
15738d8814c2Scanacar 
15742c53affbSjmc 			/* A = A + X (add off_nl again to compensate) */
15758d8814c2Scanacar 			sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
15768d8814c2Scanacar 
15778d8814c2Scanacar 			/* MEM[iphl_reg] = A */
15788d8814c2Scanacar 			iphl_reg = alloc_reg();
15798d8814c2Scanacar 			tmp = new_stmt(BPF_ST);
15808d8814c2Scanacar 			tmp->s.k = iphl_reg;
15818d8814c2Scanacar 			sappend(s, tmp);
15828d8814c2Scanacar 
15838d8814c2Scanacar 			sappend(init_code, s);
15848d8814c2Scanacar 		}
15858d8814c2Scanacar 		s = new_stmt(BPF_LDX|BPF_MEM);
15868d8814c2Scanacar 		s->s.k = iphl_reg;
15878d8814c2Scanacar 
15888d8814c2Scanacar 	} else {
15898d8814c2Scanacar 		s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
15908d8814c2Scanacar 		s->s.k = off_nl;
15918d8814c2Scanacar 	}
15928d8814c2Scanacar 
15938d8814c2Scanacar 	return s;
15948d8814c2Scanacar }
15958d8814c2Scanacar 
1596df930be7Sderaadt static struct block *
159719fef815Sderaadt gen_portatom(int off, bpf_int32 v)
1598df930be7Sderaadt {
15998d8814c2Scanacar 	struct slist *s, *tmp;
1600df930be7Sderaadt 	struct block *b;
1601df930be7Sderaadt 
16028d8814c2Scanacar 	s = iphl_to_x();
1603df930be7Sderaadt 
16048d8814c2Scanacar 	tmp = new_stmt(BPF_LD|BPF_IND|BPF_H);
16058d8814c2Scanacar 	tmp->s.k = off_nl + off;	/* off_nl == 0 if variable_nl */
16068d8814c2Scanacar 	sappend(s, tmp);
1607df930be7Sderaadt 
1608df930be7Sderaadt 	b = new_block(JMP(BPF_JEQ));
1609df930be7Sderaadt 	b->stmts = s;
1610df930be7Sderaadt 	b->s.k = v;
1611df930be7Sderaadt 
1612df930be7Sderaadt 	return b;
1613df930be7Sderaadt }
1614df930be7Sderaadt 
1615a9b0695fSjakob #ifdef INET6
1616a9b0695fSjakob static struct block *
161719fef815Sderaadt gen_portatom6(int off, bpf_int32 v)
1618a9b0695fSjakob {
16198d8814c2Scanacar 	return gen_cmp_nl(40 + off, BPF_H, v);
1620a9b0695fSjakob }
1621a9b0695fSjakob #endif/*INET6*/
1622a9b0695fSjakob 
1623df930be7Sderaadt struct block *
162419fef815Sderaadt gen_portop(int port, int proto, int dir)
1625df930be7Sderaadt {
1626df930be7Sderaadt 	struct block *b0, *b1, *tmp;
1627df930be7Sderaadt 
1628df930be7Sderaadt 	/* ip proto 'proto' */
16298d8814c2Scanacar 	tmp = gen_cmp_nl(9, BPF_B, (bpf_int32)proto);
1630df930be7Sderaadt 	b0 = gen_ipfrag();
1631df930be7Sderaadt 	gen_and(tmp, b0);
1632df930be7Sderaadt 
1633df930be7Sderaadt 	switch (dir) {
1634df930be7Sderaadt 	case Q_SRC:
16359b113833Smickey 		b1 = gen_portatom(0, (bpf_int32)port);
1636df930be7Sderaadt 		break;
1637df930be7Sderaadt 
1638df930be7Sderaadt 	case Q_DST:
16399b113833Smickey 		b1 = gen_portatom(2, (bpf_int32)port);
1640df930be7Sderaadt 		break;
1641df930be7Sderaadt 
1642df930be7Sderaadt 	case Q_OR:
1643df930be7Sderaadt 	case Q_DEFAULT:
16449b113833Smickey 		tmp = gen_portatom(0, (bpf_int32)port);
16459b113833Smickey 		b1 = gen_portatom(2, (bpf_int32)port);
1646df930be7Sderaadt 		gen_or(tmp, b1);
1647df930be7Sderaadt 		break;
1648df930be7Sderaadt 
1649df930be7Sderaadt 	case Q_AND:
16509b113833Smickey 		tmp = gen_portatom(0, (bpf_int32)port);
16519b113833Smickey 		b1 = gen_portatom(2, (bpf_int32)port);
1652df930be7Sderaadt 		gen_and(tmp, b1);
1653df930be7Sderaadt 		break;
1654df930be7Sderaadt 
1655df930be7Sderaadt 	default:
1656df930be7Sderaadt 		abort();
1657df930be7Sderaadt 	}
1658df930be7Sderaadt 	gen_and(b0, b1);
1659df930be7Sderaadt 
1660df930be7Sderaadt 	return b1;
1661df930be7Sderaadt }
1662df930be7Sderaadt 
1663df930be7Sderaadt static struct block *
166419fef815Sderaadt gen_port(int port, int ip_proto, int dir)
1665df930be7Sderaadt {
1666df930be7Sderaadt 	struct block *b0, *b1, *tmp;
1667df930be7Sderaadt 
1668df930be7Sderaadt 	/* ether proto ip */
1669df930be7Sderaadt 	b0 =  gen_linktype(ETHERTYPE_IP);
1670df930be7Sderaadt 
1671df930be7Sderaadt 	switch (ip_proto) {
1672df930be7Sderaadt 	case IPPROTO_UDP:
1673df930be7Sderaadt 	case IPPROTO_TCP:
1674df930be7Sderaadt 		b1 = gen_portop(port, ip_proto, dir);
1675df930be7Sderaadt 		break;
1676df930be7Sderaadt 
1677df930be7Sderaadt 	case PROTO_UNDEF:
1678df930be7Sderaadt 		tmp = gen_portop(port, IPPROTO_TCP, dir);
1679df930be7Sderaadt 		b1 = gen_portop(port, IPPROTO_UDP, dir);
1680df930be7Sderaadt 		gen_or(tmp, b1);
1681df930be7Sderaadt 		break;
1682df930be7Sderaadt 
1683df930be7Sderaadt 	default:
1684df930be7Sderaadt 		abort();
1685df930be7Sderaadt 	}
1686df930be7Sderaadt 	gen_and(b0, b1);
1687df930be7Sderaadt 	return b1;
1688df930be7Sderaadt }
1689df930be7Sderaadt 
1690a9b0695fSjakob #ifdef INET6
1691a9b0695fSjakob struct block *
169219fef815Sderaadt gen_portop6(int port, int proto, int dir)
1693a9b0695fSjakob {
1694a9b0695fSjakob 	struct block *b0, *b1, *tmp;
1695a9b0695fSjakob 
1696a9b0695fSjakob 	/* ip proto 'proto' */
16978d8814c2Scanacar 	b0 = gen_cmp_nl(6, BPF_B, (bpf_int32)proto);
1698a9b0695fSjakob 
1699a9b0695fSjakob 	switch (dir) {
1700a9b0695fSjakob 	case Q_SRC:
1701a9b0695fSjakob 		b1 = gen_portatom6(0, (bpf_int32)port);
1702a9b0695fSjakob 		break;
1703a9b0695fSjakob 
1704a9b0695fSjakob 	case Q_DST:
1705a9b0695fSjakob 		b1 = gen_portatom6(2, (bpf_int32)port);
1706a9b0695fSjakob 		break;
1707a9b0695fSjakob 
1708a9b0695fSjakob 	case Q_OR:
1709a9b0695fSjakob 	case Q_DEFAULT:
1710a9b0695fSjakob 		tmp = gen_portatom6(0, (bpf_int32)port);
1711a9b0695fSjakob 		b1 = gen_portatom6(2, (bpf_int32)port);
1712a9b0695fSjakob 		gen_or(tmp, b1);
1713a9b0695fSjakob 		break;
1714a9b0695fSjakob 
1715a9b0695fSjakob 	case Q_AND:
1716a9b0695fSjakob 		tmp = gen_portatom6(0, (bpf_int32)port);
1717a9b0695fSjakob 		b1 = gen_portatom6(2, (bpf_int32)port);
1718a9b0695fSjakob 		gen_and(tmp, b1);
1719a9b0695fSjakob 		break;
1720a9b0695fSjakob 
1721a9b0695fSjakob 	default:
1722a9b0695fSjakob 		abort();
1723a9b0695fSjakob 	}
1724a9b0695fSjakob 	gen_and(b0, b1);
1725a9b0695fSjakob 
1726a9b0695fSjakob 	return b1;
1727a9b0695fSjakob }
1728a9b0695fSjakob 
1729a9b0695fSjakob static struct block *
173019fef815Sderaadt gen_port6(int port, int ip_proto, int dir)
1731a9b0695fSjakob {
1732a9b0695fSjakob 	struct block *b0, *b1, *tmp;
1733a9b0695fSjakob 
1734a9b0695fSjakob 	/* ether proto ip */
1735a9b0695fSjakob 	b0 =  gen_linktype(ETHERTYPE_IPV6);
1736a9b0695fSjakob 
1737a9b0695fSjakob 	switch (ip_proto) {
1738a9b0695fSjakob 	case IPPROTO_UDP:
1739a9b0695fSjakob 	case IPPROTO_TCP:
1740a9b0695fSjakob 		b1 = gen_portop6(port, ip_proto, dir);
1741a9b0695fSjakob 		break;
1742a9b0695fSjakob 
1743a9b0695fSjakob 	case PROTO_UNDEF:
1744a9b0695fSjakob 		tmp = gen_portop6(port, IPPROTO_TCP, dir);
1745a9b0695fSjakob 		b1 = gen_portop6(port, IPPROTO_UDP, dir);
1746a9b0695fSjakob 		gen_or(tmp, b1);
1747a9b0695fSjakob 		break;
1748a9b0695fSjakob 
1749a9b0695fSjakob 	default:
1750a9b0695fSjakob 		abort();
1751a9b0695fSjakob 	}
1752a9b0695fSjakob 	gen_and(b0, b1);
1753a9b0695fSjakob 	return b1;
1754a9b0695fSjakob }
1755a9b0695fSjakob #endif /* INET6 */
1756a9b0695fSjakob 
1757df930be7Sderaadt static int
175819fef815Sderaadt lookup_proto(const char *name, int proto)
1759df930be7Sderaadt {
1760d0438536Smmcc 	int v;
1761df930be7Sderaadt 
1762df930be7Sderaadt 	switch (proto) {
176301efc7efSderaadt 
1764df930be7Sderaadt 	case Q_DEFAULT:
1765df930be7Sderaadt 	case Q_IP:
1766df930be7Sderaadt 		v = pcap_nametoproto(name);
1767df930be7Sderaadt 		if (v == PROTO_UNDEF)
1768df930be7Sderaadt 			bpf_error("unknown ip proto '%s'", name);
1769df930be7Sderaadt 		break;
1770df930be7Sderaadt 
1771df930be7Sderaadt 	case Q_LINK:
1772df930be7Sderaadt 		/* XXX should look up h/w protocol type based on linktype */
1773df930be7Sderaadt 		v = pcap_nametoeproto(name);
1774f562933eSmpf 		if (v == PROTO_UNDEF) {
1775f562933eSmpf 			v = pcap_nametollc(name);
1776df930be7Sderaadt 			if (v == PROTO_UNDEF)
1777df930be7Sderaadt 				bpf_error("unknown ether proto '%s'", name);
1778f562933eSmpf 		}
1779df930be7Sderaadt 		break;
1780df930be7Sderaadt 
1781df930be7Sderaadt 	default:
1782df930be7Sderaadt 		v = PROTO_UNDEF;
1783df930be7Sderaadt 		break;
1784df930be7Sderaadt 	}
1785df930be7Sderaadt 	return v;
1786df930be7Sderaadt }
1787df930be7Sderaadt 
1788df930be7Sderaadt static struct block *
178919fef815Sderaadt gen_protochain(int v, int proto, int dir)
1790a9b0695fSjakob {
1791a9b0695fSjakob 	struct block *b0, *b;
1792a9b0695fSjakob 	struct slist *s[100];
1793a9b0695fSjakob 	int fix2, fix3, fix4, fix5;
1794a9b0695fSjakob 	int ahcheck, again, end;
1795a9b0695fSjakob 	int i, max;
1796a9b0695fSjakob 	int reg1 = alloc_reg();
1797a9b0695fSjakob 	int reg2 = alloc_reg();
1798a9b0695fSjakob 
1799a9b0695fSjakob 	memset(s, 0, sizeof(s));
1800a9b0695fSjakob 	fix2 = fix3 = fix4 = fix5 = 0;
1801a9b0695fSjakob 
18028d8814c2Scanacar 	if (variable_nl) {
18038d8814c2Scanacar 		bpf_error("'gen_protochain' not supported for variable DLTs");
18048d8814c2Scanacar 		/*NOTREACHED*/
18058d8814c2Scanacar 	}
18068d8814c2Scanacar 
1807a9b0695fSjakob 	switch (proto) {
1808a9b0695fSjakob 	case Q_IP:
1809a9b0695fSjakob 	case Q_IPV6:
1810a9b0695fSjakob 		break;
1811a9b0695fSjakob 	case Q_DEFAULT:
1812a9b0695fSjakob 		b0 = gen_protochain(v, Q_IP, dir);
1813a9b0695fSjakob 		b = gen_protochain(v, Q_IPV6, dir);
1814a9b0695fSjakob 		gen_or(b0, b);
1815a9b0695fSjakob 		return b;
1816a9b0695fSjakob 	default:
1817a9b0695fSjakob 		bpf_error("bad protocol applied for 'protochain'");
1818a9b0695fSjakob 		/*NOTREACHED*/
1819a9b0695fSjakob 	}
1820a9b0695fSjakob 
1821a9b0695fSjakob 	no_optimize = 1; /*this code is not compatible with optimzer yet */
1822a9b0695fSjakob 
1823a9b0695fSjakob 	/*
1824a9b0695fSjakob 	 * s[0] is a dummy entry to protect other BPF insn from damaged
1825a9b0695fSjakob 	 * by s[fix] = foo with uninitialized variable "fix".  It is somewhat
1826a9b0695fSjakob 	 * hard to find interdependency made by jump table fixup.
1827a9b0695fSjakob 	 */
1828a9b0695fSjakob 	i = 0;
1829a9b0695fSjakob 	s[i] = new_stmt(0);	/*dummy*/
1830a9b0695fSjakob 	i++;
1831a9b0695fSjakob 
1832a9b0695fSjakob 	switch (proto) {
1833a9b0695fSjakob 	case Q_IP:
1834a9b0695fSjakob 		b0 = gen_linktype(ETHERTYPE_IP);
1835a9b0695fSjakob 
1836a9b0695fSjakob 		/* A = ip->ip_p */
1837a9b0695fSjakob 		s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
1838a9b0695fSjakob 		s[i]->s.k = off_nl + 9;
1839a9b0695fSjakob 		i++;
1840a9b0695fSjakob 		/* X = ip->ip_hl << 2 */
1841a9b0695fSjakob 		s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
1842a9b0695fSjakob 		s[i]->s.k = off_nl;
1843a9b0695fSjakob 		i++;
1844a9b0695fSjakob 		break;
1845a9b0695fSjakob 	case Q_IPV6:
1846a9b0695fSjakob 		b0 = gen_linktype(ETHERTYPE_IPV6);
1847a9b0695fSjakob 
1848a9b0695fSjakob 		/* A = ip6->ip_nxt */
1849a9b0695fSjakob 		s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B);
1850a9b0695fSjakob 		s[i]->s.k = off_nl + 6;
1851a9b0695fSjakob 		i++;
1852a9b0695fSjakob 		/* X = sizeof(struct ip6_hdr) */
1853a9b0695fSjakob 		s[i] = new_stmt(BPF_LDX|BPF_IMM);
1854a9b0695fSjakob 		s[i]->s.k = 40;
1855a9b0695fSjakob 		i++;
1856a9b0695fSjakob 		break;
1857a9b0695fSjakob 	default:
1858a9b0695fSjakob 		bpf_error("unsupported proto to gen_protochain");
1859a9b0695fSjakob 		/*NOTREACHED*/
1860a9b0695fSjakob 	}
1861a9b0695fSjakob 
1862a9b0695fSjakob 	/* again: if (A == v) goto end; else fall through; */
1863a9b0695fSjakob 	again = i;
1864a9b0695fSjakob 	s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1865a9b0695fSjakob 	s[i]->s.k = v;
1866a9b0695fSjakob 	s[i]->s.jt = NULL;		/*later*/
1867a9b0695fSjakob 	s[i]->s.jf = NULL;		/*update in next stmt*/
1868a9b0695fSjakob 	fix5 = i;
1869a9b0695fSjakob 	i++;
1870a9b0695fSjakob 
1871a9b0695fSjakob 	/* if (A == IPPROTO_NONE) goto end */
1872a9b0695fSjakob 	s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1873a9b0695fSjakob 	s[i]->s.jt = NULL;	/*later*/
1874a9b0695fSjakob 	s[i]->s.jf = NULL;	/*update in next stmt*/
1875a9b0695fSjakob 	s[i]->s.k = IPPROTO_NONE;
1876a9b0695fSjakob 	s[fix5]->s.jf = s[i];
1877a9b0695fSjakob 	fix2 = i;
1878a9b0695fSjakob 	i++;
1879a9b0695fSjakob 
1880a9b0695fSjakob 	if (proto == Q_IPV6) {
1881a9b0695fSjakob 		int v6start, v6end, v6advance, j;
1882a9b0695fSjakob 
1883a9b0695fSjakob 		v6start = i;
1884a9b0695fSjakob 		/* if (A == IPPROTO_HOPOPTS) goto v6advance */
1885a9b0695fSjakob 		s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1886a9b0695fSjakob 		s[i]->s.jt = NULL;	/*later*/
1887a9b0695fSjakob 		s[i]->s.jf = NULL;	/*update in next stmt*/
1888a9b0695fSjakob 		s[i]->s.k = IPPROTO_HOPOPTS;
1889a9b0695fSjakob 		s[fix2]->s.jf = s[i];
1890a9b0695fSjakob 		i++;
1891a9b0695fSjakob 		/* if (A == IPPROTO_DSTOPTS) goto v6advance */
1892a9b0695fSjakob 		s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1893a9b0695fSjakob 		s[i]->s.jt = NULL;	/*later*/
1894a9b0695fSjakob 		s[i]->s.jf = NULL;	/*update in next stmt*/
1895a9b0695fSjakob 		s[i]->s.k = IPPROTO_DSTOPTS;
1896a9b0695fSjakob 		i++;
1897a9b0695fSjakob 		/* if (A == IPPROTO_ROUTING) goto v6advance */
1898a9b0695fSjakob 		s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1899a9b0695fSjakob 		s[i]->s.jt = NULL;	/*later*/
1900a9b0695fSjakob 		s[i]->s.jf = NULL;	/*update in next stmt*/
1901a9b0695fSjakob 		s[i]->s.k = IPPROTO_ROUTING;
1902a9b0695fSjakob 		i++;
1903a9b0695fSjakob 		/* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */
1904a9b0695fSjakob 		s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1905a9b0695fSjakob 		s[i]->s.jt = NULL;	/*later*/
1906a9b0695fSjakob 		s[i]->s.jf = NULL;	/*later*/
1907a9b0695fSjakob 		s[i]->s.k = IPPROTO_FRAGMENT;
1908a9b0695fSjakob 		fix3 = i;
1909a9b0695fSjakob 		v6end = i;
1910a9b0695fSjakob 		i++;
1911a9b0695fSjakob 
1912a9b0695fSjakob 		/* v6advance: */
1913a9b0695fSjakob 		v6advance = i;
1914a9b0695fSjakob 
1915a9b0695fSjakob 		/*
1916a9b0695fSjakob 		 * in short,
1917a9b0695fSjakob 		 * A = P[X + 1];
1918a9b0695fSjakob 		 * X = X + (P[X] + 1) * 8;
1919a9b0695fSjakob 		 */
1920a9b0695fSjakob 		/* A = X */
1921a9b0695fSjakob 		s[i] = new_stmt(BPF_MISC|BPF_TXA);
1922a9b0695fSjakob 		i++;
1923a9b0695fSjakob 		/* MEM[reg1] = A */
1924a9b0695fSjakob 		s[i] = new_stmt(BPF_ST);
1925a9b0695fSjakob 		s[i]->s.k = reg1;
1926a9b0695fSjakob 		i++;
1927a9b0695fSjakob 		/* A += 1 */
1928a9b0695fSjakob 		s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
1929a9b0695fSjakob 		s[i]->s.k = 1;
1930a9b0695fSjakob 		i++;
1931a9b0695fSjakob 		/* X = A */
1932a9b0695fSjakob 		s[i] = new_stmt(BPF_MISC|BPF_TAX);
1933a9b0695fSjakob 		i++;
1934a9b0695fSjakob 		/* A = P[X + packet head]; */
1935a9b0695fSjakob 		s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
1936a9b0695fSjakob 		s[i]->s.k = off_nl;
1937a9b0695fSjakob 		i++;
1938a9b0695fSjakob 		/* MEM[reg2] = A */
1939a9b0695fSjakob 		s[i] = new_stmt(BPF_ST);
1940a9b0695fSjakob 		s[i]->s.k = reg2;
1941a9b0695fSjakob 		i++;
1942a9b0695fSjakob 		/* X = MEM[reg1] */
1943a9b0695fSjakob 		s[i] = new_stmt(BPF_LDX|BPF_MEM);
1944a9b0695fSjakob 		s[i]->s.k = reg1;
1945a9b0695fSjakob 		i++;
1946a9b0695fSjakob 		/* A = P[X + packet head] */
1947a9b0695fSjakob 		s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
1948a9b0695fSjakob 		s[i]->s.k = off_nl;
1949a9b0695fSjakob 		i++;
1950a9b0695fSjakob 		/* A += 1 */
1951a9b0695fSjakob 		s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
1952a9b0695fSjakob 		s[i]->s.k = 1;
1953a9b0695fSjakob 		i++;
1954a9b0695fSjakob 		/* A *= 8 */
1955a9b0695fSjakob 		s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K);
1956a9b0695fSjakob 		s[i]->s.k = 8;
1957a9b0695fSjakob 		i++;
1958a9b0695fSjakob 		/* X = A; */
1959a9b0695fSjakob 		s[i] = new_stmt(BPF_MISC|BPF_TAX);
1960a9b0695fSjakob 		i++;
1961a9b0695fSjakob 		/* A = MEM[reg2] */
1962a9b0695fSjakob 		s[i] = new_stmt(BPF_LD|BPF_MEM);
1963a9b0695fSjakob 		s[i]->s.k = reg2;
1964a9b0695fSjakob 		i++;
1965a9b0695fSjakob 
1966a9b0695fSjakob 		/* goto again; (must use BPF_JA for backward jump) */
1967a9b0695fSjakob 		s[i] = new_stmt(BPF_JMP|BPF_JA);
1968a9b0695fSjakob 		s[i]->s.k = again - i - 1;
1969a9b0695fSjakob 		s[i - 1]->s.jf = s[i];
1970a9b0695fSjakob 		i++;
1971a9b0695fSjakob 
1972a9b0695fSjakob 		/* fixup */
1973a9b0695fSjakob 		for (j = v6start; j <= v6end; j++)
1974a9b0695fSjakob 			s[j]->s.jt = s[v6advance];
1975a9b0695fSjakob 	} else {
1976a9b0695fSjakob 		/* nop */
1977a9b0695fSjakob 		s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
1978a9b0695fSjakob 		s[i]->s.k = 0;
1979a9b0695fSjakob 		s[fix2]->s.jf = s[i];
1980a9b0695fSjakob 		i++;
1981a9b0695fSjakob 	}
1982a9b0695fSjakob 
1983a9b0695fSjakob 	/* ahcheck: */
1984a9b0695fSjakob 	ahcheck = i;
1985a9b0695fSjakob 	/* if (A == IPPROTO_AH) then fall through; else goto end; */
1986a9b0695fSjakob 	s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K);
1987a9b0695fSjakob 	s[i]->s.jt = NULL;	/*later*/
1988a9b0695fSjakob 	s[i]->s.jf = NULL;	/*later*/
1989a9b0695fSjakob 	s[i]->s.k = IPPROTO_AH;
1990a9b0695fSjakob 	if (fix3)
1991a9b0695fSjakob 		s[fix3]->s.jf = s[ahcheck];
1992a9b0695fSjakob 	fix4 = i;
1993a9b0695fSjakob 	i++;
1994a9b0695fSjakob 
1995a9b0695fSjakob 	/*
1996a9b0695fSjakob 	 * in short,
1997a9b0695fSjakob 	 * A = P[X + 1];
1998a9b0695fSjakob 	 * X = X + (P[X] + 2) * 4;
1999a9b0695fSjakob 	 */
2000a9b0695fSjakob 	/* A = X */
2001a9b0695fSjakob 	s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA);
2002a9b0695fSjakob 	i++;
2003a9b0695fSjakob 	/* MEM[reg1] = A */
2004a9b0695fSjakob 	s[i] = new_stmt(BPF_ST);
2005a9b0695fSjakob 	s[i]->s.k = reg1;
2006a9b0695fSjakob 	i++;
2007a9b0695fSjakob 	/* A += 1 */
2008a9b0695fSjakob 	s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
2009a9b0695fSjakob 	s[i]->s.k = 1;
2010a9b0695fSjakob 	i++;
2011a9b0695fSjakob 	/* X = A */
2012a9b0695fSjakob 	s[i] = new_stmt(BPF_MISC|BPF_TAX);
2013a9b0695fSjakob 	i++;
2014a9b0695fSjakob 	/* A = P[X + packet head]; */
2015a9b0695fSjakob 	s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
2016a9b0695fSjakob 	s[i]->s.k = off_nl;
2017a9b0695fSjakob 	i++;
2018a9b0695fSjakob 	/* MEM[reg2] = A */
2019a9b0695fSjakob 	s[i] = new_stmt(BPF_ST);
2020a9b0695fSjakob 	s[i]->s.k = reg2;
2021a9b0695fSjakob 	i++;
2022a9b0695fSjakob 	/* X = MEM[reg1] */
2023a9b0695fSjakob 	s[i] = new_stmt(BPF_LDX|BPF_MEM);
2024a9b0695fSjakob 	s[i]->s.k = reg1;
2025a9b0695fSjakob 	i++;
2026a9b0695fSjakob 	/* A = P[X + packet head] */
2027a9b0695fSjakob 	s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B);
2028a9b0695fSjakob 	s[i]->s.k = off_nl;
2029a9b0695fSjakob 	i++;
2030a9b0695fSjakob 	/* A += 2 */
2031a9b0695fSjakob 	s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
2032a9b0695fSjakob 	s[i]->s.k = 2;
2033a9b0695fSjakob 	i++;
2034a9b0695fSjakob 	/* A *= 4 */
2035a9b0695fSjakob 	s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K);
2036a9b0695fSjakob 	s[i]->s.k = 4;
2037a9b0695fSjakob 	i++;
2038a9b0695fSjakob 	/* X = A; */
2039a9b0695fSjakob 	s[i] = new_stmt(BPF_MISC|BPF_TAX);
2040a9b0695fSjakob 	i++;
2041a9b0695fSjakob 	/* A = MEM[reg2] */
2042a9b0695fSjakob 	s[i] = new_stmt(BPF_LD|BPF_MEM);
2043a9b0695fSjakob 	s[i]->s.k = reg2;
2044a9b0695fSjakob 	i++;
2045a9b0695fSjakob 
2046a9b0695fSjakob 	/* goto again; (must use BPF_JA for backward jump) */
2047a9b0695fSjakob 	s[i] = new_stmt(BPF_JMP|BPF_JA);
2048a9b0695fSjakob 	s[i]->s.k = again - i - 1;
2049a9b0695fSjakob 	i++;
2050a9b0695fSjakob 
2051a9b0695fSjakob 	/* end: nop */
2052a9b0695fSjakob 	end = i;
2053a9b0695fSjakob 	s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
2054a9b0695fSjakob 	s[i]->s.k = 0;
2055a9b0695fSjakob 	s[fix2]->s.jt = s[end];
2056a9b0695fSjakob 	s[fix4]->s.jf = s[end];
2057a9b0695fSjakob 	s[fix5]->s.jt = s[end];
2058a9b0695fSjakob 	i++;
2059a9b0695fSjakob 
2060a9b0695fSjakob 	/*
2061a9b0695fSjakob 	 * make slist chain
2062a9b0695fSjakob 	 */
2063a9b0695fSjakob 	max = i;
2064a9b0695fSjakob 	for (i = 0; i < max - 1; i++)
2065a9b0695fSjakob 		s[i]->next = s[i + 1];
2066a9b0695fSjakob 	s[max - 1]->next = NULL;
2067a9b0695fSjakob 
2068a9b0695fSjakob 	/*
2069a9b0695fSjakob 	 * emit final check
2070a9b0695fSjakob 	 */
2071a9b0695fSjakob 	b = new_block(JMP(BPF_JEQ));
2072a9b0695fSjakob 	b->stmts = s[1];	/*remember, s[0] is dummy*/
2073a9b0695fSjakob 	b->s.k = v;
2074a9b0695fSjakob 
2075a9b0695fSjakob 	free_reg(reg1);
2076a9b0695fSjakob 	free_reg(reg2);
2077a9b0695fSjakob 
2078a9b0695fSjakob 	gen_and(b0, b);
2079a9b0695fSjakob 	return b;
2080a9b0695fSjakob }
2081a9b0695fSjakob 
2082a9b0695fSjakob static struct block *
208319fef815Sderaadt gen_proto(int v, int proto, int dir)
2084df930be7Sderaadt {
2085df930be7Sderaadt 	struct block *b0, *b1;
2086df930be7Sderaadt 
2087df930be7Sderaadt 	if (dir != Q_DEFAULT)
2088df930be7Sderaadt 		bpf_error("direction applied to 'proto'");
2089df930be7Sderaadt 
2090df930be7Sderaadt 	switch (proto) {
2091df930be7Sderaadt 	case Q_DEFAULT:
2092a9b0695fSjakob #ifdef INET6
2093a9b0695fSjakob 		b0 = gen_proto(v, Q_IP, dir);
2094a9b0695fSjakob 		b1 = gen_proto(v, Q_IPV6, dir);
2095a9b0695fSjakob 		gen_or(b0, b1);
2096a9b0695fSjakob 		return b1;
2097a9b0695fSjakob #else
2098a9b0695fSjakob 		/*FALLTHROUGH*/
2099a9b0695fSjakob #endif
2100df930be7Sderaadt 	case Q_IP:
2101df930be7Sderaadt 		b0 = gen_linktype(ETHERTYPE_IP);
2102a9b0695fSjakob #ifndef CHASE_CHAIN
21038d8814c2Scanacar 		b1 = gen_cmp_nl(9, BPF_B, (bpf_int32)v);
2104a9b0695fSjakob #else
2105a9b0695fSjakob 		b1 = gen_protochain(v, Q_IP);
2106a9b0695fSjakob #endif
2107df930be7Sderaadt 		gen_and(b0, b1);
2108df930be7Sderaadt 		return b1;
2109df930be7Sderaadt 
2110df930be7Sderaadt 	case Q_ARP:
2111df930be7Sderaadt 		bpf_error("arp does not encapsulate another protocol");
2112df930be7Sderaadt 		/* NOTREACHED */
2113df930be7Sderaadt 
2114df930be7Sderaadt 	case Q_RARP:
2115df930be7Sderaadt 		bpf_error("rarp does not encapsulate another protocol");
2116df930be7Sderaadt 		/* NOTREACHED */
2117df930be7Sderaadt 
211801efc7efSderaadt 	case Q_ATALK:
211901efc7efSderaadt 		bpf_error("atalk encapsulation is not specifiable");
212001efc7efSderaadt 		/* NOTREACHED */
212101efc7efSderaadt 
2122df930be7Sderaadt 	case Q_DECNET:
2123df930be7Sderaadt 		bpf_error("decnet encapsulation is not specifiable");
2124df930be7Sderaadt 		/* NOTREACHED */
2125df930be7Sderaadt 
212601efc7efSderaadt 	case Q_SCA:
212701efc7efSderaadt 		bpf_error("sca does not encapsulate another protocol");
212801efc7efSderaadt 		/* NOTREACHED */
212901efc7efSderaadt 
2130df930be7Sderaadt 	case Q_LAT:
2131df930be7Sderaadt 		bpf_error("lat does not encapsulate another protocol");
2132df930be7Sderaadt 		/* NOTREACHED */
2133df930be7Sderaadt 
2134df930be7Sderaadt 	case Q_MOPRC:
2135df930be7Sderaadt 		bpf_error("moprc does not encapsulate another protocol");
2136df930be7Sderaadt 		/* NOTREACHED */
2137df930be7Sderaadt 
2138df930be7Sderaadt 	case Q_MOPDL:
2139df930be7Sderaadt 		bpf_error("mopdl does not encapsulate another protocol");
2140df930be7Sderaadt 		/* NOTREACHED */
2141df930be7Sderaadt 
2142df930be7Sderaadt 	case Q_LINK:
2143df930be7Sderaadt 		return gen_linktype(v);
2144df930be7Sderaadt 
2145df930be7Sderaadt 	case Q_UDP:
2146df930be7Sderaadt 		bpf_error("'udp proto' is bogus");
2147df930be7Sderaadt 		/* NOTREACHED */
2148df930be7Sderaadt 
2149df930be7Sderaadt 	case Q_TCP:
2150df930be7Sderaadt 		bpf_error("'tcp proto' is bogus");
2151df930be7Sderaadt 		/* NOTREACHED */
2152df930be7Sderaadt 
2153df930be7Sderaadt 	case Q_ICMP:
2154df930be7Sderaadt 		bpf_error("'icmp proto' is bogus");
2155df930be7Sderaadt 		/* NOTREACHED */
2156df930be7Sderaadt 
21579b113833Smickey 	case Q_IGMP:
21589b113833Smickey 		bpf_error("'igmp proto' is bogus");
21599b113833Smickey 		/* NOTREACHED */
21609b113833Smickey 
216101efc7efSderaadt 	case Q_IGRP:
216201efc7efSderaadt 		bpf_error("'igrp proto' is bogus");
216301efc7efSderaadt 		/* NOTREACHED */
216401efc7efSderaadt 
2165a9b0695fSjakob 	case Q_PIM:
2166a9b0695fSjakob 		bpf_error("'pim proto' is bogus");
2167a9b0695fSjakob 		/* NOTREACHED */
2168a9b0695fSjakob 
2169f562933eSmpf 	case Q_STP:
2170f562933eSmpf 		bpf_error("'stp proto' is bogus");
2171f562933eSmpf 		/* NOTREACHED */
2172f562933eSmpf 
2173a9b0695fSjakob #ifdef INET6
2174a9b0695fSjakob 	case Q_IPV6:
2175a9b0695fSjakob 		b0 = gen_linktype(ETHERTYPE_IPV6);
2176a9b0695fSjakob #ifndef CHASE_CHAIN
21778d8814c2Scanacar 		b1 = gen_cmp_nl(6, BPF_B, (bpf_int32)v);
2178a9b0695fSjakob #else
2179a9b0695fSjakob 		b1 = gen_protochain(v, Q_IPV6);
2180a9b0695fSjakob #endif
2181a9b0695fSjakob 		gen_and(b0, b1);
2182a9b0695fSjakob 		return b1;
2183a9b0695fSjakob 
2184a9b0695fSjakob 	case Q_ICMPV6:
2185a9b0695fSjakob 		bpf_error("'icmp6 proto' is bogus");
2186a9b0695fSjakob #endif /* INET6 */
2187a9b0695fSjakob 
2188a9b0695fSjakob 	case Q_AH:
2189a9b0695fSjakob 		bpf_error("'ah proto' is bogus");
2190a9b0695fSjakob 
2191a9b0695fSjakob 	case Q_ESP:
2192ac451769Sdenis 		bpf_error("'esp proto' is bogus");
2193a9b0695fSjakob 
2194df930be7Sderaadt 	default:
2195df930be7Sderaadt 		abort();
2196df930be7Sderaadt 		/* NOTREACHED */
2197df930be7Sderaadt 	}
2198df930be7Sderaadt 	/* NOTREACHED */
2199df930be7Sderaadt }
2200df930be7Sderaadt 
2201df930be7Sderaadt struct block *
220219fef815Sderaadt gen_scode(const char *name, struct qual q)
2203df930be7Sderaadt {
2204df930be7Sderaadt 	int proto = q.proto;
2205df930be7Sderaadt 	int dir = q.dir;
220601efc7efSderaadt 	int tproto;
2207df930be7Sderaadt 	u_char *eaddr;
2208a9b0695fSjakob 	bpf_u_int32 mask, addr;
2209a9b0695fSjakob #ifndef INET6
2210a9b0695fSjakob 	bpf_u_int32 **alist;
2211a9b0695fSjakob #else
2212a9b0695fSjakob 	int tproto6;
2213a9b0695fSjakob 	struct sockaddr_in *sin;
2214a9b0695fSjakob 	struct sockaddr_in6 *sin6;
2215a9b0695fSjakob 	struct addrinfo *res, *res0;
2216a9b0695fSjakob 	struct in6_addr mask128;
2217a9b0695fSjakob #endif /*INET6*/
2218df930be7Sderaadt 	struct block *b, *tmp;
2219df930be7Sderaadt 	int port, real_proto;
2220df930be7Sderaadt 
2221df930be7Sderaadt 	switch (q.addr) {
2222df930be7Sderaadt 
2223df930be7Sderaadt 	case Q_NET:
2224df930be7Sderaadt 		addr = pcap_nametonetaddr(name);
2225df930be7Sderaadt 		if (addr == 0)
2226df930be7Sderaadt 			bpf_error("unknown network '%s'", name);
222701efc7efSderaadt 		/* Left justify network addr and calculate its network mask */
222801efc7efSderaadt 		mask = 0xffffffff;
222901efc7efSderaadt 		while (addr && (addr & 0xff000000) == 0) {
223001efc7efSderaadt 			addr <<= 8;
223101efc7efSderaadt 			mask <<= 8;
223201efc7efSderaadt 		}
2233df930be7Sderaadt 		return gen_host(addr, mask, proto, dir);
2234df930be7Sderaadt 
2235df930be7Sderaadt 	case Q_DEFAULT:
2236df930be7Sderaadt 	case Q_HOST:
2237df930be7Sderaadt 		if (proto == Q_LINK) {
2238df930be7Sderaadt 			switch (linktype) {
22399b113833Smickey 
2240df930be7Sderaadt 			case DLT_EN10MB:
2241df930be7Sderaadt 				eaddr = pcap_ether_hostton(name);
2242df930be7Sderaadt 				if (eaddr == NULL)
22439b113833Smickey 					bpf_error(
22449b113833Smickey 					    "unknown ether host '%s'", name);
2245df930be7Sderaadt 				return gen_ehostop(eaddr, dir);
2246df930be7Sderaadt 
2247df930be7Sderaadt 			case DLT_FDDI:
2248df930be7Sderaadt 				eaddr = pcap_ether_hostton(name);
2249df930be7Sderaadt 				if (eaddr == NULL)
22509b113833Smickey 					bpf_error(
22519b113833Smickey 					    "unknown FDDI host '%s'", name);
2252df930be7Sderaadt 				return gen_fhostop(eaddr, dir);
22539b113833Smickey 
2254d42a50a0Sreyk 			case DLT_IEEE802_11:
2255d42a50a0Sreyk 			case DLT_IEEE802_11_RADIO:
2256d42a50a0Sreyk 				eaddr = pcap_ether_hostton(name);
2257d42a50a0Sreyk 				if (eaddr == NULL)
2258d42a50a0Sreyk 					bpf_error(
2259d42a50a0Sreyk 					    "unknown 802.11 host '%s'", name);
2260d42a50a0Sreyk 
2261d42a50a0Sreyk 				return gen_p80211_hostop(eaddr, dir);
2262d42a50a0Sreyk 
2263df930be7Sderaadt 			default:
22649b113833Smickey 				bpf_error(
22659b113833Smickey 			"only ethernet/FDDI supports link-level host name");
2266df930be7Sderaadt 				break;
2267df930be7Sderaadt 			}
2268df930be7Sderaadt 		} else if (proto == Q_DECNET) {
2269df930be7Sderaadt 			unsigned short dn_addr = __pcap_nametodnaddr(name);
2270df930be7Sderaadt 			/*
2271df930be7Sderaadt 			 * I don't think DECNET hosts can be multihomed, so
2272df930be7Sderaadt 			 * there is no need to build up a list of addresses
2273df930be7Sderaadt 			 */
2274df930be7Sderaadt 			return (gen_host(dn_addr, 0, proto, dir));
2275df930be7Sderaadt 		} else {
2276a9b0695fSjakob #ifndef INET6
2277df930be7Sderaadt 			alist = pcap_nametoaddr(name);
2278df930be7Sderaadt 			if (alist == NULL || *alist == NULL)
2279df930be7Sderaadt 				bpf_error("unknown host '%s'", name);
228001efc7efSderaadt 			tproto = proto;
228101efc7efSderaadt 			if (off_linktype == -1 && tproto == Q_DEFAULT)
228201efc7efSderaadt 				tproto = Q_IP;
228301efc7efSderaadt 			b = gen_host(**alist++, 0xffffffff, tproto, dir);
2284df930be7Sderaadt 			while (*alist) {
228501efc7efSderaadt 				tmp = gen_host(**alist++, 0xffffffff,
228601efc7efSderaadt 					       tproto, dir);
2287df930be7Sderaadt 				gen_or(b, tmp);
2288df930be7Sderaadt 				b = tmp;
2289df930be7Sderaadt 			}
2290df930be7Sderaadt 			return b;
2291a9b0695fSjakob #else
2292a9b0695fSjakob 			memset(&mask128, 0xff, sizeof(mask128));
2293a9b0695fSjakob 			res0 = res = pcap_nametoaddrinfo(name);
2294a9b0695fSjakob 			if (res == NULL)
2295a9b0695fSjakob 				bpf_error("unknown host '%s'", name);
2296a9b0695fSjakob 			b = tmp = NULL;
2297a9b0695fSjakob 			tproto = tproto6 = proto;
2298a9b0695fSjakob 			if (off_linktype == -1 && tproto == Q_DEFAULT) {
2299a9b0695fSjakob 				tproto = Q_IP;
2300a9b0695fSjakob 				tproto6 = Q_IPV6;
2301a9b0695fSjakob 			}
2302a9b0695fSjakob 			for (res = res0; res; res = res->ai_next) {
2303a9b0695fSjakob 				switch (res->ai_family) {
2304a9b0695fSjakob 				case AF_INET:
2305a9b0695fSjakob 					if (tproto == Q_IPV6)
2306a9b0695fSjakob 						continue;
2307a9b0695fSjakob 
2308a9b0695fSjakob 					sin = (struct sockaddr_in *)
2309a9b0695fSjakob 						res->ai_addr;
2310a9b0695fSjakob 					tmp = gen_host(ntohl(sin->sin_addr.s_addr),
2311a9b0695fSjakob 						0xffffffff, tproto, dir);
2312a9b0695fSjakob 					break;
2313a9b0695fSjakob 				case AF_INET6:
2314a9b0695fSjakob 					if (tproto6 == Q_IP)
2315a9b0695fSjakob 						continue;
2316a9b0695fSjakob 
2317a9b0695fSjakob 					sin6 = (struct sockaddr_in6 *)
2318a9b0695fSjakob 						res->ai_addr;
2319a9b0695fSjakob 					tmp = gen_host6(&sin6->sin6_addr,
2320a9b0695fSjakob 						&mask128, tproto6, dir);
2321a9b0695fSjakob 					break;
2322a9b0695fSjakob 				}
2323a9b0695fSjakob 				if (b)
2324a9b0695fSjakob 					gen_or(b, tmp);
2325a9b0695fSjakob 				b = tmp;
2326a9b0695fSjakob 			}
2327a9b0695fSjakob 			freeaddrinfo(res0);
2328a9b0695fSjakob 			if (b == NULL) {
2329a9b0695fSjakob 				bpf_error("unknown host '%s'%s", name,
2330a9b0695fSjakob 				    (proto == Q_DEFAULT)
2331a9b0695fSjakob 					? ""
2332a9b0695fSjakob 					: " for specified address family");
2333a9b0695fSjakob 			}
2334a9b0695fSjakob 			return b;
2335a9b0695fSjakob #endif /*INET6*/
2336df930be7Sderaadt 		}
2337df930be7Sderaadt 
2338df930be7Sderaadt 	case Q_PORT:
2339df930be7Sderaadt 		if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP)
2340df930be7Sderaadt 			bpf_error("illegal qualifier of 'port'");
2341df930be7Sderaadt 		if (pcap_nametoport(name, &port, &real_proto) == 0)
2342df930be7Sderaadt 			bpf_error("unknown port '%s'", name);
2343df930be7Sderaadt 		if (proto == Q_UDP) {
2344df930be7Sderaadt 			if (real_proto == IPPROTO_TCP)
2345df930be7Sderaadt 				bpf_error("port '%s' is tcp", name);
2346df930be7Sderaadt 			else
2347df930be7Sderaadt 				/* override PROTO_UNDEF */
2348df930be7Sderaadt 				real_proto = IPPROTO_UDP;
2349df930be7Sderaadt 		}
2350df930be7Sderaadt 		if (proto == Q_TCP) {
2351df930be7Sderaadt 			if (real_proto == IPPROTO_UDP)
2352df930be7Sderaadt 				bpf_error("port '%s' is udp", name);
2353df930be7Sderaadt 			else
2354df930be7Sderaadt 				/* override PROTO_UNDEF */
2355df930be7Sderaadt 				real_proto = IPPROTO_TCP;
2356df930be7Sderaadt 		}
2357a9b0695fSjakob #ifndef INET6
2358df930be7Sderaadt 		return gen_port(port, real_proto, dir);
2359a9b0695fSjakob #else
2360a9b0695fSjakob 	    {
2361a9b0695fSjakob 		struct block *b;
2362a9b0695fSjakob 		b = gen_port(port, real_proto, dir);
2363a9b0695fSjakob 		gen_or(gen_port6(port, real_proto, dir), b);
2364a9b0695fSjakob 		return b;
2365a9b0695fSjakob 	    }
2366a9b0695fSjakob #endif /* INET6 */
2367df930be7Sderaadt 
2368df930be7Sderaadt 	case Q_GATEWAY:
2369a9b0695fSjakob #ifndef INET6
2370df930be7Sderaadt 		eaddr = pcap_ether_hostton(name);
2371df930be7Sderaadt 		if (eaddr == NULL)
2372df930be7Sderaadt 			bpf_error("unknown ether host: %s", name);
2373df930be7Sderaadt 
2374df930be7Sderaadt 		alist = pcap_nametoaddr(name);
2375df930be7Sderaadt 		if (alist == NULL || *alist == NULL)
2376df930be7Sderaadt 			bpf_error("unknown host '%s'", name);
2377df930be7Sderaadt 		return gen_gateway(eaddr, alist, proto, dir);
2378a9b0695fSjakob #else
2379a9b0695fSjakob 		bpf_error("'gateway' not supported in this configuration");
2380a9b0695fSjakob #endif /*INET6*/
2381df930be7Sderaadt 
2382df930be7Sderaadt 	case Q_PROTO:
2383df930be7Sderaadt 		real_proto = lookup_proto(name, proto);
2384df930be7Sderaadt 		if (real_proto >= 0)
2385df930be7Sderaadt 			return gen_proto(real_proto, proto, dir);
2386df930be7Sderaadt 		else
2387df930be7Sderaadt 			bpf_error("unknown protocol: %s", name);
2388df930be7Sderaadt 
2389a9b0695fSjakob 	case Q_PROTOCHAIN:
2390a9b0695fSjakob 		real_proto = lookup_proto(name, proto);
2391a9b0695fSjakob 		if (real_proto >= 0)
2392a9b0695fSjakob 			return gen_protochain(real_proto, proto, dir);
2393a9b0695fSjakob 		else
2394a9b0695fSjakob 			bpf_error("unknown protocol: %s", name);
2395a9b0695fSjakob 
2396a9b0695fSjakob 
2397df930be7Sderaadt 	case Q_UNDEF:
2398df930be7Sderaadt 		syntax();
2399df930be7Sderaadt 		/* NOTREACHED */
2400df930be7Sderaadt 	}
2401df930be7Sderaadt 	abort();
2402df930be7Sderaadt 	/* NOTREACHED */
2403df930be7Sderaadt }
2404df930be7Sderaadt 
2405df930be7Sderaadt struct block *
240619fef815Sderaadt gen_mcode(const char *s1, const char *s2, int masklen, struct qual q)
240701efc7efSderaadt {
2408d0438536Smmcc 	int nlen, mlen;
240901efc7efSderaadt 	bpf_u_int32 n, m;
241001efc7efSderaadt 
241101efc7efSderaadt 	nlen = __pcap_atoin(s1, &n);
241201efc7efSderaadt 	/* Promote short ipaddr */
241301efc7efSderaadt 	n <<= 32 - nlen;
241401efc7efSderaadt 
241501efc7efSderaadt 	if (s2 != NULL) {
241601efc7efSderaadt 		mlen = __pcap_atoin(s2, &m);
241701efc7efSderaadt 		/* Promote short ipaddr */
241801efc7efSderaadt 		m <<= 32 - mlen;
241901efc7efSderaadt 		if ((n & ~m) != 0)
242001efc7efSderaadt 			bpf_error("non-network bits set in \"%s mask %s\"",
242101efc7efSderaadt 			    s1, s2);
242201efc7efSderaadt 	} else {
242301efc7efSderaadt 		/* Convert mask len to mask */
242401efc7efSderaadt 		if (masklen > 32)
242501efc7efSderaadt 			bpf_error("mask length must be <= 32");
242601efc7efSderaadt 		m = 0xffffffff << (32 - masklen);
242701efc7efSderaadt 		if ((n & ~m) != 0)
242801efc7efSderaadt 			bpf_error("non-network bits set in \"%s/%d\"",
242901efc7efSderaadt 			    s1, masklen);
243001efc7efSderaadt 	}
243101efc7efSderaadt 
243201efc7efSderaadt 	switch (q.addr) {
243301efc7efSderaadt 
243401efc7efSderaadt 	case Q_NET:
243501efc7efSderaadt 		return gen_host(n, m, q.proto, q.dir);
243601efc7efSderaadt 
243701efc7efSderaadt 	default:
243801efc7efSderaadt 		bpf_error("Mask syntax for networks only");
243901efc7efSderaadt 		/* NOTREACHED */
244001efc7efSderaadt 	}
244101efc7efSderaadt }
244201efc7efSderaadt 
244301efc7efSderaadt struct block *
244419fef815Sderaadt gen_ncode(const char *s, bpf_u_int32 v, struct qual q)
2445df930be7Sderaadt {
24469b113833Smickey 	bpf_u_int32 mask;
2447df930be7Sderaadt 	int proto = q.proto;
2448df930be7Sderaadt 	int dir = q.dir;
2449d0438536Smmcc 	int vlen;
245001efc7efSderaadt 
245101efc7efSderaadt 	if (s == NULL)
245201efc7efSderaadt 		vlen = 32;
245301efc7efSderaadt 	else if (q.proto == Q_DECNET)
245401efc7efSderaadt 		vlen = __pcap_atodn(s, &v);
245501efc7efSderaadt 	else
245601efc7efSderaadt 		vlen = __pcap_atoin(s, &v);
2457df930be7Sderaadt 
2458df930be7Sderaadt 	switch (q.addr) {
2459df930be7Sderaadt 
2460df930be7Sderaadt 	case Q_DEFAULT:
2461df930be7Sderaadt 	case Q_HOST:
2462df930be7Sderaadt 	case Q_NET:
2463df930be7Sderaadt 		if (proto == Q_DECNET)
2464df930be7Sderaadt 			return gen_host(v, 0, proto, dir);
2465df930be7Sderaadt 		else if (proto == Q_LINK) {
2466df930be7Sderaadt 			bpf_error("illegal link layer address");
2467df930be7Sderaadt 		} else {
246801efc7efSderaadt 			mask = 0xffffffff;
246901efc7efSderaadt 			if (s == NULL && q.addr == Q_NET) {
247001efc7efSderaadt 				/* Promote short net number */
247101efc7efSderaadt 				while (v && (v & 0xff000000) == 0) {
247201efc7efSderaadt 					v <<= 8;
247301efc7efSderaadt 					mask <<= 8;
247401efc7efSderaadt 				}
247501efc7efSderaadt 			} else {
247601efc7efSderaadt 				/* Promote short ipaddr */
247701efc7efSderaadt 				v <<= 32 - vlen;
247801efc7efSderaadt 				mask <<= 32 - vlen;
247901efc7efSderaadt 			}
2480df930be7Sderaadt 			return gen_host(v, mask, proto, dir);
2481df930be7Sderaadt 		}
2482df930be7Sderaadt 
2483df930be7Sderaadt 	case Q_PORT:
2484df930be7Sderaadt 		if (proto == Q_UDP)
2485df930be7Sderaadt 			proto = IPPROTO_UDP;
2486df930be7Sderaadt 		else if (proto == Q_TCP)
2487df930be7Sderaadt 			proto = IPPROTO_TCP;
2488df930be7Sderaadt 		else if (proto == Q_DEFAULT)
2489df930be7Sderaadt 			proto = PROTO_UNDEF;
2490df930be7Sderaadt 		else
2491df930be7Sderaadt 			bpf_error("illegal qualifier of 'port'");
2492df930be7Sderaadt 
2493a9b0695fSjakob #ifndef INET6
2494df930be7Sderaadt 		return gen_port((int)v, proto, dir);
2495a9b0695fSjakob #else
2496a9b0695fSjakob 	    {
2497a9b0695fSjakob 		struct block *b;
2498a9b0695fSjakob 		b = gen_port((int)v, proto, dir);
2499a9b0695fSjakob 		gen_or(gen_port6((int)v, proto, dir), b);
2500a9b0695fSjakob 		return b;
2501a9b0695fSjakob 	    }
2502a9b0695fSjakob #endif /* INET6 */
2503df930be7Sderaadt 
2504df930be7Sderaadt 	case Q_GATEWAY:
2505df930be7Sderaadt 		bpf_error("'gateway' requires a name");
2506df930be7Sderaadt 		/* NOTREACHED */
2507df930be7Sderaadt 
2508df930be7Sderaadt 	case Q_PROTO:
2509df930be7Sderaadt 		return gen_proto((int)v, proto, dir);
2510df930be7Sderaadt 
2511a9b0695fSjakob 	case Q_PROTOCHAIN:
2512a9b0695fSjakob 		return gen_protochain((int)v, proto, dir);
2513a9b0695fSjakob 
2514df930be7Sderaadt 	case Q_UNDEF:
2515df930be7Sderaadt 		syntax();
2516df930be7Sderaadt 		/* NOTREACHED */
2517df930be7Sderaadt 
2518df930be7Sderaadt 	default:
2519df930be7Sderaadt 		abort();
2520df930be7Sderaadt 		/* NOTREACHED */
2521df930be7Sderaadt 	}
2522df930be7Sderaadt 	/* NOTREACHED */
2523df930be7Sderaadt }
2524df930be7Sderaadt 
2525a9b0695fSjakob #ifdef INET6
2526a9b0695fSjakob struct block *
252719fef815Sderaadt gen_mcode6(const char *s1, const char *s2, int masklen, struct qual q)
2528a9b0695fSjakob {
2529a9b0695fSjakob 	struct addrinfo *res;
2530a9b0695fSjakob 	struct in6_addr *addr;
2531a9b0695fSjakob 	struct in6_addr mask;
2532a9b0695fSjakob 	struct block *b;
2533a9b0695fSjakob 	u_int32_t *a, *m;
2534a9b0695fSjakob 
2535a9b0695fSjakob 	if (s2)
2536a9b0695fSjakob 		bpf_error("no mask %s supported", s2);
2537a9b0695fSjakob 
2538a9b0695fSjakob 	res = pcap_nametoaddrinfo(s1);
2539a9b0695fSjakob 	if (!res)
2540a9b0695fSjakob 		bpf_error("invalid ip6 address %s", s1);
2541a9b0695fSjakob 	if (res->ai_next)
2542a9b0695fSjakob 		bpf_error("%s resolved to multiple address", s1);
2543a9b0695fSjakob 	addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
2544a9b0695fSjakob 
2545a9b0695fSjakob 	if (sizeof(mask) * 8 < masklen)
2546a9b0695fSjakob 		bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8));
25475b39c4fbSbluhm 	memset(&mask, 0, sizeof(mask));
2548a9b0695fSjakob 	memset(&mask, 0xff, masklen / 8);
2549a9b0695fSjakob 	if (masklen % 8) {
2550a9b0695fSjakob 		mask.s6_addr[masklen / 8] =
2551a9b0695fSjakob 			(0xff << (8 - masklen % 8)) & 0xff;
2552a9b0695fSjakob 	}
2553a9b0695fSjakob 
2554a9b0695fSjakob 	a = (u_int32_t *)addr;
2555a9b0695fSjakob 	m = (u_int32_t *)&mask;
2556a9b0695fSjakob 	if ((a[0] & ~m[0]) || (a[1] & ~m[1])
2557a9b0695fSjakob 	 || (a[2] & ~m[2]) || (a[3] & ~m[3])) {
2558a9b0695fSjakob 		bpf_error("non-network bits set in \"%s/%d\"", s1, masklen);
2559a9b0695fSjakob 	}
2560a9b0695fSjakob 
2561a9b0695fSjakob 	switch (q.addr) {
2562a9b0695fSjakob 
2563a9b0695fSjakob 	case Q_DEFAULT:
2564a9b0695fSjakob 	case Q_HOST:
2565a9b0695fSjakob 		if (masklen != 128)
2566a9b0695fSjakob 			bpf_error("Mask syntax for networks only");
2567a9b0695fSjakob 		/* FALLTHROUGH */
2568a9b0695fSjakob 
2569a9b0695fSjakob 	case Q_NET:
2570a9b0695fSjakob 		b = gen_host6(addr, &mask, q.proto, q.dir);
2571a9b0695fSjakob 		freeaddrinfo(res);
2572a9b0695fSjakob 		return b;
2573a9b0695fSjakob 
2574a9b0695fSjakob 	default:
2575a9b0695fSjakob 		bpf_error("invalid qualifier against IPv6 address");
2576a9b0695fSjakob 		/* NOTREACHED */
2577a9b0695fSjakob 	}
2578a9b0695fSjakob }
2579a9b0695fSjakob #endif /*INET6*/
2580a9b0695fSjakob 
2581df930be7Sderaadt struct block *
258219fef815Sderaadt gen_ecode(const u_char *eaddr, struct qual q)
2583df930be7Sderaadt {
2584df930be7Sderaadt 	if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
2585df930be7Sderaadt 		if (linktype == DLT_EN10MB)
2586df930be7Sderaadt 			return gen_ehostop(eaddr, (int)q.dir);
2587df930be7Sderaadt 		if (linktype == DLT_FDDI)
2588df930be7Sderaadt 			return gen_fhostop(eaddr, (int)q.dir);
2589d42a50a0Sreyk 		if (linktype == DLT_IEEE802_11 ||
2590d42a50a0Sreyk 		    linktype == DLT_IEEE802_11_RADIO)
2591d42a50a0Sreyk 			return gen_p80211_hostop(eaddr, (int)q.dir);
2592df930be7Sderaadt 	}
2593df930be7Sderaadt 	bpf_error("ethernet address used in non-ether expression");
2594df930be7Sderaadt 	/* NOTREACHED */
2595df930be7Sderaadt }
2596df930be7Sderaadt 
2597df930be7Sderaadt void
259819fef815Sderaadt sappend(struct slist *s0, struct slist *s1)
2599df930be7Sderaadt {
2600df930be7Sderaadt 	/*
2601df930be7Sderaadt 	 * This is definitely not the best way to do this, but the
2602df930be7Sderaadt 	 * lists will rarely get long.
2603df930be7Sderaadt 	 */
2604df930be7Sderaadt 	while (s0->next)
2605df930be7Sderaadt 		s0 = s0->next;
2606df930be7Sderaadt 	s0->next = s1;
2607df930be7Sderaadt }
2608df930be7Sderaadt 
2609df930be7Sderaadt static struct slist *
261019fef815Sderaadt xfer_to_x(struct arth *a)
2611df930be7Sderaadt {
2612df930be7Sderaadt 	struct slist *s;
2613df930be7Sderaadt 
2614df930be7Sderaadt 	s = new_stmt(BPF_LDX|BPF_MEM);
2615df930be7Sderaadt 	s->s.k = a->regno;
2616df930be7Sderaadt 	return s;
2617df930be7Sderaadt }
2618df930be7Sderaadt 
2619df930be7Sderaadt static struct slist *
262019fef815Sderaadt xfer_to_a(struct arth *a)
2621df930be7Sderaadt {
2622df930be7Sderaadt 	struct slist *s;
2623df930be7Sderaadt 
2624df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_MEM);
2625df930be7Sderaadt 	s->s.k = a->regno;
2626df930be7Sderaadt 	return s;
2627df930be7Sderaadt }
2628df930be7Sderaadt 
2629df930be7Sderaadt struct arth *
263019fef815Sderaadt gen_load(int proto, struct arth *index, int size)
2631df930be7Sderaadt {
2632df930be7Sderaadt 	struct slist *s, *tmp;
2633df930be7Sderaadt 	struct block *b;
2634df930be7Sderaadt 	int regno = alloc_reg();
2635df930be7Sderaadt 
2636df930be7Sderaadt 	free_reg(index->regno);
2637df930be7Sderaadt 	switch (size) {
2638df930be7Sderaadt 
2639df930be7Sderaadt 	default:
2640df930be7Sderaadt 		bpf_error("data size must be 1, 2, or 4");
2641df930be7Sderaadt 
2642df930be7Sderaadt 	case 1:
2643df930be7Sderaadt 		size = BPF_B;
2644df930be7Sderaadt 		break;
2645df930be7Sderaadt 
2646df930be7Sderaadt 	case 2:
2647df930be7Sderaadt 		size = BPF_H;
2648df930be7Sderaadt 		break;
2649df930be7Sderaadt 
2650df930be7Sderaadt 	case 4:
2651df930be7Sderaadt 		size = BPF_W;
2652df930be7Sderaadt 		break;
2653df930be7Sderaadt 	}
2654df930be7Sderaadt 	switch (proto) {
2655df930be7Sderaadt 	default:
2656df930be7Sderaadt 		bpf_error("unsupported index operation");
2657df930be7Sderaadt 
2658df930be7Sderaadt 	case Q_LINK:
2659df930be7Sderaadt 		s = xfer_to_x(index);
2660df930be7Sderaadt 		tmp = new_stmt(BPF_LD|BPF_IND|size);
2661df930be7Sderaadt 		sappend(s, tmp);
2662df930be7Sderaadt 		sappend(index->s, s);
2663df930be7Sderaadt 		break;
2664df930be7Sderaadt 
2665df930be7Sderaadt 	case Q_IP:
2666df930be7Sderaadt 	case Q_ARP:
2667df930be7Sderaadt 	case Q_RARP:
266801efc7efSderaadt 	case Q_ATALK:
2669df930be7Sderaadt 	case Q_DECNET:
267001efc7efSderaadt 	case Q_SCA:
2671df930be7Sderaadt 	case Q_LAT:
2672df930be7Sderaadt 	case Q_MOPRC:
2673df930be7Sderaadt 	case Q_MOPDL:
2674a9b0695fSjakob #ifdef INET6
2675a9b0695fSjakob 	case Q_IPV6:
2676a9b0695fSjakob #endif
2677a9b0695fSjakob 		/* XXX Note that we assume a fixed link header here. */
26788d8814c2Scanacar 		if (variable_nl) {
26798d8814c2Scanacar 			s = nl2X_stmt();
26808d8814c2Scanacar 			sappend(s, xfer_to_a(index));
26818d8814c2Scanacar 			sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
26828d8814c2Scanacar 			sappend(s, new_stmt(BPF_MISC|BPF_TAX));
26838d8814c2Scanacar 		} else {
2684df930be7Sderaadt 			s = xfer_to_x(index);
26858d8814c2Scanacar 		}
2686df930be7Sderaadt 		tmp = new_stmt(BPF_LD|BPF_IND|size);
26878d8814c2Scanacar 		tmp->s.k = off_nl;	/* off_nl == 0 for variable_nl */
2688df930be7Sderaadt 		sappend(s, tmp);
2689df930be7Sderaadt 		sappend(index->s, s);
2690df930be7Sderaadt 
2691df930be7Sderaadt 		b = gen_proto_abbrev(proto);
2692df930be7Sderaadt 		if (index->b)
2693df930be7Sderaadt 			gen_and(index->b, b);
2694df930be7Sderaadt 		index->b = b;
2695df930be7Sderaadt 		break;
2696df930be7Sderaadt 
2697df930be7Sderaadt 	case Q_TCP:
2698df930be7Sderaadt 	case Q_UDP:
2699df930be7Sderaadt 	case Q_ICMP:
27009b113833Smickey 	case Q_IGMP:
270101efc7efSderaadt 	case Q_IGRP:
2702a9b0695fSjakob 	case Q_PIM:
27038d8814c2Scanacar 		s = iphl_to_x();
2704df930be7Sderaadt 		sappend(s, xfer_to_a(index));
2705df930be7Sderaadt 		sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
2706df930be7Sderaadt 		sappend(s, new_stmt(BPF_MISC|BPF_TAX));
2707df930be7Sderaadt 		sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
27088d8814c2Scanacar 		tmp->s.k = off_nl;	/* off_nl is 0 if variable_nl */
2709df930be7Sderaadt 		sappend(index->s, s);
2710df930be7Sderaadt 
2711df930be7Sderaadt 		gen_and(gen_proto_abbrev(proto), b = gen_ipfrag());
2712df930be7Sderaadt 		if (index->b)
2713df930be7Sderaadt 			gen_and(index->b, b);
2714a9b0695fSjakob #ifdef INET6
2715a9b0695fSjakob 		gen_and(gen_proto_abbrev(Q_IP), b);
2716a9b0695fSjakob #endif
2717df930be7Sderaadt 		index->b = b;
2718df930be7Sderaadt 		break;
2719a9b0695fSjakob #ifdef INET6
2720a9b0695fSjakob 	case Q_ICMPV6:
2721a9b0695fSjakob 		bpf_error("IPv6 upper-layer protocol is not supported by proto[x]");
2722a9b0695fSjakob 		/*NOTREACHED*/
2723a9b0695fSjakob #endif
2724df930be7Sderaadt 	}
2725df930be7Sderaadt 	index->regno = regno;
2726df930be7Sderaadt 	s = new_stmt(BPF_ST);
2727df930be7Sderaadt 	s->s.k = regno;
2728df930be7Sderaadt 	sappend(index->s, s);
2729df930be7Sderaadt 
2730df930be7Sderaadt 	return index;
2731df930be7Sderaadt }
2732df930be7Sderaadt 
2733df930be7Sderaadt struct block *
273419fef815Sderaadt gen_relation(int code, struct arth *a0, struct arth *a1, int reversed)
2735df930be7Sderaadt {
2736df930be7Sderaadt 	struct slist *s0, *s1, *s2;
2737df930be7Sderaadt 	struct block *b, *tmp;
2738df930be7Sderaadt 
2739df930be7Sderaadt 	s0 = xfer_to_x(a1);
2740df930be7Sderaadt 	s1 = xfer_to_a(a0);
2741df930be7Sderaadt 	s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X);
2742df930be7Sderaadt 	b = new_block(JMP(code));
27439b113833Smickey 	if (code == BPF_JGT || code == BPF_JGE) {
27449b113833Smickey 		reversed = !reversed;
27459b113833Smickey 		b->s.k = 0x80000000;
27469b113833Smickey 	}
2747df930be7Sderaadt 	if (reversed)
2748df930be7Sderaadt 		gen_not(b);
2749df930be7Sderaadt 
2750df930be7Sderaadt 	sappend(s1, s2);
2751df930be7Sderaadt 	sappend(s0, s1);
2752df930be7Sderaadt 	sappend(a1->s, s0);
2753df930be7Sderaadt 	sappend(a0->s, a1->s);
2754df930be7Sderaadt 
2755df930be7Sderaadt 	b->stmts = a0->s;
2756df930be7Sderaadt 
2757df930be7Sderaadt 	free_reg(a0->regno);
2758df930be7Sderaadt 	free_reg(a1->regno);
2759df930be7Sderaadt 
2760df930be7Sderaadt 	/* 'and' together protocol checks */
2761df930be7Sderaadt 	if (a0->b) {
2762df930be7Sderaadt 		if (a1->b) {
2763df930be7Sderaadt 			gen_and(a0->b, tmp = a1->b);
2764df930be7Sderaadt 		}
2765df930be7Sderaadt 		else
2766df930be7Sderaadt 			tmp = a0->b;
2767df930be7Sderaadt 	} else
2768df930be7Sderaadt 		tmp = a1->b;
2769df930be7Sderaadt 
2770df930be7Sderaadt 	if (tmp)
2771df930be7Sderaadt 		gen_and(tmp, b);
2772df930be7Sderaadt 
2773df930be7Sderaadt 	return b;
2774df930be7Sderaadt }
2775df930be7Sderaadt 
2776df930be7Sderaadt struct arth *
2777146262eaSjsg gen_loadlen(void)
2778df930be7Sderaadt {
2779df930be7Sderaadt 	int regno = alloc_reg();
2780df930be7Sderaadt 	struct arth *a = (struct arth *)newchunk(sizeof(*a));
2781df930be7Sderaadt 	struct slist *s;
2782df930be7Sderaadt 
2783df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_LEN);
2784df930be7Sderaadt 	s->next = new_stmt(BPF_ST);
2785df930be7Sderaadt 	s->next->s.k = regno;
2786df930be7Sderaadt 	a->s = s;
2787df930be7Sderaadt 	a->regno = regno;
2788df930be7Sderaadt 
2789df930be7Sderaadt 	return a;
2790df930be7Sderaadt }
2791df930be7Sderaadt 
2792df930be7Sderaadt struct arth *
2793146262eaSjsg gen_loadrnd(void)
2794a8e9f808Sdlg {
2795a8e9f808Sdlg 	int regno = alloc_reg();
2796a8e9f808Sdlg 	struct arth *a = (struct arth *)newchunk(sizeof(*a));
2797a8e9f808Sdlg 	struct slist *s;
2798a8e9f808Sdlg 
2799a8e9f808Sdlg 	s = new_stmt(BPF_LD|BPF_RND);
2800a8e9f808Sdlg 	s->next = new_stmt(BPF_ST);
2801a8e9f808Sdlg 	s->next->s.k = regno;
2802a8e9f808Sdlg 	a->s = s;
2803a8e9f808Sdlg 	a->regno = regno;
2804a8e9f808Sdlg 
2805a8e9f808Sdlg 	return a;
2806a8e9f808Sdlg }
2807a8e9f808Sdlg 
2808a8e9f808Sdlg struct arth *
280919fef815Sderaadt gen_loadi(int val)
2810df930be7Sderaadt {
2811df930be7Sderaadt 	struct arth *a;
2812df930be7Sderaadt 	struct slist *s;
2813df930be7Sderaadt 	int reg;
2814df930be7Sderaadt 
2815df930be7Sderaadt 	a = (struct arth *)newchunk(sizeof(*a));
2816df930be7Sderaadt 
2817df930be7Sderaadt 	reg = alloc_reg();
2818df930be7Sderaadt 
2819df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_IMM);
2820df930be7Sderaadt 	s->s.k = val;
2821df930be7Sderaadt 	s->next = new_stmt(BPF_ST);
2822df930be7Sderaadt 	s->next->s.k = reg;
2823df930be7Sderaadt 	a->s = s;
2824df930be7Sderaadt 	a->regno = reg;
2825df930be7Sderaadt 
2826df930be7Sderaadt 	return a;
2827df930be7Sderaadt }
2828df930be7Sderaadt 
2829df930be7Sderaadt struct arth *
283019fef815Sderaadt gen_neg(struct arth *a)
2831df930be7Sderaadt {
2832df930be7Sderaadt 	struct slist *s;
2833df930be7Sderaadt 
2834df930be7Sderaadt 	s = xfer_to_a(a);
2835df930be7Sderaadt 	sappend(a->s, s);
2836df930be7Sderaadt 	s = new_stmt(BPF_ALU|BPF_NEG);
2837df930be7Sderaadt 	s->s.k = 0;
2838df930be7Sderaadt 	sappend(a->s, s);
2839df930be7Sderaadt 	s = new_stmt(BPF_ST);
2840df930be7Sderaadt 	s->s.k = a->regno;
2841df930be7Sderaadt 	sappend(a->s, s);
2842df930be7Sderaadt 
2843df930be7Sderaadt 	return a;
2844df930be7Sderaadt }
2845df930be7Sderaadt 
2846df930be7Sderaadt struct arth *
284719fef815Sderaadt gen_arth(int code, struct arth *a0, struct arth *a1)
2848df930be7Sderaadt {
2849df930be7Sderaadt 	struct slist *s0, *s1, *s2;
2850df930be7Sderaadt 
2851df930be7Sderaadt 	s0 = xfer_to_x(a1);
2852df930be7Sderaadt 	s1 = xfer_to_a(a0);
2853df930be7Sderaadt 	s2 = new_stmt(BPF_ALU|BPF_X|code);
2854df930be7Sderaadt 
2855df930be7Sderaadt 	sappend(s1, s2);
2856df930be7Sderaadt 	sappend(s0, s1);
2857df930be7Sderaadt 	sappend(a1->s, s0);
2858df930be7Sderaadt 	sappend(a0->s, a1->s);
2859df930be7Sderaadt 
2860df930be7Sderaadt 	free_reg(a1->regno);
2861df930be7Sderaadt 
2862df930be7Sderaadt 	s0 = new_stmt(BPF_ST);
2863df930be7Sderaadt 	a0->regno = s0->s.k = alloc_reg();
2864df930be7Sderaadt 	sappend(a0->s, s0);
2865df930be7Sderaadt 
2866df930be7Sderaadt 	return a0;
2867df930be7Sderaadt }
2868df930be7Sderaadt 
2869df930be7Sderaadt /*
2870df930be7Sderaadt  * Here we handle simple allocation of the scratch registers.
2871df930be7Sderaadt  * If too many registers are alloc'd, the allocator punts.
2872df930be7Sderaadt  */
2873df930be7Sderaadt static int regused[BPF_MEMWORDS];
2874df930be7Sderaadt static int curreg;
2875df930be7Sderaadt 
2876df930be7Sderaadt /*
2877df930be7Sderaadt  * Return the next free register.
2878df930be7Sderaadt  */
2879df930be7Sderaadt static int
2880146262eaSjsg alloc_reg(void)
2881df930be7Sderaadt {
2882df930be7Sderaadt 	int n = BPF_MEMWORDS;
2883df930be7Sderaadt 
2884df930be7Sderaadt 	while (--n >= 0) {
2885df930be7Sderaadt 		if (regused[curreg])
2886df930be7Sderaadt 			curreg = (curreg + 1) % BPF_MEMWORDS;
2887df930be7Sderaadt 		else {
2888df930be7Sderaadt 			regused[curreg] = 1;
2889df930be7Sderaadt 			return curreg;
2890df930be7Sderaadt 		}
2891df930be7Sderaadt 	}
2892df930be7Sderaadt 	bpf_error("too many registers needed to evaluate expression");
2893df930be7Sderaadt 	/* NOTREACHED */
2894df930be7Sderaadt }
2895df930be7Sderaadt 
2896df930be7Sderaadt /*
2897df930be7Sderaadt  * Return a register to the table so it can
2898df930be7Sderaadt  * be used later.
2899df930be7Sderaadt  */
2900df930be7Sderaadt static void
290119fef815Sderaadt free_reg(int n)
2902df930be7Sderaadt {
2903df930be7Sderaadt 	regused[n] = 0;
2904df930be7Sderaadt }
2905df930be7Sderaadt 
2906df930be7Sderaadt static struct block *
290719fef815Sderaadt gen_len(int jmp, int n)
2908df930be7Sderaadt {
2909df930be7Sderaadt 	struct slist *s;
2910df930be7Sderaadt 	struct block *b;
2911df930be7Sderaadt 
2912df930be7Sderaadt 	s = new_stmt(BPF_LD|BPF_LEN);
2913df930be7Sderaadt 	b = new_block(JMP(jmp));
2914df930be7Sderaadt 	b->stmts = s;
29159b113833Smickey 	b->s.k = n;
2916df930be7Sderaadt 
2917df930be7Sderaadt 	return b;
2918df930be7Sderaadt }
2919df930be7Sderaadt 
2920df930be7Sderaadt struct block *
292119fef815Sderaadt gen_greater(int n)
2922df930be7Sderaadt {
2923df930be7Sderaadt 	return gen_len(BPF_JGE, n);
2924df930be7Sderaadt }
2925df930be7Sderaadt 
2926df930be7Sderaadt struct block *
292719fef815Sderaadt gen_less(int n)
2928df930be7Sderaadt {
2929df930be7Sderaadt 	struct block *b;
2930df930be7Sderaadt 
2931df930be7Sderaadt 	b = gen_len(BPF_JGT, n);
2932df930be7Sderaadt 	gen_not(b);
2933df930be7Sderaadt 
2934df930be7Sderaadt 	return b;
2935df930be7Sderaadt }
2936df930be7Sderaadt 
2937df930be7Sderaadt struct block *
293819fef815Sderaadt gen_byteop(int op, int idx, int val)
2939df930be7Sderaadt {
2940df930be7Sderaadt 	struct block *b;
2941df930be7Sderaadt 	struct slist *s;
2942df930be7Sderaadt 
2943df930be7Sderaadt 	switch (op) {
2944df930be7Sderaadt 	default:
2945df930be7Sderaadt 		abort();
2946df930be7Sderaadt 
2947df930be7Sderaadt 	case '=':
29489b113833Smickey 		return gen_cmp((u_int)idx, BPF_B, (bpf_int32)val);
2949df930be7Sderaadt 
2950df930be7Sderaadt 	case '<':
29519b113833Smickey 		b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val);
2952df930be7Sderaadt 		b->s.code = JMP(BPF_JGE);
2953df930be7Sderaadt 		gen_not(b);
2954df930be7Sderaadt 		return b;
2955df930be7Sderaadt 
2956df930be7Sderaadt 	case '>':
29579b113833Smickey 		b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val);
2958df930be7Sderaadt 		b->s.code = JMP(BPF_JGT);
2959df930be7Sderaadt 		return b;
2960df930be7Sderaadt 
2961df930be7Sderaadt 	case '|':
2962df930be7Sderaadt 		s = new_stmt(BPF_ALU|BPF_OR|BPF_K);
2963df930be7Sderaadt 		break;
2964df930be7Sderaadt 
2965df930be7Sderaadt 	case '&':
2966df930be7Sderaadt 		s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
2967df930be7Sderaadt 		break;
2968df930be7Sderaadt 	}
2969df930be7Sderaadt 	s->s.k = val;
2970df930be7Sderaadt 	b = new_block(JMP(BPF_JEQ));
2971df930be7Sderaadt 	b->stmts = s;
2972df930be7Sderaadt 	gen_not(b);
2973df930be7Sderaadt 
2974df930be7Sderaadt 	return b;
2975df930be7Sderaadt }
2976df930be7Sderaadt 
2977df930be7Sderaadt struct block *
297819fef815Sderaadt gen_broadcast(int proto)
2979df930be7Sderaadt {
29809b113833Smickey 	bpf_u_int32 hostmask;
2981df930be7Sderaadt 	struct block *b0, *b1, *b2;
2982df930be7Sderaadt 	static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2983df930be7Sderaadt 
2984df930be7Sderaadt 	switch (proto) {
2985df930be7Sderaadt 
2986df930be7Sderaadt 	case Q_DEFAULT:
2987df930be7Sderaadt 	case Q_LINK:
2988df930be7Sderaadt 		if (linktype == DLT_EN10MB)
2989df930be7Sderaadt 			return gen_ehostop(ebroadcast, Q_DST);
2990df930be7Sderaadt 		if (linktype == DLT_FDDI)
2991df930be7Sderaadt 			return gen_fhostop(ebroadcast, Q_DST);
2992d42a50a0Sreyk 		if (linktype == DLT_IEEE802_11 ||
2993d42a50a0Sreyk 		    linktype == DLT_IEEE802_11_RADIO)
2994d42a50a0Sreyk 			return gen_p80211_hostop(ebroadcast, Q_DST);
2995df930be7Sderaadt 		bpf_error("not a broadcast link");
2996df930be7Sderaadt 		break;
2997df930be7Sderaadt 
2998df930be7Sderaadt 	case Q_IP:
2999ff78d6edSsthen 		/*
3000ff78d6edSsthen 		 * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff)
3001ff78d6edSsthen 		 * as an indication that we don't know the netmask, and fail
3002ff78d6edSsthen 		 * in that case.
3003ff78d6edSsthen 		 */
3004ff78d6edSsthen 		if (netmask == PCAP_NETMASK_UNKNOWN)
3005ff78d6edSsthen 			bpf_error("netmask not known, so 'ip broadcast' not supported");
3006df930be7Sderaadt 		b0 = gen_linktype(ETHERTYPE_IP);
3007df930be7Sderaadt 		hostmask = ~netmask;
30088d8814c2Scanacar 		b1 = gen_mcmp_nl(16, BPF_W, (bpf_int32)0, hostmask);
30098d8814c2Scanacar 		b2 = gen_mcmp_nl(16, BPF_W,
30109b113833Smickey 			      (bpf_int32)(~0 & hostmask), hostmask);
3011df930be7Sderaadt 		gen_or(b1, b2);
3012df930be7Sderaadt 		gen_and(b0, b2);
3013df930be7Sderaadt 		return b2;
3014df930be7Sderaadt 	}
3015df930be7Sderaadt 	bpf_error("only ether/ip broadcast filters supported");
3016df930be7Sderaadt }
3017df930be7Sderaadt 
3018df930be7Sderaadt struct block *
301919fef815Sderaadt gen_multicast(int proto)
3020df930be7Sderaadt {
3021d0438536Smmcc 	struct block *b0, *b1;
3022d0438536Smmcc 	struct slist *s;
3023df930be7Sderaadt 
3024df930be7Sderaadt 	switch (proto) {
3025df930be7Sderaadt 
3026df930be7Sderaadt 	case Q_DEFAULT:
3027df930be7Sderaadt 	case Q_LINK:
3028df930be7Sderaadt 		if (linktype == DLT_EN10MB) {
3029df930be7Sderaadt 			/* ether[0] & 1 != 0 */
3030df930be7Sderaadt 			s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
3031df930be7Sderaadt 			s->s.k = 0;
3032df930be7Sderaadt 			b0 = new_block(JMP(BPF_JSET));
3033df930be7Sderaadt 			b0->s.k = 1;
3034df930be7Sderaadt 			b0->stmts = s;
3035df930be7Sderaadt 			return b0;
3036df930be7Sderaadt 		}
3037df930be7Sderaadt 
3038df930be7Sderaadt 		if (linktype == DLT_FDDI) {
3039df930be7Sderaadt 			/* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX */
3040df930be7Sderaadt 			/* fddi[1] & 1 != 0 */
3041df930be7Sderaadt 			s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
3042df930be7Sderaadt 			s->s.k = 1;
3043df930be7Sderaadt 			b0 = new_block(JMP(BPF_JSET));
3044df930be7Sderaadt 			b0->s.k = 1;
3045df930be7Sderaadt 			b0->stmts = s;
3046df930be7Sderaadt 			return b0;
3047df930be7Sderaadt 		}
3048df930be7Sderaadt 		/* Link not known to support multicasts */
3049df930be7Sderaadt 		break;
3050df930be7Sderaadt 
3051df930be7Sderaadt 	case Q_IP:
3052df930be7Sderaadt 		b0 = gen_linktype(ETHERTYPE_IP);
30538d8814c2Scanacar 		b1 = gen_cmp_nl(16, BPF_B, (bpf_int32)224);
3054df930be7Sderaadt 		b1->s.code = JMP(BPF_JGE);
3055df930be7Sderaadt 		gen_and(b0, b1);
3056df930be7Sderaadt 		return b1;
3057a9b0695fSjakob 
3058a9b0695fSjakob #ifdef INET6
3059a9b0695fSjakob 	case Q_IPV6:
3060a9b0695fSjakob 		b0 = gen_linktype(ETHERTYPE_IPV6);
30618d8814c2Scanacar 		b1 = gen_cmp_nl(24, BPF_B, (bpf_int32)255);
3062a9b0695fSjakob 		gen_and(b0, b1);
3063a9b0695fSjakob 		return b1;
3064a9b0695fSjakob #endif /* INET6 */
3065df930be7Sderaadt 	}
3066df930be7Sderaadt 	bpf_error("only IP multicast filters supported on ethernet/FDDI");
3067df930be7Sderaadt }
3068df930be7Sderaadt 
3069df930be7Sderaadt /*
3070df930be7Sderaadt  * generate command for inbound/outbound.  It's here so we can
3071df930be7Sderaadt  * make it link-type specific.  'dir' = 0 implies "inbound",
3072df930be7Sderaadt  * = 1 implies "outbound".
3073df930be7Sderaadt  */
3074df930be7Sderaadt struct block *
307519fef815Sderaadt gen_inbound(int dir)
3076df930be7Sderaadt {
3077d0438536Smmcc 	struct block *b0;
3078df930be7Sderaadt 
3079a9b0695fSjakob 	/*
3080a9b0695fSjakob 	 * Only SLIP and old-style PPP data link types support
3081a9b0695fSjakob 	 * inbound/outbound qualifiers.
3082a9b0695fSjakob 	 */
3083a9b0695fSjakob 	switch (linktype) {
3084a9b0695fSjakob 	case DLT_SLIP:
3085a9b0695fSjakob 	case DLT_PPP:
3086e83aed87Sfrantzen 		b0 = gen_relation(BPF_JEQ,
3087e83aed87Sfrantzen 				  gen_load(Q_LINK, gen_loadi(0), 1),
3088e83aed87Sfrantzen 				  gen_loadi(0),
3089e83aed87Sfrantzen 				  dir);
3090e83aed87Sfrantzen 		break;
3091e83aed87Sfrantzen 
3092e83aed87Sfrantzen 	case DLT_PFLOG:
3093263bcd0cScanacar 		b0 = gen_cmp(offsetof(struct pfloghdr, dir), BPF_B,
3094263bcd0cScanacar 		    (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
3095263bcd0cScanacar 		break;
3096263bcd0cScanacar 
3097a9b0695fSjakob 	default:
3098abbdc6b6Sreyk 		bpf_error("inbound/outbound not supported on linktype 0x%x",
3099a9b0695fSjakob 		    linktype);
3100a9b0695fSjakob 		/* NOTREACHED */
3101a9b0695fSjakob 	}
3102a9b0695fSjakob 
3103e83aed87Sfrantzen 	return (b0);
3104e83aed87Sfrantzen }
3105e83aed87Sfrantzen 
3106e83aed87Sfrantzen 
3107e83aed87Sfrantzen /* PF firewall log matched interface */
3108e83aed87Sfrantzen struct block *
3109e83aed87Sfrantzen gen_pf_ifname(char *ifname)
3110e83aed87Sfrantzen {
3111e83aed87Sfrantzen 	struct block *b0;
3112263bcd0cScanacar 	u_int len, off;
3113e83aed87Sfrantzen 
3114263bcd0cScanacar 	if (linktype == DLT_PFLOG) {
3115263bcd0cScanacar 		len = sizeof(((struct pfloghdr *)0)->ifname);
3116263bcd0cScanacar 		off = offsetof(struct pfloghdr, ifname);
3117263bcd0cScanacar 	} else {
3118abbdc6b6Sreyk 		bpf_error("ifname not supported on linktype 0x%x", linktype);
3119e83aed87Sfrantzen 		/* NOTREACHED */
3120e83aed87Sfrantzen 	}
3121263bcd0cScanacar 	if (strlen(ifname) >= len) {
3122abbdc6b6Sreyk 		bpf_error("ifname interface names can only be %d characters",
3123263bcd0cScanacar 		    len - 1);
3124e83aed87Sfrantzen 		/* NOTREACHED */
3125e83aed87Sfrantzen 	}
3126daa036abSdlg 	b0 = gen_bcmp(off, strlen(ifname) + 1, ifname);
3127263bcd0cScanacar 	return (b0);
3128263bcd0cScanacar }
3129263bcd0cScanacar 
3130263bcd0cScanacar 
313163c47f2fSjoel /* PF firewall log ruleset name */
3132263bcd0cScanacar struct block *
3133263bcd0cScanacar gen_pf_ruleset(char *ruleset)
3134263bcd0cScanacar {
3135263bcd0cScanacar 	struct block *b0;
3136263bcd0cScanacar 
3137263bcd0cScanacar 	if (linktype != DLT_PFLOG) {
3138abbdc6b6Sreyk 		bpf_error("ruleset not supported on linktype 0x%x", linktype);
3139263bcd0cScanacar 		/* NOTREACHED */
3140263bcd0cScanacar 	}
3141263bcd0cScanacar 	if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) {
31421717b5a3Schl 		bpf_error("ruleset names can only be %zu characters",
3143263bcd0cScanacar 		    sizeof(((struct pfloghdr *)0)->ruleset) - 1);
3144263bcd0cScanacar 		/* NOTREACHED */
3145263bcd0cScanacar 	}
3146263bcd0cScanacar 	b0 = gen_bcmp(offsetof(struct pfloghdr, ruleset),
3147263bcd0cScanacar 	    strlen(ruleset), ruleset);
3148e83aed87Sfrantzen 	return (b0);
3149e83aed87Sfrantzen }
3150e83aed87Sfrantzen 
3151e83aed87Sfrantzen 
3152e83aed87Sfrantzen /* PF firewall log rule number */
3153e83aed87Sfrantzen struct block *
3154e83aed87Sfrantzen gen_pf_rnr(int rnr)
3155e83aed87Sfrantzen {
3156e83aed87Sfrantzen 	struct block *b0;
3157e83aed87Sfrantzen 
3158263bcd0cScanacar 	if (linktype == DLT_PFLOG) {
3159263bcd0cScanacar 		b0 = gen_cmp(offsetof(struct pfloghdr, rulenr), BPF_W,
3160263bcd0cScanacar 			 (bpf_int32)rnr);
3161263bcd0cScanacar 	} else {
3162abbdc6b6Sreyk 		bpf_error("rnr not supported on linktype 0x%x", linktype);
3163e83aed87Sfrantzen 		/* NOTREACHED */
3164e83aed87Sfrantzen 	}
3165e83aed87Sfrantzen 
3166263bcd0cScanacar 	return (b0);
3167263bcd0cScanacar }
3168263bcd0cScanacar 
3169263bcd0cScanacar 
3170263bcd0cScanacar /* PF firewall log sub-rule number */
3171263bcd0cScanacar struct block *
3172263bcd0cScanacar gen_pf_srnr(int srnr)
3173263bcd0cScanacar {
3174263bcd0cScanacar 	struct block *b0;
3175263bcd0cScanacar 
3176263bcd0cScanacar 	if (linktype != DLT_PFLOG) {
3177abbdc6b6Sreyk 		bpf_error("srnr not supported on linktype 0x%x", linktype);
3178263bcd0cScanacar 		/* NOTREACHED */
3179263bcd0cScanacar 	}
3180263bcd0cScanacar 
3181263bcd0cScanacar 	b0 = gen_cmp(offsetof(struct pfloghdr, subrulenr), BPF_W,
3182263bcd0cScanacar 	    (bpf_int32)srnr);
3183e83aed87Sfrantzen 	return (b0);
3184e83aed87Sfrantzen }
3185e83aed87Sfrantzen 
3186e83aed87Sfrantzen /* PF firewall log reason code */
3187e83aed87Sfrantzen struct block *
3188e83aed87Sfrantzen gen_pf_reason(int reason)
3189e83aed87Sfrantzen {
3190e83aed87Sfrantzen 	struct block *b0;
3191e83aed87Sfrantzen 
3192263bcd0cScanacar 	if (linktype == DLT_PFLOG) {
3193263bcd0cScanacar 		b0 = gen_cmp(offsetof(struct pfloghdr, reason), BPF_B,
3194263bcd0cScanacar 		    (bpf_int32)reason);
3195263bcd0cScanacar 	} else {
3196abbdc6b6Sreyk 		bpf_error("reason not supported on linktype 0x%x", linktype);
3197e83aed87Sfrantzen 		/* NOTREACHED */
3198e83aed87Sfrantzen 	}
3199e83aed87Sfrantzen 
3200e83aed87Sfrantzen 	return (b0);
3201e83aed87Sfrantzen }
3202e83aed87Sfrantzen 
3203e83aed87Sfrantzen /* PF firewall log action */
3204e83aed87Sfrantzen struct block *
3205e83aed87Sfrantzen gen_pf_action(int action)
3206e83aed87Sfrantzen {
3207e83aed87Sfrantzen 	struct block *b0;
3208e83aed87Sfrantzen 
3209263bcd0cScanacar 	if (linktype == DLT_PFLOG) {
3210263bcd0cScanacar 		b0 = gen_cmp(offsetof(struct pfloghdr, action), BPF_B,
3211263bcd0cScanacar 		    (bpf_int32)action);
3212263bcd0cScanacar 	} else {
3213abbdc6b6Sreyk 		bpf_error("action not supported on linktype 0x%x", linktype);
3214e83aed87Sfrantzen 		/* NOTREACHED */
3215e83aed87Sfrantzen 	}
3216e83aed87Sfrantzen 
3217df930be7Sderaadt 	return (b0);
3218df930be7Sderaadt }
3219d42a50a0Sreyk 
3220d42a50a0Sreyk /* IEEE 802.11 wireless header */
3221d42a50a0Sreyk struct block *
3222d42a50a0Sreyk gen_p80211_type(int type, int mask)
3223d42a50a0Sreyk {
3224d42a50a0Sreyk 	struct block *b0;
3225d42a50a0Sreyk 	u_int offset;
3226d42a50a0Sreyk 
3227d42a50a0Sreyk 	if (!(linktype == DLT_IEEE802_11 ||
3228d42a50a0Sreyk 	    linktype == DLT_IEEE802_11_RADIO)) {
3229d42a50a0Sreyk 		bpf_error("type not supported on linktype 0x%x",
3230d42a50a0Sreyk 		    linktype);
3231d42a50a0Sreyk 		/* NOTREACHED */
3232d42a50a0Sreyk 	}
3233d42a50a0Sreyk 	offset = (u_int)offsetof(struct ieee80211_frame, i_fc[0]);
3234d42a50a0Sreyk 	if (linktype == DLT_IEEE802_11_RADIO)
3235d42a50a0Sreyk 		offset += IEEE80211_RADIOTAP_HDRLEN;
3236d42a50a0Sreyk 
3237d42a50a0Sreyk 	b0 = gen_mcmp(offset, BPF_B, (bpf_int32)type, (bpf_u_int32)mask);
3238d42a50a0Sreyk 
3239d42a50a0Sreyk 	return (b0);
3240d42a50a0Sreyk }
3241d42a50a0Sreyk 
3242febc6dcdSdtucker static struct block *
324319fef815Sderaadt gen_ahostop(const u_char *eaddr, int dir)
3244febc6dcdSdtucker {
3245d0438536Smmcc 	struct block *b0, *b1;
3246febc6dcdSdtucker 
3247febc6dcdSdtucker 	switch (dir) {
3248febc6dcdSdtucker 	/* src comes first, different from Ethernet */
3249febc6dcdSdtucker 	case Q_SRC:
3250febc6dcdSdtucker 		return gen_bcmp(0, 1, eaddr);
3251febc6dcdSdtucker 
3252febc6dcdSdtucker 	case Q_DST:
3253febc6dcdSdtucker 		return gen_bcmp(1, 1, eaddr);
3254febc6dcdSdtucker 
3255febc6dcdSdtucker 	case Q_AND:
3256febc6dcdSdtucker 		b0 = gen_ahostop(eaddr, Q_SRC);
3257febc6dcdSdtucker 		b1 = gen_ahostop(eaddr, Q_DST);
3258febc6dcdSdtucker 		gen_and(b0, b1);
3259febc6dcdSdtucker 		return b1;
3260febc6dcdSdtucker 
3261febc6dcdSdtucker 	case Q_DEFAULT:
3262febc6dcdSdtucker 	case Q_OR:
3263febc6dcdSdtucker 		b0 = gen_ahostop(eaddr, Q_SRC);
3264febc6dcdSdtucker 		b1 = gen_ahostop(eaddr, Q_DST);
3265febc6dcdSdtucker 		gen_or(b0, b1);
3266febc6dcdSdtucker 		return b1;
3267febc6dcdSdtucker 	}
3268febc6dcdSdtucker 	abort();
3269febc6dcdSdtucker 	/* NOTREACHED */
3270febc6dcdSdtucker }
3271febc6dcdSdtucker 
32726b5a0ec1Sderaadt struct block *
327319fef815Sderaadt gen_acode(const u_char *eaddr, struct qual q)
32746b5a0ec1Sderaadt {
32756b5a0ec1Sderaadt 	if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
32766b5a0ec1Sderaadt 		if (linktype == DLT_ARCNET)
32776b5a0ec1Sderaadt 			return gen_ahostop(eaddr, (int)q.dir);
32786b5a0ec1Sderaadt 	}
32796b5a0ec1Sderaadt 	bpf_error("ARCnet address used in non-arc expression");
32806b5a0ec1Sderaadt 	/* NOTREACHED */
32816b5a0ec1Sderaadt }
32826b5a0ec1Sderaadt 
3283ff52dd4aSdenis struct block *
328419fef815Sderaadt gen_mpls(int label)
3285ff52dd4aSdenis {
3286ff52dd4aSdenis 	struct block	*b0;
3287ff52dd4aSdenis 
3288ff52dd4aSdenis 	if (label > MPLS_LABEL_MAX)
3289ff52dd4aSdenis 		bpf_error("invalid MPLS label : %d", label);
3290ff52dd4aSdenis 
3291ff52dd4aSdenis 	if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
3292ff52dd4aSdenis 		b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
3293ff52dd4aSdenis 	else
3294ff52dd4aSdenis 		b0 = gen_linktype(ETHERTYPE_MPLS);
3295ff52dd4aSdenis 
3296ff52dd4aSdenis 	if (label >= 0) {
3297ff52dd4aSdenis 		struct block *b1;
3298ff52dd4aSdenis 
3299ff52dd4aSdenis 		b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
3300ff52dd4aSdenis 		    MPLS_LABEL_MASK);
3301ff52dd4aSdenis 		gen_and(b0, b1);
3302ff52dd4aSdenis 		b0 = b1;
3303ff52dd4aSdenis 	}
3304ff52dd4aSdenis 	off_nl += 4;
3305ff52dd4aSdenis 	off_linktype += 4;
3306ff52dd4aSdenis 	mpls_stack++;
3307ff52dd4aSdenis 	return (b0);
3308ff52dd4aSdenis }
3309ff52dd4aSdenis 
3310febc6dcdSdtucker /*
3311febc6dcdSdtucker  * support IEEE 802.1Q VLAN trunk over ethernet
3312febc6dcdSdtucker  */
3313febc6dcdSdtucker struct block *
331419fef815Sderaadt gen_vlan(int vlan_num)
3315febc6dcdSdtucker {
3316febc6dcdSdtucker 	struct	block	*b0;
3317febc6dcdSdtucker 
33188d8814c2Scanacar 	if (variable_nl) {
33198d8814c2Scanacar 		bpf_error("'vlan' not supported for variable DLTs");
33208d8814c2Scanacar 		/*NOTREACHED*/
33218d8814c2Scanacar 	}
33228d8814c2Scanacar 
33234f6bb374Sdenis 	if (vlan_num > 4095) {
33244f6bb374Sdenis 		bpf_error("invalid VLAN number : %d", vlan_num);
33254f6bb374Sdenis 		/*NOTREACHED*/
33264f6bb374Sdenis 	}
33274f6bb374Sdenis 
3328febc6dcdSdtucker 	/*
3329febc6dcdSdtucker 	 * Change the offsets to point to the type and data fields within
3330febc6dcdSdtucker 	 * the VLAN packet.  This is somewhat of a kludge.
3331febc6dcdSdtucker 	 */
3332febc6dcdSdtucker 	if (orig_nl == (u_int)-1) {
3333febc6dcdSdtucker 		orig_linktype = off_linktype;	/* save original values */
3334febc6dcdSdtucker 		orig_nl = off_nl;
3335febc6dcdSdtucker 		orig_nl_nosnap = off_nl_nosnap;
3336febc6dcdSdtucker 
3337febc6dcdSdtucker 		switch (linktype) {
3338febc6dcdSdtucker 
3339febc6dcdSdtucker 		case DLT_EN10MB:
3340febc6dcdSdtucker 			off_linktype = 16;
3341febc6dcdSdtucker 			off_nl_nosnap = 18;
3342febc6dcdSdtucker 			off_nl = 18;
3343febc6dcdSdtucker 			break;
3344febc6dcdSdtucker 
3345febc6dcdSdtucker 		default:
3346febc6dcdSdtucker 			bpf_error("no VLAN support for data link type %d",
3347febc6dcdSdtucker 				  linktype);
3348febc6dcdSdtucker 			/*NOTREACHED*/
3349febc6dcdSdtucker 		}
3350febc6dcdSdtucker 	}
3351febc6dcdSdtucker 
3352febc6dcdSdtucker 	/* check for VLAN */
3353febc6dcdSdtucker 	b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q);
3354febc6dcdSdtucker 
3355febc6dcdSdtucker 	/* If a specific VLAN is requested, check VLAN id */
3356febc6dcdSdtucker 	if (vlan_num >= 0) {
3357febc6dcdSdtucker 		struct block *b1;
3358febc6dcdSdtucker 
33594f6bb374Sdenis 		b1 = gen_mcmp(orig_nl, BPF_H, (bpf_int32)vlan_num, 0x0FFF);
3360febc6dcdSdtucker 		gen_and(b0, b1);
3361febc6dcdSdtucker 		b0 = b1;
3362febc6dcdSdtucker 	}
3363febc6dcdSdtucker 
3364febc6dcdSdtucker 	return (b0);
3365febc6dcdSdtucker }
3366febc6dcdSdtucker 
3367febc6dcdSdtucker struct block *
33682cba36b5Sdlg gen_sample(int rate)
33692cba36b5Sdlg {
33702cba36b5Sdlg 	struct block *b0;
33712cba36b5Sdlg 	long long threshold = 0x100000000LL; /* 0xffffffff + 1 */
33722cba36b5Sdlg 
33732cba36b5Sdlg 	if (rate < 2) {
33742cba36b5Sdlg 		bpf_error("sample %d is too low", rate);
33752cba36b5Sdlg 		/*NOTREACHED*/
33762cba36b5Sdlg 	}
33772cba36b5Sdlg 	if (rate > (1 << 20)) {
33782cba36b5Sdlg 		bpf_error("sample %d is too high", rate);
33792cba36b5Sdlg 		/*NOTREACHED*/
33802cba36b5Sdlg 	}
33812cba36b5Sdlg 
33822cba36b5Sdlg 	threshold /= rate;
33832cba36b5Sdlg 	b0 = gen_relation(BPF_JGT, gen_loadrnd(), gen_loadi(threshold), 1);
33842cba36b5Sdlg 
33852cba36b5Sdlg 	return (b0);
33862cba36b5Sdlg }
33872cba36b5Sdlg 
33882cba36b5Sdlg struct block *
3389d42a50a0Sreyk gen_p80211_fcdir(int fcdir)
3390d42a50a0Sreyk {
3391d42a50a0Sreyk 	struct block *b0;
3392d42a50a0Sreyk 	u_int offset;
3393d42a50a0Sreyk 
3394d42a50a0Sreyk 	if (!(linktype == DLT_IEEE802_11 ||
3395d42a50a0Sreyk 	    linktype == DLT_IEEE802_11_RADIO)) {
3396d42a50a0Sreyk 		bpf_error("frame direction not supported on linktype 0x%x",
3397d42a50a0Sreyk 		    linktype);
3398d42a50a0Sreyk 		/* NOTREACHED */
3399d42a50a0Sreyk 	}
3400d42a50a0Sreyk 	offset = (u_int)offsetof(struct ieee80211_frame, i_fc[1]);
3401d42a50a0Sreyk 	if (linktype == DLT_IEEE802_11_RADIO)
3402d42a50a0Sreyk 		offset += IEEE80211_RADIOTAP_HDRLEN;
3403d42a50a0Sreyk 
3404d42a50a0Sreyk 	b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir,
3405d42a50a0Sreyk 	    (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
3406d42a50a0Sreyk 
3407d42a50a0Sreyk 	return (b0);
3408d42a50a0Sreyk }
3409d42a50a0Sreyk 
3410d42a50a0Sreyk static struct block *
3411d42a50a0Sreyk gen_p80211_hostop(const u_char *lladdr, int dir)
3412d42a50a0Sreyk {
3413d42a50a0Sreyk 	struct block *b0, *b1, *b2, *b3, *b4;
3414d42a50a0Sreyk 	u_int offset = 0;
3415d42a50a0Sreyk 
3416d42a50a0Sreyk 	if (linktype == DLT_IEEE802_11_RADIO)
3417d42a50a0Sreyk 		offset = IEEE80211_RADIOTAP_HDRLEN;
3418d42a50a0Sreyk 
3419d42a50a0Sreyk 	switch (dir) {
3420d42a50a0Sreyk 	case Q_SRC:
3421d42a50a0Sreyk 		b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset +
3422d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr2),
3423d42a50a0Sreyk 		    lladdr);
3424d42a50a0Sreyk 		b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset +
3425d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr2),
3426d42a50a0Sreyk 		    lladdr);
3427d42a50a0Sreyk 		b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset +
3428d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr3),
3429d42a50a0Sreyk 		    lladdr);
3430d42a50a0Sreyk 		b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset +
3431d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame_addr4, i_addr4),
3432d42a50a0Sreyk 		    lladdr);
3433d42a50a0Sreyk 		b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset +
3434d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame_addr4, i_addr2),
3435d42a50a0Sreyk 		    lladdr);
3436d42a50a0Sreyk 
3437d42a50a0Sreyk 		gen_or(b0, b1);
3438d42a50a0Sreyk 		gen_or(b1, b2);
3439d42a50a0Sreyk 		gen_or(b2, b3);
3440d42a50a0Sreyk 		gen_or(b3, b4);
3441d42a50a0Sreyk 		return (b4);
3442d42a50a0Sreyk 
3443d42a50a0Sreyk 	case Q_DST:
3444d42a50a0Sreyk 		b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset +
3445d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr1),
3446d42a50a0Sreyk 		    lladdr);
3447d42a50a0Sreyk 		b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset +
3448d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr3),
3449d42a50a0Sreyk 		    lladdr);
3450d42a50a0Sreyk 		b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset +
3451d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame, i_addr1),
3452d42a50a0Sreyk 		    lladdr);
3453d42a50a0Sreyk 		b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset +
3454d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame_addr4, i_addr3),
3455d42a50a0Sreyk 		    lladdr);
3456d42a50a0Sreyk 		b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset +
3457d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame_addr4, i_addr1),
3458d42a50a0Sreyk 		    lladdr);
3459d42a50a0Sreyk 
3460d42a50a0Sreyk 		gen_or(b0, b1);
3461d42a50a0Sreyk 		gen_or(b1, b2);
3462d42a50a0Sreyk 		gen_or(b2, b3);
3463d42a50a0Sreyk 		gen_or(b3, b4);
3464d42a50a0Sreyk 		return (b4);
3465d42a50a0Sreyk 
3466d42a50a0Sreyk 	case Q_ADDR1:
3467d42a50a0Sreyk 		return (gen_bcmp(offset +
3468d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame,
3469d42a50a0Sreyk 		    i_addr1), IEEE80211_ADDR_LEN, lladdr));
3470d42a50a0Sreyk 
3471d42a50a0Sreyk 	case Q_ADDR2:
3472d42a50a0Sreyk 		return (gen_bcmp(offset +
3473d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame,
3474d42a50a0Sreyk 		    i_addr2), IEEE80211_ADDR_LEN, lladdr));
3475d42a50a0Sreyk 
3476d42a50a0Sreyk 	case Q_ADDR3:
3477d42a50a0Sreyk 		return (gen_bcmp(offset +
3478d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame,
3479d42a50a0Sreyk 		    i_addr3), IEEE80211_ADDR_LEN, lladdr));
3480d42a50a0Sreyk 
3481d42a50a0Sreyk 	case Q_ADDR4:
3482d42a50a0Sreyk 		return (gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset +
3483d42a50a0Sreyk 		    (u_int)offsetof(struct ieee80211_frame_addr4, i_addr4),
3484d42a50a0Sreyk 		    lladdr));
3485d42a50a0Sreyk 
3486d42a50a0Sreyk 	case Q_AND:
3487d42a50a0Sreyk 		b0 = gen_p80211_hostop(lladdr, Q_SRC);
3488d42a50a0Sreyk 		b1 = gen_p80211_hostop(lladdr, Q_DST);
3489d42a50a0Sreyk 		gen_and(b0, b1);
3490d42a50a0Sreyk 		return (b1);
3491d42a50a0Sreyk 
3492d42a50a0Sreyk 	case Q_DEFAULT:
3493d42a50a0Sreyk 	case Q_OR:
3494d42a50a0Sreyk 		b0 = gen_p80211_hostop(lladdr, Q_ADDR1);
3495d42a50a0Sreyk 		b1 = gen_p80211_hostop(lladdr, Q_ADDR2);
3496d42a50a0Sreyk 		b2 = gen_p80211_hostop(lladdr, Q_ADDR3);
3497d42a50a0Sreyk 		b3 = gen_p80211_hostop(lladdr, Q_ADDR4);
3498d42a50a0Sreyk 		gen_or(b0, b1);
3499d42a50a0Sreyk 		gen_or(b1, b2);
3500d42a50a0Sreyk 		gen_or(b2, b3);
3501d42a50a0Sreyk 		return (b3);
3502d42a50a0Sreyk 
3503d42a50a0Sreyk 	default:
3504d42a50a0Sreyk 		bpf_error("direction not supported on linktype 0x%x",
3505d42a50a0Sreyk 		    linktype);
3506d42a50a0Sreyk 	}
3507d42a50a0Sreyk 	/* NOTREACHED */
3508d42a50a0Sreyk }
3509d42a50a0Sreyk 
3510d42a50a0Sreyk static struct block *
3511d42a50a0Sreyk gen_p80211_addr(int fcdir, u_int offset, const u_char *lladdr)
3512d42a50a0Sreyk {
3513d42a50a0Sreyk 	struct block *b0, *b1;
3514d42a50a0Sreyk 
3515d42a50a0Sreyk 	b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir, IEEE80211_FC1_DIR_MASK);
3516d42a50a0Sreyk 	b1 = gen_bcmp(offset, IEEE80211_ADDR_LEN, lladdr);
3517d42a50a0Sreyk 	gen_and(b0, b1);
3518d42a50a0Sreyk 
3519d42a50a0Sreyk 	return (b1);
3520d42a50a0Sreyk }
3521