ring: use xzmalloc_aligned
[netsniff-ng.git] / bpf_parser.y
blob4e50a9458f8a7743756009b570f47ccd5d0e7304
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 /* yacc-func-prefix: yy */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdbool.h>
16 #include <signal.h>
17 #include <stdint.h>
18 #include <errno.h>
19 #include <libgen.h>
20 #include <linux/filter.h>
22 #include "bpf.h"
23 #include "str.h"
24 #include "xmalloc.h"
25 #include "bpf_parser.tab.h"
26 #include "built_in.h"
27 #include "die.h"
28 #include "cpp.h"
30 static int curr_instr = 0;
32 static struct sock_filter out[BPF_MAXINSNS];
34 static char *labels[BPF_MAXINSNS];
35 static char *labels_jt[BPF_MAXINSNS];
36 static char *labels_jf[BPF_MAXINSNS];
37 static char *labels_k[BPF_MAXINSNS];
39 #define YYERROR_VERBOSE 0
40 #define YYDEBUG 0
41 #define YYLTYPE_IS_TRIVIAL 1
43 extern FILE *yyin;
44 extern int yylex(void);
45 extern void yyerror(const char *);
46 extern int yylineno;
47 extern char *yytext;
49 static inline void check_max_instr(void)
51 if (curr_instr >= BPF_MAXINSNS)
52 panic("Exceeded maximal number of instructions!\n");
55 static inline void set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf, uint32_t k)
57 check_max_instr();
59 out[curr_instr].code = code;
60 out[curr_instr].jt = jt;
61 out[curr_instr].jf = jf;
62 out[curr_instr].k = k;
64 curr_instr++;
67 static inline void set_curr_label(char *label)
69 check_max_instr();
71 labels[curr_instr] = label;
74 #define JTL 1
75 #define JFL 2
76 #define JKL 3
78 static inline void set_jmp_label(char *label, int which)
80 check_max_instr();
82 switch (which) {
83 case JTL:
84 labels_jt[curr_instr] = label;
85 break;
86 case JFL:
87 labels_jf[curr_instr] = label;
88 break;
89 case JKL:
90 labels_k[curr_instr] = label;
91 break;
92 default:
93 bug();
97 static int find_intr_offset_or_panic(char *label_to_search)
99 int i, max = curr_instr, ret = -ENOENT;
101 bug_on(!label_to_search);
103 for (i = 0; i < max; ++i) {
104 if (labels[i] != NULL) {
105 /* Both are \0-terminated! */
106 if (!strcmp(label_to_search, labels[i])) {
107 ret = i;
108 break;
113 if (ret == -ENOENT)
114 panic("No such label!\n");
116 return ret;
121 %union {
122 char *label;
123 long int number;
126 %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
127 %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH
128 %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
129 %token OP_LDXI
131 %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
132 %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF
134 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
136 %token number label
138 %type <number> number
139 %type <label> label
143 prog
144 : line
145 | prog line
148 line
149 : instr
150 | labelled_instr
153 labelled_instr
154 : labelled instr
157 instr
158 : ldb
159 | ldh
160 | ld
161 | ldi
162 | ldx
163 | ldxi
164 | st
165 | stx
166 | jmp
167 | jeq
168 | jneq
169 | jlt
170 | jle
171 | jgt
172 | jge
173 | jset
174 | add
175 | sub
176 | mul
177 | div
178 | mod
179 | neg
180 | and
181 | or
182 | xor
183 | lsh
184 | rsh
185 | ret
186 | tax
187 | txa
190 labelled
191 : label ':' { set_curr_label($1); }
195 : OP_LDB '[' 'x' '+' number ']' {
196 set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); }
197 | OP_LDB '[' '%' 'x' '+' number ']' {
198 set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
199 | OP_LDB '[' number ']' {
200 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
201 | OP_LDB K_PROTO {
202 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
203 SKF_AD_OFF + SKF_AD_PROTOCOL); }
204 | OP_LDB K_TYPE {
205 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
206 SKF_AD_OFF + SKF_AD_PKTTYPE); }
207 | OP_LDB K_IFIDX {
208 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
209 SKF_AD_OFF + SKF_AD_IFINDEX); }
210 | OP_LDB K_NLATTR {
211 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
212 SKF_AD_OFF + SKF_AD_NLATTR); }
213 | OP_LDB K_NLATTR_NEST {
214 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
215 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
216 | OP_LDB K_MARK {
217 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
218 SKF_AD_OFF + SKF_AD_MARK); }
219 | OP_LDB K_QUEUE {
220 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
221 SKF_AD_OFF + SKF_AD_QUEUE); }
222 | OP_LDB K_HATYPE {
223 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
224 SKF_AD_OFF + SKF_AD_HATYPE); }
225 | OP_LDB K_RXHASH {
226 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
227 SKF_AD_OFF + SKF_AD_RXHASH); }
228 | OP_LDB K_CPU {
229 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
230 SKF_AD_OFF + SKF_AD_CPU); }
231 | OP_LDB K_VLANT {
232 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
233 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
234 | OP_LDB K_VLANP {
235 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
236 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
237 | OP_LDB K_POFF {
238 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
239 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
243 : OP_LDH '[' 'x' '+' number ']' {
244 set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); }
245 | OP_LDH '[' '%' 'x' '+' number ']' {
246 set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
247 | OP_LDH '[' number ']' {
248 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
249 | OP_LDH K_PROTO {
250 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
251 SKF_AD_OFF + SKF_AD_PROTOCOL); }
252 | OP_LDH K_TYPE {
253 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
254 SKF_AD_OFF + SKF_AD_PKTTYPE); }
255 | OP_LDH K_IFIDX {
256 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
257 SKF_AD_OFF + SKF_AD_IFINDEX); }
258 | OP_LDH K_NLATTR {
259 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
260 SKF_AD_OFF + SKF_AD_NLATTR); }
261 | OP_LDH K_NLATTR_NEST {
262 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
263 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
264 | OP_LDH K_MARK {
265 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
266 SKF_AD_OFF + SKF_AD_MARK); }
267 | OP_LDH K_QUEUE {
268 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
269 SKF_AD_OFF + SKF_AD_QUEUE); }
270 | OP_LDH K_HATYPE {
271 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
272 SKF_AD_OFF + SKF_AD_HATYPE); }
273 | OP_LDH K_RXHASH {
274 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
275 SKF_AD_OFF + SKF_AD_RXHASH); }
276 | OP_LDH K_CPU {
277 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
278 SKF_AD_OFF + SKF_AD_CPU); }
279 | OP_LDH K_VLANT {
280 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
281 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
282 | OP_LDH K_VLANP {
283 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
284 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
285 | OP_LDH K_POFF {
286 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
287 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
291 : OP_LDI '#' number {
292 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
293 | OP_LDI number {
294 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); }
298 : OP_LD '#' number {
299 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
300 | OP_LD K_PKT_LEN {
301 set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
302 | OP_LD K_PROTO {
303 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
304 SKF_AD_OFF + SKF_AD_PROTOCOL); }
305 | OP_LD K_TYPE {
306 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
307 SKF_AD_OFF + SKF_AD_PKTTYPE); }
308 | OP_LD K_IFIDX {
309 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
310 SKF_AD_OFF + SKF_AD_IFINDEX); }
311 | OP_LD K_NLATTR {
312 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
313 SKF_AD_OFF + SKF_AD_NLATTR); }
314 | OP_LD K_NLATTR_NEST {
315 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
316 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
317 | OP_LD K_MARK {
318 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
319 SKF_AD_OFF + SKF_AD_MARK); }
320 | OP_LD K_QUEUE {
321 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
322 SKF_AD_OFF + SKF_AD_QUEUE); }
323 | OP_LD K_HATYPE {
324 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
325 SKF_AD_OFF + SKF_AD_HATYPE); }
326 | OP_LD K_RXHASH {
327 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
328 SKF_AD_OFF + SKF_AD_RXHASH); }
329 | OP_LD K_CPU {
330 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
331 SKF_AD_OFF + SKF_AD_CPU); }
332 | OP_LD K_VLANT {
333 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
334 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
335 | OP_LD K_VLANP {
336 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
337 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
338 | OP_LD K_POFF {
339 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
340 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
341 | OP_LD 'M' '[' number ']' {
342 set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
343 | OP_LD '[' 'x' '+' number ']' {
344 set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); }
345 | OP_LD '[' '%' 'x' '+' number ']' {
346 set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); }
347 | OP_LD '[' number ']' {
348 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); }
351 ldxi
352 : OP_LDXI '#' number {
353 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
354 | OP_LDXI number {
355 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); }
359 : OP_LDX '#' number {
360 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
361 | OP_LDX K_PKT_LEN {
362 set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); }
363 | OP_LDX 'M' '[' number ']' {
364 set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); }
365 | OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
366 if ($2 != 4 || $9 != 0xf) {
367 panic("ldxb offset not supported!\n");
368 } else {
369 set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
370 | OP_LDX number '*' '(' '[' number ']' '&' number ')' {
371 if ($2 != 4 || $9 != 0xf) {
372 panic("ldxb offset not supported!\n");
373 } else {
374 set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
378 : OP_ST 'M' '[' number ']' {
379 set_curr_instr(BPF_ST, 0, 0, $4); }
383 : OP_STX 'M' '[' number ']' {
384 set_curr_instr(BPF_STX, 0, 0, $4); }
388 : OP_JMP label {
389 set_jmp_label($2, JKL);
390 set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); }
394 : OP_JEQ '#' number ',' label ',' label {
395 set_jmp_label($5, JTL);
396 set_jmp_label($7, JFL);
397 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
398 | OP_JEQ 'x' ',' label ',' label {
399 set_jmp_label($4, JTL);
400 set_jmp_label($6, JFL);
401 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
402 | OP_JEQ '%' 'x' ',' label ',' label {
403 set_jmp_label($5, JTL);
404 set_jmp_label($7, JFL);
405 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
406 | OP_JEQ '#' number ',' label {
407 set_jmp_label($5, JTL);
408 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
409 | OP_JEQ 'x' ',' label {
410 set_jmp_label($4, JTL);
411 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
412 | OP_JEQ '%' 'x' ',' label {
413 set_jmp_label($5, JTL);
414 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
417 jneq
418 : OP_JNEQ '#' number ',' label {
419 set_jmp_label($5, JFL);
420 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
421 | OP_JNEQ 'x' ',' label {
422 set_jmp_label($4, JFL);
423 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
424 | OP_JNEQ '%' 'x' ',' label {
425 set_jmp_label($5, JFL);
426 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
430 : OP_JLT '#' number ',' label {
431 set_jmp_label($5, JFL);
432 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
433 | OP_JLT 'x' ',' label {
434 set_jmp_label($4, JFL);
435 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
436 | OP_JLT '%' 'x' ',' label {
437 set_jmp_label($5, JFL);
438 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
442 : OP_JLE '#' number ',' label {
443 set_jmp_label($5, JFL);
444 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
445 | OP_JLE 'x' ',' label {
446 set_jmp_label($4, JFL);
447 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
448 | OP_JLE '%' 'x' ',' label {
449 set_jmp_label($5, JFL);
450 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
454 : OP_JGT '#' number ',' label ',' label {
455 set_jmp_label($5, JTL);
456 set_jmp_label($7, JFL);
457 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
458 | OP_JGT 'x' ',' label ',' label {
459 set_jmp_label($4, JTL);
460 set_jmp_label($6, JFL);
461 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
462 | OP_JGT '%' 'x' ',' label ',' label {
463 set_jmp_label($5, JTL);
464 set_jmp_label($7, JFL);
465 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
466 | OP_JGT '#' number ',' label {
467 set_jmp_label($5, JTL);
468 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
469 | OP_JGT 'x' ',' label {
470 set_jmp_label($4, JTL);
471 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
472 | OP_JGT '%' 'x' ',' label {
473 set_jmp_label($5, JTL);
474 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
478 : OP_JGE '#' number ',' label ',' label {
479 set_jmp_label($5, JTL);
480 set_jmp_label($7, JFL);
481 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
482 | OP_JGE 'x' ',' label ',' label {
483 set_jmp_label($4, JTL);
484 set_jmp_label($6, JFL);
485 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
486 | OP_JGE '%' 'x' ',' label ',' label {
487 set_jmp_label($5, JTL);
488 set_jmp_label($7, JFL);
489 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
490 | OP_JGE '#' number ',' label {
491 set_jmp_label($5, JTL);
492 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
493 | OP_JGE 'x' ',' label {
494 set_jmp_label($4, JTL);
495 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
496 | OP_JGE '%' 'x' ',' label {
497 set_jmp_label($5, JTL);
498 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
501 jset
502 : OP_JSET '#' number ',' label ',' label {
503 set_jmp_label($5, JTL);
504 set_jmp_label($7, JFL);
505 set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
506 | OP_JSET 'x' ',' label ',' label {
507 set_jmp_label($4, JTL);
508 set_jmp_label($6, JFL);
509 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
510 | OP_JSET '%' 'x' ',' label ',' label {
511 set_jmp_label($5, JTL);
512 set_jmp_label($7, JFL);
513 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
514 | OP_JSET '#' number ',' label {
515 set_jmp_label($5, JTL);
516 set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
517 | OP_JSET 'x' ',' label {
518 set_jmp_label($4, JTL);
519 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
520 | OP_JSET '%' 'x' ',' label {
521 set_jmp_label($5, JTL);
522 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
526 : OP_ADD '#' number {
527 set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); }
528 | OP_ADD 'x' {
529 set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
530 | OP_ADD '%' 'x' {
531 set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
535 : OP_SUB '#' number {
536 set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); }
537 | OP_SUB 'x' {
538 set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
539 | OP_SUB '%' 'x' {
540 set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
544 : OP_MUL '#' number {
545 set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); }
546 | OP_MUL 'x' {
547 set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
548 | OP_MUL '%' 'x' {
549 set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
553 : OP_DIV '#' number {
554 set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); }
555 | OP_DIV 'x' {
556 set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
557 | OP_DIV '%' 'x' {
558 set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
562 : OP_MOD '#' number {
563 set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); }
564 | OP_MOD 'x' {
565 set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
566 | OP_MOD '%' 'x' {
567 set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
571 : OP_NEG {
572 set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); }
576 : OP_AND '#' number {
577 set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); }
578 | OP_AND 'x' {
579 set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
580 | OP_AND '%' 'x' {
581 set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
585 : OP_OR '#' number {
586 set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); }
587 | OP_OR 'x' {
588 set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
589 | OP_OR '%' 'x' {
590 set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
594 : OP_XOR '#' number {
595 set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); }
596 | OP_XOR 'x' {
597 set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
598 | OP_XOR '%' 'x' {
599 set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
603 : OP_LSH '#' number {
604 set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); }
605 | OP_LSH 'x' {
606 set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
607 | OP_LSH '%' 'x' {
608 set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
612 : OP_RSH '#' number {
613 set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); }
614 | OP_RSH 'x' {
615 set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
616 | OP_RSH '%' 'x' {
617 set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
621 : OP_RET 'a' {
622 set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
623 | OP_RET '%' 'a' {
624 set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
625 | OP_RET 'x' {
626 set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
627 | OP_RET '%' 'x' {
628 set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
629 | OP_RET '#' number {
630 set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); }
634 : OP_TAX {
635 set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); }
639 : OP_TXA {
640 set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); }
645 static void stage_1_inline(void)
647 yyparse();
650 static void stage_2_label_reduce(void)
652 int i, max = curr_instr, off;
654 /* 1. reduce k jumps */
655 for (i = 0; i < max; ++i) {
656 if (labels_k[i] != NULL) {
657 off = find_intr_offset_or_panic(labels_k[i]);
658 out[i].k = (uint32_t) (off - i - 1);
662 /* 1. reduce jt jumps */
663 for (i = 0; i < max; ++i) {
664 if (labels_jt[i] != NULL) {
665 off = find_intr_offset_or_panic(labels_jt[i]);
666 out[i].jt = (uint8_t) (off - i -1);
670 /* 1. reduce jf jumps */
671 for (i = 0; i < max; ++i) {
672 if (labels_jf[i] != NULL) {
673 off = find_intr_offset_or_panic(labels_jf[i]);
674 out[i].jf = (uint8_t) (off - i - 1);
679 static void pretty_printer_c(const struct sock_fprog *prog)
681 int i;
683 for (i = 0; i < prog->len; ++i) {
684 printf("{ 0x%x, %u, %u, 0x%08x },\n",
685 prog->filter[i].code, prog->filter[i].jt,
686 prog->filter[i].jf, prog->filter[i].k);
690 static void pretty_printer_xt_bpf(const struct sock_fprog *prog)
692 int i;
694 printf("%d,", prog->len);
695 for (i = 0; i < prog->len; ++i) {
696 printf("%u %u %u %u,",
697 prog->filter[i].code, prog->filter[i].jt,
698 prog->filter[i].jf, prog->filter[i].k);
701 fflush(stdout);
704 static void pretty_printer_tcpdump(const struct sock_fprog *prog)
706 int i;
708 for (i = 0; i < prog->len; ++i) {
709 printf("%u %u %u %u\n",
710 prog->filter[i].code, prog->filter[i].jt,
711 prog->filter[i].jf, prog->filter[i].k);
715 static void pretty_printer(const struct sock_fprog *prog, int format)
717 switch (format) {
718 case 0:
719 pretty_printer_c(prog);
720 break;
721 case 1:
722 pretty_printer_xt_bpf(prog);
723 break;
724 case 2:
725 pretty_printer_tcpdump(prog);
726 break;
727 default:
728 bug();
732 int compile_filter(char *file, bool verbose, int bypass, int format,
733 bool invoke_cpp, char *const cpp_argv[])
735 int i;
736 struct sock_fprog res;
737 char tmp_file[128];
738 int ret = 0;
740 memset(tmp_file, 0, sizeof(tmp_file));
742 if (invoke_cpp) {
743 ret = cpp_exec(file, tmp_file, sizeof(tmp_file), cpp_argv);
744 if (ret) {
745 fprintf(stderr, "Failed to invoke C preprocessor!\n");
746 goto exit;
749 file = tmp_file;
752 if (!strncmp("-", file, strlen("-")))
753 yyin = stdin;
754 else
755 yyin = fopen(file, "r");
756 if (!yyin)
757 panic("Cannot open file!\n");
759 memset(out, 0, sizeof(out));
760 memset(labels, 0, sizeof(labels));
761 memset(labels_jf, 0, sizeof(labels_jf));
762 memset(labels_jt, 0, sizeof(labels_jt));
763 memset(labels_k, 0, sizeof(labels_k));
765 stage_1_inline();
766 stage_2_label_reduce();
768 res.filter = out;
769 res.len = curr_instr;
771 if (verbose) {
772 printf("Generated program:\n");
773 bpf_dump_all(&res);
776 if (!bypass) {
777 if (verbose) {
778 printf("Validating: ");
779 fflush(stdout);
782 if (__bpf_validate(&res) == 0) {
783 if (verbose)
784 printf("Semantic error! BPF validation failed!\n");
785 else {
786 printf("Semantic error! BPF validation failed! "
787 "Try -V for debugging output!\n");
788 ret = 1;
789 goto exit;
791 } else if (verbose) {
792 printf("is runnable!\n");
796 if (verbose)
797 printf("Result:\n");
799 pretty_printer(&res, format);
801 for (i = 0; i < res.len; ++i) {
802 free(labels[i]);
803 free(labels_jt[i]);
804 free(labels_jf[i]);
805 free(labels_k[i]);
808 if (yyin && yyin != stdin)
809 fclose(yyin);
811 exit:
812 if (invoke_cpp)
813 unlink(tmp_file);
815 return ret;
818 void yyerror(const char *err)
820 panic("Syntax error at line %d: %s! %s!\n",
821 yylineno, yytext, err);