bpf_filter.c revision 145554
1145519Sdarrenr/*	$FreeBSD: head/contrib/ipfilter/bpf_filter.c 145554 2005-04-26 15:18:45Z darrenr $	*/
2145510Sdarrenr
3145510Sdarrenr/*-
4145510Sdarrenr * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
5145510Sdarrenr *	The Regents of the University of California.  All rights reserved.
6145510Sdarrenr *
7145510Sdarrenr * This code is derived from the Stanford/CMU enet packet filter,
8145510Sdarrenr * (net/enet.c) distributed as part of 4.3BSD, and code contributed
9145510Sdarrenr * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
10145510Sdarrenr * Berkeley Laboratory.
11145510Sdarrenr *
12145510Sdarrenr * Redistribution and use in source and binary forms, with or without
13145510Sdarrenr * modification, are permitted provided that the following conditions
14145510Sdarrenr * are met:
15145510Sdarrenr * 1. Redistributions of source code must retain the above copyright
16145510Sdarrenr *    notice, this list of conditions and the following disclaimer.
17145510Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright
18145510Sdarrenr *    notice, this list of conditions and the following disclaimer in the
19145510Sdarrenr *    documentation and/or other materials provided with the distribution.
20145510Sdarrenr * 3. All advertising materials mentioning features or use of this software
21145510Sdarrenr *    must display the following acknowledgement:
22145510Sdarrenr *	This product includes software developed by the University of
23145510Sdarrenr *	California, Berkeley and its contributors.
24145510Sdarrenr * 4. Neither the name of the University nor the names of its contributors
25145510Sdarrenr *    may be used to endorse or promote products derived from this software
26145510Sdarrenr *    without specific prior written permission.
27145510Sdarrenr *
28145510Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29145510Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30145510Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31145510Sdarrenr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32145510Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33145510Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34145510Sdarrenr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35145510Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36145510Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37145510Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38145510Sdarrenr * SUCH DAMAGE.
39145510Sdarrenr *
40145510Sdarrenr *	@(#)bpf.c	7.5 (Berkeley) 7/15/91
41145510Sdarrenr */
42145510Sdarrenr
43145510Sdarrenr#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL))
44145510Sdarrenrstatic const char rcsid[] =
45145510Sdarrenr    "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2 2003/08/19 16:49:58 darrenr Exp $ (LBL)";
46145510Sdarrenr#endif
47145510Sdarrenr
48145510Sdarrenr#include <sys/param.h>
49145510Sdarrenr#include <sys/types.h>
50145510Sdarrenr#include <sys/time.h>
51145510Sdarrenr#include <sys/socket.h>
52145510Sdarrenr
53145510Sdarrenr#include <netinet/in.h>
54145510Sdarrenr#include <net/if.h>
55145510Sdarrenr
56145554Sdarrenr#include "netinet/ip_compat.h"
57145510Sdarrenr#include "bpf-ipf.h"
58145510Sdarrenr
59145510Sdarrenr
60145510Sdarrenr#if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL))
61145510Sdarrenr# include <sys/sysmacros.h>
62145510Sdarrenr# include <sys/stream.h>
63145510Sdarrenr#endif
64145510Sdarrenr
65145510Sdarrenr#include "pcap-ipf.h"
66145510Sdarrenr
67145510Sdarrenr#if !defined(KERNEL) && !defined(_KERNEL)
68145510Sdarrenr#include <stdlib.h>
69145510Sdarrenr#endif
70145510Sdarrenr
71145510Sdarrenr#define int32 bpf_int32
72145510Sdarrenr#define u_int32 bpf_u_int32
73145510Sdarrenr
74145510Sdarrenrstatic int m_xword __P((mb_t *, int, int *));
75145510Sdarrenrstatic int m_xhalf __P((mb_t *, int, int *));
76145510Sdarrenr
77145510Sdarrenr#ifndef LBL_ALIGN
78145510Sdarrenr/*
79145510Sdarrenr * XXX - IA-64?  If not, this probably won't work on Win64 IA-64
80145510Sdarrenr * systems, unless LBL_ALIGN is defined elsewhere for them.
81145510Sdarrenr * XXX - SuperH?  If not, this probably won't work on WinCE SuperH
82145510Sdarrenr * systems, unless LBL_ALIGN is defined elsewhere for them.
83145510Sdarrenr */
84145510Sdarrenr#if defined(sparc) || defined(__sparc__) || defined(mips) || \
85145510Sdarrenr    defined(ibm032) || defined(__alpha) || defined(__hpux) || \
86145510Sdarrenr    defined(__arm__)
87145510Sdarrenr#define LBL_ALIGN
88145510Sdarrenr#endif
89145510Sdarrenr#endif
90145510Sdarrenr
91145510Sdarrenr#ifndef LBL_ALIGN
92145510Sdarrenr
93145510Sdarrenr#define EXTRACT_SHORT(p)	((u_short)ntohs(*(u_short *)p))
94145510Sdarrenr#define EXTRACT_LONG(p)		(ntohl(*(u_int32 *)p))
95145510Sdarrenr#else
96145510Sdarrenr#define EXTRACT_SHORT(p)\
97145510Sdarrenr	((u_short)\
98145510Sdarrenr		((u_short)*((u_char *)p+0)<<8|\
99145510Sdarrenr		 (u_short)*((u_char *)p+1)<<0))
100145510Sdarrenr#define EXTRACT_LONG(p)\
101145510Sdarrenr		((u_int32)*((u_char *)p+0)<<24|\
102145510Sdarrenr		 (u_int32)*((u_char *)p+1)<<16|\
103145510Sdarrenr		 (u_int32)*((u_char *)p+2)<<8|\
104145510Sdarrenr		 (u_int32)*((u_char *)p+3)<<0)
105145510Sdarrenr#endif
106145510Sdarrenr
107145510Sdarrenr#define MINDEX(len, _m, _k) \
108145510Sdarrenr{ \
109145510Sdarrenr	len = M_LEN(m); \
110145510Sdarrenr	while ((_k) >= len) { \
111145510Sdarrenr		(_k) -= len; \
112145510Sdarrenr		(_m) = (_m)->m_next; \
113145510Sdarrenr		if ((_m) == 0) \
114145510Sdarrenr			return 0; \
115145510Sdarrenr		len = M_LEN(m); \
116145510Sdarrenr	} \
117145510Sdarrenr}
118145510Sdarrenr
119145510Sdarrenrstatic int
120145510Sdarrenrm_xword(m, k, err)
121145510Sdarrenr	register mb_t *m;
122145510Sdarrenr	register int k, *err;
123145510Sdarrenr{
124145510Sdarrenr	register int len;
125145510Sdarrenr	register u_char *cp, *np;
126145510Sdarrenr	register mb_t *m0;
127145510Sdarrenr
128145510Sdarrenr	MINDEX(len, m, k);
129145510Sdarrenr	cp = MTOD(m, u_char *) + k;
130145510Sdarrenr	if (len - k >= 4) {
131145510Sdarrenr		*err = 0;
132145510Sdarrenr		return EXTRACT_LONG(cp);
133145510Sdarrenr	}
134145510Sdarrenr	m0 = m->m_next;
135145510Sdarrenr	if (m0 == 0 || M_LEN(m0) + len - k < 4)
136145510Sdarrenr		goto bad;
137145510Sdarrenr	*err = 0;
138145510Sdarrenr	np = MTOD(m0, u_char *);
139145510Sdarrenr	switch (len - k) {
140145510Sdarrenr
141145510Sdarrenr	case 1:
142145510Sdarrenr		return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
143145510Sdarrenr
144145510Sdarrenr	case 2:
145145510Sdarrenr		return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1];
146145510Sdarrenr
147145510Sdarrenr	default:
148145510Sdarrenr		return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0];
149145510Sdarrenr	}
150145510Sdarrenr    bad:
151145510Sdarrenr	*err = 1;
152145510Sdarrenr	return 0;
153145510Sdarrenr}
154145510Sdarrenr
155145510Sdarrenrstatic int
156145510Sdarrenrm_xhalf(m, k, err)
157145510Sdarrenr	register mb_t *m;
158145510Sdarrenr	register int k, *err;
159145510Sdarrenr{
160145510Sdarrenr	register int len;
161145510Sdarrenr	register u_char *cp;
162145510Sdarrenr	register mb_t *m0;
163145510Sdarrenr
164145510Sdarrenr	MINDEX(len, m, k);
165145510Sdarrenr	cp = MTOD(m, u_char *) + k;
166145510Sdarrenr	if (len - k >= 2) {
167145510Sdarrenr		*err = 0;
168145510Sdarrenr		return EXTRACT_SHORT(cp);
169145510Sdarrenr	}
170145510Sdarrenr	m0 = m->m_next;
171145510Sdarrenr	if (m0 == 0)
172145510Sdarrenr		goto bad;
173145510Sdarrenr	*err = 0;
174145510Sdarrenr	return (cp[0] << 8) | MTOD(m0, u_char *)[0];
175145510Sdarrenr bad:
176145510Sdarrenr	*err = 1;
177145510Sdarrenr	return 0;
178145510Sdarrenr}
179145510Sdarrenr
180145510Sdarrenr/*
181145510Sdarrenr * Execute the filter program starting at pc on the packet p
182145510Sdarrenr * wirelen is the length of the original packet
183145510Sdarrenr * buflen is the amount of data present
184145510Sdarrenr * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0,
185145510Sdarrenr * in all other cases, p is a pointer to a buffer and buflen is its size.
186145510Sdarrenr */
187145510Sdarrenru_int
188145510Sdarrenrbpf_filter(pc, p, wirelen, buflen)
189145510Sdarrenr	register struct bpf_insn *pc;
190145510Sdarrenr	register u_char *p;
191145510Sdarrenr	u_int wirelen;
192145510Sdarrenr	register u_int buflen;
193145510Sdarrenr{
194145510Sdarrenr	register u_int32 A, X;
195145510Sdarrenr	register int k;
196145510Sdarrenr	int32 mem[BPF_MEMWORDS];
197145510Sdarrenr	mb_t *m, *n;
198145510Sdarrenr	int merr, len;
199145510Sdarrenr
200145510Sdarrenr	if (buflen == 0) {
201145510Sdarrenr		m = (mb_t *)p;
202145510Sdarrenr		p = MTOD(m, u_char *);
203145510Sdarrenr		buflen = M_LEN(m);
204145510Sdarrenr	} else
205145510Sdarrenr		m = NULL;
206145510Sdarrenr
207145510Sdarrenr	if (pc == 0)
208145510Sdarrenr		/*
209145510Sdarrenr		 * No filter means accept all.
210145510Sdarrenr		 */
211145510Sdarrenr		return (u_int)-1;
212145510Sdarrenr	A = 0;
213145510Sdarrenr	X = 0;
214145510Sdarrenr	--pc;
215145510Sdarrenr	while (1) {
216145510Sdarrenr		++pc;
217145510Sdarrenr		switch (pc->code) {
218145510Sdarrenr
219145510Sdarrenr		default:
220145510Sdarrenr			return 0;
221145510Sdarrenr		case BPF_RET|BPF_K:
222145510Sdarrenr			return (u_int)pc->k;
223145510Sdarrenr
224145510Sdarrenr		case BPF_RET|BPF_A:
225145510Sdarrenr			return (u_int)A;
226145510Sdarrenr
227145510Sdarrenr		case BPF_LD|BPF_W|BPF_ABS:
228145510Sdarrenr			k = pc->k;
229145510Sdarrenr			if (k + sizeof(int32) > buflen) {
230145510Sdarrenr				if (m == NULL)
231145510Sdarrenr					return 0;
232145510Sdarrenr				A = m_xword(m, k, &merr);
233145510Sdarrenr				if (merr != 0)
234145510Sdarrenr					return 0;
235145510Sdarrenr				continue;
236145510Sdarrenr			}
237145510Sdarrenr			A = EXTRACT_LONG(&p[k]);
238145510Sdarrenr			continue;
239145510Sdarrenr
240145510Sdarrenr		case BPF_LD|BPF_H|BPF_ABS:
241145510Sdarrenr			k = pc->k;
242145510Sdarrenr			if (k + sizeof(short) > buflen) {
243145510Sdarrenr				if (m == NULL)
244145510Sdarrenr					return 0;
245145510Sdarrenr				A = m_xhalf(m, k, &merr);
246145510Sdarrenr				if (merr != 0)
247145510Sdarrenr					return 0;
248145510Sdarrenr				continue;
249145510Sdarrenr			}
250145510Sdarrenr			A = EXTRACT_SHORT(&p[k]);
251145510Sdarrenr			continue;
252145510Sdarrenr
253145510Sdarrenr		case BPF_LD|BPF_B|BPF_ABS:
254145510Sdarrenr			k = pc->k;
255145510Sdarrenr			if (k >= buflen) {
256145510Sdarrenr				if (m == NULL)
257145510Sdarrenr					return 0;
258145510Sdarrenr				n = m;
259145510Sdarrenr				MINDEX(len, n, k);
260145510Sdarrenr				A = MTOD(n, u_char *)[k];
261145510Sdarrenr				continue;
262145510Sdarrenr			}
263145510Sdarrenr			A = p[k];
264145510Sdarrenr			continue;
265145510Sdarrenr
266145510Sdarrenr		case BPF_LD|BPF_W|BPF_LEN:
267145510Sdarrenr			A = wirelen;
268145510Sdarrenr			continue;
269145510Sdarrenr
270145510Sdarrenr		case BPF_LDX|BPF_W|BPF_LEN:
271145510Sdarrenr			X = wirelen;
272145510Sdarrenr			continue;
273145510Sdarrenr
274145510Sdarrenr		case BPF_LD|BPF_W|BPF_IND:
275145510Sdarrenr			k = X + pc->k;
276145510Sdarrenr			if (k + sizeof(int32) > buflen) {
277145510Sdarrenr				if (m == NULL)
278145510Sdarrenr					return 0;
279145510Sdarrenr				A = m_xword(m, k, &merr);
280145510Sdarrenr				if (merr != 0)
281145510Sdarrenr					return 0;
282145510Sdarrenr				continue;
283145510Sdarrenr			}
284145510Sdarrenr			A = EXTRACT_LONG(&p[k]);
285145510Sdarrenr			continue;
286145510Sdarrenr
287145510Sdarrenr		case BPF_LD|BPF_H|BPF_IND:
288145510Sdarrenr			k = X + pc->k;
289145510Sdarrenr			if (k + sizeof(short) > buflen) {
290145510Sdarrenr				if (m == NULL)
291145510Sdarrenr					return 0;
292145510Sdarrenr				A = m_xhalf(m, k, &merr);
293145510Sdarrenr				if (merr != 0)
294145510Sdarrenr					return 0;
295145510Sdarrenr				continue;
296145510Sdarrenr			}
297145510Sdarrenr			A = EXTRACT_SHORT(&p[k]);
298145510Sdarrenr			continue;
299145510Sdarrenr
300145510Sdarrenr		case BPF_LD|BPF_B|BPF_IND:
301145510Sdarrenr			k = X + pc->k;
302145510Sdarrenr			if (k >= buflen) {
303145510Sdarrenr				if (m == NULL)
304145510Sdarrenr					return 0;
305145510Sdarrenr				n = m;
306145510Sdarrenr				MINDEX(len, n, k);
307145510Sdarrenr				A = MTOD(n, u_char *)[k];
308145510Sdarrenr				continue;
309145510Sdarrenr			}
310145510Sdarrenr			A = p[k];
311145510Sdarrenr			continue;
312145510Sdarrenr
313145510Sdarrenr		case BPF_LDX|BPF_MSH|BPF_B:
314145510Sdarrenr			k = pc->k;
315145510Sdarrenr			if (k >= buflen) {
316145510Sdarrenr				if (m == NULL)
317145510Sdarrenr					return 0;
318145510Sdarrenr				n = m;
319145510Sdarrenr				MINDEX(len, n, k);
320145510Sdarrenr				X = (MTOD(n, char *)[k] & 0xf) << 2;
321145510Sdarrenr				continue;
322145510Sdarrenr			}
323145510Sdarrenr			X = (p[pc->k] & 0xf) << 2;
324145510Sdarrenr			continue;
325145510Sdarrenr
326145510Sdarrenr		case BPF_LD|BPF_IMM:
327145510Sdarrenr			A = pc->k;
328145510Sdarrenr			continue;
329145510Sdarrenr
330145510Sdarrenr		case BPF_LDX|BPF_IMM:
331145510Sdarrenr			X = pc->k;
332145510Sdarrenr			continue;
333145510Sdarrenr
334145510Sdarrenr		case BPF_LD|BPF_MEM:
335145510Sdarrenr			A = mem[pc->k];
336145510Sdarrenr			continue;
337145510Sdarrenr
338145510Sdarrenr		case BPF_LDX|BPF_MEM:
339145510Sdarrenr			X = mem[pc->k];
340145510Sdarrenr			continue;
341145510Sdarrenr
342145510Sdarrenr		case BPF_ST:
343145510Sdarrenr			mem[pc->k] = A;
344145510Sdarrenr			continue;
345145510Sdarrenr
346145510Sdarrenr		case BPF_STX:
347145510Sdarrenr			mem[pc->k] = X;
348145510Sdarrenr			continue;
349145510Sdarrenr
350145510Sdarrenr		case BPF_JMP|BPF_JA:
351145510Sdarrenr			pc += pc->k;
352145510Sdarrenr			continue;
353145510Sdarrenr
354145510Sdarrenr		case BPF_JMP|BPF_JGT|BPF_K:
355145510Sdarrenr			pc += (A > pc->k) ? pc->jt : pc->jf;
356145510Sdarrenr			continue;
357145510Sdarrenr
358145510Sdarrenr		case BPF_JMP|BPF_JGE|BPF_K:
359145510Sdarrenr			pc += (A >= pc->k) ? pc->jt : pc->jf;
360145510Sdarrenr			continue;
361145510Sdarrenr
362145510Sdarrenr		case BPF_JMP|BPF_JEQ|BPF_K:
363145510Sdarrenr			pc += (A == pc->k) ? pc->jt : pc->jf;
364145510Sdarrenr			continue;
365145510Sdarrenr
366145510Sdarrenr		case BPF_JMP|BPF_JSET|BPF_K:
367145510Sdarrenr			pc += (A & pc->k) ? pc->jt : pc->jf;
368145510Sdarrenr			continue;
369145510Sdarrenr
370145510Sdarrenr		case BPF_JMP|BPF_JGT|BPF_X:
371145510Sdarrenr			pc += (A > X) ? pc->jt : pc->jf;
372145510Sdarrenr			continue;
373145510Sdarrenr
374145510Sdarrenr		case BPF_JMP|BPF_JGE|BPF_X:
375145510Sdarrenr			pc += (A >= X) ? pc->jt : pc->jf;
376145510Sdarrenr			continue;
377145510Sdarrenr
378145510Sdarrenr		case BPF_JMP|BPF_JEQ|BPF_X:
379145510Sdarrenr			pc += (A == X) ? pc->jt : pc->jf;
380145510Sdarrenr			continue;
381145510Sdarrenr
382145510Sdarrenr		case BPF_JMP|BPF_JSET|BPF_X:
383145510Sdarrenr			pc += (A & X) ? pc->jt : pc->jf;
384145510Sdarrenr			continue;
385145510Sdarrenr
386145510Sdarrenr		case BPF_ALU|BPF_ADD|BPF_X:
387145510Sdarrenr			A += X;
388145510Sdarrenr			continue;
389145510Sdarrenr
390145510Sdarrenr		case BPF_ALU|BPF_SUB|BPF_X:
391145510Sdarrenr			A -= X;
392145510Sdarrenr			continue;
393145510Sdarrenr
394145510Sdarrenr		case BPF_ALU|BPF_MUL|BPF_X:
395145510Sdarrenr			A *= X;
396145510Sdarrenr			continue;
397145510Sdarrenr
398145510Sdarrenr		case BPF_ALU|BPF_DIV|BPF_X:
399145510Sdarrenr			if (X == 0)
400145510Sdarrenr				return 0;
401145510Sdarrenr			A /= X;
402145510Sdarrenr			continue;
403145510Sdarrenr
404145510Sdarrenr		case BPF_ALU|BPF_AND|BPF_X:
405145510Sdarrenr			A &= X;
406145510Sdarrenr			continue;
407145510Sdarrenr
408145510Sdarrenr		case BPF_ALU|BPF_OR|BPF_X:
409145510Sdarrenr			A |= X;
410145510Sdarrenr			continue;
411145510Sdarrenr
412145510Sdarrenr		case BPF_ALU|BPF_LSH|BPF_X:
413145510Sdarrenr			A <<= X;
414145510Sdarrenr			continue;
415145510Sdarrenr
416145510Sdarrenr		case BPF_ALU|BPF_RSH|BPF_X:
417145510Sdarrenr			A >>= X;
418145510Sdarrenr			continue;
419145510Sdarrenr
420145510Sdarrenr		case BPF_ALU|BPF_ADD|BPF_K:
421145510Sdarrenr			A += pc->k;
422145510Sdarrenr			continue;
423145510Sdarrenr
424145510Sdarrenr		case BPF_ALU|BPF_SUB|BPF_K:
425145510Sdarrenr			A -= pc->k;
426145510Sdarrenr			continue;
427145510Sdarrenr
428145510Sdarrenr		case BPF_ALU|BPF_MUL|BPF_K:
429145510Sdarrenr			A *= pc->k;
430145510Sdarrenr			continue;
431145510Sdarrenr
432145510Sdarrenr		case BPF_ALU|BPF_DIV|BPF_K:
433145510Sdarrenr			A /= pc->k;
434145510Sdarrenr			continue;
435145510Sdarrenr
436145510Sdarrenr		case BPF_ALU|BPF_AND|BPF_K:
437145510Sdarrenr			A &= pc->k;
438145510Sdarrenr			continue;
439145510Sdarrenr
440145510Sdarrenr		case BPF_ALU|BPF_OR|BPF_K:
441145510Sdarrenr			A |= pc->k;
442145510Sdarrenr			continue;
443145510Sdarrenr
444145510Sdarrenr		case BPF_ALU|BPF_LSH|BPF_K:
445145510Sdarrenr			A <<= pc->k;
446145510Sdarrenr			continue;
447145510Sdarrenr
448145510Sdarrenr		case BPF_ALU|BPF_RSH|BPF_K:
449145510Sdarrenr			A >>= pc->k;
450145510Sdarrenr			continue;
451145510Sdarrenr
452145510Sdarrenr		case BPF_ALU|BPF_NEG:
453145510Sdarrenr			A = -A;
454145510Sdarrenr			continue;
455145510Sdarrenr
456145510Sdarrenr		case BPF_MISC|BPF_TAX:
457145510Sdarrenr			X = A;
458145510Sdarrenr			continue;
459145510Sdarrenr
460145510Sdarrenr		case BPF_MISC|BPF_TXA:
461145510Sdarrenr			A = X;
462145510Sdarrenr			continue;
463145510Sdarrenr		}
464145510Sdarrenr	}
465145510Sdarrenr}
466145510Sdarrenr
467145510Sdarrenr
468145510Sdarrenr/*
469145510Sdarrenr * Return true if the 'fcode' is a valid filter program.
470145510Sdarrenr * The constraints are that each jump be forward and to a valid
471145510Sdarrenr * code.  The code must terminate with either an accept or reject.
472145510Sdarrenr * 'valid' is an array for use by the routine (it must be at least
473145510Sdarrenr * 'len' bytes long).
474145510Sdarrenr *
475145510Sdarrenr * The kernel needs to be able to verify an application's filter code.
476145510Sdarrenr * Otherwise, a bogus program could easily crash the system.
477145510Sdarrenr */
478145510Sdarrenrint
479145510Sdarrenrbpf_validate(f, len)
480145510Sdarrenr	struct bpf_insn *f;
481145510Sdarrenr	int len;
482145510Sdarrenr{
483145510Sdarrenr	register int i;
484145510Sdarrenr	register struct bpf_insn *p;
485145510Sdarrenr
486145510Sdarrenr	for (i = 0; i < len; ++i) {
487145510Sdarrenr		/*
488145510Sdarrenr		 * Check that that jumps are forward, and within
489145510Sdarrenr		 * the code block.
490145510Sdarrenr		 */
491145510Sdarrenr		p = &f[i];
492145510Sdarrenr		if (BPF_CLASS(p->code) == BPF_JMP) {
493145510Sdarrenr			register int from = i + 1;
494145510Sdarrenr
495145510Sdarrenr			if (BPF_OP(p->code) == BPF_JA) {
496145510Sdarrenr				if (from + p->k >= (unsigned)len)
497145510Sdarrenr					return 0;
498145510Sdarrenr			}
499145510Sdarrenr			else if (from + p->jt >= len || from + p->jf >= len)
500145510Sdarrenr				return 0;
501145510Sdarrenr		}
502145510Sdarrenr		/*
503145510Sdarrenr		 * Check that memory operations use valid addresses.
504145510Sdarrenr		 */
505145510Sdarrenr		if ((BPF_CLASS(p->code) == BPF_ST ||
506145510Sdarrenr		     (BPF_CLASS(p->code) == BPF_LD &&
507145510Sdarrenr		      (p->code & 0xe0) == BPF_MEM)) &&
508145510Sdarrenr		    (p->k >= BPF_MEMWORDS || p->k < 0))
509145510Sdarrenr			return 0;
510145510Sdarrenr		/*
511145510Sdarrenr		 * Check for constant division by 0.
512145510Sdarrenr		 */
513145510Sdarrenr		if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
514145510Sdarrenr			return 0;
515145510Sdarrenr	}
516145510Sdarrenr	return BPF_CLASS(f[len - 1].code) == BPF_RET;
517145510Sdarrenr}
518