17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d6f299a8Sdg  * Common Development and Distribution License (the "License").
6d6f299a8Sdg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
222b24ab6bSSebastien Roy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247d897698SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <stddef.h>
362b24ab6bSSebastien Roy #include <unistd.h>
372b24ab6bSSebastien Roy #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <sys/socket.h>
397c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
40605445d5Sdg #include <sys/vlan.h>
417c478bd9Sstevel@tonic-gate #include <net/if.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in.h>
437c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
447c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip.h>
467c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
477c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
487c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
497c478bd9Sstevel@tonic-gate #include <netdb.h>
507c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
517c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
527c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
53b127ac41SPhilip Kirk #include <sys/dlpi.h>
557c478bd9Sstevel@tonic-gate #include <snoop.h>
56605445d5Sdg #include "snoop_vlan.h"
587c478bd9Sstevel@tonic-gate #define	IPV4_ONLY	0
597c478bd9Sstevel@tonic-gate #define	IPV6_ONLY	1
607c478bd9Sstevel@tonic-gate #define	IPV4_AND_IPV6	2
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * The following constants represent the offsets in bytes from the beginning
647c478bd9Sstevel@tonic-gate  * of the IP(v6) header of the source and destination IP(v6) addresses.
657c478bd9Sstevel@tonic-gate  * These are useful when generating filter code.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate #define	IPV4_SRCADDR_OFFSET	12
687c478bd9Sstevel@tonic-gate #define	IPV4_DSTADDR_OFFSET	16
697c478bd9Sstevel@tonic-gate #define	IPV6_SRCADDR_OFFSET	8
707c478bd9Sstevel@tonic-gate #define	IPV6_DSTADDR_OFFSET	24
717c478bd9Sstevel@tonic-gate #define	IP_VERS(p)	(((*(uchar_t *)p) & 0xf0) >> 4)
727c478bd9Sstevel@tonic-gate #define	MASKED_IPV4_VERS	0x40
737c478bd9Sstevel@tonic-gate #define	MASKED_IPV6_VERS	0x60
747c478bd9Sstevel@tonic-gate #define	IP_HDR_LEN(p)	(((*(uchar_t *)p) & 0xf) * 4)
757c478bd9Sstevel@tonic-gate #define	TCP_HDR_LEN(p)	((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4)
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * Coding the constant below is tacky, but the compiler won't let us
797c478bd9Sstevel@tonic-gate  * be more clever.  E.g., &((struct ip *)0)->ip_xxx
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate #define	IP_PROTO_OF(p)	(((uchar_t *)p)[9])
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * AppleTalk uses 802.2 Ethernet encapsulation with LLC/SNAP headers,
857c478bd9Sstevel@tonic-gate  * for 8 octets of overhead, and the common AppleTalk DDP Ethernet
867c478bd9Sstevel@tonic-gate  * header is another 4 octets.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * The following constants represents the offsets in bytes from the beginning
897c478bd9Sstevel@tonic-gate  * of the Ethernet payload to various parts of the DDP header.
907c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate #define	AT_DST_NET_OFFSET	12
937c478bd9Sstevel@tonic-gate #define	AT_SRC_NET_OFFSET	14
947c478bd9Sstevel@tonic-gate #define	AT_DST_NODE_OFFSET	16
957c478bd9Sstevel@tonic-gate #define	AT_SRC_NODE_OFFSET	17
97b127ac41SPhilip Kirk /*
98b127ac41SPhilip Kirk  * Offset for the source and destination zoneid in the ipnet header.
99b127ac41SPhilip Kirk  */
1000a0e9771SDarren Reed #define	IPNET_SRCZONE_OFFSET 16
1010a0e9771SDarren Reed #define	IPNET_DSTZONE_OFFSET 20
102b127ac41SPhilip Kirk 
1037c478bd9Sstevel@tonic-gate int eaddr;	/* need ethernet addr */
1057c478bd9Sstevel@tonic-gate int opstack;	/* operand stack depth */
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * These are the operators of the user-level filter.
1097c478bd9Sstevel@tonic-gate  * STOP ends execution of the filter expression and
1107c478bd9Sstevel@tonic-gate  * returns the truth value at the top of the stack.
1117c478bd9Sstevel@tonic-gate  * OP_LOAD_OCTET, OP_LOAD_SHORT and OP_LOAD_LONG pop
1127c478bd9Sstevel@tonic-gate  * an offset value from the stack and load a value of
1137c478bd9Sstevel@tonic-gate  * an appropriate size from the packet (octet, short or
1147c478bd9Sstevel@tonic-gate  * long).  The offset is computed from a base value that
1157c478bd9Sstevel@tonic-gate  * may be set via the OP_OFFSET operators.
1167c478bd9Sstevel@tonic-gate  * OP_EQ, OP_NE, OP_GT, OP_GE, OP_LT, OP_LE pop two values
1177c478bd9Sstevel@tonic-gate  * from the stack and return the result of their comparison.
1187c478bd9Sstevel@tonic-gate  * OP_AND, OP_OR, OP_XOR pop two values from the stack and
1197c478bd9Sstevel@tonic-gate  * do perform a bitwise operation on them - returning a result
1207c478bd9Sstevel@tonic-gate  * to the stack.  OP_NOT inverts the bits of the value on the
1217c478bd9Sstevel@tonic-gate  * stack.
1227c478bd9Sstevel@tonic-gate  * OP_BRFL and OP_BRTR branch to an offset in the code array
1237c478bd9Sstevel@tonic-gate  * depending on the value at the top of the stack: true (not 0)
1247c478bd9Sstevel@tonic-gate  * or false (0).
1257c478bd9Sstevel@tonic-gate  * OP_ADD, OP_SUB, OP_MUL, OP_DIV and OP_REM pop two values
1267c478bd9Sstevel@tonic-gate  * from the stack and perform arithmetic.
1277c478bd9Sstevel@tonic-gate  * The OP_OFFSET operators change the base from which the
1287c478bd9Sstevel@tonic-gate  * OP_LOAD operators compute their offsets.
1297c478bd9Sstevel@tonic-gate  * OP_OFFSET_ZERO sets the offset to zero - beginning of packet.
1307c478bd9Sstevel@tonic-gate  * OP_OFFSET_LINK sets the base to the first octet after
1317c478bd9Sstevel@tonic-gate  * the link (DLC) header.  OP_OFFSET_IP, OP_OFFSET_TCP,
1327c478bd9Sstevel@tonic-gate  * and OP_OFFSET_UDP do the same for those headers - they
1337c478bd9Sstevel@tonic-gate  * set the offset base to the *end* of the header - not the
1347c478bd9Sstevel@tonic-gate  * beginning.  The OP_OFFSET_RPC operator is a bit unusual.
1357c478bd9Sstevel@tonic-gate  * It points the base at the cached RPC header.  For the
1367c478bd9Sstevel@tonic-gate  * purposes of selection, RPC reply headers look like call
1377c478bd9Sstevel@tonic-gate  * headers except for the direction value.
138605445d5Sdg  * OP_OFFSET_ETHERTYPE sets base according to the following
139605445d5Sdg  * algorithm:
140605445d5Sdg  *   if the packet is not VLAN tagged, then set base to
141605445d5Sdg  *         the ethertype field in the ethernet header
142605445d5Sdg  *   else set base to the ethertype field of the VLAN header
1437c478bd9Sstevel@tonic-gate  * OP_OFFSET_POP restores the offset base to the value prior
1447c478bd9Sstevel@tonic-gate  * to the most recent OP_OFFSET call.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate enum optype {
1477c478bd9Sstevel@tonic-gate 	OP_STOP = 0,
1487c478bd9Sstevel@tonic-gate 	OP_LOAD_OCTET,
1497c478bd9Sstevel@tonic-gate 	OP_LOAD_SHORT,
1507c478bd9Sstevel@tonic-gate 	OP_LOAD_LONG,
1517c478bd9Sstevel@tonic-gate 	OP_LOAD_CONST,
1527c478bd9Sstevel@tonic-gate 	OP_LOAD_LENGTH,
1537c478bd9Sstevel@tonic-gate 	OP_EQ,
1547c478bd9Sstevel@tonic-gate 	OP_NE,
1557c478bd9Sstevel@tonic-gate 	OP_GT,
1567c478bd9Sstevel@tonic-gate 	OP_GE,
1577c478bd9Sstevel@tonic-gate 	OP_LT,
1587c478bd9Sstevel@tonic-gate 	OP_LE,
1597c478bd9Sstevel@tonic-gate 	OP_AND,
1607c478bd9Sstevel@tonic-gate 	OP_OR,
1617c478bd9Sstevel@tonic-gate 	OP_XOR,
1627c478bd9Sstevel@tonic-gate 	OP_NOT,
1637c478bd9Sstevel@tonic-gate 	OP_BRFL,
1647c478bd9Sstevel@tonic-gate 	OP_BRTR,
1657c478bd9Sstevel@tonic-gate 	OP_ADD,
1667c478bd9Sstevel@tonic-gate 	OP_SUB,
1677c478bd9Sstevel@tonic-gate 	OP_MUL,
1687c478bd9Sstevel@tonic-gate 	OP_DIV,
1697c478bd9Sstevel@tonic-gate 	OP_REM,
1707c478bd9Sstevel@tonic-gate 	OP_OFFSET_POP,
1717c478bd9Sstevel@tonic-gate 	OP_OFFSET_ZERO,
1727c478bd9Sstevel@tonic-gate 	OP_OFFSET_LINK,
1737c478bd9Sstevel@tonic-gate 	OP_OFFSET_IP,
1747c478bd9Sstevel@tonic-gate 	OP_OFFSET_TCP,
1757c478bd9Sstevel@tonic-gate 	OP_OFFSET_UDP,
1767c478bd9Sstevel@tonic-gate 	OP_OFFSET_RPC,
1777c478bd9Sstevel@tonic-gate 	OP_OFFSET_SLP,
178605445d5Sdg 	OP_OFFSET_ETHERTYPE,
1797c478bd9Sstevel@tonic-gate 	OP_LAST
1807c478bd9Sstevel@tonic-gate };
1827c478bd9Sstevel@tonic-gate static char *opnames[] = {
1837c478bd9Sstevel@tonic-gate 	"STOP",
1847c478bd9Sstevel@tonic-gate 	"LOAD_OCTET",
1857c478bd9Sstevel@tonic-gate 	"LOAD_SHORT",
1867c478bd9Sstevel@tonic-gate 	"LOAD_LONG",
1877c478bd9Sstevel@tonic-gate 	"LOAD_CONST",
1887c478bd9Sstevel@tonic-gate 	"LOAD_LENGTH",
1897c478bd9Sstevel@tonic-gate 	"EQ",
1907c478bd9Sstevel@tonic-gate 	"NE",
1917c478bd9Sstevel@tonic-gate 	"GT",
1927c478bd9Sstevel@tonic-gate 	"GE",
1937c478bd9Sstevel@tonic-gate 	"LT",
1947c478bd9Sstevel@tonic-gate 	"LE",
1957c478bd9Sstevel@tonic-gate 	"AND",
1967c478bd9Sstevel@tonic-gate 	"OR",
1977c478bd9Sstevel@tonic-gate 	"XOR",
1987c478bd9Sstevel@tonic-gate 	"NOT",
1997c478bd9Sstevel@tonic-gate 	"BRFL",
2007c478bd9Sstevel@tonic-gate 	"BRTR",
2017c478bd9Sstevel@tonic-gate 	"ADD",
2027c478bd9Sstevel@tonic-gate 	"SUB",
2037c478bd9Sstevel@tonic-gate 	"MUL",
2047c478bd9Sstevel@tonic-gate 	"DIV",
2057c478bd9Sstevel@tonic-gate 	"REM",
2067c478bd9Sstevel@tonic-gate 	"OFFSET_POP",
2077c478bd9Sstevel@tonic-gate 	"OFFSET_ZERO",
2087c478bd9Sstevel@tonic-gate 	"OFFSET_ETHER",
2097c478bd9Sstevel@tonic-gate 	"OFFSET_IP",
2107c478bd9Sstevel@tonic-gate 	"OFFSET_TCP",
2117c478bd9Sstevel@tonic-gate 	"OFFSET_UDP",
2127c478bd9Sstevel@tonic-gate 	"OFFSET_RPC",
2137c478bd9Sstevel@tonic-gate 	"OP_OFFSET_SLP",
214605445d5Sdg 	"OFFSET_ETHERTYPE",
2157c478bd9Sstevel@tonic-gate 	""
2167c478bd9Sstevel@tonic-gate };
2187c478bd9Sstevel@tonic-gate #define	MAXOPS 1024
2197c478bd9Sstevel@tonic-gate #define	MAXSS	64
2207c478bd9Sstevel@tonic-gate static uint_t oplist[MAXOPS];	/* array of operators */
2217c478bd9Sstevel@tonic-gate static uint_t *curr_op;		/* last op generated */
2237c478bd9Sstevel@tonic-gate extern int valid_slp(uchar_t *, int);	/* decides if a SLP msg is valid */
2247c478bd9Sstevel@tonic-gate extern struct hostent *lgetipnodebyname(const char *, int, int, int *);
2267c478bd9Sstevel@tonic-gate static void alternation();
2277c478bd9Sstevel@tonic-gate static uint_t chain();
2287c478bd9Sstevel@tonic-gate static void codeprint();
2297c478bd9Sstevel@tonic-gate static void emitop();
2307c478bd9Sstevel@tonic-gate static void emitval();
2317c478bd9Sstevel@tonic-gate static void expression();
2327c478bd9Sstevel@tonic-gate static struct xid_entry *find_rpc();
2337c478bd9Sstevel@tonic-gate static void optimize();
2347c478bd9Sstevel@tonic-gate static void ethertype_match();
236605445d5Sdg /*
237605445d5Sdg  * Get a ushort from a possibly unaligned character buffer.
238605445d5Sdg  *
239605445d5Sdg  * INPUTS:  buffer - where the data is.  Must be at least
240605445d5Sdg  *          sizeof(uint16_t) bytes long.
241605445d5Sdg  * OUPUTS:  An unsigned short that contains the data at buffer.
242605445d5Sdg  *          No calls to ntohs or htons are done on the data.
243605445d5Sdg  */
244605445d5Sdg static uint16_t
get_u16(uchar_t * buffer)245605445d5Sdg get_u16(uchar_t *buffer)
246605445d5Sdg {
247605445d5Sdg 	uint8_t	*bufraw = buffer;
249605445d5Sdg 	/*
250605445d5Sdg 	 * ntohs is used only as a cheap way to flip the bits
251605445d5Sdg 	 * around on a little endian platform.  The value will
252605445d5Sdg 	 * still be in host order or network order, depending on
253605445d5Sdg 	 * the order it was in when it was passed in.
254605445d5Sdg 	 */
255605445d5Sdg 	return (ntohs(bufraw[0] << 8 | bufraw[1]));
256605445d5Sdg }
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Returns the ULP for an IPv4 or IPv6 packet
2607c478bd9Sstevel@tonic-gate  * Assumes that the packet has already been checked to verify
2617c478bd9Sstevel@tonic-gate  * that it's either IPv4 or IPv6
2627c478bd9Sstevel@tonic-gate  *
2637c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
2647c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate static uchar_t
ip_proto_of(uchar_t * ip)2677c478bd9Sstevel@tonic-gate ip_proto_of(uchar_t *ip)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
2707c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
2717c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
2737c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
2747c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
2757c478bd9Sstevel@tonic-gate 		return (IP_PROTO_OF(ip));
2767c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
2787c478bd9Sstevel@tonic-gate 		nxt = ip[6];
2797c478bd9Sstevel@tonic-gate 		ptr += 40;		/* size of ip6 header */
2807c478bd9Sstevel@tonic-gate 		do {
2817c478bd9Sstevel@tonic-gate 			switch (nxt) {
2827c478bd9Sstevel@tonic-gate 			/*
2837c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
2847c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
2857c478bd9Sstevel@tonic-gate 			 */
2867c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
2877c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
2887c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
2897c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
2907c478bd9Sstevel@tonic-gate 				ptr += (8 * (ptr[1] + 1));
2917c478bd9Sstevel@tonic-gate 				nxt = *ptr;
2927c478bd9Sstevel@tonic-gate 				break;
2947c478bd9Sstevel@tonic-gate 			default:
2957c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
2967c478bd9Sstevel@tonic-gate 				break;
2977c478bd9Sstevel@tonic-gate 			}
2987c478bd9Sstevel@tonic-gate 		} while (not_done);
2997c478bd9Sstevel@tonic-gate 		return (nxt);
3007c478bd9Sstevel@tonic-gate 	default:
3017c478bd9Sstevel@tonic-gate 		break;			/* shouldn't get here... */
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	return (0);
3047c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Returns the total IP header length.
3087c478bd9Sstevel@tonic-gate  * For v4, this includes any options present.
3097c478bd9Sstevel@tonic-gate  * For v6, this is the length of the IPv6 header plus
3107c478bd9Sstevel@tonic-gate  * any extension headers present.
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
3137c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate static int
ip_hdr_len(uchar_t * ip)3167c478bd9Sstevel@tonic-gate ip_hdr_len(uchar_t *ip)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
3197c478bd9Sstevel@tonic-gate 	int		hdr_len;
3207c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
3217c478bd9Sstevel@tonic-gate 	int		len = 40;	/* IPv6 header size */
3227c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
3247c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
3257c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
3267c478bd9Sstevel@tonic-gate 		return (IP_HDR_LEN(ip));
3277c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
3287c478bd9Sstevel@tonic-gate 		nxt = ip[6];
3297c478bd9Sstevel@tonic-gate 		ptr += len;
3307c478bd9Sstevel@tonic-gate 		do {
3317c478bd9Sstevel@tonic-gate 			switch (nxt) {
3327c478bd9Sstevel@tonic-gate 			/*
3337c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
3347c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
3357c478bd9Sstevel@tonic-gate 			 */
3367c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
3377c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
3387c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
3397c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
3407c478bd9Sstevel@tonic-gate 				hdr_len = (8 * (ptr[1] + 1));
3417c478bd9Sstevel@tonic-gate 				len += hdr_len;
3427c478bd9Sstevel@tonic-gate 				ptr += hdr_len;
3437c478bd9Sstevel@tonic-gate 				nxt = *ptr;
3447c478bd9Sstevel@tonic-gate 				break;
3467c478bd9Sstevel@tonic-gate 			default:
3477c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
3487c478bd9Sstevel@tonic-gate 				break;
3497c478bd9Sstevel@tonic-gate 			}
3507c478bd9Sstevel@tonic-gate 		} while (not_done);
3517c478bd9Sstevel@tonic-gate 		return (len);
3527c478bd9Sstevel@tonic-gate 	default:
3537c478bd9Sstevel@tonic-gate 		break;
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	return (0);			/* not IP */
3567c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate static void
codeprint()3597c478bd9Sstevel@tonic-gate codeprint()
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	uint_t *op;
3637c478bd9Sstevel@tonic-gate 	printf("User filter:\n");
3657c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
3667c478bd9Sstevel@tonic-gate 		if (*op <= OP_LAST)
3677c478bd9Sstevel@tonic-gate 			printf("\t%2d: %s\n", op - oplist, opnames[*op]);
3687c478bd9Sstevel@tonic-gate 		else
3697c478bd9Sstevel@tonic-gate 			printf("\t%2d: (%d)\n", op - oplist, *op);
3717c478bd9Sstevel@tonic-gate 		switch (*op) {
3727c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
3737c478bd9Sstevel@tonic-gate 		case OP_BRTR:
3747c478bd9Sstevel@tonic-gate 		case OP_BRFL:
3757c478bd9Sstevel@tonic-gate 			op++;
3767c478bd9Sstevel@tonic-gate 			if ((int)*op < 0)
3777c478bd9Sstevel@tonic-gate 				printf("\t%2d:   0x%08x (%d)\n",
378b127ac41SPhilip Kirk 				    op - oplist, *op, *op);
3797c478bd9Sstevel@tonic-gate 			else
3807c478bd9Sstevel@tonic-gate 				printf("\t%2d:   %d (0x%08x)\n",
381b127ac41SPhilip Kirk 				    op - oplist, *op, *op);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	printf("\t%2d: STOP\n", op - oplist);
3857c478bd9Sstevel@tonic-gate 	printf("\n");
3867c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * Take a pass through the generated code and optimize
3917c478bd9Sstevel@tonic-gate  * branches.  A branch true (BRTR) that has another BRTR
3927c478bd9Sstevel@tonic-gate  * at its destination can use the address of the destination
3937c478bd9Sstevel@tonic-gate  * BRTR.  A BRTR that points to a BRFL (branch false) should
3947c478bd9Sstevel@tonic-gate  * point to the address following the BRFL.
3957c478bd9Sstevel@tonic-gate  * A similar optimization applies to BRFL operators.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate static void
optimize(uint_t * oplistp)3987c478bd9Sstevel@tonic-gate optimize(uint_t *oplistp)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	uint_t *op;
4027c478bd9Sstevel@tonic-gate 	for (op = oplistp; *op; op++) {
4037c478bd9Sstevel@tonic-gate 		switch (*op) {
4047c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
4057c478bd9Sstevel@tonic-gate 			op++;
4067c478bd9Sstevel@tonic-gate 			break;
4077c478bd9Sstevel@tonic-gate 		case OP_BRTR:
4087c478bd9Sstevel@tonic-gate 			op++;
4097c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
4107c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRFL)
4117c478bd9Sstevel@tonic-gate 				*op += 2;
4127c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRTR)
4137c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
4147c478bd9Sstevel@tonic-gate 			break;
4157c478bd9Sstevel@tonic-gate 		case OP_BRFL:
4167c478bd9Sstevel@tonic-gate 			op++;
4177c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
4187c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRTR)
4197c478bd9Sstevel@tonic-gate 				*op += 2;
4207c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRFL)
4217c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
4227c478bd9Sstevel@tonic-gate 			break;
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate  * RPC packets are tough to filter.
4297c478bd9Sstevel@tonic-gate  * While the call packet has all the interesting
4307c478bd9Sstevel@tonic-gate  * info: program number, version, procedure etc,
4317c478bd9Sstevel@tonic-gate  * the reply packet has none of this information.
4327c478bd9Sstevel@tonic-gate  * If we want to do useful filtering based on this
4337c478bd9Sstevel@tonic-gate  * information then we have to stash the information
4347c478bd9Sstevel@tonic-gate  * from the call packet, and use the XID in the reply
4357c478bd9Sstevel@tonic-gate  * to find the stashed info.  The stashed info is
4367c478bd9Sstevel@tonic-gate  * kept in a circular lifo, assuming that a call packet
4377c478bd9Sstevel@tonic-gate  * will be followed quickly by its reply.
4387c478bd9Sstevel@tonic-gate  */
4407c478bd9Sstevel@tonic-gate struct xid_entry {
4417c478bd9Sstevel@tonic-gate 	unsigned	x_xid;		/* The XID (32 bits) */
4427c478bd9Sstevel@tonic-gate 	unsigned	x_dir;		/* CALL or REPLY */
4437c478bd9Sstevel@tonic-gate 	unsigned	x_rpcvers;	/* Protocol version (2) */
4447c478bd9Sstevel@tonic-gate 	unsigned	x_prog;		/* RPC program number */
4457c478bd9Sstevel@tonic-gate 	unsigned	x_vers;		/* RPC version number */
4467c478bd9Sstevel@tonic-gate 	unsigned	x_proc;		/* RPC procedure number */
4477c478bd9Sstevel@tonic-gate };
4487c478bd9Sstevel@tonic-gate static struct xid_entry	xe_table[XID_CACHE_SIZE];
4497c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_first = &xe_table[0];
4507c478bd9Sstevel@tonic-gate static struct xid_entry	*xe	  = &xe_table[0];
4517c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_last  = &xe_table[XID_CACHE_SIZE - 1];
4537c478bd9Sstevel@tonic-gate static struct xid_entry *
find_rpc(struct rpc_msg * rpc)4547c478bd9Sstevel@tonic-gate find_rpc(struct rpc_msg *rpc)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
4587c478bd9Sstevel@tonic-gate 	for (x = xe; x >= xe_first; x--)
4597c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
4607c478bd9Sstevel@tonic-gate 			return (x);
4617c478bd9Sstevel@tonic-gate 	for (x = xe_last; x > xe; x--)
4627c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
4637c478bd9Sstevel@tonic-gate 			return (x);
4647c478bd9Sstevel@tonic-gate 	return (NULL);
4657c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate static void
stash_rpc(struct rpc_msg * rpc)4687c478bd9Sstevel@tonic-gate stash_rpc(struct rpc_msg *rpc)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
4727c478bd9Sstevel@tonic-gate 	if (find_rpc(rpc))
4737c478bd9Sstevel@tonic-gate 		return;
4757c478bd9Sstevel@tonic-gate 	x = xe++;
4767c478bd9Sstevel@tonic-gate 	if (xe > xe_last)
4777c478bd9Sstevel@tonic-gate 		xe = xe_first;
4787c478bd9Sstevel@tonic-gate 	x->x_xid  = rpc->rm_xid;
4797c478bd9Sstevel@tonic-gate 	x->x_dir  = htonl(REPLY);
4807c478bd9Sstevel@tonic-gate 	x->x_prog = rpc->rm_call.cb_prog;
4817c478bd9Sstevel@tonic-gate 	x->x_vers = rpc->rm_call.cb_vers;
4827c478bd9Sstevel@tonic-gate 	x->x_proc = rpc->rm_call.cb_proc;
4837c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * SLP can multicast requests, and recieve unicast replies in which
4877c478bd9Sstevel@tonic-gate  * neither the source nor destination port is identifiable as a SLP
4887c478bd9Sstevel@tonic-gate  * port. Hence, we need to do as RPC does, and keep track of packets we
4897c478bd9Sstevel@tonic-gate  * are interested in. For SLP, however, we use ports, not XIDs, and
4907c478bd9Sstevel@tonic-gate  * a smaller cache size is more efficient since every incoming packet
4917c478bd9Sstevel@tonic-gate  * needs to be checked.
4927c478bd9Sstevel@tonic-gate  */
4947c478bd9Sstevel@tonic-gate #define	SLP_CACHE_SIZE 64
4957c478bd9Sstevel@tonic-gate static uint_t slp_table[SLP_CACHE_SIZE];
4967c478bd9Sstevel@tonic-gate static int slp_index	= 0;
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * Returns the index of dport in the table if found, otherwise -1.
5007c478bd9Sstevel@tonic-gate  */
5017c478bd9Sstevel@tonic-gate static int
find_slp(uint_t dport)502*cd93bdd3SToomas Soome find_slp(uint_t dport)
503*cd93bdd3SToomas Soome {
504*cd93bdd3SToomas Soome 	int i;
506*cd93bdd3SToomas Soome 	if (!dport)
507*cd93bdd3SToomas Soome 		return (0);
509*cd93bdd3SToomas Soome 	for (i = slp_index; i >= 0; i--)
510*cd93bdd3SToomas Soome 		if (slp_table[i] == dport) {
511*cd93bdd3SToomas Soome 			return (i);
512*cd93bdd3SToomas Soome 		}
513*cd93bdd3SToomas Soome 	for (i = SLP_CACHE_SIZE - 1; i > slp_index; i--)
514*cd93bdd3SToomas Soome 		if (slp_table[i] == dport) {
515*cd93bdd3SToomas Soome 			return (i);
516*cd93bdd3SToomas Soome 		}
517*cd93bdd3SToomas Soome 	return (-1);
5187c478bd9Sstevel@tonic-gate }
520*cd93bdd3SToomas Soome static void
stash_slp(uint_t sport)521*cd93bdd3SToomas Soome stash_slp(uint_t sport)
522*cd93bdd3SToomas Soome {
523*cd93bdd3SToomas Soome 	if (slp_table[slp_index - 1] == sport)
524*cd93bdd3SToomas Soome 		/* avoid redundancy due to multicast retransmissions */
525*cd93bdd3SToomas Soome 		return;
527*cd93bdd3SToomas Soome 	slp_table[slp_index++] = sport;
528*cd93bdd3SToomas Soome 	if (slp_index == SLP_CACHE_SIZE)
529*cd93bdd3SToomas Soome 		slp_index = 0;
5307c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate  * This routine takes a packet and returns true or false
5347c478bd9Sstevel@tonic-gate  * according to whether the filter expression selects it
5357c478bd9Sstevel@tonic-gate  * or not.
5367c478bd9Sstevel@tonic-gate  * We assume here that offsets for short and long values
5377c478bd9Sstevel@tonic-gate  * are even - we may die with an alignment error if the
5387c478bd9Sstevel@tonic-gate  * CPU doesn't support odd addresses.  Note that long
5397c478bd9Sstevel@tonic-gate  * values are loaded as two shorts so that 32 bit word
5407c478bd9Sstevel@tonic-gate  * alignment isn't important.
5417c478bd9Sstevel@tonic-gate  *
5427c478bd9Sstevel@tonic-gate  * IPv6 is a bit stickier to handle than IPv4...
5437c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate int
want_packet(uchar_t * pkt,int len,int origlen)5467c478bd9Sstevel@tonic-gate want_packet(uchar_t *pkt, int len, int origlen)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	uint_t stack[MAXSS];	/* operand stack */
5497c478bd9Sstevel@tonic-gate 	uint_t *op;		/* current operator */
5507c478bd9Sstevel@tonic-gate 	uint_t *sp;		/* top of operand stack */
5517c478bd9Sstevel@tonic-gate 	uchar_t *base;		/* base for offsets into packet */
5527c478bd9Sstevel@tonic-gate 	uchar_t *ip;		/* addr of IP header, unaligned */
5537c478bd9Sstevel@tonic-gate 	uchar_t *tcp;		/* addr of TCP header, unaligned */
5547c478bd9Sstevel@tonic-gate 	uchar_t *udp;		/* addr of UDP header, unaligned */
5557c478bd9Sstevel@tonic-gate 	struct rpc_msg rpcmsg;	/* addr of RPC header */
5567c478bd9Sstevel@tonic-gate 	struct rpc_msg *rpc;
5577c478bd9Sstevel@tonic-gate 	int newrpc = 0;
5587c478bd9Sstevel@tonic-gate 	uchar_t *slphdr;		/* beginning of SLP header */
5597c478bd9Sstevel@tonic-gate 	uint_t slp_sport, slp_dport;
5607c478bd9Sstevel@tonic-gate 	int off, header_size;
5617c478bd9Sstevel@tonic-gate 	uchar_t *offstack[MAXSS];	/* offset stack */
5627c478bd9Sstevel@tonic-gate 	uchar_t **offp;		/* current offset */
5637c478bd9Sstevel@tonic-gate 	uchar_t *opkt = NULL;
5647c478bd9Sstevel@tonic-gate 	uint_t olen;
5667c478bd9Sstevel@tonic-gate 	sp = stack;
5677c478bd9Sstevel@tonic-gate 	*sp = 1;
5687c478bd9Sstevel@tonic-gate 	base = pkt;
5697c478bd9Sstevel@tonic-gate 	offp = offstack;
5712b24ab6bSSebastien Roy 	header_size = (*interface->header_len)((char *)pkt, len);
5737c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
5747c478bd9Sstevel@tonic-gate 		switch ((enum optype) *op) {
5757c478bd9Sstevel@tonic-gate 		case OP_LOAD_OCTET:
5767c478bd9Sstevel@tonic-gate 			if ((base + *sp) > (pkt + len))
5777c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
5797c478bd9Sstevel@tonic-gate 			*sp = *((uchar_t *)(base + *sp));
5807c478bd9Sstevel@tonic-gate 			break;
5817c478bd9Sstevel@tonic-gate 		case OP_LOAD_SHORT:
5827c478bd9Sstevel@tonic-gate 			off = *sp;
5847c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint16_t) - 1) > (pkt + len))
5857c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
587605445d5Sdg 			*sp = ntohs(get_u16((uchar_t *)(base + off)));
5887c478bd9Sstevel@tonic-gate 			break;
5897c478bd9Sstevel@tonic-gate 		case OP_LOAD_LONG:
5907c478bd9Sstevel@tonic-gate 			off = *sp;
5927c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint32_t) - 1) > (pkt + len))
5937c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
5957c478bd9Sstevel@tonic-gate 			/*
5967c478bd9Sstevel@tonic-gate 			 * Handle 3 possible alignments
5977c478bd9Sstevel@tonic-gate 			 */
5987c478bd9Sstevel@tonic-gate 			switch ((((unsigned)base) + off) % sizeof (uint_t)) {
5997c478bd9Sstevel@tonic-gate 			case 0:
6007c478bd9Sstevel@tonic-gate 				*sp = *(uint_t *)(base + off);
6017c478bd9Sstevel@tonic-gate 				break;
6037c478bd9Sstevel@tonic-gate 			case 2:
6047c478bd9Sstevel@tonic-gate 				*((ushort_t *)(sp)) =
605b127ac41SPhilip Kirk 				    *((ushort_t *)(base + off));
6067c478bd9Sstevel@tonic-gate 				*(((ushort_t *)sp) + 1) =
607b127ac41SPhilip Kirk 				    *((ushort_t *)(base + off) + 1);
6087c478bd9Sstevel@tonic-gate 				break;
6107c478bd9Sstevel@tonic-gate 			case 1:
6117c478bd9Sstevel@tonic-gate 			case 3:
6127c478bd9Sstevel@tonic-gate 				*((uchar_t *)(sp)) =
613b127ac41SPhilip Kirk 				    *((uchar_t *)(base + off));
6147c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 1) =
615b127ac41SPhilip Kirk 				    *((uchar_t *)(base + off) + 1);
6167c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 2) =
617b127ac41SPhilip Kirk 				    *((uchar_t *)(base + off) + 2);
6187c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 3) =
619b127ac41SPhilip Kirk 				    *((uchar_t *)(base + off) + 3);
6207c478bd9Sstevel@tonic-gate 				break;
6217c478bd9Sstevel@tonic-gate 			}
6227c478bd9Sstevel@tonic-gate 			*sp = ntohl(*sp);
6237c478bd9Sstevel@tonic-gate 			break;
6247c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
6257c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
6267c478bd9Sstevel@tonic-gate 				return (0);
6277c478bd9Sstevel@tonic-gate 			*(++sp) = *(++op);
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case OP_LOAD_LENGTH:
6307c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
6317c478bd9Sstevel@tonic-gate 				return (0);
6327c478bd9Sstevel@tonic-gate 			*(++sp) = origlen;
6337c478bd9Sstevel@tonic-gate 			break;
6347c478bd9Sstevel@tonic-gate 		case OP_EQ:
6357c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6367c478bd9Sstevel@tonic-gate 				return (0);
6377c478bd9Sstevel@tonic-gate 			sp--;
6387c478bd9Sstevel@tonic-gate 			*sp = *sp == *(sp + 1);
6397c478bd9Sstevel@tonic-gate 			break;
6407c478bd9Sstevel@tonic-gate 		case OP_NE:
6417c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6427c478bd9Sstevel@tonic-gate 				return (0);
6437c478bd9Sstevel@tonic-gate 			sp--;
6447c478bd9Sstevel@tonic-gate 			*sp = *sp != *(sp + 1);
6457c478bd9Sstevel@tonic-gate 			break;
6467c478bd9Sstevel@tonic-gate 		case OP_GT:
6477c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6487c478bd9Sstevel@tonic-gate 				return (0);
6497c478bd9Sstevel@tonic-gate 			sp--;
6507c478bd9Sstevel@tonic-gate 			*sp = *sp > *(sp + 1);
6517c478bd9Sstevel@tonic-gate 			break;
6527c478bd9Sstevel@tonic-gate 		case OP_GE:
6537c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6547c478bd9Sstevel@tonic-gate 				return (0);
6557c478bd9Sstevel@tonic-gate 			sp--;
6567c478bd9Sstevel@tonic-gate 			*sp = *sp >= *(sp + 1);
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 		case OP_LT:
6597c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6607c478bd9Sstevel@tonic-gate 				return (0);
6617c478bd9Sstevel@tonic-gate 			sp--;
6627c478bd9Sstevel@tonic-gate 			*sp = *sp < *(sp + 1);
6637c478bd9Sstevel@tonic-gate 			break;
6647c478bd9Sstevel@tonic-gate 		case OP_LE:
6657c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6667c478bd9Sstevel@tonic-gate 				return (0);
6677c478bd9Sstevel@tonic-gate 			sp--;
6687c478bd9Sstevel@tonic-gate 			*sp = *sp <= *(sp + 1);
6697c478bd9Sstevel@tonic-gate 			break;
6707c478bd9Sstevel@tonic-gate 		case OP_AND:
6717c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6727c478bd9Sstevel@tonic-gate 				return (0);
6737c478bd9Sstevel@tonic-gate 			sp--;
6747c478bd9Sstevel@tonic-gate 			*sp &= *(sp + 1);
6757c478bd9Sstevel@tonic-gate 			break;
6767c478bd9Sstevel@tonic-gate 		case OP_OR:
6777c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6787c478bd9Sstevel@tonic-gate 				return (0);
6797c478bd9Sstevel@tonic-gate 			sp--;
6807c478bd9Sstevel@tonic-gate 			*sp |= *(sp + 1);
6817c478bd9Sstevel@tonic-gate 			break;
6827c478bd9Sstevel@tonic-gate 		case OP_XOR:
6837c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6847c478bd9Sstevel@tonic-gate 				return (0);
6857c478bd9Sstevel@tonic-gate 			sp--;
6867c478bd9Sstevel@tonic-gate 			*sp ^= *(sp + 1);
6877c478bd9Sstevel@tonic-gate 			break;
6887c478bd9Sstevel@tonic-gate 		case OP_NOT:
6897c478bd9Sstevel@tonic-gate 			*sp = !*sp;
6907c478bd9Sstevel@tonic-gate 			break;
6917c478bd9Sstevel@tonic-gate 		case OP_BRFL:
6927c478bd9Sstevel@tonic-gate 			op++;
6937c478bd9Sstevel@tonic-gate 			if (!*sp)
6947c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
6957c478bd9Sstevel@tonic-gate 			break;
6967c478bd9Sstevel@tonic-gate 		case OP_BRTR:
6977c478bd9Sstevel@tonic-gate 			op++;
6987c478bd9Sstevel@tonic-gate 			if (*sp)
6997c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
7007c478bd9Sstevel@tonic-gate 			break;
7017c478bd9Sstevel@tonic-gate 		case OP_ADD:
7027c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
7037c478bd9Sstevel@tonic-gate 				return (0);
7047c478bd9Sstevel@tonic-gate 			sp--;
7057c478bd9Sstevel@tonic-gate 			*sp += *(sp + 1);
7067c478bd9Sstevel@tonic-gate 			break;
7077c478bd9Sstevel@tonic-gate 		case OP_SUB:
7087c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
7097c478bd9Sstevel@tonic-gate 				return (0);
7107c478bd9Sstevel@tonic-gate 			sp--;
7117c478bd9Sstevel@tonic-gate 			*sp -= *(sp + 1);
7127c478bd9Sstevel@tonic-gate 			break;
7137c478bd9Sstevel@tonic-gate 		case OP_MUL:
7147c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
7157c478bd9Sstevel@tonic-gate 				return (0);
7167c478bd9Sstevel@tonic-gate 			sp--;
7177c478bd9Sstevel@tonic-gate 			*sp *= *(sp + 1);
7187c478bd9Sstevel@tonic-gate 			break;
7197c478bd9Sstevel@tonic-gate 		case OP_DIV:
7207c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
7217c478bd9Sstevel@tonic-gate 				return (0);
7227c478bd9Sstevel@tonic-gate 			sp--;
7237c478bd9Sstevel@tonic-gate 			*sp /= *(sp + 1);
7247c478bd9Sstevel@tonic-gate 			break;
7257c478bd9Sstevel@tonic-gate 		case OP_REM:
7267c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
7277c478bd9Sstevel@tonic-gate 				return (0);
7287c478bd9Sstevel@tonic-gate 			sp--;
7297c478bd9Sstevel@tonic-gate 			*sp %= *(sp + 1);
7307c478bd9Sstevel@tonic-gate 			break;
7317c478bd9Sstevel@tonic-gate 		case OP_OFFSET_POP:
7327c478bd9Sstevel@tonic-gate 			if (offp < &offstack[0])
7337c478bd9Sstevel@tonic-gate 				return (0);
7347c478bd9Sstevel@tonic-gate 			base = *offp--;
7357c478bd9Sstevel@tonic-gate 			if (opkt != NULL) {
7367c478bd9Sstevel@tonic-gate 				pkt = opkt;
7377c478bd9Sstevel@tonic-gate 				len = olen;
7387c478bd9Sstevel@tonic-gate 				opkt = NULL;
7397c478bd9Sstevel@tonic-gate 			}
7407c478bd9Sstevel@tonic-gate 			break;
7417c478bd9Sstevel@tonic-gate 		case OP_OFFSET_ZERO:
7427c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7437c478bd9Sstevel@tonic-gate 				return (0);
7447c478bd9Sstevel@tonic-gate 			*++offp = base;
7457c478bd9Sstevel@tonic-gate 			base = pkt;
7467c478bd9Sstevel@tonic-gate 			break;
7477c478bd9Sstevel@tonic-gate 		case OP_OFFSET_LINK:
7487c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7497c478bd9Sstevel@tonic-gate 				return (0);
7507c478bd9Sstevel@tonic-gate 			*++offp = base;
7517c478bd9Sstevel@tonic-gate 			base = pkt + header_size;
7527c478bd9Sstevel@tonic-gate 			/*
7537c478bd9Sstevel@tonic-gate 			 * If the offset exceeds the packet length,
7547c478bd9Sstevel@tonic-gate 			 * we should not be interested in this packet...
7557c478bd9Sstevel@tonic-gate 			 * Just return 0.
7567c478bd9Sstevel@tonic-gate 			 */
7577c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7587c478bd9Sstevel@tonic-gate 				return (0);
7597c478bd9Sstevel@tonic-gate 			}
7607c478bd9Sstevel@tonic-gate 			break;
7617c478bd9Sstevel@tonic-gate 		case OP_OFFSET_IP:
7627c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7637c478bd9Sstevel@tonic-gate 				return (0);
7647c478bd9Sstevel@tonic-gate 			*++offp = base;
7657c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7667c478bd9Sstevel@tonic-gate 			base = ip + ip_hdr_len(ip);
7677c478bd9Sstevel@tonic-gate 			if (base == ip) {
7687c478bd9Sstevel@tonic-gate 				return (0);			/* not IP */
7697c478bd9Sstevel@tonic-gate 			}
7707c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7717c478bd9Sstevel@tonic-gate 				return (0);			/* bad pkt */
7727c478bd9Sstevel@tonic-gate 			}
7737c478bd9Sstevel@tonic-gate 			break;
7747c478bd9Sstevel@tonic-gate 		case OP_OFFSET_TCP:
7757c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7767c478bd9Sstevel@tonic-gate 				return (0);
7777c478bd9Sstevel@tonic-gate 			*++offp = base;
7787c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7797c478bd9Sstevel@tonic-gate 			tcp = ip + ip_hdr_len(ip);
7807c478bd9Sstevel@tonic-gate 			if (tcp == ip) {
7817c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
7827c478bd9Sstevel@tonic-gate 			}
7837c478bd9Sstevel@tonic-gate 			base = tcp + TCP_HDR_LEN(tcp);
7847c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7857c478bd9Sstevel@tonic-gate 				return (0);
7867c478bd9Sstevel@tonic-gate 			}
7877c478bd9Sstevel@tonic-gate 			break;
7887c478bd9Sstevel@tonic-gate 		case OP_OFFSET_UDP:
7897c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7907c478bd9Sstevel@tonic-gate 				return (0);
7917c478bd9Sstevel@tonic-gate 			*++offp = base;
7927c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7937c478bd9Sstevel@tonic-gate 			udp = ip + ip_hdr_len(ip);
7947c478bd9Sstevel@tonic-gate 			if (udp == ip) {
7957c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
7967c478bd9Sstevel@tonic-gate 			}
7977c478bd9Sstevel@tonic-gate 			base = udp + sizeof (struct udphdr);
7987c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7997c478bd9Sstevel@tonic-gate 				return (0);
8007c478bd9Sstevel@tonic-gate 			}
8017c478bd9Sstevel@tonic-gate 			break;
8027c478bd9Sstevel@tonic-gate 		case OP_OFFSET_RPC:
8037c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
8047c478bd9Sstevel@tonic-gate 				return (0);
8057c478bd9Sstevel@tonic-gate 			*++offp = base;
8067c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
8077c478bd9Sstevel@tonic-gate 			rpc = NULL;
8097c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
8107c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
8117c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8127c478bd9Sstevel@tonic-gate 					return (0);
8137c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8147c478bd9Sstevel@tonic-gate 				break;
8157c478bd9Sstevel@tonic-gate 			}
8177c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
8187c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
8197c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
8207c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(udp +
8217c478bd9Sstevel@tonic-gate 				    sizeof (struct udphdr));
8227c478bd9Sstevel@tonic-gate 				break;
8237c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
8247c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
8257c478bd9Sstevel@tonic-gate 				/*
8267c478bd9Sstevel@tonic-gate 				 * Need to skip an extra 4 for the xdr_rec
8277c478bd9Sstevel@tonic-gate 				 * field.
8287c478bd9Sstevel@tonic-gate 				 */
8297c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(tcp +
8307c478bd9Sstevel@tonic-gate 				    TCP_HDR_LEN(tcp) + 4);
8317c478bd9Sstevel@tonic-gate 				break;
8327c478bd9Sstevel@tonic-gate 			}
8337c478bd9Sstevel@tonic-gate 			/*
8347c478bd9Sstevel@tonic-gate 			 * We need to have at least 24 bytes of a RPC
8357c478bd9Sstevel@tonic-gate 			 * packet to look at to determine the validity
8367c478bd9Sstevel@tonic-gate 			 * of it.
8377c478bd9Sstevel@tonic-gate 			 */
8387c478bd9Sstevel@tonic-gate 			if (rpc == NULL || (uchar_t *)rpc + 24 > pkt + len) {
8397c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8407c478bd9Sstevel@tonic-gate 					return (0);
8417c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8427c478bd9Sstevel@tonic-gate 				break;
8437c478bd9Sstevel@tonic-gate 			}
8447c478bd9Sstevel@tonic-gate 			/* align */
8457c478bd9Sstevel@tonic-gate 			(void) memcpy(&rpcmsg, rpc, 24);
8462b24ab6bSSebastien Roy 			if (!valid_rpc((char *)&rpcmsg, 24)) {
8477c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8487c478bd9Sstevel@tonic-gate 					return (0);
8497c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8507c478bd9Sstevel@tonic-gate 				break;
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 			if (ntohl(rpcmsg.rm_direction) == CALL) {
8537c478bd9Sstevel@tonic-gate 				base = (uchar_t *)rpc;
8547c478bd9Sstevel@tonic-gate 				newrpc = 1;
8557c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8567c478bd9Sstevel@tonic-gate 					return (0);
8577c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
8587c478bd9Sstevel@tonic-gate 			} else {
8597c478bd9Sstevel@tonic-gate 				opkt = pkt;
8607c478bd9Sstevel@tonic-gate 				olen = len;
8627c478bd9Sstevel@tonic-gate 				pkt = base = (uchar_t *)find_rpc(&rpcmsg);
8637c478bd9Sstevel@tonic-gate 				len = sizeof (struct xid_entry);
8647c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8657c478bd9Sstevel@tonic-gate 					return (0);
8667c478bd9Sstevel@tonic-gate 				*(++sp) = base != NULL;
8677c478bd9Sstevel@tonic-gate 			}
8687c478bd9Sstevel@tonic-gate 			break;
8697c478bd9Sstevel@tonic-gate 		case OP_OFFSET_SLP:
8707c478bd9Sstevel@tonic-gate 			slphdr = NULL;
8717c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
8737c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
8747c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
8757c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8767c478bd9Sstevel@tonic-gate 					return (0);
8777c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8787c478bd9Sstevel@tonic-gate 				break;
8797c478bd9Sstevel@tonic-gate 			}
8817c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
8827c478bd9Sstevel@tonic-gate 				struct udphdr udp_h;
8837c478bd9Sstevel@tonic-gate 				struct tcphdr tcp_h;
8847c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
8857c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
8867c478bd9Sstevel@tonic-gate 				/* align */
8877c478bd9Sstevel@tonic-gate 				memcpy(&udp_h, udp, sizeof (udp_h));
8887c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(udp_h.uh_sport);
8897c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(udp_h.uh_dport);
8907c478bd9Sstevel@tonic-gate 				slphdr = udp + sizeof (struct udphdr);
8917c478bd9Sstevel@tonic-gate 				break;
8927c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
8937c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
8947c478bd9Sstevel@tonic-gate 				/* align */
8957c478bd9Sstevel@tonic-gate 				memcpy(&tcp_h, tcp, sizeof (tcp_h));
8967c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(tcp_h.th_sport);
8977c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(tcp_h.th_dport);
8987c478bd9Sstevel@tonic-gate 				slphdr = tcp + TCP_HDR_LEN(tcp);
8997c478bd9Sstevel@tonic-gate 				break;
9007c478bd9Sstevel@tonic-gate 			}
9017c478bd9Sstevel@tonic-gate 			if (slphdr == NULL || slphdr > pkt + len) {
9027c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
9037c478bd9Sstevel@tonic-gate 					return (0);
9047c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
9057c478bd9Sstevel@tonic-gate 				break;
9067c478bd9Sstevel@tonic-gate 			}
9077c478bd9Sstevel@tonic-gate 			if (slp_sport == 427 || slp_dport == 427) {
9087c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
9097c478bd9Sstevel@tonic-gate 					return (0);
9107c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
9117c478bd9Sstevel@tonic-gate 				if (slp_sport != 427 && slp_dport == 427)
9127c478bd9Sstevel@tonic-gate 					stash_slp(slp_sport);
9137c478bd9Sstevel@tonic-gate 				break;
9147c478bd9Sstevel@tonic-gate 			} else if (find_slp(slp_dport) != -1) {
9157c478bd9Sstevel@tonic-gate 				if (valid_slp(slphdr, len)) {
9167c478bd9Sstevel@tonic-gate 					if (sp >= &stack[MAXSS])
9177c478bd9Sstevel@tonic-gate 						return (0);
9187c478bd9Sstevel@tonic-gate 					*(++sp) = 1;
9197c478bd9Sstevel@tonic-gate 					break;
9207c478bd9Sstevel@tonic-gate 				}
9217c478bd9Sstevel@tonic-gate 				/* else fallthrough to reject */
9227c478bd9Sstevel@tonic-gate 			}
9237c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
9247c478bd9Sstevel@tonic-gate 				return (0);
9257c478bd9Sstevel@tonic-gate 			*(++sp) = 0;
9267c478bd9Sstevel@tonic-gate 			break;
927605445d5Sdg 		case OP_OFFSET_ETHERTYPE:
928605445d5Sdg 			/*
929b127ac41SPhilip Kirk 			 * Set base to the location of the ethertype as
930b127ac41SPhilip Kirk 			 * appropriate for this link type.  Note that it's
931b127ac41SPhilip Kirk 			 * not called "ethertype" for every link type, but
932b127ac41SPhilip Kirk 			 * we need to call it something.
933605445d5Sdg 			 */
934605445d5Sdg 			if (offp >= &offstack[MAXSS])
935605445d5Sdg 				return (0);
936605445d5Sdg 			*++offp = base;
937605445d5Sdg 			base = pkt + interface->network_type_offset;
939605445d5Sdg 			/*
940b127ac41SPhilip Kirk 			 * Below, we adjust the offset for unusual
941b127ac41SPhilip Kirk 			 * link-layer headers that may have the protocol
942b127ac41SPhilip Kirk 			 * type in a variable location beyond what was set
943b127ac41SPhilip Kirk 			 * above.
944605445d5Sdg 			 */
945b127ac41SPhilip Kirk 			switch (interface->mac_type) {
946b127ac41SPhilip Kirk 			case DL_ETHER:
947b127ac41SPhilip Kirk 			case DL_CSMACD:
948b127ac41SPhilip Kirk 				/*
949b127ac41SPhilip Kirk 				 * If this is a VLAN-tagged packet, we need
950b127ac41SPhilip Kirk 				 * to point to the ethertype field in the
951b127ac41SPhilip Kirk 				 * VLAN header.  Move past the ethertype
952b127ac41SPhilip Kirk 				 * field in the ethernet header.
953b127ac41SPhilip Kirk 				 */
954b127ac41SPhilip Kirk 				if (ntohs(get_u16(base)) == ETHERTYPE_VLAN)
955605445d5Sdg 					base += (ENCAP_ETHERTYPE_OFF);
956b127ac41SPhilip Kirk 				break;
957b127ac41SPhilip Kirk 			}
958b127ac41SPhilip Kirk 			if (base > pkt + len) {
959b127ac41SPhilip Kirk 				/* Went too far, drop the packet */
960b127ac41SPhilip Kirk 				return (0);
961605445d5Sdg 			}
962605445d5Sdg 			break;
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 	}
9667c478bd9Sstevel@tonic-gate 	if (*sp && newrpc)
9677c478bd9Sstevel@tonic-gate 		stash_rpc(&rpcmsg);
9697c478bd9Sstevel@tonic-gate 	return (*sp);
9707c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate static void
load_const(uint_t constval)9737c478bd9Sstevel@tonic-gate load_const(uint_t constval)
9747c478bd9Sstevel@tonic-gate {
9757c478bd9Sstevel@tonic-gate 	emitop(OP_LOAD_CONST);
9767c478bd9Sstevel@tonic-gate 	emitval(constval);
9777c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate static void
load_value(int offset,int len)9807c478bd9Sstevel@tonic-gate load_value(int offset, int len)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate 	if (offset >= 0)
9837c478bd9Sstevel@tonic-gate 		load_const(offset);
9857c478bd9Sstevel@tonic-gate 	switch (len) {
9867c478bd9Sstevel@tonic-gate 		case 1:
9877c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_OCTET);
9887c478bd9Sstevel@tonic-gate 			break;
9897c478bd9Sstevel@tonic-gate 		case 2:
9907c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_SHORT);
9917c478bd9Sstevel@tonic-gate 			break;
9927c478bd9Sstevel@tonic-gate 		case 4:
9937c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LONG);
9947c478bd9Sstevel@tonic-gate 			break;
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate }
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate  * Emit code to compare a field in
10007c478bd9Sstevel@tonic-gate  * the packet against a constant value.
10017c478bd9Sstevel@tonic-gate  */
10027c478bd9Sstevel@tonic-gate static void
compare_value(uint_t offset,uint_t len,uint_t val)10037c478bd9Sstevel@tonic-gate compare_value(uint_t offset, uint_t len, uint_t val)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	load_const(val);
10067c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10077c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10087c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate static void
compare_addr_v4(uint_t offset,uint_t len,uint_t val)10117c478bd9Sstevel@tonic-gate compare_addr_v4(uint_t offset, uint_t len, uint_t val)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate 	load_const(ntohl(val));
10147c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10157c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10167c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate static void
compare_addr_v6(uint_t offset,uint_t len,struct in6_addr val)10197c478bd9Sstevel@tonic-gate compare_addr_v6(uint_t offset, uint_t len, struct in6_addr val)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	int i;
10227c478bd9Sstevel@tonic-gate 	uint32_t value;
10247c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i += 4) {
10257c478bd9Sstevel@tonic-gate 		value = ntohl(*(uint32_t *)&val.s6_addr[i]);
10267c478bd9Sstevel@tonic-gate 		load_const(value);
10277c478bd9Sstevel@tonic-gate 		load_value(offset + i, 4);
10287c478bd9Sstevel@tonic-gate 		emitop(OP_EQ);
10297c478bd9Sstevel@tonic-gate 		if (i != 0)
10307c478bd9Sstevel@tonic-gate 			emitop(OP_AND);
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate  * Same as above except do the comparison
10367c478bd9Sstevel@tonic-gate  * after and'ing a mask value.  Useful
10377c478bd9Sstevel@tonic-gate  * for comparing IP network numbers
10387c478bd9Sstevel@tonic-gate  */
10397c478bd9Sstevel@tonic-gate static void
compare_value_mask(uint_t offset,uint_t len,uint_t val,int mask)10407c478bd9Sstevel@tonic-gate compare_value_mask(uint_t offset, uint_t len, uint_t val, int mask)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10437c478bd9Sstevel@tonic-gate 	load_const(mask);
10447c478bd9Sstevel@tonic-gate 	emitop(OP_AND);
10457c478bd9Sstevel@tonic-gate 	load_const(val);
10467c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10477c478bd9Sstevel@tonic-gate }