vn_open now returns locked, so must unlock when done
[unix-history] / usr / src / sys / net / bpf_filter.c
CommitLineData
6cfe221b
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
54c31626
SM
3 * All rights reserved.
4 *
6cfe221b
KB
5 * This code is derived from the Stanford/CMU enet packet filter,
6 * (net/enet.c) distributed as part of 4.3BSD, and code contributed
7 * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory.
8 *
9 * %sccs.include.redist.c%
10 *
033112db 11 * @(#)bpf_filter.c 7.2 (Berkeley) %G%
6cfe221b
KB
12 *
13 * static char rcsid[] =
14 * "@(#) $Header: bpf_filter.c,v 1.10 91/04/24 22:07:07 mccanne Locked $ (LBL)";
54c31626 15 */
54c31626 16
f8e186b1 17#include <sys/param.h>
54c31626 18#include <sys/types.h>
54c31626
SM
19#include <sys/time.h>
20#include <net/bpf.h>
21
033112db
SM
22#ifdef sun
23#include <netinet/in.h>
24#endif
25
54c31626
SM
26#if defined(sparc) || defined(mips)
27#define ALIGN
28#endif
29
30#ifndef ALIGN
31#define EXTRACT_SHORT(p) (ntohs(*(u_short *)p))
32#define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
33#else
34#define EXTRACT_SHORT(p)\
35 ((u_short)\
033112db
SM
36 (*((u_char *)(p)+0)<<8|\
37 *((u_char *)(p)+1)<<0))
54c31626 38#define EXTRACT_LONG(p)\
033112db
SM
39 (*((u_char *)(p)+0)<<24|\
40 *((u_char *)(p)+1)<<16|\
41 *((u_char *)(p)+2)<<8|\
42 *((u_char *)(p)+3)<<0)
54c31626
SM
43#endif
44
a277f25c
SM
45#ifdef KERNEL
46#include <sys/mbuf.h>
47#define MINDEX(m, k) \
48{ \
49 register int len = m->m_len; \
50 \
51 while (k >= len) { \
52 k -= len; \
53 m = m->m_next; \
54 if (m == 0) \
55 return 0; \
56 len = m->m_len; \
57 } \
58}
033112db
SM
59
60static int
61m_xword(m, k, err)
62 register struct mbuf *m;
63 register int k, *err;
64{
65 register int len;
66 register u_char *cp, *np;
67 register struct mbuf *m0;
68
69 len = m->m_len;
70 while (k >= len) {
71 k -= len;
72 m = m->m_next;
73 if (m == 0)
74 goto bad;
75 len = m->m_len;
76 }
77 cp = mtod(m, u_char *) + k;
78 if (len - k >= 4) {
79 *err = 0;
80 return EXTRACT_LONG(cp);
81 }
82 m0 = m->m_next;
83 if (m0 == 0 || m0->m_len + len - k < 4)
84 goto bad;
85 *err = 0;
86 np = mtod(m0, u_char *);
87 switch (len - k) {
88
89 case 1:
90 return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
91
92 case 2:
93 return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) |
94 np[1];
95
96 default:
97 return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
98 np[0];
99 }
100 bad:
101 *err = 1;
102 return 0;
103}
104
105static int
106m_xhalf(m, k, err)
107 register struct mbuf *m;
108 register int k, *err;
109{
110 register int len;
111 register u_char *cp, *np;
112 register struct mbuf *m0;
113
114 len = m->m_len;
115 while (k >= len) {
116 k -= len;
117 m = m->m_next;
118 if (m == 0)
119 goto bad;
120 len = m->m_len;
121 }
122 cp = mtod(m, u_char *) + k;
123 if (len - k >= 2) {
124 *err = 0;
125 return EXTRACT_SHORT(cp);
126 }
127 m0 = m->m_next;
128 if (m0 == 0)
129 goto bad;
130 *err = 0;
131 return (cp[k] << 8) | mtod(m0, u_char *)[0];
132 bad:
133 *err = 1;
134 return 0;
135}
136
137
a277f25c
SM
138#endif
139
54c31626 140/*
61f2dc53
SM
141 * Execute the filter program starting at pc on the packet p
142 * wirelen is the length of the original packet
143 * buflen is the amount of data present
54c31626
SM
144 */
145u_int
146bpf_filter(pc, p, wirelen, buflen)
147 register struct bpf_insn *pc;
148 register u_char *p;
149 u_int wirelen;
61f2dc53 150 register u_int buflen;
54c31626 151{
54c31626 152 register long A, X;
61f2dc53 153 register int k;
54c31626
SM
154 long mem[BPF_MEMWORDS];
155
156 if (pc == 0)
157 /*
158 * No filter means accept all.
159 */
61f2dc53 160 return (u_int)-1;
54c31626
SM
161#ifdef lint
162 A = 0;
163 X = 0;
164#endif
61f2dc53 165 --pc;
54c31626 166 while (1) {
61f2dc53 167 ++pc;
54c31626
SM
168 switch (pc->code) {
169
170 default:
171#ifdef KERNEL
172 return 0;
173#else
174 abort();
175#endif
61f2dc53 176 case BPF_RET|BPF_K:
54c31626
SM
177 return (u_int)pc->k;
178
61f2dc53 179 case BPF_RET|BPF_A:
54c31626
SM
180 return (u_int)A;
181
61f2dc53
SM
182 case BPF_LD|BPF_W|BPF_ABS:
183 k = pc->k;
a277f25c
SM
184 if (k + sizeof(long) > buflen) {
185#ifdef KERNEL
033112db 186 int merr;
a277f25c
SM
187
188 if (buflen != 0)
189 return 0;
033112db
SM
190 A = m_xword((struct mbuf *)p, k, &merr);
191 if (merr != 0)
192 return 0;
193 continue;
a277f25c 194#else
54c31626 195 return 0;
a277f25c
SM
196#endif
197 }
61f2dc53
SM
198#ifdef ALIGN
199 if (((int)(p + k) & 3) != 0)
200 A = EXTRACT_LONG(&p[k]);
201 else
202#endif
203 A = *(long *)(p + k);
033112db 204 continue;
54c31626 205
61f2dc53
SM
206 case BPF_LD|BPF_H|BPF_ABS:
207 k = pc->k;
a277f25c
SM
208 if (k + sizeof(short) > buflen) {
209#ifdef KERNEL
033112db 210 int merr;
a277f25c
SM
211
212 if (buflen != 0)
213 return 0;
033112db
SM
214 A = m_xhalf((struct mbuf *)p, k, &merr);
215 continue;
a277f25c 216#else
54c31626 217 return 0;
a277f25c
SM
218#endif
219 }
61f2dc53 220 A = EXTRACT_SHORT(&p[k]);
033112db 221 continue;
54c31626 222
61f2dc53
SM
223 case BPF_LD|BPF_B|BPF_ABS:
224 k = pc->k;
a277f25c
SM
225 if (k >= buflen) {
226#ifdef KERNEL
227 register struct mbuf *m;
228
229 if (buflen != 0)
230 return 0;
231 m = (struct mbuf *)p;
232 MINDEX(m, k);
033112db
SM
233 A = mtod(m, u_char *)[k];
234 continue;
a277f25c 235#else
54c31626 236 return 0;
a277f25c
SM
237#endif
238 }
61f2dc53 239 A = p[k];
033112db 240 continue;
54c31626 241
61f2dc53 242 case BPF_LD|BPF_W|BPF_LEN:
54c31626 243 A = wirelen;
033112db 244 continue;
54c31626 245
61f2dc53
SM
246 case BPF_LDX|BPF_W|BPF_LEN:
247 X = wirelen;
033112db 248 continue;
61f2dc53
SM
249
250 case BPF_LD|BPF_W|BPF_IND:
251 k = X + pc->k;
a277f25c
SM
252 if (k + sizeof(long) > buflen) {
253#ifdef KERNEL
033112db 254 int merr;
a277f25c
SM
255
256 if (buflen != 0)
257 return 0;
033112db
SM
258 A = m_xword((struct mbuf *)p, k, &merr);
259 if (merr != 0)
260 return 0;
261 continue;
a277f25c 262#else
54c31626 263 return 0;
a277f25c
SM
264#endif
265 }
61f2dc53
SM
266#ifdef ALIGN
267 if (((int)(p + k) & 3) != 0)
268 A = EXTRACT_LONG(&p[k]);
269 else
270#endif
271 A = *(long *)(p + k);
033112db 272 continue;
54c31626 273
61f2dc53
SM
274 case BPF_LD|BPF_H|BPF_IND:
275 k = X + pc->k;
a277f25c
SM
276 if (k + sizeof(short) > buflen) {
277#ifdef KERNEL
033112db 278 int merr;
a277f25c
SM
279
280 if (buflen != 0)
281 return 0;
033112db
SM
282 A = m_xhalf((struct mbuf *)p, k, &merr);
283 if (merr != 0)
284 return 0;
285 continue;
a277f25c 286#else
54c31626 287 return 0;
a277f25c
SM
288#endif
289 }
61f2dc53 290 A = EXTRACT_SHORT(&p[k]);
033112db 291 continue;
54c31626 292
61f2dc53
SM
293 case BPF_LD|BPF_B|BPF_IND:
294 k = X + pc->k;
a277f25c
SM
295 if (k >= buflen) {
296#ifdef KERNEL
297 register struct mbuf *m;
298
299 if (buflen != 0)
300 return 0;
301 m = (struct mbuf *)p;
302 MINDEX(m, k);
303 A = mtod(m, char *)[k];
033112db 304 continue;
a277f25c 305#else
54c31626 306 return 0;
a277f25c
SM
307#endif
308 }
61f2dc53 309 A = p[k];
033112db 310 continue;
54c31626 311
a277f25c
SM
312 case BPF_LDX|BPF_MSH|BPF_B:
313 k = pc->k;
314 if (k >= buflen) {
315#ifdef KERNEL
316 register struct mbuf *m;
317
318 if (buflen != 0)
319 return 0;
320 m = (struct mbuf *)p;
321 MINDEX(m, k);
322 X = (mtod(m, char *)[k] & 0xf) << 2;
033112db 323 continue;
a277f25c
SM
324#else
325 return 0;
326#endif
327 }
328 X = (p[pc->k] & 0xf) << 2;
033112db 329 continue;
a277f25c 330
61f2dc53 331 case BPF_LD|BPF_IMM:
54c31626 332 A = pc->k;
033112db 333 continue;
54c31626 334
61f2dc53 335 case BPF_LDX|BPF_IMM:
54c31626 336 X = pc->k;
033112db 337 continue;
54c31626 338
61f2dc53
SM
339 case BPF_LD|BPF_MEM:
340 A = mem[pc->k];
033112db 341 continue;
61f2dc53
SM
342
343 case BPF_LDX|BPF_MEM:
344 X = mem[pc->k];
033112db 345 continue;
54c31626 346
61f2dc53 347 case BPF_ST:
54c31626 348 mem[pc->k] = A;
033112db 349 continue;
54c31626 350
61f2dc53 351 case BPF_STX:
54c31626 352 mem[pc->k] = X;
033112db 353 continue;
54c31626 354
61f2dc53
SM
355 case BPF_JMP|BPF_JA:
356 pc += pc->k;
033112db 357 continue;
61f2dc53
SM
358
359 case BPF_JMP|BPF_JGT|BPF_K:
360 pc += (A > pc->k) ? pc->jt : pc->jf;
033112db 361 continue;
61f2dc53
SM
362
363 case BPF_JMP|BPF_JGE|BPF_K:
364 pc += (A >= pc->k) ? pc->jt : pc->jf;
033112db 365 continue;
54c31626 366
61f2dc53
SM
367 case BPF_JMP|BPF_JEQ|BPF_K:
368 pc += (A == pc->k) ? pc->jt : pc->jf;
033112db 369 continue;
54c31626 370
61f2dc53
SM
371 case BPF_JMP|BPF_JSET|BPF_K:
372 pc += (A & pc->k) ? pc->jt : pc->jf;
033112db 373 continue;
61f2dc53
SM
374
375 case BPF_JMP|BPF_JGT|BPF_X:
376 pc += (A > X) ? pc->jt : pc->jf;
033112db 377 continue;
54c31626 378
61f2dc53
SM
379 case BPF_JMP|BPF_JGE|BPF_X:
380 pc += (A >= X) ? pc->jt : pc->jf;
033112db 381 continue;
61f2dc53
SM
382
383 case BPF_JMP|BPF_JEQ|BPF_X:
384 pc += (A == X) ? pc->jt : pc->jf;
033112db 385 continue;
54c31626 386
61f2dc53
SM
387 case BPF_JMP|BPF_JSET|BPF_X:
388 pc += (A & X) ? pc->jt : pc->jf;
033112db 389 continue;
54c31626 390
61f2dc53 391 case BPF_ALU|BPF_ADD|BPF_X:
54c31626 392 A += X;
033112db 393 continue;
54c31626 394
61f2dc53 395 case BPF_ALU|BPF_SUB|BPF_X:
54c31626 396 A -= X;
033112db 397 continue;
54c31626 398
61f2dc53 399 case BPF_ALU|BPF_MUL|BPF_X:
54c31626 400 A *= X;
033112db 401 continue;
54c31626 402
61f2dc53 403 case BPF_ALU|BPF_DIV|BPF_X:
54c31626
SM
404 if (X == 0)
405 return 0;
406 A /= X;
033112db 407 continue;
54c31626 408
61f2dc53 409 case BPF_ALU|BPF_AND|BPF_X:
54c31626 410 A &= X;
033112db 411 continue;
54c31626 412
61f2dc53 413 case BPF_ALU|BPF_OR|BPF_X:
54c31626 414 A |= X;
033112db 415 continue;
54c31626 416
61f2dc53 417 case BPF_ALU|BPF_LSH|BPF_X:
54c31626 418 A <<= X;
033112db 419 continue;
54c31626 420
61f2dc53 421 case BPF_ALU|BPF_RSH|BPF_X:
54c31626 422 A >>= X;
033112db 423 continue;
54c31626 424
61f2dc53 425 case BPF_ALU|BPF_ADD|BPF_K:
54c31626 426 A += pc->k;
033112db 427 continue;
54c31626 428
61f2dc53 429 case BPF_ALU|BPF_SUB|BPF_K:
54c31626 430 A -= pc->k;
033112db 431 continue;
54c31626 432
61f2dc53 433 case BPF_ALU|BPF_MUL|BPF_K:
54c31626 434 A *= pc->k;
033112db 435 continue;
54c31626 436
61f2dc53 437 case BPF_ALU|BPF_DIV|BPF_K:
54c31626 438 A /= pc->k;
033112db 439 continue;
54c31626 440
61f2dc53 441 case BPF_ALU|BPF_AND|BPF_K:
54c31626 442 A &= pc->k;
033112db 443 continue;
54c31626 444
61f2dc53 445 case BPF_ALU|BPF_OR|BPF_K:
54c31626 446 A |= pc->k;
033112db 447 continue;
54c31626 448
61f2dc53 449 case BPF_ALU|BPF_LSH|BPF_K:
54c31626 450 A <<= pc->k;
033112db 451 continue;
54c31626 452
61f2dc53 453 case BPF_ALU|BPF_RSH|BPF_K:
54c31626 454 A >>= pc->k;
033112db 455 continue;
54c31626 456
61f2dc53 457 case BPF_ALU|BPF_NEG:
54c31626 458 A = -A;
033112db 459 continue;
61f2dc53
SM
460
461 case BPF_MISC|BPF_TAX:
462 X = A;
033112db 463 continue;
61f2dc53
SM
464
465 case BPF_MISC|BPF_TXA:
466 A = X;
033112db 467 continue;
54c31626 468 }
54c31626
SM
469 }
470}
471
472#ifdef KERNEL
473/*
474 * Return true if the 'fcode' is a valid filter program.
475 * The constraints are that each jump be forward and to a valid
476 * code. The code must terminate with either an accept or reject.
477 * 'valid' is an array for use by the routine (it must be at least
478 * 'len' bytes long).
479 *
480 * The kernel needs to be able to verify an application's filter code.
481 * Otherwise, a bogus program could easily crash the system.
482 */
483int
61f2dc53
SM
484bpf_validate(f, len)
485 struct bpf_insn *f;
54c31626
SM
486 int len;
487{
61f2dc53
SM
488 register int i;
489 register struct bpf_insn *p;
54c31626 490
61f2dc53 491 for (i = 0; i < len; ++i) {
54c31626
SM
492 /*
493 * Check that that jumps are forward, and within
494 * the code block.
495 */
61f2dc53
SM
496 p = &f[i];
497 if (BPF_CLASS(p->code) == BPF_JMP) {
498 register int from = i + 1;
499
500 if (BPF_OP(p->code) == BPF_JA) {
501 if (from + p->k >= len)
502 return 0;
503 }
504 else if (from + p->jt >= len || from + p->jf >= len)
505 return 0;
506 }
54c31626
SM
507 /*
508 * Check that memory operations use valid addresses.
509 */
61f2dc53
SM
510 if ((BPF_CLASS(p->code) == BPF_ST ||
511 (BPF_CLASS(p->code) == BPF_LD &&
512 (p->code & 0xe0) == BPF_MEM)) &&
513 (p->k >= BPF_MEMWORDS || p->k < 0))
514 return 0;
515 /*
516 * Check for constant division by 0.
517 */
518 if (p->code == BPF_ALU|BPF_DIV|BPF_K && p->k == 0)
519 return;
54c31626 520 }
61f2dc53 521 return BPF_CLASS(f[len - 1].code) == BPF_RET;
54c31626
SM
522}
523#endif