GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: gencode.c,v 1.46 2016/11/20 12:45:26 reyk Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 |
||
5 |
* The Regents of the University of California. All rights reserved. |
||
6 |
* |
||
7 |
* Redistribution and use in source and binary forms, with or without |
||
8 |
* modification, are permitted provided that: (1) source code distributions |
||
9 |
* retain the above copyright notice and this paragraph in its entirety, (2) |
||
10 |
* distributions including binary code include the above copyright notice and |
||
11 |
* this paragraph in its entirety in the documentation or other materials |
||
12 |
* provided with the distribution, and (3) all advertising materials mentioning |
||
13 |
* features or use of this software display the following acknowledgement: |
||
14 |
* ``This product includes software developed by the University of California, |
||
15 |
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
||
16 |
* the University nor the names of its contributors may be used to endorse |
||
17 |
* or promote products derived from this software without specific prior |
||
18 |
* written permission. |
||
19 |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||
20 |
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
||
21 |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
||
22 |
*/ |
||
23 |
|||
24 |
#include <sys/param.h> /* ALIGN */ |
||
25 |
#include <sys/types.h> |
||
26 |
#include <sys/socket.h> |
||
27 |
#include <sys/time.h> |
||
28 |
|||
29 |
struct mbuf; |
||
30 |
struct rtentry; |
||
31 |
|||
32 |
#include <net/if.h> |
||
33 |
|||
34 |
#include <netinet/in.h> |
||
35 |
#include <netinet/if_ether.h> |
||
36 |
|||
37 |
#include <net/if_pflog.h> |
||
38 |
#include <net/pfvar.h> |
||
39 |
|||
40 |
#include <net80211/ieee80211.h> |
||
41 |
#include <net80211/ieee80211_radiotap.h> |
||
42 |
|||
43 |
#include <stdlib.h> |
||
44 |
#include <stddef.h> |
||
45 |
#include <setjmp.h> |
||
46 |
#include <stdarg.h> |
||
47 |
#include <string.h> |
||
48 |
|||
49 |
#include "pcap-int.h" |
||
50 |
|||
51 |
#include "ethertype.h" |
||
52 |
#include "llc.h" |
||
53 |
#include "gencode.h" |
||
54 |
#include "ppp.h" |
||
55 |
#include <pcap-namedb.h> |
||
56 |
#ifdef INET6 |
||
57 |
#include <netdb.h> |
||
58 |
#endif /*INET6*/ |
||
59 |
|||
60 |
#ifdef HAVE_OS_PROTO_H |
||
61 |
#include "os-proto.h" |
||
62 |
#endif |
||
63 |
|||
64 |
#define JMP(c) ((c)|BPF_JMP|BPF_K) |
||
65 |
|||
66 |
/* Locals */ |
||
67 |
static jmp_buf top_ctx; |
||
68 |
static pcap_t *bpf_pcap; |
||
69 |
|||
70 |
/* Hack for updating VLAN offsets. */ |
||
71 |
static u_int orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1; |
||
72 |
|||
73 |
/* XXX */ |
||
74 |
#ifdef PCAP_FDDIPAD |
||
75 |
int pcap_fddipad = PCAP_FDDIPAD; |
||
76 |
#else |
||
77 |
int pcap_fddipad; |
||
78 |
#endif |
||
79 |
|||
80 |
__dead void |
||
81 |
bpf_error(const char *fmt, ...) |
||
82 |
{ |
||
83 |
va_list ap; |
||
84 |
|||
85 |
va_start(ap, fmt); |
||
86 |
if (bpf_pcap != NULL) |
||
87 |
(void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, |
||
88 |
fmt, ap); |
||
89 |
va_end(ap); |
||
90 |
longjmp(top_ctx, 1); |
||
91 |
/* NOTREACHED */ |
||
92 |
} |
||
93 |
|||
94 |
static void init_linktype(int); |
||
95 |
|||
96 |
static int alloc_reg(void); |
||
97 |
static void free_reg(int); |
||
98 |
|||
99 |
static struct block *root; |
||
100 |
|||
101 |
/* initialization code used for variable link header */ |
||
102 |
static struct slist *init_code = NULL; |
||
103 |
|||
104 |
/* Flags and registers for variable link type handling */ |
||
105 |
static int variable_nl; |
||
106 |
static int nl_reg, iphl_reg; |
||
107 |
|||
108 |
/* |
||
109 |
* We divy out chunks of memory rather than call malloc each time so |
||
110 |
* we don't have to worry about leaking memory. It's probably |
||
111 |
* not a big deal if all this memory was wasted but it this ever |
||
112 |
* goes into a library that would probably not be a good idea. |
||
113 |
*/ |
||
114 |
#define NCHUNKS 16 |
||
115 |
#define CHUNK0SIZE 1024 |
||
116 |
struct chunk { |
||
117 |
u_int n_left; |
||
118 |
void *m; |
||
119 |
}; |
||
120 |
|||
121 |
static struct chunk chunks[NCHUNKS]; |
||
122 |
static int cur_chunk; |
||
123 |
|||
124 |
static void *newchunk(u_int); |
||
125 |
static void freechunks(void); |
||
126 |
static __inline struct block *new_block(int); |
||
127 |
static __inline struct slist *new_stmt(int); |
||
128 |
static struct block *gen_retblk(int); |
||
129 |
static __inline void syntax(void); |
||
130 |
|||
131 |
static void backpatch(struct block *, struct block *); |
||
132 |
static void merge(struct block *, struct block *); |
||
133 |
static struct block *gen_cmp(u_int, u_int, bpf_int32); |
||
134 |
static struct block *gen_cmp_gt(u_int, u_int, bpf_int32); |
||
135 |
static struct block *gen_cmp_nl(u_int, u_int, bpf_int32); |
||
136 |
static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32); |
||
137 |
static struct block *gen_mcmp_nl(u_int, u_int, bpf_int32, bpf_u_int32); |
||
138 |
static struct block *gen_bcmp(u_int, u_int, const u_char *); |
||
139 |
static struct block *gen_uncond(int); |
||
140 |
static __inline struct block *gen_true(void); |
||
141 |
static __inline struct block *gen_false(void); |
||
142 |
static struct block *gen_linktype(int); |
||
143 |
static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); |
||
144 |
#ifdef INET6 |
||
145 |
static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); |
||
146 |
#endif |
||
147 |
static struct block *gen_ehostop(const u_char *, int); |
||
148 |
static struct block *gen_fhostop(const u_char *, int); |
||
149 |
static struct block *gen_dnhostop(bpf_u_int32, int, u_int); |
||
150 |
static struct block *gen_p80211_hostop(const u_char *, int); |
||
151 |
static struct block *gen_p80211_addr(int, u_int, const u_char *); |
||
152 |
static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int); |
||
153 |
#ifdef INET6 |
||
154 |
static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int); |
||
155 |
#endif |
||
156 |
#ifndef INET6 |
||
157 |
static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); |
||
158 |
#endif |
||
159 |
static struct block *gen_ipfrag(void); |
||
160 |
static struct block *gen_portatom(int, bpf_int32); |
||
161 |
#ifdef INET6 |
||
162 |
static struct block *gen_portatom6(int, bpf_int32); |
||
163 |
#endif |
||
164 |
struct block *gen_portop(int, int, int); |
||
165 |
static struct block *gen_port(int, int, int); |
||
166 |
#ifdef INET6 |
||
167 |
struct block *gen_portop6(int, int, int); |
||
168 |
static struct block *gen_port6(int, int, int); |
||
169 |
#endif |
||
170 |
static int lookup_proto(const char *, int); |
||
171 |
static struct block *gen_protochain(int, int, int); |
||
172 |
static struct block *gen_proto(int, int, int); |
||
173 |
static struct slist *xfer_to_x(struct arth *); |
||
174 |
static struct slist *xfer_to_a(struct arth *); |
||
175 |
static struct block *gen_len(int, int); |
||
176 |
|||
177 |
static void * |
||
178 |
newchunk(n) |
||
179 |
u_int n; |
||
180 |
{ |
||
181 |
struct chunk *cp; |
||
182 |
int k, size; |
||
183 |
|||
184 |
/* XXX Round to structure boundary. */ |
||
185 |
126 |
n = ALIGN(n); |
|
186 |
|||
187 |
63 |
cp = &chunks[cur_chunk]; |
|
188 |
✓✓ | 63 |
if (n > cp->n_left) { |
189 |
6 |
++cp, k = ++cur_chunk; |
|
190 |
✗✓ | 6 |
if (k >= NCHUNKS) |
191 |
bpf_error("out of memory"); |
||
192 |
6 |
size = CHUNK0SIZE << k; |
|
193 |
6 |
cp->m = calloc(1, size); |
|
194 |
✗✓ | 6 |
if (cp->m == NULL) |
195 |
bpf_error("out of memory"); |
||
196 |
|||
197 |
6 |
cp->n_left = size; |
|
198 |
✗✓ | 6 |
if (n > size) |
199 |
bpf_error("out of memory"); |
||
200 |
} |
||
201 |
63 |
cp->n_left -= n; |
|
202 |
63 |
return (void *)((char *)cp->m + cp->n_left); |
|
203 |
} |
||
204 |
|||
205 |
static void |
||
206 |
freechunks() |
||
207 |
{ |
||
208 |
int i; |
||
209 |
|||
210 |
6 |
cur_chunk = 0; |
|
211 |
✓✓ | 102 |
for (i = 0; i < NCHUNKS; ++i) { |
212 |
48 |
free(chunks[i].m); |
|
213 |
48 |
chunks[i].m = NULL; |
|
214 |
} |
||
215 |
3 |
} |
|
216 |
|||
217 |
/* |
||
218 |
* A strdup whose allocations are freed after code generation is over. |
||
219 |
*/ |
||
220 |
char * |
||
221 |
sdup(s) |
||
222 |
const char *s; |
||
223 |
{ |
||
224 |
int n = strlen(s) + 1; |
||
225 |
char *cp = newchunk(n); |
||
226 |
|||
227 |
strlcpy(cp, s, n); |
||
228 |
return (cp); |
||
229 |
} |
||
230 |
|||
231 |
static __inline struct block * |
||
232 |
new_block(code) |
||
233 |
int code; |
||
234 |
{ |
||
235 |
struct block *p; |
||
236 |
|||
237 |
36 |
p = (struct block *)newchunk(sizeof(*p)); |
|
238 |
18 |
p->s.code = code; |
|
239 |
18 |
p->head = p; |
|
240 |
|||
241 |
18 |
return p; |
|
242 |
} |
||
243 |
|||
244 |
static __inline struct slist * |
||
245 |
new_stmt(code) |
||
246 |
int code; |
||
247 |
{ |
||
248 |
struct slist *p; |
||
249 |
|||
250 |
78 |
p = (struct slist *)newchunk(sizeof(*p)); |
|
251 |
39 |
p->s.code = code; |
|
252 |
|||
253 |
39 |
return p; |
|
254 |
} |
||
255 |
|||
256 |
static struct block * |
||
257 |
gen_retblk(v) |
||
258 |
int v; |
||
259 |
{ |
||
260 |
12 |
struct block *b = new_block(BPF_RET|BPF_K); |
|
261 |
|||
262 |
6 |
b->s.k = v; |
|
263 |
6 |
return b; |
|
264 |
} |
||
265 |
|||
266 |
static __inline void |
||
267 |
syntax() |
||
268 |
{ |
||
269 |
bpf_error("syntax error in filter expression"); |
||
270 |
} |
||
271 |
|||
272 |
static bpf_u_int32 netmask; |
||
273 |
static int snaplen; |
||
274 |
int no_optimize; |
||
275 |
|||
276 |
int |
||
277 |
pcap_compile(pcap_t *p, struct bpf_program *program, |
||
278 |
char *buf, int optimize, bpf_u_int32 mask) |
||
279 |
{ |
||
280 |
extern int n_errors; |
||
281 |
6 |
int len; |
|
282 |
|||
283 |
3 |
no_optimize = 0; |
|
284 |
3 |
n_errors = 0; |
|
285 |
3 |
root = NULL; |
|
286 |
3 |
bpf_pcap = p; |
|
287 |
✗✓ | 3 |
if (setjmp(top_ctx)) { |
288 |
freechunks(); |
||
289 |
return (-1); |
||
290 |
} |
||
291 |
|||
292 |
3 |
netmask = mask; |
|
293 |
3 |
snaplen = pcap_snapshot(p); |
|
294 |
|||
295 |
3 |
lex_init(buf ? buf : ""); |
|
296 |
3 |
init_linktype(pcap_datalink(p)); |
|
297 |
3 |
(void)pcap_parse(); |
|
298 |
|||
299 |
✗✓ | 3 |
if (n_errors) |
300 |
syntax(); |
||
301 |
|||
302 |
✗✓ | 3 |
if (root == NULL) |
303 |
root = gen_retblk(snaplen); |
||
304 |
|||
305 |
✗✓ | 3 |
if (optimize && !no_optimize) { |
306 |
bpf_optimize(&root); |
||
307 |
if (root == NULL || |
||
308 |
(root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) |
||
309 |
bpf_error("expression rejects all packets"); |
||
310 |
} |
||
311 |
3 |
program->bf_insns = icode_to_fcode(root, &len); |
|
312 |
3 |
program->bf_len = len; |
|
313 |
|||
314 |
3 |
freechunks(); |
|
315 |
3 |
return (0); |
|
316 |
3 |
} |
|
317 |
|||
318 |
/* |
||
319 |
* entry point for using the compiler with no pcap open |
||
320 |
* pass in all the stuff that is needed explicitly instead. |
||
321 |
*/ |
||
322 |
int |
||
323 |
pcap_compile_nopcap(int snaplen_arg, int linktype_arg, |
||
324 |
struct bpf_program *program, |
||
325 |
char *buf, int optimize, bpf_u_int32 mask) |
||
326 |
{ |
||
327 |
extern int n_errors; |
||
328 |
int len; |
||
329 |
|||
330 |
n_errors = 0; |
||
331 |
root = NULL; |
||
332 |
bpf_pcap = NULL; |
||
333 |
if (setjmp(top_ctx)) { |
||
334 |
freechunks(); |
||
335 |
return (-1); |
||
336 |
} |
||
337 |
|||
338 |
netmask = mask; |
||
339 |
|||
340 |
/* XXX needed? I don't grok the use of globals here. */ |
||
341 |
snaplen = snaplen_arg; |
||
342 |
|||
343 |
lex_init(buf ? buf : ""); |
||
344 |
init_linktype(linktype_arg); |
||
345 |
(void)pcap_parse(); |
||
346 |
|||
347 |
if (n_errors) |
||
348 |
syntax(); |
||
349 |
|||
350 |
if (root == NULL) |
||
351 |
root = gen_retblk(snaplen_arg); |
||
352 |
|||
353 |
if (optimize) { |
||
354 |
bpf_optimize(&root); |
||
355 |
if (root == NULL || |
||
356 |
(root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) |
||
357 |
bpf_error("expression rejects all packets"); |
||
358 |
} |
||
359 |
program->bf_insns = icode_to_fcode(root, &len); |
||
360 |
program->bf_len = len; |
||
361 |
|||
362 |
freechunks(); |
||
363 |
return (0); |
||
364 |
} |
||
365 |
|||
366 |
/* |
||
367 |
* Clean up a "struct bpf_program" by freeing all the memory allocated |
||
368 |
* in it. |
||
369 |
*/ |
||
370 |
void |
||
371 |
pcap_freecode(struct bpf_program *program) |
||
372 |
{ |
||
373 |
8 |
program->bf_len = 0; |
|
374 |
✗✓ | 4 |
if (program->bf_insns != NULL) { |
375 |
free((char *)program->bf_insns); |
||
376 |
program->bf_insns = NULL; |
||
377 |
} |
||
378 |
4 |
} |
|
379 |
|||
380 |
/* |
||
381 |
* Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates |
||
382 |
* which of the jt and jf fields has been resolved and which is a pointer |
||
383 |
* back to another unresolved block (or nil). At least one of the fields |
||
384 |
* in each block is already resolved. |
||
385 |
*/ |
||
386 |
static void |
||
387 |
backpatch(list, target) |
||
388 |
struct block *list, *target; |
||
389 |
{ |
||
390 |
struct block *next; |
||
391 |
|||
392 |
✓✓ | 93 |
while (list) { |
393 |
✓✓ | 24 |
if (!list->sense) { |
394 |
12 |
next = JT(list); |
|
395 |
JT(list) = target; |
||
396 |
12 |
} else { |
|
397 |
12 |
next = JF(list); |
|
398 |
JF(list) = target; |
||
399 |
} |
||
400 |
list = next; |
||
401 |
} |
||
402 |
15 |
} |
|
403 |
|||
404 |
/* |
||
405 |
* Merge the lists in b0 and b1, using the 'sense' field to indicate |
||
406 |
* which of jt and jf is the link. |
||
407 |
*/ |
||
408 |
static void |
||
409 |
merge(b0, b1) |
||
410 |
struct block *b0, *b1; |
||
411 |
{ |
||
412 |
struct block **p = &b0; |
||
413 |
|||
414 |
/* Find end of list. */ |
||
415 |
✓✓ | 42 |
while (*p) |
416 |
12 |
p = !((*p)->sense) ? &JT(*p) : &JF(*p); |
|
417 |
|||
418 |
/* Concatenate the lists. */ |
||
419 |
9 |
*p = b1; |
|
420 |
9 |
} |
|
421 |
|||
422 |
void |
||
423 |
finish_parse(p) |
||
424 |
struct block *p; |
||
425 |
{ |
||
426 |
6 |
backpatch(p, gen_retblk(snaplen)); |
|
427 |
3 |
p->sense = !p->sense; |
|
428 |
3 |
backpatch(p, gen_retblk(0)); |
|
429 |
3 |
root = p->head; |
|
430 |
|||
431 |
/* prepend initialization code to root */ |
||
432 |
✗✓ | 3 |
if (init_code != NULL && root != NULL) { |
433 |
sappend(init_code, root->stmts); |
||
434 |
root->stmts = init_code; |
||
435 |
init_code = NULL; |
||
436 |
} |
||
437 |
|||
438 |
✗✓ | 3 |
if (iphl_reg != -1) { |
439 |
free_reg(iphl_reg); |
||
440 |
iphl_reg = -1; |
||
441 |
} |
||
442 |
✗✓ | 3 |
if (nl_reg != -1) { |
443 |
free_reg(nl_reg); |
||
444 |
nl_reg = -1; |
||
445 |
} |
||
446 |
3 |
} |
|
447 |
|||
448 |
void |
||
449 |
gen_and(b0, b1) |
||
450 |
struct block *b0, *b1; |
||
451 |
{ |
||
452 |
18 |
backpatch(b0, b1->head); |
|
453 |
9 |
b0->sense = !b0->sense; |
|
454 |
9 |
b1->sense = !b1->sense; |
|
455 |
9 |
merge(b1, b0); |
|
456 |
9 |
b1->sense = !b1->sense; |
|
457 |
9 |
b1->head = b0->head; |
|
458 |
9 |
} |
|
459 |
|||
460 |
void |
||
461 |
gen_or(b0, b1) |
||
462 |
struct block *b0, *b1; |
||
463 |
{ |
||
464 |
b0->sense = !b0->sense; |
||
465 |
backpatch(b0, b1->head); |
||
466 |
b0->sense = !b0->sense; |
||
467 |
merge(b1, b0); |
||
468 |
b1->head = b0->head; |
||
469 |
} |
||
470 |
|||
471 |
void |
||
472 |
gen_not(b) |
||
473 |
struct block *b; |
||
474 |
{ |
||
475 |
b->sense = !b->sense; |
||
476 |
} |
||
477 |
|||
478 |
static struct block * |
||
479 |
gen_cmp(offset, size, v) |
||
480 |
u_int offset, size; |
||
481 |
bpf_int32 v; |
||
482 |
{ |
||
483 |
struct slist *s; |
||
484 |
struct block *b; |
||
485 |
|||
486 |
12 |
s = new_stmt(BPF_LD|BPF_ABS|size); |
|
487 |
6 |
s->s.k = offset; |
|
488 |
|||
489 |
6 |
b = new_block(JMP(BPF_JEQ)); |
|
490 |
6 |
b->stmts = s; |
|
491 |
6 |
b->s.k = v; |
|
492 |
|||
493 |
6 |
return b; |
|
494 |
} |
||
495 |
|||
496 |
static struct block * |
||
497 |
gen_cmp_gt(offset, size, v) |
||
498 |
u_int offset, size; |
||
499 |
bpf_int32 v; |
||
500 |
{ |
||
501 |
struct slist *s; |
||
502 |
struct block *b; |
||
503 |
|||
504 |
s = new_stmt(BPF_LD|BPF_ABS|size); |
||
505 |
s->s.k = offset; |
||
506 |
|||
507 |
b = new_block(JMP(BPF_JGT)); |
||
508 |
b->stmts = s; |
||
509 |
b->s.k = v; |
||
510 |
|||
511 |
return b; |
||
512 |
} |
||
513 |
|||
514 |
static struct block * |
||
515 |
gen_mcmp(offset, size, v, mask) |
||
516 |
u_int offset, size; |
||
517 |
bpf_int32 v; |
||
518 |
bpf_u_int32 mask; |
||
519 |
{ |
||
520 |
struct block *b = gen_cmp(offset, size, v); |
||
521 |
struct slist *s; |
||
522 |
|||
523 |
if (mask != 0xffffffff) { |
||
524 |
s = new_stmt(BPF_ALU|BPF_AND|BPF_K); |
||
525 |
s->s.k = mask; |
||
526 |
sappend(b->stmts, s); |
||
527 |
} |
||
528 |
return b; |
||
529 |
} |
||
530 |
|||
531 |
/* Like gen_mcmp with 'dynamic off_nl' added to the offset */ |
||
532 |
static struct block * |
||
533 |
gen_mcmp_nl(offset, size, v, mask) |
||
534 |
u_int offset, size; |
||
535 |
bpf_int32 v; |
||
536 |
bpf_u_int32 mask; |
||
537 |
{ |
||
538 |
struct block *b = gen_cmp_nl(offset, size, v); |
||
539 |
struct slist *s; |
||
540 |
|||
541 |
if (mask != 0xffffffff) { |
||
542 |
s = new_stmt(BPF_ALU|BPF_AND|BPF_K); |
||
543 |
s->s.k = mask; |
||
544 |
sappend(b->stmts, s); |
||
545 |
} |
||
546 |
return b; |
||
547 |
} |
||
548 |
|||
549 |
static struct block * |
||
550 |
gen_bcmp(offset, size, v) |
||
551 |
u_int offset, size; |
||
552 |
const u_char *v; |
||
553 |
{ |
||
554 |
struct block *b, *tmp; |
||
555 |
|||
556 |
b = NULL; |
||
557 |
while (size >= 4) { |
||
558 |
const u_char *p = &v[size - 4]; |
||
559 |
bpf_int32 w = ((bpf_int32)p[0] << 24) | |
||
560 |
((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; |
||
561 |
|||
562 |
tmp = gen_cmp(offset + size - 4, BPF_W, w); |
||
563 |
if (b != NULL) |
||
564 |
gen_and(b, tmp); |
||
565 |
b = tmp; |
||
566 |
size -= 4; |
||
567 |
} |
||
568 |
while (size >= 2) { |
||
569 |
const u_char *p = &v[size - 2]; |
||
570 |
bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; |
||
571 |
|||
572 |
tmp = gen_cmp(offset + size - 2, BPF_H, w); |
||
573 |
if (b != NULL) |
||
574 |
gen_and(b, tmp); |
||
575 |
b = tmp; |
||
576 |
size -= 2; |
||
577 |
} |
||
578 |
if (size > 0) { |
||
579 |
tmp = gen_cmp(offset, BPF_B, (bpf_int32)v[0]); |
||
580 |
if (b != NULL) |
||
581 |
gen_and(b, tmp); |
||
582 |
b = tmp; |
||
583 |
} |
||
584 |
return b; |
||
585 |
} |
||
586 |
|||
587 |
/* |
||
588 |
* Various code constructs need to know the layout of the data link |
||
589 |
* layer. These variables give the necessary offsets. off_linktype |
||
590 |
* is set to -1 for no encapsulation, in which case, IP is assumed. |
||
591 |
*/ |
||
592 |
static u_int off_linktype; |
||
593 |
static u_int off_nl; |
||
594 |
static u_int off_nl_nosnap; |
||
595 |
|||
596 |
static int linktype; |
||
597 |
|||
598 |
/* Generate code to load the dynamic 'off_nl' to the X register */ |
||
599 |
static struct slist * |
||
600 |
nl2X_stmt(void) |
||
601 |
{ |
||
602 |
struct slist *s, *tmp; |
||
603 |
|||
604 |
if (nl_reg == -1) { |
||
605 |
switch (linktype) { |
||
606 |
case DLT_PFLOG: |
||
607 |
/* The pflog header contains PFLOG_REAL_HDRLEN |
||
608 |
which does NOT include the padding. Round |
||
609 |
up to the nearest dword boundary */ |
||
610 |
s = new_stmt(BPF_LD|BPF_B|BPF_ABS); |
||
611 |
s->s.k = 0; |
||
612 |
|||
613 |
tmp = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
614 |
tmp->s.k = 3; |
||
615 |
sappend(s, tmp); |
||
616 |
|||
617 |
tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K); |
||
618 |
tmp->s.k = 0xfc; |
||
619 |
sappend(s, tmp); |
||
620 |
|||
621 |
nl_reg = alloc_reg(); |
||
622 |
tmp = new_stmt(BPF_ST); |
||
623 |
tmp->s.k = nl_reg; |
||
624 |
sappend(s, tmp); |
||
625 |
|||
626 |
break; |
||
627 |
default: |
||
628 |
bpf_error("Unknown header size for link type 0x%x", |
||
629 |
linktype); |
||
630 |
} |
||
631 |
|||
632 |
if (init_code == NULL) |
||
633 |
init_code = s; |
||
634 |
else |
||
635 |
sappend(init_code, s); |
||
636 |
} |
||
637 |
|||
638 |
s = new_stmt(BPF_LDX|BPF_MEM); |
||
639 |
s->s.k = nl_reg; |
||
640 |
|||
641 |
return s; |
||
642 |
} |
||
643 |
|||
644 |
/* Like gen_cmp but adds the dynamic 'off_nl' to the offset */ |
||
645 |
static struct block * |
||
646 |
gen_cmp_nl(offset, size, v) |
||
647 |
u_int offset, size; |
||
648 |
bpf_int32 v; |
||
649 |
{ |
||
650 |
struct slist *s, *tmp; |
||
651 |
struct block *b; |
||
652 |
|||
653 |
✗✓ | 6 |
if (variable_nl) { |
654 |
s = nl2X_stmt(); |
||
655 |
tmp = new_stmt(BPF_LD|BPF_IND|size); |
||
656 |
tmp->s.k = offset; |
||
657 |
sappend(s, tmp); |
||
658 |
} else { |
||
659 |
3 |
s = new_stmt(BPF_LD|BPF_ABS|size); |
|
660 |
3 |
s->s.k = offset + off_nl; |
|
661 |
} |
||
662 |
3 |
b = new_block(JMP(BPF_JEQ)); |
|
663 |
3 |
b->stmts = s; |
|
664 |
3 |
b->s.k = v; |
|
665 |
|||
666 |
3 |
return b; |
|
667 |
} |
||
668 |
|||
669 |
static void |
||
670 |
init_linktype(type) |
||
671 |
int type; |
||
672 |
{ |
||
673 |
6 |
linktype = type; |
|
674 |
3 |
init_code = NULL; |
|
675 |
3 |
nl_reg = iphl_reg = -1; |
|
676 |
|||
677 |
✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗ |
3 |
switch (type) { |
678 |
|||
679 |
case DLT_EN10MB: |
||
680 |
3 |
off_linktype = 12; |
|
681 |
off_nl = 14; |
||
682 |
3 |
return; |
|
683 |
|||
684 |
case DLT_SLIP: |
||
685 |
/* |
||
686 |
* SLIP doesn't have a link level type. The 16 byte |
||
687 |
* header is hacked into our SLIP driver. |
||
688 |
*/ |
||
689 |
off_linktype = -1; |
||
690 |
off_nl = 16; |
||
691 |
return; |
||
692 |
|||
693 |
case DLT_SLIP_BSDOS: |
||
694 |
/* XXX this may be the same as the DLT_PPP_BSDOS case */ |
||
695 |
off_linktype = -1; |
||
696 |
/* XXX end */ |
||
697 |
off_nl = 24; |
||
698 |
return; |
||
699 |
|||
700 |
case DLT_NULL: |
||
701 |
off_linktype = 0; |
||
702 |
off_nl = 4; |
||
703 |
return; |
||
704 |
|||
705 |
case DLT_PPP: |
||
706 |
off_linktype = 2; |
||
707 |
off_nl = 4; |
||
708 |
return; |
||
709 |
|||
710 |
case DLT_PPP_ETHER: |
||
711 |
/* |
||
712 |
* This does not include the Ethernet header, and |
||
713 |
* only covers session state. |
||
714 |
*/ |
||
715 |
off_linktype = 6; |
||
716 |
off_nl = 8; |
||
717 |
return; |
||
718 |
|||
719 |
case DLT_PPP_BSDOS: |
||
720 |
off_linktype = 5; |
||
721 |
off_nl = 24; |
||
722 |
return; |
||
723 |
|||
724 |
case DLT_FDDI: |
||
725 |
/* |
||
726 |
* FDDI doesn't really have a link-level type field. |
||
727 |
* We assume that SSAP = SNAP is being used and pick |
||
728 |
* out the encapsulated Ethernet type. |
||
729 |
*/ |
||
730 |
off_linktype = 19; |
||
731 |
#ifdef PCAP_FDDIPAD |
||
732 |
off_linktype += pcap_fddipad; |
||
733 |
#endif |
||
734 |
off_nl = 21; |
||
735 |
#ifdef PCAP_FDDIPAD |
||
736 |
off_nl += pcap_fddipad; |
||
737 |
#endif |
||
738 |
return; |
||
739 |
|||
740 |
case DLT_IEEE802: |
||
741 |
off_linktype = 20; |
||
742 |
off_nl = 22; |
||
743 |
return; |
||
744 |
|||
745 |
case DLT_IEEE802_11: |
||
746 |
off_linktype = 30; /* XXX variable */ |
||
747 |
off_nl = 32; |
||
748 |
return; |
||
749 |
|||
750 |
case DLT_IEEE802_11_RADIO: /* XXX variable */ |
||
751 |
off_linktype = 30 + IEEE80211_RADIOTAP_HDRLEN; |
||
752 |
off_nl = 32 + IEEE80211_RADIOTAP_HDRLEN; |
||
753 |
return; |
||
754 |
|||
755 |
case DLT_ATM_RFC1483: |
||
756 |
/* |
||
757 |
* assume routed, non-ISO PDUs |
||
758 |
* (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) |
||
759 |
*/ |
||
760 |
off_linktype = 6; |
||
761 |
off_nl = 8; |
||
762 |
return; |
||
763 |
|||
764 |
case DLT_LOOP: |
||
765 |
off_linktype = -1; |
||
766 |
off_nl = 4; |
||
767 |
return; |
||
768 |
|||
769 |
case DLT_ENC: |
||
770 |
off_linktype = -1; |
||
771 |
off_nl = 12; |
||
772 |
return; |
||
773 |
|||
774 |
case DLT_PFLOG: |
||
775 |
off_linktype = 0; |
||
776 |
variable_nl = 1; |
||
777 |
off_nl = 0; |
||
778 |
return; |
||
779 |
|||
780 |
case DLT_PFSYNC: |
||
781 |
off_linktype = -1; |
||
782 |
off_nl = 4; |
||
783 |
return; |
||
784 |
|||
785 |
case DLT_OPENFLOW: |
||
786 |
off_linktype = -1; |
||
787 |
off_nl = 12; |
||
788 |
return; |
||
789 |
|||
790 |
case DLT_RAW: |
||
791 |
off_linktype = -1; |
||
792 |
off_nl = 0; |
||
793 |
return; |
||
794 |
} |
||
795 |
bpf_error("unknown data link type 0x%x", linktype); |
||
796 |
/* NOTREACHED */ |
||
797 |
3 |
} |
|
798 |
|||
799 |
static struct block * |
||
800 |
gen_uncond(rsense) |
||
801 |
int rsense; |
||
802 |
{ |
||
803 |
struct block *b; |
||
804 |
struct slist *s; |
||
805 |
|||
806 |
s = new_stmt(BPF_LD|BPF_IMM); |
||
807 |
s->s.k = !rsense; |
||
808 |
b = new_block(JMP(BPF_JEQ)); |
||
809 |
b->stmts = s; |
||
810 |
|||
811 |
return b; |
||
812 |
} |
||
813 |
|||
814 |
static __inline struct block * |
||
815 |
gen_true() |
||
816 |
{ |
||
817 |
return gen_uncond(1); |
||
818 |
} |
||
819 |
|||
820 |
static __inline struct block * |
||
821 |
gen_false() |
||
822 |
{ |
||
823 |
return gen_uncond(0); |
||
824 |
} |
||
825 |
|||
826 |
static struct block * |
||
827 |
gen_linktype(proto) |
||
828 |
int proto; |
||
829 |
{ |
||
830 |
struct block *b0, *b1; |
||
831 |
|||
832 |
/* If we're not using encapsulation and checking for IP, we're done */ |
||
833 |
✗✓ | 12 |
if (off_linktype == -1 && proto == ETHERTYPE_IP) |
834 |
return gen_true(); |
||
835 |
#ifdef INET6 |
||
836 |
/* this isn't the right thing to do, but sometimes necessary */ |
||
837 |
✗✓ | 6 |
if (off_linktype == -1 && proto == ETHERTYPE_IPV6) |
838 |
return gen_true(); |
||
839 |
#endif |
||
840 |
|||
841 |
✓✗✗✗ ✗✗✗✗ ✗✗ |
6 |
switch (linktype) { |
842 |
|||
843 |
case DLT_EN10MB: |
||
844 |
✗✓ | 6 |
if (proto <= ETHERMTU) { |
845 |
/* This is an LLC SAP value */ |
||
846 |
b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); |
||
847 |
gen_not(b0); |
||
848 |
b1 = gen_cmp(off_linktype + 2, BPF_B, (bpf_int32)proto); |
||
849 |
gen_and(b0, b1); |
||
850 |
return b1; |
||
851 |
} else { |
||
852 |
/* This is an Ethernet type */ |
||
853 |
6 |
return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); |
|
854 |
} |
||
855 |
break; |
||
856 |
|||
857 |
case DLT_SLIP: |
||
858 |
return gen_false(); |
||
859 |
|||
860 |
case DLT_PPP: |
||
861 |
case DLT_PPP_ETHER: |
||
862 |
if (proto == ETHERTYPE_IP) |
||
863 |
proto = PPP_IP; /* XXX was 0x21 */ |
||
864 |
#ifdef INET6 |
||
865 |
else if (proto == ETHERTYPE_IPV6) |
||
866 |
proto = PPP_IPV6; |
||
867 |
#endif |
||
868 |
break; |
||
869 |
|||
870 |
case DLT_PPP_BSDOS: |
||
871 |
switch (proto) { |
||
872 |
|||
873 |
case ETHERTYPE_IP: |
||
874 |
b0 = gen_cmp(off_linktype, BPF_H, PPP_IP); |
||
875 |
b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC); |
||
876 |
gen_or(b0, b1); |
||
877 |
b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC); |
||
878 |
gen_or(b1, b0); |
||
879 |
return b0; |
||
880 |
|||
881 |
#ifdef INET6 |
||
882 |
case ETHERTYPE_IPV6: |
||
883 |
proto = PPP_IPV6; |
||
884 |
/* more to go? */ |
||
885 |
break; |
||
886 |
#endif /* INET6 */ |
||
887 |
|||
888 |
case ETHERTYPE_DN: |
||
889 |
proto = PPP_DECNET; |
||
890 |
break; |
||
891 |
|||
892 |
case ETHERTYPE_ATALK: |
||
893 |
proto = PPP_APPLE; |
||
894 |
break; |
||
895 |
|||
896 |
case ETHERTYPE_NS: |
||
897 |
proto = PPP_NS; |
||
898 |
break; |
||
899 |
} |
||
900 |
break; |
||
901 |
|||
902 |
case DLT_LOOP: |
||
903 |
case DLT_ENC: |
||
904 |
case DLT_NULL: |
||
905 |
/* XXX */ |
||
906 |
if (proto == ETHERTYPE_IP) |
||
907 |
return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET))); |
||
908 |
#ifdef INET6 |
||
909 |
else if (proto == ETHERTYPE_IPV6) |
||
910 |
return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET6))); |
||
911 |
#endif /* INET6 */ |
||
912 |
else |
||
913 |
return gen_false(); |
||
914 |
break; |
||
915 |
case DLT_PFLOG: |
||
916 |
if (proto == ETHERTYPE_IP) |
||
917 |
return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, |
||
918 |
(bpf_int32)AF_INET)); |
||
919 |
#ifdef INET6 |
||
920 |
else if (proto == ETHERTYPE_IPV6) |
||
921 |
return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, |
||
922 |
(bpf_int32)AF_INET6)); |
||
923 |
#endif /* INET6 */ |
||
924 |
else |
||
925 |
return gen_false(); |
||
926 |
break; |
||
927 |
|||
928 |
} |
||
929 |
return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); |
||
930 |
6 |
} |
|
931 |
|||
932 |
static struct block * |
||
933 |
gen_hostop(addr, mask, dir, proto, src_off, dst_off) |
||
934 |
bpf_u_int32 addr; |
||
935 |
bpf_u_int32 mask; |
||
936 |
int dir, proto; |
||
937 |
u_int src_off, dst_off; |
||
938 |
{ |
||
939 |
struct block *b0, *b1; |
||
940 |
u_int offset; |
||
941 |
|||
942 |
switch (dir) { |
||
943 |
|||
944 |
case Q_SRC: |
||
945 |
offset = src_off; |
||
946 |
break; |
||
947 |
|||
948 |
case Q_DST: |
||
949 |
offset = dst_off; |
||
950 |
break; |
||
951 |
|||
952 |
case Q_AND: |
||
953 |
b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); |
||
954 |
b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); |
||
955 |
gen_and(b0, b1); |
||
956 |
return b1; |
||
957 |
|||
958 |
case Q_OR: |
||
959 |
case Q_DEFAULT: |
||
960 |
b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); |
||
961 |
b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); |
||
962 |
gen_or(b0, b1); |
||
963 |
return b1; |
||
964 |
|||
965 |
default: |
||
966 |
bpf_error("direction not supported on linktype 0x%x", |
||
967 |
linktype); |
||
968 |
} |
||
969 |
b0 = gen_linktype(proto); |
||
970 |
b1 = gen_mcmp_nl(offset, BPF_W, (bpf_int32)addr, mask); |
||
971 |
gen_and(b0, b1); |
||
972 |
return b1; |
||
973 |
} |
||
974 |
|||
975 |
#ifdef INET6 |
||
976 |
static struct block * |
||
977 |
gen_hostop6(addr, mask, dir, proto, src_off, dst_off) |
||
978 |
struct in6_addr *addr; |
||
979 |
struct in6_addr *mask; |
||
980 |
int dir, proto; |
||
981 |
u_int src_off, dst_off; |
||
982 |
{ |
||
983 |
struct block *b0, *b1; |
||
984 |
u_int offset; |
||
985 |
u_int32_t *a, *m; |
||
986 |
|||
987 |
switch (dir) { |
||
988 |
|||
989 |
case Q_SRC: |
||
990 |
offset = src_off; |
||
991 |
break; |
||
992 |
|||
993 |
case Q_DST: |
||
994 |
offset = dst_off; |
||
995 |
break; |
||
996 |
|||
997 |
case Q_AND: |
||
998 |
b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); |
||
999 |
b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); |
||
1000 |
gen_and(b0, b1); |
||
1001 |
return b1; |
||
1002 |
|||
1003 |
case Q_OR: |
||
1004 |
case Q_DEFAULT: |
||
1005 |
b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); |
||
1006 |
b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); |
||
1007 |
gen_or(b0, b1); |
||
1008 |
return b1; |
||
1009 |
|||
1010 |
default: |
||
1011 |
bpf_error("direction not supported on linktype 0x%x", |
||
1012 |
linktype); |
||
1013 |
} |
||
1014 |
/* this order is important */ |
||
1015 |
a = (u_int32_t *)addr; |
||
1016 |
m = (u_int32_t *)mask; |
||
1017 |
b1 = gen_mcmp_nl(offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); |
||
1018 |
b0 = gen_mcmp_nl(offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); |
||
1019 |
gen_and(b0, b1); |
||
1020 |
b0 = gen_mcmp_nl(offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); |
||
1021 |
gen_and(b0, b1); |
||
1022 |
b0 = gen_mcmp_nl(offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); |
||
1023 |
gen_and(b0, b1); |
||
1024 |
b0 = gen_linktype(proto); |
||
1025 |
gen_and(b0, b1); |
||
1026 |
return b1; |
||
1027 |
} |
||
1028 |
#endif /*INET6*/ |
||
1029 |
|||
1030 |
static struct block * |
||
1031 |
gen_ehostop(eaddr, dir) |
||
1032 |
const u_char *eaddr; |
||
1033 |
int dir; |
||
1034 |
{ |
||
1035 |
struct block *b0, *b1; |
||
1036 |
|||
1037 |
switch (dir) { |
||
1038 |
case Q_SRC: |
||
1039 |
return gen_bcmp(6, 6, eaddr); |
||
1040 |
|||
1041 |
case Q_DST: |
||
1042 |
return gen_bcmp(0, 6, eaddr); |
||
1043 |
|||
1044 |
case Q_AND: |
||
1045 |
b0 = gen_ehostop(eaddr, Q_SRC); |
||
1046 |
b1 = gen_ehostop(eaddr, Q_DST); |
||
1047 |
gen_and(b0, b1); |
||
1048 |
return b1; |
||
1049 |
|||
1050 |
case Q_DEFAULT: |
||
1051 |
case Q_OR: |
||
1052 |
b0 = gen_ehostop(eaddr, Q_SRC); |
||
1053 |
b1 = gen_ehostop(eaddr, Q_DST); |
||
1054 |
gen_or(b0, b1); |
||
1055 |
return b1; |
||
1056 |
default: |
||
1057 |
bpf_error("direction not supported on linktype 0x%x", |
||
1058 |
linktype); |
||
1059 |
} |
||
1060 |
/* NOTREACHED */ |
||
1061 |
} |
||
1062 |
|||
1063 |
/* |
||
1064 |
* Like gen_ehostop, but for DLT_FDDI |
||
1065 |
*/ |
||
1066 |
static struct block * |
||
1067 |
gen_fhostop(eaddr, dir) |
||
1068 |
const u_char *eaddr; |
||
1069 |
int dir; |
||
1070 |
{ |
||
1071 |
struct block *b0, *b1; |
||
1072 |
|||
1073 |
switch (dir) { |
||
1074 |
case Q_SRC: |
||
1075 |
#ifdef PCAP_FDDIPAD |
||
1076 |
return gen_bcmp(6 + 1 + pcap_fddipad, 6, eaddr); |
||
1077 |
#else |
||
1078 |
return gen_bcmp(6 + 1, 6, eaddr); |
||
1079 |
#endif |
||
1080 |
|||
1081 |
case Q_DST: |
||
1082 |
#ifdef PCAP_FDDIPAD |
||
1083 |
return gen_bcmp(0 + 1 + pcap_fddipad, 6, eaddr); |
||
1084 |
#else |
||
1085 |
return gen_bcmp(0 + 1, 6, eaddr); |
||
1086 |
#endif |
||
1087 |
|||
1088 |
case Q_AND: |
||
1089 |
b0 = gen_fhostop(eaddr, Q_SRC); |
||
1090 |
b1 = gen_fhostop(eaddr, Q_DST); |
||
1091 |
gen_and(b0, b1); |
||
1092 |
return b1; |
||
1093 |
|||
1094 |
case Q_DEFAULT: |
||
1095 |
case Q_OR: |
||
1096 |
b0 = gen_fhostop(eaddr, Q_SRC); |
||
1097 |
b1 = gen_fhostop(eaddr, Q_DST); |
||
1098 |
gen_or(b0, b1); |
||
1099 |
return b1; |
||
1100 |
default: |
||
1101 |
bpf_error("direction not supported on linktype 0x%x", |
||
1102 |
linktype); |
||
1103 |
} |
||
1104 |
/* NOTREACHED */ |
||
1105 |
} |
||
1106 |
|||
1107 |
/* |
||
1108 |
* This is quite tricky because there may be pad bytes in front of the |
||
1109 |
* DECNET header, and then there are two possible data packet formats that |
||
1110 |
* carry both src and dst addresses, plus 5 packet types in a format that |
||
1111 |
* carries only the src node, plus 2 types that use a different format and |
||
1112 |
* also carry just the src node. |
||
1113 |
* |
||
1114 |
* Yuck. |
||
1115 |
* |
||
1116 |
* Instead of doing those all right, we just look for data packets with |
||
1117 |
* 0 or 1 bytes of padding. If you want to look at other packets, that |
||
1118 |
* will require a lot more hacking. |
||
1119 |
* |
||
1120 |
* To add support for filtering on DECNET "areas" (network numbers) |
||
1121 |
* one would want to add a "mask" argument to this routine. That would |
||
1122 |
* make the filter even more inefficient, although one could be clever |
||
1123 |
* and not generate masking instructions if the mask is 0xFFFF. |
||
1124 |
*/ |
||
1125 |
static struct block * |
||
1126 |
gen_dnhostop(addr, dir, base_off) |
||
1127 |
bpf_u_int32 addr; |
||
1128 |
int dir; |
||
1129 |
u_int base_off; |
||
1130 |
{ |
||
1131 |
struct block *b0, *b1, *b2, *tmp; |
||
1132 |
u_int offset_lh; /* offset if long header is received */ |
||
1133 |
u_int offset_sh; /* offset if short header is received */ |
||
1134 |
|||
1135 |
switch (dir) { |
||
1136 |
|||
1137 |
case Q_DST: |
||
1138 |
offset_sh = 1; /* follows flags */ |
||
1139 |
offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ |
||
1140 |
break; |
||
1141 |
|||
1142 |
case Q_SRC: |
||
1143 |
offset_sh = 3; /* follows flags, dstnode */ |
||
1144 |
offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ |
||
1145 |
break; |
||
1146 |
|||
1147 |
case Q_AND: |
||
1148 |
/* Inefficient because we do our Calvinball dance twice */ |
||
1149 |
b0 = gen_dnhostop(addr, Q_SRC, base_off); |
||
1150 |
b1 = gen_dnhostop(addr, Q_DST, base_off); |
||
1151 |
gen_and(b0, b1); |
||
1152 |
return b1; |
||
1153 |
|||
1154 |
case Q_OR: |
||
1155 |
case Q_DEFAULT: |
||
1156 |
/* Inefficient because we do our Calvinball dance twice */ |
||
1157 |
b0 = gen_dnhostop(addr, Q_SRC, base_off); |
||
1158 |
b1 = gen_dnhostop(addr, Q_DST, base_off); |
||
1159 |
gen_or(b0, b1); |
||
1160 |
return b1; |
||
1161 |
|||
1162 |
default: |
||
1163 |
bpf_error("direction not supported on linktype 0x%x", |
||
1164 |
linktype); |
||
1165 |
} |
||
1166 |
b0 = gen_linktype(ETHERTYPE_DN); |
||
1167 |
/* Check for pad = 1, long header case */ |
||
1168 |
tmp = gen_mcmp_nl(base_off + 2, BPF_H, |
||
1169 |
(bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); |
||
1170 |
b1 = gen_cmp_nl(base_off + 2 + 1 + offset_lh, |
||
1171 |
BPF_H, (bpf_int32)ntohs(addr)); |
||
1172 |
gen_and(tmp, b1); |
||
1173 |
/* Check for pad = 0, long header case */ |
||
1174 |
tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); |
||
1175 |
b2 = gen_cmp_nl(base_off + 2 + offset_lh, BPF_H, (bpf_int32)ntohs(addr)); |
||
1176 |
gen_and(tmp, b2); |
||
1177 |
gen_or(b2, b1); |
||
1178 |
/* Check for pad = 1, short header case */ |
||
1179 |
tmp = gen_mcmp_nl(base_off + 2, BPF_H, |
||
1180 |
(bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); |
||
1181 |
b2 = gen_cmp_nl(base_off + 2 + 1 + offset_sh, |
||
1182 |
BPF_H, (bpf_int32)ntohs(addr)); |
||
1183 |
gen_and(tmp, b2); |
||
1184 |
gen_or(b2, b1); |
||
1185 |
/* Check for pad = 0, short header case */ |
||
1186 |
tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); |
||
1187 |
b2 = gen_cmp_nl(base_off + 2 + offset_sh, BPF_H, (bpf_int32)ntohs(addr)); |
||
1188 |
gen_and(tmp, b2); |
||
1189 |
gen_or(b2, b1); |
||
1190 |
|||
1191 |
/* Combine with test for linktype */ |
||
1192 |
gen_and(b0, b1); |
||
1193 |
return b1; |
||
1194 |
} |
||
1195 |
|||
1196 |
static struct block * |
||
1197 |
gen_host(addr, mask, proto, dir) |
||
1198 |
bpf_u_int32 addr; |
||
1199 |
bpf_u_int32 mask; |
||
1200 |
int proto; |
||
1201 |
int dir; |
||
1202 |
{ |
||
1203 |
struct block *b0, *b1; |
||
1204 |
|||
1205 |
switch (proto) { |
||
1206 |
|||
1207 |
case Q_DEFAULT: |
||
1208 |
b0 = gen_host(addr, mask, Q_IP, dir); |
||
1209 |
b1 = gen_host(addr, mask, Q_ARP, dir); |
||
1210 |
gen_or(b0, b1); |
||
1211 |
b0 = gen_host(addr, mask, Q_RARP, dir); |
||
1212 |
gen_or(b1, b0); |
||
1213 |
return b0; |
||
1214 |
|||
1215 |
case Q_IP: |
||
1216 |
return gen_hostop(addr, mask, dir, ETHERTYPE_IP, |
||
1217 |
12, 16); |
||
1218 |
|||
1219 |
case Q_RARP: |
||
1220 |
return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, |
||
1221 |
14, 24); |
||
1222 |
|||
1223 |
case Q_ARP: |
||
1224 |
return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, |
||
1225 |
14, 24); |
||
1226 |
|||
1227 |
case Q_TCP: |
||
1228 |
bpf_error("'tcp' modifier applied to host"); |
||
1229 |
|||
1230 |
case Q_UDP: |
||
1231 |
bpf_error("'udp' modifier applied to host"); |
||
1232 |
|||
1233 |
case Q_ICMP: |
||
1234 |
bpf_error("'icmp' modifier applied to host"); |
||
1235 |
|||
1236 |
case Q_IGMP: |
||
1237 |
bpf_error("'igmp' modifier applied to host"); |
||
1238 |
|||
1239 |
case Q_IGRP: |
||
1240 |
bpf_error("'igrp' modifier applied to host"); |
||
1241 |
|||
1242 |
case Q_PIM: |
||
1243 |
bpf_error("'pim' modifier applied to host"); |
||
1244 |
|||
1245 |
case Q_STP: |
||
1246 |
bpf_error("'stp' modifier applied to host"); |
||
1247 |
|||
1248 |
case Q_ATALK: |
||
1249 |
bpf_error("ATALK host filtering not implemented"); |
||
1250 |
|||
1251 |
case Q_DECNET: |
||
1252 |
return gen_dnhostop(addr, dir, 0); |
||
1253 |
|||
1254 |
case Q_SCA: |
||
1255 |
bpf_error("SCA host filtering not implemented"); |
||
1256 |
|||
1257 |
case Q_LAT: |
||
1258 |
bpf_error("LAT host filtering not implemented"); |
||
1259 |
|||
1260 |
case Q_MOPDL: |
||
1261 |
bpf_error("MOPDL host filtering not implemented"); |
||
1262 |
|||
1263 |
case Q_MOPRC: |
||
1264 |
bpf_error("MOPRC host filtering not implemented"); |
||
1265 |
|||
1266 |
#ifdef INET6 |
||
1267 |
case Q_IPV6: |
||
1268 |
bpf_error("'ip6' modifier applied to ip host"); |
||
1269 |
|||
1270 |
case Q_ICMPV6: |
||
1271 |
bpf_error("'icmp6' modifier applied to host"); |
||
1272 |
#endif /* INET6 */ |
||
1273 |
|||
1274 |
case Q_AH: |
||
1275 |
bpf_error("'ah' modifier applied to host"); |
||
1276 |
|||
1277 |
case Q_ESP: |
||
1278 |
bpf_error("'esp' modifier applied to host"); |
||
1279 |
|||
1280 |
default: |
||
1281 |
bpf_error("direction not supported on linktype 0x%x", |
||
1282 |
linktype); |
||
1283 |
} |
||
1284 |
/* NOTREACHED */ |
||
1285 |
} |
||
1286 |
|||
1287 |
#ifdef INET6 |
||
1288 |
static struct block * |
||
1289 |
gen_host6(addr, mask, proto, dir) |
||
1290 |
struct in6_addr *addr; |
||
1291 |
struct in6_addr *mask; |
||
1292 |
int proto; |
||
1293 |
int dir; |
||
1294 |
{ |
||
1295 |
switch (proto) { |
||
1296 |
|||
1297 |
case Q_DEFAULT: |
||
1298 |
return gen_host6(addr, mask, Q_IPV6, dir); |
||
1299 |
|||
1300 |
case Q_IP: |
||
1301 |
bpf_error("'ip' modifier applied to ip6 host"); |
||
1302 |
|||
1303 |
case Q_RARP: |
||
1304 |
bpf_error("'rarp' modifier applied to ip6 host"); |
||
1305 |
|||
1306 |
case Q_ARP: |
||
1307 |
bpf_error("'arp' modifier applied to ip6 host"); |
||
1308 |
|||
1309 |
case Q_TCP: |
||
1310 |
bpf_error("'tcp' modifier applied to host"); |
||
1311 |
|||
1312 |
case Q_UDP: |
||
1313 |
bpf_error("'udp' modifier applied to host"); |
||
1314 |
|||
1315 |
case Q_ICMP: |
||
1316 |
bpf_error("'icmp' modifier applied to host"); |
||
1317 |
|||
1318 |
case Q_IGMP: |
||
1319 |
bpf_error("'igmp' modifier applied to host"); |
||
1320 |
|||
1321 |
case Q_IGRP: |
||
1322 |
bpf_error("'igrp' modifier applied to host"); |
||
1323 |
|||
1324 |
case Q_PIM: |
||
1325 |
bpf_error("'pim' modifier applied to host"); |
||
1326 |
|||
1327 |
case Q_STP: |
||
1328 |
bpf_error("'stp' modifier applied to host"); |
||
1329 |
|||
1330 |
case Q_ATALK: |
||
1331 |
bpf_error("ATALK host filtering not implemented"); |
||
1332 |
|||
1333 |
case Q_DECNET: |
||
1334 |
bpf_error("'decnet' modifier applied to ip6 host"); |
||
1335 |
|||
1336 |
case Q_SCA: |
||
1337 |
bpf_error("SCA host filtering not implemented"); |
||
1338 |
|||
1339 |
case Q_LAT: |
||
1340 |
bpf_error("LAT host filtering not implemented"); |
||
1341 |
|||
1342 |
case Q_MOPDL: |
||
1343 |
bpf_error("MOPDL host filtering not implemented"); |
||
1344 |
|||
1345 |
case Q_MOPRC: |
||
1346 |
bpf_error("MOPRC host filtering not implemented"); |
||
1347 |
|||
1348 |
case Q_IPV6: |
||
1349 |
return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, |
||
1350 |
8, 24); |
||
1351 |
|||
1352 |
case Q_ICMPV6: |
||
1353 |
bpf_error("'icmp6' modifier applied to host"); |
||
1354 |
|||
1355 |
case Q_AH: |
||
1356 |
bpf_error("'ah' modifier applied to host"); |
||
1357 |
|||
1358 |
case Q_ESP: |
||
1359 |
bpf_error("'esp' modifier applied to host"); |
||
1360 |
|||
1361 |
default: |
||
1362 |
abort(); |
||
1363 |
} |
||
1364 |
/* NOTREACHED */ |
||
1365 |
} |
||
1366 |
#endif /*INET6*/ |
||
1367 |
|||
1368 |
#ifndef INET6 |
||
1369 |
static struct block * |
||
1370 |
gen_gateway(eaddr, alist, proto, dir) |
||
1371 |
const u_char *eaddr; |
||
1372 |
bpf_u_int32 **alist; |
||
1373 |
int proto; |
||
1374 |
int dir; |
||
1375 |
{ |
||
1376 |
struct block *b0, *b1, *tmp; |
||
1377 |
|||
1378 |
if (dir != 0) |
||
1379 |
bpf_error("direction applied to 'gateway'"); |
||
1380 |
|||
1381 |
switch (proto) { |
||
1382 |
case Q_DEFAULT: |
||
1383 |
case Q_IP: |
||
1384 |
case Q_ARP: |
||
1385 |
case Q_RARP: |
||
1386 |
if (linktype == DLT_EN10MB) |
||
1387 |
b0 = gen_ehostop(eaddr, Q_OR); |
||
1388 |
else if (linktype == DLT_FDDI) |
||
1389 |
b0 = gen_fhostop(eaddr, Q_OR); |
||
1390 |
else |
||
1391 |
bpf_error( |
||
1392 |
"'gateway' supported only on ethernet or FDDI"); |
||
1393 |
|||
1394 |
b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR); |
||
1395 |
while (*alist) { |
||
1396 |
tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR); |
||
1397 |
gen_or(b1, tmp); |
||
1398 |
b1 = tmp; |
||
1399 |
} |
||
1400 |
gen_not(b1); |
||
1401 |
gen_and(b0, b1); |
||
1402 |
return b1; |
||
1403 |
} |
||
1404 |
bpf_error("illegal modifier of 'gateway'"); |
||
1405 |
/* NOTREACHED */ |
||
1406 |
} |
||
1407 |
#endif /*INET6*/ |
||
1408 |
|||
1409 |
struct block * |
||
1410 |
gen_proto_abbrev(proto) |
||
1411 |
int proto; |
||
1412 |
{ |
||
1413 |
struct block *b0 = NULL, *b1; |
||
1414 |
|||
1415 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✓✗ ✗✗ |
12 |
switch (proto) { |
1416 |
|||
1417 |
case Q_TCP: |
||
1418 |
b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT); |
||
1419 |
#ifdef INET6 |
||
1420 |
b0 = gen_proto(IPPROTO_TCP, Q_IPV6, Q_DEFAULT); |
||
1421 |
gen_or(b0, b1); |
||
1422 |
#endif |
||
1423 |
break; |
||
1424 |
|||
1425 |
case Q_UDP: |
||
1426 |
b1 = gen_proto(IPPROTO_UDP, Q_IP, Q_DEFAULT); |
||
1427 |
#ifdef INET6 |
||
1428 |
b0 = gen_proto(IPPROTO_UDP, Q_IPV6, Q_DEFAULT); |
||
1429 |
gen_or(b0, b1); |
||
1430 |
#endif |
||
1431 |
break; |
||
1432 |
|||
1433 |
case Q_ICMP: |
||
1434 |
b1 = gen_proto(IPPROTO_ICMP, Q_IP, Q_DEFAULT); |
||
1435 |
break; |
||
1436 |
|||
1437 |
#ifndef IPPROTO_IGMP |
||
1438 |
#define IPPROTO_IGMP 2 |
||
1439 |
#endif |
||
1440 |
|||
1441 |
case Q_IGMP: |
||
1442 |
b1 = gen_proto(IPPROTO_IGMP, Q_IP, Q_DEFAULT); |
||
1443 |
break; |
||
1444 |
|||
1445 |
#ifndef IPPROTO_IGRP |
||
1446 |
#define IPPROTO_IGRP 9 |
||
1447 |
#endif |
||
1448 |
case Q_IGRP: |
||
1449 |
b1 = gen_proto(IPPROTO_IGRP, Q_IP, Q_DEFAULT); |
||
1450 |
break; |
||
1451 |
|||
1452 |
#ifndef IPPROTO_PIM |
||
1453 |
#define IPPROTO_PIM 103 |
||
1454 |
#endif |
||
1455 |
|||
1456 |
case Q_PIM: |
||
1457 |
b1 = gen_proto(IPPROTO_PIM, Q_IP, Q_DEFAULT); |
||
1458 |
#ifdef INET6 |
||
1459 |
b0 = gen_proto(IPPROTO_PIM, Q_IPV6, Q_DEFAULT); |
||
1460 |
gen_or(b0, b1); |
||
1461 |
#endif |
||
1462 |
break; |
||
1463 |
|||
1464 |
case Q_IP: |
||
1465 |
b1 = gen_linktype(ETHERTYPE_IP); |
||
1466 |
break; |
||
1467 |
|||
1468 |
case Q_ARP: |
||
1469 |
b1 = gen_linktype(ETHERTYPE_ARP); |
||
1470 |
break; |
||
1471 |
|||
1472 |
case Q_RARP: |
||
1473 |
b1 = gen_linktype(ETHERTYPE_REVARP); |
||
1474 |
break; |
||
1475 |
|||
1476 |
case Q_LINK: |
||
1477 |
bpf_error("link layer applied in wrong context"); |
||
1478 |
|||
1479 |
case Q_ATALK: |
||
1480 |
b1 = gen_linktype(ETHERTYPE_ATALK); |
||
1481 |
break; |
||
1482 |
|||
1483 |
case Q_DECNET: |
||
1484 |
b1 = gen_linktype(ETHERTYPE_DN); |
||
1485 |
break; |
||
1486 |
|||
1487 |
case Q_SCA: |
||
1488 |
b1 = gen_linktype(ETHERTYPE_SCA); |
||
1489 |
break; |
||
1490 |
|||
1491 |
case Q_LAT: |
||
1492 |
b1 = gen_linktype(ETHERTYPE_LAT); |
||
1493 |
break; |
||
1494 |
|||
1495 |
case Q_MOPDL: |
||
1496 |
b1 = gen_linktype(ETHERTYPE_MOPDL); |
||
1497 |
break; |
||
1498 |
|||
1499 |
case Q_MOPRC: |
||
1500 |
b1 = gen_linktype(ETHERTYPE_MOPRC); |
||
1501 |
break; |
||
1502 |
|||
1503 |
case Q_STP: |
||
1504 |
b1 = gen_linktype(LLCSAP_8021D); |
||
1505 |
break; |
||
1506 |
|||
1507 |
#ifdef INET6 |
||
1508 |
case Q_IPV6: |
||
1509 |
3 |
b1 = gen_linktype(ETHERTYPE_IPV6); |
|
1510 |
3 |
break; |
|
1511 |
|||
1512 |
#ifndef IPPROTO_ICMPV6 |
||
1513 |
#define IPPROTO_ICMPV6 58 |
||
1514 |
#endif |
||
1515 |
case Q_ICMPV6: |
||
1516 |
3 |
b1 = gen_proto(IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); |
|
1517 |
3 |
break; |
|
1518 |
#endif /* INET6 */ |
||
1519 |
|||
1520 |
#ifndef IPPROTO_AH |
||
1521 |
#define IPPROTO_AH 51 |
||
1522 |
#endif |
||
1523 |
case Q_AH: |
||
1524 |
b1 = gen_proto(IPPROTO_AH, Q_IP, Q_DEFAULT); |
||
1525 |
#ifdef INET6 |
||
1526 |
b0 = gen_proto(IPPROTO_AH, Q_IPV6, Q_DEFAULT); |
||
1527 |
gen_or(b0, b1); |
||
1528 |
#endif |
||
1529 |
break; |
||
1530 |
|||
1531 |
#ifndef IPPROTO_ESP |
||
1532 |
#define IPPROTO_ESP 50 |
||
1533 |
#endif |
||
1534 |
case Q_ESP: |
||
1535 |
b1 = gen_proto(IPPROTO_ESP, Q_IP, Q_DEFAULT); |
||
1536 |
#ifdef INET6 |
||
1537 |
b0 = gen_proto(IPPROTO_ESP, Q_IPV6, Q_DEFAULT); |
||
1538 |
gen_or(b0, b1); |
||
1539 |
#endif |
||
1540 |
break; |
||
1541 |
|||
1542 |
default: |
||
1543 |
abort(); |
||
1544 |
} |
||
1545 |
6 |
return b1; |
|
1546 |
} |
||
1547 |
|||
1548 |
static struct block * |
||
1549 |
gen_ipfrag() |
||
1550 |
{ |
||
1551 |
struct slist *s, *tmp; |
||
1552 |
struct block *b; |
||
1553 |
|||
1554 |
/* not ip frag */ |
||
1555 |
if (variable_nl) { |
||
1556 |
s = nl2X_stmt(); |
||
1557 |
tmp = new_stmt(BPF_LD|BPF_H|BPF_IND); |
||
1558 |
tmp->s.k = 6; |
||
1559 |
sappend(s, tmp); |
||
1560 |
} else { |
||
1561 |
s = new_stmt(BPF_LD|BPF_H|BPF_ABS); |
||
1562 |
s->s.k = off_nl + 6; |
||
1563 |
} |
||
1564 |
b = new_block(JMP(BPF_JSET)); |
||
1565 |
b->s.k = 0x1fff; |
||
1566 |
b->stmts = s; |
||
1567 |
gen_not(b); |
||
1568 |
|||
1569 |
return b; |
||
1570 |
} |
||
1571 |
|||
1572 |
/* For dynamic off_nl, the BPF_LDX|BPF_MSH instruction does not work |
||
1573 |
This function generates code to set X to the start of the IP payload |
||
1574 |
X = off_nl + IP header_len. |
||
1575 |
*/ |
||
1576 |
static struct slist * |
||
1577 |
iphl_to_x(void) |
||
1578 |
{ |
||
1579 |
struct slist *s, *tmp; |
||
1580 |
|||
1581 |
/* XXX clobbers A if variable_nl*/ |
||
1582 |
if (variable_nl) { |
||
1583 |
if (iphl_reg == -1) { |
||
1584 |
/* X <- off_nl */ |
||
1585 |
s = nl2X_stmt(); |
||
1586 |
|||
1587 |
/* A = p[X+0] */ |
||
1588 |
tmp = new_stmt(BPF_LD|BPF_B|BPF_IND); |
||
1589 |
tmp->s.k = 0; |
||
1590 |
sappend(s, tmp); |
||
1591 |
|||
1592 |
/* A = A & 0x0f */ |
||
1593 |
tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K); |
||
1594 |
tmp->s.k = 0x0f; |
||
1595 |
sappend(s, tmp); |
||
1596 |
|||
1597 |
/* A = A << 2 */ |
||
1598 |
tmp = new_stmt(BPF_ALU|BPF_LSH|BPF_K); |
||
1599 |
tmp->s.k = 2; |
||
1600 |
sappend(s, tmp); |
||
1601 |
|||
1602 |
/* A = A + X (add off_nl again to compansate) */ |
||
1603 |
sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); |
||
1604 |
|||
1605 |
/* MEM[iphl_reg] = A */ |
||
1606 |
iphl_reg = alloc_reg(); |
||
1607 |
tmp = new_stmt(BPF_ST); |
||
1608 |
tmp->s.k = iphl_reg; |
||
1609 |
sappend(s, tmp); |
||
1610 |
|||
1611 |
sappend(init_code, s); |
||
1612 |
} |
||
1613 |
s = new_stmt(BPF_LDX|BPF_MEM); |
||
1614 |
s->s.k = iphl_reg; |
||
1615 |
|||
1616 |
} else { |
||
1617 |
s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); |
||
1618 |
s->s.k = off_nl; |
||
1619 |
} |
||
1620 |
|||
1621 |
return s; |
||
1622 |
} |
||
1623 |
|||
1624 |
static struct block * |
||
1625 |
gen_portatom(off, v) |
||
1626 |
int off; |
||
1627 |
bpf_int32 v; |
||
1628 |
{ |
||
1629 |
struct slist *s, *tmp; |
||
1630 |
struct block *b; |
||
1631 |
|||
1632 |
s = iphl_to_x(); |
||
1633 |
|||
1634 |
tmp = new_stmt(BPF_LD|BPF_IND|BPF_H); |
||
1635 |
tmp->s.k = off_nl + off; /* off_nl == 0 if variable_nl */ |
||
1636 |
sappend(s, tmp); |
||
1637 |
|||
1638 |
b = new_block(JMP(BPF_JEQ)); |
||
1639 |
b->stmts = s; |
||
1640 |
b->s.k = v; |
||
1641 |
|||
1642 |
return b; |
||
1643 |
} |
||
1644 |
|||
1645 |
#ifdef INET6 |
||
1646 |
static struct block * |
||
1647 |
gen_portatom6(off, v) |
||
1648 |
int off; |
||
1649 |
bpf_int32 v; |
||
1650 |
{ |
||
1651 |
return gen_cmp_nl(40 + off, BPF_H, v); |
||
1652 |
} |
||
1653 |
#endif/*INET6*/ |
||
1654 |
|||
1655 |
struct block * |
||
1656 |
gen_portop(port, proto, dir) |
||
1657 |
int port, proto, dir; |
||
1658 |
{ |
||
1659 |
struct block *b0, *b1, *tmp; |
||
1660 |
|||
1661 |
/* ip proto 'proto' */ |
||
1662 |
tmp = gen_cmp_nl(9, BPF_B, (bpf_int32)proto); |
||
1663 |
b0 = gen_ipfrag(); |
||
1664 |
gen_and(tmp, b0); |
||
1665 |
|||
1666 |
switch (dir) { |
||
1667 |
case Q_SRC: |
||
1668 |
b1 = gen_portatom(0, (bpf_int32)port); |
||
1669 |
break; |
||
1670 |
|||
1671 |
case Q_DST: |
||
1672 |
b1 = gen_portatom(2, (bpf_int32)port); |
||
1673 |
break; |
||
1674 |
|||
1675 |
case Q_OR: |
||
1676 |
case Q_DEFAULT: |
||
1677 |
tmp = gen_portatom(0, (bpf_int32)port); |
||
1678 |
b1 = gen_portatom(2, (bpf_int32)port); |
||
1679 |
gen_or(tmp, b1); |
||
1680 |
break; |
||
1681 |
|||
1682 |
case Q_AND: |
||
1683 |
tmp = gen_portatom(0, (bpf_int32)port); |
||
1684 |
b1 = gen_portatom(2, (bpf_int32)port); |
||
1685 |
gen_and(tmp, b1); |
||
1686 |
break; |
||
1687 |
|||
1688 |
default: |
||
1689 |
abort(); |
||
1690 |
} |
||
1691 |
gen_and(b0, b1); |
||
1692 |
|||
1693 |
return b1; |
||
1694 |
} |
||
1695 |
|||
1696 |
static struct block * |
||
1697 |
gen_port(port, ip_proto, dir) |
||
1698 |
int port; |
||
1699 |
int ip_proto; |
||
1700 |
int dir; |
||
1701 |
{ |
||
1702 |
struct block *b0, *b1, *tmp; |
||
1703 |
|||
1704 |
/* ether proto ip */ |
||
1705 |
b0 = gen_linktype(ETHERTYPE_IP); |
||
1706 |
|||
1707 |
switch (ip_proto) { |
||
1708 |
case IPPROTO_UDP: |
||
1709 |
case IPPROTO_TCP: |
||
1710 |
b1 = gen_portop(port, ip_proto, dir); |
||
1711 |
break; |
||
1712 |
|||
1713 |
case PROTO_UNDEF: |
||
1714 |
tmp = gen_portop(port, IPPROTO_TCP, dir); |
||
1715 |
b1 = gen_portop(port, IPPROTO_UDP, dir); |
||
1716 |
gen_or(tmp, b1); |
||
1717 |
break; |
||
1718 |
|||
1719 |
default: |
||
1720 |
abort(); |
||
1721 |
} |
||
1722 |
gen_and(b0, b1); |
||
1723 |
return b1; |
||
1724 |
} |
||
1725 |
|||
1726 |
#ifdef INET6 |
||
1727 |
struct block * |
||
1728 |
gen_portop6(port, proto, dir) |
||
1729 |
int port, proto, dir; |
||
1730 |
{ |
||
1731 |
struct block *b0, *b1, *tmp; |
||
1732 |
|||
1733 |
/* ip proto 'proto' */ |
||
1734 |
b0 = gen_cmp_nl(6, BPF_B, (bpf_int32)proto); |
||
1735 |
|||
1736 |
switch (dir) { |
||
1737 |
case Q_SRC: |
||
1738 |
b1 = gen_portatom6(0, (bpf_int32)port); |
||
1739 |
break; |
||
1740 |
|||
1741 |
case Q_DST: |
||
1742 |
b1 = gen_portatom6(2, (bpf_int32)port); |
||
1743 |
break; |
||
1744 |
|||
1745 |
case Q_OR: |
||
1746 |
case Q_DEFAULT: |
||
1747 |
tmp = gen_portatom6(0, (bpf_int32)port); |
||
1748 |
b1 = gen_portatom6(2, (bpf_int32)port); |
||
1749 |
gen_or(tmp, b1); |
||
1750 |
break; |
||
1751 |
|||
1752 |
case Q_AND: |
||
1753 |
tmp = gen_portatom6(0, (bpf_int32)port); |
||
1754 |
b1 = gen_portatom6(2, (bpf_int32)port); |
||
1755 |
gen_and(tmp, b1); |
||
1756 |
break; |
||
1757 |
|||
1758 |
default: |
||
1759 |
abort(); |
||
1760 |
} |
||
1761 |
gen_and(b0, b1); |
||
1762 |
|||
1763 |
return b1; |
||
1764 |
} |
||
1765 |
|||
1766 |
static struct block * |
||
1767 |
gen_port6(port, ip_proto, dir) |
||
1768 |
int port; |
||
1769 |
int ip_proto; |
||
1770 |
int dir; |
||
1771 |
{ |
||
1772 |
struct block *b0, *b1, *tmp; |
||
1773 |
|||
1774 |
/* ether proto ip */ |
||
1775 |
b0 = gen_linktype(ETHERTYPE_IPV6); |
||
1776 |
|||
1777 |
switch (ip_proto) { |
||
1778 |
case IPPROTO_UDP: |
||
1779 |
case IPPROTO_TCP: |
||
1780 |
b1 = gen_portop6(port, ip_proto, dir); |
||
1781 |
break; |
||
1782 |
|||
1783 |
case PROTO_UNDEF: |
||
1784 |
tmp = gen_portop6(port, IPPROTO_TCP, dir); |
||
1785 |
b1 = gen_portop6(port, IPPROTO_UDP, dir); |
||
1786 |
gen_or(tmp, b1); |
||
1787 |
break; |
||
1788 |
|||
1789 |
default: |
||
1790 |
abort(); |
||
1791 |
} |
||
1792 |
gen_and(b0, b1); |
||
1793 |
return b1; |
||
1794 |
} |
||
1795 |
#endif /* INET6 */ |
||
1796 |
|||
1797 |
static int |
||
1798 |
lookup_proto(name, proto) |
||
1799 |
const char *name; |
||
1800 |
int proto; |
||
1801 |
{ |
||
1802 |
int v; |
||
1803 |
|||
1804 |
switch (proto) { |
||
1805 |
|||
1806 |
case Q_DEFAULT: |
||
1807 |
case Q_IP: |
||
1808 |
v = pcap_nametoproto(name); |
||
1809 |
if (v == PROTO_UNDEF) |
||
1810 |
bpf_error("unknown ip proto '%s'", name); |
||
1811 |
break; |
||
1812 |
|||
1813 |
case Q_LINK: |
||
1814 |
/* XXX should look up h/w protocol type based on linktype */ |
||
1815 |
v = pcap_nametoeproto(name); |
||
1816 |
if (v == PROTO_UNDEF) { |
||
1817 |
v = pcap_nametollc(name); |
||
1818 |
if (v == PROTO_UNDEF) |
||
1819 |
bpf_error("unknown ether proto '%s'", name); |
||
1820 |
} |
||
1821 |
break; |
||
1822 |
|||
1823 |
default: |
||
1824 |
v = PROTO_UNDEF; |
||
1825 |
break; |
||
1826 |
} |
||
1827 |
return v; |
||
1828 |
} |
||
1829 |
|||
1830 |
static struct block * |
||
1831 |
gen_protochain(v, proto, dir) |
||
1832 |
int v; |
||
1833 |
int proto; |
||
1834 |
int dir; |
||
1835 |
{ |
||
1836 |
struct block *b0, *b; |
||
1837 |
struct slist *s[100]; |
||
1838 |
int fix2, fix3, fix4, fix5; |
||
1839 |
int ahcheck, again, end; |
||
1840 |
int i, max; |
||
1841 |
int reg1 = alloc_reg(); |
||
1842 |
int reg2 = alloc_reg(); |
||
1843 |
|||
1844 |
memset(s, 0, sizeof(s)); |
||
1845 |
fix2 = fix3 = fix4 = fix5 = 0; |
||
1846 |
|||
1847 |
if (variable_nl) { |
||
1848 |
bpf_error("'gen_protochain' not supported for variable DLTs"); |
||
1849 |
/*NOTREACHED*/ |
||
1850 |
} |
||
1851 |
|||
1852 |
switch (proto) { |
||
1853 |
case Q_IP: |
||
1854 |
case Q_IPV6: |
||
1855 |
break; |
||
1856 |
case Q_DEFAULT: |
||
1857 |
b0 = gen_protochain(v, Q_IP, dir); |
||
1858 |
b = gen_protochain(v, Q_IPV6, dir); |
||
1859 |
gen_or(b0, b); |
||
1860 |
return b; |
||
1861 |
default: |
||
1862 |
bpf_error("bad protocol applied for 'protochain'"); |
||
1863 |
/*NOTREACHED*/ |
||
1864 |
} |
||
1865 |
|||
1866 |
no_optimize = 1; /*this code is not compatible with optimzer yet */ |
||
1867 |
|||
1868 |
/* |
||
1869 |
* s[0] is a dummy entry to protect other BPF insn from damaged |
||
1870 |
* by s[fix] = foo with uninitialized variable "fix". It is somewhat |
||
1871 |
* hard to find interdependency made by jump table fixup. |
||
1872 |
*/ |
||
1873 |
i = 0; |
||
1874 |
s[i] = new_stmt(0); /*dummy*/ |
||
1875 |
i++; |
||
1876 |
|||
1877 |
switch (proto) { |
||
1878 |
case Q_IP: |
||
1879 |
b0 = gen_linktype(ETHERTYPE_IP); |
||
1880 |
|||
1881 |
/* A = ip->ip_p */ |
||
1882 |
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); |
||
1883 |
s[i]->s.k = off_nl + 9; |
||
1884 |
i++; |
||
1885 |
/* X = ip->ip_hl << 2 */ |
||
1886 |
s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); |
||
1887 |
s[i]->s.k = off_nl; |
||
1888 |
i++; |
||
1889 |
break; |
||
1890 |
case Q_IPV6: |
||
1891 |
b0 = gen_linktype(ETHERTYPE_IPV6); |
||
1892 |
|||
1893 |
/* A = ip6->ip_nxt */ |
||
1894 |
s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); |
||
1895 |
s[i]->s.k = off_nl + 6; |
||
1896 |
i++; |
||
1897 |
/* X = sizeof(struct ip6_hdr) */ |
||
1898 |
s[i] = new_stmt(BPF_LDX|BPF_IMM); |
||
1899 |
s[i]->s.k = 40; |
||
1900 |
i++; |
||
1901 |
break; |
||
1902 |
default: |
||
1903 |
bpf_error("unsupported proto to gen_protochain"); |
||
1904 |
/*NOTREACHED*/ |
||
1905 |
} |
||
1906 |
|||
1907 |
/* again: if (A == v) goto end; else fall through; */ |
||
1908 |
again = i; |
||
1909 |
s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1910 |
s[i]->s.k = v; |
||
1911 |
s[i]->s.jt = NULL; /*later*/ |
||
1912 |
s[i]->s.jf = NULL; /*update in next stmt*/ |
||
1913 |
fix5 = i; |
||
1914 |
i++; |
||
1915 |
|||
1916 |
/* if (A == IPPROTO_NONE) goto end */ |
||
1917 |
s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1918 |
s[i]->s.jt = NULL; /*later*/ |
||
1919 |
s[i]->s.jf = NULL; /*update in next stmt*/ |
||
1920 |
s[i]->s.k = IPPROTO_NONE; |
||
1921 |
s[fix5]->s.jf = s[i]; |
||
1922 |
fix2 = i; |
||
1923 |
i++; |
||
1924 |
|||
1925 |
if (proto == Q_IPV6) { |
||
1926 |
int v6start, v6end, v6advance, j; |
||
1927 |
|||
1928 |
v6start = i; |
||
1929 |
/* if (A == IPPROTO_HOPOPTS) goto v6advance */ |
||
1930 |
s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1931 |
s[i]->s.jt = NULL; /*later*/ |
||
1932 |
s[i]->s.jf = NULL; /*update in next stmt*/ |
||
1933 |
s[i]->s.k = IPPROTO_HOPOPTS; |
||
1934 |
s[fix2]->s.jf = s[i]; |
||
1935 |
i++; |
||
1936 |
/* if (A == IPPROTO_DSTOPTS) goto v6advance */ |
||
1937 |
s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1938 |
s[i]->s.jt = NULL; /*later*/ |
||
1939 |
s[i]->s.jf = NULL; /*update in next stmt*/ |
||
1940 |
s[i]->s.k = IPPROTO_DSTOPTS; |
||
1941 |
i++; |
||
1942 |
/* if (A == IPPROTO_ROUTING) goto v6advance */ |
||
1943 |
s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1944 |
s[i]->s.jt = NULL; /*later*/ |
||
1945 |
s[i]->s.jf = NULL; /*update in next stmt*/ |
||
1946 |
s[i]->s.k = IPPROTO_ROUTING; |
||
1947 |
i++; |
||
1948 |
/* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ |
||
1949 |
s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
1950 |
s[i]->s.jt = NULL; /*later*/ |
||
1951 |
s[i]->s.jf = NULL; /*later*/ |
||
1952 |
s[i]->s.k = IPPROTO_FRAGMENT; |
||
1953 |
fix3 = i; |
||
1954 |
v6end = i; |
||
1955 |
i++; |
||
1956 |
|||
1957 |
/* v6advance: */ |
||
1958 |
v6advance = i; |
||
1959 |
|||
1960 |
/* |
||
1961 |
* in short, |
||
1962 |
* A = P[X + 1]; |
||
1963 |
* X = X + (P[X] + 1) * 8; |
||
1964 |
*/ |
||
1965 |
/* A = X */ |
||
1966 |
s[i] = new_stmt(BPF_MISC|BPF_TXA); |
||
1967 |
i++; |
||
1968 |
/* MEM[reg1] = A */ |
||
1969 |
s[i] = new_stmt(BPF_ST); |
||
1970 |
s[i]->s.k = reg1; |
||
1971 |
i++; |
||
1972 |
/* A += 1 */ |
||
1973 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
1974 |
s[i]->s.k = 1; |
||
1975 |
i++; |
||
1976 |
/* X = A */ |
||
1977 |
s[i] = new_stmt(BPF_MISC|BPF_TAX); |
||
1978 |
i++; |
||
1979 |
/* A = P[X + packet head]; */ |
||
1980 |
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); |
||
1981 |
s[i]->s.k = off_nl; |
||
1982 |
i++; |
||
1983 |
/* MEM[reg2] = A */ |
||
1984 |
s[i] = new_stmt(BPF_ST); |
||
1985 |
s[i]->s.k = reg2; |
||
1986 |
i++; |
||
1987 |
/* X = MEM[reg1] */ |
||
1988 |
s[i] = new_stmt(BPF_LDX|BPF_MEM); |
||
1989 |
s[i]->s.k = reg1; |
||
1990 |
i++; |
||
1991 |
/* A = P[X + packet head] */ |
||
1992 |
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); |
||
1993 |
s[i]->s.k = off_nl; |
||
1994 |
i++; |
||
1995 |
/* A += 1 */ |
||
1996 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
1997 |
s[i]->s.k = 1; |
||
1998 |
i++; |
||
1999 |
/* A *= 8 */ |
||
2000 |
s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); |
||
2001 |
s[i]->s.k = 8; |
||
2002 |
i++; |
||
2003 |
/* X = A; */ |
||
2004 |
s[i] = new_stmt(BPF_MISC|BPF_TAX); |
||
2005 |
i++; |
||
2006 |
/* A = MEM[reg2] */ |
||
2007 |
s[i] = new_stmt(BPF_LD|BPF_MEM); |
||
2008 |
s[i]->s.k = reg2; |
||
2009 |
i++; |
||
2010 |
|||
2011 |
/* goto again; (must use BPF_JA for backward jump) */ |
||
2012 |
s[i] = new_stmt(BPF_JMP|BPF_JA); |
||
2013 |
s[i]->s.k = again - i - 1; |
||
2014 |
s[i - 1]->s.jf = s[i]; |
||
2015 |
i++; |
||
2016 |
|||
2017 |
/* fixup */ |
||
2018 |
for (j = v6start; j <= v6end; j++) |
||
2019 |
s[j]->s.jt = s[v6advance]; |
||
2020 |
} else { |
||
2021 |
/* nop */ |
||
2022 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
2023 |
s[i]->s.k = 0; |
||
2024 |
s[fix2]->s.jf = s[i]; |
||
2025 |
i++; |
||
2026 |
} |
||
2027 |
|||
2028 |
/* ahcheck: */ |
||
2029 |
ahcheck = i; |
||
2030 |
/* if (A == IPPROTO_AH) then fall through; else goto end; */ |
||
2031 |
s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); |
||
2032 |
s[i]->s.jt = NULL; /*later*/ |
||
2033 |
s[i]->s.jf = NULL; /*later*/ |
||
2034 |
s[i]->s.k = IPPROTO_AH; |
||
2035 |
if (fix3) |
||
2036 |
s[fix3]->s.jf = s[ahcheck]; |
||
2037 |
fix4 = i; |
||
2038 |
i++; |
||
2039 |
|||
2040 |
/* |
||
2041 |
* in short, |
||
2042 |
* A = P[X + 1]; |
||
2043 |
* X = X + (P[X] + 2) * 4; |
||
2044 |
*/ |
||
2045 |
/* A = X */ |
||
2046 |
s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); |
||
2047 |
i++; |
||
2048 |
/* MEM[reg1] = A */ |
||
2049 |
s[i] = new_stmt(BPF_ST); |
||
2050 |
s[i]->s.k = reg1; |
||
2051 |
i++; |
||
2052 |
/* A += 1 */ |
||
2053 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
2054 |
s[i]->s.k = 1; |
||
2055 |
i++; |
||
2056 |
/* X = A */ |
||
2057 |
s[i] = new_stmt(BPF_MISC|BPF_TAX); |
||
2058 |
i++; |
||
2059 |
/* A = P[X + packet head]; */ |
||
2060 |
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); |
||
2061 |
s[i]->s.k = off_nl; |
||
2062 |
i++; |
||
2063 |
/* MEM[reg2] = A */ |
||
2064 |
s[i] = new_stmt(BPF_ST); |
||
2065 |
s[i]->s.k = reg2; |
||
2066 |
i++; |
||
2067 |
/* X = MEM[reg1] */ |
||
2068 |
s[i] = new_stmt(BPF_LDX|BPF_MEM); |
||
2069 |
s[i]->s.k = reg1; |
||
2070 |
i++; |
||
2071 |
/* A = P[X + packet head] */ |
||
2072 |
s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); |
||
2073 |
s[i]->s.k = off_nl; |
||
2074 |
i++; |
||
2075 |
/* A += 2 */ |
||
2076 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
2077 |
s[i]->s.k = 2; |
||
2078 |
i++; |
||
2079 |
/* A *= 4 */ |
||
2080 |
s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); |
||
2081 |
s[i]->s.k = 4; |
||
2082 |
i++; |
||
2083 |
/* X = A; */ |
||
2084 |
s[i] = new_stmt(BPF_MISC|BPF_TAX); |
||
2085 |
i++; |
||
2086 |
/* A = MEM[reg2] */ |
||
2087 |
s[i] = new_stmt(BPF_LD|BPF_MEM); |
||
2088 |
s[i]->s.k = reg2; |
||
2089 |
i++; |
||
2090 |
|||
2091 |
/* goto again; (must use BPF_JA for backward jump) */ |
||
2092 |
s[i] = new_stmt(BPF_JMP|BPF_JA); |
||
2093 |
s[i]->s.k = again - i - 1; |
||
2094 |
i++; |
||
2095 |
|||
2096 |
/* end: nop */ |
||
2097 |
end = i; |
||
2098 |
s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); |
||
2099 |
s[i]->s.k = 0; |
||
2100 |
s[fix2]->s.jt = s[end]; |
||
2101 |
s[fix4]->s.jf = s[end]; |
||
2102 |
s[fix5]->s.jt = s[end]; |
||
2103 |
i++; |
||
2104 |
|||
2105 |
/* |
||
2106 |
* make slist chain |
||
2107 |
*/ |
||
2108 |
max = i; |
||
2109 |
for (i = 0; i < max - 1; i++) |
||
2110 |
s[i]->next = s[i + 1]; |
||
2111 |
s[max - 1]->next = NULL; |
||
2112 |
|||
2113 |
/* |
||
2114 |
* emit final check |
||
2115 |
*/ |
||
2116 |
b = new_block(JMP(BPF_JEQ)); |
||
2117 |
b->stmts = s[1]; /*remember, s[0] is dummy*/ |
||
2118 |
b->s.k = v; |
||
2119 |
|||
2120 |
free_reg(reg1); |
||
2121 |
free_reg(reg2); |
||
2122 |
|||
2123 |
gen_and(b0, b); |
||
2124 |
return b; |
||
2125 |
} |
||
2126 |
|||
2127 |
static struct block * |
||
2128 |
gen_proto(v, proto, dir) |
||
2129 |
int v; |
||
2130 |
int proto; |
||
2131 |
int dir; |
||
2132 |
{ |
||
2133 |
struct block *b0, *b1; |
||
2134 |
|||
2135 |
✗✓ | 6 |
if (dir != Q_DEFAULT) |
2136 |
bpf_error("direction applied to 'proto'"); |
||
2137 |
|||
2138 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗ |
3 |
switch (proto) { |
2139 |
case Q_DEFAULT: |
||
2140 |
#ifdef INET6 |
||
2141 |
b0 = gen_proto(v, Q_IP, dir); |
||
2142 |
b1 = gen_proto(v, Q_IPV6, dir); |
||
2143 |
gen_or(b0, b1); |
||
2144 |
return b1; |
||
2145 |
#else |
||
2146 |
/*FALLTHROUGH*/ |
||
2147 |
#endif |
||
2148 |
case Q_IP: |
||
2149 |
b0 = gen_linktype(ETHERTYPE_IP); |
||
2150 |
#ifndef CHASE_CHAIN |
||
2151 |
b1 = gen_cmp_nl(9, BPF_B, (bpf_int32)v); |
||
2152 |
#else |
||
2153 |
b1 = gen_protochain(v, Q_IP); |
||
2154 |
#endif |
||
2155 |
gen_and(b0, b1); |
||
2156 |
return b1; |
||
2157 |
|||
2158 |
case Q_ARP: |
||
2159 |
bpf_error("arp does not encapsulate another protocol"); |
||
2160 |
/* NOTREACHED */ |
||
2161 |
|||
2162 |
case Q_RARP: |
||
2163 |
bpf_error("rarp does not encapsulate another protocol"); |
||
2164 |
/* NOTREACHED */ |
||
2165 |
|||
2166 |
case Q_ATALK: |
||
2167 |
bpf_error("atalk encapsulation is not specifiable"); |
||
2168 |
/* NOTREACHED */ |
||
2169 |
|||
2170 |
case Q_DECNET: |
||
2171 |
bpf_error("decnet encapsulation is not specifiable"); |
||
2172 |
/* NOTREACHED */ |
||
2173 |
|||
2174 |
case Q_SCA: |
||
2175 |
bpf_error("sca does not encapsulate another protocol"); |
||
2176 |
/* NOTREACHED */ |
||
2177 |
|||
2178 |
case Q_LAT: |
||
2179 |
bpf_error("lat does not encapsulate another protocol"); |
||
2180 |
/* NOTREACHED */ |
||
2181 |
|||
2182 |
case Q_MOPRC: |
||
2183 |
bpf_error("moprc does not encapsulate another protocol"); |
||
2184 |
/* NOTREACHED */ |
||
2185 |
|||
2186 |
case Q_MOPDL: |
||
2187 |
bpf_error("mopdl does not encapsulate another protocol"); |
||
2188 |
/* NOTREACHED */ |
||
2189 |
|||
2190 |
case Q_LINK: |
||
2191 |
return gen_linktype(v); |
||
2192 |
|||
2193 |
case Q_UDP: |
||
2194 |
bpf_error("'udp proto' is bogus"); |
||
2195 |
/* NOTREACHED */ |
||
2196 |
|||
2197 |
case Q_TCP: |
||
2198 |
bpf_error("'tcp proto' is bogus"); |
||
2199 |
/* NOTREACHED */ |
||
2200 |
|||
2201 |
case Q_ICMP: |
||
2202 |
bpf_error("'icmp proto' is bogus"); |
||
2203 |
/* NOTREACHED */ |
||
2204 |
|||
2205 |
case Q_IGMP: |
||
2206 |
bpf_error("'igmp proto' is bogus"); |
||
2207 |
/* NOTREACHED */ |
||
2208 |
|||
2209 |
case Q_IGRP: |
||
2210 |
bpf_error("'igrp proto' is bogus"); |
||
2211 |
/* NOTREACHED */ |
||
2212 |
|||
2213 |
case Q_PIM: |
||
2214 |
bpf_error("'pim proto' is bogus"); |
||
2215 |
/* NOTREACHED */ |
||
2216 |
|||
2217 |
case Q_STP: |
||
2218 |
bpf_error("'stp proto' is bogus"); |
||
2219 |
/* NOTREACHED */ |
||
2220 |
|||
2221 |
#ifdef INET6 |
||
2222 |
case Q_IPV6: |
||
2223 |
3 |
b0 = gen_linktype(ETHERTYPE_IPV6); |
|
2224 |
#ifndef CHASE_CHAIN |
||
2225 |
3 |
b1 = gen_cmp_nl(6, BPF_B, (bpf_int32)v); |
|
2226 |
#else |
||
2227 |
b1 = gen_protochain(v, Q_IPV6); |
||
2228 |
#endif |
||
2229 |
3 |
gen_and(b0, b1); |
|
2230 |
3 |
return b1; |
|
2231 |
|||
2232 |
case Q_ICMPV6: |
||
2233 |
bpf_error("'icmp6 proto' is bogus"); |
||
2234 |
#endif /* INET6 */ |
||
2235 |
|||
2236 |
case Q_AH: |
||
2237 |
bpf_error("'ah proto' is bogus"); |
||
2238 |
|||
2239 |
case Q_ESP: |
||
2240 |
bpf_error("'ah proto' is bogus"); |
||
2241 |
|||
2242 |
default: |
||
2243 |
abort(); |
||
2244 |
/* NOTREACHED */ |
||
2245 |
} |
||
2246 |
/* NOTREACHED */ |
||
2247 |
3 |
} |
|
2248 |
|||
2249 |
struct block * |
||
2250 |
gen_scode(name, q) |
||
2251 |
const char *name; |
||
2252 |
struct qual q; |
||
2253 |
{ |
||
2254 |
int proto = q.proto; |
||
2255 |
int dir = q.dir; |
||
2256 |
int tproto; |
||
2257 |
u_char *eaddr; |
||
2258 |
bpf_u_int32 mask, addr; |
||
2259 |
#ifndef INET6 |
||
2260 |
bpf_u_int32 **alist; |
||
2261 |
#else |
||
2262 |
int tproto6; |
||
2263 |
struct sockaddr_in *sin; |
||
2264 |
struct sockaddr_in6 *sin6; |
||
2265 |
struct addrinfo *res, *res0; |
||
2266 |
struct in6_addr mask128; |
||
2267 |
#endif /*INET6*/ |
||
2268 |
struct block *b, *tmp; |
||
2269 |
int port, real_proto; |
||
2270 |
|||
2271 |
switch (q.addr) { |
||
2272 |
|||
2273 |
case Q_NET: |
||
2274 |
addr = pcap_nametonetaddr(name); |
||
2275 |
if (addr == 0) |
||
2276 |
bpf_error("unknown network '%s'", name); |
||
2277 |
/* Left justify network addr and calculate its network mask */ |
||
2278 |
mask = 0xffffffff; |
||
2279 |
while (addr && (addr & 0xff000000) == 0) { |
||
2280 |
addr <<= 8; |
||
2281 |
mask <<= 8; |
||
2282 |
} |
||
2283 |
return gen_host(addr, mask, proto, dir); |
||
2284 |
|||
2285 |
case Q_DEFAULT: |
||
2286 |
case Q_HOST: |
||
2287 |
if (proto == Q_LINK) { |
||
2288 |
switch (linktype) { |
||
2289 |
|||
2290 |
case DLT_EN10MB: |
||
2291 |
eaddr = pcap_ether_hostton(name); |
||
2292 |
if (eaddr == NULL) |
||
2293 |
bpf_error( |
||
2294 |
"unknown ether host '%s'", name); |
||
2295 |
return gen_ehostop(eaddr, dir); |
||
2296 |
|||
2297 |
case DLT_FDDI: |
||
2298 |
eaddr = pcap_ether_hostton(name); |
||
2299 |
if (eaddr == NULL) |
||
2300 |
bpf_error( |
||
2301 |
"unknown FDDI host '%s'", name); |
||
2302 |
return gen_fhostop(eaddr, dir); |
||
2303 |
|||
2304 |
case DLT_IEEE802_11: |
||
2305 |
case DLT_IEEE802_11_RADIO: |
||
2306 |
eaddr = pcap_ether_hostton(name); |
||
2307 |
if (eaddr == NULL) |
||
2308 |
bpf_error( |
||
2309 |
"unknown 802.11 host '%s'", name); |
||
2310 |
|||
2311 |
return gen_p80211_hostop(eaddr, dir); |
||
2312 |
|||
2313 |
default: |
||
2314 |
bpf_error( |
||
2315 |
"only ethernet/FDDI supports link-level host name"); |
||
2316 |
break; |
||
2317 |
} |
||
2318 |
} else if (proto == Q_DECNET) { |
||
2319 |
unsigned short dn_addr = __pcap_nametodnaddr(name); |
||
2320 |
/* |
||
2321 |
* I don't think DECNET hosts can be multihomed, so |
||
2322 |
* there is no need to build up a list of addresses |
||
2323 |
*/ |
||
2324 |
return (gen_host(dn_addr, 0, proto, dir)); |
||
2325 |
} else { |
||
2326 |
#ifndef INET6 |
||
2327 |
alist = pcap_nametoaddr(name); |
||
2328 |
if (alist == NULL || *alist == NULL) |
||
2329 |
bpf_error("unknown host '%s'", name); |
||
2330 |
tproto = proto; |
||
2331 |
if (off_linktype == -1 && tproto == Q_DEFAULT) |
||
2332 |
tproto = Q_IP; |
||
2333 |
b = gen_host(**alist++, 0xffffffff, tproto, dir); |
||
2334 |
while (*alist) { |
||
2335 |
tmp = gen_host(**alist++, 0xffffffff, |
||
2336 |
tproto, dir); |
||
2337 |
gen_or(b, tmp); |
||
2338 |
b = tmp; |
||
2339 |
} |
||
2340 |
return b; |
||
2341 |
#else |
||
2342 |
memset(&mask128, 0xff, sizeof(mask128)); |
||
2343 |
res0 = res = pcap_nametoaddrinfo(name); |
||
2344 |
if (res == NULL) |
||
2345 |
bpf_error("unknown host '%s'", name); |
||
2346 |
b = tmp = NULL; |
||
2347 |
tproto = tproto6 = proto; |
||
2348 |
if (off_linktype == -1 && tproto == Q_DEFAULT) { |
||
2349 |
tproto = Q_IP; |
||
2350 |
tproto6 = Q_IPV6; |
||
2351 |
} |
||
2352 |
for (res = res0; res; res = res->ai_next) { |
||
2353 |
switch (res->ai_family) { |
||
2354 |
case AF_INET: |
||
2355 |
if (tproto == Q_IPV6) |
||
2356 |
continue; |
||
2357 |
|||
2358 |
sin = (struct sockaddr_in *) |
||
2359 |
res->ai_addr; |
||
2360 |
tmp = gen_host(ntohl(sin->sin_addr.s_addr), |
||
2361 |
0xffffffff, tproto, dir); |
||
2362 |
break; |
||
2363 |
case AF_INET6: |
||
2364 |
if (tproto6 == Q_IP) |
||
2365 |
continue; |
||
2366 |
|||
2367 |
sin6 = (struct sockaddr_in6 *) |
||
2368 |
res->ai_addr; |
||
2369 |
tmp = gen_host6(&sin6->sin6_addr, |
||
2370 |
&mask128, tproto6, dir); |
||
2371 |
break; |
||
2372 |
} |
||
2373 |
if (b) |
||
2374 |
gen_or(b, tmp); |
||
2375 |
b = tmp; |
||
2376 |
} |
||
2377 |
freeaddrinfo(res0); |
||
2378 |
if (b == NULL) { |
||
2379 |
bpf_error("unknown host '%s'%s", name, |
||
2380 |
(proto == Q_DEFAULT) |
||
2381 |
? "" |
||
2382 |
: " for specified address family"); |
||
2383 |
} |
||
2384 |
return b; |
||
2385 |
#endif /*INET6*/ |
||
2386 |
} |
||
2387 |
|||
2388 |
case Q_PORT: |
||
2389 |
if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP) |
||
2390 |
bpf_error("illegal qualifier of 'port'"); |
||
2391 |
if (pcap_nametoport(name, &port, &real_proto) == 0) |
||
2392 |
bpf_error("unknown port '%s'", name); |
||
2393 |
if (proto == Q_UDP) { |
||
2394 |
if (real_proto == IPPROTO_TCP) |
||
2395 |
bpf_error("port '%s' is tcp", name); |
||
2396 |
else |
||
2397 |
/* override PROTO_UNDEF */ |
||
2398 |
real_proto = IPPROTO_UDP; |
||
2399 |
} |
||
2400 |
if (proto == Q_TCP) { |
||
2401 |
if (real_proto == IPPROTO_UDP) |
||
2402 |
bpf_error("port '%s' is udp", name); |
||
2403 |
else |
||
2404 |
/* override PROTO_UNDEF */ |
||
2405 |
real_proto = IPPROTO_TCP; |
||
2406 |
} |
||
2407 |
#ifndef INET6 |
||
2408 |
return gen_port(port, real_proto, dir); |
||
2409 |
#else |
||
2410 |
{ |
||
2411 |
struct block *b; |
||
2412 |
b = gen_port(port, real_proto, dir); |
||
2413 |
gen_or(gen_port6(port, real_proto, dir), b); |
||
2414 |
return b; |
||
2415 |
} |
||
2416 |
#endif /* INET6 */ |
||
2417 |
|||
2418 |
case Q_GATEWAY: |
||
2419 |
#ifndef INET6 |
||
2420 |
eaddr = pcap_ether_hostton(name); |
||
2421 |
if (eaddr == NULL) |
||
2422 |
bpf_error("unknown ether host: %s", name); |
||
2423 |
|||
2424 |
alist = pcap_nametoaddr(name); |
||
2425 |
if (alist == NULL || *alist == NULL) |
||
2426 |
bpf_error("unknown host '%s'", name); |
||
2427 |
return gen_gateway(eaddr, alist, proto, dir); |
||
2428 |
#else |
||
2429 |
bpf_error("'gateway' not supported in this configuration"); |
||
2430 |
#endif /*INET6*/ |
||
2431 |
|||
2432 |
case Q_PROTO: |
||
2433 |
real_proto = lookup_proto(name, proto); |
||
2434 |
if (real_proto >= 0) |
||
2435 |
return gen_proto(real_proto, proto, dir); |
||
2436 |
else |
||
2437 |
bpf_error("unknown protocol: %s", name); |
||
2438 |
|||
2439 |
case Q_PROTOCHAIN: |
||
2440 |
real_proto = lookup_proto(name, proto); |
||
2441 |
if (real_proto >= 0) |
||
2442 |
return gen_protochain(real_proto, proto, dir); |
||
2443 |
else |
||
2444 |
bpf_error("unknown protocol: %s", name); |
||
2445 |
|||
2446 |
|||
2447 |
case Q_UNDEF: |
||
2448 |
syntax(); |
||
2449 |
/* NOTREACHED */ |
||
2450 |
} |
||
2451 |
abort(); |
||
2452 |
/* NOTREACHED */ |
||
2453 |
} |
||
2454 |
|||
2455 |
struct block * |
||
2456 |
gen_mcode(s1, s2, masklen, q) |
||
2457 |
const char *s1, *s2; |
||
2458 |
int masklen; |
||
2459 |
struct qual q; |
||
2460 |
{ |
||
2461 |
int nlen, mlen; |
||
2462 |
bpf_u_int32 n, m; |
||
2463 |
|||
2464 |
nlen = __pcap_atoin(s1, &n); |
||
2465 |
/* Promote short ipaddr */ |
||
2466 |
n <<= 32 - nlen; |
||
2467 |
|||
2468 |
if (s2 != NULL) { |
||
2469 |
mlen = __pcap_atoin(s2, &m); |
||
2470 |
/* Promote short ipaddr */ |
||
2471 |
m <<= 32 - mlen; |
||
2472 |
if ((n & ~m) != 0) |
||
2473 |
bpf_error("non-network bits set in \"%s mask %s\"", |
||
2474 |
s1, s2); |
||
2475 |
} else { |
||
2476 |
/* Convert mask len to mask */ |
||
2477 |
if (masklen > 32) |
||
2478 |
bpf_error("mask length must be <= 32"); |
||
2479 |
m = 0xffffffff << (32 - masklen); |
||
2480 |
if ((n & ~m) != 0) |
||
2481 |
bpf_error("non-network bits set in \"%s/%d\"", |
||
2482 |
s1, masklen); |
||
2483 |
} |
||
2484 |
|||
2485 |
switch (q.addr) { |
||
2486 |
|||
2487 |
case Q_NET: |
||
2488 |
return gen_host(n, m, q.proto, q.dir); |
||
2489 |
|||
2490 |
default: |
||
2491 |
bpf_error("Mask syntax for networks only"); |
||
2492 |
/* NOTREACHED */ |
||
2493 |
} |
||
2494 |
} |
||
2495 |
|||
2496 |
struct block * |
||
2497 |
gen_ncode(s, v, q) |
||
2498 |
const char *s; |
||
2499 |
bpf_u_int32 v; |
||
2500 |
struct qual q; |
||
2501 |
{ |
||
2502 |
bpf_u_int32 mask; |
||
2503 |
int proto = q.proto; |
||
2504 |
int dir = q.dir; |
||
2505 |
int vlen; |
||
2506 |
|||
2507 |
if (s == NULL) |
||
2508 |
vlen = 32; |
||
2509 |
else if (q.proto == Q_DECNET) |
||
2510 |
vlen = __pcap_atodn(s, &v); |
||
2511 |
else |
||
2512 |
vlen = __pcap_atoin(s, &v); |
||
2513 |
|||
2514 |
switch (q.addr) { |
||
2515 |
|||
2516 |
case Q_DEFAULT: |
||
2517 |
case Q_HOST: |
||
2518 |
case Q_NET: |
||
2519 |
if (proto == Q_DECNET) |
||
2520 |
return gen_host(v, 0, proto, dir); |
||
2521 |
else if (proto == Q_LINK) { |
||
2522 |
bpf_error("illegal link layer address"); |
||
2523 |
} else { |
||
2524 |
mask = 0xffffffff; |
||
2525 |
if (s == NULL && q.addr == Q_NET) { |
||
2526 |
/* Promote short net number */ |
||
2527 |
while (v && (v & 0xff000000) == 0) { |
||
2528 |
v <<= 8; |
||
2529 |
mask <<= 8; |
||
2530 |
} |
||
2531 |
} else { |
||
2532 |
/* Promote short ipaddr */ |
||
2533 |
v <<= 32 - vlen; |
||
2534 |
mask <<= 32 - vlen; |
||
2535 |
} |
||
2536 |
return gen_host(v, mask, proto, dir); |
||
2537 |
} |
||
2538 |
|||
2539 |
case Q_PORT: |
||
2540 |
if (proto == Q_UDP) |
||
2541 |
proto = IPPROTO_UDP; |
||
2542 |
else if (proto == Q_TCP) |
||
2543 |
proto = IPPROTO_TCP; |
||
2544 |
else if (proto == Q_DEFAULT) |
||
2545 |
proto = PROTO_UNDEF; |
||
2546 |
else |
||
2547 |
bpf_error("illegal qualifier of 'port'"); |
||
2548 |
|||
2549 |
#ifndef INET6 |
||
2550 |
return gen_port((int)v, proto, dir); |
||
2551 |
#else |
||
2552 |
{ |
||
2553 |
struct block *b; |
||
2554 |
b = gen_port((int)v, proto, dir); |
||
2555 |
gen_or(gen_port6((int)v, proto, dir), b); |
||
2556 |
return b; |
||
2557 |
} |
||
2558 |
#endif /* INET6 */ |
||
2559 |
|||
2560 |
case Q_GATEWAY: |
||
2561 |
bpf_error("'gateway' requires a name"); |
||
2562 |
/* NOTREACHED */ |
||
2563 |
|||
2564 |
case Q_PROTO: |
||
2565 |
return gen_proto((int)v, proto, dir); |
||
2566 |
|||
2567 |
case Q_PROTOCHAIN: |
||
2568 |
return gen_protochain((int)v, proto, dir); |
||
2569 |
|||
2570 |
case Q_UNDEF: |
||
2571 |
syntax(); |
||
2572 |
/* NOTREACHED */ |
||
2573 |
|||
2574 |
default: |
||
2575 |
abort(); |
||
2576 |
/* NOTREACHED */ |
||
2577 |
} |
||
2578 |
/* NOTREACHED */ |
||
2579 |
} |
||
2580 |
|||
2581 |
#ifdef INET6 |
||
2582 |
struct block * |
||
2583 |
gen_mcode6(s1, s2, masklen, q) |
||
2584 |
const char *s1, *s2; |
||
2585 |
int masklen; |
||
2586 |
struct qual q; |
||
2587 |
{ |
||
2588 |
struct addrinfo *res; |
||
2589 |
struct in6_addr *addr; |
||
2590 |
struct in6_addr mask; |
||
2591 |
struct block *b; |
||
2592 |
u_int32_t *a, *m; |
||
2593 |
|||
2594 |
if (s2) |
||
2595 |
bpf_error("no mask %s supported", s2); |
||
2596 |
|||
2597 |
res = pcap_nametoaddrinfo(s1); |
||
2598 |
if (!res) |
||
2599 |
bpf_error("invalid ip6 address %s", s1); |
||
2600 |
if (res->ai_next) |
||
2601 |
bpf_error("%s resolved to multiple address", s1); |
||
2602 |
addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; |
||
2603 |
|||
2604 |
if (sizeof(mask) * 8 < masklen) |
||
2605 |
bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); |
||
2606 |
memset(&mask, 0, sizeof(mask)); |
||
2607 |
memset(&mask, 0xff, masklen / 8); |
||
2608 |
if (masklen % 8) { |
||
2609 |
mask.s6_addr[masklen / 8] = |
||
2610 |
(0xff << (8 - masklen % 8)) & 0xff; |
||
2611 |
} |
||
2612 |
|||
2613 |
a = (u_int32_t *)addr; |
||
2614 |
m = (u_int32_t *)&mask; |
||
2615 |
if ((a[0] & ~m[0]) || (a[1] & ~m[1]) |
||
2616 |
|| (a[2] & ~m[2]) || (a[3] & ~m[3])) { |
||
2617 |
bpf_error("non-network bits set in \"%s/%d\"", s1, masklen); |
||
2618 |
} |
||
2619 |
|||
2620 |
switch (q.addr) { |
||
2621 |
|||
2622 |
case Q_DEFAULT: |
||
2623 |
case Q_HOST: |
||
2624 |
if (masklen != 128) |
||
2625 |
bpf_error("Mask syntax for networks only"); |
||
2626 |
/* FALLTHROUGH */ |
||
2627 |
|||
2628 |
case Q_NET: |
||
2629 |
b = gen_host6(addr, &mask, q.proto, q.dir); |
||
2630 |
freeaddrinfo(res); |
||
2631 |
return b; |
||
2632 |
|||
2633 |
default: |
||
2634 |
bpf_error("invalid qualifier against IPv6 address"); |
||
2635 |
/* NOTREACHED */ |
||
2636 |
} |
||
2637 |
} |
||
2638 |
#endif /*INET6*/ |
||
2639 |
|||
2640 |
struct block * |
||
2641 |
gen_ecode(eaddr, q) |
||
2642 |
const u_char *eaddr; |
||
2643 |
struct qual q; |
||
2644 |
{ |
||
2645 |
if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { |
||
2646 |
if (linktype == DLT_EN10MB) |
||
2647 |
return gen_ehostop(eaddr, (int)q.dir); |
||
2648 |
if (linktype == DLT_FDDI) |
||
2649 |
return gen_fhostop(eaddr, (int)q.dir); |
||
2650 |
if (linktype == DLT_IEEE802_11 || |
||
2651 |
linktype == DLT_IEEE802_11_RADIO) |
||
2652 |
return gen_p80211_hostop(eaddr, (int)q.dir); |
||
2653 |
} |
||
2654 |
bpf_error("ethernet address used in non-ether expression"); |
||
2655 |
/* NOTREACHED */ |
||
2656 |
} |
||
2657 |
|||
2658 |
void |
||
2659 |
sappend(s0, s1) |
||
2660 |
struct slist *s0, *s1; |
||
2661 |
{ |
||
2662 |
/* |
||
2663 |
* This is definitely not the best way to do this, but the |
||
2664 |
* lists will rarely get long. |
||
2665 |
*/ |
||
2666 |
✓✓ | 117 |
while (s0->next) |
2667 |
s0 = s0->next; |
||
2668 |
21 |
s0->next = s1; |
|
2669 |
21 |
} |
|
2670 |
|||
2671 |
static struct slist * |
||
2672 |
xfer_to_x(a) |
||
2673 |
struct arth *a; |
||
2674 |
{ |
||
2675 |
struct slist *s; |
||
2676 |
|||
2677 |
12 |
s = new_stmt(BPF_LDX|BPF_MEM); |
|
2678 |
6 |
s->s.k = a->regno; |
|
2679 |
6 |
return s; |
|
2680 |
} |
||
2681 |
|||
2682 |
static struct slist * |
||
2683 |
xfer_to_a(a) |
||
2684 |
struct arth *a; |
||
2685 |
{ |
||
2686 |
struct slist *s; |
||
2687 |
|||
2688 |
6 |
s = new_stmt(BPF_LD|BPF_MEM); |
|
2689 |
3 |
s->s.k = a->regno; |
|
2690 |
3 |
return s; |
|
2691 |
} |
||
2692 |
|||
2693 |
struct arth * |
||
2694 |
gen_load(proto, index, size) |
||
2695 |
int proto; |
||
2696 |
struct arth *index; |
||
2697 |
int size; |
||
2698 |
{ |
||
2699 |
struct slist *s, *tmp; |
||
2700 |
struct block *b; |
||
2701 |
6 |
int regno = alloc_reg(); |
|
2702 |
|||
2703 |
3 |
free_reg(index->regno); |
|
2704 |
✗✓✗✗ |
3 |
switch (size) { |
2705 |
|||
2706 |
default: |
||
2707 |
bpf_error("data size must be 1, 2, or 4"); |
||
2708 |
|||
2709 |
case 1: |
||
2710 |
size = BPF_B; |
||
2711 |
3 |
break; |
|
2712 |
|||
2713 |
case 2: |
||
2714 |
size = BPF_H; |
||
2715 |
break; |
||
2716 |
|||
2717 |
case 4: |
||
2718 |
size = BPF_W; |
||
2719 |
break; |
||
2720 |
} |
||
2721 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗✗ |
3 |
switch (proto) { |
2722 |
default: |
||
2723 |
bpf_error("unsupported index operation"); |
||
2724 |
|||
2725 |
case Q_LINK: |
||
2726 |
s = xfer_to_x(index); |
||
2727 |
tmp = new_stmt(BPF_LD|BPF_IND|size); |
||
2728 |
sappend(s, tmp); |
||
2729 |
sappend(index->s, s); |
||
2730 |
break; |
||
2731 |
|||
2732 |
case Q_IP: |
||
2733 |
case Q_ARP: |
||
2734 |
case Q_RARP: |
||
2735 |
case Q_ATALK: |
||
2736 |
case Q_DECNET: |
||
2737 |
case Q_SCA: |
||
2738 |
case Q_LAT: |
||
2739 |
case Q_MOPRC: |
||
2740 |
case Q_MOPDL: |
||
2741 |
#ifdef INET6 |
||
2742 |
case Q_IPV6: |
||
2743 |
#endif |
||
2744 |
/* XXX Note that we assume a fixed link header here. */ |
||
2745 |
✗✓ | 3 |
if (variable_nl) { |
2746 |
s = nl2X_stmt(); |
||
2747 |
sappend(s, xfer_to_a(index)); |
||
2748 |
sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); |
||
2749 |
sappend(s, new_stmt(BPF_MISC|BPF_TAX)); |
||
2750 |
} else { |
||
2751 |
3 |
s = xfer_to_x(index); |
|
2752 |
} |
||
2753 |
3 |
tmp = new_stmt(BPF_LD|BPF_IND|size); |
|
2754 |
3 |
tmp->s.k = off_nl; /* off_nl == 0 for variable_nl */ |
|
2755 |
3 |
sappend(s, tmp); |
|
2756 |
3 |
sappend(index->s, s); |
|
2757 |
|||
2758 |
3 |
b = gen_proto_abbrev(proto); |
|
2759 |
✗✓ | 3 |
if (index->b) |
2760 |
gen_and(index->b, b); |
||
2761 |
3 |
index->b = b; |
|
2762 |
3 |
break; |
|
2763 |
|||
2764 |
case Q_TCP: |
||
2765 |
case Q_UDP: |
||
2766 |
case Q_ICMP: |
||
2767 |
case Q_IGMP: |
||
2768 |
case Q_IGRP: |
||
2769 |
case Q_PIM: |
||
2770 |
s = iphl_to_x(); |
||
2771 |
sappend(s, xfer_to_a(index)); |
||
2772 |
sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); |
||
2773 |
sappend(s, new_stmt(BPF_MISC|BPF_TAX)); |
||
2774 |
sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); |
||
2775 |
tmp->s.k = off_nl; /* off_nl is 0 if variable_nl */ |
||
2776 |
sappend(index->s, s); |
||
2777 |
|||
2778 |
gen_and(gen_proto_abbrev(proto), b = gen_ipfrag()); |
||
2779 |
if (index->b) |
||
2780 |
gen_and(index->b, b); |
||
2781 |
#ifdef INET6 |
||
2782 |
gen_and(gen_proto_abbrev(Q_IP), b); |
||
2783 |
#endif |
||
2784 |
index->b = b; |
||
2785 |
break; |
||
2786 |
#ifdef INET6 |
||
2787 |
case Q_ICMPV6: |
||
2788 |
bpf_error("IPv6 upper-layer protocol is not supported by proto[x]"); |
||
2789 |
/*NOTREACHED*/ |
||
2790 |
#endif |
||
2791 |
} |
||
2792 |
3 |
index->regno = regno; |
|
2793 |
3 |
s = new_stmt(BPF_ST); |
|
2794 |
3 |
s->s.k = regno; |
|
2795 |
3 |
sappend(index->s, s); |
|
2796 |
|||
2797 |
3 |
return index; |
|
2798 |
} |
||
2799 |
|||
2800 |
struct block * |
||
2801 |
gen_relation(code, a0, a1, reversed) |
||
2802 |
int code; |
||
2803 |
struct arth *a0, *a1; |
||
2804 |
int reversed; |
||
2805 |
{ |
||
2806 |
struct slist *s0, *s1, *s2; |
||
2807 |
struct block *b, *tmp; |
||
2808 |
|||
2809 |
6 |
s0 = xfer_to_x(a1); |
|
2810 |
3 |
s1 = xfer_to_a(a0); |
|
2811 |
3 |
s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X); |
|
2812 |
3 |
b = new_block(JMP(code)); |
|
2813 |
✗✓ | 3 |
if (code == BPF_JGT || code == BPF_JGE) { |
2814 |
reversed = !reversed; |
||
2815 |
b->s.k = 0x80000000; |
||
2816 |
} |
||
2817 |
✗✓ | 3 |
if (reversed) |
2818 |
gen_not(b); |
||
2819 |
|||
2820 |
3 |
sappend(s1, s2); |
|
2821 |
3 |
sappend(s0, s1); |
|
2822 |
3 |
sappend(a1->s, s0); |
|
2823 |
3 |
sappend(a0->s, a1->s); |
|
2824 |
|||
2825 |
3 |
b->stmts = a0->s; |
|
2826 |
|||
2827 |
3 |
free_reg(a0->regno); |
|
2828 |
3 |
free_reg(a1->regno); |
|
2829 |
|||
2830 |
/* 'and' together protocol checks */ |
||
2831 |
✓✗ | 3 |
if (a0->b) { |
2832 |
✗✓ | 3 |
if (a1->b) { |
2833 |
gen_and(a0->b, tmp = a1->b); |
||
2834 |
} |
||
2835 |
else |
||
2836 |
tmp = a0->b; |
||
2837 |
} else |
||
2838 |
tmp = a1->b; |
||
2839 |
|||
2840 |
✓✗ | 3 |
if (tmp) |
2841 |
3 |
gen_and(tmp, b); |
|
2842 |
|||
2843 |
3 |
return b; |
|
2844 |
} |
||
2845 |
|||
2846 |
struct arth * |
||
2847 |
gen_loadlen() |
||
2848 |
{ |
||
2849 |
int regno = alloc_reg(); |
||
2850 |
struct arth *a = (struct arth *)newchunk(sizeof(*a)); |
||
2851 |
struct slist *s; |
||
2852 |
|||
2853 |
s = new_stmt(BPF_LD|BPF_LEN); |
||
2854 |
s->next = new_stmt(BPF_ST); |
||
2855 |
s->next->s.k = regno; |
||
2856 |
a->s = s; |
||
2857 |
a->regno = regno; |
||
2858 |
|||
2859 |
return a; |
||
2860 |
} |
||
2861 |
|||
2862 |
struct arth * |
||
2863 |
gen_loadi(val) |
||
2864 |
int val; |
||
2865 |
{ |
||
2866 |
struct arth *a; |
||
2867 |
struct slist *s; |
||
2868 |
int reg; |
||
2869 |
|||
2870 |
12 |
a = (struct arth *)newchunk(sizeof(*a)); |
|
2871 |
|||
2872 |
6 |
reg = alloc_reg(); |
|
2873 |
|||
2874 |
6 |
s = new_stmt(BPF_LD|BPF_IMM); |
|
2875 |
6 |
s->s.k = val; |
|
2876 |
6 |
s->next = new_stmt(BPF_ST); |
|
2877 |
6 |
s->next->s.k = reg; |
|
2878 |
6 |
a->s = s; |
|
2879 |
6 |
a->regno = reg; |
|
2880 |
|||
2881 |
6 |
return a; |
|
2882 |
} |
||
2883 |
|||
2884 |
struct arth * |
||
2885 |
gen_neg(a) |
||
2886 |
struct arth *a; |
||
2887 |
{ |
||
2888 |
struct slist *s; |
||
2889 |
|||
2890 |
s = xfer_to_a(a); |
||
2891 |
sappend(a->s, s); |
||
2892 |
s = new_stmt(BPF_ALU|BPF_NEG); |
||
2893 |
s->s.k = 0; |
||
2894 |
sappend(a->s, s); |
||
2895 |
s = new_stmt(BPF_ST); |
||
2896 |
s->s.k = a->regno; |
||
2897 |
sappend(a->s, s); |
||
2898 |
|||
2899 |
return a; |
||
2900 |
} |
||
2901 |
|||
2902 |
struct arth * |
||
2903 |
gen_arth(code, a0, a1) |
||
2904 |
int code; |
||
2905 |
struct arth *a0, *a1; |
||
2906 |
{ |
||
2907 |
struct slist *s0, *s1, *s2; |
||
2908 |
|||
2909 |
s0 = xfer_to_x(a1); |
||
2910 |
s1 = xfer_to_a(a0); |
||
2911 |
s2 = new_stmt(BPF_ALU|BPF_X|code); |
||
2912 |
|||
2913 |
sappend(s1, s2); |
||
2914 |
sappend(s0, s1); |
||
2915 |
sappend(a1->s, s0); |
||
2916 |
sappend(a0->s, a1->s); |
||
2917 |
|||
2918 |
free_reg(a1->regno); |
||
2919 |
|||
2920 |
s0 = new_stmt(BPF_ST); |
||
2921 |
a0->regno = s0->s.k = alloc_reg(); |
||
2922 |
sappend(a0->s, s0); |
||
2923 |
|||
2924 |
return a0; |
||
2925 |
} |
||
2926 |
|||
2927 |
/* |
||
2928 |
* Here we handle simple allocation of the scratch registers. |
||
2929 |
* If too many registers are alloc'd, the allocator punts. |
||
2930 |
*/ |
||
2931 |
static int regused[BPF_MEMWORDS]; |
||
2932 |
static int curreg; |
||
2933 |
|||
2934 |
/* |
||
2935 |
* Return the next free register. |
||
2936 |
*/ |
||
2937 |
static int |
||
2938 |
alloc_reg() |
||
2939 |
{ |
||
2940 |
int n = BPF_MEMWORDS; |
||
2941 |
|||
2942 |
✓✗ | 39 |
while (--n >= 0) { |
2943 |
✓✓ | 15 |
if (regused[curreg]) |
2944 |
6 |
curreg = (curreg + 1) % BPF_MEMWORDS; |
|
2945 |
else { |
||
2946 |
9 |
regused[curreg] = 1; |
|
2947 |
9 |
return curreg; |
|
2948 |
} |
||
2949 |
} |
||
2950 |
bpf_error("too many registers needed to evaluate expression"); |
||
2951 |
/* NOTREACHED */ |
||
2952 |
} |
||
2953 |
|||
2954 |
/* |
||
2955 |
* Return a register to the table so it can |
||
2956 |
* be used later. |
||
2957 |
*/ |
||
2958 |
static void |
||
2959 |
free_reg(n) |
||
2960 |
int n; |
||
2961 |
{ |
||
2962 |
18 |
regused[n] = 0; |
|
2963 |
9 |
} |
|
2964 |
|||
2965 |
static struct block * |
||
2966 |
gen_len(jmp, n) |
||
2967 |
int jmp, n; |
||
2968 |
{ |
||
2969 |
struct slist *s; |
||
2970 |
struct block *b; |
||
2971 |
|||
2972 |
s = new_stmt(BPF_LD|BPF_LEN); |
||
2973 |
b = new_block(JMP(jmp)); |
||
2974 |
b->stmts = s; |
||
2975 |
b->s.k = n; |
||
2976 |
|||
2977 |
return b; |
||
2978 |
} |
||
2979 |
|||
2980 |
struct block * |
||
2981 |
gen_greater(n) |
||
2982 |
int n; |
||
2983 |
{ |
||
2984 |
return gen_len(BPF_JGE, n); |
||
2985 |
} |
||
2986 |
|||
2987 |
struct block * |
||
2988 |
gen_less(n) |
||
2989 |
int n; |
||
2990 |
{ |
||
2991 |
struct block *b; |
||
2992 |
|||
2993 |
b = gen_len(BPF_JGT, n); |
||
2994 |
gen_not(b); |
||
2995 |
|||
2996 |
return b; |
||
2997 |
} |
||
2998 |
|||
2999 |
struct block * |
||
3000 |
gen_byteop(op, idx, val) |
||
3001 |
int op, idx, val; |
||
3002 |
{ |
||
3003 |
struct block *b; |
||
3004 |
struct slist *s; |
||
3005 |
|||
3006 |
switch (op) { |
||
3007 |
default: |
||
3008 |
abort(); |
||
3009 |
|||
3010 |
case '=': |
||
3011 |
return gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); |
||
3012 |
|||
3013 |
case '<': |
||
3014 |
b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); |
||
3015 |
b->s.code = JMP(BPF_JGE); |
||
3016 |
gen_not(b); |
||
3017 |
return b; |
||
3018 |
|||
3019 |
case '>': |
||
3020 |
b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); |
||
3021 |
b->s.code = JMP(BPF_JGT); |
||
3022 |
return b; |
||
3023 |
|||
3024 |
case '|': |
||
3025 |
s = new_stmt(BPF_ALU|BPF_OR|BPF_K); |
||
3026 |
break; |
||
3027 |
|||
3028 |
case '&': |
||
3029 |
s = new_stmt(BPF_ALU|BPF_AND|BPF_K); |
||
3030 |
break; |
||
3031 |
} |
||
3032 |
s->s.k = val; |
||
3033 |
b = new_block(JMP(BPF_JEQ)); |
||
3034 |
b->stmts = s; |
||
3035 |
gen_not(b); |
||
3036 |
|||
3037 |
return b; |
||
3038 |
} |
||
3039 |
|||
3040 |
struct block * |
||
3041 |
gen_broadcast(proto) |
||
3042 |
int proto; |
||
3043 |
{ |
||
3044 |
bpf_u_int32 hostmask; |
||
3045 |
struct block *b0, *b1, *b2; |
||
3046 |
static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
||
3047 |
|||
3048 |
switch (proto) { |
||
3049 |
|||
3050 |
case Q_DEFAULT: |
||
3051 |
case Q_LINK: |
||
3052 |
if (linktype == DLT_EN10MB) |
||
3053 |
return gen_ehostop(ebroadcast, Q_DST); |
||
3054 |
if (linktype == DLT_FDDI) |
||
3055 |
return gen_fhostop(ebroadcast, Q_DST); |
||
3056 |
if (linktype == DLT_IEEE802_11 || |
||
3057 |
linktype == DLT_IEEE802_11_RADIO) |
||
3058 |
return gen_p80211_hostop(ebroadcast, Q_DST); |
||
3059 |
bpf_error("not a broadcast link"); |
||
3060 |
break; |
||
3061 |
|||
3062 |
case Q_IP: |
||
3063 |
b0 = gen_linktype(ETHERTYPE_IP); |
||
3064 |
hostmask = ~netmask; |
||
3065 |
b1 = gen_mcmp_nl(16, BPF_W, (bpf_int32)0, hostmask); |
||
3066 |
b2 = gen_mcmp_nl(16, BPF_W, |
||
3067 |
(bpf_int32)(~0 & hostmask), hostmask); |
||
3068 |
gen_or(b1, b2); |
||
3069 |
gen_and(b0, b2); |
||
3070 |
return b2; |
||
3071 |
} |
||
3072 |
bpf_error("only ether/ip broadcast filters supported"); |
||
3073 |
} |
||
3074 |
|||
3075 |
struct block * |
||
3076 |
gen_multicast(proto) |
||
3077 |
int proto; |
||
3078 |
{ |
||
3079 |
struct block *b0, *b1; |
||
3080 |
struct slist *s; |
||
3081 |
|||
3082 |
switch (proto) { |
||
3083 |
|||
3084 |
case Q_DEFAULT: |
||
3085 |
case Q_LINK: |
||
3086 |
if (linktype == DLT_EN10MB) { |
||
3087 |
/* ether[0] & 1 != 0 */ |
||
3088 |
s = new_stmt(BPF_LD|BPF_B|BPF_ABS); |
||
3089 |
s->s.k = 0; |
||
3090 |
b0 = new_block(JMP(BPF_JSET)); |
||
3091 |
b0->s.k = 1; |
||
3092 |
b0->stmts = s; |
||
3093 |
return b0; |
||
3094 |
} |
||
3095 |
|||
3096 |
if (linktype == DLT_FDDI) { |
||
3097 |
/* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX */ |
||
3098 |
/* fddi[1] & 1 != 0 */ |
||
3099 |
s = new_stmt(BPF_LD|BPF_B|BPF_ABS); |
||
3100 |
s->s.k = 1; |
||
3101 |
b0 = new_block(JMP(BPF_JSET)); |
||
3102 |
b0->s.k = 1; |
||
3103 |
b0->stmts = s; |
||
3104 |
return b0; |
||
3105 |
} |
||
3106 |
/* Link not known to support multicasts */ |
||
3107 |
break; |
||
3108 |
|||
3109 |
case Q_IP: |
||
3110 |
b0 = gen_linktype(ETHERTYPE_IP); |
||
3111 |
b1 = gen_cmp_nl(16, BPF_B, (bpf_int32)224); |
||
3112 |
b1->s.code = JMP(BPF_JGE); |
||
3113 |
gen_and(b0, b1); |
||
3114 |
return b1; |
||
3115 |
|||
3116 |
#ifdef INET6 |
||
3117 |
case Q_IPV6: |
||
3118 |
b0 = gen_linktype(ETHERTYPE_IPV6); |
||
3119 |
b1 = gen_cmp_nl(24, BPF_B, (bpf_int32)255); |
||
3120 |
gen_and(b0, b1); |
||
3121 |
return b1; |
||
3122 |
#endif /* INET6 */ |
||
3123 |
} |
||
3124 |
bpf_error("only IP multicast filters supported on ethernet/FDDI"); |
||
3125 |
} |
||
3126 |
|||
3127 |
/* |
||
3128 |
* generate command for inbound/outbound. It's here so we can |
||
3129 |
* make it link-type specific. 'dir' = 0 implies "inbound", |
||
3130 |
* = 1 implies "outbound". |
||
3131 |
*/ |
||
3132 |
struct block * |
||
3133 |
gen_inbound(dir) |
||
3134 |
int dir; |
||
3135 |
{ |
||
3136 |
struct block *b0; |
||
3137 |
|||
3138 |
/* |
||
3139 |
* Only SLIP and old-style PPP data link types support |
||
3140 |
* inbound/outbound qualifiers. |
||
3141 |
*/ |
||
3142 |
switch (linktype) { |
||
3143 |
case DLT_SLIP: |
||
3144 |
case DLT_PPP: |
||
3145 |
b0 = gen_relation(BPF_JEQ, |
||
3146 |
gen_load(Q_LINK, gen_loadi(0), 1), |
||
3147 |
gen_loadi(0), |
||
3148 |
dir); |
||
3149 |
break; |
||
3150 |
|||
3151 |
case DLT_PFLOG: |
||
3152 |
b0 = gen_cmp(offsetof(struct pfloghdr, dir), BPF_B, |
||
3153 |
(bpf_int32)((dir == 0) ? PF_IN : PF_OUT)); |
||
3154 |
break; |
||
3155 |
|||
3156 |
default: |
||
3157 |
bpf_error("inbound/outbound not supported on linktype 0x%x", |
||
3158 |
linktype); |
||
3159 |
/* NOTREACHED */ |
||
3160 |
} |
||
3161 |
|||
3162 |
return (b0); |
||
3163 |
} |
||
3164 |
|||
3165 |
|||
3166 |
/* PF firewall log matched interface */ |
||
3167 |
struct block * |
||
3168 |
gen_pf_ifname(char *ifname) |
||
3169 |
{ |
||
3170 |
struct block *b0; |
||
3171 |
u_int len, off; |
||
3172 |
|||
3173 |
if (linktype == DLT_PFLOG) { |
||
3174 |
len = sizeof(((struct pfloghdr *)0)->ifname); |
||
3175 |
off = offsetof(struct pfloghdr, ifname); |
||
3176 |
} else { |
||
3177 |
bpf_error("ifname not supported on linktype 0x%x", linktype); |
||
3178 |
/* NOTREACHED */ |
||
3179 |
} |
||
3180 |
if (strlen(ifname) >= len) { |
||
3181 |
bpf_error("ifname interface names can only be %d characters", |
||
3182 |
len - 1); |
||
3183 |
/* NOTREACHED */ |
||
3184 |
} |
||
3185 |
b0 = gen_bcmp(off, strlen(ifname), ifname); |
||
3186 |
return (b0); |
||
3187 |
} |
||
3188 |
|||
3189 |
|||
3190 |
/* PF firewall log ruleset name */ |
||
3191 |
struct block * |
||
3192 |
gen_pf_ruleset(char *ruleset) |
||
3193 |
{ |
||
3194 |
struct block *b0; |
||
3195 |
|||
3196 |
if (linktype != DLT_PFLOG) { |
||
3197 |
bpf_error("ruleset not supported on linktype 0x%x", linktype); |
||
3198 |
/* NOTREACHED */ |
||
3199 |
} |
||
3200 |
if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { |
||
3201 |
bpf_error("ruleset names can only be %zu characters", |
||
3202 |
sizeof(((struct pfloghdr *)0)->ruleset) - 1); |
||
3203 |
/* NOTREACHED */ |
||
3204 |
} |
||
3205 |
b0 = gen_bcmp(offsetof(struct pfloghdr, ruleset), |
||
3206 |
strlen(ruleset), ruleset); |
||
3207 |
return (b0); |
||
3208 |
} |
||
3209 |
|||
3210 |
|||
3211 |
/* PF firewall log rule number */ |
||
3212 |
struct block * |
||
3213 |
gen_pf_rnr(int rnr) |
||
3214 |
{ |
||
3215 |
struct block *b0; |
||
3216 |
|||
3217 |
if (linktype == DLT_PFLOG) { |
||
3218 |
b0 = gen_cmp(offsetof(struct pfloghdr, rulenr), BPF_W, |
||
3219 |
(bpf_int32)rnr); |
||
3220 |
} else { |
||
3221 |
bpf_error("rnr not supported on linktype 0x%x", linktype); |
||
3222 |
/* NOTREACHED */ |
||
3223 |
} |
||
3224 |
|||
3225 |
return (b0); |
||
3226 |
} |
||
3227 |
|||
3228 |
|||
3229 |
/* PF firewall log sub-rule number */ |
||
3230 |
struct block * |
||
3231 |
gen_pf_srnr(int srnr) |
||
3232 |
{ |
||
3233 |
struct block *b0; |
||
3234 |
|||
3235 |
if (linktype != DLT_PFLOG) { |
||
3236 |
bpf_error("srnr not supported on linktype 0x%x", linktype); |
||
3237 |
/* NOTREACHED */ |
||
3238 |
} |
||
3239 |
|||
3240 |
b0 = gen_cmp(offsetof(struct pfloghdr, subrulenr), BPF_W, |
||
3241 |
(bpf_int32)srnr); |
||
3242 |
return (b0); |
||
3243 |
} |
||
3244 |
|||
3245 |
/* PF firewall log reason code */ |
||
3246 |
struct block * |
||
3247 |
gen_pf_reason(int reason) |
||
3248 |
{ |
||
3249 |
struct block *b0; |
||
3250 |
|||
3251 |
if (linktype == DLT_PFLOG) { |
||
3252 |
b0 = gen_cmp(offsetof(struct pfloghdr, reason), BPF_B, |
||
3253 |
(bpf_int32)reason); |
||
3254 |
} else { |
||
3255 |
bpf_error("reason not supported on linktype 0x%x", linktype); |
||
3256 |
/* NOTREACHED */ |
||
3257 |
} |
||
3258 |
|||
3259 |
return (b0); |
||
3260 |
} |
||
3261 |
|||
3262 |
/* PF firewall log action */ |
||
3263 |
struct block * |
||
3264 |
gen_pf_action(int action) |
||
3265 |
{ |
||
3266 |
struct block *b0; |
||
3267 |
|||
3268 |
if (linktype == DLT_PFLOG) { |
||
3269 |
b0 = gen_cmp(offsetof(struct pfloghdr, action), BPF_B, |
||
3270 |
(bpf_int32)action); |
||
3271 |
} else { |
||
3272 |
bpf_error("action not supported on linktype 0x%x", linktype); |
||
3273 |
/* NOTREACHED */ |
||
3274 |
} |
||
3275 |
|||
3276 |
return (b0); |
||
3277 |
} |
||
3278 |
|||
3279 |
/* IEEE 802.11 wireless header */ |
||
3280 |
struct block * |
||
3281 |
gen_p80211_type(int type, int mask) |
||
3282 |
{ |
||
3283 |
struct block *b0; |
||
3284 |
u_int offset; |
||
3285 |
|||
3286 |
if (!(linktype == DLT_IEEE802_11 || |
||
3287 |
linktype == DLT_IEEE802_11_RADIO)) { |
||
3288 |
bpf_error("type not supported on linktype 0x%x", |
||
3289 |
linktype); |
||
3290 |
/* NOTREACHED */ |
||
3291 |
} |
||
3292 |
offset = (u_int)offsetof(struct ieee80211_frame, i_fc[0]); |
||
3293 |
if (linktype == DLT_IEEE802_11_RADIO) |
||
3294 |
offset += IEEE80211_RADIOTAP_HDRLEN; |
||
3295 |
|||
3296 |
b0 = gen_mcmp(offset, BPF_B, (bpf_int32)type, (bpf_u_int32)mask); |
||
3297 |
|||
3298 |
return (b0); |
||
3299 |
} |
||
3300 |
|||
3301 |
static struct block * |
||
3302 |
gen_ahostop(eaddr, dir) |
||
3303 |
const u_char *eaddr; |
||
3304 |
int dir; |
||
3305 |
{ |
||
3306 |
struct block *b0, *b1; |
||
3307 |
|||
3308 |
switch (dir) { |
||
3309 |
/* src comes first, different from Ethernet */ |
||
3310 |
case Q_SRC: |
||
3311 |
return gen_bcmp(0, 1, eaddr); |
||
3312 |
|||
3313 |
case Q_DST: |
||
3314 |
return gen_bcmp(1, 1, eaddr); |
||
3315 |
|||
3316 |
case Q_AND: |
||
3317 |
b0 = gen_ahostop(eaddr, Q_SRC); |
||
3318 |
b1 = gen_ahostop(eaddr, Q_DST); |
||
3319 |
gen_and(b0, b1); |
||
3320 |
return b1; |
||
3321 |
|||
3322 |
case Q_DEFAULT: |
||
3323 |
case Q_OR: |
||
3324 |
b0 = gen_ahostop(eaddr, Q_SRC); |
||
3325 |
b1 = gen_ahostop(eaddr, Q_DST); |
||
3326 |
gen_or(b0, b1); |
||
3327 |
return b1; |
||
3328 |
} |
||
3329 |
abort(); |
||
3330 |
/* NOTREACHED */ |
||
3331 |
} |
||
3332 |
|||
3333 |
struct block * |
||
3334 |
gen_acode(eaddr, q) |
||
3335 |
const u_char *eaddr; |
||
3336 |
struct qual q; |
||
3337 |
{ |
||
3338 |
if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { |
||
3339 |
if (linktype == DLT_ARCNET) |
||
3340 |
return gen_ahostop(eaddr, (int)q.dir); |
||
3341 |
} |
||
3342 |
bpf_error("ARCnet address used in non-arc expression"); |
||
3343 |
/* NOTREACHED */ |
||
3344 |
} |
||
3345 |
|||
3346 |
/* |
||
3347 |
* support IEEE 802.1Q VLAN trunk over ethernet |
||
3348 |
*/ |
||
3349 |
struct block * |
||
3350 |
gen_vlan(vlan_num) |
||
3351 |
int vlan_num; |
||
3352 |
{ |
||
3353 |
struct block *b0; |
||
3354 |
|||
3355 |
if (variable_nl) { |
||
3356 |
bpf_error("'vlan' not supported for variable DLTs"); |
||
3357 |
/*NOTREACHED*/ |
||
3358 |
} |
||
3359 |
|||
3360 |
/* |
||
3361 |
* Change the offsets to point to the type and data fields within |
||
3362 |
* the VLAN packet. This is somewhat of a kludge. |
||
3363 |
*/ |
||
3364 |
if (orig_nl == (u_int)-1) { |
||
3365 |
orig_linktype = off_linktype; /* save original values */ |
||
3366 |
orig_nl = off_nl; |
||
3367 |
orig_nl_nosnap = off_nl_nosnap; |
||
3368 |
|||
3369 |
switch (linktype) { |
||
3370 |
|||
3371 |
case DLT_EN10MB: |
||
3372 |
off_linktype = 16; |
||
3373 |
off_nl_nosnap = 18; |
||
3374 |
off_nl = 18; |
||
3375 |
break; |
||
3376 |
|||
3377 |
default: |
||
3378 |
bpf_error("no VLAN support for data link type %d", |
||
3379 |
linktype); |
||
3380 |
/*NOTREACHED*/ |
||
3381 |
} |
||
3382 |
} |
||
3383 |
|||
3384 |
/* check for VLAN */ |
||
3385 |
b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q); |
||
3386 |
|||
3387 |
/* If a specific VLAN is requested, check VLAN id */ |
||
3388 |
if (vlan_num >= 0) { |
||
3389 |
struct block *b1; |
||
3390 |
|||
3391 |
b1 = gen_cmp(orig_nl, BPF_H, (bpf_int32)vlan_num); |
||
3392 |
gen_and(b0, b1); |
||
3393 |
b0 = b1; |
||
3394 |
} |
||
3395 |
|||
3396 |
return (b0); |
||
3397 |
} |
||
3398 |
|||
3399 |
struct block * |
||
3400 |
gen_p80211_fcdir(int fcdir) |
||
3401 |
{ |
||
3402 |
struct block *b0; |
||
3403 |
u_int offset; |
||
3404 |
|||
3405 |
if (!(linktype == DLT_IEEE802_11 || |
||
3406 |
linktype == DLT_IEEE802_11_RADIO)) { |
||
3407 |
bpf_error("frame direction not supported on linktype 0x%x", |
||
3408 |
linktype); |
||
3409 |
/* NOTREACHED */ |
||
3410 |
} |
||
3411 |
offset = (u_int)offsetof(struct ieee80211_frame, i_fc[1]); |
||
3412 |
if (linktype == DLT_IEEE802_11_RADIO) |
||
3413 |
offset += IEEE80211_RADIOTAP_HDRLEN; |
||
3414 |
|||
3415 |
b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir, |
||
3416 |
(bpf_u_int32)IEEE80211_FC1_DIR_MASK); |
||
3417 |
|||
3418 |
return (b0); |
||
3419 |
} |
||
3420 |
|||
3421 |
static struct block * |
||
3422 |
gen_p80211_hostop(const u_char *lladdr, int dir) |
||
3423 |
{ |
||
3424 |
struct block *b0, *b1, *b2, *b3, *b4; |
||
3425 |
u_int offset = 0; |
||
3426 |
|||
3427 |
if (linktype == DLT_IEEE802_11_RADIO) |
||
3428 |
offset = IEEE80211_RADIOTAP_HDRLEN; |
||
3429 |
|||
3430 |
switch (dir) { |
||
3431 |
case Q_SRC: |
||
3432 |
b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset + |
||
3433 |
(u_int)offsetof(struct ieee80211_frame, i_addr2), |
||
3434 |
lladdr); |
||
3435 |
b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset + |
||
3436 |
(u_int)offsetof(struct ieee80211_frame, i_addr2), |
||
3437 |
lladdr); |
||
3438 |
b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset + |
||
3439 |
(u_int)offsetof(struct ieee80211_frame, i_addr3), |
||
3440 |
lladdr); |
||
3441 |
b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + |
||
3442 |
(u_int)offsetof(struct ieee80211_frame_addr4, i_addr4), |
||
3443 |
lladdr); |
||
3444 |
b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + |
||
3445 |
(u_int)offsetof(struct ieee80211_frame_addr4, i_addr2), |
||
3446 |
lladdr); |
||
3447 |
|||
3448 |
gen_or(b0, b1); |
||
3449 |
gen_or(b1, b2); |
||
3450 |
gen_or(b2, b3); |
||
3451 |
gen_or(b3, b4); |
||
3452 |
return (b4); |
||
3453 |
|||
3454 |
case Q_DST: |
||
3455 |
b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset + |
||
3456 |
(u_int)offsetof(struct ieee80211_frame, i_addr1), |
||
3457 |
lladdr); |
||
3458 |
b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset + |
||
3459 |
(u_int)offsetof(struct ieee80211_frame, i_addr3), |
||
3460 |
lladdr); |
||
3461 |
b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset + |
||
3462 |
(u_int)offsetof(struct ieee80211_frame, i_addr1), |
||
3463 |
lladdr); |
||
3464 |
b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + |
||
3465 |
(u_int)offsetof(struct ieee80211_frame_addr4, i_addr3), |
||
3466 |
lladdr); |
||
3467 |
b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + |
||
3468 |
(u_int)offsetof(struct ieee80211_frame_addr4, i_addr1), |
||
3469 |
lladdr); |
||
3470 |
|||
3471 |
gen_or(b0, b1); |
||
3472 |
gen_or(b1, b2); |
||
3473 |
gen_or(b2, b3); |
||
3474 |
gen_or(b3, b4); |
||
3475 |
return (b4); |
||
3476 |
|||
3477 |
case Q_ADDR1: |
||
3478 |
return (gen_bcmp(offset + |
||
3479 |
(u_int)offsetof(struct ieee80211_frame, |
||
3480 |
i_addr1), IEEE80211_ADDR_LEN, lladdr)); |
||
3481 |
|||
3482 |
case Q_ADDR2: |
||
3483 |
return (gen_bcmp(offset + |
||
3484 |
(u_int)offsetof(struct ieee80211_frame, |
||
3485 |
i_addr2), IEEE80211_ADDR_LEN, lladdr)); |
||
3486 |
|||
3487 |
case Q_ADDR3: |
||
3488 |
return (gen_bcmp(offset + |
||
3489 |
(u_int)offsetof(struct ieee80211_frame, |
||
3490 |
i_addr3), IEEE80211_ADDR_LEN, lladdr)); |
||
3491 |
|||
3492 |
case Q_ADDR4: |
||
3493 |
return (gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + |
||
3494 |
(u_int)offsetof(struct ieee80211_frame_addr4, i_addr4), |
||
3495 |
lladdr)); |
||
3496 |
|||
3497 |
case Q_AND: |
||
3498 |
b0 = gen_p80211_hostop(lladdr, Q_SRC); |
||
3499 |
b1 = gen_p80211_hostop(lladdr, Q_DST); |
||
3500 |
gen_and(b0, b1); |
||
3501 |
return (b1); |
||
3502 |
|||
3503 |
case Q_DEFAULT: |
||
3504 |
case Q_OR: |
||
3505 |
b0 = gen_p80211_hostop(lladdr, Q_ADDR1); |
||
3506 |
b1 = gen_p80211_hostop(lladdr, Q_ADDR2); |
||
3507 |
b2 = gen_p80211_hostop(lladdr, Q_ADDR3); |
||
3508 |
b3 = gen_p80211_hostop(lladdr, Q_ADDR4); |
||
3509 |
gen_or(b0, b1); |
||
3510 |
gen_or(b1, b2); |
||
3511 |
gen_or(b2, b3); |
||
3512 |
return (b3); |
||
3513 |
|||
3514 |
default: |
||
3515 |
bpf_error("direction not supported on linktype 0x%x", |
||
3516 |
linktype); |
||
3517 |
} |
||
3518 |
/* NOTREACHED */ |
||
3519 |
} |
||
3520 |
|||
3521 |
static struct block * |
||
3522 |
gen_p80211_addr(int fcdir, u_int offset, const u_char *lladdr) |
||
3523 |
{ |
||
3524 |
struct block *b0, *b1; |
||
3525 |
|||
3526 |
b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir, IEEE80211_FC1_DIR_MASK); |
||
3527 |
b1 = gen_bcmp(offset, IEEE80211_ADDR_LEN, lladdr); |
||
3528 |
gen_and(b0, b1); |
||
3529 |
|||
3530 |
return (b1); |
||
3531 |
} |
Generated by: GCOVR (Version 3.3) |