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