xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <ctype.h>
31*0Sstevel@tonic-gate #include <string.h>
32*0Sstevel@tonic-gate #include <fcntl.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <sys/types.h>
35*0Sstevel@tonic-gate #include <sys/time.h>
36*0Sstevel@tonic-gate #include <sys/isa_defs.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <sys/socket.h>
39*0Sstevel@tonic-gate #include <sys/sockio.h>
40*0Sstevel@tonic-gate #include <sys/dlpi.h>
41*0Sstevel@tonic-gate #include <net/if.h>
42*0Sstevel@tonic-gate #include <netinet/in_systm.h>
43*0Sstevel@tonic-gate #include <netinet/in.h>
44*0Sstevel@tonic-gate #include <netinet/ip.h>
45*0Sstevel@tonic-gate #include <netinet/if_ether.h>
46*0Sstevel@tonic-gate #include <netinet/tcp.h>
47*0Sstevel@tonic-gate #include <netinet/udp.h>
48*0Sstevel@tonic-gate #include <netdb.h>
49*0Sstevel@tonic-gate #include <rpc/rpc.h>
50*0Sstevel@tonic-gate #include <setjmp.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #include <sys/pfmod.h>
53*0Sstevel@tonic-gate #include "snoop.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * This module generates code for the kernel packet filter.
57*0Sstevel@tonic-gate  * The kernel packet filter is more efficient since it
58*0Sstevel@tonic-gate  * operates without context switching or moving data into
59*0Sstevel@tonic-gate  * the capture buffer.  On the other hand, it is limited
60*0Sstevel@tonic-gate  * in its filtering ability i.e. can't cope with variable
61*0Sstevel@tonic-gate  * length headers, can't compare the packet size, 1 and 4 octet
62*0Sstevel@tonic-gate  * comparisons are awkward, code space is limited to ENMAXFILTERS
63*0Sstevel@tonic-gate  * halfwords, etc.
64*0Sstevel@tonic-gate  * The parser is the same for the user-level packet filter though
65*0Sstevel@tonic-gate  * more limited in the variety of expressions it can generate
66*0Sstevel@tonic-gate  * code for.  If the pf compiler finds an expression it can't
67*0Sstevel@tonic-gate  * handle, it tries to set up a split filter in kernel and do the
68*0Sstevel@tonic-gate  * remaining filtering in userland. If that also fails, it resorts
69*0Sstevel@tonic-gate  * to userland filter. (See additional comment in pf_compile)
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate extern struct Pf_ext_packetfilt pf;
73*0Sstevel@tonic-gate static ushort_t *pfp;
74*0Sstevel@tonic-gate jmp_buf env;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate int eaddr;	/* need ethernet addr */
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate int opstack;	/* operand stack depth */
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate #define	EQ(val)		(strcmp(token, val) == 0)
81*0Sstevel@tonic-gate #define	IPV4_ONLY	0
82*0Sstevel@tonic-gate #define	IPV6_ONLY	1
83*0Sstevel@tonic-gate #define	IPV4_AND_IPV6	2
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * The following constants represent the offsets in bytes from the beginning
87*0Sstevel@tonic-gate  * of the packet of the link and IP(v6) layer source/destination/type fields,
88*0Sstevel@tonic-gate  * initialized for Ethernet. Media specific code can set any unavailable
89*0Sstevel@tonic-gate  * link layer property's offset to -1 to indicate that the property's value
90*0Sstevel@tonic-gate  * is not available from the frame.
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static int link_header_len = 14, link_type_offset = 12;
93*0Sstevel@tonic-gate static int link_dest_offset = 0, link_src_offset = 6;
94*0Sstevel@tonic-gate static int link_addr_len = 6;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate #define	IPV4_SRCADDR_OFFSET	(link_header_len + 12)
97*0Sstevel@tonic-gate #define	IPV4_DSTADDR_OFFSET	(link_header_len + 16)
98*0Sstevel@tonic-gate #define	IPV6_SRCADDR_OFFSET	(link_header_len + 8)
99*0Sstevel@tonic-gate #define	IPV6_DSTADDR_OFFSET	(link_header_len + 24)
100*0Sstevel@tonic-gate #define	IPV4_TYPE_OFFSET	(link_header_len + 9)
101*0Sstevel@tonic-gate #define	IPV6_TYPE_OFFSET	(link_header_len + 6)
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate static int inBrace = 0, inBraceOR = 0;
104*0Sstevel@tonic-gate static int foundOR = 0;
105*0Sstevel@tonic-gate char *tkp, *sav_tkp;
106*0Sstevel@tonic-gate char *token;
107*0Sstevel@tonic-gate enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
108*0Sstevel@tonic-gate 	ADDR_IP6 } tokentype;
109*0Sstevel@tonic-gate uint_t tokenval;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate enum direction { ANY, TO, FROM };
112*0Sstevel@tonic-gate enum direction dir;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate extern void next();
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate static void pf_expression();
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate static void
119*0Sstevel@tonic-gate pf_emit(x)
120*0Sstevel@tonic-gate 	ushort_t x;
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
123*0Sstevel@tonic-gate 		longjmp(env, 1);
124*0Sstevel@tonic-gate 	*pfp++ = x;
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate static void
128*0Sstevel@tonic-gate pf_codeprint(code, len)
129*0Sstevel@tonic-gate 	ushort_t *code;
130*0Sstevel@tonic-gate 	int len;
131*0Sstevel@tonic-gate {
132*0Sstevel@tonic-gate 	ushort_t *pc;
133*0Sstevel@tonic-gate 	ushort_t *plast = code + len;
134*0Sstevel@tonic-gate 	int op, action;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	if (len > 0) {
137*0Sstevel@tonic-gate 		printf("Kernel Filter:\n");
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	for (pc = code; pc < plast; pc++) {
141*0Sstevel@tonic-gate 		printf("\t%3d: ", pc - code);
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 		op = *pc & 0xfc00;	/* high 10 bits */
144*0Sstevel@tonic-gate 		action = *pc & 0x3ff;	/* low   6 bits */
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 		switch (action) {
147*0Sstevel@tonic-gate 		case ENF_PUSHLIT:
148*0Sstevel@tonic-gate 			printf("PUSHLIT ");
149*0Sstevel@tonic-gate 			break;
150*0Sstevel@tonic-gate 		case ENF_PUSHZERO:
151*0Sstevel@tonic-gate 			printf("PUSHZERO ");
152*0Sstevel@tonic-gate 			break;
153*0Sstevel@tonic-gate #ifdef ENF_PUSHONE
154*0Sstevel@tonic-gate 		case ENF_PUSHONE:
155*0Sstevel@tonic-gate 			printf("PUSHONE ");
156*0Sstevel@tonic-gate 			break;
157*0Sstevel@tonic-gate #endif
158*0Sstevel@tonic-gate #ifdef ENF_PUSHFFFF
159*0Sstevel@tonic-gate 		case ENF_PUSHFFFF:
160*0Sstevel@tonic-gate 			printf("PUSHFFFF ");
161*0Sstevel@tonic-gate 			break;
162*0Sstevel@tonic-gate #endif
163*0Sstevel@tonic-gate #ifdef ENF_PUSHFF00
164*0Sstevel@tonic-gate 		case ENF_PUSHFF00:
165*0Sstevel@tonic-gate 			printf("PUSHFF00 ");
166*0Sstevel@tonic-gate 			break;
167*0Sstevel@tonic-gate #endif
168*0Sstevel@tonic-gate #ifdef ENF_PUSH00FF
169*0Sstevel@tonic-gate 		case ENF_PUSH00FF:
170*0Sstevel@tonic-gate 			printf("PUSH00FF ");
171*0Sstevel@tonic-gate 			break;
172*0Sstevel@tonic-gate #endif
173*0Sstevel@tonic-gate 		}
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 		if (action >= ENF_PUSHWORD)
176*0Sstevel@tonic-gate 			printf("PUSHWORD %d ", action - ENF_PUSHWORD);
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 		switch (op) {
179*0Sstevel@tonic-gate 		case ENF_EQ:
180*0Sstevel@tonic-gate 			printf("EQ ");
181*0Sstevel@tonic-gate 			break;
182*0Sstevel@tonic-gate 		case ENF_LT:
183*0Sstevel@tonic-gate 			printf("LT ");
184*0Sstevel@tonic-gate 			break;
185*0Sstevel@tonic-gate 		case ENF_LE:
186*0Sstevel@tonic-gate 			printf("LE ");
187*0Sstevel@tonic-gate 			break;
188*0Sstevel@tonic-gate 		case ENF_GT:
189*0Sstevel@tonic-gate 			printf("GT ");
190*0Sstevel@tonic-gate 			break;
191*0Sstevel@tonic-gate 		case ENF_GE:
192*0Sstevel@tonic-gate 			printf("GE ");
193*0Sstevel@tonic-gate 			break;
194*0Sstevel@tonic-gate 		case ENF_AND:
195*0Sstevel@tonic-gate 			printf("AND ");
196*0Sstevel@tonic-gate 			break;
197*0Sstevel@tonic-gate 		case ENF_OR:
198*0Sstevel@tonic-gate 			printf("OR ");
199*0Sstevel@tonic-gate 			break;
200*0Sstevel@tonic-gate 		case ENF_XOR:
201*0Sstevel@tonic-gate 			printf("XOR ");
202*0Sstevel@tonic-gate 			break;
203*0Sstevel@tonic-gate 		case ENF_COR:
204*0Sstevel@tonic-gate 			printf("COR ");
205*0Sstevel@tonic-gate 			break;
206*0Sstevel@tonic-gate 		case ENF_CAND:
207*0Sstevel@tonic-gate 			printf("CAND ");
208*0Sstevel@tonic-gate 			break;
209*0Sstevel@tonic-gate 		case ENF_CNOR:
210*0Sstevel@tonic-gate 			printf("CNOR ");
211*0Sstevel@tonic-gate 			break;
212*0Sstevel@tonic-gate 		case ENF_CNAND:
213*0Sstevel@tonic-gate 			printf("CNAND ");
214*0Sstevel@tonic-gate 			break;
215*0Sstevel@tonic-gate 		case ENF_NEQ:
216*0Sstevel@tonic-gate 			printf("NEQ ");
217*0Sstevel@tonic-gate 			break;
218*0Sstevel@tonic-gate 		}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		if (action == ENF_PUSHLIT) {
221*0Sstevel@tonic-gate 			pc++;
222*0Sstevel@tonic-gate 			printf("\n\t%3d:   %d (0x%04x)", pc - code, *pc, *pc);
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		printf("\n");
226*0Sstevel@tonic-gate 	}
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * Emit packet filter code to check a
231*0Sstevel@tonic-gate  * field in the packet for a particular value.
232*0Sstevel@tonic-gate  * Need different code for each field size.
233*0Sstevel@tonic-gate  * Since the pf can only compare 16 bit quantities
234*0Sstevel@tonic-gate  * we have to use masking to compare byte values.
235*0Sstevel@tonic-gate  * Long word (32 bit) quantities have to be done
236*0Sstevel@tonic-gate  * as two 16 bit comparisons.
237*0Sstevel@tonic-gate  */
238*0Sstevel@tonic-gate static void
239*0Sstevel@tonic-gate pf_compare_value(int offset, uint_t len, uint_t val)
240*0Sstevel@tonic-gate {
241*0Sstevel@tonic-gate 	/*
242*0Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
243*0Sstevel@tonic-gate 	 * packet, error out.
244*0Sstevel@tonic-gate 	 */
245*0Sstevel@tonic-gate 	if (offset == -1)
246*0Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	switch (len) {
249*0Sstevel@tonic-gate 	case 1:
250*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
251*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
252*0Sstevel@tonic-gate 		if (offset % 2)
253*0Sstevel@tonic-gate #else
254*0Sstevel@tonic-gate 		if (!(offset % 2))
255*0Sstevel@tonic-gate #endif
256*0Sstevel@tonic-gate 		{
257*0Sstevel@tonic-gate #ifdef ENF_PUSH00FF
258*0Sstevel@tonic-gate 			pf_emit(ENF_PUSH00FF | ENF_AND);
259*0Sstevel@tonic-gate #else
260*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
261*0Sstevel@tonic-gate 			pf_emit(0x00FF);
262*0Sstevel@tonic-gate #endif
263*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
264*0Sstevel@tonic-gate 			pf_emit(val);
265*0Sstevel@tonic-gate 		} else {
266*0Sstevel@tonic-gate #ifdef ENF_PUSHFF00
267*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHFF00 | ENF_AND);
268*0Sstevel@tonic-gate #else
269*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
270*0Sstevel@tonic-gate 			pf_emit(0xFF00);
271*0Sstevel@tonic-gate #endif
272*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
273*0Sstevel@tonic-gate 			pf_emit(val << 8);
274*0Sstevel@tonic-gate 		}
275*0Sstevel@tonic-gate 		break;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	case 2:
278*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
279*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
280*0Sstevel@tonic-gate 		pf_emit((ushort_t)val);
281*0Sstevel@tonic-gate 		break;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	case 4:
284*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
285*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
286*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
287*0Sstevel@tonic-gate 		pf_emit(val >> 16);
288*0Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN)
289*0Sstevel@tonic-gate 		pf_emit(val & 0xffff);
290*0Sstevel@tonic-gate #else
291*0Sstevel@tonic-gate #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
292*0Sstevel@tonic-gate #endif
293*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
294*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
295*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
296*0Sstevel@tonic-gate 		pf_emit(val & 0xffff);
297*0Sstevel@tonic-gate #else
298*0Sstevel@tonic-gate 		pf_emit(val >> 16);
299*0Sstevel@tonic-gate #endif
300*0Sstevel@tonic-gate 		pf_emit(ENF_AND);
301*0Sstevel@tonic-gate 		break;
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate /*
306*0Sstevel@tonic-gate  * same as pf_compare_value, but only for emiting code to
307*0Sstevel@tonic-gate  * compare ipv6 addresses.
308*0Sstevel@tonic-gate  */
309*0Sstevel@tonic-gate static void
310*0Sstevel@tonic-gate pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
311*0Sstevel@tonic-gate {
312*0Sstevel@tonic-gate 	int i;
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	for (i = 0; i < len; i += 2) {
315*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
316*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
317*0Sstevel@tonic-gate 		pf_emit(*(uint16_t *)&val.s6_addr[i]);
318*0Sstevel@tonic-gate 		if (i != 0)
319*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate }
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate /*
325*0Sstevel@tonic-gate  * Same as above except mask the field value
326*0Sstevel@tonic-gate  * before doing the comparison.
327*0Sstevel@tonic-gate  */
328*0Sstevel@tonic-gate static void
329*0Sstevel@tonic-gate pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
330*0Sstevel@tonic-gate {
331*0Sstevel@tonic-gate 	/*
332*0Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
333*0Sstevel@tonic-gate 	 * packet, error out.
334*0Sstevel@tonic-gate 	 */
335*0Sstevel@tonic-gate 	if (offset == -1)
336*0Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	switch (len) {
339*0Sstevel@tonic-gate 	case 1:
340*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
341*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
342*0Sstevel@tonic-gate 		if (offset % 2)
343*0Sstevel@tonic-gate #else
344*0Sstevel@tonic-gate 		if (!offset % 2)
345*0Sstevel@tonic-gate #endif
346*0Sstevel@tonic-gate 		{
347*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
348*0Sstevel@tonic-gate 			pf_emit(mask & 0x00ff);
349*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
350*0Sstevel@tonic-gate 			pf_emit(val);
351*0Sstevel@tonic-gate 		} else {
352*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
353*0Sstevel@tonic-gate 			pf_emit((mask << 8) & 0xff00);
354*0Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
355*0Sstevel@tonic-gate 			pf_emit(val << 8);
356*0Sstevel@tonic-gate 		}
357*0Sstevel@tonic-gate 		break;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	case 2:
360*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
361*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
362*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)mask));
363*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
364*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)val));
365*0Sstevel@tonic-gate 		break;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	case 4:
368*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
369*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
370*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
371*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
372*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
375*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
376*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)(mask & 0xffff)));
377*0Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
378*0Sstevel@tonic-gate 		pf_emit(htons((ushort_t)(val & 0xffff)));
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		pf_emit(ENF_AND);
381*0Sstevel@tonic-gate 		break;
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate /*
386*0Sstevel@tonic-gate  * Generate pf code to match an IPv4 or IPv6 address.
387*0Sstevel@tonic-gate  */
388*0Sstevel@tonic-gate static void
389*0Sstevel@tonic-gate pf_ipaddr_match(which, hostname, inet_type)
390*0Sstevel@tonic-gate 	enum direction which;
391*0Sstevel@tonic-gate 	char *hostname;
392*0Sstevel@tonic-gate 	int inet_type;
393*0Sstevel@tonic-gate {
394*0Sstevel@tonic-gate 	bool_t found_host;
395*0Sstevel@tonic-gate 	uint_t *addr4ptr;
396*0Sstevel@tonic-gate 	uint_t addr4;
397*0Sstevel@tonic-gate 	struct in6_addr *addr6ptr;
398*0Sstevel@tonic-gate 	int h_addr_index;
399*0Sstevel@tonic-gate 	struct hostent *hp = NULL;
400*0Sstevel@tonic-gate 	int error_num = 0;
401*0Sstevel@tonic-gate 	boolean_t first = B_TRUE;
402*0Sstevel@tonic-gate 	int pass = 0;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	/*
405*0Sstevel@tonic-gate 	 * The addr4offset and addr6offset variables simplify the code which
406*0Sstevel@tonic-gate 	 * generates the address comparison filter.  With these two variables,
407*0Sstevel@tonic-gate 	 * duplicate code need not exist for the TO and FROM case.
408*0Sstevel@tonic-gate 	 * A value of -1 describes the ANY case (TO and FROM).
409*0Sstevel@tonic-gate 	 */
410*0Sstevel@tonic-gate 	int addr4offset;
411*0Sstevel@tonic-gate 	int addr6offset;
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	found_host = 0;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	if (tokentype == ADDR_IP) {
416*0Sstevel@tonic-gate 		hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
417*0Sstevel@tonic-gate 		if (hp == NULL) {
418*0Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
419*0Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
420*0Sstevel@tonic-gate 				    hostname);
421*0Sstevel@tonic-gate 			} else {
422*0Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
423*0Sstevel@tonic-gate 			}
424*0Sstevel@tonic-gate 		}
425*0Sstevel@tonic-gate 		inet_type = IPV4_ONLY;
426*0Sstevel@tonic-gate 	} else if (tokentype == ADDR_IP6) {
427*0Sstevel@tonic-gate 		hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
428*0Sstevel@tonic-gate 		if (hp == NULL) {
429*0Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
430*0Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
431*0Sstevel@tonic-gate 				    hostname);
432*0Sstevel@tonic-gate 			} else {
433*0Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
434*0Sstevel@tonic-gate 			}
435*0Sstevel@tonic-gate 		}
436*0Sstevel@tonic-gate 		inet_type = IPV6_ONLY;
437*0Sstevel@tonic-gate 	} else if (tokentype == ALPHA) {
438*0Sstevel@tonic-gate 		/* Some hostname i.e. tokentype is ALPHA */
439*0Sstevel@tonic-gate 		switch (inet_type) {
440*0Sstevel@tonic-gate 		case IPV4_ONLY:
441*0Sstevel@tonic-gate 			/* Only IPv4 address is needed */
442*0Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
443*0Sstevel@tonic-gate 			if (hp != NULL) {
444*0Sstevel@tonic-gate 				found_host = 1;
445*0Sstevel@tonic-gate 			}
446*0Sstevel@tonic-gate 			break;
447*0Sstevel@tonic-gate 		case IPV6_ONLY:
448*0Sstevel@tonic-gate 			/* Only IPv6 address is needed */
449*0Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
450*0Sstevel@tonic-gate 			if (hp != NULL) {
451*0Sstevel@tonic-gate 				found_host = 1;
452*0Sstevel@tonic-gate 			}
453*0Sstevel@tonic-gate 			break;
454*0Sstevel@tonic-gate 		case IPV4_AND_IPV6:
455*0Sstevel@tonic-gate 			/* Both IPv4 and IPv6 are needed */
456*0Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6,
457*0Sstevel@tonic-gate 			    AI_ALL | AI_V4MAPPED, &error_num);
458*0Sstevel@tonic-gate 			if (hp != NULL) {
459*0Sstevel@tonic-gate 				found_host = 1;
460*0Sstevel@tonic-gate 			}
461*0Sstevel@tonic-gate 			break;
462*0Sstevel@tonic-gate 		default:
463*0Sstevel@tonic-gate 			found_host = 0;
464*0Sstevel@tonic-gate 		}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 		if (!found_host) {
467*0Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
468*0Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
469*0Sstevel@tonic-gate 				    hostname);
470*0Sstevel@tonic-gate 			} else {
471*0Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
472*0Sstevel@tonic-gate 			}
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 	} else {
475*0Sstevel@tonic-gate 		pr_err("unknown token type: %s", hostname);
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	switch (which) {
479*0Sstevel@tonic-gate 	case TO:
480*0Sstevel@tonic-gate 		addr4offset = IPV4_DSTADDR_OFFSET;
481*0Sstevel@tonic-gate 		addr6offset = IPV6_DSTADDR_OFFSET;
482*0Sstevel@tonic-gate 		break;
483*0Sstevel@tonic-gate 	case FROM:
484*0Sstevel@tonic-gate 		addr4offset = IPV4_SRCADDR_OFFSET;
485*0Sstevel@tonic-gate 		addr6offset = IPV6_SRCADDR_OFFSET;
486*0Sstevel@tonic-gate 		break;
487*0Sstevel@tonic-gate 	case ANY:
488*0Sstevel@tonic-gate 		addr4offset = -1;
489*0Sstevel@tonic-gate 		addr6offset = -1;
490*0Sstevel@tonic-gate 		break;
491*0Sstevel@tonic-gate 	}
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	if (hp != NULL && hp->h_addrtype == AF_INET) {
494*0Sstevel@tonic-gate 		pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_IP));
495*0Sstevel@tonic-gate 		h_addr_index = 0;
496*0Sstevel@tonic-gate 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
497*0Sstevel@tonic-gate 		while (addr4ptr != NULL) {
498*0Sstevel@tonic-gate 			if (addr4offset == -1) {
499*0Sstevel@tonic-gate 				pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
500*0Sstevel@tonic-gate 				    *addr4ptr);
501*0Sstevel@tonic-gate 				if (h_addr_index != 0)
502*0Sstevel@tonic-gate 					pf_emit(ENF_OR);
503*0Sstevel@tonic-gate 				pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
504*0Sstevel@tonic-gate 				    *addr4ptr);
505*0Sstevel@tonic-gate 				pf_emit(ENF_OR);
506*0Sstevel@tonic-gate 			} else {
507*0Sstevel@tonic-gate 				pf_compare_value(addr4offset, 4,
508*0Sstevel@tonic-gate 				    *addr4ptr);
509*0Sstevel@tonic-gate 				if (h_addr_index != 0)
510*0Sstevel@tonic-gate 					pf_emit(ENF_OR);
511*0Sstevel@tonic-gate 			}
512*0Sstevel@tonic-gate 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 		pf_emit(ENF_AND);
515*0Sstevel@tonic-gate 	} else {
516*0Sstevel@tonic-gate 		/* first pass: IPv4 addresses */
517*0Sstevel@tonic-gate 		h_addr_index = 0;
518*0Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
519*0Sstevel@tonic-gate 		first = B_TRUE;
520*0Sstevel@tonic-gate 		while (addr6ptr != NULL) {
521*0Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
522*0Sstevel@tonic-gate 				if (first) {
523*0Sstevel@tonic-gate 					pf_compare_value(link_type_offset, 2,
524*0Sstevel@tonic-gate 						htons(ETHERTYPE_IP));
525*0Sstevel@tonic-gate 					pass++;
526*0Sstevel@tonic-gate 				}
527*0Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
528*0Sstevel@tonic-gate 				    (struct in_addr *)&addr4);
529*0Sstevel@tonic-gate 				if (addr4offset == -1) {
530*0Sstevel@tonic-gate 					pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
531*0Sstevel@tonic-gate 					    addr4);
532*0Sstevel@tonic-gate 					if (!first)
533*0Sstevel@tonic-gate 						pf_emit(ENF_OR);
534*0Sstevel@tonic-gate 					pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
535*0Sstevel@tonic-gate 					    addr4);
536*0Sstevel@tonic-gate 					pf_emit(ENF_OR);
537*0Sstevel@tonic-gate 				} else {
538*0Sstevel@tonic-gate 					pf_compare_value(addr4offset, 4,
539*0Sstevel@tonic-gate 					    addr4);
540*0Sstevel@tonic-gate 					if (!first)
541*0Sstevel@tonic-gate 						pf_emit(ENF_OR);
542*0Sstevel@tonic-gate 				}
543*0Sstevel@tonic-gate 				if (first)
544*0Sstevel@tonic-gate 					first = B_FALSE;
545*0Sstevel@tonic-gate 			}
546*0Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
547*0Sstevel@tonic-gate 				hp->h_addr_list[++h_addr_index];
548*0Sstevel@tonic-gate 		}
549*0Sstevel@tonic-gate 		if (!first) {
550*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
551*0Sstevel@tonic-gate 		}
552*0Sstevel@tonic-gate 		/* second pass: IPv6 addresses */
553*0Sstevel@tonic-gate 		h_addr_index = 0;
554*0Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
555*0Sstevel@tonic-gate 		first = B_TRUE;
556*0Sstevel@tonic-gate 		while (addr6ptr != NULL) {
557*0Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
558*0Sstevel@tonic-gate 				if (first) {
559*0Sstevel@tonic-gate 					pf_compare_value(link_type_offset, 2,
560*0Sstevel@tonic-gate 						htons(ETHERTYPE_IPV6));
561*0Sstevel@tonic-gate 					pass++;
562*0Sstevel@tonic-gate 				}
563*0Sstevel@tonic-gate 				if (addr6offset == -1) {
564*0Sstevel@tonic-gate 					pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
565*0Sstevel@tonic-gate 					    16, *addr6ptr);
566*0Sstevel@tonic-gate 					if (!first)
567*0Sstevel@tonic-gate 						pf_emit(ENF_OR);
568*0Sstevel@tonic-gate 					pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
569*0Sstevel@tonic-gate 					    16, *addr6ptr);
570*0Sstevel@tonic-gate 					pf_emit(ENF_OR);
571*0Sstevel@tonic-gate 				} else {
572*0Sstevel@tonic-gate 					pf_compare_value_v6(addr6offset, 16,
573*0Sstevel@tonic-gate 					    *addr6ptr);
574*0Sstevel@tonic-gate 					if (!first)
575*0Sstevel@tonic-gate 						pf_emit(ENF_OR);
576*0Sstevel@tonic-gate 				}
577*0Sstevel@tonic-gate 				if (first)
578*0Sstevel@tonic-gate 					first = B_FALSE;
579*0Sstevel@tonic-gate 			}
580*0Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
581*0Sstevel@tonic-gate 				hp->h_addr_list[++h_addr_index];
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 		if (!first) {
584*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
585*0Sstevel@tonic-gate 		}
586*0Sstevel@tonic-gate 		if (pass == 2) {
587*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
588*0Sstevel@tonic-gate 		}
589*0Sstevel@tonic-gate 	}
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	if (hp != NULL) {
592*0Sstevel@tonic-gate 		freehostent(hp);
593*0Sstevel@tonic-gate 	}
594*0Sstevel@tonic-gate }
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate static void
598*0Sstevel@tonic-gate pf_compare_address(int offset, uint_t len, uchar_t *addr)
599*0Sstevel@tonic-gate {
600*0Sstevel@tonic-gate 	uint32_t val;
601*0Sstevel@tonic-gate 	uint16_t sval;
602*0Sstevel@tonic-gate 	boolean_t didone = B_FALSE;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	/*
605*0Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
606*0Sstevel@tonic-gate 	 * packet, error out.
607*0Sstevel@tonic-gate 	 */
608*0Sstevel@tonic-gate 	if (offset == -1)
609*0Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	while (len > 0) {
612*0Sstevel@tonic-gate 		if (len >= 4) {
613*0Sstevel@tonic-gate 			(void) memcpy(&val, addr, 4);
614*0Sstevel@tonic-gate 			pf_compare_value(offset, 4, val);
615*0Sstevel@tonic-gate 			addr += 4;
616*0Sstevel@tonic-gate 			offset += 4;
617*0Sstevel@tonic-gate 			len -= 4;
618*0Sstevel@tonic-gate 		} else if (len >= 2) {
619*0Sstevel@tonic-gate 			(void) memcpy(&sval, addr, 2);
620*0Sstevel@tonic-gate 			pf_compare_value(offset, 2, sval);
621*0Sstevel@tonic-gate 			addr += 2;
622*0Sstevel@tonic-gate 			offset += 2;
623*0Sstevel@tonic-gate 			len -= 2;
624*0Sstevel@tonic-gate 		} else {
625*0Sstevel@tonic-gate 			pf_compare_value(offset++, 1, *addr++);
626*0Sstevel@tonic-gate 			len--;
627*0Sstevel@tonic-gate 		}
628*0Sstevel@tonic-gate 		if (didone)
629*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
630*0Sstevel@tonic-gate 		didone = B_TRUE;
631*0Sstevel@tonic-gate 	}
632*0Sstevel@tonic-gate }
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate /*
635*0Sstevel@tonic-gate  * Compare ethernet addresses.
636*0Sstevel@tonic-gate  */
637*0Sstevel@tonic-gate static void
638*0Sstevel@tonic-gate pf_etheraddr_match(which, hostname)
639*0Sstevel@tonic-gate 	enum direction which;
640*0Sstevel@tonic-gate 	char *hostname;
641*0Sstevel@tonic-gate {
642*0Sstevel@tonic-gate 	struct ether_addr e, *ep = NULL;
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	if (isxdigit(*hostname))
645*0Sstevel@tonic-gate 		ep = ether_aton(hostname);
646*0Sstevel@tonic-gate 	if (ep == NULL) {
647*0Sstevel@tonic-gate 		if (ether_hostton(hostname, &e))
648*0Sstevel@tonic-gate 			if (!arp_for_ether(hostname, &e))
649*0Sstevel@tonic-gate 				pr_err("cannot obtain ether addr for %s",
650*0Sstevel@tonic-gate 					hostname);
651*0Sstevel@tonic-gate 		ep = &e;
652*0Sstevel@tonic-gate 	}
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	switch (which) {
655*0Sstevel@tonic-gate 	case TO:
656*0Sstevel@tonic-gate 		pf_compare_address(link_dest_offset, link_addr_len,
657*0Sstevel@tonic-gate 		    (uchar_t *)ep);
658*0Sstevel@tonic-gate 		break;
659*0Sstevel@tonic-gate 	case FROM:
660*0Sstevel@tonic-gate 		pf_compare_address(link_src_offset, link_addr_len,
661*0Sstevel@tonic-gate 		    (uchar_t *)ep);
662*0Sstevel@tonic-gate 		break;
663*0Sstevel@tonic-gate 	case ANY:
664*0Sstevel@tonic-gate 		pf_compare_address(link_dest_offset, link_addr_len,
665*0Sstevel@tonic-gate 		    (uchar_t *)ep);
666*0Sstevel@tonic-gate 		pf_compare_address(link_src_offset, link_addr_len,
667*0Sstevel@tonic-gate 		    (uchar_t *)ep);
668*0Sstevel@tonic-gate 		pf_emit(ENF_OR);
669*0Sstevel@tonic-gate 		break;
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate /*
674*0Sstevel@tonic-gate  * Emit code to compare the network part of
675*0Sstevel@tonic-gate  * an IP address.
676*0Sstevel@tonic-gate  */
677*0Sstevel@tonic-gate static void
678*0Sstevel@tonic-gate pf_netaddr_match(which, netname)
679*0Sstevel@tonic-gate 	enum direction which;
680*0Sstevel@tonic-gate 	char *netname;
681*0Sstevel@tonic-gate {
682*0Sstevel@tonic-gate 	uint_t addr;
683*0Sstevel@tonic-gate 	uint_t mask = 0xff000000;
684*0Sstevel@tonic-gate 	struct netent *np;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	if (isdigit(*netname)) {
687*0Sstevel@tonic-gate 		addr = inet_network(netname);
688*0Sstevel@tonic-gate 	} else {
689*0Sstevel@tonic-gate 		np = getnetbyname(netname);
690*0Sstevel@tonic-gate 		if (np == NULL)
691*0Sstevel@tonic-gate 			pr_err("net %s not known", netname);
692*0Sstevel@tonic-gate 		addr = np->n_net;
693*0Sstevel@tonic-gate 	}
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	/*
696*0Sstevel@tonic-gate 	 * Left justify the address and figure
697*0Sstevel@tonic-gate 	 * out a mask based on the supplied address.
698*0Sstevel@tonic-gate 	 * Set the mask according to the number of zero
699*0Sstevel@tonic-gate 	 * low-order bytes.
700*0Sstevel@tonic-gate 	 * Note: this works only for whole octet masks.
701*0Sstevel@tonic-gate 	 */
702*0Sstevel@tonic-gate 	if (addr) {
703*0Sstevel@tonic-gate 		while ((addr & ~mask) != 0) {
704*0Sstevel@tonic-gate 			mask |= (mask >> 8);
705*0Sstevel@tonic-gate 		}
706*0Sstevel@tonic-gate 	}
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	switch (which) {
709*0Sstevel@tonic-gate 	case TO:
710*0Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
711*0Sstevel@tonic-gate 		break;
712*0Sstevel@tonic-gate 	case FROM:
713*0Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
714*0Sstevel@tonic-gate 		break;
715*0Sstevel@tonic-gate 	case ANY:
716*0Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
717*0Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
718*0Sstevel@tonic-gate 		pf_emit(ENF_OR);
719*0Sstevel@tonic-gate 		break;
720*0Sstevel@tonic-gate 	}
721*0Sstevel@tonic-gate }
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate static void
724*0Sstevel@tonic-gate pf_primary()
725*0Sstevel@tonic-gate {
726*0Sstevel@tonic-gate 	for (;;) {
727*0Sstevel@tonic-gate 		if (tokentype == FIELD)
728*0Sstevel@tonic-gate 			break;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 		if (EQ("ip")) {
731*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
732*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
733*0Sstevel@tonic-gate 			opstack++;
734*0Sstevel@tonic-gate 			next();
735*0Sstevel@tonic-gate 			break;
736*0Sstevel@tonic-gate 		}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 		if (EQ("ip6")) {
739*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
740*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
741*0Sstevel@tonic-gate 			opstack++;
742*0Sstevel@tonic-gate 			next();
743*0Sstevel@tonic-gate 			break;
744*0Sstevel@tonic-gate 		}
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 		if (EQ("pppoe")) {
747*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
748*0Sstevel@tonic-gate 			    htons(ETHERTYPE_PPPOED));
749*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
750*0Sstevel@tonic-gate 			    htons(ETHERTYPE_PPPOES));
751*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
752*0Sstevel@tonic-gate 			opstack++;
753*0Sstevel@tonic-gate 			next();
754*0Sstevel@tonic-gate 			break;
755*0Sstevel@tonic-gate 		}
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 		if (EQ("pppoed")) {
758*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
759*0Sstevel@tonic-gate 			    htons(ETHERTYPE_PPPOED));
760*0Sstevel@tonic-gate 			opstack++;
761*0Sstevel@tonic-gate 			next();
762*0Sstevel@tonic-gate 			break;
763*0Sstevel@tonic-gate 		}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 		if (EQ("pppoes")) {
766*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
767*0Sstevel@tonic-gate 			    htons(ETHERTYPE_PPPOES));
768*0Sstevel@tonic-gate 			opstack++;
769*0Sstevel@tonic-gate 			next();
770*0Sstevel@tonic-gate 			break;
771*0Sstevel@tonic-gate 		}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 		if (EQ("arp")) {
774*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
775*0Sstevel@tonic-gate 			    htons(ETHERTYPE_ARP));
776*0Sstevel@tonic-gate 			opstack++;
777*0Sstevel@tonic-gate 			next();
778*0Sstevel@tonic-gate 			break;
779*0Sstevel@tonic-gate 		}
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 		if (EQ("rarp")) {
782*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
783*0Sstevel@tonic-gate 			    htons(ETHERTYPE_REVARP));
784*0Sstevel@tonic-gate 			opstack++;
785*0Sstevel@tonic-gate 			next();
786*0Sstevel@tonic-gate 			break;
787*0Sstevel@tonic-gate 		}
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 		if (EQ("tcp")) {
790*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
791*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
792*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_TCP);
793*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
794*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
795*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
796*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_TCP);
797*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
798*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
799*0Sstevel@tonic-gate 			opstack++;
800*0Sstevel@tonic-gate 			next();
801*0Sstevel@tonic-gate 			break;
802*0Sstevel@tonic-gate 		}
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 		if (EQ("udp")) {
805*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
806*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
807*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_UDP);
808*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
809*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
810*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
811*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_UDP);
812*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
813*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
814*0Sstevel@tonic-gate 			opstack++;
815*0Sstevel@tonic-gate 			next();
816*0Sstevel@tonic-gate 			break;
817*0Sstevel@tonic-gate 		}
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 		if (EQ("ospf")) {
820*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
821*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
822*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_OSPF);
823*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
824*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
825*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
826*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_OSPF);
827*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
828*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
829*0Sstevel@tonic-gate 			opstack++;
830*0Sstevel@tonic-gate 			next();
831*0Sstevel@tonic-gate 			break;
832*0Sstevel@tonic-gate 		}
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 		if (EQ("sctp")) {
836*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
837*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
838*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_SCTP);
839*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
840*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
841*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
842*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_SCTP);
843*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
844*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
845*0Sstevel@tonic-gate 			opstack++;
846*0Sstevel@tonic-gate 			next();
847*0Sstevel@tonic-gate 			break;
848*0Sstevel@tonic-gate 		}
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 		if (EQ("icmp")) {
851*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
852*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
853*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ICMP);
854*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
855*0Sstevel@tonic-gate 			opstack++;
856*0Sstevel@tonic-gate 			next();
857*0Sstevel@tonic-gate 			break;
858*0Sstevel@tonic-gate 		}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 		if (EQ("icmp6")) {
861*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
862*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
863*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ICMPV6);
864*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
865*0Sstevel@tonic-gate 			opstack++;
866*0Sstevel@tonic-gate 			next();
867*0Sstevel@tonic-gate 			break;
868*0Sstevel@tonic-gate 		}
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 		if (EQ("ip-in-ip")) {
871*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
872*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
873*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ENCAP);
874*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
875*0Sstevel@tonic-gate 			opstack++;
876*0Sstevel@tonic-gate 			next();
877*0Sstevel@tonic-gate 			break;
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 		if (EQ("esp")) {
881*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
882*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
883*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ESP);
884*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
885*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
886*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
887*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ESP);
888*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
889*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
890*0Sstevel@tonic-gate 			opstack++;
891*0Sstevel@tonic-gate 			next();
892*0Sstevel@tonic-gate 			break;
893*0Sstevel@tonic-gate 		}
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 		if (EQ("ah")) {
896*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
897*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IP));
898*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_AH);
899*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
900*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2,
901*0Sstevel@tonic-gate 			    htons(ETHERTYPE_IPV6));
902*0Sstevel@tonic-gate 			pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_AH);
903*0Sstevel@tonic-gate 			pf_emit(ENF_AND);
904*0Sstevel@tonic-gate 			pf_emit(ENF_OR);
905*0Sstevel@tonic-gate 			opstack++;
906*0Sstevel@tonic-gate 			next();
907*0Sstevel@tonic-gate 			break;
908*0Sstevel@tonic-gate 		}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 		if (EQ("(")) {
911*0Sstevel@tonic-gate 			inBrace++;
912*0Sstevel@tonic-gate 			next();
913*0Sstevel@tonic-gate 			pf_expression();
914*0Sstevel@tonic-gate 			if (EQ(")")) {
915*0Sstevel@tonic-gate 				if (inBrace)
916*0Sstevel@tonic-gate 					inBraceOR--;
917*0Sstevel@tonic-gate 				inBrace--;
918*0Sstevel@tonic-gate 				next();
919*0Sstevel@tonic-gate 			}
920*0Sstevel@tonic-gate 			break;
921*0Sstevel@tonic-gate 		}
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 		if (EQ("to") || EQ("dst")) {
924*0Sstevel@tonic-gate 			dir = TO;
925*0Sstevel@tonic-gate 			next();
926*0Sstevel@tonic-gate 			continue;
927*0Sstevel@tonic-gate 		}
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 		if (EQ("from") || EQ("src")) {
930*0Sstevel@tonic-gate 			dir = FROM;
931*0Sstevel@tonic-gate 			next();
932*0Sstevel@tonic-gate 			continue;
933*0Sstevel@tonic-gate 		}
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 		if (EQ("ether")) {
936*0Sstevel@tonic-gate 			eaddr = 1;
937*0Sstevel@tonic-gate 			next();
938*0Sstevel@tonic-gate 			continue;
939*0Sstevel@tonic-gate 		}
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 		if (EQ("inet")) {
942*0Sstevel@tonic-gate 			next();
943*0Sstevel@tonic-gate 			if (EQ("host"))
944*0Sstevel@tonic-gate 				next();
945*0Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP)
946*0Sstevel@tonic-gate 				pr_err("host/IPv4 addr expected after inet");
947*0Sstevel@tonic-gate 			pf_ipaddr_match(dir, token, IPV4_ONLY);
948*0Sstevel@tonic-gate 			opstack++;
949*0Sstevel@tonic-gate 			next();
950*0Sstevel@tonic-gate 			break;
951*0Sstevel@tonic-gate 		}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 		if (EQ("inet6")) {
954*0Sstevel@tonic-gate 			next();
955*0Sstevel@tonic-gate 			if (EQ("host"))
956*0Sstevel@tonic-gate 				next();
957*0Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
958*0Sstevel@tonic-gate 				pr_err("host/IPv6 addr expected after inet6");
959*0Sstevel@tonic-gate 			pf_ipaddr_match(dir, token, IPV6_ONLY);
960*0Sstevel@tonic-gate 			opstack++;
961*0Sstevel@tonic-gate 			next();
962*0Sstevel@tonic-gate 			break;
963*0Sstevel@tonic-gate 		}
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 		if (EQ("proto")) {
966*0Sstevel@tonic-gate 			next();
967*0Sstevel@tonic-gate 			if (tokentype != NUMBER)
968*0Sstevel@tonic-gate 				pr_err("IP proto type expected");
969*0Sstevel@tonic-gate 			pf_compare_value(IPV4_TYPE_OFFSET, 1, tokenval);
970*0Sstevel@tonic-gate 			opstack++;
971*0Sstevel@tonic-gate 			next();
972*0Sstevel@tonic-gate 			break;
973*0Sstevel@tonic-gate 		}
974*0Sstevel@tonic-gate 
975*0Sstevel@tonic-gate 		if (EQ("broadcast")) {
976*0Sstevel@tonic-gate 			pf_compare_value(link_dest_offset, 4, 0xffffffff);
977*0Sstevel@tonic-gate 			opstack++;
978*0Sstevel@tonic-gate 			next();
979*0Sstevel@tonic-gate 			break;
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 		if (EQ("multicast")) {
983*0Sstevel@tonic-gate 			pf_compare_value_mask(link_dest_offset, 1, 0x01, 0x01);
984*0Sstevel@tonic-gate 			opstack++;
985*0Sstevel@tonic-gate 			next();
986*0Sstevel@tonic-gate 			break;
987*0Sstevel@tonic-gate 		}
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 		if (EQ("ethertype")) {
990*0Sstevel@tonic-gate 			next();
991*0Sstevel@tonic-gate 			if (tokentype != NUMBER)
992*0Sstevel@tonic-gate 				pr_err("ether type expected");
993*0Sstevel@tonic-gate 			pf_compare_value(link_type_offset, 2, htons(tokenval));
994*0Sstevel@tonic-gate 			opstack++;
995*0Sstevel@tonic-gate 			next();
996*0Sstevel@tonic-gate 			break;
997*0Sstevel@tonic-gate 		}
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
1000*0Sstevel@tonic-gate 			if (EQ("dstnet"))
1001*0Sstevel@tonic-gate 				dir = TO;
1002*0Sstevel@tonic-gate 			else if (EQ("srcnet"))
1003*0Sstevel@tonic-gate 				dir = FROM;
1004*0Sstevel@tonic-gate 			next();
1005*0Sstevel@tonic-gate 			pf_netaddr_match(dir, token);
1006*0Sstevel@tonic-gate 			dir = ANY;
1007*0Sstevel@tonic-gate 			opstack++;
1008*0Sstevel@tonic-gate 			next();
1009*0Sstevel@tonic-gate 			break;
1010*0Sstevel@tonic-gate 		}
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 		/*
1013*0Sstevel@tonic-gate 		 * Give up on anything that's obviously
1014*0Sstevel@tonic-gate 		 * not a primary.
1015*0Sstevel@tonic-gate 		 */
1016*0Sstevel@tonic-gate 		if (EQ("and") || EQ("or") ||
1017*0Sstevel@tonic-gate 		    EQ("not") || EQ("decnet") || EQ("apple") ||
1018*0Sstevel@tonic-gate 		    EQ("length") || EQ("less") || EQ("greater") ||
1019*0Sstevel@tonic-gate 		    EQ("port") || EQ("srcport") || EQ("dstport") ||
1020*0Sstevel@tonic-gate 		    EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1021*0Sstevel@tonic-gate 		    EQ("bootp") || EQ("dhcp") || EQ("slp") || EQ("ldap")) {
1022*0Sstevel@tonic-gate 			break;
1023*0Sstevel@tonic-gate 		}
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 		if (EQ("host") || EQ("between") ||
1026*0Sstevel@tonic-gate 		    tokentype == ALPHA || /* assume its a hostname */
1027*0Sstevel@tonic-gate 		    tokentype == ADDR_IP ||
1028*0Sstevel@tonic-gate 		    tokentype == ADDR_IP6 ||
1029*0Sstevel@tonic-gate 		    tokentype == ADDR_ETHER) {
1030*0Sstevel@tonic-gate 			if (EQ("host") || EQ("between"))
1031*0Sstevel@tonic-gate 				next();
1032*0Sstevel@tonic-gate 			if (eaddr || tokentype == ADDR_ETHER) {
1033*0Sstevel@tonic-gate 				pf_etheraddr_match(dir, token);
1034*0Sstevel@tonic-gate 			} else if (tokentype == ALPHA) {
1035*0Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
1036*0Sstevel@tonic-gate 			} else if (tokentype == ADDR_IP) {
1037*0Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV4_ONLY);
1038*0Sstevel@tonic-gate 			} else {
1039*0Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV6_ONLY);
1040*0Sstevel@tonic-gate 			}
1041*0Sstevel@tonic-gate 			dir = ANY;
1042*0Sstevel@tonic-gate 			eaddr = 0;
1043*0Sstevel@tonic-gate 			opstack++;
1044*0Sstevel@tonic-gate 			next();
1045*0Sstevel@tonic-gate 			break;
1046*0Sstevel@tonic-gate 		}
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate 		break;	/* unknown token */
1049*0Sstevel@tonic-gate 	}
1050*0Sstevel@tonic-gate }
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate static void
1053*0Sstevel@tonic-gate pf_alternation()
1054*0Sstevel@tonic-gate {
1055*0Sstevel@tonic-gate 	int s = opstack;
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	pf_primary();
1058*0Sstevel@tonic-gate 	for (;;) {
1059*0Sstevel@tonic-gate 		if (EQ("and"))
1060*0Sstevel@tonic-gate 			next();
1061*0Sstevel@tonic-gate 		pf_primary();
1062*0Sstevel@tonic-gate 		if (opstack != s + 2)
1063*0Sstevel@tonic-gate 			break;
1064*0Sstevel@tonic-gate 		pf_emit(ENF_AND);
1065*0Sstevel@tonic-gate 		opstack--;
1066*0Sstevel@tonic-gate 	}
1067*0Sstevel@tonic-gate }
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate static void
1070*0Sstevel@tonic-gate pf_expression()
1071*0Sstevel@tonic-gate {
1072*0Sstevel@tonic-gate 	pf_alternation();
1073*0Sstevel@tonic-gate 	while (EQ("or") || EQ(",")) {
1074*0Sstevel@tonic-gate 		if (inBrace)
1075*0Sstevel@tonic-gate 			inBraceOR++;
1076*0Sstevel@tonic-gate 		else
1077*0Sstevel@tonic-gate 			foundOR++;
1078*0Sstevel@tonic-gate 		next();
1079*0Sstevel@tonic-gate 		pf_alternation();
1080*0Sstevel@tonic-gate 		pf_emit(ENF_OR);
1081*0Sstevel@tonic-gate 		opstack--;
1082*0Sstevel@tonic-gate 	}
1083*0Sstevel@tonic-gate }
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate /*
1086*0Sstevel@tonic-gate  * Attempt to compile the expression
1087*0Sstevel@tonic-gate  * in the string "e".  If we can generate
1088*0Sstevel@tonic-gate  * pf code for it then return 1 - otherwise
1089*0Sstevel@tonic-gate  * return 0 and leave it up to the user-level
1090*0Sstevel@tonic-gate  * filter.
1091*0Sstevel@tonic-gate  */
1092*0Sstevel@tonic-gate int
1093*0Sstevel@tonic-gate pf_compile(e, print)
1094*0Sstevel@tonic-gate 	char *e;
1095*0Sstevel@tonic-gate 	int print;
1096*0Sstevel@tonic-gate {
1097*0Sstevel@tonic-gate 	char *argstr;
1098*0Sstevel@tonic-gate 	char *sav_str, *ptr, *sav_ptr;
1099*0Sstevel@tonic-gate 	int inBr = 0, aheadOR = 0;
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	argstr = strdup(e);
1102*0Sstevel@tonic-gate 	sav_str = e;
1103*0Sstevel@tonic-gate 	tkp = argstr;
1104*0Sstevel@tonic-gate 	dir = ANY;
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate 	pfp = &pf.Pf_Filter[0];
1107*0Sstevel@tonic-gate 	if (setjmp(env)) {
1108*0Sstevel@tonic-gate 		return (0);
1109*0Sstevel@tonic-gate 	}
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 	/*
1112*0Sstevel@tonic-gate 	 * Set media specific packet offsets that this code uses.
1113*0Sstevel@tonic-gate 	 */
1114*0Sstevel@tonic-gate 	if (interface->mac_type == DL_IB) {
1115*0Sstevel@tonic-gate 		link_header_len = 4;
1116*0Sstevel@tonic-gate 		link_type_offset = 0;
1117*0Sstevel@tonic-gate 		link_dest_offset = link_src_offset = -1;
1118*0Sstevel@tonic-gate 		link_addr_len = 20;
1119*0Sstevel@tonic-gate 	}
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	next();
1122*0Sstevel@tonic-gate 	pf_expression();
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 	if (tokentype != EOL) {
1125*0Sstevel@tonic-gate 		/*
1126*0Sstevel@tonic-gate 		 * The idea here is to do as much filtering as possible in
1127*0Sstevel@tonic-gate 		 * the kernel. So even if we find a token we don't understand,
1128*0Sstevel@tonic-gate 		 * we try to see if we can still set up a portion of the filter
1129*0Sstevel@tonic-gate 		 * in the kernel and use the userland filter to filter the
1130*0Sstevel@tonic-gate 		 * remaining stuff. Obviously, if our filter expression is of
1131*0Sstevel@tonic-gate 		 * type A AND B, we can filter A in kernel and then apply B
1132*0Sstevel@tonic-gate 		 * to the packets that got through. The same is not true for
1133*0Sstevel@tonic-gate 		 * a filter of type A OR B. We can't apply A first and then B
1134*0Sstevel@tonic-gate 		 * on the packets filtered through A.
1135*0Sstevel@tonic-gate 		 *
1136*0Sstevel@tonic-gate 		 * (We need to keep track of the fact when we find an OR,
1137*0Sstevel@tonic-gate 		 * and the fact that we are inside brackets when we find OR.
1138*0Sstevel@tonic-gate 		 * The variable 'foundOR' tells us if there was an OR behind,
1139*0Sstevel@tonic-gate 		 * 'inBraceOR' tells us if we found an OR before we could find
1140*0Sstevel@tonic-gate 		 * the end brace i.e. ')', and variable 'aheadOR' checks if
1141*0Sstevel@tonic-gate 		 * there is an OR in the expression ahead. if either of these
1142*0Sstevel@tonic-gate 		 * cases become true, we can't split the filtering)
1143*0Sstevel@tonic-gate 		 */
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 		if (foundOR || inBraceOR) {
1146*0Sstevel@tonic-gate 			/* FORGET IN KERNEL FILTERING */
1147*0Sstevel@tonic-gate 			return (0);
1148*0Sstevel@tonic-gate 		} else {
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 			/* CHECK IF NO OR AHEAD */
1151*0Sstevel@tonic-gate 			sav_ptr = (char *)((uintptr_t)sav_str +
1152*0Sstevel@tonic-gate 						(uintptr_t)sav_tkp -
1153*0Sstevel@tonic-gate 						(uintptr_t)argstr);
1154*0Sstevel@tonic-gate 			ptr = sav_ptr;
1155*0Sstevel@tonic-gate 			while (*ptr != '\0') {
1156*0Sstevel@tonic-gate 				switch (*ptr) {
1157*0Sstevel@tonic-gate 				case '(':
1158*0Sstevel@tonic-gate 					inBr++;
1159*0Sstevel@tonic-gate 					break;
1160*0Sstevel@tonic-gate 				case ')':
1161*0Sstevel@tonic-gate 					inBr--;
1162*0Sstevel@tonic-gate 					break;
1163*0Sstevel@tonic-gate 				case 'o':
1164*0Sstevel@tonic-gate 				case 'O':
1165*0Sstevel@tonic-gate 					if ((*(ptr + 1) == 'R' ||
1166*0Sstevel@tonic-gate 						*(ptr + 1) == 'r') && !inBr)
1167*0Sstevel@tonic-gate 						aheadOR = 1;
1168*0Sstevel@tonic-gate 					break;
1169*0Sstevel@tonic-gate 				case ',':
1170*0Sstevel@tonic-gate 					if (!inBr)
1171*0Sstevel@tonic-gate 						aheadOR = 1;
1172*0Sstevel@tonic-gate 					break;
1173*0Sstevel@tonic-gate 				}
1174*0Sstevel@tonic-gate 				ptr++;
1175*0Sstevel@tonic-gate 			}
1176*0Sstevel@tonic-gate 			if (!aheadOR) {
1177*0Sstevel@tonic-gate 				/* NO OR AHEAD, SPLIT UP THE FILTERING */
1178*0Sstevel@tonic-gate 				pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1179*0Sstevel@tonic-gate 				pf.Pf_Priority = 5;
1180*0Sstevel@tonic-gate 				if (print) {
1181*0Sstevel@tonic-gate 					pf_codeprint(&pf.Pf_Filter[0],
1182*0Sstevel@tonic-gate 							pf.Pf_FilterLen);
1183*0Sstevel@tonic-gate 				}
1184*0Sstevel@tonic-gate 				compile(sav_ptr, print);
1185*0Sstevel@tonic-gate 				return (2);
1186*0Sstevel@tonic-gate 			} else
1187*0Sstevel@tonic-gate 				return (0);
1188*0Sstevel@tonic-gate 		}
1189*0Sstevel@tonic-gate 	}
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1192*0Sstevel@tonic-gate 	pf.Pf_Priority = 5;	/* unimportant, so long as > 2 */
1193*0Sstevel@tonic-gate 	if (print) {
1194*0Sstevel@tonic-gate 		pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
1195*0Sstevel@tonic-gate 	}
1196*0Sstevel@tonic-gate 	return (1);
1197*0Sstevel@tonic-gate }
1198