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