1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1991-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <ctype.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
37*7c478bd9Sstevel@tonic-gate #include <stddef.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
41*7c478bd9Sstevel@tonic-gate #include <net/if.h>
42*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
44*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
45*7c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
46*7c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
47*7c478bd9Sstevel@tonic-gate #include <inet/ip.h>
48*7c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
49*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
50*7c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
51*7c478bd9Sstevel@tonic-gate #include <netdb.h>
52*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
53*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
54*7c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
57*7c478bd9Sstevel@tonic-gate #include <snoop.h>
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #define	IPV4_ONLY	0
60*7c478bd9Sstevel@tonic-gate #define	IPV6_ONLY	1
61*7c478bd9Sstevel@tonic-gate #define	IPV4_AND_IPV6	2
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /*
64*7c478bd9Sstevel@tonic-gate  * The following constants represent the offsets in bytes from the beginning
65*7c478bd9Sstevel@tonic-gate  * of the IP(v6) header of the source and destination IP(v6) addresses.
66*7c478bd9Sstevel@tonic-gate  * These are useful when generating filter code.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate #define	IPV4_SRCADDR_OFFSET	12
69*7c478bd9Sstevel@tonic-gate #define	IPV4_DSTADDR_OFFSET	16
70*7c478bd9Sstevel@tonic-gate #define	IPV6_SRCADDR_OFFSET	8
71*7c478bd9Sstevel@tonic-gate #define	IPV6_DSTADDR_OFFSET	24
72*7c478bd9Sstevel@tonic-gate #define	IP_VERS(p)	(((*(uchar_t *)p) & 0xf0) >> 4)
73*7c478bd9Sstevel@tonic-gate #define	MASKED_IPV4_VERS	0x40
74*7c478bd9Sstevel@tonic-gate #define	MASKED_IPV6_VERS	0x60
75*7c478bd9Sstevel@tonic-gate #define	IP_HDR_LEN(p)	(((*(uchar_t *)p) & 0xf) * 4)
76*7c478bd9Sstevel@tonic-gate #define	TCP_HDR_LEN(p)	((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4)
77*7c478bd9Sstevel@tonic-gate /*
78*7c478bd9Sstevel@tonic-gate  * Coding the constant below is tacky, but the compiler won't let us
79*7c478bd9Sstevel@tonic-gate  * be more clever.  E.g., &((struct ip *)0)->ip_xxx
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate #define	IP_PROTO_OF(p)	(((uchar_t *)p)[9])
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * AppleTalk uses 802.2 Ethernet encapsulation with LLC/SNAP headers,
85*7c478bd9Sstevel@tonic-gate  * for 8 octets of overhead, and the common AppleTalk DDP Ethernet
86*7c478bd9Sstevel@tonic-gate  * header is another 4 octets.
87*7c478bd9Sstevel@tonic-gate  *
88*7c478bd9Sstevel@tonic-gate  * The following constants represents the offsets in bytes from the beginning
89*7c478bd9Sstevel@tonic-gate  * of the Ethernet payload to various parts of the DDP header.
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #define	AT_DST_NET_OFFSET	12
93*7c478bd9Sstevel@tonic-gate #define	AT_SRC_NET_OFFSET	14
94*7c478bd9Sstevel@tonic-gate #define	AT_DST_NODE_OFFSET	16
95*7c478bd9Sstevel@tonic-gate #define	AT_SRC_NODE_OFFSET	17
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate int eaddr;	/* need ethernet addr */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate int opstack;	/* operand stack depth */
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * These are the operators of the user-level filter.
103*7c478bd9Sstevel@tonic-gate  * STOP ends execution of the filter expression and
104*7c478bd9Sstevel@tonic-gate  * returns the truth value at the top of the stack.
105*7c478bd9Sstevel@tonic-gate  * OP_LOAD_OCTET, OP_LOAD_SHORT and OP_LOAD_LONG pop
106*7c478bd9Sstevel@tonic-gate  * an offset value from the stack and load a value of
107*7c478bd9Sstevel@tonic-gate  * an appropriate size from the packet (octet, short or
108*7c478bd9Sstevel@tonic-gate  * long).  The offset is computed from a base value that
109*7c478bd9Sstevel@tonic-gate  * may be set via the OP_OFFSET operators.
110*7c478bd9Sstevel@tonic-gate  * OP_EQ, OP_NE, OP_GT, OP_GE, OP_LT, OP_LE pop two values
111*7c478bd9Sstevel@tonic-gate  * from the stack and return the result of their comparison.
112*7c478bd9Sstevel@tonic-gate  * OP_AND, OP_OR, OP_XOR pop two values from the stack and
113*7c478bd9Sstevel@tonic-gate  * do perform a bitwise operation on them - returning a result
114*7c478bd9Sstevel@tonic-gate  * to the stack.  OP_NOT inverts the bits of the value on the
115*7c478bd9Sstevel@tonic-gate  * stack.
116*7c478bd9Sstevel@tonic-gate  * OP_BRFL and OP_BRTR branch to an offset in the code array
117*7c478bd9Sstevel@tonic-gate  * depending on the value at the top of the stack: true (not 0)
118*7c478bd9Sstevel@tonic-gate  * or false (0).
119*7c478bd9Sstevel@tonic-gate  * OP_ADD, OP_SUB, OP_MUL, OP_DIV and OP_REM pop two values
120*7c478bd9Sstevel@tonic-gate  * from the stack and perform arithmetic.
121*7c478bd9Sstevel@tonic-gate  * The OP_OFFSET operators change the base from which the
122*7c478bd9Sstevel@tonic-gate  * OP_LOAD operators compute their offsets.
123*7c478bd9Sstevel@tonic-gate  * OP_OFFSET_ZERO sets the offset to zero - beginning of packet.
124*7c478bd9Sstevel@tonic-gate  * OP_OFFSET_LINK sets the base to the first octet after
125*7c478bd9Sstevel@tonic-gate  * the link (DLC) header.  OP_OFFSET_IP, OP_OFFSET_TCP,
126*7c478bd9Sstevel@tonic-gate  * and OP_OFFSET_UDP do the same for those headers - they
127*7c478bd9Sstevel@tonic-gate  * set the offset base to the *end* of the header - not the
128*7c478bd9Sstevel@tonic-gate  * beginning.  The OP_OFFSET_RPC operator is a bit unusual.
129*7c478bd9Sstevel@tonic-gate  * It points the base at the cached RPC header.  For the
130*7c478bd9Sstevel@tonic-gate  * purposes of selection, RPC reply headers look like call
131*7c478bd9Sstevel@tonic-gate  * headers except for the direction value.
132*7c478bd9Sstevel@tonic-gate  * OP_OFFSET_POP restores the offset base to the value prior
133*7c478bd9Sstevel@tonic-gate  * to the most recent OP_OFFSET call.
134*7c478bd9Sstevel@tonic-gate  */
135*7c478bd9Sstevel@tonic-gate enum optype {
136*7c478bd9Sstevel@tonic-gate 	OP_STOP = 0,
137*7c478bd9Sstevel@tonic-gate 	OP_LOAD_OCTET,
138*7c478bd9Sstevel@tonic-gate 	OP_LOAD_SHORT,
139*7c478bd9Sstevel@tonic-gate 	OP_LOAD_LONG,
140*7c478bd9Sstevel@tonic-gate 	OP_LOAD_CONST,
141*7c478bd9Sstevel@tonic-gate 	OP_LOAD_LENGTH,
142*7c478bd9Sstevel@tonic-gate 	OP_EQ,
143*7c478bd9Sstevel@tonic-gate 	OP_NE,
144*7c478bd9Sstevel@tonic-gate 	OP_GT,
145*7c478bd9Sstevel@tonic-gate 	OP_GE,
146*7c478bd9Sstevel@tonic-gate 	OP_LT,
147*7c478bd9Sstevel@tonic-gate 	OP_LE,
148*7c478bd9Sstevel@tonic-gate 	OP_AND,
149*7c478bd9Sstevel@tonic-gate 	OP_OR,
150*7c478bd9Sstevel@tonic-gate 	OP_XOR,
151*7c478bd9Sstevel@tonic-gate 	OP_NOT,
152*7c478bd9Sstevel@tonic-gate 	OP_BRFL,
153*7c478bd9Sstevel@tonic-gate 	OP_BRTR,
154*7c478bd9Sstevel@tonic-gate 	OP_ADD,
155*7c478bd9Sstevel@tonic-gate 	OP_SUB,
156*7c478bd9Sstevel@tonic-gate 	OP_MUL,
157*7c478bd9Sstevel@tonic-gate 	OP_DIV,
158*7c478bd9Sstevel@tonic-gate 	OP_REM,
159*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_POP,
160*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_ZERO,
161*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_LINK,
162*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_IP,
163*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_TCP,
164*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_UDP,
165*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_RPC,
166*7c478bd9Sstevel@tonic-gate 	OP_OFFSET_SLP,
167*7c478bd9Sstevel@tonic-gate 	OP_LAST
168*7c478bd9Sstevel@tonic-gate };
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate static char *opnames[] = {
171*7c478bd9Sstevel@tonic-gate 	"STOP",
172*7c478bd9Sstevel@tonic-gate 	"LOAD_OCTET",
173*7c478bd9Sstevel@tonic-gate 	"LOAD_SHORT",
174*7c478bd9Sstevel@tonic-gate 	"LOAD_LONG",
175*7c478bd9Sstevel@tonic-gate 	"LOAD_CONST",
176*7c478bd9Sstevel@tonic-gate 	"LOAD_LENGTH",
177*7c478bd9Sstevel@tonic-gate 	"EQ",
178*7c478bd9Sstevel@tonic-gate 	"NE",
179*7c478bd9Sstevel@tonic-gate 	"GT",
180*7c478bd9Sstevel@tonic-gate 	"GE",
181*7c478bd9Sstevel@tonic-gate 	"LT",
182*7c478bd9Sstevel@tonic-gate 	"LE",
183*7c478bd9Sstevel@tonic-gate 	"AND",
184*7c478bd9Sstevel@tonic-gate 	"OR",
185*7c478bd9Sstevel@tonic-gate 	"XOR",
186*7c478bd9Sstevel@tonic-gate 	"NOT",
187*7c478bd9Sstevel@tonic-gate 	"BRFL",
188*7c478bd9Sstevel@tonic-gate 	"BRTR",
189*7c478bd9Sstevel@tonic-gate 	"ADD",
190*7c478bd9Sstevel@tonic-gate 	"SUB",
191*7c478bd9Sstevel@tonic-gate 	"MUL",
192*7c478bd9Sstevel@tonic-gate 	"DIV",
193*7c478bd9Sstevel@tonic-gate 	"REM",
194*7c478bd9Sstevel@tonic-gate 	"OFFSET_POP",
195*7c478bd9Sstevel@tonic-gate 	"OFFSET_ZERO",
196*7c478bd9Sstevel@tonic-gate 	"OFFSET_ETHER",
197*7c478bd9Sstevel@tonic-gate 	"OFFSET_IP",
198*7c478bd9Sstevel@tonic-gate 	"OFFSET_TCP",
199*7c478bd9Sstevel@tonic-gate 	"OFFSET_UDP",
200*7c478bd9Sstevel@tonic-gate 	"OFFSET_RPC",
201*7c478bd9Sstevel@tonic-gate 	"OP_OFFSET_SLP",
202*7c478bd9Sstevel@tonic-gate 	""
203*7c478bd9Sstevel@tonic-gate };
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate #define	MAXOPS 1024
206*7c478bd9Sstevel@tonic-gate #define	MAXSS	64
207*7c478bd9Sstevel@tonic-gate static uint_t oplist[MAXOPS];	/* array of operators */
208*7c478bd9Sstevel@tonic-gate static uint_t *curr_op;		/* last op generated */
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate extern int valid_slp(uchar_t *, int);	/* decides if a SLP msg is valid */
211*7c478bd9Sstevel@tonic-gate extern struct hostent *lgetipnodebyname(const char *, int, int, int *);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static void alternation();
214*7c478bd9Sstevel@tonic-gate static uint_t chain();
215*7c478bd9Sstevel@tonic-gate static void codeprint();
216*7c478bd9Sstevel@tonic-gate static void emitop();
217*7c478bd9Sstevel@tonic-gate static void emitval();
218*7c478bd9Sstevel@tonic-gate static void expression();
219*7c478bd9Sstevel@tonic-gate static struct xid_entry *find_rpc();
220*7c478bd9Sstevel@tonic-gate static void optimize();
221*7c478bd9Sstevel@tonic-gate static void ethertype_match();
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate /*
225*7c478bd9Sstevel@tonic-gate  * Returns the ULP for an IPv4 or IPv6 packet
226*7c478bd9Sstevel@tonic-gate  * Assumes that the packet has already been checked to verify
227*7c478bd9Sstevel@tonic-gate  * that it's either IPv4 or IPv6
228*7c478bd9Sstevel@tonic-gate  *
229*7c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
230*7c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
231*7c478bd9Sstevel@tonic-gate  */
232*7c478bd9Sstevel@tonic-gate static uchar_t
233*7c478bd9Sstevel@tonic-gate ip_proto_of(uchar_t *ip)
234*7c478bd9Sstevel@tonic-gate {
235*7c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
236*7c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
237*7c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
240*7c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
241*7c478bd9Sstevel@tonic-gate 		return (IP_PROTO_OF(ip));
242*7c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 		nxt = ip[6];
245*7c478bd9Sstevel@tonic-gate 		ptr += 40;		/* size of ip6 header */
246*7c478bd9Sstevel@tonic-gate 		do {
247*7c478bd9Sstevel@tonic-gate 			switch (nxt) {
248*7c478bd9Sstevel@tonic-gate 			/*
249*7c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
250*7c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
251*7c478bd9Sstevel@tonic-gate 			 */
252*7c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
253*7c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
254*7c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
255*7c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
256*7c478bd9Sstevel@tonic-gate 				ptr += (8 * (ptr[1] + 1));
257*7c478bd9Sstevel@tonic-gate 				nxt = *ptr;
258*7c478bd9Sstevel@tonic-gate 				break;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 			default:
261*7c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
262*7c478bd9Sstevel@tonic-gate 				break;
263*7c478bd9Sstevel@tonic-gate 			}
264*7c478bd9Sstevel@tonic-gate 		} while (not_done);
265*7c478bd9Sstevel@tonic-gate 		return (nxt);
266*7c478bd9Sstevel@tonic-gate 	default:
267*7c478bd9Sstevel@tonic-gate 		break;			/* shouldn't get here... */
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 	return (0);
270*7c478bd9Sstevel@tonic-gate }
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate /*
273*7c478bd9Sstevel@tonic-gate  * Returns the total IP header length.
274*7c478bd9Sstevel@tonic-gate  * For v4, this includes any options present.
275*7c478bd9Sstevel@tonic-gate  * For v6, this is the length of the IPv6 header plus
276*7c478bd9Sstevel@tonic-gate  * any extension headers present.
277*7c478bd9Sstevel@tonic-gate  *
278*7c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
279*7c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
280*7c478bd9Sstevel@tonic-gate  */
281*7c478bd9Sstevel@tonic-gate static int
282*7c478bd9Sstevel@tonic-gate ip_hdr_len(uchar_t *ip)
283*7c478bd9Sstevel@tonic-gate {
284*7c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
285*7c478bd9Sstevel@tonic-gate 	int		hdr_len;
286*7c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
287*7c478bd9Sstevel@tonic-gate 	int		len = 40;	/* IPv6 header size */
288*7c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
291*7c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
292*7c478bd9Sstevel@tonic-gate 		return (IP_HDR_LEN(ip));
293*7c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
294*7c478bd9Sstevel@tonic-gate 		nxt = ip[6];
295*7c478bd9Sstevel@tonic-gate 		ptr += len;
296*7c478bd9Sstevel@tonic-gate 		do {
297*7c478bd9Sstevel@tonic-gate 			switch (nxt) {
298*7c478bd9Sstevel@tonic-gate 			/*
299*7c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
300*7c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
301*7c478bd9Sstevel@tonic-gate 			 */
302*7c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
303*7c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
304*7c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
305*7c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
306*7c478bd9Sstevel@tonic-gate 				hdr_len = (8 * (ptr[1] + 1));
307*7c478bd9Sstevel@tonic-gate 				len += hdr_len;
308*7c478bd9Sstevel@tonic-gate 				ptr += hdr_len;
309*7c478bd9Sstevel@tonic-gate 				nxt = *ptr;
310*7c478bd9Sstevel@tonic-gate 				break;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 			default:
313*7c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
314*7c478bd9Sstevel@tonic-gate 				break;
315*7c478bd9Sstevel@tonic-gate 			}
316*7c478bd9Sstevel@tonic-gate 		} while (not_done);
317*7c478bd9Sstevel@tonic-gate 		return (len);
318*7c478bd9Sstevel@tonic-gate 	default:
319*7c478bd9Sstevel@tonic-gate 		break;
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 	return (0);			/* not IP */
322*7c478bd9Sstevel@tonic-gate }
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate static void
325*7c478bd9Sstevel@tonic-gate codeprint()
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	uint_t *op;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	printf("User filter:\n");
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
332*7c478bd9Sstevel@tonic-gate 		if (*op <= OP_LAST)
333*7c478bd9Sstevel@tonic-gate 			printf("\t%2d: %s\n", op - oplist, opnames[*op]);
334*7c478bd9Sstevel@tonic-gate 		else
335*7c478bd9Sstevel@tonic-gate 			printf("\t%2d: (%d)\n", op - oplist, *op);
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 		switch (*op) {
338*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
339*7c478bd9Sstevel@tonic-gate 		case OP_BRTR:
340*7c478bd9Sstevel@tonic-gate 		case OP_BRFL:
341*7c478bd9Sstevel@tonic-gate 			op++;
342*7c478bd9Sstevel@tonic-gate 			if ((int)*op < 0)
343*7c478bd9Sstevel@tonic-gate 				printf("\t%2d:   0x%08x (%d)\n",
344*7c478bd9Sstevel@tonic-gate 					op - oplist, *op, *op);
345*7c478bd9Sstevel@tonic-gate 			else
346*7c478bd9Sstevel@tonic-gate 				printf("\t%2d:   %d (0x%08x)\n",
347*7c478bd9Sstevel@tonic-gate 					op - oplist, *op, *op);
348*7c478bd9Sstevel@tonic-gate 		}
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 	printf("\t%2d: STOP\n", op - oplist);
351*7c478bd9Sstevel@tonic-gate 	printf("\n");
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate /*
356*7c478bd9Sstevel@tonic-gate  * Take a pass through the generated code and optimize
357*7c478bd9Sstevel@tonic-gate  * branches.  A branch true (BRTR) that has another BRTR
358*7c478bd9Sstevel@tonic-gate  * at its destination can use the address of the destination
359*7c478bd9Sstevel@tonic-gate  * BRTR.  A BRTR that points to a BRFL (branch false) should
360*7c478bd9Sstevel@tonic-gate  * point to the address following the BRFL.
361*7c478bd9Sstevel@tonic-gate  * A similar optimization applies to BRFL operators.
362*7c478bd9Sstevel@tonic-gate  */
363*7c478bd9Sstevel@tonic-gate static void
364*7c478bd9Sstevel@tonic-gate optimize(uint_t *oplistp)
365*7c478bd9Sstevel@tonic-gate {
366*7c478bd9Sstevel@tonic-gate 	uint_t *op;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	for (op = oplistp; *op; op++) {
369*7c478bd9Sstevel@tonic-gate 		switch (*op) {
370*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
371*7c478bd9Sstevel@tonic-gate 			op++;
372*7c478bd9Sstevel@tonic-gate 			break;
373*7c478bd9Sstevel@tonic-gate 		case OP_BRTR:
374*7c478bd9Sstevel@tonic-gate 			op++;
375*7c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
376*7c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRFL)
377*7c478bd9Sstevel@tonic-gate 				*op += 2;
378*7c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRTR)
379*7c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
380*7c478bd9Sstevel@tonic-gate 			break;
381*7c478bd9Sstevel@tonic-gate 		case OP_BRFL:
382*7c478bd9Sstevel@tonic-gate 			op++;
383*7c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
384*7c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRTR)
385*7c478bd9Sstevel@tonic-gate 				*op += 2;
386*7c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRFL)
387*7c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
388*7c478bd9Sstevel@tonic-gate 			break;
389*7c478bd9Sstevel@tonic-gate 		}
390*7c478bd9Sstevel@tonic-gate 	}
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*
394*7c478bd9Sstevel@tonic-gate  * RPC packets are tough to filter.
395*7c478bd9Sstevel@tonic-gate  * While the call packet has all the interesting
396*7c478bd9Sstevel@tonic-gate  * info: program number, version, procedure etc,
397*7c478bd9Sstevel@tonic-gate  * the reply packet has none of this information.
398*7c478bd9Sstevel@tonic-gate  * If we want to do useful filtering based on this
399*7c478bd9Sstevel@tonic-gate  * information then we have to stash the information
400*7c478bd9Sstevel@tonic-gate  * from the call packet, and use the XID in the reply
401*7c478bd9Sstevel@tonic-gate  * to find the stashed info.  The stashed info is
402*7c478bd9Sstevel@tonic-gate  * kept in a circular lifo, assuming that a call packet
403*7c478bd9Sstevel@tonic-gate  * will be followed quickly by its reply.
404*7c478bd9Sstevel@tonic-gate  */
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate struct xid_entry {
407*7c478bd9Sstevel@tonic-gate 	unsigned	x_xid;		/* The XID (32 bits) */
408*7c478bd9Sstevel@tonic-gate 	unsigned	x_dir;		/* CALL or REPLY */
409*7c478bd9Sstevel@tonic-gate 	unsigned	x_rpcvers;	/* Protocol version (2) */
410*7c478bd9Sstevel@tonic-gate 	unsigned	x_prog;		/* RPC program number */
411*7c478bd9Sstevel@tonic-gate 	unsigned	x_vers;		/* RPC version number */
412*7c478bd9Sstevel@tonic-gate 	unsigned	x_proc;		/* RPC procedure number */
413*7c478bd9Sstevel@tonic-gate };
414*7c478bd9Sstevel@tonic-gate static struct xid_entry	xe_table[XID_CACHE_SIZE];
415*7c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_first = &xe_table[0];
416*7c478bd9Sstevel@tonic-gate static struct xid_entry	*xe	  = &xe_table[0];
417*7c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_last  = &xe_table[XID_CACHE_SIZE - 1];
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate static struct xid_entry *
420*7c478bd9Sstevel@tonic-gate find_rpc(struct rpc_msg *rpc)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	for (x = xe; x >= xe_first; x--)
425*7c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
426*7c478bd9Sstevel@tonic-gate 			return (x);
427*7c478bd9Sstevel@tonic-gate 	for (x = xe_last; x > xe; x--)
428*7c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
429*7c478bd9Sstevel@tonic-gate 			return (x);
430*7c478bd9Sstevel@tonic-gate 	return (NULL);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate static void
434*7c478bd9Sstevel@tonic-gate stash_rpc(struct rpc_msg *rpc)
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	if (find_rpc(rpc))
439*7c478bd9Sstevel@tonic-gate 		return;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	x = xe++;
442*7c478bd9Sstevel@tonic-gate 	if (xe > xe_last)
443*7c478bd9Sstevel@tonic-gate 		xe = xe_first;
444*7c478bd9Sstevel@tonic-gate 	x->x_xid  = rpc->rm_xid;
445*7c478bd9Sstevel@tonic-gate 	x->x_dir  = htonl(REPLY);
446*7c478bd9Sstevel@tonic-gate 	x->x_prog = rpc->rm_call.cb_prog;
447*7c478bd9Sstevel@tonic-gate 	x->x_vers = rpc->rm_call.cb_vers;
448*7c478bd9Sstevel@tonic-gate 	x->x_proc = rpc->rm_call.cb_proc;
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate  * SLP can multicast requests, and recieve unicast replies in which
453*7c478bd9Sstevel@tonic-gate  * neither the source nor destination port is identifiable as a SLP
454*7c478bd9Sstevel@tonic-gate  * port. Hence, we need to do as RPC does, and keep track of packets we
455*7c478bd9Sstevel@tonic-gate  * are interested in. For SLP, however, we use ports, not XIDs, and
456*7c478bd9Sstevel@tonic-gate  * a smaller cache size is more efficient since every incoming packet
457*7c478bd9Sstevel@tonic-gate  * needs to be checked.
458*7c478bd9Sstevel@tonic-gate  */
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate #define	SLP_CACHE_SIZE 64
461*7c478bd9Sstevel@tonic-gate static uint_t slp_table[SLP_CACHE_SIZE];
462*7c478bd9Sstevel@tonic-gate static int slp_index	= 0;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate /*
465*7c478bd9Sstevel@tonic-gate  * Returns the index of dport in the table if found, otherwise -1.
466*7c478bd9Sstevel@tonic-gate  */
467*7c478bd9Sstevel@tonic-gate static int
468*7c478bd9Sstevel@tonic-gate find_slp(uint_t dport) {
469*7c478bd9Sstevel@tonic-gate     int i;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate     if (!dport)
472*7c478bd9Sstevel@tonic-gate 	return (0);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate     for (i = slp_index; i >= 0; i--)
475*7c478bd9Sstevel@tonic-gate 	if (slp_table[i] == dport) {
476*7c478bd9Sstevel@tonic-gate 	    return (i);
477*7c478bd9Sstevel@tonic-gate 	}
478*7c478bd9Sstevel@tonic-gate     for (i = SLP_CACHE_SIZE - 1; i > slp_index; i--)
479*7c478bd9Sstevel@tonic-gate 	if (slp_table[i] == dport) {
480*7c478bd9Sstevel@tonic-gate 	    return (i);
481*7c478bd9Sstevel@tonic-gate 	}
482*7c478bd9Sstevel@tonic-gate     return (-1);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate static void stash_slp(uint_t sport) {
486*7c478bd9Sstevel@tonic-gate     if (slp_table[slp_index - 1] == sport)
487*7c478bd9Sstevel@tonic-gate 	/* avoid redundancy due to multicast retransmissions */
488*7c478bd9Sstevel@tonic-gate 	return;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate     slp_table[slp_index++] = sport;
491*7c478bd9Sstevel@tonic-gate     if (slp_index == SLP_CACHE_SIZE)
492*7c478bd9Sstevel@tonic-gate 	slp_index = 0;
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate /*
496*7c478bd9Sstevel@tonic-gate  * This routine takes a packet and returns true or false
497*7c478bd9Sstevel@tonic-gate  * according to whether the filter expression selects it
498*7c478bd9Sstevel@tonic-gate  * or not.
499*7c478bd9Sstevel@tonic-gate  * We assume here that offsets for short and long values
500*7c478bd9Sstevel@tonic-gate  * are even - we may die with an alignment error if the
501*7c478bd9Sstevel@tonic-gate  * CPU doesn't support odd addresses.  Note that long
502*7c478bd9Sstevel@tonic-gate  * values are loaded as two shorts so that 32 bit word
503*7c478bd9Sstevel@tonic-gate  * alignment isn't important.
504*7c478bd9Sstevel@tonic-gate  *
505*7c478bd9Sstevel@tonic-gate  * IPv6 is a bit stickier to handle than IPv4...
506*7c478bd9Sstevel@tonic-gate  */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate int
509*7c478bd9Sstevel@tonic-gate want_packet(uchar_t *pkt, int len, int origlen)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	uint_t stack[MAXSS];	/* operand stack */
512*7c478bd9Sstevel@tonic-gate 	uint_t *op;		/* current operator */
513*7c478bd9Sstevel@tonic-gate 	uint_t *sp;		/* top of operand stack */
514*7c478bd9Sstevel@tonic-gate 	uchar_t *base;		/* base for offsets into packet */
515*7c478bd9Sstevel@tonic-gate 	uchar_t *ip;		/* addr of IP header, unaligned */
516*7c478bd9Sstevel@tonic-gate 	uchar_t *tcp;		/* addr of TCP header, unaligned */
517*7c478bd9Sstevel@tonic-gate 	uchar_t *udp;		/* addr of UDP header, unaligned */
518*7c478bd9Sstevel@tonic-gate 	struct rpc_msg rpcmsg;	/* addr of RPC header */
519*7c478bd9Sstevel@tonic-gate 	struct rpc_msg *rpc;
520*7c478bd9Sstevel@tonic-gate 	int newrpc = 0;
521*7c478bd9Sstevel@tonic-gate 	uchar_t *slphdr;		/* beginning of SLP header */
522*7c478bd9Sstevel@tonic-gate 	uint_t slp_sport, slp_dport;
523*7c478bd9Sstevel@tonic-gate 	int off, header_size;
524*7c478bd9Sstevel@tonic-gate 	uchar_t *offstack[MAXSS];	/* offset stack */
525*7c478bd9Sstevel@tonic-gate 	uchar_t **offp;		/* current offset */
526*7c478bd9Sstevel@tonic-gate 	uchar_t *opkt = NULL;
527*7c478bd9Sstevel@tonic-gate 	uint_t olen;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	sp = stack;
530*7c478bd9Sstevel@tonic-gate 	*sp = 1;
531*7c478bd9Sstevel@tonic-gate 	base = pkt;
532*7c478bd9Sstevel@tonic-gate 	offp = offstack;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	header_size = (*interface->header_len)((char *)pkt);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
537*7c478bd9Sstevel@tonic-gate 		switch ((enum optype) *op) {
538*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_OCTET:
539*7c478bd9Sstevel@tonic-gate 			if ((base + *sp) > (pkt + len))
540*7c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 			*sp = *((uchar_t *)(base + *sp));
543*7c478bd9Sstevel@tonic-gate 			break;
544*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_SHORT:
545*7c478bd9Sstevel@tonic-gate 			off = *sp;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint16_t) - 1) > (pkt + len))
548*7c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 			/*
551*7c478bd9Sstevel@tonic-gate 			 * Handle 2 possible alignments
552*7c478bd9Sstevel@tonic-gate 			 */
553*7c478bd9Sstevel@tonic-gate 			switch ((((unsigned)base)+off) % sizeof (ushort_t)) {
554*7c478bd9Sstevel@tonic-gate 			case 0:
555*7c478bd9Sstevel@tonic-gate 				*sp = ntohs(*((ushort_t *)(base + *sp)));
556*7c478bd9Sstevel@tonic-gate 				break;
557*7c478bd9Sstevel@tonic-gate 			case 1:
558*7c478bd9Sstevel@tonic-gate 				*((uchar_t *)(sp)) =
559*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off));
560*7c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 1) =
561*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 1);
562*7c478bd9Sstevel@tonic-gate 				*sp = ntohs(*(ushort_t *)sp);
563*7c478bd9Sstevel@tonic-gate 				break;
564*7c478bd9Sstevel@tonic-gate 			}
565*7c478bd9Sstevel@tonic-gate 			break;
566*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_LONG:
567*7c478bd9Sstevel@tonic-gate 			off = *sp;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint32_t) - 1) > (pkt + len))
570*7c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 			/*
573*7c478bd9Sstevel@tonic-gate 			 * Handle 3 possible alignments
574*7c478bd9Sstevel@tonic-gate 			 */
575*7c478bd9Sstevel@tonic-gate 			switch ((((unsigned)base) + off) % sizeof (uint_t)) {
576*7c478bd9Sstevel@tonic-gate 			case 0:
577*7c478bd9Sstevel@tonic-gate 				*sp = *(uint_t *)(base + off);
578*7c478bd9Sstevel@tonic-gate 				break;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 			case 2:
581*7c478bd9Sstevel@tonic-gate 				*((ushort_t *)(sp)) =
582*7c478bd9Sstevel@tonic-gate 					*((ushort_t *)(base + off));
583*7c478bd9Sstevel@tonic-gate 				*(((ushort_t *)sp) + 1) =
584*7c478bd9Sstevel@tonic-gate 					*((ushort_t *)(base + off) + 1);
585*7c478bd9Sstevel@tonic-gate 				break;
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 			case 1:
588*7c478bd9Sstevel@tonic-gate 			case 3:
589*7c478bd9Sstevel@tonic-gate 				*((uchar_t *)(sp)) =
590*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off));
591*7c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 1) =
592*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 1);
593*7c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 2) =
594*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 2);
595*7c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 3) =
596*7c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 3);
597*7c478bd9Sstevel@tonic-gate 				break;
598*7c478bd9Sstevel@tonic-gate 			}
599*7c478bd9Sstevel@tonic-gate 			*sp = ntohl(*sp);
600*7c478bd9Sstevel@tonic-gate 			break;
601*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
602*7c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
603*7c478bd9Sstevel@tonic-gate 				return (0);
604*7c478bd9Sstevel@tonic-gate 			*(++sp) = *(++op);
605*7c478bd9Sstevel@tonic-gate 			break;
606*7c478bd9Sstevel@tonic-gate 		case OP_LOAD_LENGTH:
607*7c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
608*7c478bd9Sstevel@tonic-gate 				return (0);
609*7c478bd9Sstevel@tonic-gate 			*(++sp) = origlen;
610*7c478bd9Sstevel@tonic-gate 			break;
611*7c478bd9Sstevel@tonic-gate 		case OP_EQ:
612*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
613*7c478bd9Sstevel@tonic-gate 				return (0);
614*7c478bd9Sstevel@tonic-gate 			sp--;
615*7c478bd9Sstevel@tonic-gate 			*sp = *sp == *(sp + 1);
616*7c478bd9Sstevel@tonic-gate 			break;
617*7c478bd9Sstevel@tonic-gate 		case OP_NE:
618*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
619*7c478bd9Sstevel@tonic-gate 				return (0);
620*7c478bd9Sstevel@tonic-gate 			sp--;
621*7c478bd9Sstevel@tonic-gate 			*sp = *sp != *(sp + 1);
622*7c478bd9Sstevel@tonic-gate 			break;
623*7c478bd9Sstevel@tonic-gate 		case OP_GT:
624*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
625*7c478bd9Sstevel@tonic-gate 				return (0);
626*7c478bd9Sstevel@tonic-gate 			sp--;
627*7c478bd9Sstevel@tonic-gate 			*sp = *sp > *(sp + 1);
628*7c478bd9Sstevel@tonic-gate 			break;
629*7c478bd9Sstevel@tonic-gate 		case OP_GE:
630*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
631*7c478bd9Sstevel@tonic-gate 				return (0);
632*7c478bd9Sstevel@tonic-gate 			sp--;
633*7c478bd9Sstevel@tonic-gate 			*sp = *sp >= *(sp + 1);
634*7c478bd9Sstevel@tonic-gate 			break;
635*7c478bd9Sstevel@tonic-gate 		case OP_LT:
636*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
637*7c478bd9Sstevel@tonic-gate 				return (0);
638*7c478bd9Sstevel@tonic-gate 			sp--;
639*7c478bd9Sstevel@tonic-gate 			*sp = *sp < *(sp + 1);
640*7c478bd9Sstevel@tonic-gate 			break;
641*7c478bd9Sstevel@tonic-gate 		case OP_LE:
642*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
643*7c478bd9Sstevel@tonic-gate 				return (0);
644*7c478bd9Sstevel@tonic-gate 			sp--;
645*7c478bd9Sstevel@tonic-gate 			*sp = *sp <= *(sp + 1);
646*7c478bd9Sstevel@tonic-gate 			break;
647*7c478bd9Sstevel@tonic-gate 		case OP_AND:
648*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
649*7c478bd9Sstevel@tonic-gate 				return (0);
650*7c478bd9Sstevel@tonic-gate 			sp--;
651*7c478bd9Sstevel@tonic-gate 			*sp &= *(sp + 1);
652*7c478bd9Sstevel@tonic-gate 			break;
653*7c478bd9Sstevel@tonic-gate 		case OP_OR:
654*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
655*7c478bd9Sstevel@tonic-gate 				return (0);
656*7c478bd9Sstevel@tonic-gate 			sp--;
657*7c478bd9Sstevel@tonic-gate 			*sp |= *(sp + 1);
658*7c478bd9Sstevel@tonic-gate 			break;
659*7c478bd9Sstevel@tonic-gate 		case OP_XOR:
660*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
661*7c478bd9Sstevel@tonic-gate 				return (0);
662*7c478bd9Sstevel@tonic-gate 			sp--;
663*7c478bd9Sstevel@tonic-gate 			*sp ^= *(sp + 1);
664*7c478bd9Sstevel@tonic-gate 			break;
665*7c478bd9Sstevel@tonic-gate 		case OP_NOT:
666*7c478bd9Sstevel@tonic-gate 			*sp = !*sp;
667*7c478bd9Sstevel@tonic-gate 			break;
668*7c478bd9Sstevel@tonic-gate 		case OP_BRFL:
669*7c478bd9Sstevel@tonic-gate 			op++;
670*7c478bd9Sstevel@tonic-gate 			if (!*sp)
671*7c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
672*7c478bd9Sstevel@tonic-gate 			break;
673*7c478bd9Sstevel@tonic-gate 		case OP_BRTR:
674*7c478bd9Sstevel@tonic-gate 			op++;
675*7c478bd9Sstevel@tonic-gate 			if (*sp)
676*7c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
677*7c478bd9Sstevel@tonic-gate 			break;
678*7c478bd9Sstevel@tonic-gate 		case OP_ADD:
679*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
680*7c478bd9Sstevel@tonic-gate 				return (0);
681*7c478bd9Sstevel@tonic-gate 			sp--;
682*7c478bd9Sstevel@tonic-gate 			*sp += *(sp + 1);
683*7c478bd9Sstevel@tonic-gate 			break;
684*7c478bd9Sstevel@tonic-gate 		case OP_SUB:
685*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
686*7c478bd9Sstevel@tonic-gate 				return (0);
687*7c478bd9Sstevel@tonic-gate 			sp--;
688*7c478bd9Sstevel@tonic-gate 			*sp -= *(sp + 1);
689*7c478bd9Sstevel@tonic-gate 			break;
690*7c478bd9Sstevel@tonic-gate 		case OP_MUL:
691*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
692*7c478bd9Sstevel@tonic-gate 				return (0);
693*7c478bd9Sstevel@tonic-gate 			sp--;
694*7c478bd9Sstevel@tonic-gate 			*sp *= *(sp + 1);
695*7c478bd9Sstevel@tonic-gate 			break;
696*7c478bd9Sstevel@tonic-gate 		case OP_DIV:
697*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
698*7c478bd9Sstevel@tonic-gate 				return (0);
699*7c478bd9Sstevel@tonic-gate 			sp--;
700*7c478bd9Sstevel@tonic-gate 			*sp /= *(sp + 1);
701*7c478bd9Sstevel@tonic-gate 			break;
702*7c478bd9Sstevel@tonic-gate 		case OP_REM:
703*7c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
704*7c478bd9Sstevel@tonic-gate 				return (0);
705*7c478bd9Sstevel@tonic-gate 			sp--;
706*7c478bd9Sstevel@tonic-gate 			*sp %= *(sp + 1);
707*7c478bd9Sstevel@tonic-gate 			break;
708*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_POP:
709*7c478bd9Sstevel@tonic-gate 			if (offp < &offstack[0])
710*7c478bd9Sstevel@tonic-gate 				return (0);
711*7c478bd9Sstevel@tonic-gate 			base = *offp--;
712*7c478bd9Sstevel@tonic-gate 			if (opkt != NULL) {
713*7c478bd9Sstevel@tonic-gate 				pkt = opkt;
714*7c478bd9Sstevel@tonic-gate 				len = olen;
715*7c478bd9Sstevel@tonic-gate 				opkt = NULL;
716*7c478bd9Sstevel@tonic-gate 			}
717*7c478bd9Sstevel@tonic-gate 			break;
718*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_ZERO:
719*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
720*7c478bd9Sstevel@tonic-gate 				return (0);
721*7c478bd9Sstevel@tonic-gate 			*++offp = base;
722*7c478bd9Sstevel@tonic-gate 			base = pkt;
723*7c478bd9Sstevel@tonic-gate 			break;
724*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_LINK:
725*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
726*7c478bd9Sstevel@tonic-gate 				return (0);
727*7c478bd9Sstevel@tonic-gate 			*++offp = base;
728*7c478bd9Sstevel@tonic-gate 			base = pkt + header_size;
729*7c478bd9Sstevel@tonic-gate 			/*
730*7c478bd9Sstevel@tonic-gate 			 * If the offset exceeds the packet length,
731*7c478bd9Sstevel@tonic-gate 			 * we should not be interested in this packet...
732*7c478bd9Sstevel@tonic-gate 			 * Just return 0.
733*7c478bd9Sstevel@tonic-gate 			 */
734*7c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
735*7c478bd9Sstevel@tonic-gate 				return (0);
736*7c478bd9Sstevel@tonic-gate 			}
737*7c478bd9Sstevel@tonic-gate 			break;
738*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_IP:
739*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
740*7c478bd9Sstevel@tonic-gate 				return (0);
741*7c478bd9Sstevel@tonic-gate 			*++offp = base;
742*7c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
743*7c478bd9Sstevel@tonic-gate 			base = ip + ip_hdr_len(ip);
744*7c478bd9Sstevel@tonic-gate 			if (base == ip) {
745*7c478bd9Sstevel@tonic-gate 				return (0);			/* not IP */
746*7c478bd9Sstevel@tonic-gate 			}
747*7c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
748*7c478bd9Sstevel@tonic-gate 				return (0);			/* bad pkt */
749*7c478bd9Sstevel@tonic-gate 			}
750*7c478bd9Sstevel@tonic-gate 			break;
751*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_TCP:
752*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
753*7c478bd9Sstevel@tonic-gate 				return (0);
754*7c478bd9Sstevel@tonic-gate 			*++offp = base;
755*7c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
756*7c478bd9Sstevel@tonic-gate 			tcp = ip + ip_hdr_len(ip);
757*7c478bd9Sstevel@tonic-gate 			if (tcp == ip) {
758*7c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
759*7c478bd9Sstevel@tonic-gate 			}
760*7c478bd9Sstevel@tonic-gate 			base = tcp + TCP_HDR_LEN(tcp);
761*7c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
762*7c478bd9Sstevel@tonic-gate 				return (0);
763*7c478bd9Sstevel@tonic-gate 			}
764*7c478bd9Sstevel@tonic-gate 			break;
765*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_UDP:
766*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
767*7c478bd9Sstevel@tonic-gate 				return (0);
768*7c478bd9Sstevel@tonic-gate 			*++offp = base;
769*7c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
770*7c478bd9Sstevel@tonic-gate 			udp = ip + ip_hdr_len(ip);
771*7c478bd9Sstevel@tonic-gate 			if (udp == ip) {
772*7c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
773*7c478bd9Sstevel@tonic-gate 			}
774*7c478bd9Sstevel@tonic-gate 			base = udp + sizeof (struct udphdr);
775*7c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
776*7c478bd9Sstevel@tonic-gate 				return (0);
777*7c478bd9Sstevel@tonic-gate 			}
778*7c478bd9Sstevel@tonic-gate 			break;
779*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_RPC:
780*7c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
781*7c478bd9Sstevel@tonic-gate 				return (0);
782*7c478bd9Sstevel@tonic-gate 			*++offp = base;
783*7c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
784*7c478bd9Sstevel@tonic-gate 			rpc = NULL;
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
787*7c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
788*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
789*7c478bd9Sstevel@tonic-gate 					return (0);
790*7c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
791*7c478bd9Sstevel@tonic-gate 				break;
792*7c478bd9Sstevel@tonic-gate 			}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
795*7c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
796*7c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
797*7c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(udp +
798*7c478bd9Sstevel@tonic-gate 				    sizeof (struct udphdr));
799*7c478bd9Sstevel@tonic-gate 				break;
800*7c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
801*7c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
802*7c478bd9Sstevel@tonic-gate 				/*
803*7c478bd9Sstevel@tonic-gate 				 * Need to skip an extra 4 for the xdr_rec
804*7c478bd9Sstevel@tonic-gate 				 * field.
805*7c478bd9Sstevel@tonic-gate 				 */
806*7c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(tcp +
807*7c478bd9Sstevel@tonic-gate 				    TCP_HDR_LEN(tcp) + 4);
808*7c478bd9Sstevel@tonic-gate 				break;
809*7c478bd9Sstevel@tonic-gate 			}
810*7c478bd9Sstevel@tonic-gate 			/*
811*7c478bd9Sstevel@tonic-gate 			 * We need to have at least 24 bytes of a RPC
812*7c478bd9Sstevel@tonic-gate 			 * packet to look at to determine the validity
813*7c478bd9Sstevel@tonic-gate 			 * of it.
814*7c478bd9Sstevel@tonic-gate 			 */
815*7c478bd9Sstevel@tonic-gate 			if (rpc == NULL || (uchar_t *)rpc + 24 > pkt + len) {
816*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
817*7c478bd9Sstevel@tonic-gate 					return (0);
818*7c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
819*7c478bd9Sstevel@tonic-gate 				break;
820*7c478bd9Sstevel@tonic-gate 			}
821*7c478bd9Sstevel@tonic-gate 			/* align */
822*7c478bd9Sstevel@tonic-gate 			(void) memcpy(&rpcmsg, rpc, 24);
823*7c478bd9Sstevel@tonic-gate 			if (!valid_rpc(&rpcmsg, 24)) {
824*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
825*7c478bd9Sstevel@tonic-gate 					return (0);
826*7c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
827*7c478bd9Sstevel@tonic-gate 				break;
828*7c478bd9Sstevel@tonic-gate 			}
829*7c478bd9Sstevel@tonic-gate 			if (ntohl(rpcmsg.rm_direction) == CALL) {
830*7c478bd9Sstevel@tonic-gate 				base = (uchar_t *)rpc;
831*7c478bd9Sstevel@tonic-gate 				newrpc = 1;
832*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
833*7c478bd9Sstevel@tonic-gate 					return (0);
834*7c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
835*7c478bd9Sstevel@tonic-gate 			} else {
836*7c478bd9Sstevel@tonic-gate 				opkt = pkt;
837*7c478bd9Sstevel@tonic-gate 				olen = len;
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 				pkt = base = (uchar_t *)find_rpc(&rpcmsg);
840*7c478bd9Sstevel@tonic-gate 				len = sizeof (struct xid_entry);
841*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
842*7c478bd9Sstevel@tonic-gate 					return (0);
843*7c478bd9Sstevel@tonic-gate 				*(++sp) = base != NULL;
844*7c478bd9Sstevel@tonic-gate 			}
845*7c478bd9Sstevel@tonic-gate 			break;
846*7c478bd9Sstevel@tonic-gate 		case OP_OFFSET_SLP:
847*7c478bd9Sstevel@tonic-gate 			slphdr = NULL;
848*7c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
851*7c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
852*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
853*7c478bd9Sstevel@tonic-gate 					return (0);
854*7c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
855*7c478bd9Sstevel@tonic-gate 				break;
856*7c478bd9Sstevel@tonic-gate 			}
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
859*7c478bd9Sstevel@tonic-gate 				struct udphdr udp_h;
860*7c478bd9Sstevel@tonic-gate 				struct tcphdr tcp_h;
861*7c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
862*7c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
863*7c478bd9Sstevel@tonic-gate 				/* align */
864*7c478bd9Sstevel@tonic-gate 				memcpy(&udp_h, udp, sizeof (udp_h));
865*7c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(udp_h.uh_sport);
866*7c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(udp_h.uh_dport);
867*7c478bd9Sstevel@tonic-gate 				slphdr = udp + sizeof (struct udphdr);
868*7c478bd9Sstevel@tonic-gate 				break;
869*7c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
870*7c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
871*7c478bd9Sstevel@tonic-gate 				/* align */
872*7c478bd9Sstevel@tonic-gate 				memcpy(&tcp_h, tcp, sizeof (tcp_h));
873*7c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(tcp_h.th_sport);
874*7c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(tcp_h.th_dport);
875*7c478bd9Sstevel@tonic-gate 				slphdr = tcp + TCP_HDR_LEN(tcp);
876*7c478bd9Sstevel@tonic-gate 				break;
877*7c478bd9Sstevel@tonic-gate 			}
878*7c478bd9Sstevel@tonic-gate 			if (slphdr == NULL || slphdr > pkt + len) {
879*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
880*7c478bd9Sstevel@tonic-gate 					return (0);
881*7c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
882*7c478bd9Sstevel@tonic-gate 				break;
883*7c478bd9Sstevel@tonic-gate 			}
884*7c478bd9Sstevel@tonic-gate 			if (slp_sport == 427 || slp_dport == 427) {
885*7c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
886*7c478bd9Sstevel@tonic-gate 					return (0);
887*7c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
888*7c478bd9Sstevel@tonic-gate 				if (slp_sport != 427 && slp_dport == 427)
889*7c478bd9Sstevel@tonic-gate 					stash_slp(slp_sport);
890*7c478bd9Sstevel@tonic-gate 				break;
891*7c478bd9Sstevel@tonic-gate 			} else if (find_slp(slp_dport) != -1) {
892*7c478bd9Sstevel@tonic-gate 				if (valid_slp(slphdr, len)) {
893*7c478bd9Sstevel@tonic-gate 					if (sp >= &stack[MAXSS])
894*7c478bd9Sstevel@tonic-gate 						return (0);
895*7c478bd9Sstevel@tonic-gate 					*(++sp) = 1;
896*7c478bd9Sstevel@tonic-gate 					break;
897*7c478bd9Sstevel@tonic-gate 				}
898*7c478bd9Sstevel@tonic-gate 				/* else fallthrough to reject */
899*7c478bd9Sstevel@tonic-gate 			}
900*7c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
901*7c478bd9Sstevel@tonic-gate 				return (0);
902*7c478bd9Sstevel@tonic-gate 			*(++sp) = 0;
903*7c478bd9Sstevel@tonic-gate 			break;
904*7c478bd9Sstevel@tonic-gate 		}
905*7c478bd9Sstevel@tonic-gate 	}
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	if (*sp && newrpc)
908*7c478bd9Sstevel@tonic-gate 		stash_rpc(&rpcmsg);
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	return (*sp);
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate static void
914*7c478bd9Sstevel@tonic-gate load_const(uint_t constval)
915*7c478bd9Sstevel@tonic-gate {
916*7c478bd9Sstevel@tonic-gate 	emitop(OP_LOAD_CONST);
917*7c478bd9Sstevel@tonic-gate 	emitval(constval);
918*7c478bd9Sstevel@tonic-gate }
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate static void
921*7c478bd9Sstevel@tonic-gate load_value(int offset, int len)
922*7c478bd9Sstevel@tonic-gate {
923*7c478bd9Sstevel@tonic-gate 	if (offset >= 0)
924*7c478bd9Sstevel@tonic-gate 		load_const(offset);
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	switch (len) {
927*7c478bd9Sstevel@tonic-gate 		case 1:
928*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_OCTET);
929*7c478bd9Sstevel@tonic-gate 			break;
930*7c478bd9Sstevel@tonic-gate 		case 2:
931*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_SHORT);
932*7c478bd9Sstevel@tonic-gate 			break;
933*7c478bd9Sstevel@tonic-gate 		case 4:
934*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LONG);
935*7c478bd9Sstevel@tonic-gate 			break;
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate }
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate /*
940*7c478bd9Sstevel@tonic-gate  * Emit code to compare a field in
941*7c478bd9Sstevel@tonic-gate  * the packet against a constant value.
942*7c478bd9Sstevel@tonic-gate  */
943*7c478bd9Sstevel@tonic-gate static void
944*7c478bd9Sstevel@tonic-gate compare_value(uint_t offset, uint_t len, uint_t val)
945*7c478bd9Sstevel@tonic-gate {
946*7c478bd9Sstevel@tonic-gate 	load_const(val);
947*7c478bd9Sstevel@tonic-gate 	load_value(offset, len);
948*7c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate static void
952*7c478bd9Sstevel@tonic-gate compare_addr_v4(uint_t offset, uint_t len, uint_t val)
953*7c478bd9Sstevel@tonic-gate {
954*7c478bd9Sstevel@tonic-gate 	load_const(ntohl(val));
955*7c478bd9Sstevel@tonic-gate 	load_value(offset, len);
956*7c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
957*7c478bd9Sstevel@tonic-gate }
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate static void
960*7c478bd9Sstevel@tonic-gate compare_addr_v6(uint_t offset, uint_t len, struct in6_addr val)
961*7c478bd9Sstevel@tonic-gate {
962*7c478bd9Sstevel@tonic-gate 	int i;
963*7c478bd9Sstevel@tonic-gate 	uint32_t value;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i += 4) {
966*7c478bd9Sstevel@tonic-gate 		value = ntohl(*(uint32_t *)&val.s6_addr[i]);
967*7c478bd9Sstevel@tonic-gate 		load_const(value);
968*7c478bd9Sstevel@tonic-gate 		load_value(offset + i, 4);
969*7c478bd9Sstevel@tonic-gate 		emitop(OP_EQ);
970*7c478bd9Sstevel@tonic-gate 		if (i != 0)
971*7c478bd9Sstevel@tonic-gate 			emitop(OP_AND);
972*7c478bd9Sstevel@tonic-gate 	}
973*7c478bd9Sstevel@tonic-gate }
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate /*
976*7c478bd9Sstevel@tonic-gate  * Same as above except do the comparison
977*7c478bd9Sstevel@tonic-gate  * after and'ing a mask value.  Useful
978*7c478bd9Sstevel@tonic-gate  * for comparing IP network numbers
979*7c478bd9Sstevel@tonic-gate  */
980*7c478bd9Sstevel@tonic-gate static void
981*7c478bd9Sstevel@tonic-gate compare_value_mask(uint_t offset, uint_t len, uint_t val, int mask)
982*7c478bd9Sstevel@tonic-gate {
983*7c478bd9Sstevel@tonic-gate 	load_value(offset, len);
984*7c478bd9Sstevel@tonic-gate 	load_const(mask);
985*7c478bd9Sstevel@tonic-gate 	emitop(OP_AND);
986*7c478bd9Sstevel@tonic-gate 	load_const(val);
987*7c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
988*7c478bd9Sstevel@tonic-gate }
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate /* Emit an operator into the code array */
991*7c478bd9Sstevel@tonic-gate static void
992*7c478bd9Sstevel@tonic-gate emitop(enum optype opcode)
993*7c478bd9Sstevel@tonic-gate {
994*7c478bd9Sstevel@tonic-gate 	if (curr_op >= &oplist[MAXOPS])
995*7c478bd9Sstevel@tonic-gate 		pr_err("expression too long");
996*7c478bd9Sstevel@tonic-gate 	*curr_op++ = opcode;
997*7c478bd9Sstevel@tonic-gate }
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate /*
1000*7c478bd9Sstevel@tonic-gate  * Remove n operators recently emitted into
1001*7c478bd9Sstevel@tonic-gate  * the code array.  Used by alternation().
1002*7c478bd9Sstevel@tonic-gate  */
1003*7c478bd9Sstevel@tonic-gate static void
1004*7c478bd9Sstevel@tonic-gate unemit(int numops)
1005*7c478bd9Sstevel@tonic-gate {
1006*7c478bd9Sstevel@tonic-gate 	curr_op -= numops;
1007*7c478bd9Sstevel@tonic-gate }
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate /*
1011*7c478bd9Sstevel@tonic-gate  * Same as emitop except that we're emitting
1012*7c478bd9Sstevel@tonic-gate  * a value that's not an operator.
1013*7c478bd9Sstevel@tonic-gate  */
1014*7c478bd9Sstevel@tonic-gate static void
1015*7c478bd9Sstevel@tonic-gate emitval(uint_t val)
1016*7c478bd9Sstevel@tonic-gate {
1017*7c478bd9Sstevel@tonic-gate 	if (curr_op >= &oplist[MAXOPS])
1018*7c478bd9Sstevel@tonic-gate 		pr_err("expression too long");
1019*7c478bd9Sstevel@tonic-gate 	*curr_op++ = val;
1020*7c478bd9Sstevel@tonic-gate }
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate /*
1023*7c478bd9Sstevel@tonic-gate  * Used to chain forward branches together
1024*7c478bd9Sstevel@tonic-gate  * for later resolution by resolve_chain().
1025*7c478bd9Sstevel@tonic-gate  */
1026*7c478bd9Sstevel@tonic-gate static uint_t
1027*7c478bd9Sstevel@tonic-gate chain(int p)
1028*7c478bd9Sstevel@tonic-gate {
1029*7c478bd9Sstevel@tonic-gate 	uint_t pos = curr_op - oplist;
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	emitval(p);
1032*7c478bd9Sstevel@tonic-gate 	return (pos);
1033*7c478bd9Sstevel@tonic-gate }
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate /*
1036*7c478bd9Sstevel@tonic-gate  * Proceed backward through the code array
1037*7c478bd9Sstevel@tonic-gate  * following a chain of forward references.
1038*7c478bd9Sstevel@tonic-gate  * At each reference install the destination
1039*7c478bd9Sstevel@tonic-gate  * branch offset.
1040*7c478bd9Sstevel@tonic-gate  */
1041*7c478bd9Sstevel@tonic-gate static void
1042*7c478bd9Sstevel@tonic-gate resolve_chain(uint_t p)
1043*7c478bd9Sstevel@tonic-gate {
1044*7c478bd9Sstevel@tonic-gate 	uint_t n;
1045*7c478bd9Sstevel@tonic-gate 	uint_t pos = curr_op - oplist;
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	while (p) {
1048*7c478bd9Sstevel@tonic-gate 		n = oplist[p];
1049*7c478bd9Sstevel@tonic-gate 		oplist[p] = pos;
1050*7c478bd9Sstevel@tonic-gate 		p = n;
1051*7c478bd9Sstevel@tonic-gate 	}
1052*7c478bd9Sstevel@tonic-gate }
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate #define	EQ(val) (strcmp(token, val) == 0)
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate char *tkp, *sav_tkp;
1057*7c478bd9Sstevel@tonic-gate char *token;
1058*7c478bd9Sstevel@tonic-gate enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
1059*7c478bd9Sstevel@tonic-gate 	ADDR_IP6, ADDR_AT } tokentype;
1060*7c478bd9Sstevel@tonic-gate uint_t tokenval;
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate /*
1063*7c478bd9Sstevel@tonic-gate  * This is the scanner.  Each call returns the next
1064*7c478bd9Sstevel@tonic-gate  * token in the filter expression.  A token is either:
1065*7c478bd9Sstevel@tonic-gate  * EOL:		The end of the line - no more tokens.
1066*7c478bd9Sstevel@tonic-gate  * ALPHA:	A name that begins with a letter and contains
1067*7c478bd9Sstevel@tonic-gate  *		letters or digits, hyphens or underscores.
1068*7c478bd9Sstevel@tonic-gate  * NUMBER:	A number.  The value can be represented as
1069*7c478bd9Sstevel@tonic-gate  * 		a decimal value (1234) or an octal value
1070*7c478bd9Sstevel@tonic-gate  *		that begins with zero (066) or a hex value
1071*7c478bd9Sstevel@tonic-gate  *		that begins with 0x or 0X (0xff).
1072*7c478bd9Sstevel@tonic-gate  * FIELD:	A name followed by a left square bracket.
1073*7c478bd9Sstevel@tonic-gate  * ADDR_IP:	An IP address.  Any sequence of digits
1074*7c478bd9Sstevel@tonic-gate  *		separated by dots e.g. 109.104.40.13
1075*7c478bd9Sstevel@tonic-gate  * ADDR_ETHER:	An ethernet address.  Any sequence of hex
1076*7c478bd9Sstevel@tonic-gate  *		digits separated by colons e.g. 8:0:20:0:76:39
1077*7c478bd9Sstevel@tonic-gate  * SPECIAL:	A special character e.g. ">" or "(".  The scanner
1078*7c478bd9Sstevel@tonic-gate  *		correctly handles digraphs - two special characters
1079*7c478bd9Sstevel@tonic-gate  *		that constitute a single token e.g. "==" or ">=".
1080*7c478bd9Sstevel@tonic-gate  * ADDR_IP6:    An IPv6 address.
1081*7c478bd9Sstevel@tonic-gate  *
1082*7c478bd9Sstevel@tonic-gate  * ADDR_AT:	An AppleTalk Phase II address. A sequence of two numbers
1083*7c478bd9Sstevel@tonic-gate  *		separated by a dot.
1084*7c478bd9Sstevel@tonic-gate  *
1085*7c478bd9Sstevel@tonic-gate  * The current token is maintained in "token" and and its
1086*7c478bd9Sstevel@tonic-gate  * type in "tokentype".  If tokentype is NUMBER then the
1087*7c478bd9Sstevel@tonic-gate  * value is held in "tokenval".
1088*7c478bd9Sstevel@tonic-gate  */
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate static const char *namechars =
1091*7c478bd9Sstevel@tonic-gate 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
1092*7c478bd9Sstevel@tonic-gate static const char *numchars = "0123456789abcdefABCDEFXx:.";
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate void
1095*7c478bd9Sstevel@tonic-gate next()
1096*7c478bd9Sstevel@tonic-gate {
1097*7c478bd9Sstevel@tonic-gate 	static int savechar;
1098*7c478bd9Sstevel@tonic-gate 	char *p;
1099*7c478bd9Sstevel@tonic-gate 	int size, size1;
1100*7c478bd9Sstevel@tonic-gate 	int base, colons, dots, alphas, double_colon;
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	colons = 0;
1103*7c478bd9Sstevel@tonic-gate 	double_colon = 0;
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	if (*tkp == '\0') {
1106*7c478bd9Sstevel@tonic-gate 		token = tkp;
1107*7c478bd9Sstevel@tonic-gate 		*tkp = savechar;
1108*7c478bd9Sstevel@tonic-gate 	}
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate 	sav_tkp = tkp;
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	while (isspace(*tkp)) tkp++;
1113*7c478bd9Sstevel@tonic-gate 	token = tkp;
1114*7c478bd9Sstevel@tonic-gate 	if (*token == '\0') {
1115*7c478bd9Sstevel@tonic-gate 		tokentype = EOL;
1116*7c478bd9Sstevel@tonic-gate 		return;
1117*7c478bd9Sstevel@tonic-gate 	}
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/* A token containing ':' cannot be ALPHA type */
1120*7c478bd9Sstevel@tonic-gate 	tkp = token + strspn(token, numchars);
1121*7c478bd9Sstevel@tonic-gate 	for (p = token; p < tkp; p++) {
1122*7c478bd9Sstevel@tonic-gate 		if (*p == ':') {
1123*7c478bd9Sstevel@tonic-gate 			colons++;
1124*7c478bd9Sstevel@tonic-gate 			if (*(p+1) == ':')
1125*7c478bd9Sstevel@tonic-gate 				double_colon++;
1126*7c478bd9Sstevel@tonic-gate 		}
1127*7c478bd9Sstevel@tonic-gate 	}
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	tkp = token;
1130*7c478bd9Sstevel@tonic-gate 	if (isalpha(*tkp) && !colons) {
1131*7c478bd9Sstevel@tonic-gate 		tokentype = ALPHA;
1132*7c478bd9Sstevel@tonic-gate 		tkp += strspn(tkp, namechars);
1133*7c478bd9Sstevel@tonic-gate 		if (*tkp == '[') {
1134*7c478bd9Sstevel@tonic-gate 			tokentype = FIELD;
1135*7c478bd9Sstevel@tonic-gate 			*tkp++ = '\0';
1136*7c478bd9Sstevel@tonic-gate 		}
1137*7c478bd9Sstevel@tonic-gate 	} else
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	/*
1140*7c478bd9Sstevel@tonic-gate 	 * RFC1123 states that host names may now start with digits. Need
1141*7c478bd9Sstevel@tonic-gate 	 * to change parser to account for this. Also, need to distinguish
1142*7c478bd9Sstevel@tonic-gate 	 * between 1.2.3.4 and 1.2.3.a where the first case is an IP address
1143*7c478bd9Sstevel@tonic-gate 	 * and the second is a domain name. 333aaa needs to be distinguished
1144*7c478bd9Sstevel@tonic-gate 	 * from 0x333aaa. The first is a host name and the second is a number.
1145*7c478bd9Sstevel@tonic-gate 	 *
1146*7c478bd9Sstevel@tonic-gate 	 * The (colons > 1) conditional differentiates between ethernet
1147*7c478bd9Sstevel@tonic-gate 	 * and IPv6 addresses, and an expression of the form base[expr:size],
1148*7c478bd9Sstevel@tonic-gate 	 * which can only contain one ':' character.
1149*7c478bd9Sstevel@tonic-gate 	 */
1150*7c478bd9Sstevel@tonic-gate 	if (isdigit(*tkp) || colons > 1) {
1151*7c478bd9Sstevel@tonic-gate 		tkp = token + strspn(token, numchars);
1152*7c478bd9Sstevel@tonic-gate 		dots = alphas = 0;
1153*7c478bd9Sstevel@tonic-gate 		for (p = token; p < tkp; p++) {
1154*7c478bd9Sstevel@tonic-gate 			if (*p == '.')
1155*7c478bd9Sstevel@tonic-gate 				dots++;
1156*7c478bd9Sstevel@tonic-gate 			else if (isalpha(*p))
1157*7c478bd9Sstevel@tonic-gate 				alphas = 1;
1158*7c478bd9Sstevel@tonic-gate 		}
1159*7c478bd9Sstevel@tonic-gate 		if (colons > 1) {
1160*7c478bd9Sstevel@tonic-gate 			if (colons == 5 && double_colon == 0) {
1161*7c478bd9Sstevel@tonic-gate 				tokentype = ADDR_ETHER;
1162*7c478bd9Sstevel@tonic-gate 			} else {
1163*7c478bd9Sstevel@tonic-gate 				tokentype = ADDR_IP6;
1164*7c478bd9Sstevel@tonic-gate 			}
1165*7c478bd9Sstevel@tonic-gate 		} else if (dots) {
1166*7c478bd9Sstevel@tonic-gate 			size = tkp - token;
1167*7c478bd9Sstevel@tonic-gate 			size1 = strspn(token, "0123456789.");
1168*7c478bd9Sstevel@tonic-gate 			if (dots == 1 && size == size1) {
1169*7c478bd9Sstevel@tonic-gate 				tokentype = ADDR_AT;
1170*7c478bd9Sstevel@tonic-gate 			} else
1171*7c478bd9Sstevel@tonic-gate 				if (dots != 3 || size != size1) {
1172*7c478bd9Sstevel@tonic-gate 					tokentype = ALPHA;
1173*7c478bd9Sstevel@tonic-gate 					if (*tkp != '\0' && !isspace(*tkp)) {
1174*7c478bd9Sstevel@tonic-gate 						tkp += strspn(tkp, namechars);
1175*7c478bd9Sstevel@tonic-gate 						if (*tkp == '[') {
1176*7c478bd9Sstevel@tonic-gate 							tokentype = FIELD;
1177*7c478bd9Sstevel@tonic-gate 							*tkp++ = '\0';
1178*7c478bd9Sstevel@tonic-gate 						}
1179*7c478bd9Sstevel@tonic-gate 					}
1180*7c478bd9Sstevel@tonic-gate 				} else
1181*7c478bd9Sstevel@tonic-gate 					tokentype = ADDR_IP;
1182*7c478bd9Sstevel@tonic-gate 		} else if (token + strspn(token, namechars) <= tkp) {
1183*7c478bd9Sstevel@tonic-gate 			/*
1184*7c478bd9Sstevel@tonic-gate 			 * With the above check, if there are more
1185*7c478bd9Sstevel@tonic-gate 			 * characters after the last digit, assume
1186*7c478bd9Sstevel@tonic-gate 			 * that it is not a number.
1187*7c478bd9Sstevel@tonic-gate 			 */
1188*7c478bd9Sstevel@tonic-gate 			tokentype = NUMBER;
1189*7c478bd9Sstevel@tonic-gate 			p = tkp;
1190*7c478bd9Sstevel@tonic-gate 			tkp = token;
1191*7c478bd9Sstevel@tonic-gate 			base = 10;
1192*7c478bd9Sstevel@tonic-gate 			if (*tkp == '0') {
1193*7c478bd9Sstevel@tonic-gate 				base = 8;
1194*7c478bd9Sstevel@tonic-gate 				tkp++;
1195*7c478bd9Sstevel@tonic-gate 				if (*tkp == 'x' || *tkp == 'X')
1196*7c478bd9Sstevel@tonic-gate 					base = 16;
1197*7c478bd9Sstevel@tonic-gate 			}
1198*7c478bd9Sstevel@tonic-gate 			if ((base == 10 || base == 8) && alphas) {
1199*7c478bd9Sstevel@tonic-gate 				tokentype = ALPHA;
1200*7c478bd9Sstevel@tonic-gate 				tkp = p;
1201*7c478bd9Sstevel@tonic-gate 			} else if (base == 16) {
1202*7c478bd9Sstevel@tonic-gate 				size = 2 + strspn(token+2,
1203*7c478bd9Sstevel@tonic-gate 					"0123456789abcdefABCDEF");
1204*7c478bd9Sstevel@tonic-gate 				size1 = p - token;
1205*7c478bd9Sstevel@tonic-gate 				if (size != size1) {
1206*7c478bd9Sstevel@tonic-gate 					tokentype = ALPHA;
1207*7c478bd9Sstevel@tonic-gate 					tkp = p;
1208*7c478bd9Sstevel@tonic-gate 				} else
1209*7c478bd9Sstevel@tonic-gate 				/*
1210*7c478bd9Sstevel@tonic-gate 				 * handles the case of 0x so an error message
1211*7c478bd9Sstevel@tonic-gate 				 * is not printed. Treats 0x as 0.
1212*7c478bd9Sstevel@tonic-gate 				 */
1213*7c478bd9Sstevel@tonic-gate 				if (size == 2) {
1214*7c478bd9Sstevel@tonic-gate 					tokenval = 0;
1215*7c478bd9Sstevel@tonic-gate 					tkp = token +2;
1216*7c478bd9Sstevel@tonic-gate 				} else {
1217*7c478bd9Sstevel@tonic-gate 					tokenval = strtoul(token, &tkp, base);
1218*7c478bd9Sstevel@tonic-gate 				}
1219*7c478bd9Sstevel@tonic-gate 			} else {
1220*7c478bd9Sstevel@tonic-gate 				tokenval = strtoul(token, &tkp, base);
1221*7c478bd9Sstevel@tonic-gate 			}
1222*7c478bd9Sstevel@tonic-gate 		} else {
1223*7c478bd9Sstevel@tonic-gate 			tokentype = ALPHA;
1224*7c478bd9Sstevel@tonic-gate 			tkp += strspn(tkp, namechars);
1225*7c478bd9Sstevel@tonic-gate 			if (*tkp == '[') {
1226*7c478bd9Sstevel@tonic-gate 				tokentype = FIELD;
1227*7c478bd9Sstevel@tonic-gate 				*tkp++ = '\0';
1228*7c478bd9Sstevel@tonic-gate 			}
1229*7c478bd9Sstevel@tonic-gate 		}
1230*7c478bd9Sstevel@tonic-gate 	} else {
1231*7c478bd9Sstevel@tonic-gate 		tokentype = SPECIAL;
1232*7c478bd9Sstevel@tonic-gate 		tkp++;
1233*7c478bd9Sstevel@tonic-gate 		if ((*token == '=' && *tkp == '=') ||
1234*7c478bd9Sstevel@tonic-gate 		    (*token == '>' && *tkp == '=') ||
1235*7c478bd9Sstevel@tonic-gate 		    (*token == '<' && *tkp == '=') ||
1236*7c478bd9Sstevel@tonic-gate 		    (*token == '!' && *tkp == '='))
1237*7c478bd9Sstevel@tonic-gate 				tkp++;
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	savechar = *tkp;
1241*7c478bd9Sstevel@tonic-gate 	*tkp = '\0';
1242*7c478bd9Sstevel@tonic-gate }
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate static struct match_type {
1245*7c478bd9Sstevel@tonic-gate 	char		*m_name;
1246*7c478bd9Sstevel@tonic-gate 	int		m_offset;
1247*7c478bd9Sstevel@tonic-gate 	int		m_size;
1248*7c478bd9Sstevel@tonic-gate 	int		m_value;
1249*7c478bd9Sstevel@tonic-gate 	int		m_depend;
1250*7c478bd9Sstevel@tonic-gate 	enum optype	m_optype;
1251*7c478bd9Sstevel@tonic-gate } match_types[] = {
1252*7c478bd9Sstevel@tonic-gate 	/*
1253*7c478bd9Sstevel@tonic-gate 	 * Table initialized assuming Ethernet data link headers.
1254*7c478bd9Sstevel@tonic-gate 	 */
1255*7c478bd9Sstevel@tonic-gate 	"ip",		12, 2, ETHERTYPE_IP,	-1,	OP_OFFSET_ZERO,
1256*7c478bd9Sstevel@tonic-gate 	"ip6",		12, 2, ETHERTYPE_IPV6,	-1,	OP_OFFSET_ZERO,
1257*7c478bd9Sstevel@tonic-gate 	"arp",		12, 2, ETHERTYPE_ARP,	-1,	OP_OFFSET_ZERO,
1258*7c478bd9Sstevel@tonic-gate 	"rarp",		12, 2, ETHERTYPE_REVARP, -1,	OP_OFFSET_ZERO,
1259*7c478bd9Sstevel@tonic-gate 	"pppoed",	12, 2, ETHERTYPE_PPPOED, -1,	OP_OFFSET_ZERO,
1260*7c478bd9Sstevel@tonic-gate 	"pppoes",	12, 2, ETHERTYPE_PPPOES, -1,	OP_OFFSET_ZERO,
1261*7c478bd9Sstevel@tonic-gate 	"tcp",		9, 1, IPPROTO_TCP,	0,	OP_OFFSET_LINK,
1262*7c478bd9Sstevel@tonic-gate 	"tcp",		6, 1, IPPROTO_TCP,	1,	OP_OFFSET_LINK,
1263*7c478bd9Sstevel@tonic-gate 	"udp",		9, 1, IPPROTO_UDP,	0,	OP_OFFSET_LINK,
1264*7c478bd9Sstevel@tonic-gate 	"udp",		6, 1, IPPROTO_UDP,	1,	OP_OFFSET_LINK,
1265*7c478bd9Sstevel@tonic-gate 	"icmp",		9, 1, IPPROTO_ICMP,	0,	OP_OFFSET_LINK,
1266*7c478bd9Sstevel@tonic-gate 	"icmp6",	6, 1, IPPROTO_ICMPV6,	1,	OP_OFFSET_LINK,
1267*7c478bd9Sstevel@tonic-gate 	"ip-in-ip",	9, 1, IPPROTO_ENCAP,	0,	OP_OFFSET_LINK,
1268*7c478bd9Sstevel@tonic-gate 	"esp",		9, 1, IPPROTO_ESP,	0,	OP_OFFSET_LINK,
1269*7c478bd9Sstevel@tonic-gate 	"esp",		6, 1, IPPROTO_ESP,	1,	OP_OFFSET_LINK,
1270*7c478bd9Sstevel@tonic-gate 	"ah",		9, 1, IPPROTO_AH,	0,	OP_OFFSET_LINK,
1271*7c478bd9Sstevel@tonic-gate 	"ah",		6, 1, IPPROTO_AH,	1,	OP_OFFSET_LINK,
1272*7c478bd9Sstevel@tonic-gate 	"sctp",		9, 1, IPPROTO_SCTP,	0,	OP_OFFSET_LINK,
1273*7c478bd9Sstevel@tonic-gate 	"sctp",		6, 1, IPPROTO_SCTP,	1,	OP_OFFSET_LINK,
1274*7c478bd9Sstevel@tonic-gate 	0,		0, 0, 0,		0,	0
1275*7c478bd9Sstevel@tonic-gate };
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate static void
1278*7c478bd9Sstevel@tonic-gate generate_check(struct match_type *mtp)
1279*7c478bd9Sstevel@tonic-gate {
1280*7c478bd9Sstevel@tonic-gate 	int	offset;
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	/*
1283*7c478bd9Sstevel@tonic-gate 	 * Note: this code assumes the above dependencies are
1284*7c478bd9Sstevel@tonic-gate 	 * not cyclic.  This *should* always be true.
1285*7c478bd9Sstevel@tonic-gate 	 */
1286*7c478bd9Sstevel@tonic-gate 	if (mtp->m_depend != -1)
1287*7c478bd9Sstevel@tonic-gate 		generate_check(&match_types[mtp->m_depend]);
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	offset = mtp->m_offset;
1290*7c478bd9Sstevel@tonic-gate 	if (mtp->m_optype == OP_OFFSET_ZERO) {
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 		/*
1293*7c478bd9Sstevel@tonic-gate 		 * The table is filled with ethernet offsets.  Here we
1294*7c478bd9Sstevel@tonic-gate 		 * fudge the value based on what know about the
1295*7c478bd9Sstevel@tonic-gate 		 * interface.  It is okay to do this because we are
1296*7c478bd9Sstevel@tonic-gate 		 * checking what we believe to be an IP/ARP/RARP
1297*7c478bd9Sstevel@tonic-gate 		 * packet, and we know those are carried in LLC-SNAP
1298*7c478bd9Sstevel@tonic-gate 		 * headers on FDDI.  We assume that it's unlikely
1299*7c478bd9Sstevel@tonic-gate 		 * another kind of packet, with a shorter FDDI header
1300*7c478bd9Sstevel@tonic-gate 		 * will happen to match the filter.
1301*7c478bd9Sstevel@tonic-gate 		 *
1302*7c478bd9Sstevel@tonic-gate 		 *		Ether	FDDI	IPoIB
1303*7c478bd9Sstevel@tonic-gate 		 *  edst addr	0	1	none
1304*7c478bd9Sstevel@tonic-gate 		 *  esrc addr	6	7	none
1305*7c478bd9Sstevel@tonic-gate 		 *  ethertype	12	19	0
1306*7c478bd9Sstevel@tonic-gate 		 *
1307*7c478bd9Sstevel@tonic-gate 		 * XXX token ring?
1308*7c478bd9Sstevel@tonic-gate 		 */
1309*7c478bd9Sstevel@tonic-gate 		if (interface->mac_type == DL_FDDI) {
1310*7c478bd9Sstevel@tonic-gate 			if (offset < 12)
1311*7c478bd9Sstevel@tonic-gate 				offset++;
1312*7c478bd9Sstevel@tonic-gate 			else if (offset == 12)
1313*7c478bd9Sstevel@tonic-gate 				offset = 19;
1314*7c478bd9Sstevel@tonic-gate 		} else if (interface->mac_type == DL_IB) {
1315*7c478bd9Sstevel@tonic-gate 			offset = 0;
1316*7c478bd9Sstevel@tonic-gate 		}
1317*7c478bd9Sstevel@tonic-gate 	}
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	if (mtp->m_optype != OP_OFFSET_ZERO) {
1320*7c478bd9Sstevel@tonic-gate 		emitop(mtp->m_optype);
1321*7c478bd9Sstevel@tonic-gate 		load_value(offset, mtp->m_size);
1322*7c478bd9Sstevel@tonic-gate 		load_const(mtp->m_value);
1323*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_POP);
1324*7c478bd9Sstevel@tonic-gate 	} else {
1325*7c478bd9Sstevel@tonic-gate 		load_value(offset, mtp->m_size);
1326*7c478bd9Sstevel@tonic-gate 		load_const(mtp->m_value);
1327*7c478bd9Sstevel@tonic-gate 	}
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 	if (mtp->m_depend != -1)
1332*7c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
1333*7c478bd9Sstevel@tonic-gate }
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate /*
1336*7c478bd9Sstevel@tonic-gate  * Generate code based on the keyword argument.
1337*7c478bd9Sstevel@tonic-gate  * This word is looked up in the match_types table
1338*7c478bd9Sstevel@tonic-gate  * and checks a field within the packet for a given
1339*7c478bd9Sstevel@tonic-gate  * value e.g. ether or ip type field.  The match
1340*7c478bd9Sstevel@tonic-gate  * can also have a dependency on another entry e.g.
1341*7c478bd9Sstevel@tonic-gate  * "tcp" requires that the packet also be "ip".
1342*7c478bd9Sstevel@tonic-gate  */
1343*7c478bd9Sstevel@tonic-gate static int
1344*7c478bd9Sstevel@tonic-gate comparison(char *s)
1345*7c478bd9Sstevel@tonic-gate {
1346*7c478bd9Sstevel@tonic-gate 	unsigned int	i, n_checks = 0;
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate 	for (i = 0; match_types[i].m_name != NULL; i++) {
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, match_types[i].m_name) != 0)
1351*7c478bd9Sstevel@tonic-gate 			continue;
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 		n_checks++;
1354*7c478bd9Sstevel@tonic-gate 		generate_check(&match_types[i]);
1355*7c478bd9Sstevel@tonic-gate 		if (n_checks > 1)
1356*7c478bd9Sstevel@tonic-gate 			emitop(OP_OR);
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate 	return (n_checks > 0);
1360*7c478bd9Sstevel@tonic-gate }
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate enum direction { ANY, TO, FROM };
1363*7c478bd9Sstevel@tonic-gate enum direction dir;
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate /*
1366*7c478bd9Sstevel@tonic-gate  * Generate code to match an IP address.  The address
1367*7c478bd9Sstevel@tonic-gate  * may be supplied either as a hostname or in dotted format.
1368*7c478bd9Sstevel@tonic-gate  * For source packets both the IP source address and ARP
1369*7c478bd9Sstevel@tonic-gate  * src are checked.
1370*7c478bd9Sstevel@tonic-gate  * Note: we don't check packet type here - whether IP or ARP.
1371*7c478bd9Sstevel@tonic-gate  * It's possible that we'll do an improper match.
1372*7c478bd9Sstevel@tonic-gate  */
1373*7c478bd9Sstevel@tonic-gate static void
1374*7c478bd9Sstevel@tonic-gate ipaddr_match(enum direction which, char *hostname, int inet_type)
1375*7c478bd9Sstevel@tonic-gate {
1376*7c478bd9Sstevel@tonic-gate 	bool_t found_host;
1377*7c478bd9Sstevel@tonic-gate 	int m = 0, n = 0;
1378*7c478bd9Sstevel@tonic-gate 	uint_t *addr4ptr;
1379*7c478bd9Sstevel@tonic-gate 	uint_t addr4;
1380*7c478bd9Sstevel@tonic-gate 	struct in6_addr *addr6ptr;
1381*7c478bd9Sstevel@tonic-gate 	int h_addr_index;
1382*7c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
1383*7c478bd9Sstevel@tonic-gate 	int error_num = 0;
1384*7c478bd9Sstevel@tonic-gate 	boolean_t freehp = B_FALSE;
1385*7c478bd9Sstevel@tonic-gate 	boolean_t first = B_TRUE;
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	/*
1388*7c478bd9Sstevel@tonic-gate 	 * The addr4offset and addr6offset variables simplify the code which
1389*7c478bd9Sstevel@tonic-gate 	 * generates the address comparison filter.  With these two variables,
1390*7c478bd9Sstevel@tonic-gate 	 * duplicate code need not exist for the TO and FROM case.
1391*7c478bd9Sstevel@tonic-gate 	 * A value of -1 describes the ANY case (TO and FROM).
1392*7c478bd9Sstevel@tonic-gate 	 */
1393*7c478bd9Sstevel@tonic-gate 	int addr4offset;
1394*7c478bd9Sstevel@tonic-gate 	int addr6offset;
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	found_host = 0;
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate 	if (tokentype == ADDR_IP) {
1399*7c478bd9Sstevel@tonic-gate 		hp = lgetipnodebyname(hostname, AF_INET,
1400*7c478bd9Sstevel@tonic-gate 					0, &error_num);
1401*7c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
1402*7c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET,
1403*7c478bd9Sstevel@tonic-gate 							0, &error_num);
1404*7c478bd9Sstevel@tonic-gate 			freehp = 1;
1405*7c478bd9Sstevel@tonic-gate 		}
1406*7c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
1407*7c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
1408*7c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s (try again later)",
1409*7c478bd9Sstevel@tonic-gate 				    hostname);
1410*7c478bd9Sstevel@tonic-gate 			} else {
1411*7c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s", hostname);
1412*7c478bd9Sstevel@tonic-gate 			}
1413*7c478bd9Sstevel@tonic-gate 		}
1414*7c478bd9Sstevel@tonic-gate 		inet_type = IPV4_ONLY;
1415*7c478bd9Sstevel@tonic-gate 	} else if (tokentype == ADDR_IP6) {
1416*7c478bd9Sstevel@tonic-gate 		hp = lgetipnodebyname(hostname, AF_INET6,
1417*7c478bd9Sstevel@tonic-gate 					0, &error_num);
1418*7c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
1419*7c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6,
1420*7c478bd9Sstevel@tonic-gate 							0, &error_num);
1421*7c478bd9Sstevel@tonic-gate 			freehp = 1;
1422*7c478bd9Sstevel@tonic-gate 		}
1423*7c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
1424*7c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
1425*7c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s (try again later)",
1426*7c478bd9Sstevel@tonic-gate 				    hostname);
1427*7c478bd9Sstevel@tonic-gate 			} else {
1428*7c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s", hostname);
1429*7c478bd9Sstevel@tonic-gate 			}
1430*7c478bd9Sstevel@tonic-gate 		}
1431*7c478bd9Sstevel@tonic-gate 		inet_type = IPV6_ONLY;
1432*7c478bd9Sstevel@tonic-gate 	} else {
1433*7c478bd9Sstevel@tonic-gate 		/* Some hostname i.e. tokentype is ALPHA */
1434*7c478bd9Sstevel@tonic-gate 		switch (inet_type) {
1435*7c478bd9Sstevel@tonic-gate 		case IPV4_ONLY:
1436*7c478bd9Sstevel@tonic-gate 			/* Only IPv4 address is needed */
1437*7c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET,
1438*7c478bd9Sstevel@tonic-gate 						0, &error_num);
1439*7c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
1440*7c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET,
1441*7c478bd9Sstevel@tonic-gate 								0, &error_num);
1442*7c478bd9Sstevel@tonic-gate 				freehp = 1;
1443*7c478bd9Sstevel@tonic-gate 			}
1444*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
1445*7c478bd9Sstevel@tonic-gate 				found_host = 1;
1446*7c478bd9Sstevel@tonic-gate 			}
1447*7c478bd9Sstevel@tonic-gate 			break;
1448*7c478bd9Sstevel@tonic-gate 		case IPV6_ONLY:
1449*7c478bd9Sstevel@tonic-gate 			/* Only IPv6 address is needed */
1450*7c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET6,
1451*7c478bd9Sstevel@tonic-gate 						0, &error_num);
1452*7c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
1453*7c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET6,
1454*7c478bd9Sstevel@tonic-gate 								0, &error_num);
1455*7c478bd9Sstevel@tonic-gate 				freehp = 1;
1456*7c478bd9Sstevel@tonic-gate 			}
1457*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
1458*7c478bd9Sstevel@tonic-gate 				found_host = 1;
1459*7c478bd9Sstevel@tonic-gate 			}
1460*7c478bd9Sstevel@tonic-gate 			break;
1461*7c478bd9Sstevel@tonic-gate 		case IPV4_AND_IPV6:
1462*7c478bd9Sstevel@tonic-gate 			/* Both IPv4 and IPv6 are needed */
1463*7c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET6,
1464*7c478bd9Sstevel@tonic-gate 					AI_ALL | AI_V4MAPPED, &error_num);
1465*7c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
1466*7c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET6,
1467*7c478bd9Sstevel@tonic-gate 					AI_ALL | AI_V4MAPPED, &error_num);
1468*7c478bd9Sstevel@tonic-gate 				freehp = 1;
1469*7c478bd9Sstevel@tonic-gate 			}
1470*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
1471*7c478bd9Sstevel@tonic-gate 				found_host = 1;
1472*7c478bd9Sstevel@tonic-gate 			}
1473*7c478bd9Sstevel@tonic-gate 			break;
1474*7c478bd9Sstevel@tonic-gate 		default:
1475*7c478bd9Sstevel@tonic-gate 			found_host = 0;
1476*7c478bd9Sstevel@tonic-gate 		}
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate 		if (!found_host) {
1479*7c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
1480*7c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
1481*7c478bd9Sstevel@tonic-gate 				    hostname);
1482*7c478bd9Sstevel@tonic-gate 			} else {
1483*7c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
1484*7c478bd9Sstevel@tonic-gate 			}
1485*7c478bd9Sstevel@tonic-gate 		}
1486*7c478bd9Sstevel@tonic-gate 	}
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 	switch (which) {
1489*7c478bd9Sstevel@tonic-gate 	case TO:
1490*7c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_DSTADDR_OFFSET;
1491*7c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_DSTADDR_OFFSET;
1492*7c478bd9Sstevel@tonic-gate 		break;
1493*7c478bd9Sstevel@tonic-gate 	case FROM:
1494*7c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_SRCADDR_OFFSET;
1495*7c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_SRCADDR_OFFSET;
1496*7c478bd9Sstevel@tonic-gate 		break;
1497*7c478bd9Sstevel@tonic-gate 	case ANY:
1498*7c478bd9Sstevel@tonic-gate 		addr4offset = -1;
1499*7c478bd9Sstevel@tonic-gate 		addr6offset = -1;
1500*7c478bd9Sstevel@tonic-gate 		break;
1501*7c478bd9Sstevel@tonic-gate 	}
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	/*
1504*7c478bd9Sstevel@tonic-gate 	 * The code below generates the filter.
1505*7c478bd9Sstevel@tonic-gate 	 */
1506*7c478bd9Sstevel@tonic-gate 	if (hp != NULL && hp->h_addrtype == AF_INET) {
1507*7c478bd9Sstevel@tonic-gate 		ethertype_match(ETHERTYPE_IP);
1508*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1509*7c478bd9Sstevel@tonic-gate 		n = chain(n);
1510*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_LINK);
1511*7c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
1512*7c478bd9Sstevel@tonic-gate 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
1513*7c478bd9Sstevel@tonic-gate 		while (addr4ptr != NULL) {
1514*7c478bd9Sstevel@tonic-gate 			if (addr4offset == -1) {
1515*7c478bd9Sstevel@tonic-gate 				compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
1516*7c478bd9Sstevel@tonic-gate 				    *addr4ptr);
1517*7c478bd9Sstevel@tonic-gate 				emitop(OP_BRTR);
1518*7c478bd9Sstevel@tonic-gate 				m = chain(m);
1519*7c478bd9Sstevel@tonic-gate 				compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
1520*7c478bd9Sstevel@tonic-gate 				    *addr4ptr);
1521*7c478bd9Sstevel@tonic-gate 			} else {
1522*7c478bd9Sstevel@tonic-gate 				compare_addr_v4(addr4offset, 4, *addr4ptr);
1523*7c478bd9Sstevel@tonic-gate 			}
1524*7c478bd9Sstevel@tonic-gate 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
1525*7c478bd9Sstevel@tonic-gate 			if (addr4ptr != NULL) {
1526*7c478bd9Sstevel@tonic-gate 				emitop(OP_BRTR);
1527*7c478bd9Sstevel@tonic-gate 				m = chain(m);
1528*7c478bd9Sstevel@tonic-gate 			}
1529*7c478bd9Sstevel@tonic-gate 		}
1530*7c478bd9Sstevel@tonic-gate 		if (m != 0) {
1531*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
1532*7c478bd9Sstevel@tonic-gate 		}
1533*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_POP);
1534*7c478bd9Sstevel@tonic-gate 		resolve_chain(n);
1535*7c478bd9Sstevel@tonic-gate 	} else {
1536*7c478bd9Sstevel@tonic-gate 		/* first pass: IPv4 addresses */
1537*7c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
1538*7c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
1539*7c478bd9Sstevel@tonic-gate 		first = B_TRUE;
1540*7c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
1541*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
1542*7c478bd9Sstevel@tonic-gate 				if (first) {
1543*7c478bd9Sstevel@tonic-gate 					ethertype_match(ETHERTYPE_IP);
1544*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRFL);
1545*7c478bd9Sstevel@tonic-gate 					n = chain(n);
1546*7c478bd9Sstevel@tonic-gate 					emitop(OP_OFFSET_LINK);
1547*7c478bd9Sstevel@tonic-gate 					first = B_FALSE;
1548*7c478bd9Sstevel@tonic-gate 				} else {
1549*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
1550*7c478bd9Sstevel@tonic-gate 					m = chain(m);
1551*7c478bd9Sstevel@tonic-gate 				}
1552*7c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
1553*7c478bd9Sstevel@tonic-gate 				    (struct in_addr *)&addr4);
1554*7c478bd9Sstevel@tonic-gate 				if (addr4offset == -1) {
1555*7c478bd9Sstevel@tonic-gate 					compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
1556*7c478bd9Sstevel@tonic-gate 					    addr4);
1557*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
1558*7c478bd9Sstevel@tonic-gate 					m = chain(m);
1559*7c478bd9Sstevel@tonic-gate 					compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
1560*7c478bd9Sstevel@tonic-gate 					    addr4);
1561*7c478bd9Sstevel@tonic-gate 				} else {
1562*7c478bd9Sstevel@tonic-gate 					compare_addr_v4(addr4offset, 4, addr4);
1563*7c478bd9Sstevel@tonic-gate 				}
1564*7c478bd9Sstevel@tonic-gate 			}
1565*7c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
1566*7c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
1567*7c478bd9Sstevel@tonic-gate 		}
1568*7c478bd9Sstevel@tonic-gate 		/* second pass: IPv6 addresses */
1569*7c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
1570*7c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
1571*7c478bd9Sstevel@tonic-gate 		first = B_TRUE;
1572*7c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
1573*7c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
1574*7c478bd9Sstevel@tonic-gate 				if (first) {
1575*7c478bd9Sstevel@tonic-gate 					/*
1576*7c478bd9Sstevel@tonic-gate 					 * bypass check for IPv6 addresses
1577*7c478bd9Sstevel@tonic-gate 					 * when we have an IPv4 packet
1578*7c478bd9Sstevel@tonic-gate 					 */
1579*7c478bd9Sstevel@tonic-gate 					if (n != 0) {
1580*7c478bd9Sstevel@tonic-gate 						emitop(OP_BRTR);
1581*7c478bd9Sstevel@tonic-gate 						m = chain(m);
1582*7c478bd9Sstevel@tonic-gate 						emitop(OP_BRFL);
1583*7c478bd9Sstevel@tonic-gate 						m = chain(m);
1584*7c478bd9Sstevel@tonic-gate 						resolve_chain(n);
1585*7c478bd9Sstevel@tonic-gate 						n = 0;
1586*7c478bd9Sstevel@tonic-gate 					}
1587*7c478bd9Sstevel@tonic-gate 					ethertype_match(ETHERTYPE_IPV6);
1588*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRFL);
1589*7c478bd9Sstevel@tonic-gate 					n = chain(n);
1590*7c478bd9Sstevel@tonic-gate 					emitop(OP_OFFSET_LINK);
1591*7c478bd9Sstevel@tonic-gate 					first = B_FALSE;
1592*7c478bd9Sstevel@tonic-gate 				} else {
1593*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
1594*7c478bd9Sstevel@tonic-gate 					m = chain(m);
1595*7c478bd9Sstevel@tonic-gate 				}
1596*7c478bd9Sstevel@tonic-gate 				if (addr6offset == -1) {
1597*7c478bd9Sstevel@tonic-gate 					compare_addr_v6(IPV6_SRCADDR_OFFSET,
1598*7c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
1599*7c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
1600*7c478bd9Sstevel@tonic-gate 					m = chain(m);
1601*7c478bd9Sstevel@tonic-gate 					compare_addr_v6(IPV6_DSTADDR_OFFSET,
1602*7c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
1603*7c478bd9Sstevel@tonic-gate 				} else {
1604*7c478bd9Sstevel@tonic-gate 					compare_addr_v6(addr6offset, 16,
1605*7c478bd9Sstevel@tonic-gate 					    *addr6ptr);
1606*7c478bd9Sstevel@tonic-gate 				}
1607*7c478bd9Sstevel@tonic-gate 			}
1608*7c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
1609*7c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
1610*7c478bd9Sstevel@tonic-gate 		}
1611*7c478bd9Sstevel@tonic-gate 		if (m != 0) {
1612*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
1613*7c478bd9Sstevel@tonic-gate 		}
1614*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_POP);
1615*7c478bd9Sstevel@tonic-gate 		resolve_chain(n);
1616*7c478bd9Sstevel@tonic-gate 	}
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 	/* only free struct hostent returned by getipnodebyname() */
1619*7c478bd9Sstevel@tonic-gate 	if (freehp) {
1620*7c478bd9Sstevel@tonic-gate 		freehostent(hp);
1621*7c478bd9Sstevel@tonic-gate 	}
1622*7c478bd9Sstevel@tonic-gate }
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate /*
1625*7c478bd9Sstevel@tonic-gate  * Generate code to match an AppleTalk address.  The address
1626*7c478bd9Sstevel@tonic-gate  * must be given as two numbers with a dot between
1627*7c478bd9Sstevel@tonic-gate  *
1628*7c478bd9Sstevel@tonic-gate  */
1629*7c478bd9Sstevel@tonic-gate static void
1630*7c478bd9Sstevel@tonic-gate ataddr_match(enum direction which, char *hostname)
1631*7c478bd9Sstevel@tonic-gate {
1632*7c478bd9Sstevel@tonic-gate 	uint_t net;
1633*7c478bd9Sstevel@tonic-gate 	uint_t node;
1634*7c478bd9Sstevel@tonic-gate 	uint_t m, n;
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	sscanf(hostname, "%u.%u", &net, &node);
1637*7c478bd9Sstevel@tonic-gate 
1638*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_LINK);
1639*7c478bd9Sstevel@tonic-gate 	switch (which) {
1640*7c478bd9Sstevel@tonic-gate 	case TO:
1641*7c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NET_OFFSET, 2, net);
1642*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1643*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1644*7c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NODE_OFFSET, 1, node);
1645*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1646*7c478bd9Sstevel@tonic-gate 		break;
1647*7c478bd9Sstevel@tonic-gate 	case FROM:
1648*7c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NET_OFFSET, 2, net);
1649*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1650*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1651*7c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NODE_OFFSET, 1, node);
1652*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1653*7c478bd9Sstevel@tonic-gate 		break;
1654*7c478bd9Sstevel@tonic-gate 	case ANY:
1655*7c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NET_OFFSET, 2, net);
1656*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1657*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1658*7c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NODE_OFFSET, 1, node);
1659*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1660*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
1661*7c478bd9Sstevel@tonic-gate 		n = chain(0);
1662*7c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NET_OFFSET, 2, net);
1663*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1664*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1665*7c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NODE_OFFSET, 1, node);
1666*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1667*7c478bd9Sstevel@tonic-gate 		resolve_chain(n);
1668*7c478bd9Sstevel@tonic-gate 		break;
1669*7c478bd9Sstevel@tonic-gate 	}
1670*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
1671*7c478bd9Sstevel@tonic-gate }
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate /*
1674*7c478bd9Sstevel@tonic-gate  * Compare ethernet addresses. The address may
1675*7c478bd9Sstevel@tonic-gate  * be provided either as a hostname or as a
1676*7c478bd9Sstevel@tonic-gate  * 6 octet colon-separated address.
1677*7c478bd9Sstevel@tonic-gate  */
1678*7c478bd9Sstevel@tonic-gate static void
1679*7c478bd9Sstevel@tonic-gate etheraddr_match(enum direction which, char *hostname)
1680*7c478bd9Sstevel@tonic-gate {
1681*7c478bd9Sstevel@tonic-gate 	uint_t addr;
1682*7c478bd9Sstevel@tonic-gate 	ushort_t *addrp;
1683*7c478bd9Sstevel@tonic-gate 	int to_offset, from_offset;
1684*7c478bd9Sstevel@tonic-gate 	struct ether_addr e, *ep = NULL;
1685*7c478bd9Sstevel@tonic-gate 	int m;
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 	/*
1688*7c478bd9Sstevel@tonic-gate 	 * First, check the interface type for whether src/dest address
1689*7c478bd9Sstevel@tonic-gate 	 * is determinable; if not, retreat early.
1690*7c478bd9Sstevel@tonic-gate 	 */
1691*7c478bd9Sstevel@tonic-gate 	switch (interface->mac_type) {
1692*7c478bd9Sstevel@tonic-gate 	case DL_ETHER:
1693*7c478bd9Sstevel@tonic-gate 		from_offset = ETHERADDRL;
1694*7c478bd9Sstevel@tonic-gate 		to_offset = 0;
1695*7c478bd9Sstevel@tonic-gate 		break;
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 	case DL_IB:
1698*7c478bd9Sstevel@tonic-gate 		/*
1699*7c478bd9Sstevel@tonic-gate 		 * If an ethernet address is attempted to be used
1700*7c478bd9Sstevel@tonic-gate 		 * on an IPoIB interface, flag error. Link address
1701*7c478bd9Sstevel@tonic-gate 		 * based filtering is unsupported on IPoIB, so there
1702*7c478bd9Sstevel@tonic-gate 		 * is no ipibaddr_match() or parsing support for IPoIB
1703*7c478bd9Sstevel@tonic-gate 		 * 20 byte link addresses.
1704*7c478bd9Sstevel@tonic-gate 		 */
1705*7c478bd9Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
1706*7c478bd9Sstevel@tonic-gate 		break;
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 	case DL_FDDI:
1709*7c478bd9Sstevel@tonic-gate 		from_offset = 7;
1710*7c478bd9Sstevel@tonic-gate 		to_offset = 1;
1711*7c478bd9Sstevel@tonic-gate 		break;
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate 	default:
1714*7c478bd9Sstevel@tonic-gate 		/*
1715*7c478bd9Sstevel@tonic-gate 		 * Where do we find "ether" address for FDDI & TR?
1716*7c478bd9Sstevel@tonic-gate 		 * XXX can improve?  ~sparker
1717*7c478bd9Sstevel@tonic-gate 		 */
1718*7c478bd9Sstevel@tonic-gate 		load_const(1);
1719*7c478bd9Sstevel@tonic-gate 		return;
1720*7c478bd9Sstevel@tonic-gate 	}
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 	if (isxdigit(*hostname))
1723*7c478bd9Sstevel@tonic-gate 		ep = ether_aton(hostname);
1724*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
1725*7c478bd9Sstevel@tonic-gate 		if (ether_hostton(hostname, &e))
1726*7c478bd9Sstevel@tonic-gate 			if (!arp_for_ether(hostname, &e))
1727*7c478bd9Sstevel@tonic-gate 				pr_err("cannot obtain ether addr for %s",
1728*7c478bd9Sstevel@tonic-gate 					hostname);
1729*7c478bd9Sstevel@tonic-gate 		ep = &e;
1730*7c478bd9Sstevel@tonic-gate 	}
1731*7c478bd9Sstevel@tonic-gate 	memcpy(&addr, (ushort_t *)ep, 4);
1732*7c478bd9Sstevel@tonic-gate 	addrp = (ushort_t *)ep + 2;
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 	switch (which) {
1735*7c478bd9Sstevel@tonic-gate 	case TO:
1736*7c478bd9Sstevel@tonic-gate 		compare_value(to_offset, 4, ntohl(addr));
1737*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1738*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1739*7c478bd9Sstevel@tonic-gate 		compare_value(to_offset + 4, 2, ntohs(*addrp));
1740*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1741*7c478bd9Sstevel@tonic-gate 		break;
1742*7c478bd9Sstevel@tonic-gate 	case FROM:
1743*7c478bd9Sstevel@tonic-gate 		compare_value(from_offset, 4, ntohl(addr));
1744*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1745*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1746*7c478bd9Sstevel@tonic-gate 		compare_value(from_offset + 4, 2, ntohs(*addrp));
1747*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1748*7c478bd9Sstevel@tonic-gate 		break;
1749*7c478bd9Sstevel@tonic-gate 	case ANY:
1750*7c478bd9Sstevel@tonic-gate 		compare_value(to_offset, 4, ntohl(addr));
1751*7c478bd9Sstevel@tonic-gate 		compare_value(to_offset + 4, 2, ntohs(*addrp));
1752*7c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
1753*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
1754*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 		compare_value(from_offset, 4, ntohl(addr));
1757*7c478bd9Sstevel@tonic-gate 		compare_value(from_offset + 4, 2, ntohs(*addrp));
1758*7c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
1759*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1760*7c478bd9Sstevel@tonic-gate 		break;
1761*7c478bd9Sstevel@tonic-gate 	}
1762*7c478bd9Sstevel@tonic-gate }
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate static void
1765*7c478bd9Sstevel@tonic-gate ethertype_match(int val)
1766*7c478bd9Sstevel@tonic-gate {
1767*7c478bd9Sstevel@tonic-gate 	int	m;
1768*7c478bd9Sstevel@tonic-gate 	int	ether_offset;
1769*7c478bd9Sstevel@tonic-gate 
1770*7c478bd9Sstevel@tonic-gate 	switch (interface->mac_type) {
1771*7c478bd9Sstevel@tonic-gate 	case DL_ETHER:
1772*7c478bd9Sstevel@tonic-gate 		ether_offset = 12;
1773*7c478bd9Sstevel@tonic-gate 		break;
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 	case DL_IB:
1776*7c478bd9Sstevel@tonic-gate 		ether_offset = 0;
1777*7c478bd9Sstevel@tonic-gate 		break;
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate 	case DL_FDDI:
1780*7c478bd9Sstevel@tonic-gate 		/* XXX Okay to assume LLC SNAP? */
1781*7c478bd9Sstevel@tonic-gate 		ether_offset = 19;
1782*7c478bd9Sstevel@tonic-gate 		break;
1783*7c478bd9Sstevel@tonic-gate 
1784*7c478bd9Sstevel@tonic-gate 	default:
1785*7c478bd9Sstevel@tonic-gate 		load_const(1);	/* Assume a match */
1786*7c478bd9Sstevel@tonic-gate 		return;
1787*7c478bd9Sstevel@tonic-gate 	}
1788*7c478bd9Sstevel@tonic-gate 	compare_value(ether_offset, 2, val); /* XXX.sparker */
1789*7c478bd9Sstevel@tonic-gate }
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate /*
1792*7c478bd9Sstevel@tonic-gate  * Match a network address.  The host part
1793*7c478bd9Sstevel@tonic-gate  * is masked out.  The network address may
1794*7c478bd9Sstevel@tonic-gate  * be supplied either as a netname or in
1795*7c478bd9Sstevel@tonic-gate  * IP dotted format.  The mask to be used
1796*7c478bd9Sstevel@tonic-gate  * for the comparison is assumed from the
1797*7c478bd9Sstevel@tonic-gate  * address format (see comment below).
1798*7c478bd9Sstevel@tonic-gate  */
1799*7c478bd9Sstevel@tonic-gate static void
1800*7c478bd9Sstevel@tonic-gate netaddr_match(enum direction which, char *netname)
1801*7c478bd9Sstevel@tonic-gate {
1802*7c478bd9Sstevel@tonic-gate 	uint_t addr;
1803*7c478bd9Sstevel@tonic-gate 	uint_t mask = 0xff000000;
1804*7c478bd9Sstevel@tonic-gate 	uint_t m;
1805*7c478bd9Sstevel@tonic-gate 	struct netent *np;
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	if (isdigit(*netname)) {
1808*7c478bd9Sstevel@tonic-gate 		addr = inet_network(netname);
1809*7c478bd9Sstevel@tonic-gate 	} else {
1810*7c478bd9Sstevel@tonic-gate 		np = getnetbyname(netname);
1811*7c478bd9Sstevel@tonic-gate 		if (np == NULL)
1812*7c478bd9Sstevel@tonic-gate 			pr_err("net %s not known", netname);
1813*7c478bd9Sstevel@tonic-gate 		addr = np->n_net;
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate 	addr = ntohl(addr);
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 	/*
1818*7c478bd9Sstevel@tonic-gate 	 * Left justify the address and figure
1819*7c478bd9Sstevel@tonic-gate 	 * out a mask based on the supplied address.
1820*7c478bd9Sstevel@tonic-gate 	 * Set the mask according to the number of zero
1821*7c478bd9Sstevel@tonic-gate 	 * low-order bytes.
1822*7c478bd9Sstevel@tonic-gate 	 * Note: this works only for whole octet masks.
1823*7c478bd9Sstevel@tonic-gate 	 */
1824*7c478bd9Sstevel@tonic-gate 	if (addr) {
1825*7c478bd9Sstevel@tonic-gate 		while ((addr & ~mask) != 0) {
1826*7c478bd9Sstevel@tonic-gate 			mask |= (mask >> 8);
1827*7c478bd9Sstevel@tonic-gate 		}
1828*7c478bd9Sstevel@tonic-gate 	}
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_LINK);
1831*7c478bd9Sstevel@tonic-gate 	switch (which) {
1832*7c478bd9Sstevel@tonic-gate 	case TO:
1833*7c478bd9Sstevel@tonic-gate 		compare_value_mask(16, 4, addr, mask);
1834*7c478bd9Sstevel@tonic-gate 		break;
1835*7c478bd9Sstevel@tonic-gate 	case FROM:
1836*7c478bd9Sstevel@tonic-gate 		compare_value_mask(12, 4, addr, mask);
1837*7c478bd9Sstevel@tonic-gate 		break;
1838*7c478bd9Sstevel@tonic-gate 	case ANY:
1839*7c478bd9Sstevel@tonic-gate 		compare_value_mask(12, 4, addr, mask);
1840*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
1841*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1842*7c478bd9Sstevel@tonic-gate 		compare_value_mask(16, 4, addr, mask);
1843*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1844*7c478bd9Sstevel@tonic-gate 		break;
1845*7c478bd9Sstevel@tonic-gate 	}
1846*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
1847*7c478bd9Sstevel@tonic-gate }
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate /*
1850*7c478bd9Sstevel@tonic-gate  * Match either a UDP or TCP port number.
1851*7c478bd9Sstevel@tonic-gate  * The port number may be provided either as
1852*7c478bd9Sstevel@tonic-gate  * port name as listed in /etc/services ("nntp") or as
1853*7c478bd9Sstevel@tonic-gate  * the port number itself (2049).
1854*7c478bd9Sstevel@tonic-gate  */
1855*7c478bd9Sstevel@tonic-gate static void
1856*7c478bd9Sstevel@tonic-gate port_match(enum direction which, char *portname)
1857*7c478bd9Sstevel@tonic-gate {
1858*7c478bd9Sstevel@tonic-gate 	struct servent *sp;
1859*7c478bd9Sstevel@tonic-gate 	uint_t m, port;
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	if (isdigit(*portname)) {
1862*7c478bd9Sstevel@tonic-gate 		port = atoi(portname);
1863*7c478bd9Sstevel@tonic-gate 	} else {
1864*7c478bd9Sstevel@tonic-gate 		sp = getservbyname(portname, NULL);
1865*7c478bd9Sstevel@tonic-gate 		if (sp == NULL)
1866*7c478bd9Sstevel@tonic-gate 			pr_err("invalid port number or name: %s",
1867*7c478bd9Sstevel@tonic-gate 				portname);
1868*7c478bd9Sstevel@tonic-gate 		port = ntohs(sp->s_port);
1869*7c478bd9Sstevel@tonic-gate 	}
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_IP);
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 	switch (which) {
1874*7c478bd9Sstevel@tonic-gate 	case TO:
1875*7c478bd9Sstevel@tonic-gate 		compare_value(2, 2, port);
1876*7c478bd9Sstevel@tonic-gate 		break;
1877*7c478bd9Sstevel@tonic-gate 	case FROM:
1878*7c478bd9Sstevel@tonic-gate 		compare_value(0, 2, port);
1879*7c478bd9Sstevel@tonic-gate 		break;
1880*7c478bd9Sstevel@tonic-gate 	case ANY:
1881*7c478bd9Sstevel@tonic-gate 		compare_value(2, 2, port);
1882*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
1883*7c478bd9Sstevel@tonic-gate 		m = chain(0);
1884*7c478bd9Sstevel@tonic-gate 		compare_value(0, 2, port);
1885*7c478bd9Sstevel@tonic-gate 		resolve_chain(m);
1886*7c478bd9Sstevel@tonic-gate 		break;
1887*7c478bd9Sstevel@tonic-gate 	}
1888*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
1889*7c478bd9Sstevel@tonic-gate }
1890*7c478bd9Sstevel@tonic-gate 
1891*7c478bd9Sstevel@tonic-gate /*
1892*7c478bd9Sstevel@tonic-gate  * Generate code to match packets with a specific
1893*7c478bd9Sstevel@tonic-gate  * RPC program number.  If the progname is a name
1894*7c478bd9Sstevel@tonic-gate  * it is converted to a number via /etc/rpc.
1895*7c478bd9Sstevel@tonic-gate  * The program version and/or procedure may be provided
1896*7c478bd9Sstevel@tonic-gate  * as extra qualifiers.
1897*7c478bd9Sstevel@tonic-gate  */
1898*7c478bd9Sstevel@tonic-gate static void
1899*7c478bd9Sstevel@tonic-gate rpc_match_prog(enum direction which, char *progname, int vers, int proc)
1900*7c478bd9Sstevel@tonic-gate {
1901*7c478bd9Sstevel@tonic-gate 	struct rpcent *rpc;
1902*7c478bd9Sstevel@tonic-gate 	uint_t prog;
1903*7c478bd9Sstevel@tonic-gate 	uint_t m, n;
1904*7c478bd9Sstevel@tonic-gate 
1905*7c478bd9Sstevel@tonic-gate 	if (isdigit(*progname)) {
1906*7c478bd9Sstevel@tonic-gate 		prog = atoi(progname);
1907*7c478bd9Sstevel@tonic-gate 	} else {
1908*7c478bd9Sstevel@tonic-gate 		rpc = (struct rpcent *)getrpcbyname(progname);
1909*7c478bd9Sstevel@tonic-gate 		if (rpc == NULL)
1910*7c478bd9Sstevel@tonic-gate 			pr_err("invalid program name: %s", progname);
1911*7c478bd9Sstevel@tonic-gate 		prog = rpc->r_number;
1912*7c478bd9Sstevel@tonic-gate 	}
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_RPC);
1915*7c478bd9Sstevel@tonic-gate 	emitop(OP_BRFL);
1916*7c478bd9Sstevel@tonic-gate 	n = chain(0);
1917*7c478bd9Sstevel@tonic-gate 
1918*7c478bd9Sstevel@tonic-gate 	compare_value(12, 4, prog);
1919*7c478bd9Sstevel@tonic-gate 	emitop(OP_BRFL);
1920*7c478bd9Sstevel@tonic-gate 	m = chain(0);
1921*7c478bd9Sstevel@tonic-gate 	if (vers >= 0) {
1922*7c478bd9Sstevel@tonic-gate 		compare_value(16, 4, vers);
1923*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1924*7c478bd9Sstevel@tonic-gate 		m = chain(m);
1925*7c478bd9Sstevel@tonic-gate 	}
1926*7c478bd9Sstevel@tonic-gate 	if (proc >= 0) {
1927*7c478bd9Sstevel@tonic-gate 		compare_value(20, 4, proc);
1928*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1929*7c478bd9Sstevel@tonic-gate 		m = chain(m);
1930*7c478bd9Sstevel@tonic-gate 	}
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	switch (which) {
1933*7c478bd9Sstevel@tonic-gate 	case TO:
1934*7c478bd9Sstevel@tonic-gate 		compare_value(4, 4, CALL);
1935*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1936*7c478bd9Sstevel@tonic-gate 		m = chain(m);
1937*7c478bd9Sstevel@tonic-gate 		break;
1938*7c478bd9Sstevel@tonic-gate 	case FROM:
1939*7c478bd9Sstevel@tonic-gate 		compare_value(4, 4, REPLY);
1940*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
1941*7c478bd9Sstevel@tonic-gate 		m = chain(m);
1942*7c478bd9Sstevel@tonic-gate 		break;
1943*7c478bd9Sstevel@tonic-gate 	}
1944*7c478bd9Sstevel@tonic-gate 	resolve_chain(m);
1945*7c478bd9Sstevel@tonic-gate 	resolve_chain(n);
1946*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
1947*7c478bd9Sstevel@tonic-gate }
1948*7c478bd9Sstevel@tonic-gate 
1949*7c478bd9Sstevel@tonic-gate /*
1950*7c478bd9Sstevel@tonic-gate  * Generate code to parse a field specification
1951*7c478bd9Sstevel@tonic-gate  * and load the value of the field from the packet
1952*7c478bd9Sstevel@tonic-gate  * onto the operand stack.
1953*7c478bd9Sstevel@tonic-gate  * The field offset may be specified relative to the
1954*7c478bd9Sstevel@tonic-gate  * beginning of the ether header, IP header, UDP header,
1955*7c478bd9Sstevel@tonic-gate  * or TCP header.  An optional size specification may
1956*7c478bd9Sstevel@tonic-gate  * be provided following a colon.  If no size is given
1957*7c478bd9Sstevel@tonic-gate  * one byte is assumed e.g.
1958*7c478bd9Sstevel@tonic-gate  *
1959*7c478bd9Sstevel@tonic-gate  *	ether[0]	The first byte of the ether header
1960*7c478bd9Sstevel@tonic-gate  *	ip[2:2]		The second 16 bit field of the IP header
1961*7c478bd9Sstevel@tonic-gate  */
1962*7c478bd9Sstevel@tonic-gate static void
1963*7c478bd9Sstevel@tonic-gate load_field()
1964*7c478bd9Sstevel@tonic-gate {
1965*7c478bd9Sstevel@tonic-gate 	int size = 1;
1966*7c478bd9Sstevel@tonic-gate 	int s;
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate 	if (EQ("ether"))
1970*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_ZERO);
1971*7c478bd9Sstevel@tonic-gate 	else if (EQ("ip") || EQ("ip6") || EQ("pppoed") || EQ("pppoes"))
1972*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_LINK);
1973*7c478bd9Sstevel@tonic-gate 	else if (EQ("udp") || EQ("tcp") || EQ("icmp") || EQ("ip-in-ip") ||
1974*7c478bd9Sstevel@tonic-gate 	    EQ("ah") || EQ("esp"))
1975*7c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_IP);
1976*7c478bd9Sstevel@tonic-gate 	else
1977*7c478bd9Sstevel@tonic-gate 		pr_err("invalid field type");
1978*7c478bd9Sstevel@tonic-gate 	next();
1979*7c478bd9Sstevel@tonic-gate 	s = opstack;
1980*7c478bd9Sstevel@tonic-gate 	expression();
1981*7c478bd9Sstevel@tonic-gate 	if (opstack != s + 1)
1982*7c478bd9Sstevel@tonic-gate 		pr_err("invalid field offset");
1983*7c478bd9Sstevel@tonic-gate 	opstack--;
1984*7c478bd9Sstevel@tonic-gate 	if (*token == ':') {
1985*7c478bd9Sstevel@tonic-gate 		next();
1986*7c478bd9Sstevel@tonic-gate 		if (tokentype != NUMBER)
1987*7c478bd9Sstevel@tonic-gate 			pr_err("field size expected");
1988*7c478bd9Sstevel@tonic-gate 		size = tokenval;
1989*7c478bd9Sstevel@tonic-gate 		if (size != 1 && size != 2 && size != 4)
1990*7c478bd9Sstevel@tonic-gate 			pr_err("field size invalid");
1991*7c478bd9Sstevel@tonic-gate 		next();
1992*7c478bd9Sstevel@tonic-gate 	}
1993*7c478bd9Sstevel@tonic-gate 	if (*token != ']')
1994*7c478bd9Sstevel@tonic-gate 		pr_err("right bracket expected");
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	load_value(-1, size);
1997*7c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
1998*7c478bd9Sstevel@tonic-gate }
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate /*
2001*7c478bd9Sstevel@tonic-gate  * Check that the operand stack
2002*7c478bd9Sstevel@tonic-gate  * contains n arguments
2003*7c478bd9Sstevel@tonic-gate  */
2004*7c478bd9Sstevel@tonic-gate static void
2005*7c478bd9Sstevel@tonic-gate checkstack(int numargs)
2006*7c478bd9Sstevel@tonic-gate {
2007*7c478bd9Sstevel@tonic-gate 	if (opstack != numargs)
2008*7c478bd9Sstevel@tonic-gate 		pr_err("invalid expression at \"%s\".", token);
2009*7c478bd9Sstevel@tonic-gate }
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate static void
2012*7c478bd9Sstevel@tonic-gate primary()
2013*7c478bd9Sstevel@tonic-gate {
2014*7c478bd9Sstevel@tonic-gate 	int m, s;
2015*7c478bd9Sstevel@tonic-gate 
2016*7c478bd9Sstevel@tonic-gate 	for (;;) {
2017*7c478bd9Sstevel@tonic-gate 		if (tokentype == FIELD) {
2018*7c478bd9Sstevel@tonic-gate 			load_field();
2019*7c478bd9Sstevel@tonic-gate 			opstack++;
2020*7c478bd9Sstevel@tonic-gate 			next();
2021*7c478bd9Sstevel@tonic-gate 			break;
2022*7c478bd9Sstevel@tonic-gate 		}
2023*7c478bd9Sstevel@tonic-gate 
2024*7c478bd9Sstevel@tonic-gate 		if (comparison(token)) {
2025*7c478bd9Sstevel@tonic-gate 			opstack++;
2026*7c478bd9Sstevel@tonic-gate 			next();
2027*7c478bd9Sstevel@tonic-gate 			break;
2028*7c478bd9Sstevel@tonic-gate 		}
2029*7c478bd9Sstevel@tonic-gate 
2030*7c478bd9Sstevel@tonic-gate 		if (EQ("not") || EQ("!")) {
2031*7c478bd9Sstevel@tonic-gate 			next();
2032*7c478bd9Sstevel@tonic-gate 			s = opstack;
2033*7c478bd9Sstevel@tonic-gate 			primary();
2034*7c478bd9Sstevel@tonic-gate 			checkstack(s + 1);
2035*7c478bd9Sstevel@tonic-gate 			emitop(OP_NOT);
2036*7c478bd9Sstevel@tonic-gate 			break;
2037*7c478bd9Sstevel@tonic-gate 		}
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 		if (EQ("(")) {
2040*7c478bd9Sstevel@tonic-gate 			next();
2041*7c478bd9Sstevel@tonic-gate 			s = opstack;
2042*7c478bd9Sstevel@tonic-gate 			expression();
2043*7c478bd9Sstevel@tonic-gate 			checkstack(s + 1);
2044*7c478bd9Sstevel@tonic-gate 			if (!EQ(")"))
2045*7c478bd9Sstevel@tonic-gate 				pr_err("right paren expected");
2046*7c478bd9Sstevel@tonic-gate 			next();
2047*7c478bd9Sstevel@tonic-gate 		}
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 		if (EQ("to") || EQ("dst")) {
2050*7c478bd9Sstevel@tonic-gate 			dir = TO;
2051*7c478bd9Sstevel@tonic-gate 			next();
2052*7c478bd9Sstevel@tonic-gate 			continue;
2053*7c478bd9Sstevel@tonic-gate 		}
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 		if (EQ("from") || EQ("src")) {
2056*7c478bd9Sstevel@tonic-gate 			dir = FROM;
2057*7c478bd9Sstevel@tonic-gate 			next();
2058*7c478bd9Sstevel@tonic-gate 			continue;
2059*7c478bd9Sstevel@tonic-gate 		}
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 		if (EQ("ether")) {
2062*7c478bd9Sstevel@tonic-gate 			eaddr = 1;
2063*7c478bd9Sstevel@tonic-gate 			next();
2064*7c478bd9Sstevel@tonic-gate 			continue;
2065*7c478bd9Sstevel@tonic-gate 		}
2066*7c478bd9Sstevel@tonic-gate 
2067*7c478bd9Sstevel@tonic-gate 		if (EQ("proto")) { /* ignore */
2068*7c478bd9Sstevel@tonic-gate 			next();
2069*7c478bd9Sstevel@tonic-gate 			continue;
2070*7c478bd9Sstevel@tonic-gate 		}
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 		if (EQ("broadcast")) {
2073*7c478bd9Sstevel@tonic-gate 			/*
2074*7c478bd9Sstevel@tonic-gate 			 * Be tricky: FDDI ether dst address begins at
2075*7c478bd9Sstevel@tonic-gate 			 * byte one.  Since the address is really six
2076*7c478bd9Sstevel@tonic-gate 			 * bytes long, this works for FDDI & ethernet.
2077*7c478bd9Sstevel@tonic-gate 			 * XXX - Token ring?
2078*7c478bd9Sstevel@tonic-gate 			 */
2079*7c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_IB)
2080*7c478bd9Sstevel@tonic-gate 				pr_err("filter option unsupported on media");
2081*7c478bd9Sstevel@tonic-gate 			compare_value(1, 4, 0xffffffff);
2082*7c478bd9Sstevel@tonic-gate 			opstack++;
2083*7c478bd9Sstevel@tonic-gate 			next();
2084*7c478bd9Sstevel@tonic-gate 			break;
2085*7c478bd9Sstevel@tonic-gate 		}
2086*7c478bd9Sstevel@tonic-gate 
2087*7c478bd9Sstevel@tonic-gate 		if (EQ("multicast")) {
2088*7c478bd9Sstevel@tonic-gate 			/* XXX Token ring? */
2089*7c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_FDDI) {
2090*7c478bd9Sstevel@tonic-gate 				compare_value_mask(1, 1, 0x01, 0x01);
2091*7c478bd9Sstevel@tonic-gate 			} else if (interface->mac_type == DL_IB) {
2092*7c478bd9Sstevel@tonic-gate 				pr_err("filter option unsupported on media");
2093*7c478bd9Sstevel@tonic-gate 			} else {
2094*7c478bd9Sstevel@tonic-gate 				compare_value_mask(0, 1, 0x01, 0x01);
2095*7c478bd9Sstevel@tonic-gate 			}
2096*7c478bd9Sstevel@tonic-gate 			opstack++;
2097*7c478bd9Sstevel@tonic-gate 			next();
2098*7c478bd9Sstevel@tonic-gate 			break;
2099*7c478bd9Sstevel@tonic-gate 		}
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 		if (EQ("decnet")) {
2102*7c478bd9Sstevel@tonic-gate 			/* XXX Token ring? */
2103*7c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_FDDI) {
2104*7c478bd9Sstevel@tonic-gate 				load_value(19, 2);	/* ether type */
2105*7c478bd9Sstevel@tonic-gate 				load_const(0x6000);
2106*7c478bd9Sstevel@tonic-gate 				emitop(OP_GE);
2107*7c478bd9Sstevel@tonic-gate 				emitop(OP_BRFL);
2108*7c478bd9Sstevel@tonic-gate 				m = chain(0);
2109*7c478bd9Sstevel@tonic-gate 				load_value(19, 2);	/* ether type */
2110*7c478bd9Sstevel@tonic-gate 				load_const(0x6009);
2111*7c478bd9Sstevel@tonic-gate 				emitop(OP_LE);
2112*7c478bd9Sstevel@tonic-gate 				resolve_chain(m);
2113*7c478bd9Sstevel@tonic-gate 			} else {
2114*7c478bd9Sstevel@tonic-gate 				load_value(12, 2);	/* ether type */
2115*7c478bd9Sstevel@tonic-gate 				load_const(0x6000);
2116*7c478bd9Sstevel@tonic-gate 				emitop(OP_GE);
2117*7c478bd9Sstevel@tonic-gate 				emitop(OP_BRFL);
2118*7c478bd9Sstevel@tonic-gate 				m = chain(0);
2119*7c478bd9Sstevel@tonic-gate 				load_value(12, 2);	/* ether type */
2120*7c478bd9Sstevel@tonic-gate 				load_const(0x6009);
2121*7c478bd9Sstevel@tonic-gate 				emitop(OP_LE);
2122*7c478bd9Sstevel@tonic-gate 				resolve_chain(m);
2123*7c478bd9Sstevel@tonic-gate 			}
2124*7c478bd9Sstevel@tonic-gate 			opstack++;
2125*7c478bd9Sstevel@tonic-gate 			next();
2126*7c478bd9Sstevel@tonic-gate 			break;
2127*7c478bd9Sstevel@tonic-gate 		}
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 		if (EQ("apple")) {
2130*7c478bd9Sstevel@tonic-gate 			/*
2131*7c478bd9Sstevel@tonic-gate 			 * Appletalk also appears in 802.2
2132*7c478bd9Sstevel@tonic-gate 			 * packets, so check for the ethertypes
2133*7c478bd9Sstevel@tonic-gate 			 * at offset 12 and 20 in the MAC header.
2134*7c478bd9Sstevel@tonic-gate 			 */
2135*7c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_AT);
2136*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
2137*7c478bd9Sstevel@tonic-gate 			m = chain(0);
2138*7c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_AARP);
2139*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
2140*7c478bd9Sstevel@tonic-gate 			m = chain(m);
2141*7c478bd9Sstevel@tonic-gate 			compare_value(20, 2, ETHERTYPE_AT); /* 802.2 */
2142*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
2143*7c478bd9Sstevel@tonic-gate 			m = chain(m);
2144*7c478bd9Sstevel@tonic-gate 			compare_value(20, 2, ETHERTYPE_AARP); /* 802.2 */
2145*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
2146*7c478bd9Sstevel@tonic-gate 			opstack++;
2147*7c478bd9Sstevel@tonic-gate 			next();
2148*7c478bd9Sstevel@tonic-gate 			break;
2149*7c478bd9Sstevel@tonic-gate 		}
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate 		if (EQ("bootp") || EQ("dhcp")) {
2152*7c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_LINK);
2153*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_CONST);
2154*7c478bd9Sstevel@tonic-gate 			emitval(9);
2155*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_OCTET);
2156*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_CONST);
2157*7c478bd9Sstevel@tonic-gate 			emitval(IPPROTO_UDP);
2158*7c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_IP);
2159*7c478bd9Sstevel@tonic-gate 			compare_value(0, 4,
2160*7c478bd9Sstevel@tonic-gate 			    (IPPORT_BOOTPS << 16 | IPPORT_BOOTPC));
2161*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
2162*7c478bd9Sstevel@tonic-gate 			m = chain(0);
2163*7c478bd9Sstevel@tonic-gate 			compare_value(0, 4,
2164*7c478bd9Sstevel@tonic-gate 			    (IPPORT_BOOTPC << 16 | IPPORT_BOOTPS));
2165*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
2166*7c478bd9Sstevel@tonic-gate 			opstack++;
2167*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2168*7c478bd9Sstevel@tonic-gate 			next();
2169*7c478bd9Sstevel@tonic-gate 			break;
2170*7c478bd9Sstevel@tonic-gate 		}
2171*7c478bd9Sstevel@tonic-gate 
2172*7c478bd9Sstevel@tonic-gate 		if (EQ("ethertype")) {
2173*7c478bd9Sstevel@tonic-gate 			next();
2174*7c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
2175*7c478bd9Sstevel@tonic-gate 				pr_err("ether type expected");
2176*7c478bd9Sstevel@tonic-gate 			ethertype_match(tokenval);
2177*7c478bd9Sstevel@tonic-gate 			opstack++;
2178*7c478bd9Sstevel@tonic-gate 			next();
2179*7c478bd9Sstevel@tonic-gate 			break;
2180*7c478bd9Sstevel@tonic-gate 		}
2181*7c478bd9Sstevel@tonic-gate 
2182*7c478bd9Sstevel@tonic-gate 		if (EQ("pppoe")) {
2183*7c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_PPPOED);
2184*7c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_PPPOES);
2185*7c478bd9Sstevel@tonic-gate 			emitop(OP_OR);
2186*7c478bd9Sstevel@tonic-gate 			opstack++;
2187*7c478bd9Sstevel@tonic-gate 			next();
2188*7c478bd9Sstevel@tonic-gate 			break;
2189*7c478bd9Sstevel@tonic-gate 		}
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 		if (EQ("inet")) {
2192*7c478bd9Sstevel@tonic-gate 			next();
2193*7c478bd9Sstevel@tonic-gate 			if (EQ("host"))
2194*7c478bd9Sstevel@tonic-gate 				next();
2195*7c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP)
2196*7c478bd9Sstevel@tonic-gate 				pr_err("host/IPv4 addr expected after inet");
2197*7c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV4_ONLY);
2198*7c478bd9Sstevel@tonic-gate 			opstack++;
2199*7c478bd9Sstevel@tonic-gate 			next();
2200*7c478bd9Sstevel@tonic-gate 			break;
2201*7c478bd9Sstevel@tonic-gate 		}
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate 		if (EQ("inet6")) {
2204*7c478bd9Sstevel@tonic-gate 			next();
2205*7c478bd9Sstevel@tonic-gate 			if (EQ("host"))
2206*7c478bd9Sstevel@tonic-gate 				next();
2207*7c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
2208*7c478bd9Sstevel@tonic-gate 				pr_err("host/IPv6 addr expected after inet6");
2209*7c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV6_ONLY);
2210*7c478bd9Sstevel@tonic-gate 			opstack++;
2211*7c478bd9Sstevel@tonic-gate 			next();
2212*7c478bd9Sstevel@tonic-gate 			break;
2213*7c478bd9Sstevel@tonic-gate 		}
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 		if (EQ("length")) {
2216*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
2217*7c478bd9Sstevel@tonic-gate 			opstack++;
2218*7c478bd9Sstevel@tonic-gate 			next();
2219*7c478bd9Sstevel@tonic-gate 			break;
2220*7c478bd9Sstevel@tonic-gate 		}
2221*7c478bd9Sstevel@tonic-gate 
2222*7c478bd9Sstevel@tonic-gate 		if (EQ("less")) {
2223*7c478bd9Sstevel@tonic-gate 			next();
2224*7c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
2225*7c478bd9Sstevel@tonic-gate 				pr_err("packet length expected");
2226*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
2227*7c478bd9Sstevel@tonic-gate 			load_const(tokenval);
2228*7c478bd9Sstevel@tonic-gate 			emitop(OP_LT);
2229*7c478bd9Sstevel@tonic-gate 			opstack++;
2230*7c478bd9Sstevel@tonic-gate 			next();
2231*7c478bd9Sstevel@tonic-gate 			break;
2232*7c478bd9Sstevel@tonic-gate 		}
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 		if (EQ("greater")) {
2235*7c478bd9Sstevel@tonic-gate 			next();
2236*7c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
2237*7c478bd9Sstevel@tonic-gate 				pr_err("packet length expected");
2238*7c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
2239*7c478bd9Sstevel@tonic-gate 			load_const(tokenval);
2240*7c478bd9Sstevel@tonic-gate 			emitop(OP_GT);
2241*7c478bd9Sstevel@tonic-gate 			opstack++;
2242*7c478bd9Sstevel@tonic-gate 			next();
2243*7c478bd9Sstevel@tonic-gate 			break;
2244*7c478bd9Sstevel@tonic-gate 		}
2245*7c478bd9Sstevel@tonic-gate 
2246*7c478bd9Sstevel@tonic-gate 		if (EQ("nofrag")) {
2247*7c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_LINK);
2248*7c478bd9Sstevel@tonic-gate 			compare_value_mask(6, 2, 0, 0x1fff);
2249*7c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_POP);
2250*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRFL);
2251*7c478bd9Sstevel@tonic-gate 			m = chain(0);
2252*7c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_IP);
2253*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
2254*7c478bd9Sstevel@tonic-gate 			opstack++;
2255*7c478bd9Sstevel@tonic-gate 			next();
2256*7c478bd9Sstevel@tonic-gate 			break;
2257*7c478bd9Sstevel@tonic-gate 		}
2258*7c478bd9Sstevel@tonic-gate 
2259*7c478bd9Sstevel@tonic-gate 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
2260*7c478bd9Sstevel@tonic-gate 			if (EQ("dstnet"))
2261*7c478bd9Sstevel@tonic-gate 				dir = TO;
2262*7c478bd9Sstevel@tonic-gate 			else if (EQ("srcnet"))
2263*7c478bd9Sstevel@tonic-gate 				dir = FROM;
2264*7c478bd9Sstevel@tonic-gate 			next();
2265*7c478bd9Sstevel@tonic-gate 			netaddr_match(dir, token);
2266*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2267*7c478bd9Sstevel@tonic-gate 			opstack++;
2268*7c478bd9Sstevel@tonic-gate 			next();
2269*7c478bd9Sstevel@tonic-gate 			break;
2270*7c478bd9Sstevel@tonic-gate 		}
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 		if (EQ("port") || EQ("srcport") || EQ("dstport")) {
2273*7c478bd9Sstevel@tonic-gate 			if (EQ("dstport"))
2274*7c478bd9Sstevel@tonic-gate 				dir = TO;
2275*7c478bd9Sstevel@tonic-gate 			else if (EQ("srcport"))
2276*7c478bd9Sstevel@tonic-gate 				dir = FROM;
2277*7c478bd9Sstevel@tonic-gate 			next();
2278*7c478bd9Sstevel@tonic-gate 			port_match(dir, token);
2279*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2280*7c478bd9Sstevel@tonic-gate 			opstack++;
2281*7c478bd9Sstevel@tonic-gate 			next();
2282*7c478bd9Sstevel@tonic-gate 			break;
2283*7c478bd9Sstevel@tonic-gate 		}
2284*7c478bd9Sstevel@tonic-gate 
2285*7c478bd9Sstevel@tonic-gate 		if (EQ("rpc")) {
2286*7c478bd9Sstevel@tonic-gate 			uint_t vers, proc;
2287*7c478bd9Sstevel@tonic-gate 			char savetoken[32];
2288*7c478bd9Sstevel@tonic-gate 
2289*7c478bd9Sstevel@tonic-gate 			vers = proc = -1;
2290*7c478bd9Sstevel@tonic-gate 			next();
2291*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(savetoken, token, sizeof (savetoken));
2292*7c478bd9Sstevel@tonic-gate 			next();
2293*7c478bd9Sstevel@tonic-gate 			if (*token == ',') {
2294*7c478bd9Sstevel@tonic-gate 				next();
2295*7c478bd9Sstevel@tonic-gate 				if (tokentype != NUMBER)
2296*7c478bd9Sstevel@tonic-gate 					pr_err("version number expected");
2297*7c478bd9Sstevel@tonic-gate 				vers = tokenval;
2298*7c478bd9Sstevel@tonic-gate 				next();
2299*7c478bd9Sstevel@tonic-gate 			}
2300*7c478bd9Sstevel@tonic-gate 			if (*token == ',') {
2301*7c478bd9Sstevel@tonic-gate 				next();
2302*7c478bd9Sstevel@tonic-gate 				if (tokentype != NUMBER)
2303*7c478bd9Sstevel@tonic-gate 					pr_err("proc number expected");
2304*7c478bd9Sstevel@tonic-gate 				proc = tokenval;
2305*7c478bd9Sstevel@tonic-gate 				next();
2306*7c478bd9Sstevel@tonic-gate 			}
2307*7c478bd9Sstevel@tonic-gate 			rpc_match_prog(dir, savetoken, vers, proc);
2308*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2309*7c478bd9Sstevel@tonic-gate 			opstack++;
2310*7c478bd9Sstevel@tonic-gate 			break;
2311*7c478bd9Sstevel@tonic-gate 		}
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate 		if (EQ("slp")) {
2314*7c478bd9Sstevel@tonic-gate 		    /* filter out TCP handshakes */
2315*7c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_LINK);
2316*7c478bd9Sstevel@tonic-gate 		    compare_value(9, 1, IPPROTO_TCP);
2317*7c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_CONST);
2318*7c478bd9Sstevel@tonic-gate 		    emitval(52);
2319*7c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_CONST);
2320*7c478bd9Sstevel@tonic-gate 		    emitval(2);
2321*7c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_SHORT);
2322*7c478bd9Sstevel@tonic-gate 		    emitop(OP_GE);
2323*7c478bd9Sstevel@tonic-gate 		    emitop(OP_AND);	/* proto == TCP && len < 52 */
2324*7c478bd9Sstevel@tonic-gate 		    emitop(OP_NOT);
2325*7c478bd9Sstevel@tonic-gate 		    emitop(OP_BRFL);	/* pkt too short to be a SLP call */
2326*7c478bd9Sstevel@tonic-gate 		    m = chain(0);
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_POP);
2329*7c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_SLP);
2330*7c478bd9Sstevel@tonic-gate 		    resolve_chain(m);
2331*7c478bd9Sstevel@tonic-gate 		    opstack++;
2332*7c478bd9Sstevel@tonic-gate 		    next();
2333*7c478bd9Sstevel@tonic-gate 		    break;
2334*7c478bd9Sstevel@tonic-gate 		}
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate 		if (EQ("ldap")) {
2337*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2338*7c478bd9Sstevel@tonic-gate 			port_match(dir, "ldap");
2339*7c478bd9Sstevel@tonic-gate 			opstack++;
2340*7c478bd9Sstevel@tonic-gate 			next();
2341*7c478bd9Sstevel@tonic-gate 			break;
2342*7c478bd9Sstevel@tonic-gate 		}
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate 		if (EQ("and") || EQ("or")) {
2345*7c478bd9Sstevel@tonic-gate 			break;
2346*7c478bd9Sstevel@tonic-gate 		}
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 		if (EQ("gateway")) {
2349*7c478bd9Sstevel@tonic-gate 			next();
2350*7c478bd9Sstevel@tonic-gate 			if (eaddr || tokentype != ALPHA)
2351*7c478bd9Sstevel@tonic-gate 				pr_err("hostname required: %s", token);
2352*7c478bd9Sstevel@tonic-gate 			etheraddr_match(dir, token);
2353*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2354*7c478bd9Sstevel@tonic-gate 			emitop(OP_BRFL);
2355*7c478bd9Sstevel@tonic-gate 			m = chain(0);
2356*7c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV4_AND_IPV6);
2357*7c478bd9Sstevel@tonic-gate 			emitop(OP_NOT);
2358*7c478bd9Sstevel@tonic-gate 			resolve_chain(m);
2359*7c478bd9Sstevel@tonic-gate 			opstack++;
2360*7c478bd9Sstevel@tonic-gate 			next();
2361*7c478bd9Sstevel@tonic-gate 		}
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 		if (EQ("host") || EQ("between") ||
2364*7c478bd9Sstevel@tonic-gate 		    tokentype == ALPHA ||	/* assume its a hostname */
2365*7c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP ||
2366*7c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP6 ||
2367*7c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_AT ||
2368*7c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_ETHER) {
2369*7c478bd9Sstevel@tonic-gate 			if (EQ("host") || EQ("between"))
2370*7c478bd9Sstevel@tonic-gate 				next();
2371*7c478bd9Sstevel@tonic-gate 			if (eaddr || tokentype == ADDR_ETHER) {
2372*7c478bd9Sstevel@tonic-gate 				etheraddr_match(dir, token);
2373*7c478bd9Sstevel@tonic-gate 			} else if (tokentype == ALPHA) {
2374*7c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV4_AND_IPV6);
2375*7c478bd9Sstevel@tonic-gate 			} else if (tokentype == ADDR_AT) {
2376*7c478bd9Sstevel@tonic-gate 				ataddr_match(dir, token);
2377*7c478bd9Sstevel@tonic-gate 			} else if (tokentype == ADDR_IP) {
2378*7c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV4_ONLY);
2379*7c478bd9Sstevel@tonic-gate 			} else {
2380*7c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV6_ONLY);
2381*7c478bd9Sstevel@tonic-gate 			}
2382*7c478bd9Sstevel@tonic-gate 			dir = ANY;
2383*7c478bd9Sstevel@tonic-gate 			eaddr = 0;
2384*7c478bd9Sstevel@tonic-gate 			opstack++;
2385*7c478bd9Sstevel@tonic-gate 			next();
2386*7c478bd9Sstevel@tonic-gate 			break;
2387*7c478bd9Sstevel@tonic-gate 		}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 		if (tokentype == NUMBER) {
2390*7c478bd9Sstevel@tonic-gate 			load_const(tokenval);
2391*7c478bd9Sstevel@tonic-gate 			opstack++;
2392*7c478bd9Sstevel@tonic-gate 			next();
2393*7c478bd9Sstevel@tonic-gate 			break;
2394*7c478bd9Sstevel@tonic-gate 		}
2395*7c478bd9Sstevel@tonic-gate 
2396*7c478bd9Sstevel@tonic-gate 		break;	/* unknown token */
2397*7c478bd9Sstevel@tonic-gate 	}
2398*7c478bd9Sstevel@tonic-gate }
2399*7c478bd9Sstevel@tonic-gate 
2400*7c478bd9Sstevel@tonic-gate struct optable {
2401*7c478bd9Sstevel@tonic-gate 	char *op_tok;
2402*7c478bd9Sstevel@tonic-gate 	enum optype op_type;
2403*7c478bd9Sstevel@tonic-gate };
2404*7c478bd9Sstevel@tonic-gate 
2405*7c478bd9Sstevel@tonic-gate static struct optable
2406*7c478bd9Sstevel@tonic-gate mulops[] = {
2407*7c478bd9Sstevel@tonic-gate 	"*",	OP_MUL,
2408*7c478bd9Sstevel@tonic-gate 	"/",	OP_DIV,
2409*7c478bd9Sstevel@tonic-gate 	"%",	OP_REM,
2410*7c478bd9Sstevel@tonic-gate 	"&",	OP_AND,
2411*7c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
2412*7c478bd9Sstevel@tonic-gate };
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate static struct optable
2415*7c478bd9Sstevel@tonic-gate addops[] = {
2416*7c478bd9Sstevel@tonic-gate 	"+",	OP_ADD,
2417*7c478bd9Sstevel@tonic-gate 	"-",	OP_SUB,
2418*7c478bd9Sstevel@tonic-gate 	"|",	OP_OR,
2419*7c478bd9Sstevel@tonic-gate 	"^",	OP_XOR,
2420*7c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
2421*7c478bd9Sstevel@tonic-gate };
2422*7c478bd9Sstevel@tonic-gate 
2423*7c478bd9Sstevel@tonic-gate static struct optable
2424*7c478bd9Sstevel@tonic-gate compareops[] = {
2425*7c478bd9Sstevel@tonic-gate 	"==",	OP_EQ,
2426*7c478bd9Sstevel@tonic-gate 	"=",	OP_EQ,
2427*7c478bd9Sstevel@tonic-gate 	"!=",	OP_NE,
2428*7c478bd9Sstevel@tonic-gate 	">",	OP_GT,
2429*7c478bd9Sstevel@tonic-gate 	">=",	OP_GE,
2430*7c478bd9Sstevel@tonic-gate 	"<",	OP_LT,
2431*7c478bd9Sstevel@tonic-gate 	"<=",	OP_LE,
2432*7c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
2433*7c478bd9Sstevel@tonic-gate };
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate /*
2436*7c478bd9Sstevel@tonic-gate  * Using the table, find the operator
2437*7c478bd9Sstevel@tonic-gate  * that corresponds to the token.
2438*7c478bd9Sstevel@tonic-gate  * Return 0 if not found.
2439*7c478bd9Sstevel@tonic-gate  */
2440*7c478bd9Sstevel@tonic-gate static int
2441*7c478bd9Sstevel@tonic-gate find_op(char *tok, struct optable *table)
2442*7c478bd9Sstevel@tonic-gate {
2443*7c478bd9Sstevel@tonic-gate 	struct optable *op;
2444*7c478bd9Sstevel@tonic-gate 
2445*7c478bd9Sstevel@tonic-gate 	for (op = table; *op->op_tok; op++) {
2446*7c478bd9Sstevel@tonic-gate 		if (strcmp(tok, op->op_tok) == 0)
2447*7c478bd9Sstevel@tonic-gate 			return (op->op_type);
2448*7c478bd9Sstevel@tonic-gate 	}
2449*7c478bd9Sstevel@tonic-gate 
2450*7c478bd9Sstevel@tonic-gate 	return (0);
2451*7c478bd9Sstevel@tonic-gate }
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate static void
2454*7c478bd9Sstevel@tonic-gate expr_mul()
2455*7c478bd9Sstevel@tonic-gate {
2456*7c478bd9Sstevel@tonic-gate 	int op;
2457*7c478bd9Sstevel@tonic-gate 	int s = opstack;
2458*7c478bd9Sstevel@tonic-gate 
2459*7c478bd9Sstevel@tonic-gate 	primary();
2460*7c478bd9Sstevel@tonic-gate 	while (op = find_op(token, mulops)) {
2461*7c478bd9Sstevel@tonic-gate 		next();
2462*7c478bd9Sstevel@tonic-gate 		primary();
2463*7c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
2464*7c478bd9Sstevel@tonic-gate 		emitop(op);
2465*7c478bd9Sstevel@tonic-gate 		opstack--;
2466*7c478bd9Sstevel@tonic-gate 	}
2467*7c478bd9Sstevel@tonic-gate }
2468*7c478bd9Sstevel@tonic-gate 
2469*7c478bd9Sstevel@tonic-gate static void
2470*7c478bd9Sstevel@tonic-gate expr_add()
2471*7c478bd9Sstevel@tonic-gate {
2472*7c478bd9Sstevel@tonic-gate 	int op, s = opstack;
2473*7c478bd9Sstevel@tonic-gate 
2474*7c478bd9Sstevel@tonic-gate 	expr_mul();
2475*7c478bd9Sstevel@tonic-gate 	while (op = find_op(token, addops)) {
2476*7c478bd9Sstevel@tonic-gate 		next();
2477*7c478bd9Sstevel@tonic-gate 		expr_mul();
2478*7c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
2479*7c478bd9Sstevel@tonic-gate 		emitop(op);
2480*7c478bd9Sstevel@tonic-gate 		opstack--;
2481*7c478bd9Sstevel@tonic-gate 	}
2482*7c478bd9Sstevel@tonic-gate }
2483*7c478bd9Sstevel@tonic-gate 
2484*7c478bd9Sstevel@tonic-gate static void
2485*7c478bd9Sstevel@tonic-gate expr_compare()
2486*7c478bd9Sstevel@tonic-gate {
2487*7c478bd9Sstevel@tonic-gate 	int op, s = opstack;
2488*7c478bd9Sstevel@tonic-gate 
2489*7c478bd9Sstevel@tonic-gate 	expr_add();
2490*7c478bd9Sstevel@tonic-gate 	while (op = find_op(token, compareops)) {
2491*7c478bd9Sstevel@tonic-gate 		next();
2492*7c478bd9Sstevel@tonic-gate 		expr_add();
2493*7c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
2494*7c478bd9Sstevel@tonic-gate 		emitop(op);
2495*7c478bd9Sstevel@tonic-gate 		opstack--;
2496*7c478bd9Sstevel@tonic-gate 	}
2497*7c478bd9Sstevel@tonic-gate }
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate /*
2500*7c478bd9Sstevel@tonic-gate  * Alternation ("and") is difficult because
2501*7c478bd9Sstevel@tonic-gate  * an implied "and" is acknowledge between
2502*7c478bd9Sstevel@tonic-gate  * two adjacent primaries.  Just keep calling
2503*7c478bd9Sstevel@tonic-gate  * the lower-level expression routine until
2504*7c478bd9Sstevel@tonic-gate  * no value is added to the opstack.
2505*7c478bd9Sstevel@tonic-gate  */
2506*7c478bd9Sstevel@tonic-gate static void
2507*7c478bd9Sstevel@tonic-gate alternation()
2508*7c478bd9Sstevel@tonic-gate {
2509*7c478bd9Sstevel@tonic-gate 	int m = 0;
2510*7c478bd9Sstevel@tonic-gate 	int s = opstack;
2511*7c478bd9Sstevel@tonic-gate 
2512*7c478bd9Sstevel@tonic-gate 	expr_compare();
2513*7c478bd9Sstevel@tonic-gate 	checkstack(s + 1);
2514*7c478bd9Sstevel@tonic-gate 	for (;;) {
2515*7c478bd9Sstevel@tonic-gate 		if (EQ("and"))
2516*7c478bd9Sstevel@tonic-gate 			next();
2517*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
2518*7c478bd9Sstevel@tonic-gate 		m = chain(m);
2519*7c478bd9Sstevel@tonic-gate 		expr_compare();
2520*7c478bd9Sstevel@tonic-gate 		if (opstack != s + 2)
2521*7c478bd9Sstevel@tonic-gate 			break;
2522*7c478bd9Sstevel@tonic-gate 		opstack--;
2523*7c478bd9Sstevel@tonic-gate 	}
2524*7c478bd9Sstevel@tonic-gate 	unemit(2);
2525*7c478bd9Sstevel@tonic-gate 	resolve_chain(m);
2526*7c478bd9Sstevel@tonic-gate }
2527*7c478bd9Sstevel@tonic-gate 
2528*7c478bd9Sstevel@tonic-gate static void
2529*7c478bd9Sstevel@tonic-gate expression()
2530*7c478bd9Sstevel@tonic-gate {
2531*7c478bd9Sstevel@tonic-gate 	int m = 0;
2532*7c478bd9Sstevel@tonic-gate 	int s = opstack;
2533*7c478bd9Sstevel@tonic-gate 
2534*7c478bd9Sstevel@tonic-gate 	alternation();
2535*7c478bd9Sstevel@tonic-gate 	while (EQ("or") || EQ(",")) {
2536*7c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
2537*7c478bd9Sstevel@tonic-gate 		m = chain(m);
2538*7c478bd9Sstevel@tonic-gate 		next();
2539*7c478bd9Sstevel@tonic-gate 		alternation();
2540*7c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
2541*7c478bd9Sstevel@tonic-gate 		opstack--;
2542*7c478bd9Sstevel@tonic-gate 	}
2543*7c478bd9Sstevel@tonic-gate 	resolve_chain(m);
2544*7c478bd9Sstevel@tonic-gate }
2545*7c478bd9Sstevel@tonic-gate 
2546*7c478bd9Sstevel@tonic-gate /*
2547*7c478bd9Sstevel@tonic-gate  * Take n args from the argv list
2548*7c478bd9Sstevel@tonic-gate  * and concatenate them into a single string.
2549*7c478bd9Sstevel@tonic-gate  */
2550*7c478bd9Sstevel@tonic-gate char *
2551*7c478bd9Sstevel@tonic-gate concat_args(char **argv, int argc)
2552*7c478bd9Sstevel@tonic-gate {
2553*7c478bd9Sstevel@tonic-gate 	int i, len;
2554*7c478bd9Sstevel@tonic-gate 	char *str, *p;
2555*7c478bd9Sstevel@tonic-gate 
2556*7c478bd9Sstevel@tonic-gate 	/* First add the lengths of all the strings */
2557*7c478bd9Sstevel@tonic-gate 	len = 0;
2558*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++)
2559*7c478bd9Sstevel@tonic-gate 		len += strlen(argv[i]) + 1;
2560*7c478bd9Sstevel@tonic-gate 
2561*7c478bd9Sstevel@tonic-gate 	/* allocate the big string */
2562*7c478bd9Sstevel@tonic-gate 	str = (char *)malloc(len);
2563*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
2564*7c478bd9Sstevel@tonic-gate 		pr_err("no mem");
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate 	p = str;
2567*7c478bd9Sstevel@tonic-gate 
2568*7c478bd9Sstevel@tonic-gate 	/*
2569*7c478bd9Sstevel@tonic-gate 	 * Concat the strings into the big
2570*7c478bd9Sstevel@tonic-gate 	 * string using a space as separator
2571*7c478bd9Sstevel@tonic-gate 	 */
2572*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
2573*7c478bd9Sstevel@tonic-gate 		strcpy(p, argv[i]);
2574*7c478bd9Sstevel@tonic-gate 		p += strlen(p);
2575*7c478bd9Sstevel@tonic-gate 		*p++ = ' ';
2576*7c478bd9Sstevel@tonic-gate 	}
2577*7c478bd9Sstevel@tonic-gate 	*--p = '\0';
2578*7c478bd9Sstevel@tonic-gate 
2579*7c478bd9Sstevel@tonic-gate 	return (str);
2580*7c478bd9Sstevel@tonic-gate }
2581*7c478bd9Sstevel@tonic-gate 
2582*7c478bd9Sstevel@tonic-gate /*
2583*7c478bd9Sstevel@tonic-gate  * Take the expression in the string "expr"
2584*7c478bd9Sstevel@tonic-gate  * and compile it into the code array.
2585*7c478bd9Sstevel@tonic-gate  * Print the generated code if the print
2586*7c478bd9Sstevel@tonic-gate  * arg is set.
2587*7c478bd9Sstevel@tonic-gate  */
2588*7c478bd9Sstevel@tonic-gate void
2589*7c478bd9Sstevel@tonic-gate compile(char *expr, int print)
2590*7c478bd9Sstevel@tonic-gate {
2591*7c478bd9Sstevel@tonic-gate 	expr = strdup(expr);
2592*7c478bd9Sstevel@tonic-gate 	if (expr == NULL)
2593*7c478bd9Sstevel@tonic-gate 		pr_err("no mem");
2594*7c478bd9Sstevel@tonic-gate 	curr_op = oplist;
2595*7c478bd9Sstevel@tonic-gate 	tkp = expr;
2596*7c478bd9Sstevel@tonic-gate 	dir = ANY;
2597*7c478bd9Sstevel@tonic-gate 
2598*7c478bd9Sstevel@tonic-gate 	next();
2599*7c478bd9Sstevel@tonic-gate 	if (tokentype != EOL)
2600*7c478bd9Sstevel@tonic-gate 		expression();
2601*7c478bd9Sstevel@tonic-gate 	emitop(OP_STOP);
2602*7c478bd9Sstevel@tonic-gate 	if (tokentype != EOL)
2603*7c478bd9Sstevel@tonic-gate 		pr_err("invalid expression");
2604*7c478bd9Sstevel@tonic-gate 	optimize(oplist);
2605*7c478bd9Sstevel@tonic-gate 	if (print)
2606*7c478bd9Sstevel@tonic-gate 		codeprint();
2607*7c478bd9Sstevel@tonic-gate }
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate /*
2610*7c478bd9Sstevel@tonic-gate  * Lookup hostname in the arp cache.
2611*7c478bd9Sstevel@tonic-gate  */
2612*7c478bd9Sstevel@tonic-gate boolean_t
2613*7c478bd9Sstevel@tonic-gate arp_for_ether(char *hostname, struct ether_addr *ep)
2614*7c478bd9Sstevel@tonic-gate {
2615*7c478bd9Sstevel@tonic-gate 	struct arpreq ar;
2616*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
2617*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
2618*7c478bd9Sstevel@tonic-gate 	int error_num;
2619*7c478bd9Sstevel@tonic-gate 	int s;
2620*7c478bd9Sstevel@tonic-gate 
2621*7c478bd9Sstevel@tonic-gate 	memset(&ar, 0, sizeof (ar));
2622*7c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ar.arp_pa;
2623*7c478bd9Sstevel@tonic-gate 	sin->sin_family = AF_INET;
2624*7c478bd9Sstevel@tonic-gate 	hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
2625*7c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
2626*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2627*7c478bd9Sstevel@tonic-gate 	}
2628*7c478bd9Sstevel@tonic-gate 	memcpy(&sin->sin_addr, hp->h_addr, sizeof (sin->sin_addr));
2629*7c478bd9Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
2630*7c478bd9Sstevel@tonic-gate 	if (s < 0) {
2631*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2632*7c478bd9Sstevel@tonic-gate 	}
2633*7c478bd9Sstevel@tonic-gate 	if (ioctl(s, SIOCGARP, &ar) < 0) {
2634*7c478bd9Sstevel@tonic-gate 		close(s);
2635*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2636*7c478bd9Sstevel@tonic-gate 	}
2637*7c478bd9Sstevel@tonic-gate 	close(s);
2638*7c478bd9Sstevel@tonic-gate 	memcpy(ep->ether_addr_octet, ar.arp_ha.sa_data, sizeof (*ep));
2639*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
2640*7c478bd9Sstevel@tonic-gate }
2641