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 /*
22d6f299a8Sdg  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/time.h>
367c478bd9Sstevel@tonic-gate #include <stddef.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/socket.h>
397c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
40*605445d5Sdg #include <sys/vlan.h>
417c478bd9Sstevel@tonic-gate #include <net/if.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
457c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
467c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
477c478bd9Sstevel@tonic-gate #include <inet/ip.h>
487c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
497c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
507c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
517c478bd9Sstevel@tonic-gate #include <netdb.h>
527c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
537c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
547c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
577c478bd9Sstevel@tonic-gate #include <snoop.h>
58*605445d5Sdg #include "snoop_vlan.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	IPV4_ONLY	0
617c478bd9Sstevel@tonic-gate #define	IPV6_ONLY	1
627c478bd9Sstevel@tonic-gate #define	IPV4_AND_IPV6	2
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * The following constants represent the offsets in bytes from the beginning
667c478bd9Sstevel@tonic-gate  * of the IP(v6) header of the source and destination IP(v6) addresses.
677c478bd9Sstevel@tonic-gate  * These are useful when generating filter code.
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate #define	IPV4_SRCADDR_OFFSET	12
707c478bd9Sstevel@tonic-gate #define	IPV4_DSTADDR_OFFSET	16
717c478bd9Sstevel@tonic-gate #define	IPV6_SRCADDR_OFFSET	8
727c478bd9Sstevel@tonic-gate #define	IPV6_DSTADDR_OFFSET	24
737c478bd9Sstevel@tonic-gate #define	IP_VERS(p)	(((*(uchar_t *)p) & 0xf0) >> 4)
747c478bd9Sstevel@tonic-gate #define	MASKED_IPV4_VERS	0x40
757c478bd9Sstevel@tonic-gate #define	MASKED_IPV6_VERS	0x60
767c478bd9Sstevel@tonic-gate #define	IP_HDR_LEN(p)	(((*(uchar_t *)p) & 0xf) * 4)
777c478bd9Sstevel@tonic-gate #define	TCP_HDR_LEN(p)	((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4)
78*605445d5Sdg 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * Coding the constant below is tacky, but the compiler won't let us
817c478bd9Sstevel@tonic-gate  * be more clever.  E.g., &((struct ip *)0)->ip_xxx
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate #define	IP_PROTO_OF(p)	(((uchar_t *)p)[9])
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * AppleTalk uses 802.2 Ethernet encapsulation with LLC/SNAP headers,
877c478bd9Sstevel@tonic-gate  * for 8 octets of overhead, and the common AppleTalk DDP Ethernet
887c478bd9Sstevel@tonic-gate  * header is another 4 octets.
897c478bd9Sstevel@tonic-gate  *
907c478bd9Sstevel@tonic-gate  * The following constants represents the offsets in bytes from the beginning
917c478bd9Sstevel@tonic-gate  * of the Ethernet payload to various parts of the DDP header.
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #define	AT_DST_NET_OFFSET	12
957c478bd9Sstevel@tonic-gate #define	AT_SRC_NET_OFFSET	14
967c478bd9Sstevel@tonic-gate #define	AT_DST_NODE_OFFSET	16
977c478bd9Sstevel@tonic-gate #define	AT_SRC_NODE_OFFSET	17
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate int eaddr;	/* need ethernet addr */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate int opstack;	/* operand stack depth */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * These are the operators of the user-level filter.
1057c478bd9Sstevel@tonic-gate  * STOP ends execution of the filter expression and
1067c478bd9Sstevel@tonic-gate  * returns the truth value at the top of the stack.
1077c478bd9Sstevel@tonic-gate  * OP_LOAD_OCTET, OP_LOAD_SHORT and OP_LOAD_LONG pop
1087c478bd9Sstevel@tonic-gate  * an offset value from the stack and load a value of
1097c478bd9Sstevel@tonic-gate  * an appropriate size from the packet (octet, short or
1107c478bd9Sstevel@tonic-gate  * long).  The offset is computed from a base value that
1117c478bd9Sstevel@tonic-gate  * may be set via the OP_OFFSET operators.
1127c478bd9Sstevel@tonic-gate  * OP_EQ, OP_NE, OP_GT, OP_GE, OP_LT, OP_LE pop two values
1137c478bd9Sstevel@tonic-gate  * from the stack and return the result of their comparison.
1147c478bd9Sstevel@tonic-gate  * OP_AND, OP_OR, OP_XOR pop two values from the stack and
1157c478bd9Sstevel@tonic-gate  * do perform a bitwise operation on them - returning a result
1167c478bd9Sstevel@tonic-gate  * to the stack.  OP_NOT inverts the bits of the value on the
1177c478bd9Sstevel@tonic-gate  * stack.
1187c478bd9Sstevel@tonic-gate  * OP_BRFL and OP_BRTR branch to an offset in the code array
1197c478bd9Sstevel@tonic-gate  * depending on the value at the top of the stack: true (not 0)
1207c478bd9Sstevel@tonic-gate  * or false (0).
1217c478bd9Sstevel@tonic-gate  * OP_ADD, OP_SUB, OP_MUL, OP_DIV and OP_REM pop two values
1227c478bd9Sstevel@tonic-gate  * from the stack and perform arithmetic.
1237c478bd9Sstevel@tonic-gate  * The OP_OFFSET operators change the base from which the
1247c478bd9Sstevel@tonic-gate  * OP_LOAD operators compute their offsets.
1257c478bd9Sstevel@tonic-gate  * OP_OFFSET_ZERO sets the offset to zero - beginning of packet.
1267c478bd9Sstevel@tonic-gate  * OP_OFFSET_LINK sets the base to the first octet after
1277c478bd9Sstevel@tonic-gate  * the link (DLC) header.  OP_OFFSET_IP, OP_OFFSET_TCP,
1287c478bd9Sstevel@tonic-gate  * and OP_OFFSET_UDP do the same for those headers - they
1297c478bd9Sstevel@tonic-gate  * set the offset base to the *end* of the header - not the
1307c478bd9Sstevel@tonic-gate  * beginning.  The OP_OFFSET_RPC operator is a bit unusual.
1317c478bd9Sstevel@tonic-gate  * It points the base at the cached RPC header.  For the
1327c478bd9Sstevel@tonic-gate  * purposes of selection, RPC reply headers look like call
1337c478bd9Sstevel@tonic-gate  * headers except for the direction value.
134*605445d5Sdg  * OP_OFFSET_ETHERTYPE sets base according to the following
135*605445d5Sdg  * algorithm:
136*605445d5Sdg  *   if the packet is not VLAN tagged, then set base to
137*605445d5Sdg  *         the ethertype field in the ethernet header
138*605445d5Sdg  *   else set base to the ethertype field of the VLAN header
1397c478bd9Sstevel@tonic-gate  * OP_OFFSET_POP restores the offset base to the value prior
1407c478bd9Sstevel@tonic-gate  * to the most recent OP_OFFSET call.
1417c478bd9Sstevel@tonic-gate  */
1427c478bd9Sstevel@tonic-gate enum optype {
1437c478bd9Sstevel@tonic-gate 	OP_STOP = 0,
1447c478bd9Sstevel@tonic-gate 	OP_LOAD_OCTET,
1457c478bd9Sstevel@tonic-gate 	OP_LOAD_SHORT,
1467c478bd9Sstevel@tonic-gate 	OP_LOAD_LONG,
1477c478bd9Sstevel@tonic-gate 	OP_LOAD_CONST,
1487c478bd9Sstevel@tonic-gate 	OP_LOAD_LENGTH,
1497c478bd9Sstevel@tonic-gate 	OP_EQ,
1507c478bd9Sstevel@tonic-gate 	OP_NE,
1517c478bd9Sstevel@tonic-gate 	OP_GT,
1527c478bd9Sstevel@tonic-gate 	OP_GE,
1537c478bd9Sstevel@tonic-gate 	OP_LT,
1547c478bd9Sstevel@tonic-gate 	OP_LE,
1557c478bd9Sstevel@tonic-gate 	OP_AND,
1567c478bd9Sstevel@tonic-gate 	OP_OR,
1577c478bd9Sstevel@tonic-gate 	OP_XOR,
1587c478bd9Sstevel@tonic-gate 	OP_NOT,
1597c478bd9Sstevel@tonic-gate 	OP_BRFL,
1607c478bd9Sstevel@tonic-gate 	OP_BRTR,
1617c478bd9Sstevel@tonic-gate 	OP_ADD,
1627c478bd9Sstevel@tonic-gate 	OP_SUB,
1637c478bd9Sstevel@tonic-gate 	OP_MUL,
1647c478bd9Sstevel@tonic-gate 	OP_DIV,
1657c478bd9Sstevel@tonic-gate 	OP_REM,
1667c478bd9Sstevel@tonic-gate 	OP_OFFSET_POP,
1677c478bd9Sstevel@tonic-gate 	OP_OFFSET_ZERO,
1687c478bd9Sstevel@tonic-gate 	OP_OFFSET_LINK,
1697c478bd9Sstevel@tonic-gate 	OP_OFFSET_IP,
1707c478bd9Sstevel@tonic-gate 	OP_OFFSET_TCP,
1717c478bd9Sstevel@tonic-gate 	OP_OFFSET_UDP,
1727c478bd9Sstevel@tonic-gate 	OP_OFFSET_RPC,
1737c478bd9Sstevel@tonic-gate 	OP_OFFSET_SLP,
174*605445d5Sdg 	OP_OFFSET_ETHERTYPE,
1757c478bd9Sstevel@tonic-gate 	OP_LAST
1767c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate static char *opnames[] = {
1797c478bd9Sstevel@tonic-gate 	"STOP",
1807c478bd9Sstevel@tonic-gate 	"LOAD_OCTET",
1817c478bd9Sstevel@tonic-gate 	"LOAD_SHORT",
1827c478bd9Sstevel@tonic-gate 	"LOAD_LONG",
1837c478bd9Sstevel@tonic-gate 	"LOAD_CONST",
1847c478bd9Sstevel@tonic-gate 	"LOAD_LENGTH",
1857c478bd9Sstevel@tonic-gate 	"EQ",
1867c478bd9Sstevel@tonic-gate 	"NE",
1877c478bd9Sstevel@tonic-gate 	"GT",
1887c478bd9Sstevel@tonic-gate 	"GE",
1897c478bd9Sstevel@tonic-gate 	"LT",
1907c478bd9Sstevel@tonic-gate 	"LE",
1917c478bd9Sstevel@tonic-gate 	"AND",
1927c478bd9Sstevel@tonic-gate 	"OR",
1937c478bd9Sstevel@tonic-gate 	"XOR",
1947c478bd9Sstevel@tonic-gate 	"NOT",
1957c478bd9Sstevel@tonic-gate 	"BRFL",
1967c478bd9Sstevel@tonic-gate 	"BRTR",
1977c478bd9Sstevel@tonic-gate 	"ADD",
1987c478bd9Sstevel@tonic-gate 	"SUB",
1997c478bd9Sstevel@tonic-gate 	"MUL",
2007c478bd9Sstevel@tonic-gate 	"DIV",
2017c478bd9Sstevel@tonic-gate 	"REM",
2027c478bd9Sstevel@tonic-gate 	"OFFSET_POP",
2037c478bd9Sstevel@tonic-gate 	"OFFSET_ZERO",
2047c478bd9Sstevel@tonic-gate 	"OFFSET_ETHER",
2057c478bd9Sstevel@tonic-gate 	"OFFSET_IP",
2067c478bd9Sstevel@tonic-gate 	"OFFSET_TCP",
2077c478bd9Sstevel@tonic-gate 	"OFFSET_UDP",
2087c478bd9Sstevel@tonic-gate 	"OFFSET_RPC",
2097c478bd9Sstevel@tonic-gate 	"OP_OFFSET_SLP",
210*605445d5Sdg 	"OFFSET_ETHERTYPE",
2117c478bd9Sstevel@tonic-gate 	""
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate #define	MAXOPS 1024
2157c478bd9Sstevel@tonic-gate #define	MAXSS	64
2167c478bd9Sstevel@tonic-gate static uint_t oplist[MAXOPS];	/* array of operators */
2177c478bd9Sstevel@tonic-gate static uint_t *curr_op;		/* last op generated */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate extern int valid_slp(uchar_t *, int);	/* decides if a SLP msg is valid */
2207c478bd9Sstevel@tonic-gate extern struct hostent *lgetipnodebyname(const char *, int, int, int *);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static void alternation();
2237c478bd9Sstevel@tonic-gate static uint_t chain();
2247c478bd9Sstevel@tonic-gate static void codeprint();
2257c478bd9Sstevel@tonic-gate static void emitop();
2267c478bd9Sstevel@tonic-gate static void emitval();
2277c478bd9Sstevel@tonic-gate static void expression();
2287c478bd9Sstevel@tonic-gate static struct xid_entry *find_rpc();
2297c478bd9Sstevel@tonic-gate static void optimize();
2307c478bd9Sstevel@tonic-gate static void ethertype_match();
2317c478bd9Sstevel@tonic-gate 
232*605445d5Sdg /*
233*605445d5Sdg  * Get a ushort from a possibly unaligned character buffer.
234*605445d5Sdg  *
235*605445d5Sdg  * INPUTS:  buffer - where the data is.  Must be at least
236*605445d5Sdg  *          sizeof(uint16_t) bytes long.
237*605445d5Sdg  * OUPUTS:  An unsigned short that contains the data at buffer.
238*605445d5Sdg  *          No calls to ntohs or htons are done on the data.
239*605445d5Sdg  */
240*605445d5Sdg static uint16_t
241*605445d5Sdg get_u16(uchar_t *buffer)
242*605445d5Sdg {
243*605445d5Sdg 	uint8_t	*bufraw = buffer;
244*605445d5Sdg 
245*605445d5Sdg 	/*
246*605445d5Sdg 	 * ntohs is used only as a cheap way to flip the bits
247*605445d5Sdg 	 * around on a little endian platform.  The value will
248*605445d5Sdg 	 * still be in host order or network order, depending on
249*605445d5Sdg 	 * the order it was in when it was passed in.
250*605445d5Sdg 	 */
251*605445d5Sdg 	return (ntohs(bufraw[0] << 8 | bufraw[1]));
252*605445d5Sdg }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * Returns the ULP for an IPv4 or IPv6 packet
2567c478bd9Sstevel@tonic-gate  * Assumes that the packet has already been checked to verify
2577c478bd9Sstevel@tonic-gate  * that it's either IPv4 or IPv6
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
2607c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
2617c478bd9Sstevel@tonic-gate  */
2627c478bd9Sstevel@tonic-gate static uchar_t
2637c478bd9Sstevel@tonic-gate ip_proto_of(uchar_t *ip)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
2667c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
2677c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
2707c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
2717c478bd9Sstevel@tonic-gate 		return (IP_PROTO_OF(ip));
2727c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		nxt = ip[6];
2757c478bd9Sstevel@tonic-gate 		ptr += 40;		/* size of ip6 header */
2767c478bd9Sstevel@tonic-gate 		do {
2777c478bd9Sstevel@tonic-gate 			switch (nxt) {
2787c478bd9Sstevel@tonic-gate 			/*
2797c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
2807c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
2817c478bd9Sstevel@tonic-gate 			 */
2827c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
2837c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
2847c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
2857c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
2867c478bd9Sstevel@tonic-gate 				ptr += (8 * (ptr[1] + 1));
2877c478bd9Sstevel@tonic-gate 				nxt = *ptr;
2887c478bd9Sstevel@tonic-gate 				break;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 			default:
2917c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
2927c478bd9Sstevel@tonic-gate 				break;
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 		} while (not_done);
2957c478bd9Sstevel@tonic-gate 		return (nxt);
2967c478bd9Sstevel@tonic-gate 	default:
2977c478bd9Sstevel@tonic-gate 		break;			/* shouldn't get here... */
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	return (0);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * Returns the total IP header length.
3047c478bd9Sstevel@tonic-gate  * For v4, this includes any options present.
3057c478bd9Sstevel@tonic-gate  * For v6, this is the length of the IPv6 header plus
3067c478bd9Sstevel@tonic-gate  * any extension headers present.
3077c478bd9Sstevel@tonic-gate  *
3087c478bd9Sstevel@tonic-gate  * XXX Will need to be updated for AH and ESP
3097c478bd9Sstevel@tonic-gate  * XXX when IPsec is supported for v6.
3107c478bd9Sstevel@tonic-gate  */
3117c478bd9Sstevel@tonic-gate static int
3127c478bd9Sstevel@tonic-gate ip_hdr_len(uchar_t *ip)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	uchar_t		nxt;
3157c478bd9Sstevel@tonic-gate 	int		hdr_len;
3167c478bd9Sstevel@tonic-gate 	boolean_t	not_done = B_TRUE;
3177c478bd9Sstevel@tonic-gate 	int		len = 40;	/* IPv6 header size */
3187c478bd9Sstevel@tonic-gate 	uchar_t		*ptr = ip;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	switch (IP_VERS(ip)) {
3217c478bd9Sstevel@tonic-gate 	case IPV4_VERSION:
3227c478bd9Sstevel@tonic-gate 		return (IP_HDR_LEN(ip));
3237c478bd9Sstevel@tonic-gate 	case IPV6_VERSION:
3247c478bd9Sstevel@tonic-gate 		nxt = ip[6];
3257c478bd9Sstevel@tonic-gate 		ptr += len;
3267c478bd9Sstevel@tonic-gate 		do {
3277c478bd9Sstevel@tonic-gate 			switch (nxt) {
3287c478bd9Sstevel@tonic-gate 			/*
3297c478bd9Sstevel@tonic-gate 			 * XXX Add IPsec headers here when supported for v6
3307c478bd9Sstevel@tonic-gate 			 * XXX (the AH will have a different size...)
3317c478bd9Sstevel@tonic-gate 			 */
3327c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
3337c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
3347c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
3357c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
3367c478bd9Sstevel@tonic-gate 				hdr_len = (8 * (ptr[1] + 1));
3377c478bd9Sstevel@tonic-gate 				len += hdr_len;
3387c478bd9Sstevel@tonic-gate 				ptr += hdr_len;
3397c478bd9Sstevel@tonic-gate 				nxt = *ptr;
3407c478bd9Sstevel@tonic-gate 				break;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 			default:
3437c478bd9Sstevel@tonic-gate 				not_done = B_FALSE;
3447c478bd9Sstevel@tonic-gate 				break;
3457c478bd9Sstevel@tonic-gate 			}
3467c478bd9Sstevel@tonic-gate 		} while (not_done);
3477c478bd9Sstevel@tonic-gate 		return (len);
3487c478bd9Sstevel@tonic-gate 	default:
3497c478bd9Sstevel@tonic-gate 		break;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	return (0);			/* not IP */
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static void
3557c478bd9Sstevel@tonic-gate codeprint()
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	uint_t *op;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	printf("User filter:\n");
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
3627c478bd9Sstevel@tonic-gate 		if (*op <= OP_LAST)
3637c478bd9Sstevel@tonic-gate 			printf("\t%2d: %s\n", op - oplist, opnames[*op]);
3647c478bd9Sstevel@tonic-gate 		else
3657c478bd9Sstevel@tonic-gate 			printf("\t%2d: (%d)\n", op - oplist, *op);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		switch (*op) {
3687c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
3697c478bd9Sstevel@tonic-gate 		case OP_BRTR:
3707c478bd9Sstevel@tonic-gate 		case OP_BRFL:
3717c478bd9Sstevel@tonic-gate 			op++;
3727c478bd9Sstevel@tonic-gate 			if ((int)*op < 0)
3737c478bd9Sstevel@tonic-gate 				printf("\t%2d:   0x%08x (%d)\n",
3747c478bd9Sstevel@tonic-gate 					op - oplist, *op, *op);
3757c478bd9Sstevel@tonic-gate 			else
3767c478bd9Sstevel@tonic-gate 				printf("\t%2d:   %d (0x%08x)\n",
3777c478bd9Sstevel@tonic-gate 					op - oplist, *op, *op);
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	printf("\t%2d: STOP\n", op - oplist);
3817c478bd9Sstevel@tonic-gate 	printf("\n");
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * Take a pass through the generated code and optimize
3877c478bd9Sstevel@tonic-gate  * branches.  A branch true (BRTR) that has another BRTR
3887c478bd9Sstevel@tonic-gate  * at its destination can use the address of the destination
3897c478bd9Sstevel@tonic-gate  * BRTR.  A BRTR that points to a BRFL (branch false) should
3907c478bd9Sstevel@tonic-gate  * point to the address following the BRFL.
3917c478bd9Sstevel@tonic-gate  * A similar optimization applies to BRFL operators.
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static void
3947c478bd9Sstevel@tonic-gate optimize(uint_t *oplistp)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	uint_t *op;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	for (op = oplistp; *op; op++) {
3997c478bd9Sstevel@tonic-gate 		switch (*op) {
4007c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
4017c478bd9Sstevel@tonic-gate 			op++;
4027c478bd9Sstevel@tonic-gate 			break;
4037c478bd9Sstevel@tonic-gate 		case OP_BRTR:
4047c478bd9Sstevel@tonic-gate 			op++;
4057c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
4067c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRFL)
4077c478bd9Sstevel@tonic-gate 				*op += 2;
4087c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRTR)
4097c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
4107c478bd9Sstevel@tonic-gate 			break;
4117c478bd9Sstevel@tonic-gate 		case OP_BRFL:
4127c478bd9Sstevel@tonic-gate 			op++;
4137c478bd9Sstevel@tonic-gate 			optimize(&oplist[*op]);
4147c478bd9Sstevel@tonic-gate 			if (oplist[*op] == OP_BRTR)
4157c478bd9Sstevel@tonic-gate 				*op += 2;
4167c478bd9Sstevel@tonic-gate 			else if (oplist[*op] == OP_BRFL)
4177c478bd9Sstevel@tonic-gate 				*op = oplist[*op + 1];
4187c478bd9Sstevel@tonic-gate 			break;
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  * RPC packets are tough to filter.
4257c478bd9Sstevel@tonic-gate  * While the call packet has all the interesting
4267c478bd9Sstevel@tonic-gate  * info: program number, version, procedure etc,
4277c478bd9Sstevel@tonic-gate  * the reply packet has none of this information.
4287c478bd9Sstevel@tonic-gate  * If we want to do useful filtering based on this
4297c478bd9Sstevel@tonic-gate  * information then we have to stash the information
4307c478bd9Sstevel@tonic-gate  * from the call packet, and use the XID in the reply
4317c478bd9Sstevel@tonic-gate  * to find the stashed info.  The stashed info is
4327c478bd9Sstevel@tonic-gate  * kept in a circular lifo, assuming that a call packet
4337c478bd9Sstevel@tonic-gate  * will be followed quickly by its reply.
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate struct xid_entry {
4377c478bd9Sstevel@tonic-gate 	unsigned	x_xid;		/* The XID (32 bits) */
4387c478bd9Sstevel@tonic-gate 	unsigned	x_dir;		/* CALL or REPLY */
4397c478bd9Sstevel@tonic-gate 	unsigned	x_rpcvers;	/* Protocol version (2) */
4407c478bd9Sstevel@tonic-gate 	unsigned	x_prog;		/* RPC program number */
4417c478bd9Sstevel@tonic-gate 	unsigned	x_vers;		/* RPC version number */
4427c478bd9Sstevel@tonic-gate 	unsigned	x_proc;		/* RPC procedure number */
4437c478bd9Sstevel@tonic-gate };
4447c478bd9Sstevel@tonic-gate static struct xid_entry	xe_table[XID_CACHE_SIZE];
4457c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_first = &xe_table[0];
4467c478bd9Sstevel@tonic-gate static struct xid_entry	*xe	  = &xe_table[0];
4477c478bd9Sstevel@tonic-gate static struct xid_entry	*xe_last  = &xe_table[XID_CACHE_SIZE - 1];
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate static struct xid_entry *
4507c478bd9Sstevel@tonic-gate find_rpc(struct rpc_msg *rpc)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	for (x = xe; x >= xe_first; x--)
4557c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
4567c478bd9Sstevel@tonic-gate 			return (x);
4577c478bd9Sstevel@tonic-gate 	for (x = xe_last; x > xe; x--)
4587c478bd9Sstevel@tonic-gate 		if (x->x_xid == rpc->rm_xid)
4597c478bd9Sstevel@tonic-gate 			return (x);
4607c478bd9Sstevel@tonic-gate 	return (NULL);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate static void
4647c478bd9Sstevel@tonic-gate stash_rpc(struct rpc_msg *rpc)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	struct xid_entry *x;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if (find_rpc(rpc))
4697c478bd9Sstevel@tonic-gate 		return;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	x = xe++;
4727c478bd9Sstevel@tonic-gate 	if (xe > xe_last)
4737c478bd9Sstevel@tonic-gate 		xe = xe_first;
4747c478bd9Sstevel@tonic-gate 	x->x_xid  = rpc->rm_xid;
4757c478bd9Sstevel@tonic-gate 	x->x_dir  = htonl(REPLY);
4767c478bd9Sstevel@tonic-gate 	x->x_prog = rpc->rm_call.cb_prog;
4777c478bd9Sstevel@tonic-gate 	x->x_vers = rpc->rm_call.cb_vers;
4787c478bd9Sstevel@tonic-gate 	x->x_proc = rpc->rm_call.cb_proc;
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * SLP can multicast requests, and recieve unicast replies in which
4837c478bd9Sstevel@tonic-gate  * neither the source nor destination port is identifiable as a SLP
4847c478bd9Sstevel@tonic-gate  * port. Hence, we need to do as RPC does, and keep track of packets we
4857c478bd9Sstevel@tonic-gate  * are interested in. For SLP, however, we use ports, not XIDs, and
4867c478bd9Sstevel@tonic-gate  * a smaller cache size is more efficient since every incoming packet
4877c478bd9Sstevel@tonic-gate  * needs to be checked.
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate #define	SLP_CACHE_SIZE 64
4917c478bd9Sstevel@tonic-gate static uint_t slp_table[SLP_CACHE_SIZE];
4927c478bd9Sstevel@tonic-gate static int slp_index	= 0;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * Returns the index of dport in the table if found, otherwise -1.
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate static int
4987c478bd9Sstevel@tonic-gate find_slp(uint_t dport) {
4997c478bd9Sstevel@tonic-gate     int i;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate     if (!dport)
5027c478bd9Sstevel@tonic-gate 	return (0);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate     for (i = slp_index; i >= 0; i--)
5057c478bd9Sstevel@tonic-gate 	if (slp_table[i] == dport) {
5067c478bd9Sstevel@tonic-gate 	    return (i);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate     for (i = SLP_CACHE_SIZE - 1; i > slp_index; i--)
5097c478bd9Sstevel@tonic-gate 	if (slp_table[i] == dport) {
5107c478bd9Sstevel@tonic-gate 	    return (i);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate     return (-1);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static void stash_slp(uint_t sport) {
5167c478bd9Sstevel@tonic-gate     if (slp_table[slp_index - 1] == sport)
5177c478bd9Sstevel@tonic-gate 	/* avoid redundancy due to multicast retransmissions */
5187c478bd9Sstevel@tonic-gate 	return;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate     slp_table[slp_index++] = sport;
5217c478bd9Sstevel@tonic-gate     if (slp_index == SLP_CACHE_SIZE)
5227c478bd9Sstevel@tonic-gate 	slp_index = 0;
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate  * This routine takes a packet and returns true or false
5277c478bd9Sstevel@tonic-gate  * according to whether the filter expression selects it
5287c478bd9Sstevel@tonic-gate  * or not.
5297c478bd9Sstevel@tonic-gate  * We assume here that offsets for short and long values
5307c478bd9Sstevel@tonic-gate  * are even - we may die with an alignment error if the
5317c478bd9Sstevel@tonic-gate  * CPU doesn't support odd addresses.  Note that long
5327c478bd9Sstevel@tonic-gate  * values are loaded as two shorts so that 32 bit word
5337c478bd9Sstevel@tonic-gate  * alignment isn't important.
5347c478bd9Sstevel@tonic-gate  *
5357c478bd9Sstevel@tonic-gate  * IPv6 is a bit stickier to handle than IPv4...
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate int
5397c478bd9Sstevel@tonic-gate want_packet(uchar_t *pkt, int len, int origlen)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	uint_t stack[MAXSS];	/* operand stack */
5427c478bd9Sstevel@tonic-gate 	uint_t *op;		/* current operator */
5437c478bd9Sstevel@tonic-gate 	uint_t *sp;		/* top of operand stack */
5447c478bd9Sstevel@tonic-gate 	uchar_t *base;		/* base for offsets into packet */
5457c478bd9Sstevel@tonic-gate 	uchar_t *ip;		/* addr of IP header, unaligned */
5467c478bd9Sstevel@tonic-gate 	uchar_t *tcp;		/* addr of TCP header, unaligned */
5477c478bd9Sstevel@tonic-gate 	uchar_t *udp;		/* addr of UDP header, unaligned */
5487c478bd9Sstevel@tonic-gate 	struct rpc_msg rpcmsg;	/* addr of RPC header */
5497c478bd9Sstevel@tonic-gate 	struct rpc_msg *rpc;
5507c478bd9Sstevel@tonic-gate 	int newrpc = 0;
5517c478bd9Sstevel@tonic-gate 	uchar_t *slphdr;		/* beginning of SLP header */
5527c478bd9Sstevel@tonic-gate 	uint_t slp_sport, slp_dport;
5537c478bd9Sstevel@tonic-gate 	int off, header_size;
5547c478bd9Sstevel@tonic-gate 	uchar_t *offstack[MAXSS];	/* offset stack */
5557c478bd9Sstevel@tonic-gate 	uchar_t **offp;		/* current offset */
5567c478bd9Sstevel@tonic-gate 	uchar_t *opkt = NULL;
5577c478bd9Sstevel@tonic-gate 	uint_t olen;
558*605445d5Sdg 	uint_t ethertype = 0;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	sp = stack;
5617c478bd9Sstevel@tonic-gate 	*sp = 1;
5627c478bd9Sstevel@tonic-gate 	base = pkt;
5637c478bd9Sstevel@tonic-gate 	offp = offstack;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	header_size = (*interface->header_len)((char *)pkt);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	for (op = oplist; *op; op++) {
5687c478bd9Sstevel@tonic-gate 		switch ((enum optype) *op) {
5697c478bd9Sstevel@tonic-gate 		case OP_LOAD_OCTET:
5707c478bd9Sstevel@tonic-gate 			if ((base + *sp) > (pkt + len))
5717c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 			*sp = *((uchar_t *)(base + *sp));
5747c478bd9Sstevel@tonic-gate 			break;
5757c478bd9Sstevel@tonic-gate 		case OP_LOAD_SHORT:
5767c478bd9Sstevel@tonic-gate 			off = *sp;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint16_t) - 1) > (pkt + len))
5797c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
5807c478bd9Sstevel@tonic-gate 
581*605445d5Sdg 			*sp = ntohs(get_u16((uchar_t *)(base + off)));
5827c478bd9Sstevel@tonic-gate 			break;
5837c478bd9Sstevel@tonic-gate 		case OP_LOAD_LONG:
5847c478bd9Sstevel@tonic-gate 			off = *sp;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 			if ((base + off + sizeof (uint32_t) - 1) > (pkt + len))
5877c478bd9Sstevel@tonic-gate 				return (0); /* packet too short */
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 			/*
5907c478bd9Sstevel@tonic-gate 			 * Handle 3 possible alignments
5917c478bd9Sstevel@tonic-gate 			 */
5927c478bd9Sstevel@tonic-gate 			switch ((((unsigned)base) + off) % sizeof (uint_t)) {
5937c478bd9Sstevel@tonic-gate 			case 0:
5947c478bd9Sstevel@tonic-gate 				*sp = *(uint_t *)(base + off);
5957c478bd9Sstevel@tonic-gate 				break;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 			case 2:
5987c478bd9Sstevel@tonic-gate 				*((ushort_t *)(sp)) =
5997c478bd9Sstevel@tonic-gate 					*((ushort_t *)(base + off));
6007c478bd9Sstevel@tonic-gate 				*(((ushort_t *)sp) + 1) =
6017c478bd9Sstevel@tonic-gate 					*((ushort_t *)(base + off) + 1);
6027c478bd9Sstevel@tonic-gate 				break;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 			case 1:
6057c478bd9Sstevel@tonic-gate 			case 3:
6067c478bd9Sstevel@tonic-gate 				*((uchar_t *)(sp)) =
6077c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off));
6087c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 1) =
6097c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 1);
6107c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 2) =
6117c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 2);
6127c478bd9Sstevel@tonic-gate 				*(((uchar_t *)sp) + 3) =
6137c478bd9Sstevel@tonic-gate 					*((uchar_t *)(base + off) + 3);
6147c478bd9Sstevel@tonic-gate 				break;
6157c478bd9Sstevel@tonic-gate 			}
6167c478bd9Sstevel@tonic-gate 			*sp = ntohl(*sp);
6177c478bd9Sstevel@tonic-gate 			break;
6187c478bd9Sstevel@tonic-gate 		case OP_LOAD_CONST:
6197c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
6207c478bd9Sstevel@tonic-gate 				return (0);
6217c478bd9Sstevel@tonic-gate 			*(++sp) = *(++op);
6227c478bd9Sstevel@tonic-gate 			break;
6237c478bd9Sstevel@tonic-gate 		case OP_LOAD_LENGTH:
6247c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
6257c478bd9Sstevel@tonic-gate 				return (0);
6267c478bd9Sstevel@tonic-gate 			*(++sp) = origlen;
6277c478bd9Sstevel@tonic-gate 			break;
6287c478bd9Sstevel@tonic-gate 		case OP_EQ:
6297c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6307c478bd9Sstevel@tonic-gate 				return (0);
6317c478bd9Sstevel@tonic-gate 			sp--;
6327c478bd9Sstevel@tonic-gate 			*sp = *sp == *(sp + 1);
6337c478bd9Sstevel@tonic-gate 			break;
6347c478bd9Sstevel@tonic-gate 		case OP_NE:
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_GT:
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_GE:
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_LT:
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_LE:
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_AND:
6657c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6667c478bd9Sstevel@tonic-gate 				return (0);
6677c478bd9Sstevel@tonic-gate 			sp--;
6687c478bd9Sstevel@tonic-gate 			*sp &= *(sp + 1);
6697c478bd9Sstevel@tonic-gate 			break;
6707c478bd9Sstevel@tonic-gate 		case OP_OR:
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_XOR:
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_NOT:
6837c478bd9Sstevel@tonic-gate 			*sp = !*sp;
6847c478bd9Sstevel@tonic-gate 			break;
6857c478bd9Sstevel@tonic-gate 		case OP_BRFL:
6867c478bd9Sstevel@tonic-gate 			op++;
6877c478bd9Sstevel@tonic-gate 			if (!*sp)
6887c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
6897c478bd9Sstevel@tonic-gate 			break;
6907c478bd9Sstevel@tonic-gate 		case OP_BRTR:
6917c478bd9Sstevel@tonic-gate 			op++;
6927c478bd9Sstevel@tonic-gate 			if (*sp)
6937c478bd9Sstevel@tonic-gate 				op = &oplist[*op] - 1;
6947c478bd9Sstevel@tonic-gate 			break;
6957c478bd9Sstevel@tonic-gate 		case OP_ADD:
6967c478bd9Sstevel@tonic-gate 			if (sp < &stack[1])
6977c478bd9Sstevel@tonic-gate 				return (0);
6987c478bd9Sstevel@tonic-gate 			sp--;
6997c478bd9Sstevel@tonic-gate 			*sp += *(sp + 1);
7007c478bd9Sstevel@tonic-gate 			break;
7017c478bd9Sstevel@tonic-gate 		case OP_SUB:
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_MUL:
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_DIV:
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_REM:
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_OFFSET_POP:
7267c478bd9Sstevel@tonic-gate 			if (offp < &offstack[0])
7277c478bd9Sstevel@tonic-gate 				return (0);
7287c478bd9Sstevel@tonic-gate 			base = *offp--;
7297c478bd9Sstevel@tonic-gate 			if (opkt != NULL) {
7307c478bd9Sstevel@tonic-gate 				pkt = opkt;
7317c478bd9Sstevel@tonic-gate 				len = olen;
7327c478bd9Sstevel@tonic-gate 				opkt = NULL;
7337c478bd9Sstevel@tonic-gate 			}
7347c478bd9Sstevel@tonic-gate 			break;
7357c478bd9Sstevel@tonic-gate 		case OP_OFFSET_ZERO:
7367c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7377c478bd9Sstevel@tonic-gate 				return (0);
7387c478bd9Sstevel@tonic-gate 			*++offp = base;
7397c478bd9Sstevel@tonic-gate 			base = pkt;
7407c478bd9Sstevel@tonic-gate 			break;
7417c478bd9Sstevel@tonic-gate 		case OP_OFFSET_LINK:
7427c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7437c478bd9Sstevel@tonic-gate 				return (0);
7447c478bd9Sstevel@tonic-gate 			*++offp = base;
7457c478bd9Sstevel@tonic-gate 			base = pkt + header_size;
7467c478bd9Sstevel@tonic-gate 			/*
7477c478bd9Sstevel@tonic-gate 			 * If the offset exceeds the packet length,
7487c478bd9Sstevel@tonic-gate 			 * we should not be interested in this packet...
7497c478bd9Sstevel@tonic-gate 			 * Just return 0.
7507c478bd9Sstevel@tonic-gate 			 */
7517c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7527c478bd9Sstevel@tonic-gate 				return (0);
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 			break;
7557c478bd9Sstevel@tonic-gate 		case OP_OFFSET_IP:
7567c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7577c478bd9Sstevel@tonic-gate 				return (0);
7587c478bd9Sstevel@tonic-gate 			*++offp = base;
7597c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7607c478bd9Sstevel@tonic-gate 			base = ip + ip_hdr_len(ip);
7617c478bd9Sstevel@tonic-gate 			if (base == ip) {
7627c478bd9Sstevel@tonic-gate 				return (0);			/* not IP */
7637c478bd9Sstevel@tonic-gate 			}
7647c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7657c478bd9Sstevel@tonic-gate 				return (0);			/* bad pkt */
7667c478bd9Sstevel@tonic-gate 			}
7677c478bd9Sstevel@tonic-gate 			break;
7687c478bd9Sstevel@tonic-gate 		case OP_OFFSET_TCP:
7697c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7707c478bd9Sstevel@tonic-gate 				return (0);
7717c478bd9Sstevel@tonic-gate 			*++offp = base;
7727c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7737c478bd9Sstevel@tonic-gate 			tcp = ip + ip_hdr_len(ip);
7747c478bd9Sstevel@tonic-gate 			if (tcp == ip) {
7757c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
7767c478bd9Sstevel@tonic-gate 			}
7777c478bd9Sstevel@tonic-gate 			base = tcp + TCP_HDR_LEN(tcp);
7787c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7797c478bd9Sstevel@tonic-gate 				return (0);
7807c478bd9Sstevel@tonic-gate 			}
7817c478bd9Sstevel@tonic-gate 			break;
7827c478bd9Sstevel@tonic-gate 		case OP_OFFSET_UDP:
7837c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7847c478bd9Sstevel@tonic-gate 				return (0);
7857c478bd9Sstevel@tonic-gate 			*++offp = base;
7867c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
7877c478bd9Sstevel@tonic-gate 			udp = ip + ip_hdr_len(ip);
7887c478bd9Sstevel@tonic-gate 			if (udp == ip) {
7897c478bd9Sstevel@tonic-gate 				return (0);			    /* not IP */
7907c478bd9Sstevel@tonic-gate 			}
7917c478bd9Sstevel@tonic-gate 			base = udp + sizeof (struct udphdr);
7927c478bd9Sstevel@tonic-gate 			if (base > pkt + len) {
7937c478bd9Sstevel@tonic-gate 				return (0);
7947c478bd9Sstevel@tonic-gate 			}
7957c478bd9Sstevel@tonic-gate 			break;
7967c478bd9Sstevel@tonic-gate 		case OP_OFFSET_RPC:
7977c478bd9Sstevel@tonic-gate 			if (offp >= &offstack[MAXSS])
7987c478bd9Sstevel@tonic-gate 				return (0);
7997c478bd9Sstevel@tonic-gate 			*++offp = base;
8007c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
8017c478bd9Sstevel@tonic-gate 			rpc = NULL;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
8047c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
8057c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8067c478bd9Sstevel@tonic-gate 					return (0);
8077c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8087c478bd9Sstevel@tonic-gate 				break;
8097c478bd9Sstevel@tonic-gate 			}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
8127c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
8137c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
8147c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(udp +
8157c478bd9Sstevel@tonic-gate 				    sizeof (struct udphdr));
8167c478bd9Sstevel@tonic-gate 				break;
8177c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
8187c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
8197c478bd9Sstevel@tonic-gate 				/*
8207c478bd9Sstevel@tonic-gate 				 * Need to skip an extra 4 for the xdr_rec
8217c478bd9Sstevel@tonic-gate 				 * field.
8227c478bd9Sstevel@tonic-gate 				 */
8237c478bd9Sstevel@tonic-gate 				rpc = (struct rpc_msg *)(tcp +
8247c478bd9Sstevel@tonic-gate 				    TCP_HDR_LEN(tcp) + 4);
8257c478bd9Sstevel@tonic-gate 				break;
8267c478bd9Sstevel@tonic-gate 			}
8277c478bd9Sstevel@tonic-gate 			/*
8287c478bd9Sstevel@tonic-gate 			 * We need to have at least 24 bytes of a RPC
8297c478bd9Sstevel@tonic-gate 			 * packet to look at to determine the validity
8307c478bd9Sstevel@tonic-gate 			 * of it.
8317c478bd9Sstevel@tonic-gate 			 */
8327c478bd9Sstevel@tonic-gate 			if (rpc == NULL || (uchar_t *)rpc + 24 > pkt + len) {
8337c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8347c478bd9Sstevel@tonic-gate 					return (0);
8357c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8367c478bd9Sstevel@tonic-gate 				break;
8377c478bd9Sstevel@tonic-gate 			}
8387c478bd9Sstevel@tonic-gate 			/* align */
8397c478bd9Sstevel@tonic-gate 			(void) memcpy(&rpcmsg, rpc, 24);
8407c478bd9Sstevel@tonic-gate 			if (!valid_rpc(&rpcmsg, 24)) {
8417c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8427c478bd9Sstevel@tonic-gate 					return (0);
8437c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8447c478bd9Sstevel@tonic-gate 				break;
8457c478bd9Sstevel@tonic-gate 			}
8467c478bd9Sstevel@tonic-gate 			if (ntohl(rpcmsg.rm_direction) == CALL) {
8477c478bd9Sstevel@tonic-gate 				base = (uchar_t *)rpc;
8487c478bd9Sstevel@tonic-gate 				newrpc = 1;
8497c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8507c478bd9Sstevel@tonic-gate 					return (0);
8517c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
8527c478bd9Sstevel@tonic-gate 			} else {
8537c478bd9Sstevel@tonic-gate 				opkt = pkt;
8547c478bd9Sstevel@tonic-gate 				olen = len;
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 				pkt = base = (uchar_t *)find_rpc(&rpcmsg);
8577c478bd9Sstevel@tonic-gate 				len = sizeof (struct xid_entry);
8587c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8597c478bd9Sstevel@tonic-gate 					return (0);
8607c478bd9Sstevel@tonic-gate 				*(++sp) = base != NULL;
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 			break;
8637c478bd9Sstevel@tonic-gate 		case OP_OFFSET_SLP:
8647c478bd9Sstevel@tonic-gate 			slphdr = NULL;
8657c478bd9Sstevel@tonic-gate 			ip = pkt + header_size;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 			if (IP_VERS(ip) != IPV4_VERSION &&
8687c478bd9Sstevel@tonic-gate 			    IP_VERS(ip) != IPV6_VERSION) {
8697c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8707c478bd9Sstevel@tonic-gate 					return (0);
8717c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8727c478bd9Sstevel@tonic-gate 				break;
8737c478bd9Sstevel@tonic-gate 			}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 			switch (ip_proto_of(ip)) {
8767c478bd9Sstevel@tonic-gate 				struct udphdr udp_h;
8777c478bd9Sstevel@tonic-gate 				struct tcphdr tcp_h;
8787c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
8797c478bd9Sstevel@tonic-gate 				udp = ip + ip_hdr_len(ip);
8807c478bd9Sstevel@tonic-gate 				/* align */
8817c478bd9Sstevel@tonic-gate 				memcpy(&udp_h, udp, sizeof (udp_h));
8827c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(udp_h.uh_sport);
8837c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(udp_h.uh_dport);
8847c478bd9Sstevel@tonic-gate 				slphdr = udp + sizeof (struct udphdr);
8857c478bd9Sstevel@tonic-gate 				break;
8867c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
8877c478bd9Sstevel@tonic-gate 				tcp = ip + ip_hdr_len(ip);
8887c478bd9Sstevel@tonic-gate 				/* align */
8897c478bd9Sstevel@tonic-gate 				memcpy(&tcp_h, tcp, sizeof (tcp_h));
8907c478bd9Sstevel@tonic-gate 				slp_sport = ntohs(tcp_h.th_sport);
8917c478bd9Sstevel@tonic-gate 				slp_dport = ntohs(tcp_h.th_dport);
8927c478bd9Sstevel@tonic-gate 				slphdr = tcp + TCP_HDR_LEN(tcp);
8937c478bd9Sstevel@tonic-gate 				break;
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 			if (slphdr == NULL || slphdr > pkt + len) {
8967c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
8977c478bd9Sstevel@tonic-gate 					return (0);
8987c478bd9Sstevel@tonic-gate 				*(++sp) = 0;
8997c478bd9Sstevel@tonic-gate 				break;
9007c478bd9Sstevel@tonic-gate 			}
9017c478bd9Sstevel@tonic-gate 			if (slp_sport == 427 || slp_dport == 427) {
9027c478bd9Sstevel@tonic-gate 				if (sp >= &stack[MAXSS])
9037c478bd9Sstevel@tonic-gate 					return (0);
9047c478bd9Sstevel@tonic-gate 				*(++sp) = 1;
9057c478bd9Sstevel@tonic-gate 				if (slp_sport != 427 && slp_dport == 427)
9067c478bd9Sstevel@tonic-gate 					stash_slp(slp_sport);
9077c478bd9Sstevel@tonic-gate 				break;
9087c478bd9Sstevel@tonic-gate 			} else if (find_slp(slp_dport) != -1) {
9097c478bd9Sstevel@tonic-gate 				if (valid_slp(slphdr, len)) {
9107c478bd9Sstevel@tonic-gate 					if (sp >= &stack[MAXSS])
9117c478bd9Sstevel@tonic-gate 						return (0);
9127c478bd9Sstevel@tonic-gate 					*(++sp) = 1;
9137c478bd9Sstevel@tonic-gate 					break;
9147c478bd9Sstevel@tonic-gate 				}
9157c478bd9Sstevel@tonic-gate 				/* else fallthrough to reject */
9167c478bd9Sstevel@tonic-gate 			}
9177c478bd9Sstevel@tonic-gate 			if (sp >= &stack[MAXSS])
9187c478bd9Sstevel@tonic-gate 				return (0);
9197c478bd9Sstevel@tonic-gate 			*(++sp) = 0;
9207c478bd9Sstevel@tonic-gate 			break;
921*605445d5Sdg 		case OP_OFFSET_ETHERTYPE:
922*605445d5Sdg 			/*
923*605445d5Sdg 			 * Set base to the location of the ethertype.
924*605445d5Sdg 			 * If the packet is VLAN tagged, move base
925*605445d5Sdg 			 * to the ethertype field in the VLAN header.
926*605445d5Sdg 			 * Otherwise, set it to the appropriate field
927*605445d5Sdg 			 * for this link type.
928*605445d5Sdg 			 */
929*605445d5Sdg 			if (offp >= &offstack[MAXSS])
930*605445d5Sdg 				return (0);
931*605445d5Sdg 			*++offp = base;
932*605445d5Sdg 			base = pkt + interface->network_type_offset;
933*605445d5Sdg 			if (base > pkt + len) {
934*605445d5Sdg 				/* Went too far, drop the packet */
935*605445d5Sdg 				return (0);
936*605445d5Sdg 			}
937*605445d5Sdg 
938*605445d5Sdg 			/*
939*605445d5Sdg 			 * VLAN links are only supported on Ethernet-like
940*605445d5Sdg 			 * links.
941*605445d5Sdg 			 */
942*605445d5Sdg 			if (interface->mac_type == DL_ETHER ||
943*605445d5Sdg 			    interface->mac_type == DL_CSMACD) {
944*605445d5Sdg 				if (ntohs(get_u16(base)) == ETHERTYPE_VLAN) {
945*605445d5Sdg 					/*
946*605445d5Sdg 					 * We need to point to the
947*605445d5Sdg 					 * ethertype field in the VLAN
948*605445d5Sdg 					 * tag, so also move past the
949*605445d5Sdg 					 * ethertype field in the
950*605445d5Sdg 					 * ethernet header.
951*605445d5Sdg 					 */
952*605445d5Sdg 					base += (ENCAP_ETHERTYPE_OFF);
953*605445d5Sdg 				}
954*605445d5Sdg 				if (base > pkt + len) {
955*605445d5Sdg 					/* Went too far, drop the packet */
956*605445d5Sdg 					return (0);
957*605445d5Sdg 				}
958*605445d5Sdg 			}
959*605445d5Sdg 			break;
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (*sp && newrpc)
9647c478bd9Sstevel@tonic-gate 		stash_rpc(&rpcmsg);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	return (*sp);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate static void
9707c478bd9Sstevel@tonic-gate load_const(uint_t constval)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate 	emitop(OP_LOAD_CONST);
9737c478bd9Sstevel@tonic-gate 	emitval(constval);
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate static void
9777c478bd9Sstevel@tonic-gate load_value(int offset, int len)
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	if (offset >= 0)
9807c478bd9Sstevel@tonic-gate 		load_const(offset);
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	switch (len) {
9837c478bd9Sstevel@tonic-gate 		case 1:
9847c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_OCTET);
9857c478bd9Sstevel@tonic-gate 			break;
9867c478bd9Sstevel@tonic-gate 		case 2:
9877c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_SHORT);
9887c478bd9Sstevel@tonic-gate 			break;
9897c478bd9Sstevel@tonic-gate 		case 4:
9907c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LONG);
9917c478bd9Sstevel@tonic-gate 			break;
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate /*
9967c478bd9Sstevel@tonic-gate  * Emit code to compare a field in
9977c478bd9Sstevel@tonic-gate  * the packet against a constant value.
9987c478bd9Sstevel@tonic-gate  */
9997c478bd9Sstevel@tonic-gate static void
10007c478bd9Sstevel@tonic-gate compare_value(uint_t offset, uint_t len, uint_t val)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate 	load_const(val);
10037c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10047c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate static void
10087c478bd9Sstevel@tonic-gate compare_addr_v4(uint_t offset, uint_t len, uint_t val)
10097c478bd9Sstevel@tonic-gate {
10107c478bd9Sstevel@tonic-gate 	load_const(ntohl(val));
10117c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10127c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static void
10167c478bd9Sstevel@tonic-gate compare_addr_v6(uint_t offset, uint_t len, struct in6_addr val)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	int i;
10197c478bd9Sstevel@tonic-gate 	uint32_t value;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i += 4) {
10227c478bd9Sstevel@tonic-gate 		value = ntohl(*(uint32_t *)&val.s6_addr[i]);
10237c478bd9Sstevel@tonic-gate 		load_const(value);
10247c478bd9Sstevel@tonic-gate 		load_value(offset + i, 4);
10257c478bd9Sstevel@tonic-gate 		emitop(OP_EQ);
10267c478bd9Sstevel@tonic-gate 		if (i != 0)
10277c478bd9Sstevel@tonic-gate 			emitop(OP_AND);
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate /*
10327c478bd9Sstevel@tonic-gate  * Same as above except do the comparison
10337c478bd9Sstevel@tonic-gate  * after and'ing a mask value.  Useful
10347c478bd9Sstevel@tonic-gate  * for comparing IP network numbers
10357c478bd9Sstevel@tonic-gate  */
10367c478bd9Sstevel@tonic-gate static void
10377c478bd9Sstevel@tonic-gate compare_value_mask(uint_t offset, uint_t len, uint_t val, int mask)
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	load_value(offset, len);
10407c478bd9Sstevel@tonic-gate 	load_const(mask);
10417c478bd9Sstevel@tonic-gate 	emitop(OP_AND);
10427c478bd9Sstevel@tonic-gate 	load_const(val);
10437c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate /* Emit an operator into the code array */
10477c478bd9Sstevel@tonic-gate static void
10487c478bd9Sstevel@tonic-gate emitop(enum optype opcode)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate 	if (curr_op >= &oplist[MAXOPS])
10517c478bd9Sstevel@tonic-gate 		pr_err("expression too long");
10527c478bd9Sstevel@tonic-gate 	*curr_op++ = opcode;
10537c478bd9Sstevel@tonic-gate }
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate /*
10567c478bd9Sstevel@tonic-gate  * Remove n operators recently emitted into
10577c478bd9Sstevel@tonic-gate  * the code array.  Used by alternation().
10587c478bd9Sstevel@tonic-gate  */
10597c478bd9Sstevel@tonic-gate static void
10607c478bd9Sstevel@tonic-gate unemit(int numops)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate 	curr_op -= numops;
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate  * Same as emitop except that we're emitting
10687c478bd9Sstevel@tonic-gate  * a value that's not an operator.
10697c478bd9Sstevel@tonic-gate  */
10707c478bd9Sstevel@tonic-gate static void
10717c478bd9Sstevel@tonic-gate emitval(uint_t val)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate 	if (curr_op >= &oplist[MAXOPS])
10747c478bd9Sstevel@tonic-gate 		pr_err("expression too long");
10757c478bd9Sstevel@tonic-gate 	*curr_op++ = val;
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate /*
10797c478bd9Sstevel@tonic-gate  * Used to chain forward branches together
10807c478bd9Sstevel@tonic-gate  * for later resolution by resolve_chain().
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate static uint_t
10837c478bd9Sstevel@tonic-gate chain(int p)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	uint_t pos = curr_op - oplist;
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	emitval(p);
10887c478bd9Sstevel@tonic-gate 	return (pos);
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate /*
10927c478bd9Sstevel@tonic-gate  * Proceed backward through the code array
10937c478bd9Sstevel@tonic-gate  * following a chain of forward references.
10947c478bd9Sstevel@tonic-gate  * At each reference install the destination
10957c478bd9Sstevel@tonic-gate  * branch offset.
10967c478bd9Sstevel@tonic-gate  */
10977c478bd9Sstevel@tonic-gate static void
10987c478bd9Sstevel@tonic-gate resolve_chain(uint_t p)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate 	uint_t n;
11017c478bd9Sstevel@tonic-gate 	uint_t pos = curr_op - oplist;
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	while (p) {
11047c478bd9Sstevel@tonic-gate 		n = oplist[p];
11057c478bd9Sstevel@tonic-gate 		oplist[p] = pos;
11067c478bd9Sstevel@tonic-gate 		p = n;
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate }
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate #define	EQ(val) (strcmp(token, val) == 0)
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate char *tkp, *sav_tkp;
11137c478bd9Sstevel@tonic-gate char *token;
11147c478bd9Sstevel@tonic-gate enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
11157c478bd9Sstevel@tonic-gate 	ADDR_IP6, ADDR_AT } tokentype;
11167c478bd9Sstevel@tonic-gate uint_t tokenval;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate /*
11197c478bd9Sstevel@tonic-gate  * This is the scanner.  Each call returns the next
11207c478bd9Sstevel@tonic-gate  * token in the filter expression.  A token is either:
11217c478bd9Sstevel@tonic-gate  * EOL:		The end of the line - no more tokens.
11227c478bd9Sstevel@tonic-gate  * ALPHA:	A name that begins with a letter and contains
11237c478bd9Sstevel@tonic-gate  *		letters or digits, hyphens or underscores.
11247c478bd9Sstevel@tonic-gate  * NUMBER:	A number.  The value can be represented as
11257c478bd9Sstevel@tonic-gate  * 		a decimal value (1234) or an octal value
11267c478bd9Sstevel@tonic-gate  *		that begins with zero (066) or a hex value
11277c478bd9Sstevel@tonic-gate  *		that begins with 0x or 0X (0xff).
11287c478bd9Sstevel@tonic-gate  * FIELD:	A name followed by a left square bracket.
11297c478bd9Sstevel@tonic-gate  * ADDR_IP:	An IP address.  Any sequence of digits
11307c478bd9Sstevel@tonic-gate  *		separated by dots e.g. 109.104.40.13
11317c478bd9Sstevel@tonic-gate  * ADDR_ETHER:	An ethernet address.  Any sequence of hex
11327c478bd9Sstevel@tonic-gate  *		digits separated by colons e.g. 8:0:20:0:76:39
11337c478bd9Sstevel@tonic-gate  * SPECIAL:	A special character e.g. ">" or "(".  The scanner
11347c478bd9Sstevel@tonic-gate  *		correctly handles digraphs - two special characters
11357c478bd9Sstevel@tonic-gate  *		that constitute a single token e.g. "==" or ">=".
11367c478bd9Sstevel@tonic-gate  * ADDR_IP6:    An IPv6 address.
11377c478bd9Sstevel@tonic-gate  *
11387c478bd9Sstevel@tonic-gate  * ADDR_AT:	An AppleTalk Phase II address. A sequence of two numbers
11397c478bd9Sstevel@tonic-gate  *		separated by a dot.
11407c478bd9Sstevel@tonic-gate  *
11417c478bd9Sstevel@tonic-gate  * The current token is maintained in "token" and and its
11427c478bd9Sstevel@tonic-gate  * type in "tokentype".  If tokentype is NUMBER then the
11437c478bd9Sstevel@tonic-gate  * value is held in "tokenval".
11447c478bd9Sstevel@tonic-gate  */
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate static const char *namechars =
11477c478bd9Sstevel@tonic-gate 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
11487c478bd9Sstevel@tonic-gate static const char *numchars = "0123456789abcdefABCDEFXx:.";
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate void
11517c478bd9Sstevel@tonic-gate next()
11527c478bd9Sstevel@tonic-gate {
11537c478bd9Sstevel@tonic-gate 	static int savechar;
11547c478bd9Sstevel@tonic-gate 	char *p;
11557c478bd9Sstevel@tonic-gate 	int size, size1;
11567c478bd9Sstevel@tonic-gate 	int base, colons, dots, alphas, double_colon;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	colons = 0;
11597c478bd9Sstevel@tonic-gate 	double_colon = 0;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	if (*tkp == '\0') {
11627c478bd9Sstevel@tonic-gate 		token = tkp;
11637c478bd9Sstevel@tonic-gate 		*tkp = savechar;
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	sav_tkp = tkp;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	while (isspace(*tkp)) tkp++;
11697c478bd9Sstevel@tonic-gate 	token = tkp;
11707c478bd9Sstevel@tonic-gate 	if (*token == '\0') {
11717c478bd9Sstevel@tonic-gate 		tokentype = EOL;
11727c478bd9Sstevel@tonic-gate 		return;
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/* A token containing ':' cannot be ALPHA type */
11767c478bd9Sstevel@tonic-gate 	tkp = token + strspn(token, numchars);
11777c478bd9Sstevel@tonic-gate 	for (p = token; p < tkp; p++) {
11787c478bd9Sstevel@tonic-gate 		if (*p == ':') {
11797c478bd9Sstevel@tonic-gate 			colons++;
11807c478bd9Sstevel@tonic-gate 			if (*(p+1) == ':')
11817c478bd9Sstevel@tonic-gate 				double_colon++;
11827c478bd9Sstevel@tonic-gate 		}
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	tkp = token;
11867c478bd9Sstevel@tonic-gate 	if (isalpha(*tkp) && !colons) {
11877c478bd9Sstevel@tonic-gate 		tokentype = ALPHA;
11887c478bd9Sstevel@tonic-gate 		tkp += strspn(tkp, namechars);
11897c478bd9Sstevel@tonic-gate 		if (*tkp == '[') {
11907c478bd9Sstevel@tonic-gate 			tokentype = FIELD;
11917c478bd9Sstevel@tonic-gate 			*tkp++ = '\0';
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 	} else
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	/*
11967c478bd9Sstevel@tonic-gate 	 * RFC1123 states that host names may now start with digits. Need
11977c478bd9Sstevel@tonic-gate 	 * to change parser to account for this. Also, need to distinguish
11987c478bd9Sstevel@tonic-gate 	 * between 1.2.3.4 and 1.2.3.a where the first case is an IP address
11997c478bd9Sstevel@tonic-gate 	 * and the second is a domain name. 333aaa needs to be distinguished
12007c478bd9Sstevel@tonic-gate 	 * from 0x333aaa. The first is a host name and the second is a number.
12017c478bd9Sstevel@tonic-gate 	 *
12027c478bd9Sstevel@tonic-gate 	 * The (colons > 1) conditional differentiates between ethernet
12037c478bd9Sstevel@tonic-gate 	 * and IPv6 addresses, and an expression of the form base[expr:size],
12047c478bd9Sstevel@tonic-gate 	 * which can only contain one ':' character.
12057c478bd9Sstevel@tonic-gate 	 */
12067c478bd9Sstevel@tonic-gate 	if (isdigit(*tkp) || colons > 1) {
12077c478bd9Sstevel@tonic-gate 		tkp = token + strspn(token, numchars);
12087c478bd9Sstevel@tonic-gate 		dots = alphas = 0;
12097c478bd9Sstevel@tonic-gate 		for (p = token; p < tkp; p++) {
12107c478bd9Sstevel@tonic-gate 			if (*p == '.')
12117c478bd9Sstevel@tonic-gate 				dots++;
12127c478bd9Sstevel@tonic-gate 			else if (isalpha(*p))
12137c478bd9Sstevel@tonic-gate 				alphas = 1;
12147c478bd9Sstevel@tonic-gate 		}
12157c478bd9Sstevel@tonic-gate 		if (colons > 1) {
12167c478bd9Sstevel@tonic-gate 			if (colons == 5 && double_colon == 0) {
12177c478bd9Sstevel@tonic-gate 				tokentype = ADDR_ETHER;
12187c478bd9Sstevel@tonic-gate 			} else {
12197c478bd9Sstevel@tonic-gate 				tokentype = ADDR_IP6;
12207c478bd9Sstevel@tonic-gate 			}
12217c478bd9Sstevel@tonic-gate 		} else if (dots) {
12227c478bd9Sstevel@tonic-gate 			size = tkp - token;
12237c478bd9Sstevel@tonic-gate 			size1 = strspn(token, "0123456789.");
12247c478bd9Sstevel@tonic-gate 			if (dots == 1 && size == size1) {
12257c478bd9Sstevel@tonic-gate 				tokentype = ADDR_AT;
12267c478bd9Sstevel@tonic-gate 			} else
12277c478bd9Sstevel@tonic-gate 				if (dots != 3 || size != size1) {
12287c478bd9Sstevel@tonic-gate 					tokentype = ALPHA;
12297c478bd9Sstevel@tonic-gate 					if (*tkp != '\0' && !isspace(*tkp)) {
12307c478bd9Sstevel@tonic-gate 						tkp += strspn(tkp, namechars);
12317c478bd9Sstevel@tonic-gate 						if (*tkp == '[') {
12327c478bd9Sstevel@tonic-gate 							tokentype = FIELD;
12337c478bd9Sstevel@tonic-gate 							*tkp++ = '\0';
12347c478bd9Sstevel@tonic-gate 						}
12357c478bd9Sstevel@tonic-gate 					}
12367c478bd9Sstevel@tonic-gate 				} else
12377c478bd9Sstevel@tonic-gate 					tokentype = ADDR_IP;
12387c478bd9Sstevel@tonic-gate 		} else if (token + strspn(token, namechars) <= tkp) {
12397c478bd9Sstevel@tonic-gate 			/*
12407c478bd9Sstevel@tonic-gate 			 * With the above check, if there are more
12417c478bd9Sstevel@tonic-gate 			 * characters after the last digit, assume
12427c478bd9Sstevel@tonic-gate 			 * that it is not a number.
12437c478bd9Sstevel@tonic-gate 			 */
12447c478bd9Sstevel@tonic-gate 			tokentype = NUMBER;
12457c478bd9Sstevel@tonic-gate 			p = tkp;
12467c478bd9Sstevel@tonic-gate 			tkp = token;
12477c478bd9Sstevel@tonic-gate 			base = 10;
12487c478bd9Sstevel@tonic-gate 			if (*tkp == '0') {
12497c478bd9Sstevel@tonic-gate 				base = 8;
12507c478bd9Sstevel@tonic-gate 				tkp++;
12517c478bd9Sstevel@tonic-gate 				if (*tkp == 'x' || *tkp == 'X')
12527c478bd9Sstevel@tonic-gate 					base = 16;
12537c478bd9Sstevel@tonic-gate 			}
12547c478bd9Sstevel@tonic-gate 			if ((base == 10 || base == 8) && alphas) {
12557c478bd9Sstevel@tonic-gate 				tokentype = ALPHA;
12567c478bd9Sstevel@tonic-gate 				tkp = p;
12577c478bd9Sstevel@tonic-gate 			} else if (base == 16) {
12587c478bd9Sstevel@tonic-gate 				size = 2 + strspn(token+2,
12597c478bd9Sstevel@tonic-gate 					"0123456789abcdefABCDEF");
12607c478bd9Sstevel@tonic-gate 				size1 = p - token;
12617c478bd9Sstevel@tonic-gate 				if (size != size1) {
12627c478bd9Sstevel@tonic-gate 					tokentype = ALPHA;
12637c478bd9Sstevel@tonic-gate 					tkp = p;
12647c478bd9Sstevel@tonic-gate 				} else
12657c478bd9Sstevel@tonic-gate 				/*
12667c478bd9Sstevel@tonic-gate 				 * handles the case of 0x so an error message
12677c478bd9Sstevel@tonic-gate 				 * is not printed. Treats 0x as 0.
12687c478bd9Sstevel@tonic-gate 				 */
12697c478bd9Sstevel@tonic-gate 				if (size == 2) {
12707c478bd9Sstevel@tonic-gate 					tokenval = 0;
12717c478bd9Sstevel@tonic-gate 					tkp = token +2;
12727c478bd9Sstevel@tonic-gate 				} else {
12737c478bd9Sstevel@tonic-gate 					tokenval = strtoul(token, &tkp, base);
12747c478bd9Sstevel@tonic-gate 				}
12757c478bd9Sstevel@tonic-gate 			} else {
12767c478bd9Sstevel@tonic-gate 				tokenval = strtoul(token, &tkp, base);
12777c478bd9Sstevel@tonic-gate 			}
12787c478bd9Sstevel@tonic-gate 		} else {
12797c478bd9Sstevel@tonic-gate 			tokentype = ALPHA;
12807c478bd9Sstevel@tonic-gate 			tkp += strspn(tkp, namechars);
12817c478bd9Sstevel@tonic-gate 			if (*tkp == '[') {
12827c478bd9Sstevel@tonic-gate 				tokentype = FIELD;
12837c478bd9Sstevel@tonic-gate 				*tkp++ = '\0';
12847c478bd9Sstevel@tonic-gate 			}
12857c478bd9Sstevel@tonic-gate 		}
12867c478bd9Sstevel@tonic-gate 	} else {
12877c478bd9Sstevel@tonic-gate 		tokentype = SPECIAL;
12887c478bd9Sstevel@tonic-gate 		tkp++;
12897c478bd9Sstevel@tonic-gate 		if ((*token == '=' && *tkp == '=') ||
12907c478bd9Sstevel@tonic-gate 		    (*token == '>' && *tkp == '=') ||
12917c478bd9Sstevel@tonic-gate 		    (*token == '<' && *tkp == '=') ||
12927c478bd9Sstevel@tonic-gate 		    (*token == '!' && *tkp == '='))
12937c478bd9Sstevel@tonic-gate 				tkp++;
12947c478bd9Sstevel@tonic-gate 	}
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	savechar = *tkp;
12977c478bd9Sstevel@tonic-gate 	*tkp = '\0';
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate static struct match_type {
13017c478bd9Sstevel@tonic-gate 	char		*m_name;
13027c478bd9Sstevel@tonic-gate 	int		m_offset;
13037c478bd9Sstevel@tonic-gate 	int		m_size;
13047c478bd9Sstevel@tonic-gate 	int		m_value;
13057c478bd9Sstevel@tonic-gate 	int		m_depend;
13067c478bd9Sstevel@tonic-gate 	enum optype	m_optype;
13077c478bd9Sstevel@tonic-gate } match_types[] = {
13087c478bd9Sstevel@tonic-gate 	/*
13097c478bd9Sstevel@tonic-gate 	 * Table initialized assuming Ethernet data link headers.
1310*605445d5Sdg 	 * m_offset is an offset beyond the offset op, which is why
1311*605445d5Sdg 	 * the offset is zero for when snoop needs to check an ethertype.
13127c478bd9Sstevel@tonic-gate 	 */
1313*605445d5Sdg 	"ip",		0,  2, ETHERTYPE_IP,	 -1,	OP_OFFSET_ETHERTYPE,
1314*605445d5Sdg 	"ip6",		0,  2, ETHERTYPE_IPV6,	 -1,	OP_OFFSET_ETHERTYPE,
1315*605445d5Sdg 	"arp",		0,  2, ETHERTYPE_ARP,	 -1,	OP_OFFSET_ETHERTYPE,
1316*605445d5Sdg 	"rarp",		0,  2, ETHERTYPE_REVARP, -1,	OP_OFFSET_ETHERTYPE,
1317*605445d5Sdg 	"pppoed",	0,  2, ETHERTYPE_PPPOED, -1,	OP_OFFSET_ETHERTYPE,
1318*605445d5Sdg 	"pppoes",	0,  2, ETHERTYPE_PPPOES, -1,	OP_OFFSET_ETHERTYPE,
1319*605445d5Sdg 	"tcp",		9,  1, IPPROTO_TCP,	 0,	OP_OFFSET_LINK,
1320*605445d5Sdg 	"tcp",		6,  1, IPPROTO_TCP,	 1,	OP_OFFSET_LINK,
1321*605445d5Sdg 	"udp",		9,  1, IPPROTO_UDP,	 0,	OP_OFFSET_LINK,
1322*605445d5Sdg 	"udp",		6,  1, IPPROTO_UDP,	 1,	OP_OFFSET_LINK,
1323*605445d5Sdg 	"icmp",		9,  1, IPPROTO_ICMP,	 0,	OP_OFFSET_LINK,
1324*605445d5Sdg 	"icmp6",	6,  1, IPPROTO_ICMPV6,	 1,	OP_OFFSET_LINK,
1325*605445d5Sdg 	"ospf",		9,  1, IPPROTO_OSPF,	 0,	OP_OFFSET_LINK,
1326*605445d5Sdg 	"ospf",		6,  1, IPPROTO_OSPF,	 1,	OP_OFFSET_LINK,
1327*605445d5Sdg 	"ip-in-ip",	9,  1, IPPROTO_ENCAP,	 0,	OP_OFFSET_LINK,
1328*605445d5Sdg 	"esp",		9,  1, IPPROTO_ESP,	 0,	OP_OFFSET_LINK,
1329*605445d5Sdg 	"esp",		6,  1, IPPROTO_ESP,	 1,	OP_OFFSET_LINK,
1330*605445d5Sdg 	"ah",		9,  1, IPPROTO_AH,	 0,	OP_OFFSET_LINK,
1331*605445d5Sdg 	"ah",		6,  1, IPPROTO_AH,	 1,	OP_OFFSET_LINK,
1332*605445d5Sdg 	"sctp",		9,  1, IPPROTO_SCTP,	 0,	OP_OFFSET_LINK,
1333*605445d5Sdg 	"sctp",		6,  1, IPPROTO_SCTP,	 1,	OP_OFFSET_LINK,
1334*605445d5Sdg 	0,		0,  0, 0,		 0,	0
13357c478bd9Sstevel@tonic-gate };
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate static void
13387c478bd9Sstevel@tonic-gate generate_check(struct match_type *mtp)
13397c478bd9Sstevel@tonic-gate {
13407c478bd9Sstevel@tonic-gate 	/*
13417c478bd9Sstevel@tonic-gate 	 * Note: this code assumes the above dependencies are
13427c478bd9Sstevel@tonic-gate 	 * not cyclic.  This *should* always be true.
13437c478bd9Sstevel@tonic-gate 	 */
13447c478bd9Sstevel@tonic-gate 	if (mtp->m_depend != -1)
13457c478bd9Sstevel@tonic-gate 		generate_check(&match_types[mtp->m_depend]);
13467c478bd9Sstevel@tonic-gate 
1347*605445d5Sdg 	emitop(mtp->m_optype);
1348*605445d5Sdg 	load_value(mtp->m_offset, mtp->m_size);
1349*605445d5Sdg 	load_const(mtp->m_value);
1350*605445d5Sdg 	emitop(OP_OFFSET_POP);
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	emitop(OP_EQ);
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	if (mtp->m_depend != -1)
13557c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate  * Generate code based on the keyword argument.
13607c478bd9Sstevel@tonic-gate  * This word is looked up in the match_types table
13617c478bd9Sstevel@tonic-gate  * and checks a field within the packet for a given
13627c478bd9Sstevel@tonic-gate  * value e.g. ether or ip type field.  The match
13637c478bd9Sstevel@tonic-gate  * can also have a dependency on another entry e.g.
13647c478bd9Sstevel@tonic-gate  * "tcp" requires that the packet also be "ip".
13657c478bd9Sstevel@tonic-gate  */
13667c478bd9Sstevel@tonic-gate static int
13677c478bd9Sstevel@tonic-gate comparison(char *s)
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate 	unsigned int	i, n_checks = 0;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	for (i = 0; match_types[i].m_name != NULL; i++) {
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 		if (strcmp(s, match_types[i].m_name) != 0)
13747c478bd9Sstevel@tonic-gate 			continue;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 		n_checks++;
13777c478bd9Sstevel@tonic-gate 		generate_check(&match_types[i]);
13787c478bd9Sstevel@tonic-gate 		if (n_checks > 1)
13797c478bd9Sstevel@tonic-gate 			emitop(OP_OR);
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	return (n_checks > 0);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate enum direction { ANY, TO, FROM };
13867c478bd9Sstevel@tonic-gate enum direction dir;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate  * Generate code to match an IP address.  The address
13907c478bd9Sstevel@tonic-gate  * may be supplied either as a hostname or in dotted format.
13917c478bd9Sstevel@tonic-gate  * For source packets both the IP source address and ARP
13927c478bd9Sstevel@tonic-gate  * src are checked.
13937c478bd9Sstevel@tonic-gate  * Note: we don't check packet type here - whether IP or ARP.
13947c478bd9Sstevel@tonic-gate  * It's possible that we'll do an improper match.
13957c478bd9Sstevel@tonic-gate  */
13967c478bd9Sstevel@tonic-gate static void
13977c478bd9Sstevel@tonic-gate ipaddr_match(enum direction which, char *hostname, int inet_type)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate 	bool_t found_host;
14007c478bd9Sstevel@tonic-gate 	int m = 0, n = 0;
14017c478bd9Sstevel@tonic-gate 	uint_t *addr4ptr;
14027c478bd9Sstevel@tonic-gate 	uint_t addr4;
14037c478bd9Sstevel@tonic-gate 	struct in6_addr *addr6ptr;
14047c478bd9Sstevel@tonic-gate 	int h_addr_index;
14057c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
14067c478bd9Sstevel@tonic-gate 	int error_num = 0;
14077c478bd9Sstevel@tonic-gate 	boolean_t freehp = B_FALSE;
14087c478bd9Sstevel@tonic-gate 	boolean_t first = B_TRUE;
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	/*
14117c478bd9Sstevel@tonic-gate 	 * The addr4offset and addr6offset variables simplify the code which
14127c478bd9Sstevel@tonic-gate 	 * generates the address comparison filter.  With these two variables,
14137c478bd9Sstevel@tonic-gate 	 * duplicate code need not exist for the TO and FROM case.
14147c478bd9Sstevel@tonic-gate 	 * A value of -1 describes the ANY case (TO and FROM).
14157c478bd9Sstevel@tonic-gate 	 */
14167c478bd9Sstevel@tonic-gate 	int addr4offset;
14177c478bd9Sstevel@tonic-gate 	int addr6offset;
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	found_host = 0;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	if (tokentype == ADDR_IP) {
14227c478bd9Sstevel@tonic-gate 		hp = lgetipnodebyname(hostname, AF_INET,
14237c478bd9Sstevel@tonic-gate 					0, &error_num);
14247c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
14257c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET,
14267c478bd9Sstevel@tonic-gate 							0, &error_num);
14277c478bd9Sstevel@tonic-gate 			freehp = 1;
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
14307c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
14317c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s (try again later)",
14327c478bd9Sstevel@tonic-gate 				    hostname);
14337c478bd9Sstevel@tonic-gate 			} else {
14347c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s", hostname);
14357c478bd9Sstevel@tonic-gate 			}
14367c478bd9Sstevel@tonic-gate 		}
14377c478bd9Sstevel@tonic-gate 		inet_type = IPV4_ONLY;
14387c478bd9Sstevel@tonic-gate 	} else if (tokentype == ADDR_IP6) {
14397c478bd9Sstevel@tonic-gate 		hp = lgetipnodebyname(hostname, AF_INET6,
14407c478bd9Sstevel@tonic-gate 					0, &error_num);
14417c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
14427c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6,
14437c478bd9Sstevel@tonic-gate 							0, &error_num);
14447c478bd9Sstevel@tonic-gate 			freehp = 1;
14457c478bd9Sstevel@tonic-gate 		}
14467c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
14477c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
14487c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s (try again later)",
14497c478bd9Sstevel@tonic-gate 				    hostname);
14507c478bd9Sstevel@tonic-gate 			} else {
14517c478bd9Sstevel@tonic-gate 				pr_err("couldn't resolve %s", hostname);
14527c478bd9Sstevel@tonic-gate 			}
14537c478bd9Sstevel@tonic-gate 		}
14547c478bd9Sstevel@tonic-gate 		inet_type = IPV6_ONLY;
14557c478bd9Sstevel@tonic-gate 	} else {
14567c478bd9Sstevel@tonic-gate 		/* Some hostname i.e. tokentype is ALPHA */
14577c478bd9Sstevel@tonic-gate 		switch (inet_type) {
14587c478bd9Sstevel@tonic-gate 		case IPV4_ONLY:
14597c478bd9Sstevel@tonic-gate 			/* Only IPv4 address is needed */
14607c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET,
14617c478bd9Sstevel@tonic-gate 						0, &error_num);
14627c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
14637c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET,
14647c478bd9Sstevel@tonic-gate 								0, &error_num);
14657c478bd9Sstevel@tonic-gate 				freehp = 1;
14667c478bd9Sstevel@tonic-gate 			}
14677c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
14687c478bd9Sstevel@tonic-gate 				found_host = 1;
14697c478bd9Sstevel@tonic-gate 			}
14707c478bd9Sstevel@tonic-gate 			break;
14717c478bd9Sstevel@tonic-gate 		case IPV6_ONLY:
14727c478bd9Sstevel@tonic-gate 			/* Only IPv6 address is needed */
14737c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET6,
14747c478bd9Sstevel@tonic-gate 						0, &error_num);
14757c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
14767c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET6,
14777c478bd9Sstevel@tonic-gate 								0, &error_num);
14787c478bd9Sstevel@tonic-gate 				freehp = 1;
14797c478bd9Sstevel@tonic-gate 			}
14807c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
14817c478bd9Sstevel@tonic-gate 				found_host = 1;
14827c478bd9Sstevel@tonic-gate 			}
14837c478bd9Sstevel@tonic-gate 			break;
14847c478bd9Sstevel@tonic-gate 		case IPV4_AND_IPV6:
14857c478bd9Sstevel@tonic-gate 			/* Both IPv4 and IPv6 are needed */
14867c478bd9Sstevel@tonic-gate 			hp = lgetipnodebyname(hostname, AF_INET6,
14877c478bd9Sstevel@tonic-gate 					AI_ALL | AI_V4MAPPED, &error_num);
14887c478bd9Sstevel@tonic-gate 			if (hp == NULL) {
14897c478bd9Sstevel@tonic-gate 				hp = getipnodebyname(hostname, AF_INET6,
14907c478bd9Sstevel@tonic-gate 					AI_ALL | AI_V4MAPPED, &error_num);
14917c478bd9Sstevel@tonic-gate 				freehp = 1;
14927c478bd9Sstevel@tonic-gate 			}
14937c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
14947c478bd9Sstevel@tonic-gate 				found_host = 1;
14957c478bd9Sstevel@tonic-gate 			}
14967c478bd9Sstevel@tonic-gate 			break;
14977c478bd9Sstevel@tonic-gate 		default:
14987c478bd9Sstevel@tonic-gate 			found_host = 0;
14997c478bd9Sstevel@tonic-gate 		}
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		if (!found_host) {
15027c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
15037c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
15047c478bd9Sstevel@tonic-gate 				    hostname);
15057c478bd9Sstevel@tonic-gate 			} else {
15067c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
15077c478bd9Sstevel@tonic-gate 			}
15087c478bd9Sstevel@tonic-gate 		}
15097c478bd9Sstevel@tonic-gate 	}
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	switch (which) {
15127c478bd9Sstevel@tonic-gate 	case TO:
15137c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_DSTADDR_OFFSET;
15147c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_DSTADDR_OFFSET;
15157c478bd9Sstevel@tonic-gate 		break;
15167c478bd9Sstevel@tonic-gate 	case FROM:
15177c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_SRCADDR_OFFSET;
15187c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_SRCADDR_OFFSET;
15197c478bd9Sstevel@tonic-gate 		break;
15207c478bd9Sstevel@tonic-gate 	case ANY:
15217c478bd9Sstevel@tonic-gate 		addr4offset = -1;
15227c478bd9Sstevel@tonic-gate 		addr6offset = -1;
15237c478bd9Sstevel@tonic-gate 		break;
15247c478bd9Sstevel@tonic-gate 	}
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	/*
15277c478bd9Sstevel@tonic-gate 	 * The code below generates the filter.
15287c478bd9Sstevel@tonic-gate 	 */
15297c478bd9Sstevel@tonic-gate 	if (hp != NULL && hp->h_addrtype == AF_INET) {
15307c478bd9Sstevel@tonic-gate 		ethertype_match(ETHERTYPE_IP);
15317c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
15327c478bd9Sstevel@tonic-gate 		n = chain(n);
15337c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_LINK);
15347c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
15357c478bd9Sstevel@tonic-gate 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
15367c478bd9Sstevel@tonic-gate 		while (addr4ptr != NULL) {
15377c478bd9Sstevel@tonic-gate 			if (addr4offset == -1) {
15387c478bd9Sstevel@tonic-gate 				compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
15397c478bd9Sstevel@tonic-gate 				    *addr4ptr);
15407c478bd9Sstevel@tonic-gate 				emitop(OP_BRTR);
15417c478bd9Sstevel@tonic-gate 				m = chain(m);
15427c478bd9Sstevel@tonic-gate 				compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
15437c478bd9Sstevel@tonic-gate 				    *addr4ptr);
15447c478bd9Sstevel@tonic-gate 			} else {
15457c478bd9Sstevel@tonic-gate 				compare_addr_v4(addr4offset, 4, *addr4ptr);
15467c478bd9Sstevel@tonic-gate 			}
15477c478bd9Sstevel@tonic-gate 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
15487c478bd9Sstevel@tonic-gate 			if (addr4ptr != NULL) {
15497c478bd9Sstevel@tonic-gate 				emitop(OP_BRTR);
15507c478bd9Sstevel@tonic-gate 				m = chain(m);
15517c478bd9Sstevel@tonic-gate 			}
15527c478bd9Sstevel@tonic-gate 		}
15537c478bd9Sstevel@tonic-gate 		if (m != 0) {
15547c478bd9Sstevel@tonic-gate 			resolve_chain(m);
15557c478bd9Sstevel@tonic-gate 		}
15567c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_POP);
15577c478bd9Sstevel@tonic-gate 		resolve_chain(n);
15587c478bd9Sstevel@tonic-gate 	} else {
15597c478bd9Sstevel@tonic-gate 		/* first pass: IPv4 addresses */
15607c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
15617c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
15627c478bd9Sstevel@tonic-gate 		first = B_TRUE;
15637c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
15647c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
15657c478bd9Sstevel@tonic-gate 				if (first) {
15667c478bd9Sstevel@tonic-gate 					ethertype_match(ETHERTYPE_IP);
15677c478bd9Sstevel@tonic-gate 					emitop(OP_BRFL);
15687c478bd9Sstevel@tonic-gate 					n = chain(n);
15697c478bd9Sstevel@tonic-gate 					emitop(OP_OFFSET_LINK);
15707c478bd9Sstevel@tonic-gate 					first = B_FALSE;
15717c478bd9Sstevel@tonic-gate 				} else {
15727c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
15737c478bd9Sstevel@tonic-gate 					m = chain(m);
15747c478bd9Sstevel@tonic-gate 				}
15757c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
15767c478bd9Sstevel@tonic-gate 				    (struct in_addr *)&addr4);
15777c478bd9Sstevel@tonic-gate 				if (addr4offset == -1) {
15787c478bd9Sstevel@tonic-gate 					compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
15797c478bd9Sstevel@tonic-gate 					    addr4);
15807c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
15817c478bd9Sstevel@tonic-gate 					m = chain(m);
15827c478bd9Sstevel@tonic-gate 					compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
15837c478bd9Sstevel@tonic-gate 					    addr4);
15847c478bd9Sstevel@tonic-gate 				} else {
15857c478bd9Sstevel@tonic-gate 					compare_addr_v4(addr4offset, 4, addr4);
15867c478bd9Sstevel@tonic-gate 				}
15877c478bd9Sstevel@tonic-gate 			}
15887c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
15897c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
15907c478bd9Sstevel@tonic-gate 		}
15917c478bd9Sstevel@tonic-gate 		/* second pass: IPv6 addresses */
15927c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
15937c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
15947c478bd9Sstevel@tonic-gate 		first = B_TRUE;
15957c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
15967c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
15977c478bd9Sstevel@tonic-gate 				if (first) {
15987c478bd9Sstevel@tonic-gate 					/*
15997c478bd9Sstevel@tonic-gate 					 * bypass check for IPv6 addresses
16007c478bd9Sstevel@tonic-gate 					 * when we have an IPv4 packet
16017c478bd9Sstevel@tonic-gate 					 */
16027c478bd9Sstevel@tonic-gate 					if (n != 0) {
16037c478bd9Sstevel@tonic-gate 						emitop(OP_BRTR);
16047c478bd9Sstevel@tonic-gate 						m = chain(m);
16057c478bd9Sstevel@tonic-gate 						emitop(OP_BRFL);
16067c478bd9Sstevel@tonic-gate 						m = chain(m);
16077c478bd9Sstevel@tonic-gate 						resolve_chain(n);
16087c478bd9Sstevel@tonic-gate 						n = 0;
16097c478bd9Sstevel@tonic-gate 					}
16107c478bd9Sstevel@tonic-gate 					ethertype_match(ETHERTYPE_IPV6);
16117c478bd9Sstevel@tonic-gate 					emitop(OP_BRFL);
16127c478bd9Sstevel@tonic-gate 					n = chain(n);
16137c478bd9Sstevel@tonic-gate 					emitop(OP_OFFSET_LINK);
16147c478bd9Sstevel@tonic-gate 					first = B_FALSE;
16157c478bd9Sstevel@tonic-gate 				} else {
16167c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
16177c478bd9Sstevel@tonic-gate 					m = chain(m);
16187c478bd9Sstevel@tonic-gate 				}
16197c478bd9Sstevel@tonic-gate 				if (addr6offset == -1) {
16207c478bd9Sstevel@tonic-gate 					compare_addr_v6(IPV6_SRCADDR_OFFSET,
16217c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
16227c478bd9Sstevel@tonic-gate 					emitop(OP_BRTR);
16237c478bd9Sstevel@tonic-gate 					m = chain(m);
16247c478bd9Sstevel@tonic-gate 					compare_addr_v6(IPV6_DSTADDR_OFFSET,
16257c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
16267c478bd9Sstevel@tonic-gate 				} else {
16277c478bd9Sstevel@tonic-gate 					compare_addr_v6(addr6offset, 16,
16287c478bd9Sstevel@tonic-gate 					    *addr6ptr);
16297c478bd9Sstevel@tonic-gate 				}
16307c478bd9Sstevel@tonic-gate 			}
16317c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
16327c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
16337c478bd9Sstevel@tonic-gate 		}
16347c478bd9Sstevel@tonic-gate 		if (m != 0) {
16357c478bd9Sstevel@tonic-gate 			resolve_chain(m);
16367c478bd9Sstevel@tonic-gate 		}
16377c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_POP);
16387c478bd9Sstevel@tonic-gate 		resolve_chain(n);
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	/* only free struct hostent returned by getipnodebyname() */
16427c478bd9Sstevel@tonic-gate 	if (freehp) {
16437c478bd9Sstevel@tonic-gate 		freehostent(hp);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate }
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate /*
16487c478bd9Sstevel@tonic-gate  * Generate code to match an AppleTalk address.  The address
16497c478bd9Sstevel@tonic-gate  * must be given as two numbers with a dot between
16507c478bd9Sstevel@tonic-gate  *
16517c478bd9Sstevel@tonic-gate  */
16527c478bd9Sstevel@tonic-gate static void
16537c478bd9Sstevel@tonic-gate ataddr_match(enum direction which, char *hostname)
16547c478bd9Sstevel@tonic-gate {
16557c478bd9Sstevel@tonic-gate 	uint_t net;
16567c478bd9Sstevel@tonic-gate 	uint_t node;
16577c478bd9Sstevel@tonic-gate 	uint_t m, n;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	sscanf(hostname, "%u.%u", &net, &node);
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_LINK);
16627c478bd9Sstevel@tonic-gate 	switch (which) {
16637c478bd9Sstevel@tonic-gate 	case TO:
16647c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NET_OFFSET, 2, net);
16657c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
16667c478bd9Sstevel@tonic-gate 		m = chain(0);
16677c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NODE_OFFSET, 1, node);
16687c478bd9Sstevel@tonic-gate 		resolve_chain(m);
16697c478bd9Sstevel@tonic-gate 		break;
16707c478bd9Sstevel@tonic-gate 	case FROM:
16717c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NET_OFFSET, 2, net);
16727c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
16737c478bd9Sstevel@tonic-gate 		m = chain(0);
16747c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NODE_OFFSET, 1, node);
16757c478bd9Sstevel@tonic-gate 		resolve_chain(m);
16767c478bd9Sstevel@tonic-gate 		break;
16777c478bd9Sstevel@tonic-gate 	case ANY:
16787c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NET_OFFSET, 2, net);
16797c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
16807c478bd9Sstevel@tonic-gate 		m = chain(0);
16817c478bd9Sstevel@tonic-gate 		compare_value(AT_DST_NODE_OFFSET, 1, node);
16827c478bd9Sstevel@tonic-gate 		resolve_chain(m);
16837c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
16847c478bd9Sstevel@tonic-gate 		n = chain(0);
16857c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NET_OFFSET, 2, net);
16867c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
16877c478bd9Sstevel@tonic-gate 		m = chain(0);
16887c478bd9Sstevel@tonic-gate 		compare_value(AT_SRC_NODE_OFFSET, 1, node);
16897c478bd9Sstevel@tonic-gate 		resolve_chain(m);
16907c478bd9Sstevel@tonic-gate 		resolve_chain(n);
16917c478bd9Sstevel@tonic-gate 		break;
16927c478bd9Sstevel@tonic-gate 	}
16937c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate  * Compare ethernet addresses. The address may
16987c478bd9Sstevel@tonic-gate  * be provided either as a hostname or as a
16997c478bd9Sstevel@tonic-gate  * 6 octet colon-separated address.
17007c478bd9Sstevel@tonic-gate  */
17017c478bd9Sstevel@tonic-gate static void
17027c478bd9Sstevel@tonic-gate etheraddr_match(enum direction which, char *hostname)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	uint_t addr;
17057c478bd9Sstevel@tonic-gate 	ushort_t *addrp;
17067c478bd9Sstevel@tonic-gate 	int to_offset, from_offset;
17077c478bd9Sstevel@tonic-gate 	struct ether_addr e, *ep = NULL;
17087c478bd9Sstevel@tonic-gate 	int m;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	/*
17117c478bd9Sstevel@tonic-gate 	 * First, check the interface type for whether src/dest address
17127c478bd9Sstevel@tonic-gate 	 * is determinable; if not, retreat early.
17137c478bd9Sstevel@tonic-gate 	 */
17147c478bd9Sstevel@tonic-gate 	switch (interface->mac_type) {
17157c478bd9Sstevel@tonic-gate 	case DL_ETHER:
17167c478bd9Sstevel@tonic-gate 		from_offset = ETHERADDRL;
17177c478bd9Sstevel@tonic-gate 		to_offset = 0;
17187c478bd9Sstevel@tonic-gate 		break;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	case DL_IB:
17217c478bd9Sstevel@tonic-gate 		/*
17227c478bd9Sstevel@tonic-gate 		 * If an ethernet address is attempted to be used
17237c478bd9Sstevel@tonic-gate 		 * on an IPoIB interface, flag error. Link address
17247c478bd9Sstevel@tonic-gate 		 * based filtering is unsupported on IPoIB, so there
17257c478bd9Sstevel@tonic-gate 		 * is no ipibaddr_match() or parsing support for IPoIB
17267c478bd9Sstevel@tonic-gate 		 * 20 byte link addresses.
17277c478bd9Sstevel@tonic-gate 		 */
17287c478bd9Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
17297c478bd9Sstevel@tonic-gate 		break;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	case DL_FDDI:
17327c478bd9Sstevel@tonic-gate 		from_offset = 7;
17337c478bd9Sstevel@tonic-gate 		to_offset = 1;
17347c478bd9Sstevel@tonic-gate 		break;
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	default:
17377c478bd9Sstevel@tonic-gate 		/*
17387c478bd9Sstevel@tonic-gate 		 * Where do we find "ether" address for FDDI & TR?
17397c478bd9Sstevel@tonic-gate 		 * XXX can improve?  ~sparker
17407c478bd9Sstevel@tonic-gate 		 */
17417c478bd9Sstevel@tonic-gate 		load_const(1);
17427c478bd9Sstevel@tonic-gate 		return;
17437c478bd9Sstevel@tonic-gate 	}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (isxdigit(*hostname))
17467c478bd9Sstevel@tonic-gate 		ep = ether_aton(hostname);
17477c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
17487c478bd9Sstevel@tonic-gate 		if (ether_hostton(hostname, &e))
17497c478bd9Sstevel@tonic-gate 			if (!arp_for_ether(hostname, &e))
17507c478bd9Sstevel@tonic-gate 				pr_err("cannot obtain ether addr for %s",
17517c478bd9Sstevel@tonic-gate 					hostname);
17527c478bd9Sstevel@tonic-gate 		ep = &e;
17537c478bd9Sstevel@tonic-gate 	}
17547c478bd9Sstevel@tonic-gate 	memcpy(&addr, (ushort_t *)ep, 4);
17557c478bd9Sstevel@tonic-gate 	addrp = (ushort_t *)ep + 2;
17567c478bd9Sstevel@tonic-gate 
1757*605445d5Sdg 	emitop(OP_OFFSET_ZERO);
17587c478bd9Sstevel@tonic-gate 	switch (which) {
17597c478bd9Sstevel@tonic-gate 	case TO:
17607c478bd9Sstevel@tonic-gate 		compare_value(to_offset, 4, ntohl(addr));
17617c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
17627c478bd9Sstevel@tonic-gate 		m = chain(0);
17637c478bd9Sstevel@tonic-gate 		compare_value(to_offset + 4, 2, ntohs(*addrp));
17647c478bd9Sstevel@tonic-gate 		resolve_chain(m);
17657c478bd9Sstevel@tonic-gate 		break;
17667c478bd9Sstevel@tonic-gate 	case FROM:
17677c478bd9Sstevel@tonic-gate 		compare_value(from_offset, 4, ntohl(addr));
17687c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
17697c478bd9Sstevel@tonic-gate 		m = chain(0);
17707c478bd9Sstevel@tonic-gate 		compare_value(from_offset + 4, 2, ntohs(*addrp));
17717c478bd9Sstevel@tonic-gate 		resolve_chain(m);
17727c478bd9Sstevel@tonic-gate 		break;
17737c478bd9Sstevel@tonic-gate 	case ANY:
17747c478bd9Sstevel@tonic-gate 		compare_value(to_offset, 4, ntohl(addr));
17757c478bd9Sstevel@tonic-gate 		compare_value(to_offset + 4, 2, ntohs(*addrp));
17767c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
17777c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
17787c478bd9Sstevel@tonic-gate 		m = chain(0);
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 		compare_value(from_offset, 4, ntohl(addr));
17817c478bd9Sstevel@tonic-gate 		compare_value(from_offset + 4, 2, ntohs(*addrp));
17827c478bd9Sstevel@tonic-gate 		emitop(OP_AND);
17837c478bd9Sstevel@tonic-gate 		resolve_chain(m);
17847c478bd9Sstevel@tonic-gate 		break;
17857c478bd9Sstevel@tonic-gate 	}
1786*605445d5Sdg 	emitop(OP_OFFSET_POP);
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate static void
17907c478bd9Sstevel@tonic-gate ethertype_match(int val)
17917c478bd9Sstevel@tonic-gate {
1792*605445d5Sdg 	int ether_offset = interface->network_type_offset;
17937c478bd9Sstevel@tonic-gate 
1794*605445d5Sdg 	/*
1795*605445d5Sdg 	 * If the user is interested in ethertype VLAN,
1796*605445d5Sdg 	 * then we need to set the offset to the beginning of the packet.
1797*605445d5Sdg 	 * But if the user is interested in another ethertype,
1798*605445d5Sdg 	 * such as IPv4, then we need to take into consideration
1799*605445d5Sdg 	 * the fact that the packet might be VLAN tagged.
1800*605445d5Sdg 	 */
1801*605445d5Sdg 	if (interface->mac_type == DL_ETHER ||
1802*605445d5Sdg 	    interface->mac_type == DL_CSMACD) {
1803*605445d5Sdg 		if (val != ETHERTYPE_VLAN) {
1804*605445d5Sdg 			/*
1805*605445d5Sdg 			 * OP_OFFSET_ETHERTYPE puts us at the ethertype
1806*605445d5Sdg 			 * field whether or not there is a VLAN tag,
1807*605445d5Sdg 			 * so ether_offset goes to zero if we get here.
1808*605445d5Sdg 			 */
1809*605445d5Sdg 			emitop(OP_OFFSET_ETHERTYPE);
1810*605445d5Sdg 			ether_offset = 0;
1811*605445d5Sdg 		} else {
1812*605445d5Sdg 			emitop(OP_OFFSET_ZERO);
1813*605445d5Sdg 		}
1814*605445d5Sdg 	}
1815*605445d5Sdg 	compare_value(ether_offset, 2, val);
1816*605445d5Sdg 	if (interface->mac_type == DL_ETHER ||
1817*605445d5Sdg 	    interface->mac_type == DL_CSMACD) {
1818*605445d5Sdg 		emitop(OP_OFFSET_POP);
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate }
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate /*
18237c478bd9Sstevel@tonic-gate  * Match a network address.  The host part
18247c478bd9Sstevel@tonic-gate  * is masked out.  The network address may
18257c478bd9Sstevel@tonic-gate  * be supplied either as a netname or in
18267c478bd9Sstevel@tonic-gate  * IP dotted format.  The mask to be used
18277c478bd9Sstevel@tonic-gate  * for the comparison is assumed from the
18287c478bd9Sstevel@tonic-gate  * address format (see comment below).
18297c478bd9Sstevel@tonic-gate  */
18307c478bd9Sstevel@tonic-gate static void
18317c478bd9Sstevel@tonic-gate netaddr_match(enum direction which, char *netname)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	uint_t addr;
18347c478bd9Sstevel@tonic-gate 	uint_t mask = 0xff000000;
18357c478bd9Sstevel@tonic-gate 	uint_t m;
18367c478bd9Sstevel@tonic-gate 	struct netent *np;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	if (isdigit(*netname)) {
18397c478bd9Sstevel@tonic-gate 		addr = inet_network(netname);
18407c478bd9Sstevel@tonic-gate 	} else {
18417c478bd9Sstevel@tonic-gate 		np = getnetbyname(netname);
18427c478bd9Sstevel@tonic-gate 		if (np == NULL)
18437c478bd9Sstevel@tonic-gate 			pr_err("net %s not known", netname);
18447c478bd9Sstevel@tonic-gate 		addr = np->n_net;
18457c478bd9Sstevel@tonic-gate 	}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	/*
18487c478bd9Sstevel@tonic-gate 	 * Left justify the address and figure
18497c478bd9Sstevel@tonic-gate 	 * out a mask based on the supplied address.
18507c478bd9Sstevel@tonic-gate 	 * Set the mask according to the number of zero
18517c478bd9Sstevel@tonic-gate 	 * low-order bytes.
18527c478bd9Sstevel@tonic-gate 	 * Note: this works only for whole octet masks.
18537c478bd9Sstevel@tonic-gate 	 */
18547c478bd9Sstevel@tonic-gate 	if (addr) {
18557c478bd9Sstevel@tonic-gate 		while ((addr & ~mask) != 0) {
18567c478bd9Sstevel@tonic-gate 			mask |= (mask >> 8);
18577c478bd9Sstevel@tonic-gate 		}
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_LINK);
18617c478bd9Sstevel@tonic-gate 	switch (which) {
18627c478bd9Sstevel@tonic-gate 	case TO:
18637c478bd9Sstevel@tonic-gate 		compare_value_mask(16, 4, addr, mask);
18647c478bd9Sstevel@tonic-gate 		break;
18657c478bd9Sstevel@tonic-gate 	case FROM:
18667c478bd9Sstevel@tonic-gate 		compare_value_mask(12, 4, addr, mask);
18677c478bd9Sstevel@tonic-gate 		break;
18687c478bd9Sstevel@tonic-gate 	case ANY:
18697c478bd9Sstevel@tonic-gate 		compare_value_mask(12, 4, addr, mask);
18707c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
18717c478bd9Sstevel@tonic-gate 		m = chain(0);
18727c478bd9Sstevel@tonic-gate 		compare_value_mask(16, 4, addr, mask);
18737c478bd9Sstevel@tonic-gate 		resolve_chain(m);
18747c478bd9Sstevel@tonic-gate 		break;
18757c478bd9Sstevel@tonic-gate 	}
18767c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
18777c478bd9Sstevel@tonic-gate }
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate /*
18807c478bd9Sstevel@tonic-gate  * Match either a UDP or TCP port number.
18817c478bd9Sstevel@tonic-gate  * The port number may be provided either as
18827c478bd9Sstevel@tonic-gate  * port name as listed in /etc/services ("nntp") or as
18837c478bd9Sstevel@tonic-gate  * the port number itself (2049).
18847c478bd9Sstevel@tonic-gate  */
18857c478bd9Sstevel@tonic-gate static void
18867c478bd9Sstevel@tonic-gate port_match(enum direction which, char *portname)
18877c478bd9Sstevel@tonic-gate {
18887c478bd9Sstevel@tonic-gate 	struct servent *sp;
18897c478bd9Sstevel@tonic-gate 	uint_t m, port;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	if (isdigit(*portname)) {
18927c478bd9Sstevel@tonic-gate 		port = atoi(portname);
18937c478bd9Sstevel@tonic-gate 	} else {
18947c478bd9Sstevel@tonic-gate 		sp = getservbyname(portname, NULL);
18957c478bd9Sstevel@tonic-gate 		if (sp == NULL)
18967c478bd9Sstevel@tonic-gate 			pr_err("invalid port number or name: %s",
18977c478bd9Sstevel@tonic-gate 				portname);
18987c478bd9Sstevel@tonic-gate 		port = ntohs(sp->s_port);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_IP);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	switch (which) {
19047c478bd9Sstevel@tonic-gate 	case TO:
19057c478bd9Sstevel@tonic-gate 		compare_value(2, 2, port);
19067c478bd9Sstevel@tonic-gate 		break;
19077c478bd9Sstevel@tonic-gate 	case FROM:
19087c478bd9Sstevel@tonic-gate 		compare_value(0, 2, port);
19097c478bd9Sstevel@tonic-gate 		break;
19107c478bd9Sstevel@tonic-gate 	case ANY:
19117c478bd9Sstevel@tonic-gate 		compare_value(2, 2, port);
19127c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
19137c478bd9Sstevel@tonic-gate 		m = chain(0);
19147c478bd9Sstevel@tonic-gate 		compare_value(0, 2, port);
19157c478bd9Sstevel@tonic-gate 		resolve_chain(m);
19167c478bd9Sstevel@tonic-gate 		break;
19177c478bd9Sstevel@tonic-gate 	}
19187c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate /*
19227c478bd9Sstevel@tonic-gate  * Generate code to match packets with a specific
19237c478bd9Sstevel@tonic-gate  * RPC program number.  If the progname is a name
19247c478bd9Sstevel@tonic-gate  * it is converted to a number via /etc/rpc.
19257c478bd9Sstevel@tonic-gate  * The program version and/or procedure may be provided
19267c478bd9Sstevel@tonic-gate  * as extra qualifiers.
19277c478bd9Sstevel@tonic-gate  */
19287c478bd9Sstevel@tonic-gate static void
19297c478bd9Sstevel@tonic-gate rpc_match_prog(enum direction which, char *progname, int vers, int proc)
19307c478bd9Sstevel@tonic-gate {
19317c478bd9Sstevel@tonic-gate 	struct rpcent *rpc;
19327c478bd9Sstevel@tonic-gate 	uint_t prog;
19337c478bd9Sstevel@tonic-gate 	uint_t m, n;
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	if (isdigit(*progname)) {
19367c478bd9Sstevel@tonic-gate 		prog = atoi(progname);
19377c478bd9Sstevel@tonic-gate 	} else {
19387c478bd9Sstevel@tonic-gate 		rpc = (struct rpcent *)getrpcbyname(progname);
19397c478bd9Sstevel@tonic-gate 		if (rpc == NULL)
19407c478bd9Sstevel@tonic-gate 			pr_err("invalid program name: %s", progname);
19417c478bd9Sstevel@tonic-gate 		prog = rpc->r_number;
19427c478bd9Sstevel@tonic-gate 	}
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_RPC);
19457c478bd9Sstevel@tonic-gate 	emitop(OP_BRFL);
19467c478bd9Sstevel@tonic-gate 	n = chain(0);
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 	compare_value(12, 4, prog);
19497c478bd9Sstevel@tonic-gate 	emitop(OP_BRFL);
19507c478bd9Sstevel@tonic-gate 	m = chain(0);
19517c478bd9Sstevel@tonic-gate 	if (vers >= 0) {
19527c478bd9Sstevel@tonic-gate 		compare_value(16, 4, vers);
19537c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
19547c478bd9Sstevel@tonic-gate 		m = chain(m);
19557c478bd9Sstevel@tonic-gate 	}
19567c478bd9Sstevel@tonic-gate 	if (proc >= 0) {
19577c478bd9Sstevel@tonic-gate 		compare_value(20, 4, proc);
19587c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
19597c478bd9Sstevel@tonic-gate 		m = chain(m);
19607c478bd9Sstevel@tonic-gate 	}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	switch (which) {
19637c478bd9Sstevel@tonic-gate 	case TO:
19647c478bd9Sstevel@tonic-gate 		compare_value(4, 4, CALL);
19657c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
19667c478bd9Sstevel@tonic-gate 		m = chain(m);
19677c478bd9Sstevel@tonic-gate 		break;
19687c478bd9Sstevel@tonic-gate 	case FROM:
19697c478bd9Sstevel@tonic-gate 		compare_value(4, 4, REPLY);
19707c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
19717c478bd9Sstevel@tonic-gate 		m = chain(m);
19727c478bd9Sstevel@tonic-gate 		break;
19737c478bd9Sstevel@tonic-gate 	}
19747c478bd9Sstevel@tonic-gate 	resolve_chain(m);
19757c478bd9Sstevel@tonic-gate 	resolve_chain(n);
19767c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate  * Generate code to parse a field specification
19817c478bd9Sstevel@tonic-gate  * and load the value of the field from the packet
19827c478bd9Sstevel@tonic-gate  * onto the operand stack.
19837c478bd9Sstevel@tonic-gate  * The field offset may be specified relative to the
19847c478bd9Sstevel@tonic-gate  * beginning of the ether header, IP header, UDP header,
19857c478bd9Sstevel@tonic-gate  * or TCP header.  An optional size specification may
19867c478bd9Sstevel@tonic-gate  * be provided following a colon.  If no size is given
19877c478bd9Sstevel@tonic-gate  * one byte is assumed e.g.
19887c478bd9Sstevel@tonic-gate  *
19897c478bd9Sstevel@tonic-gate  *	ether[0]	The first byte of the ether header
19907c478bd9Sstevel@tonic-gate  *	ip[2:2]		The second 16 bit field of the IP header
19917c478bd9Sstevel@tonic-gate  */
19927c478bd9Sstevel@tonic-gate static void
19937c478bd9Sstevel@tonic-gate load_field()
19947c478bd9Sstevel@tonic-gate {
19957c478bd9Sstevel@tonic-gate 	int size = 1;
19967c478bd9Sstevel@tonic-gate 	int s;
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	if (EQ("ether"))
20007c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_ZERO);
20017c478bd9Sstevel@tonic-gate 	else if (EQ("ip") || EQ("ip6") || EQ("pppoed") || EQ("pppoes"))
20027c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_LINK);
20037c478bd9Sstevel@tonic-gate 	else if (EQ("udp") || EQ("tcp") || EQ("icmp") || EQ("ip-in-ip") ||
20047c478bd9Sstevel@tonic-gate 	    EQ("ah") || EQ("esp"))
20057c478bd9Sstevel@tonic-gate 		emitop(OP_OFFSET_IP);
20067c478bd9Sstevel@tonic-gate 	else
20077c478bd9Sstevel@tonic-gate 		pr_err("invalid field type");
20087c478bd9Sstevel@tonic-gate 	next();
20097c478bd9Sstevel@tonic-gate 	s = opstack;
20107c478bd9Sstevel@tonic-gate 	expression();
20117c478bd9Sstevel@tonic-gate 	if (opstack != s + 1)
20127c478bd9Sstevel@tonic-gate 		pr_err("invalid field offset");
20137c478bd9Sstevel@tonic-gate 	opstack--;
20147c478bd9Sstevel@tonic-gate 	if (*token == ':') {
20157c478bd9Sstevel@tonic-gate 		next();
20167c478bd9Sstevel@tonic-gate 		if (tokentype != NUMBER)
20177c478bd9Sstevel@tonic-gate 			pr_err("field size expected");
20187c478bd9Sstevel@tonic-gate 		size = tokenval;
20197c478bd9Sstevel@tonic-gate 		if (size != 1 && size != 2 && size != 4)
20207c478bd9Sstevel@tonic-gate 			pr_err("field size invalid");
20217c478bd9Sstevel@tonic-gate 		next();
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 	if (*token != ']')
20247c478bd9Sstevel@tonic-gate 		pr_err("right bracket expected");
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	load_value(-1, size);
20277c478bd9Sstevel@tonic-gate 	emitop(OP_OFFSET_POP);
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate /*
20317c478bd9Sstevel@tonic-gate  * Check that the operand stack
20327c478bd9Sstevel@tonic-gate  * contains n arguments
20337c478bd9Sstevel@tonic-gate  */
20347c478bd9Sstevel@tonic-gate static void
20357c478bd9Sstevel@tonic-gate checkstack(int numargs)
20367c478bd9Sstevel@tonic-gate {
20377c478bd9Sstevel@tonic-gate 	if (opstack != numargs)
20387c478bd9Sstevel@tonic-gate 		pr_err("invalid expression at \"%s\".", token);
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate static void
20427c478bd9Sstevel@tonic-gate primary()
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate 	int m, s;
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	for (;;) {
20477c478bd9Sstevel@tonic-gate 		if (tokentype == FIELD) {
20487c478bd9Sstevel@tonic-gate 			load_field();
20497c478bd9Sstevel@tonic-gate 			opstack++;
20507c478bd9Sstevel@tonic-gate 			next();
20517c478bd9Sstevel@tonic-gate 			break;
20527c478bd9Sstevel@tonic-gate 		}
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 		if (comparison(token)) {
20557c478bd9Sstevel@tonic-gate 			opstack++;
20567c478bd9Sstevel@tonic-gate 			next();
20577c478bd9Sstevel@tonic-gate 			break;
20587c478bd9Sstevel@tonic-gate 		}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 		if (EQ("not") || EQ("!")) {
20617c478bd9Sstevel@tonic-gate 			next();
20627c478bd9Sstevel@tonic-gate 			s = opstack;
20637c478bd9Sstevel@tonic-gate 			primary();
20647c478bd9Sstevel@tonic-gate 			checkstack(s + 1);
20657c478bd9Sstevel@tonic-gate 			emitop(OP_NOT);
20667c478bd9Sstevel@tonic-gate 			break;
20677c478bd9Sstevel@tonic-gate 		}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 		if (EQ("(")) {
20707c478bd9Sstevel@tonic-gate 			next();
20717c478bd9Sstevel@tonic-gate 			s = opstack;
20727c478bd9Sstevel@tonic-gate 			expression();
20737c478bd9Sstevel@tonic-gate 			checkstack(s + 1);
20747c478bd9Sstevel@tonic-gate 			if (!EQ(")"))
20757c478bd9Sstevel@tonic-gate 				pr_err("right paren expected");
20767c478bd9Sstevel@tonic-gate 			next();
20777c478bd9Sstevel@tonic-gate 		}
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 		if (EQ("to") || EQ("dst")) {
20807c478bd9Sstevel@tonic-gate 			dir = TO;
20817c478bd9Sstevel@tonic-gate 			next();
20827c478bd9Sstevel@tonic-gate 			continue;
20837c478bd9Sstevel@tonic-gate 		}
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 		if (EQ("from") || EQ("src")) {
20867c478bd9Sstevel@tonic-gate 			dir = FROM;
20877c478bd9Sstevel@tonic-gate 			next();
20887c478bd9Sstevel@tonic-gate 			continue;
20897c478bd9Sstevel@tonic-gate 		}
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 		if (EQ("ether")) {
20927c478bd9Sstevel@tonic-gate 			eaddr = 1;
20937c478bd9Sstevel@tonic-gate 			next();
20947c478bd9Sstevel@tonic-gate 			continue;
20957c478bd9Sstevel@tonic-gate 		}
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 		if (EQ("proto")) { /* ignore */
20987c478bd9Sstevel@tonic-gate 			next();
20997c478bd9Sstevel@tonic-gate 			continue;
21007c478bd9Sstevel@tonic-gate 		}
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 		if (EQ("broadcast")) {
21037c478bd9Sstevel@tonic-gate 			/*
21047c478bd9Sstevel@tonic-gate 			 * Be tricky: FDDI ether dst address begins at
21057c478bd9Sstevel@tonic-gate 			 * byte one.  Since the address is really six
21067c478bd9Sstevel@tonic-gate 			 * bytes long, this works for FDDI & ethernet.
21077c478bd9Sstevel@tonic-gate 			 * XXX - Token ring?
21087c478bd9Sstevel@tonic-gate 			 */
2109*605445d5Sdg 			emitop(OP_OFFSET_ZERO);
21107c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_IB)
21117c478bd9Sstevel@tonic-gate 				pr_err("filter option unsupported on media");
21127c478bd9Sstevel@tonic-gate 			compare_value(1, 4, 0xffffffff);
2113*605445d5Sdg 			emitop(OP_OFFSET_POP);
21147c478bd9Sstevel@tonic-gate 			opstack++;
21157c478bd9Sstevel@tonic-gate 			next();
21167c478bd9Sstevel@tonic-gate 			break;
21177c478bd9Sstevel@tonic-gate 		}
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 		if (EQ("multicast")) {
21207c478bd9Sstevel@tonic-gate 			/* XXX Token ring? */
2121*605445d5Sdg 			emitop(OP_OFFSET_ZERO);
21227c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_FDDI) {
21237c478bd9Sstevel@tonic-gate 				compare_value_mask(1, 1, 0x01, 0x01);
21247c478bd9Sstevel@tonic-gate 			} else if (interface->mac_type == DL_IB) {
21257c478bd9Sstevel@tonic-gate 				pr_err("filter option unsupported on media");
21267c478bd9Sstevel@tonic-gate 			} else {
21277c478bd9Sstevel@tonic-gate 				compare_value_mask(0, 1, 0x01, 0x01);
21287c478bd9Sstevel@tonic-gate 			}
2129*605445d5Sdg 			emitop(OP_OFFSET_POP);
21307c478bd9Sstevel@tonic-gate 			opstack++;
21317c478bd9Sstevel@tonic-gate 			next();
21327c478bd9Sstevel@tonic-gate 			break;
21337c478bd9Sstevel@tonic-gate 		}
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 		if (EQ("decnet")) {
21367c478bd9Sstevel@tonic-gate 			/* XXX Token ring? */
21377c478bd9Sstevel@tonic-gate 			if (interface->mac_type == DL_FDDI) {
21387c478bd9Sstevel@tonic-gate 				load_value(19, 2);	/* ether type */
21397c478bd9Sstevel@tonic-gate 				load_const(0x6000);
21407c478bd9Sstevel@tonic-gate 				emitop(OP_GE);
21417c478bd9Sstevel@tonic-gate 				emitop(OP_BRFL);
21427c478bd9Sstevel@tonic-gate 				m = chain(0);
21437c478bd9Sstevel@tonic-gate 				load_value(19, 2);	/* ether type */
21447c478bd9Sstevel@tonic-gate 				load_const(0x6009);
21457c478bd9Sstevel@tonic-gate 				emitop(OP_LE);
21467c478bd9Sstevel@tonic-gate 				resolve_chain(m);
21477c478bd9Sstevel@tonic-gate 			} else {
2148*605445d5Sdg 				emitop(OP_OFFSET_ETHERTYPE);
2149*605445d5Sdg 				load_value(0, 2);	/* ether type */
21507c478bd9Sstevel@tonic-gate 				load_const(0x6000);
21517c478bd9Sstevel@tonic-gate 				emitop(OP_GE);
21527c478bd9Sstevel@tonic-gate 				emitop(OP_BRFL);
21537c478bd9Sstevel@tonic-gate 				m = chain(0);
2154*605445d5Sdg 				load_value(0, 2);	/* ether type */
21557c478bd9Sstevel@tonic-gate 				load_const(0x6009);
21567c478bd9Sstevel@tonic-gate 				emitop(OP_LE);
21577c478bd9Sstevel@tonic-gate 				resolve_chain(m);
2158*605445d5Sdg 				emitop(OP_OFFSET_POP);
21597c478bd9Sstevel@tonic-gate 			}
21607c478bd9Sstevel@tonic-gate 			opstack++;
21617c478bd9Sstevel@tonic-gate 			next();
21627c478bd9Sstevel@tonic-gate 			break;
21637c478bd9Sstevel@tonic-gate 		}
21647c478bd9Sstevel@tonic-gate 
2165*605445d5Sdg 		if (EQ("vlan-id")) {
2166*605445d5Sdg 			next();
2167*605445d5Sdg 			if (tokentype != NUMBER)
2168*605445d5Sdg 				pr_err("vlan id expected");
2169*605445d5Sdg 			emitop(OP_OFFSET_ZERO);
2170*605445d5Sdg 			ethertype_match(ETHERTYPE_VLAN);
2171*605445d5Sdg 			emitop(OP_BRFL);
2172*605445d5Sdg 			m = chain(0);
2173*605445d5Sdg 			compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
2174*605445d5Sdg 			    VLAN_ID_MASK);
2175*605445d5Sdg 			resolve_chain(m);
2176*605445d5Sdg 			emitop(OP_OFFSET_POP);
2177*605445d5Sdg 			opstack++;
2178*605445d5Sdg 			next();
2179*605445d5Sdg 			break;
2180*605445d5Sdg 		}
2181*605445d5Sdg 
21827c478bd9Sstevel@tonic-gate 		if (EQ("apple")) {
21837c478bd9Sstevel@tonic-gate 			/*
21847c478bd9Sstevel@tonic-gate 			 * Appletalk also appears in 802.2
21857c478bd9Sstevel@tonic-gate 			 * packets, so check for the ethertypes
21867c478bd9Sstevel@tonic-gate 			 * at offset 12 and 20 in the MAC header.
21877c478bd9Sstevel@tonic-gate 			 */
21887c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_AT);
21897c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
21907c478bd9Sstevel@tonic-gate 			m = chain(0);
21917c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_AARP);
21927c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
21937c478bd9Sstevel@tonic-gate 			m = chain(m);
21947c478bd9Sstevel@tonic-gate 			compare_value(20, 2, ETHERTYPE_AT); /* 802.2 */
21957c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
21967c478bd9Sstevel@tonic-gate 			m = chain(m);
21977c478bd9Sstevel@tonic-gate 			compare_value(20, 2, ETHERTYPE_AARP); /* 802.2 */
21987c478bd9Sstevel@tonic-gate 			resolve_chain(m);
21997c478bd9Sstevel@tonic-gate 			opstack++;
22007c478bd9Sstevel@tonic-gate 			next();
22017c478bd9Sstevel@tonic-gate 			break;
22027c478bd9Sstevel@tonic-gate 		}
22037c478bd9Sstevel@tonic-gate 
2204*605445d5Sdg 		if (EQ("vlan")) {
2205*605445d5Sdg 			ethertype_match(ETHERTYPE_VLAN);
2206*605445d5Sdg 			compare_value_mask(VLAN_ID_OFFSET, 2, 0, VLAN_ID_MASK);
2207*605445d5Sdg 			emitop(OP_NOT);
2208*605445d5Sdg 			emitop(OP_AND);
2209*605445d5Sdg 			opstack++;
2210*605445d5Sdg 			next();
2211*605445d5Sdg 			break;
2212*605445d5Sdg 		}
2213*605445d5Sdg 
22147c478bd9Sstevel@tonic-gate 		if (EQ("bootp") || EQ("dhcp")) {
22157c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_LINK);
22167c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_CONST);
22177c478bd9Sstevel@tonic-gate 			emitval(9);
22187c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_OCTET);
22197c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_CONST);
22207c478bd9Sstevel@tonic-gate 			emitval(IPPROTO_UDP);
22217c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_IP);
22227c478bd9Sstevel@tonic-gate 			compare_value(0, 4,
22237c478bd9Sstevel@tonic-gate 			    (IPPORT_BOOTPS << 16 | IPPORT_BOOTPC));
22247c478bd9Sstevel@tonic-gate 			emitop(OP_BRTR);
22257c478bd9Sstevel@tonic-gate 			m = chain(0);
22267c478bd9Sstevel@tonic-gate 			compare_value(0, 4,
22277c478bd9Sstevel@tonic-gate 			    (IPPORT_BOOTPC << 16 | IPPORT_BOOTPS));
22287c478bd9Sstevel@tonic-gate 			resolve_chain(m);
2229*605445d5Sdg 			emitop(OP_OFFSET_POP);
2230*605445d5Sdg 			emitop(OP_OFFSET_POP);
22317c478bd9Sstevel@tonic-gate 			opstack++;
22327c478bd9Sstevel@tonic-gate 			dir = ANY;
22337c478bd9Sstevel@tonic-gate 			next();
22347c478bd9Sstevel@tonic-gate 			break;
22357c478bd9Sstevel@tonic-gate 		}
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 		if (EQ("ethertype")) {
22387c478bd9Sstevel@tonic-gate 			next();
22397c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
22407c478bd9Sstevel@tonic-gate 				pr_err("ether type expected");
22417c478bd9Sstevel@tonic-gate 			ethertype_match(tokenval);
22427c478bd9Sstevel@tonic-gate 			opstack++;
22437c478bd9Sstevel@tonic-gate 			next();
22447c478bd9Sstevel@tonic-gate 			break;
22457c478bd9Sstevel@tonic-gate 		}
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate 		if (EQ("pppoe")) {
22487c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_PPPOED);
22497c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_PPPOES);
22507c478bd9Sstevel@tonic-gate 			emitop(OP_OR);
22517c478bd9Sstevel@tonic-gate 			opstack++;
22527c478bd9Sstevel@tonic-gate 			next();
22537c478bd9Sstevel@tonic-gate 			break;
22547c478bd9Sstevel@tonic-gate 		}
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 		if (EQ("inet")) {
22577c478bd9Sstevel@tonic-gate 			next();
22587c478bd9Sstevel@tonic-gate 			if (EQ("host"))
22597c478bd9Sstevel@tonic-gate 				next();
22607c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP)
22617c478bd9Sstevel@tonic-gate 				pr_err("host/IPv4 addr expected after inet");
22627c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV4_ONLY);
22637c478bd9Sstevel@tonic-gate 			opstack++;
22647c478bd9Sstevel@tonic-gate 			next();
22657c478bd9Sstevel@tonic-gate 			break;
22667c478bd9Sstevel@tonic-gate 		}
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 		if (EQ("inet6")) {
22697c478bd9Sstevel@tonic-gate 			next();
22707c478bd9Sstevel@tonic-gate 			if (EQ("host"))
22717c478bd9Sstevel@tonic-gate 				next();
22727c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
22737c478bd9Sstevel@tonic-gate 				pr_err("host/IPv6 addr expected after inet6");
22747c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV6_ONLY);
22757c478bd9Sstevel@tonic-gate 			opstack++;
22767c478bd9Sstevel@tonic-gate 			next();
22777c478bd9Sstevel@tonic-gate 			break;
22787c478bd9Sstevel@tonic-gate 		}
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 		if (EQ("length")) {
22817c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
22827c478bd9Sstevel@tonic-gate 			opstack++;
22837c478bd9Sstevel@tonic-gate 			next();
22847c478bd9Sstevel@tonic-gate 			break;
22857c478bd9Sstevel@tonic-gate 		}
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 		if (EQ("less")) {
22887c478bd9Sstevel@tonic-gate 			next();
22897c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
22907c478bd9Sstevel@tonic-gate 				pr_err("packet length expected");
22917c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
22927c478bd9Sstevel@tonic-gate 			load_const(tokenval);
22937c478bd9Sstevel@tonic-gate 			emitop(OP_LT);
22947c478bd9Sstevel@tonic-gate 			opstack++;
22957c478bd9Sstevel@tonic-gate 			next();
22967c478bd9Sstevel@tonic-gate 			break;
22977c478bd9Sstevel@tonic-gate 		}
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 		if (EQ("greater")) {
23007c478bd9Sstevel@tonic-gate 			next();
23017c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
23027c478bd9Sstevel@tonic-gate 				pr_err("packet length expected");
23037c478bd9Sstevel@tonic-gate 			emitop(OP_LOAD_LENGTH);
23047c478bd9Sstevel@tonic-gate 			load_const(tokenval);
23057c478bd9Sstevel@tonic-gate 			emitop(OP_GT);
23067c478bd9Sstevel@tonic-gate 			opstack++;
23077c478bd9Sstevel@tonic-gate 			next();
23087c478bd9Sstevel@tonic-gate 			break;
23097c478bd9Sstevel@tonic-gate 		}
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 		if (EQ("nofrag")) {
23127c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_LINK);
23137c478bd9Sstevel@tonic-gate 			compare_value_mask(6, 2, 0, 0x1fff);
23147c478bd9Sstevel@tonic-gate 			emitop(OP_OFFSET_POP);
23157c478bd9Sstevel@tonic-gate 			emitop(OP_BRFL);
23167c478bd9Sstevel@tonic-gate 			m = chain(0);
23177c478bd9Sstevel@tonic-gate 			ethertype_match(ETHERTYPE_IP);
23187c478bd9Sstevel@tonic-gate 			resolve_chain(m);
23197c478bd9Sstevel@tonic-gate 			opstack++;
23207c478bd9Sstevel@tonic-gate 			next();
23217c478bd9Sstevel@tonic-gate 			break;
23227c478bd9Sstevel@tonic-gate 		}
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
23257c478bd9Sstevel@tonic-gate 			if (EQ("dstnet"))
23267c478bd9Sstevel@tonic-gate 				dir = TO;
23277c478bd9Sstevel@tonic-gate 			else if (EQ("srcnet"))
23287c478bd9Sstevel@tonic-gate 				dir = FROM;
23297c478bd9Sstevel@tonic-gate 			next();
23307c478bd9Sstevel@tonic-gate 			netaddr_match(dir, token);
23317c478bd9Sstevel@tonic-gate 			dir = ANY;
23327c478bd9Sstevel@tonic-gate 			opstack++;
23337c478bd9Sstevel@tonic-gate 			next();
23347c478bd9Sstevel@tonic-gate 			break;
23357c478bd9Sstevel@tonic-gate 		}
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 		if (EQ("port") || EQ("srcport") || EQ("dstport")) {
23387c478bd9Sstevel@tonic-gate 			if (EQ("dstport"))
23397c478bd9Sstevel@tonic-gate 				dir = TO;
23407c478bd9Sstevel@tonic-gate 			else if (EQ("srcport"))
23417c478bd9Sstevel@tonic-gate 				dir = FROM;
23427c478bd9Sstevel@tonic-gate 			next();
23437c478bd9Sstevel@tonic-gate 			port_match(dir, token);
23447c478bd9Sstevel@tonic-gate 			dir = ANY;
23457c478bd9Sstevel@tonic-gate 			opstack++;
23467c478bd9Sstevel@tonic-gate 			next();
23477c478bd9Sstevel@tonic-gate 			break;
23487c478bd9Sstevel@tonic-gate 		}
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 		if (EQ("rpc")) {
23517c478bd9Sstevel@tonic-gate 			uint_t vers, proc;
23527c478bd9Sstevel@tonic-gate 			char savetoken[32];
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 			vers = proc = -1;
23557c478bd9Sstevel@tonic-gate 			next();
23567c478bd9Sstevel@tonic-gate 			(void) strlcpy(savetoken, token, sizeof (savetoken));
23577c478bd9Sstevel@tonic-gate 			next();
23587c478bd9Sstevel@tonic-gate 			if (*token == ',') {
23597c478bd9Sstevel@tonic-gate 				next();
23607c478bd9Sstevel@tonic-gate 				if (tokentype != NUMBER)
23617c478bd9Sstevel@tonic-gate 					pr_err("version number expected");
23627c478bd9Sstevel@tonic-gate 				vers = tokenval;
23637c478bd9Sstevel@tonic-gate 				next();
23647c478bd9Sstevel@tonic-gate 			}
23657c478bd9Sstevel@tonic-gate 			if (*token == ',') {
23667c478bd9Sstevel@tonic-gate 				next();
23677c478bd9Sstevel@tonic-gate 				if (tokentype != NUMBER)
23687c478bd9Sstevel@tonic-gate 					pr_err("proc number expected");
23697c478bd9Sstevel@tonic-gate 				proc = tokenval;
23707c478bd9Sstevel@tonic-gate 				next();
23717c478bd9Sstevel@tonic-gate 			}
23727c478bd9Sstevel@tonic-gate 			rpc_match_prog(dir, savetoken, vers, proc);
23737c478bd9Sstevel@tonic-gate 			dir = ANY;
23747c478bd9Sstevel@tonic-gate 			opstack++;
23757c478bd9Sstevel@tonic-gate 			break;
23767c478bd9Sstevel@tonic-gate 		}
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 		if (EQ("slp")) {
23797c478bd9Sstevel@tonic-gate 		    /* filter out TCP handshakes */
23807c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_LINK);
23817c478bd9Sstevel@tonic-gate 		    compare_value(9, 1, IPPROTO_TCP);
23827c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_CONST);
23837c478bd9Sstevel@tonic-gate 		    emitval(52);
23847c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_CONST);
23857c478bd9Sstevel@tonic-gate 		    emitval(2);
23867c478bd9Sstevel@tonic-gate 		    emitop(OP_LOAD_SHORT);
23877c478bd9Sstevel@tonic-gate 		    emitop(OP_GE);
23887c478bd9Sstevel@tonic-gate 		    emitop(OP_AND);	/* proto == TCP && len < 52 */
23897c478bd9Sstevel@tonic-gate 		    emitop(OP_NOT);
23907c478bd9Sstevel@tonic-gate 		    emitop(OP_BRFL);	/* pkt too short to be a SLP call */
23917c478bd9Sstevel@tonic-gate 		    m = chain(0);
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_POP);
23947c478bd9Sstevel@tonic-gate 		    emitop(OP_OFFSET_SLP);
23957c478bd9Sstevel@tonic-gate 		    resolve_chain(m);
23967c478bd9Sstevel@tonic-gate 		    opstack++;
23977c478bd9Sstevel@tonic-gate 		    next();
23987c478bd9Sstevel@tonic-gate 		    break;
23997c478bd9Sstevel@tonic-gate 		}
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 		if (EQ("ldap")) {
24027c478bd9Sstevel@tonic-gate 			dir = ANY;
24037c478bd9Sstevel@tonic-gate 			port_match(dir, "ldap");
24047c478bd9Sstevel@tonic-gate 			opstack++;
24057c478bd9Sstevel@tonic-gate 			next();
24067c478bd9Sstevel@tonic-gate 			break;
24077c478bd9Sstevel@tonic-gate 		}
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 		if (EQ("and") || EQ("or")) {
24107c478bd9Sstevel@tonic-gate 			break;
24117c478bd9Sstevel@tonic-gate 		}
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 		if (EQ("gateway")) {
24147c478bd9Sstevel@tonic-gate 			next();
24157c478bd9Sstevel@tonic-gate 			if (eaddr || tokentype != ALPHA)
24167c478bd9Sstevel@tonic-gate 				pr_err("hostname required: %s", token);
24177c478bd9Sstevel@tonic-gate 			etheraddr_match(dir, token);
24187c478bd9Sstevel@tonic-gate 			dir = ANY;
24197c478bd9Sstevel@tonic-gate 			emitop(OP_BRFL);
24207c478bd9Sstevel@tonic-gate 			m = chain(0);
24217c478bd9Sstevel@tonic-gate 			ipaddr_match(dir, token, IPV4_AND_IPV6);
24227c478bd9Sstevel@tonic-gate 			emitop(OP_NOT);
24237c478bd9Sstevel@tonic-gate 			resolve_chain(m);
24247c478bd9Sstevel@tonic-gate 			opstack++;
24257c478bd9Sstevel@tonic-gate 			next();
24267c478bd9Sstevel@tonic-gate 		}
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 		if (EQ("host") || EQ("between") ||
24297c478bd9Sstevel@tonic-gate 		    tokentype == ALPHA ||	/* assume its a hostname */
24307c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP ||
24317c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP6 ||
24327c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_AT ||
24337c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_ETHER) {
24347c478bd9Sstevel@tonic-gate 			if (EQ("host") || EQ("between"))
24357c478bd9Sstevel@tonic-gate 				next();
24367c478bd9Sstevel@tonic-gate 			if (eaddr || tokentype == ADDR_ETHER) {
24377c478bd9Sstevel@tonic-gate 				etheraddr_match(dir, token);
24387c478bd9Sstevel@tonic-gate 			} else if (tokentype == ALPHA) {
24397c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV4_AND_IPV6);
24407c478bd9Sstevel@tonic-gate 			} else if (tokentype == ADDR_AT) {
24417c478bd9Sstevel@tonic-gate 				ataddr_match(dir, token);
24427c478bd9Sstevel@tonic-gate 			} else if (tokentype == ADDR_IP) {
24437c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV4_ONLY);
24447c478bd9Sstevel@tonic-gate 			} else {
24457c478bd9Sstevel@tonic-gate 				ipaddr_match(dir, token, IPV6_ONLY);
24467c478bd9Sstevel@tonic-gate 			}
24477c478bd9Sstevel@tonic-gate 			dir = ANY;
24487c478bd9Sstevel@tonic-gate 			eaddr = 0;
24497c478bd9Sstevel@tonic-gate 			opstack++;
24507c478bd9Sstevel@tonic-gate 			next();
24517c478bd9Sstevel@tonic-gate 			break;
24527c478bd9Sstevel@tonic-gate 		}
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 		if (tokentype == NUMBER) {
24557c478bd9Sstevel@tonic-gate 			load_const(tokenval);
24567c478bd9Sstevel@tonic-gate 			opstack++;
24577c478bd9Sstevel@tonic-gate 			next();
24587c478bd9Sstevel@tonic-gate 			break;
24597c478bd9Sstevel@tonic-gate 		}
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 		break;	/* unknown token */
24627c478bd9Sstevel@tonic-gate 	}
24637c478bd9Sstevel@tonic-gate }
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate struct optable {
24667c478bd9Sstevel@tonic-gate 	char *op_tok;
24677c478bd9Sstevel@tonic-gate 	enum optype op_type;
24687c478bd9Sstevel@tonic-gate };
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate static struct optable
24717c478bd9Sstevel@tonic-gate mulops[] = {
24727c478bd9Sstevel@tonic-gate 	"*",	OP_MUL,
24737c478bd9Sstevel@tonic-gate 	"/",	OP_DIV,
24747c478bd9Sstevel@tonic-gate 	"%",	OP_REM,
24757c478bd9Sstevel@tonic-gate 	"&",	OP_AND,
24767c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
24777c478bd9Sstevel@tonic-gate };
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate static struct optable
24807c478bd9Sstevel@tonic-gate addops[] = {
24817c478bd9Sstevel@tonic-gate 	"+",	OP_ADD,
24827c478bd9Sstevel@tonic-gate 	"-",	OP_SUB,
24837c478bd9Sstevel@tonic-gate 	"|",	OP_OR,
24847c478bd9Sstevel@tonic-gate 	"^",	OP_XOR,
24857c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
24867c478bd9Sstevel@tonic-gate };
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate static struct optable
24897c478bd9Sstevel@tonic-gate compareops[] = {
24907c478bd9Sstevel@tonic-gate 	"==",	OP_EQ,
24917c478bd9Sstevel@tonic-gate 	"=",	OP_EQ,
24927c478bd9Sstevel@tonic-gate 	"!=",	OP_NE,
24937c478bd9Sstevel@tonic-gate 	">",	OP_GT,
24947c478bd9Sstevel@tonic-gate 	">=",	OP_GE,
24957c478bd9Sstevel@tonic-gate 	"<",	OP_LT,
24967c478bd9Sstevel@tonic-gate 	"<=",	OP_LE,
24977c478bd9Sstevel@tonic-gate 	"",	OP_STOP,
24987c478bd9Sstevel@tonic-gate };
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate /*
25017c478bd9Sstevel@tonic-gate  * Using the table, find the operator
25027c478bd9Sstevel@tonic-gate  * that corresponds to the token.
25037c478bd9Sstevel@tonic-gate  * Return 0 if not found.
25047c478bd9Sstevel@tonic-gate  */
25057c478bd9Sstevel@tonic-gate static int
25067c478bd9Sstevel@tonic-gate find_op(char *tok, struct optable *table)
25077c478bd9Sstevel@tonic-gate {
25087c478bd9Sstevel@tonic-gate 	struct optable *op;
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	for (op = table; *op->op_tok; op++) {
25117c478bd9Sstevel@tonic-gate 		if (strcmp(tok, op->op_tok) == 0)
25127c478bd9Sstevel@tonic-gate 			return (op->op_type);
25137c478bd9Sstevel@tonic-gate 	}
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate 	return (0);
25167c478bd9Sstevel@tonic-gate }
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate static void
25197c478bd9Sstevel@tonic-gate expr_mul()
25207c478bd9Sstevel@tonic-gate {
25217c478bd9Sstevel@tonic-gate 	int op;
25227c478bd9Sstevel@tonic-gate 	int s = opstack;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	primary();
25257c478bd9Sstevel@tonic-gate 	while (op = find_op(token, mulops)) {
25267c478bd9Sstevel@tonic-gate 		next();
25277c478bd9Sstevel@tonic-gate 		primary();
25287c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
25297c478bd9Sstevel@tonic-gate 		emitop(op);
25307c478bd9Sstevel@tonic-gate 		opstack--;
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate }
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate static void
25357c478bd9Sstevel@tonic-gate expr_add()
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate 	int op, s = opstack;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	expr_mul();
25407c478bd9Sstevel@tonic-gate 	while (op = find_op(token, addops)) {
25417c478bd9Sstevel@tonic-gate 		next();
25427c478bd9Sstevel@tonic-gate 		expr_mul();
25437c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
25447c478bd9Sstevel@tonic-gate 		emitop(op);
25457c478bd9Sstevel@tonic-gate 		opstack--;
25467c478bd9Sstevel@tonic-gate 	}
25477c478bd9Sstevel@tonic-gate }
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate static void
25507c478bd9Sstevel@tonic-gate expr_compare()
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate 	int op, s = opstack;
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	expr_add();
25557c478bd9Sstevel@tonic-gate 	while (op = find_op(token, compareops)) {
25567c478bd9Sstevel@tonic-gate 		next();
25577c478bd9Sstevel@tonic-gate 		expr_add();
25587c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
25597c478bd9Sstevel@tonic-gate 		emitop(op);
25607c478bd9Sstevel@tonic-gate 		opstack--;
25617c478bd9Sstevel@tonic-gate 	}
25627c478bd9Sstevel@tonic-gate }
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate /*
25657c478bd9Sstevel@tonic-gate  * Alternation ("and") is difficult because
25667c478bd9Sstevel@tonic-gate  * an implied "and" is acknowledge between
25677c478bd9Sstevel@tonic-gate  * two adjacent primaries.  Just keep calling
25687c478bd9Sstevel@tonic-gate  * the lower-level expression routine until
25697c478bd9Sstevel@tonic-gate  * no value is added to the opstack.
25707c478bd9Sstevel@tonic-gate  */
25717c478bd9Sstevel@tonic-gate static void
25727c478bd9Sstevel@tonic-gate alternation()
25737c478bd9Sstevel@tonic-gate {
25747c478bd9Sstevel@tonic-gate 	int m = 0;
25757c478bd9Sstevel@tonic-gate 	int s = opstack;
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	expr_compare();
25787c478bd9Sstevel@tonic-gate 	checkstack(s + 1);
25797c478bd9Sstevel@tonic-gate 	for (;;) {
25807c478bd9Sstevel@tonic-gate 		if (EQ("and"))
25817c478bd9Sstevel@tonic-gate 			next();
25827c478bd9Sstevel@tonic-gate 		emitop(OP_BRFL);
25837c478bd9Sstevel@tonic-gate 		m = chain(m);
25847c478bd9Sstevel@tonic-gate 		expr_compare();
25857c478bd9Sstevel@tonic-gate 		if (opstack != s + 2)
25867c478bd9Sstevel@tonic-gate 			break;
25877c478bd9Sstevel@tonic-gate 		opstack--;
25887c478bd9Sstevel@tonic-gate 	}
25897c478bd9Sstevel@tonic-gate 	unemit(2);
25907c478bd9Sstevel@tonic-gate 	resolve_chain(m);
25917c478bd9Sstevel@tonic-gate }
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate static void
25947c478bd9Sstevel@tonic-gate expression()
25957c478bd9Sstevel@tonic-gate {
25967c478bd9Sstevel@tonic-gate 	int m = 0;
25977c478bd9Sstevel@tonic-gate 	int s = opstack;
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate 	alternation();
26007c478bd9Sstevel@tonic-gate 	while (EQ("or") || EQ(",")) {
26017c478bd9Sstevel@tonic-gate 		emitop(OP_BRTR);
26027c478bd9Sstevel@tonic-gate 		m = chain(m);
26037c478bd9Sstevel@tonic-gate 		next();
26047c478bd9Sstevel@tonic-gate 		alternation();
26057c478bd9Sstevel@tonic-gate 		checkstack(s + 2);
26067c478bd9Sstevel@tonic-gate 		opstack--;
26077c478bd9Sstevel@tonic-gate 	}
26087c478bd9Sstevel@tonic-gate 	resolve_chain(m);
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate /*
26127c478bd9Sstevel@tonic-gate  * Take n args from the argv list
26137c478bd9Sstevel@tonic-gate  * and concatenate them into a single string.
26147c478bd9Sstevel@tonic-gate  */
26157c478bd9Sstevel@tonic-gate char *
26167c478bd9Sstevel@tonic-gate concat_args(char **argv, int argc)
26177c478bd9Sstevel@tonic-gate {
26187c478bd9Sstevel@tonic-gate 	int i, len;
26197c478bd9Sstevel@tonic-gate 	char *str, *p;
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	/* First add the lengths of all the strings */
26227c478bd9Sstevel@tonic-gate 	len = 0;
26237c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++)
26247c478bd9Sstevel@tonic-gate 		len += strlen(argv[i]) + 1;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	/* allocate the big string */
26277c478bd9Sstevel@tonic-gate 	str = (char *)malloc(len);
26287c478bd9Sstevel@tonic-gate 	if (str == NULL)
26297c478bd9Sstevel@tonic-gate 		pr_err("no mem");
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate 	p = str;
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	/*
26347c478bd9Sstevel@tonic-gate 	 * Concat the strings into the big
26357c478bd9Sstevel@tonic-gate 	 * string using a space as separator
26367c478bd9Sstevel@tonic-gate 	 */
26377c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
26387c478bd9Sstevel@tonic-gate 		strcpy(p, argv[i]);
26397c478bd9Sstevel@tonic-gate 		p += strlen(p);
26407c478bd9Sstevel@tonic-gate 		*p++ = ' ';
26417c478bd9Sstevel@tonic-gate 	}
26427c478bd9Sstevel@tonic-gate 	*--p = '\0';
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	return (str);
26457c478bd9Sstevel@tonic-gate }
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate /*
26487c478bd9Sstevel@tonic-gate  * Take the expression in the string "expr"
26497c478bd9Sstevel@tonic-gate  * and compile it into the code array.
26507c478bd9Sstevel@tonic-gate  * Print the generated code if the print
26517c478bd9Sstevel@tonic-gate  * arg is set.
26527c478bd9Sstevel@tonic-gate  */
26537c478bd9Sstevel@tonic-gate void
26547c478bd9Sstevel@tonic-gate compile(char *expr, int print)
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate 	expr = strdup(expr);
26577c478bd9Sstevel@tonic-gate 	if (expr == NULL)
26587c478bd9Sstevel@tonic-gate 		pr_err("no mem");
26597c478bd9Sstevel@tonic-gate 	curr_op = oplist;
26607c478bd9Sstevel@tonic-gate 	tkp = expr;
26617c478bd9Sstevel@tonic-gate 	dir = ANY;
26627c478bd9Sstevel@tonic-gate 
26637c478bd9Sstevel@tonic-gate 	next();
26647c478bd9Sstevel@tonic-gate 	if (tokentype != EOL)
26657c478bd9Sstevel@tonic-gate 		expression();
26667c478bd9Sstevel@tonic-gate 	emitop(OP_STOP);
26677c478bd9Sstevel@tonic-gate 	if (tokentype != EOL)
26687c478bd9Sstevel@tonic-gate 		pr_err("invalid expression");
26697c478bd9Sstevel@tonic-gate 	optimize(oplist);
26707c478bd9Sstevel@tonic-gate 	if (print)
26717c478bd9Sstevel@tonic-gate 		codeprint();
26727c478bd9Sstevel@tonic-gate }
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate /*
26757c478bd9Sstevel@tonic-gate  * Lookup hostname in the arp cache.
26767c478bd9Sstevel@tonic-gate  */
26777c478bd9Sstevel@tonic-gate boolean_t
26787c478bd9Sstevel@tonic-gate arp_for_ether(char *hostname, struct ether_addr *ep)
26797c478bd9Sstevel@tonic-gate {
26807c478bd9Sstevel@tonic-gate 	struct arpreq ar;
26817c478bd9Sstevel@tonic-gate 	struct hostent *hp;
26827c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
26837c478bd9Sstevel@tonic-gate 	int error_num;
26847c478bd9Sstevel@tonic-gate 	int s;
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	memset(&ar, 0, sizeof (ar));
26877c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ar.arp_pa;
26887c478bd9Sstevel@tonic-gate 	sin->sin_family = AF_INET;
26897c478bd9Sstevel@tonic-gate 	hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
26907c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
26917c478bd9Sstevel@tonic-gate 		return (B_FALSE);
26927c478bd9Sstevel@tonic-gate 	}
26937c478bd9Sstevel@tonic-gate 	memcpy(&sin->sin_addr, hp->h_addr, sizeof (sin->sin_addr));
26947c478bd9Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
26957c478bd9Sstevel@tonic-gate 	if (s < 0) {
26967c478bd9Sstevel@tonic-gate 		return (B_FALSE);
26977c478bd9Sstevel@tonic-gate 	}
26987c478bd9Sstevel@tonic-gate 	if (ioctl(s, SIOCGARP, &ar) < 0) {
26997c478bd9Sstevel@tonic-gate 		close(s);
27007c478bd9Sstevel@tonic-gate 		return (B_FALSE);
27017c478bd9Sstevel@tonic-gate 	}
27027c478bd9Sstevel@tonic-gate 	close(s);
27037c478bd9Sstevel@tonic-gate 	memcpy(ep->ether_addr_octet, ar.arp_ha.sa_data, sizeof (*ep));
27047c478bd9Sstevel@tonic-gate 	return (B_TRUE);
27057c478bd9Sstevel@tonic-gate }
2706