diff --git a/gencode.c b/gencode.c index 4ec901f6b3..7b115996bd 100644 --- a/gencode.c +++ b/gencode.c @@ -10712,3 +10712,52 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type) } return b1; } + +struct block* +gen_offset(compiler_state_t *cstate, struct arth *a_arg) +{ + struct arth *a = a_arg; + struct block *b; + struct slist *s, *s1; + bpf_abs_offset *offsets[2]; + int i; + offsets[0] = &(cstate->off_linkpl); + offsets[1] = &(cstate->off_linktype)}; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + s = NULL; + b = gen_true(cstate); + for (i = 0; i < 2; ++i) { + bpf_abs_offset *off = offsets[i]; + // Make sure the offset being adjusted is variable + if (!off->is_variable) + off->is_variable = 1; + if (off->reg == -1) + off->reg = alloc_reg(cstate); + + // Put the current offset into the accumulator + s = new_stmt(cstate, BPF_LD|BPF_MEM); + s->s.k = off->reg; + + // Put the computed offset into the extra register + s1 = xfer_to_x(cstate, a); + sappend(s, s1); + + // Add to the accumulator from the computed offset in the extra register + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); + sappend(s, s1); + + s1 = new_stmt(cstate, BPF_ST); + s1->s.k = off->reg; + sappend(s, s1); + } + sappend(a->s, s); + b->stmts = a->s; + return b; +} diff --git a/gencode.h b/gencode.h index 22752ed1aa..3ed4019f93 100644 --- a/gencode.h +++ b/gencode.h @@ -378,6 +378,8 @@ struct block *gen_pf_action(compiler_state_t *, int); struct block *gen_p80211_type(compiler_state_t *, bpf_u_int32, bpf_u_int32); struct block *gen_p80211_fcdir(compiler_state_t *, bpf_u_int32); +struct block *gen_offset(compiler_state_t *, struct arth *); + /* * Representation of a program as a tree of blocks, plus current mark. * A block is marked if only if its mark equals the current mark. diff --git a/grammar.y.in b/grammar.y.in index 4df433960e..7ef420c666 100644 --- a/grammar.y.in +++ b/grammar.y.in @@ -401,6 +401,7 @@ DIAG_OFF_BISON_BYACC %token RADIO %token FISU LSSU MSU HFISU HLSSU HMSU %token SIO OPC DPC SLS HSIO HOPC HDPC HSLS +%token OFFSET %token LEX_ERROR %type ID EID AID @@ -689,6 +690,7 @@ other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); } | GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); } | VXLAN pnum { CHECK_PTR_VAL(($$ = gen_vxlan(cstate, $2, 1))); } | VXLAN { CHECK_PTR_VAL(($$ = gen_vxlan(cstate, 0, 0))); } + | OFFSET arth { CHECK_PTR_VAL(($$ = gen_offset(cstate, $2))); } | pfvar { $$ = $1; } | pqual p80211 { $$ = $2; } | pllc { $$ = $1; } diff --git a/scanner.l b/scanner.l index 0fa8f40724..2b28f8291e 100644 --- a/scanner.l +++ b/scanner.l @@ -471,6 +471,8 @@ tcp-ack { yylval->h = 0x10; return NUM; } tcp-urg { yylval->h = 0x20; return NUM; } tcp-ece { yylval->h = 0x40; return NUM; } tcp-cwr { yylval->h = 0x80; return NUM; } + +offset return OFFSET; [A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { yylval->s = sdup(yyextra, (char *)yytext); return ID; } "\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; }