diff --git a/bpf/net/bpf_filter.c b/bpf/net/bpf_filter.c index 22aff79..1c75840 100644 --- a/bpf/net/bpf_filter.c +++ b/bpf/net/bpf_filter.c @@ -377,7 +377,37 @@ bpf_filter(pc, p, wirelen, buflen) return 0; #endif } - X = (p[pc->k] & 0xf) << 2; + X = (p[k] & 0xf) << 2; + continue; + + case BPF_LDX|BPF_MSHM|BPF_B: + k = pc->k; + if (k >= buflen) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + k = mtod(n, char *)[k]; +#else + return 0; +#endif + } else { + k = p[k]; + } + if (k >= buflen) { +#if defined(KERNEL) || defined(_KERNEL) + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + X = (mtod(n, char *)[k] & 0xf) << 2; + continue; +#else + return 0; +#endif + } + X = (p[k] & 0xf) << 2; continue; case BPF_LD|BPF_IMM: diff --git a/bpf_image.c b/bpf_image.c index e2f1a77..7ccf95f 100644 --- a/bpf_image.c +++ b/bpf_image.c @@ -130,6 +130,11 @@ bpf_image(p, n) fmt = "4*([%d]&0xf)"; break; + case BPF_LDX|BPF_MSHM|BPF_B: + op = "ldxbi"; + fmt = "4*([[%d]]&0xf)"; + break; + case BPF_LD|BPF_MEM: op = "ld"; fmt = "M[%d]"; diff --git a/gencode.c b/gencode.c index b94ea72..6d2f6bb 100644 --- a/gencode.c +++ b/gencode.c @@ -1598,6 +1598,14 @@ init_linktype(p) off_nl = -1; off_nl_nosnap = -1; return; + + case DLT_LINK: + off_linktype = 8; + off_macpl = 0; + off_macpl_is_variable = 1; + off_nl = 0; + off_nl_nosnap = 0; + return; } bpf_error("unknown data link type %d", linktype); /* NOTREACHED */ @@ -1766,7 +1774,10 @@ gen_loadx_iphdrlen() { struct slist *s, *s2; - s = gen_off_macpl(); + if (linktype != DLT_LINK) + s = gen_off_macpl(); + else + s = NULL; if (s != NULL) { /* * There's a variable-length prefix preceding the @@ -1808,8 +1819,13 @@ gen_loadx_iphdrlen() * of off_mac_pl + off_nl from the beginning of the * raw packet data. */ - s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); - s->s.k = off_macpl + off_nl; + if (linktype == DLT_LINK) { + s = new_stmt(BPF_LDX|BPF_MSHM|BPF_B); + s->s.k = 2; + } else { + s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s->s.k = off_macpl + off_nl; + } } return s; } @@ -2427,6 +2443,39 @@ gen_load_radiotap_llprefixlen() return (NULL); } +static struct slist * +gen_load_link_ll_header_len() +{ + struct slist *s1, *s2; + + if (reg_off_macpl == -1) + reg_off_macpl = alloc_reg(); + + /* + * Generate code to load the length of the link header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (reg_off_macpl != -1) { + s1 = new_stmt(BPF_LD|BPF_H|BPF_ABS); + s1->s.k = 2; + s2 = new_stmt(BPF_ST); + s2->s.k = reg_off_macpl; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + /* * At the moment we treat PPI as normal Radiotap encoded * packets. The difference is in the function that generates @@ -2765,6 +2814,11 @@ insert_compute_vloffsets(b) case DLT_PPI: s = gen_load_802_11_header_len(s, b->stmts); break; + + case DLT_LINK: + s = gen_load_link_ll_header_len(); + break; + } /* @@ -5670,8 +5724,13 @@ gen_protochain(v, proto, dir) s[i]->s.k = off_macpl + off_nl + 9; i++; /* X = ip->ip_hl << 2 */ - s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); - s[i]->s.k = off_macpl + off_nl; + if (linktype == DLT_LINK) { + s[i] = new_stmt(BPF_LDX|BPF_MSHM|BPF_B); + s[i]->s.k = 2; + } else { + s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s[i]->s.k = off_macpl + off_nl; + } i++; break; #ifdef INET6 diff --git a/optimize.c b/optimize.c index 46dffec..0f6fd0a 100644 --- a/optimize.c +++ b/optimize.c @@ -785,7 +785,8 @@ opt_peep(b) * following it (with 0 or more nops between the * ldxms and addx). */ - if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B)) + if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B) && + next->s.code != (BPF_LDX|BPF_MSHM|BPF_B)) add = next; else add = this_op(next->next); @@ -1030,6 +1031,11 @@ opt_stmt(s, val, alter) vstore(s, &val[X_ATOM], v, alter); break; + case BPF_LDX|BPF_MSHM|BPF_B: + v = F(s->code, s->k, 0L); + vstore(s, &val[X_ATOM], v, alter); + break; + case BPF_ALU|BPF_NEG: if (alter && vmap[val[A_ATOM]].is_const) { s->code = BPF_LD|BPF_IMM; diff --git a/pcap/bpf.h b/pcap/bpf.h index 950b85b..db4ff8e 100644 --- a/pcap/bpf.h +++ b/pcap/bpf.h @@ -1035,6 +1035,7 @@ struct bpf_version { #define BPF_MEM 0x60 #define BPF_LEN 0x80 #define BPF_MSH 0xa0 +#define BPF_MSHM 0xe0 /* alu/jmp fields */ #define BPF_OP(code) ((code) & 0xf0)