17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5d6f299a8Sdg * Common Development and Distribution License (the "License").
6d6f299a8Sdg * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
222b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247d897698SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <stddef.h>
362b24ab6bSSebastien Roy #include <unistd.h>
372b24ab6bSSebastien Roy #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <sys/socket.h>
397c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
40605445d5Sdg #include <sys/vlan.h>
417c478bd9Sstevel@tonic-gate #include <net/if.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in.h>
437c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
447c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip.h>
467c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
477c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
487c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
497c478bd9Sstevel@tonic-gate #include <netdb.h>
507c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
517c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
527c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
53b127ac41SPhilip Kirk #include <sys/dlpi.h>
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate #include <snoop.h>
56605445d5Sdg #include "snoop_vlan.h"
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate #define IPV4_ONLY 0
597c478bd9Sstevel@tonic-gate #define IPV6_ONLY 1
607c478bd9Sstevel@tonic-gate #define IPV4_AND_IPV6 2
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate * The following constants represent the offsets in bytes from the beginning
647c478bd9Sstevel@tonic-gate * of the IP(v6) header of the source and destination IP(v6) addresses.
657c478bd9Sstevel@tonic-gate * These are useful when generating filter code.
667c478bd9Sstevel@tonic-gate */
677c478bd9Sstevel@tonic-gate #define IPV4_SRCADDR_OFFSET 12
687c478bd9Sstevel@tonic-gate #define IPV4_DSTADDR_OFFSET 16
697c478bd9Sstevel@tonic-gate #define IPV6_SRCADDR_OFFSET 8
707c478bd9Sstevel@tonic-gate #define IPV6_DSTADDR_OFFSET 24
717c478bd9Sstevel@tonic-gate #define IP_VERS(p) (((*(uchar_t *)p) & 0xf0) >> 4)
727c478bd9Sstevel@tonic-gate #define MASKED_IPV4_VERS 0x40
737c478bd9Sstevel@tonic-gate #define MASKED_IPV6_VERS 0x60
747c478bd9Sstevel@tonic-gate #define IP_HDR_LEN(p) (((*(uchar_t *)p) & 0xf) * 4)
757c478bd9Sstevel@tonic-gate #define TCP_HDR_LEN(p) ((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4)
76605445d5Sdg
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate * Coding the constant below is tacky, but the compiler won't let us
797c478bd9Sstevel@tonic-gate * be more clever. E.g., &((struct ip *)0)->ip_xxx
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@tonic-gate #define IP_PROTO_OF(p) (((uchar_t *)p)[9])
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate * AppleTalk uses 802.2 Ethernet encapsulation with LLC/SNAP headers,
857c478bd9Sstevel@tonic-gate * for 8 octets of overhead, and the common AppleTalk DDP Ethernet
867c478bd9Sstevel@tonic-gate * header is another 4 octets.
877c478bd9Sstevel@tonic-gate *
887c478bd9Sstevel@tonic-gate * The following constants represents the offsets in bytes from the beginning
897c478bd9Sstevel@tonic-gate * of the Ethernet payload to various parts of the DDP header.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #define AT_DST_NET_OFFSET 12
937c478bd9Sstevel@tonic-gate #define AT_SRC_NET_OFFSET 14
947c478bd9Sstevel@tonic-gate #define AT_DST_NODE_OFFSET 16
957c478bd9Sstevel@tonic-gate #define AT_SRC_NODE_OFFSET 17
967c478bd9Sstevel@tonic-gate
97b127ac41SPhilip Kirk /*
98b127ac41SPhilip Kirk * Offset for the source and destination zoneid in the ipnet header.
99b127ac41SPhilip Kirk */
1000a0e9771SDarren Reed #define IPNET_SRCZONE_OFFSET 16
1010a0e9771SDarren Reed #define IPNET_DSTZONE_OFFSET 20
102b127ac41SPhilip Kirk
1037c478bd9Sstevel@tonic-gate int eaddr; /* need ethernet addr */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate int opstack; /* operand stack depth */
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate * These are the operators of the user-level filter.
1097c478bd9Sstevel@tonic-gate * STOP ends execution of the filter expression and
1107c478bd9Sstevel@tonic-gate * returns the truth value at the top of the stack.
1117c478bd9Sstevel@tonic-gate * OP_LOAD_OCTET, OP_LOAD_SHORT and OP_LOAD_LONG pop
1127c478bd9Sstevel@tonic-gate * an offset value from the stack and load a value of
1137c478bd9Sstevel@tonic-gate * an appropriate size from the packet (octet, short or
1147c478bd9Sstevel@tonic-gate * long). The offset is computed from a base value that
1157c478bd9Sstevel@tonic-gate * may be set via the OP_OFFSET operators.
1167c478bd9Sstevel@tonic-gate * OP_EQ, OP_NE, OP_GT, OP_GE, OP_LT, OP_LE pop two values
1177c478bd9Sstevel@tonic-gate * from the stack and return the result of their comparison.
1187c478bd9Sstevel@tonic-gate * OP_AND, OP_OR, OP_XOR pop two values from the stack and
1197c478bd9Sstevel@tonic-gate * do perform a bitwise operation on them - returning a result
1207c478bd9Sstevel@tonic-gate * to the stack. OP_NOT inverts the bits of the value on the
1217c478bd9Sstevel@tonic-gate * stack.
1227c478bd9Sstevel@tonic-gate * OP_BRFL and OP_BRTR branch to an offset in the code array
1237c478bd9Sstevel@tonic-gate * depending on the value at the top of the stack: true (not 0)
1247c478bd9Sstevel@tonic-gate * or false (0).
1257c478bd9Sstevel@tonic-gate * OP_ADD, OP_SUB, OP_MUL, OP_DIV and OP_REM pop two values
1267c478bd9Sstevel@tonic-gate * from the stack and perform arithmetic.
1277c478bd9Sstevel@tonic-gate * The OP_OFFSET operators change the base from which the
1287c478bd9Sstevel@tonic-gate * OP_LOAD operators compute their offsets.
1297c478bd9Sstevel@tonic-gate * OP_OFFSET_ZERO sets the offset to zero - beginning of packet.
1307c478bd9Sstevel@tonic-gate * OP_OFFSET_LINK sets the base to the first octet after
1317c478bd9Sstevel@tonic-gate * the link (DLC) header. OP_OFFSET_IP, OP_OFFSET_TCP,
1327c478bd9Sstevel@tonic-gate * and OP_OFFSET_UDP do the same for those headers - they
1337c478bd9Sstevel@tonic-gate * set the offset base to the *end* of the header - not the
1347c478bd9Sstevel@tonic-gate * beginning. The OP_OFFSET_RPC operator is a bit unusual.
1357c478bd9Sstevel@tonic-gate * It points the base at the cached RPC header. For the
1367c478bd9Sstevel@tonic-gate * purposes of selection, RPC reply headers look like call
1377c478bd9Sstevel@tonic-gate * headers except for the direction value.
138605445d5Sdg * OP_OFFSET_ETHERTYPE sets base according to the following
139605445d5Sdg * algorithm:
140605445d5Sdg * if the packet is not VLAN tagged, then set base to
141605445d5Sdg * the ethertype field in the ethernet header
142605445d5Sdg * else set base to the ethertype field of the VLAN header
1437c478bd9Sstevel@tonic-gate * OP_OFFSET_POP restores the offset base to the value prior
1447c478bd9Sstevel@tonic-gate * to the most recent OP_OFFSET call.
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate enum optype {
1477c478bd9Sstevel@tonic-gate OP_STOP = 0,
1487c478bd9Sstevel@tonic-gate OP_LOAD_OCTET,
1497c478bd9Sstevel@tonic-gate OP_LOAD_SHORT,
1507c478bd9Sstevel@tonic-gate OP_LOAD_LONG,
1517c478bd9Sstevel@tonic-gate OP_LOAD_CONST,
1527c478bd9Sstevel@tonic-gate OP_LOAD_LENGTH,
1537c478bd9Sstevel@tonic-gate OP_EQ,
1547c478bd9Sstevel@tonic-gate OP_NE,
1557c478bd9Sstevel@tonic-gate OP_GT,
1567c478bd9Sstevel@tonic-gate OP_GE,
1577c478bd9Sstevel@tonic-gate OP_LT,
1587c478bd9Sstevel@tonic-gate OP_LE,
1597c478bd9Sstevel@tonic-gate OP_AND,
1607c478bd9Sstevel@tonic-gate OP_OR,
1617c478bd9Sstevel@tonic-gate OP_XOR,
1627c478bd9Sstevel@tonic-gate OP_NOT,
1637c478bd9Sstevel@tonic-gate OP_BRFL,
1647c478bd9Sstevel@tonic-gate OP_BRTR,
1657c478bd9Sstevel@tonic-gate OP_ADD,
1667c478bd9Sstevel@tonic-gate OP_SUB,
1677c478bd9Sstevel@tonic-gate OP_MUL,
1687c478bd9Sstevel@tonic-gate OP_DIV,
1697c478bd9Sstevel@tonic-gate OP_REM,
1707c478bd9Sstevel@tonic-gate OP_OFFSET_POP,
1717c478bd9Sstevel@tonic-gate OP_OFFSET_ZERO,
1727c478bd9Sstevel@tonic-gate OP_OFFSET_LINK,
1737c478bd9Sstevel@tonic-gate OP_OFFSET_IP,
1747c478bd9Sstevel@tonic-gate OP_OFFSET_TCP,
1757c478bd9Sstevel@tonic-gate OP_OFFSET_UDP,
1767c478bd9Sstevel@tonic-gate OP_OFFSET_RPC,
1777c478bd9Sstevel@tonic-gate OP_OFFSET_SLP,
178605445d5Sdg OP_OFFSET_ETHERTYPE,
1797c478bd9Sstevel@tonic-gate OP_LAST
1807c478bd9Sstevel@tonic-gate };
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate static char *opnames[] = {
1837c478bd9Sstevel@tonic-gate "STOP",
1847c478bd9Sstevel@tonic-gate "LOAD_OCTET",
1857c478bd9Sstevel@tonic-gate "LOAD_SHORT",
1867c478bd9Sstevel@tonic-gate "LOAD_LONG",
1877c478bd9Sstevel@tonic-gate "LOAD_CONST",
1887c478bd9Sstevel@tonic-gate "LOAD_LENGTH",
1897c478bd9Sstevel@tonic-gate "EQ",
1907c478bd9Sstevel@tonic-gate "NE",
1917c478bd9Sstevel@tonic-gate "GT",
1927c478bd9Sstevel@tonic-gate "GE",
1937c478bd9Sstevel@tonic-gate "LT",
1947c478bd9Sstevel@tonic-gate "LE",
1957c478bd9Sstevel@tonic-gate "AND",
1967c478bd9Sstevel@tonic-gate "OR",
1977c478bd9Sstevel@tonic-gate "XOR",
1987c478bd9Sstevel@tonic-gate "NOT",
1997c478bd9Sstevel@tonic-gate "BRFL",
2007c478bd9Sstevel@tonic-gate "BRTR",
2017c478bd9Sstevel@tonic-gate "ADD",
2027c478bd9Sstevel@tonic-gate "SUB",
2037c478bd9Sstevel@tonic-gate "MUL",
2047c478bd9Sstevel@tonic-gate "DIV",
2057c478bd9Sstevel@tonic-gate "REM",
2067c478bd9Sstevel@tonic-gate "OFFSET_POP",
2077c478bd9Sstevel@tonic-gate "OFFSET_ZERO",
2087c478bd9Sstevel@tonic-gate "OFFSET_ETHER",
2097c478bd9Sstevel@tonic-gate "OFFSET_IP",
2107c478bd9Sstevel@tonic-gate "OFFSET_TCP",
2117c478bd9Sstevel@tonic-gate "OFFSET_UDP",
2127c478bd9Sstevel@tonic-gate "OFFSET_RPC",
2137c478bd9Sstevel@tonic-gate "OP_OFFSET_SLP",
214605445d5Sdg "OFFSET_ETHERTYPE",
2157c478bd9Sstevel@tonic-gate ""
2167c478bd9Sstevel@tonic-gate };
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate #define MAXOPS 1024
2197c478bd9Sstevel@tonic-gate #define MAXSS 64
2207c478bd9Sstevel@tonic-gate static uint_t oplist[MAXOPS]; /* array of operators */
2217c478bd9Sstevel@tonic-gate static uint_t *curr_op; /* last op generated */
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate extern int valid_slp(uchar_t *, int); /* decides if a SLP msg is valid */
2247c478bd9Sstevel@tonic-gate extern struct hostent *lgetipnodebyname(const char *, int, int, int *);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate static void alternation();
2277c478bd9Sstevel@tonic-gate static uint_t chain();
2287c478bd9Sstevel@tonic-gate static void codeprint();
2297c478bd9Sstevel@tonic-gate static void emitop();
2307c478bd9Sstevel@tonic-gate static void emitval();
2317c478bd9Sstevel@tonic-gate static void expression();
2327c478bd9Sstevel@tonic-gate static struct xid_entry *find_rpc();
2337c478bd9Sstevel@tonic-gate static void optimize();
2347c478bd9Sstevel@tonic-gate static void ethertype_match();
2357c478bd9Sstevel@tonic-gate
236605445d5Sdg /*
237605445d5Sdg * Get a ushort from a possibly unaligned character buffer.
238605445d5Sdg *
239605445d5Sdg * INPUTS: buffer - where the data is. Must be at least
240605445d5Sdg * sizeof(uint16_t) bytes long.
241605445d5Sdg * OUPUTS: An unsigned short that contains the data at buffer.
242605445d5Sdg * No calls to ntohs or htons are done on the data.
243605445d5Sdg */
244605445d5Sdg static uint16_t
get_u16(uchar_t * buffer)245605445d5Sdg get_u16(uchar_t *buffer)
246605445d5Sdg {
247605445d5Sdg uint8_t *bufraw = buffer;
248605445d5Sdg
249605445d5Sdg /*
250605445d5Sdg * ntohs is used only as a cheap way to flip the bits
251605445d5Sdg * around on a little endian platform. The value will
252605445d5Sdg * still be in host order or network order, depending on
253605445d5Sdg * the order it was in when it was passed in.
254605445d5Sdg */
255605445d5Sdg return (ntohs(bufraw[0] << 8 | bufraw[1]));
256605445d5Sdg }
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate * Returns the ULP for an IPv4 or IPv6 packet
2607c478bd9Sstevel@tonic-gate * Assumes that the packet has already been checked to verify
2617c478bd9Sstevel@tonic-gate * that it's either IPv4 or IPv6
2627c478bd9Sstevel@tonic-gate *
2637c478bd9Sstevel@tonic-gate * XXX Will need to be updated for AH and ESP
2647c478bd9Sstevel@tonic-gate * XXX when IPsec is supported for v6.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate static uchar_t
ip_proto_of(uchar_t * ip)2677c478bd9Sstevel@tonic-gate ip_proto_of(uchar_t *ip)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate uchar_t nxt;
2707c478bd9Sstevel@tonic-gate boolean_t not_done = B_TRUE;
2717c478bd9Sstevel@tonic-gate uchar_t *ptr = ip;
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate switch (IP_VERS(ip)) {
2747c478bd9Sstevel@tonic-gate case IPV4_VERSION:
2757c478bd9Sstevel@tonic-gate return (IP_PROTO_OF(ip));
2767c478bd9Sstevel@tonic-gate case IPV6_VERSION:
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate nxt = ip[6];
2797c478bd9Sstevel@tonic-gate ptr += 40; /* size of ip6 header */
2807c478bd9Sstevel@tonic-gate do {
2817c478bd9Sstevel@tonic-gate switch (nxt) {
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * XXX Add IPsec headers here when supported for v6
2847c478bd9Sstevel@tonic-gate * XXX (the AH will have a different size...)
2857c478bd9Sstevel@tonic-gate */
2867c478bd9Sstevel@tonic-gate case IPPROTO_HOPOPTS:
2877c478bd9Sstevel@tonic-gate case IPPROTO_ROUTING:
2887c478bd9Sstevel@tonic-gate case IPPROTO_FRAGMENT:
2897c478bd9Sstevel@tonic-gate case IPPROTO_DSTOPTS:
2907c478bd9Sstevel@tonic-gate ptr += (8 * (ptr[1] + 1));
2917c478bd9Sstevel@tonic-gate nxt = *ptr;
2927c478bd9Sstevel@tonic-gate break;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate default:
2957c478bd9Sstevel@tonic-gate not_done = B_FALSE;
2967c478bd9Sstevel@tonic-gate break;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate } while (not_done);
2997c478bd9Sstevel@tonic-gate return (nxt);
3007c478bd9Sstevel@tonic-gate default:
3017c478bd9Sstevel@tonic-gate break; /* shouldn't get here... */
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate return (0);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate * Returns the total IP header length.
3087c478bd9Sstevel@tonic-gate * For v4, this includes any options present.
3097c478bd9Sstevel@tonic-gate * For v6, this is the length of the IPv6 header plus
3107c478bd9Sstevel@tonic-gate * any extension headers present.
3117c478bd9Sstevel@tonic-gate *
3127c478bd9Sstevel@tonic-gate * XXX Will need to be updated for AH and ESP
3137c478bd9Sstevel@tonic-gate * XXX when IPsec is supported for v6.
3147c478bd9Sstevel@tonic-gate */
3157c478bd9Sstevel@tonic-gate static int
ip_hdr_len(uchar_t * ip)3167c478bd9Sstevel@tonic-gate ip_hdr_len(uchar_t *ip)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate uchar_t nxt;
3197c478bd9Sstevel@tonic-gate int hdr_len;
3207c478bd9Sstevel@tonic-gate boolean_t not_done = B_TRUE;
3217c478bd9Sstevel@tonic-gate int len = 40; /* IPv6 header size */
3227c478bd9Sstevel@tonic-gate uchar_t *ptr = ip;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate switch (IP_VERS(ip)) {
3257c478bd9Sstevel@tonic-gate case IPV4_VERSION:
3267c478bd9Sstevel@tonic-gate return (IP_HDR_LEN(ip));
3277c478bd9Sstevel@tonic-gate case IPV6_VERSION:
3287c478bd9Sstevel@tonic-gate nxt = ip[6];
3297c478bd9Sstevel@tonic-gate ptr += len;
3307c478bd9Sstevel@tonic-gate do {
3317c478bd9Sstevel@tonic-gate switch (nxt) {
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * XXX Add IPsec headers here when supported for v6
3347c478bd9Sstevel@tonic-gate * XXX (the AH will have a different size...)
3357c478bd9Sstevel@tonic-gate */
3367c478bd9Sstevel@tonic-gate case IPPROTO_HOPOPTS:
3377c478bd9Sstevel@tonic-gate case IPPROTO_ROUTING:
3387c478bd9Sstevel@tonic-gate case IPPROTO_FRAGMENT:
3397c478bd9Sstevel@tonic-gate case IPPROTO_DSTOPTS:
3407c478bd9Sstevel@tonic-gate hdr_len = (8 * (ptr[1] + 1));
3417c478bd9Sstevel@tonic-gate len += hdr_len;
3427c478bd9Sstevel@tonic-gate ptr += hdr_len;
3437c478bd9Sstevel@tonic-gate nxt = *ptr;
3447c478bd9Sstevel@tonic-gate break;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate default:
3477c478bd9Sstevel@tonic-gate not_done = B_FALSE;
3487c478bd9Sstevel@tonic-gate break;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate } while (not_done);
3517c478bd9Sstevel@tonic-gate return (len);
3527c478bd9Sstevel@tonic-gate default:
3537c478bd9Sstevel@tonic-gate break;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate return (0); /* not IP */
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate static void
codeprint()3597c478bd9Sstevel@tonic-gate codeprint()
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate uint_t *op;
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate printf("User filter:\n");
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate for (op = oplist; *op; op++) {
3667c478bd9Sstevel@tonic-gate if (*op <= OP_LAST)
3677c478bd9Sstevel@tonic-gate printf("\t%2d: %s\n", op - oplist, opnames[*op]);
3687c478bd9Sstevel@tonic-gate else
3697c478bd9Sstevel@tonic-gate printf("\t%2d: (%d)\n", op - oplist, *op);
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate switch (*op) {
3727c478bd9Sstevel@tonic-gate case OP_LOAD_CONST:
3737c478bd9Sstevel@tonic-gate case OP_BRTR:
3747c478bd9Sstevel@tonic-gate case OP_BRFL:
3757c478bd9Sstevel@tonic-gate op++;
3767c478bd9Sstevel@tonic-gate if ((int)*op < 0)
3777c478bd9Sstevel@tonic-gate printf("\t%2d: 0x%08x (%d)\n",
378b127ac41SPhilip Kirk op - oplist, *op, *op);
3797c478bd9Sstevel@tonic-gate else
3807c478bd9Sstevel@tonic-gate printf("\t%2d: %d (0x%08x)\n",
381b127ac41SPhilip Kirk op - oplist, *op, *op);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate printf("\t%2d: STOP\n", op - oplist);
3857c478bd9Sstevel@tonic-gate printf("\n");
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * Take a pass through the generated code and optimize
3917c478bd9Sstevel@tonic-gate * branches. A branch true (BRTR) that has another BRTR
3927c478bd9Sstevel@tonic-gate * at its destination can use the address of the destination
3937c478bd9Sstevel@tonic-gate * BRTR. A BRTR that points to a BRFL (branch false) should
3947c478bd9Sstevel@tonic-gate * point to the address following the BRFL.
3957c478bd9Sstevel@tonic-gate * A similar optimization applies to BRFL operators.
3967c478bd9Sstevel@tonic-gate */
3977c478bd9Sstevel@tonic-gate static void
optimize(uint_t * oplistp)3987c478bd9Sstevel@tonic-gate optimize(uint_t *oplistp)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate uint_t *op;
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate for (op = oplistp; *op; op++) {
4037c478bd9Sstevel@tonic-gate switch (*op) {
4047c478bd9Sstevel@tonic-gate case OP_LOAD_CONST:
4057c478bd9Sstevel@tonic-gate op++;
4067c478bd9Sstevel@tonic-gate break;
4077c478bd9Sstevel@tonic-gate case OP_BRTR:
4087c478bd9Sstevel@tonic-gate op++;
4097c478bd9Sstevel@tonic-gate optimize(&oplist[*op]);
4107c478bd9Sstevel@tonic-gate if (oplist[*op] == OP_BRFL)
4117c478bd9Sstevel@tonic-gate *op += 2;
4127c478bd9Sstevel@tonic-gate else if (oplist[*op] == OP_BRTR)
4137c478bd9Sstevel@tonic-gate *op = oplist[*op + 1];
4147c478bd9Sstevel@tonic-gate break;
4157c478bd9Sstevel@tonic-gate case OP_BRFL:
4167c478bd9Sstevel@tonic-gate op++;
4177c478bd9Sstevel@tonic-gate optimize(&oplist[*op]);
4187c478bd9Sstevel@tonic-gate if (oplist[*op] == OP_BRTR)
4197c478bd9Sstevel@tonic-gate *op += 2;
4207c478bd9Sstevel@tonic-gate else if (oplist[*op] == OP_BRFL)
4217c478bd9Sstevel@tonic-gate *op = oplist[*op + 1];
4227c478bd9Sstevel@tonic-gate break;
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate * RPC packets are tough to filter.
4297c478bd9Sstevel@tonic-gate * While the call packet has all the interesting
4307c478bd9Sstevel@tonic-gate * info: program number, version, procedure etc,
4317c478bd9Sstevel@tonic-gate * the reply packet has none of this information.
4327c478bd9Sstevel@tonic-gate * If we want to do useful filtering based on this
4337c478bd9Sstevel@tonic-gate * information then we have to stash the information
4347c478bd9Sstevel@tonic-gate * from the call packet, and use the XID in the reply
4357c478bd9Sstevel@tonic-gate * to find the stashed info. The stashed info is
4367c478bd9Sstevel@tonic-gate * kept in a circular lifo, assuming that a call packet
4377c478bd9Sstevel@tonic-gate * will be followed quickly by its reply.
4387c478bd9Sstevel@tonic-gate */
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate struct xid_entry {
4417c478bd9Sstevel@tonic-gate unsigned x_xid; /* The XID (32 bits) */
4427c478bd9Sstevel@tonic-gate unsigned x_dir; /* CALL or REPLY */
4437c478bd9Sstevel@tonic-gate unsigned x_rpcvers; /* Protocol version (2) */
4447c478bd9Sstevel@tonic-gate unsigned x_prog; /* RPC program number */
4457c478bd9Sstevel@tonic-gate unsigned x_vers; /* RPC version number */
4467c478bd9Sstevel@tonic-gate unsigned x_proc; /* RPC procedure number */
4477c478bd9Sstevel@tonic-gate };
4487c478bd9Sstevel@tonic-gate static struct xid_entry xe_table[XID_CACHE_SIZE];
4497c478bd9Sstevel@tonic-gate static struct xid_entry *xe_first = &xe_table[0];
4507c478bd9Sstevel@tonic-gate static struct xid_entry *xe = &xe_table[0];
4517c478bd9Sstevel@tonic-gate static struct xid_entry *xe_last = &xe_table[XID_CACHE_SIZE - 1];
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate static struct xid_entry *
find_rpc(struct rpc_msg * rpc)4547c478bd9Sstevel@tonic-gate find_rpc(struct rpc_msg *rpc)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate struct xid_entry *x;
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate for (x = xe; x >= xe_first; x--)
4597c478bd9Sstevel@tonic-gate if (x->x_xid == rpc->rm_xid)
4607c478bd9Sstevel@tonic-gate return (x);
4617c478bd9Sstevel@tonic-gate for (x = xe_last; x > xe; x--)
4627c478bd9Sstevel@tonic-gate if (x->x_xid == rpc->rm_xid)
4637c478bd9Sstevel@tonic-gate return (x);
4647c478bd9Sstevel@tonic-gate return (NULL);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate static void
stash_rpc(struct rpc_msg * rpc)4687c478bd9Sstevel@tonic-gate stash_rpc(struct rpc_msg *rpc)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate struct xid_entry *x;
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate if (find_rpc(rpc))
4737c478bd9Sstevel@tonic-gate return;
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate x = xe++;
4767c478bd9Sstevel@tonic-gate if (xe > xe_last)
4777c478bd9Sstevel@tonic-gate xe = xe_first;
4787c478bd9Sstevel@tonic-gate x->x_xid = rpc->rm_xid;
4797c478bd9Sstevel@tonic-gate x->x_dir = htonl(REPLY);
4807c478bd9Sstevel@tonic-gate x->x_prog = rpc->rm_call.cb_prog;
4817c478bd9Sstevel@tonic-gate x->x_vers = rpc->rm_call.cb_vers;
4827c478bd9Sstevel@tonic-gate x->x_proc = rpc->rm_call.cb_proc;
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * SLP can multicast requests, and recieve unicast replies in which
4877c478bd9Sstevel@tonic-gate * neither the source nor destination port is identifiable as a SLP
4887c478bd9Sstevel@tonic-gate * port. Hence, we need to do as RPC does, and keep track of packets we
4897c478bd9Sstevel@tonic-gate * are interested in. For SLP, however, we use ports, not XIDs, and
4907c478bd9Sstevel@tonic-gate * a smaller cache size is more efficient since every incoming packet
4917c478bd9Sstevel@tonic-gate * needs to be checked.
4927c478bd9Sstevel@tonic-gate */
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate #define SLP_CACHE_SIZE 64
4957c478bd9Sstevel@tonic-gate static uint_t slp_table[SLP_CACHE_SIZE];
4967c478bd9Sstevel@tonic-gate static int slp_index = 0;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate * Returns the index of dport in the table if found, otherwise -1.
5007c478bd9Sstevel@tonic-gate */
5017c478bd9Sstevel@tonic-gate static int
find_slp(uint_t dport)502*cd93bdd3SToomas Soome find_slp(uint_t dport)
503*cd93bdd3SToomas Soome {
504*cd93bdd3SToomas Soome int i;
5057c478bd9Sstevel@tonic-gate
506*cd93bdd3SToomas Soome if (!dport)
507*cd93bdd3SToomas Soome return (0);
5087c478bd9Sstevel@tonic-gate
509*cd93bdd3SToomas Soome for (i = slp_index; i >= 0; i--)
510*cd93bdd3SToomas Soome if (slp_table[i] == dport) {
511*cd93bdd3SToomas Soome return (i);
512*cd93bdd3SToomas Soome }
513*cd93bdd3SToomas Soome for (i = SLP_CACHE_SIZE - 1; i > slp_index; i--)
514*cd93bdd3SToomas Soome if (slp_table[i] == dport) {
515*cd93bdd3SToomas Soome return (i);
516*cd93bdd3SToomas Soome }
517*cd93bdd3SToomas Soome return (-1);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
520*cd93bdd3SToomas Soome static void
stash_slp(uint_t sport)521*cd93bdd3SToomas Soome stash_slp(uint_t sport)
522*cd93bdd3SToomas Soome {
523*cd93bdd3SToomas Soome if (slp_table[slp_index - 1] == sport)
524*cd93bdd3SToomas Soome /* avoid redundancy due to multicast retransmissions */
525*cd93bdd3SToomas Soome return;
5267c478bd9Sstevel@tonic-gate
527*cd93bdd3SToomas Soome slp_table[slp_index++] = sport;
528*cd93bdd3SToomas Soome if (slp_index == SLP_CACHE_SIZE)
529*cd93bdd3SToomas Soome slp_index = 0;
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate * This routine takes a packet and returns true or false
5347c478bd9Sstevel@tonic-gate * according to whether the filter expression selects it
5357c478bd9Sstevel@tonic-gate * or not.
5367c478bd9Sstevel@tonic-gate * We assume here that offsets for short and long values
5377c478bd9Sstevel@tonic-gate * are even - we may die with an alignment error if the
5387c478bd9Sstevel@tonic-gate * CPU doesn't support odd addresses. Note that long
5397c478bd9Sstevel@tonic-gate * values are loaded as two shorts so that 32 bit word
5407c478bd9Sstevel@tonic-gate * alignment isn't important.
5417c478bd9Sstevel@tonic-gate *
5427c478bd9Sstevel@tonic-gate * IPv6 is a bit stickier to handle than IPv4...
5437c478bd9Sstevel@tonic-gate */
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate int
want_packet(uchar_t * pkt,int len,int origlen)5467c478bd9Sstevel@tonic-gate want_packet(uchar_t *pkt, int len, int origlen)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate uint_t stack[MAXSS]; /* operand stack */
5497c478bd9Sstevel@tonic-gate uint_t *op; /* current operator */
5507c478bd9Sstevel@tonic-gate uint_t *sp; /* top of operand stack */
5517c478bd9Sstevel@tonic-gate uchar_t *base; /* base for offsets into packet */
5527c478bd9Sstevel@tonic-gate uchar_t *ip; /* addr of IP header, unaligned */
5537c478bd9Sstevel@tonic-gate uchar_t *tcp; /* addr of TCP header, unaligned */
5547c478bd9Sstevel@tonic-gate uchar_t *udp; /* addr of UDP header, unaligned */
5557c478bd9Sstevel@tonic-gate struct rpc_msg rpcmsg; /* addr of RPC header */
5567c478bd9Sstevel@tonic-gate struct rpc_msg *rpc;
5577c478bd9Sstevel@tonic-gate int newrpc = 0;
5587c478bd9Sstevel@tonic-gate uchar_t *slphdr; /* beginning of SLP header */
5597c478bd9Sstevel@tonic-gate uint_t slp_sport, slp_dport;
5607c478bd9Sstevel@tonic-gate int off, header_size;
5617c478bd9Sstevel@tonic-gate uchar_t *offstack[MAXSS]; /* offset stack */
5627c478bd9Sstevel@tonic-gate uchar_t **offp; /* current offset */
5637c478bd9Sstevel@tonic-gate uchar_t *opkt = NULL;
5647c478bd9Sstevel@tonic-gate uint_t olen;
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate sp = stack;
5677c478bd9Sstevel@tonic-gate *sp = 1;
5687c478bd9Sstevel@tonic-gate base = pkt;
5697c478bd9Sstevel@tonic-gate offp = offstack;
5707c478bd9Sstevel@tonic-gate
5712b24ab6bSSebastien Roy header_size = (*interface->header_len)((char *)pkt, len);
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate for (op = oplist; *op; op++) {
5747c478bd9Sstevel@tonic-gate switch ((enum optype) *op) {
5757c478bd9Sstevel@tonic-gate case OP_LOAD_OCTET:
5767c478bd9Sstevel@tonic-gate if ((base + *sp) > (pkt + len))
5777c478bd9Sstevel@tonic-gate return (0); /* packet too short */
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate *sp = *((uchar_t *)(base + *sp));
5807c478bd9Sstevel@tonic-gate break;
5817c478bd9Sstevel@tonic-gate case OP_LOAD_SHORT:
5827c478bd9Sstevel@tonic-gate off = *sp;
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate if ((base + off + sizeof (uint16_t) - 1) > (pkt + len))
5857c478bd9Sstevel@tonic-gate return (0); /* packet too short */
5867c478bd9Sstevel@tonic-gate
587605445d5Sdg *sp = ntohs(get_u16((uchar_t *)(base + off)));
5887c478bd9Sstevel@tonic-gate break;
5897c478bd9Sstevel@tonic-gate case OP_LOAD_LONG:
5907c478bd9Sstevel@tonic-gate off = *sp;
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate if ((base + off + sizeof (uint32_t) - 1) > (pkt + len))
5937c478bd9Sstevel@tonic-gate return (0); /* packet too short */
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Handle 3 possible alignments
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate switch ((((unsigned)base) + off) % sizeof (uint_t)) {
5997c478bd9Sstevel@tonic-gate case 0:
6007c478bd9Sstevel@tonic-gate *sp = *(uint_t *)(base + off);
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate case 2:
6047c478bd9Sstevel@tonic-gate *((ushort_t *)(sp)) =
605b127ac41SPhilip Kirk *((ushort_t *)(base + off));
6067c478bd9Sstevel@tonic-gate *(((ushort_t *)sp) + 1) =
607b127ac41SPhilip Kirk *((ushort_t *)(base + off) + 1);
6087c478bd9Sstevel@tonic-gate break;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate case 1:
6117c478bd9Sstevel@tonic-gate case 3:
6127c478bd9Sstevel@tonic-gate *((uchar_t *)(sp)) =
613b127ac41SPhilip Kirk *((uchar_t *)(base + off));
6147c478bd9Sstevel@tonic-gate *(((uchar_t *)sp) + 1) =
615b127ac41SPhilip Kirk *((uchar_t *)(base + off) + 1);
6167c478bd9Sstevel@tonic-gate *(((uchar_t *)sp) + 2) =
617b127ac41SPhilip Kirk *((uchar_t *)(base + off) + 2);
6187c478bd9Sstevel@tonic-gate *(((uchar_t *)sp) + 3) =
619b127ac41SPhilip Kirk *((uchar_t *)(base + off) + 3);
6207c478bd9Sstevel@tonic-gate break;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate *sp = ntohl(*sp);
6237c478bd9Sstevel@tonic-gate break;
6247c478bd9Sstevel@tonic-gate case OP_LOAD_CONST:
6257c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
6267c478bd9Sstevel@tonic-gate return (0);
6277c478bd9Sstevel@tonic-gate *(++sp) = *(++op);
6287c478bd9Sstevel@tonic-gate break;
6297c478bd9Sstevel@tonic-gate case OP_LOAD_LENGTH:
6307c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
6317c478bd9Sstevel@tonic-gate return (0);
6327c478bd9Sstevel@tonic-gate *(++sp) = origlen;
6337c478bd9Sstevel@tonic-gate break;
6347c478bd9Sstevel@tonic-gate case OP_EQ:
6357c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6367c478bd9Sstevel@tonic-gate return (0);
6377c478bd9Sstevel@tonic-gate sp--;
6387c478bd9Sstevel@tonic-gate *sp = *sp == *(sp + 1);
6397c478bd9Sstevel@tonic-gate break;
6407c478bd9Sstevel@tonic-gate case OP_NE:
6417c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6427c478bd9Sstevel@tonic-gate return (0);
6437c478bd9Sstevel@tonic-gate sp--;
6447c478bd9Sstevel@tonic-gate *sp = *sp != *(sp + 1);
6457c478bd9Sstevel@tonic-gate break;
6467c478bd9Sstevel@tonic-gate case OP_GT:
6477c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6487c478bd9Sstevel@tonic-gate return (0);
6497c478bd9Sstevel@tonic-gate sp--;
6507c478bd9Sstevel@tonic-gate *sp = *sp > *(sp + 1);
6517c478bd9Sstevel@tonic-gate break;
6527c478bd9Sstevel@tonic-gate case OP_GE:
6537c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6547c478bd9Sstevel@tonic-gate return (0);
6557c478bd9Sstevel@tonic-gate sp--;
6567c478bd9Sstevel@tonic-gate *sp = *sp >= *(sp + 1);
6577c478bd9Sstevel@tonic-gate break;
6587c478bd9Sstevel@tonic-gate case OP_LT:
6597c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6607c478bd9Sstevel@tonic-gate return (0);
6617c478bd9Sstevel@tonic-gate sp--;
6627c478bd9Sstevel@tonic-gate *sp = *sp < *(sp + 1);
6637c478bd9Sstevel@tonic-gate break;
6647c478bd9Sstevel@tonic-gate case OP_LE:
6657c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6667c478bd9Sstevel@tonic-gate return (0);
6677c478bd9Sstevel@tonic-gate sp--;
6687c478bd9Sstevel@tonic-gate *sp = *sp <= *(sp + 1);
6697c478bd9Sstevel@tonic-gate break;
6707c478bd9Sstevel@tonic-gate case OP_AND:
6717c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6727c478bd9Sstevel@tonic-gate return (0);
6737c478bd9Sstevel@tonic-gate sp--;
6747c478bd9Sstevel@tonic-gate *sp &= *(sp + 1);
6757c478bd9Sstevel@tonic-gate break;
6767c478bd9Sstevel@tonic-gate case OP_OR:
6777c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6787c478bd9Sstevel@tonic-gate return (0);
6797c478bd9Sstevel@tonic-gate sp--;
6807c478bd9Sstevel@tonic-gate *sp |= *(sp + 1);
6817c478bd9Sstevel@tonic-gate break;
6827c478bd9Sstevel@tonic-gate case OP_XOR:
6837c478bd9Sstevel@tonic-gate if (sp < &stack[1])
6847c478bd9Sstevel@tonic-gate return (0);
6857c478bd9Sstevel@tonic-gate sp--;
6867c478bd9Sstevel@tonic-gate *sp ^= *(sp + 1);
6877c478bd9Sstevel@tonic-gate break;
6887c478bd9Sstevel@tonic-gate case OP_NOT:
6897c478bd9Sstevel@tonic-gate *sp = !*sp;
6907c478bd9Sstevel@tonic-gate break;
6917c478bd9Sstevel@tonic-gate case OP_BRFL:
6927c478bd9Sstevel@tonic-gate op++;
6937c478bd9Sstevel@tonic-gate if (!*sp)
6947c478bd9Sstevel@tonic-gate op = &oplist[*op] - 1;
6957c478bd9Sstevel@tonic-gate break;
6967c478bd9Sstevel@tonic-gate case OP_BRTR:
6977c478bd9Sstevel@tonic-gate op++;
6987c478bd9Sstevel@tonic-gate if (*sp)
6997c478bd9Sstevel@tonic-gate op = &oplist[*op] - 1;
7007c478bd9Sstevel@tonic-gate break;
7017c478bd9Sstevel@tonic-gate case OP_ADD:
7027c478bd9Sstevel@tonic-gate if (sp < &stack[1])
7037c478bd9Sstevel@tonic-gate return (0);
7047c478bd9Sstevel@tonic-gate sp--;
7057c478bd9Sstevel@tonic-gate *sp += *(sp + 1);
7067c478bd9Sstevel@tonic-gate break;
7077c478bd9Sstevel@tonic-gate case OP_SUB:
7087c478bd9Sstevel@tonic-gate if (sp < &stack[1])
7097c478bd9Sstevel@tonic-gate return (0);
7107c478bd9Sstevel@tonic-gate sp--;
7117c478bd9Sstevel@tonic-gate *sp -= *(sp + 1);
7127c478bd9Sstevel@tonic-gate break;
7137c478bd9Sstevel@tonic-gate case OP_MUL:
7147c478bd9Sstevel@tonic-gate if (sp < &stack[1])
7157c478bd9Sstevel@tonic-gate return (0);
7167c478bd9Sstevel@tonic-gate sp--;
7177c478bd9Sstevel@tonic-gate *sp *= *(sp + 1);
7187c478bd9Sstevel@tonic-gate break;
7197c478bd9Sstevel@tonic-gate case OP_DIV:
7207c478bd9Sstevel@tonic-gate if (sp < &stack[1])
7217c478bd9Sstevel@tonic-gate return (0);
7227c478bd9Sstevel@tonic-gate sp--;
7237c478bd9Sstevel@tonic-gate *sp /= *(sp + 1);
7247c478bd9Sstevel@tonic-gate break;
7257c478bd9Sstevel@tonic-gate case OP_REM:
7267c478bd9Sstevel@tonic-gate if (sp < &stack[1])
7277c478bd9Sstevel@tonic-gate return (0);
7287c478bd9Sstevel@tonic-gate sp--;
7297c478bd9Sstevel@tonic-gate *sp %= *(sp + 1);
7307c478bd9Sstevel@tonic-gate break;
7317c478bd9Sstevel@tonic-gate case OP_OFFSET_POP:
7327c478bd9Sstevel@tonic-gate if (offp < &offstack[0])
7337c478bd9Sstevel@tonic-gate return (0);
7347c478bd9Sstevel@tonic-gate base = *offp--;
7357c478bd9Sstevel@tonic-gate if (opkt != NULL) {
7367c478bd9Sstevel@tonic-gate pkt = opkt;
7377c478bd9Sstevel@tonic-gate len = olen;
7387c478bd9Sstevel@tonic-gate opkt = NULL;
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate break;
7417c478bd9Sstevel@tonic-gate case OP_OFFSET_ZERO:
7427c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
7437c478bd9Sstevel@tonic-gate return (0);
7447c478bd9Sstevel@tonic-gate *++offp = base;
7457c478bd9Sstevel@tonic-gate base = pkt;
7467c478bd9Sstevel@tonic-gate break;
7477c478bd9Sstevel@tonic-gate case OP_OFFSET_LINK:
7487c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
7497c478bd9Sstevel@tonic-gate return (0);
7507c478bd9Sstevel@tonic-gate *++offp = base;
7517c478bd9Sstevel@tonic-gate base = pkt + header_size;
7527c478bd9Sstevel@tonic-gate /*
7537c478bd9Sstevel@tonic-gate * If the offset exceeds the packet length,
7547c478bd9Sstevel@tonic-gate * we should not be interested in this packet...
7557c478bd9Sstevel@tonic-gate * Just return 0.
7567c478bd9Sstevel@tonic-gate */
7577c478bd9Sstevel@tonic-gate if (base > pkt + len) {
7587c478bd9Sstevel@tonic-gate return (0);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate break;
7617c478bd9Sstevel@tonic-gate case OP_OFFSET_IP:
7627c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
7637c478bd9Sstevel@tonic-gate return (0);
7647c478bd9Sstevel@tonic-gate *++offp = base;
7657c478bd9Sstevel@tonic-gate ip = pkt + header_size;
7667c478bd9Sstevel@tonic-gate base = ip + ip_hdr_len(ip);
7677c478bd9Sstevel@tonic-gate if (base == ip) {
7687c478bd9Sstevel@tonic-gate return (0); /* not IP */
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate if (base > pkt + len) {
7717c478bd9Sstevel@tonic-gate return (0); /* bad pkt */
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate break;
7747c478bd9Sstevel@tonic-gate case OP_OFFSET_TCP:
7757c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
7767c478bd9Sstevel@tonic-gate return (0);
7777c478bd9Sstevel@tonic-gate *++offp = base;
7787c478bd9Sstevel@tonic-gate ip = pkt + header_size;
7797c478bd9Sstevel@tonic-gate tcp = ip + ip_hdr_len(ip);
7807c478bd9Sstevel@tonic-gate if (tcp == ip) {
7817c478bd9Sstevel@tonic-gate return (0); /* not IP */
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate base = tcp + TCP_HDR_LEN(tcp);
7847c478bd9Sstevel@tonic-gate if (base > pkt + len) {
7857c478bd9Sstevel@tonic-gate return (0);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate break;
7887c478bd9Sstevel@tonic-gate case OP_OFFSET_UDP:
7897c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
7907c478bd9Sstevel@tonic-gate return (0);
7917c478bd9Sstevel@tonic-gate *++offp = base;
7927c478bd9Sstevel@tonic-gate ip = pkt + header_size;
7937c478bd9Sstevel@tonic-gate udp = ip + ip_hdr_len(ip);
7947c478bd9Sstevel@tonic-gate if (udp == ip) {
7957c478bd9Sstevel@tonic-gate return (0); /* not IP */
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate base = udp + sizeof (struct udphdr);
7987c478bd9Sstevel@tonic-gate if (base > pkt + len) {
7997c478bd9Sstevel@tonic-gate return (0);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate break;
8027c478bd9Sstevel@tonic-gate case OP_OFFSET_RPC:
8037c478bd9Sstevel@tonic-gate if (offp >= &offstack[MAXSS])
8047c478bd9Sstevel@tonic-gate return (0);
8057c478bd9Sstevel@tonic-gate *++offp = base;
8067c478bd9Sstevel@tonic-gate ip = pkt + header_size;
8077c478bd9Sstevel@tonic-gate rpc = NULL;
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate if (IP_VERS(ip) != IPV4_VERSION &&
8107c478bd9Sstevel@tonic-gate IP_VERS(ip) != IPV6_VERSION) {
8117c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8127c478bd9Sstevel@tonic-gate return (0);
8137c478bd9Sstevel@tonic-gate *(++sp) = 0;
8147c478bd9Sstevel@tonic-gate break;
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate switch (ip_proto_of(ip)) {
8187c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
8197c478bd9Sstevel@tonic-gate udp = ip + ip_hdr_len(ip);
8207c478bd9Sstevel@tonic-gate rpc = (struct rpc_msg *)(udp +
8217c478bd9Sstevel@tonic-gate sizeof (struct udphdr));
8227c478bd9Sstevel@tonic-gate break;
8237c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
8247c478bd9Sstevel@tonic-gate tcp = ip + ip_hdr_len(ip);
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate * Need to skip an extra 4 for the xdr_rec
8277c478bd9Sstevel@tonic-gate * field.
8287c478bd9Sstevel@tonic-gate */
8297c478bd9Sstevel@tonic-gate rpc = (struct rpc_msg *)(tcp +
8307c478bd9Sstevel@tonic-gate TCP_HDR_LEN(tcp) + 4);
8317c478bd9Sstevel@tonic-gate break;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate * We need to have at least 24 bytes of a RPC
8357c478bd9Sstevel@tonic-gate * packet to look at to determine the validity
8367c478bd9Sstevel@tonic-gate * of it.
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate if (rpc == NULL || (uchar_t *)rpc + 24 > pkt + len) {
8397c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8407c478bd9Sstevel@tonic-gate return (0);
8417c478bd9Sstevel@tonic-gate *(++sp) = 0;
8427c478bd9Sstevel@tonic-gate break;
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate /* align */
8457c478bd9Sstevel@tonic-gate (void) memcpy(&rpcmsg, rpc, 24);
8462b24ab6bSSebastien Roy if (!valid_rpc((char *)&rpcmsg, 24)) {
8477c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8487c478bd9Sstevel@tonic-gate return (0);
8497c478bd9Sstevel@tonic-gate *(++sp) = 0;
8507c478bd9Sstevel@tonic-gate break;
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate if (ntohl(rpcmsg.rm_direction) == CALL) {
8537c478bd9Sstevel@tonic-gate base = (uchar_t *)rpc;
8547c478bd9Sstevel@tonic-gate newrpc = 1;
8557c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8567c478bd9Sstevel@tonic-gate return (0);
8577c478bd9Sstevel@tonic-gate *(++sp) = 1;
8587c478bd9Sstevel@tonic-gate } else {
8597c478bd9Sstevel@tonic-gate opkt = pkt;
8607c478bd9Sstevel@tonic-gate olen = len;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate pkt = base = (uchar_t *)find_rpc(&rpcmsg);
8637c478bd9Sstevel@tonic-gate len = sizeof (struct xid_entry);
8647c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8657c478bd9Sstevel@tonic-gate return (0);
8667c478bd9Sstevel@tonic-gate *(++sp) = base != NULL;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate break;
8697c478bd9Sstevel@tonic-gate case OP_OFFSET_SLP:
8707c478bd9Sstevel@tonic-gate slphdr = NULL;
8717c478bd9Sstevel@tonic-gate ip = pkt + header_size;
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate if (IP_VERS(ip) != IPV4_VERSION &&
8747c478bd9Sstevel@tonic-gate IP_VERS(ip) != IPV6_VERSION) {
8757c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
8767c478bd9Sstevel@tonic-gate return (0);
8777c478bd9Sstevel@tonic-gate *(++sp) = 0;
8787c478bd9Sstevel@tonic-gate break;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate switch (ip_proto_of(ip)) {
8827c478bd9Sstevel@tonic-gate struct udphdr udp_h;
8837c478bd9Sstevel@tonic-gate struct tcphdr tcp_h;
8847c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
8857c478bd9Sstevel@tonic-gate udp = ip + ip_hdr_len(ip);
8867c478bd9Sstevel@tonic-gate /* align */
8877c478bd9Sstevel@tonic-gate memcpy(&udp_h, udp, sizeof (udp_h));
8887c478bd9Sstevel@tonic-gate slp_sport = ntohs(udp_h.uh_sport);
8897c478bd9Sstevel@tonic-gate slp_dport = ntohs(udp_h.uh_dport);
8907c478bd9Sstevel@tonic-gate slphdr = udp + sizeof (struct udphdr);
8917c478bd9Sstevel@tonic-gate break;
8927c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
8937c478bd9Sstevel@tonic-gate tcp = ip + ip_hdr_len(ip);
8947c478bd9Sstevel@tonic-gate /* align */
8957c478bd9Sstevel@tonic-gate memcpy(&tcp_h, tcp, sizeof (tcp_h));
8967c478bd9Sstevel@tonic-gate slp_sport = ntohs(tcp_h.th_sport);
8977c478bd9Sstevel@tonic-gate slp_dport = ntohs(tcp_h.th_dport);
8987c478bd9Sstevel@tonic-gate slphdr = tcp + TCP_HDR_LEN(tcp);
8997c478bd9Sstevel@tonic-gate break;
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate if (slphdr == NULL || slphdr > pkt + len) {
9027c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
9037c478bd9Sstevel@tonic-gate return (0);
9047c478bd9Sstevel@tonic-gate *(++sp) = 0;
9057c478bd9Sstevel@tonic-gate break;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate if (slp_sport == 427 || slp_dport == 427) {
9087c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
9097c478bd9Sstevel@tonic-gate return (0);
9107c478bd9Sstevel@tonic-gate *(++sp) = 1;
9117c478bd9Sstevel@tonic-gate if (slp_sport != 427 && slp_dport == 427)
9127c478bd9Sstevel@tonic-gate stash_slp(slp_sport);
9137c478bd9Sstevel@tonic-gate break;
9147c478bd9Sstevel@tonic-gate } else if (find_slp(slp_dport) != -1) {
9157c478bd9Sstevel@tonic-gate if (valid_slp(slphdr, len)) {
9167c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
9177c478bd9Sstevel@tonic-gate return (0);
9187c478bd9Sstevel@tonic-gate *(++sp) = 1;
9197c478bd9Sstevel@tonic-gate break;
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate /* else fallthrough to reject */
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate if (sp >= &stack[MAXSS])
9247c478bd9Sstevel@tonic-gate return (0);
9257c478bd9Sstevel@tonic-gate *(++sp) = 0;
9267c478bd9Sstevel@tonic-gate break;
927605445d5Sdg case OP_OFFSET_ETHERTYPE:
928605445d5Sdg /*
929b127ac41SPhilip Kirk * Set base to the location of the ethertype as
930b127ac41SPhilip Kirk * appropriate for this link type. Note that it's
931b127ac41SPhilip Kirk * not called "ethertype" for every link type, but
932b127ac41SPhilip Kirk * we need to call it something.
933605445d5Sdg */
934605445d5Sdg if (offp >= &offstack[MAXSS])
935605445d5Sdg return (0);
936605445d5Sdg *++offp = base;
937605445d5Sdg base = pkt + interface->network_type_offset;
938605445d5Sdg
939605445d5Sdg /*
940b127ac41SPhilip Kirk * Below, we adjust the offset for unusual
941b127ac41SPhilip Kirk * link-layer headers that may have the protocol
942b127ac41SPhilip Kirk * type in a variable location beyond what was set
943b127ac41SPhilip Kirk * above.
944605445d5Sdg */
945b127ac41SPhilip Kirk switch (interface->mac_type) {
946b127ac41SPhilip Kirk case DL_ETHER:
947b127ac41SPhilip Kirk case DL_CSMACD:
948b127ac41SPhilip Kirk /*
949b127ac41SPhilip Kirk * If this is a VLAN-tagged packet, we need
950b127ac41SPhilip Kirk * to point to the ethertype field in the
951b127ac41SPhilip Kirk * VLAN header. Move past the ethertype
952b127ac41SPhilip Kirk * field in the ethernet header.
953b127ac41SPhilip Kirk */
954b127ac41SPhilip Kirk if (ntohs(get_u16(base)) == ETHERTYPE_VLAN)
955605445d5Sdg base += (ENCAP_ETHERTYPE_OFF);
956b127ac41SPhilip Kirk break;
957b127ac41SPhilip Kirk }
958b127ac41SPhilip Kirk if (base > pkt + len) {
959b127ac41SPhilip Kirk /* Went too far, drop the packet */
960b127ac41SPhilip Kirk return (0);
961605445d5Sdg }
962605445d5Sdg break;
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate if (*sp && newrpc)
9677c478bd9Sstevel@tonic-gate stash_rpc(&rpcmsg);
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate return (*sp);
9707c478bd9Sstevel@tonic-gate }
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate static void
load_const(uint_t constval)9737c478bd9Sstevel@tonic-gate load_const(uint_t constval)
9747c478bd9Sstevel@tonic-gate {
9757c478bd9Sstevel@tonic-gate emitop(OP_LOAD_CONST);
9767c478bd9Sstevel@tonic-gate emitval(constval);
9777c478bd9Sstevel@tonic-gate }
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate static void
load_value(int offset,int len)9807c478bd9Sstevel@tonic-gate load_value(int offset, int len)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate if (offset >= 0)
9837c478bd9Sstevel@tonic-gate load_const(offset);
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate switch (len) {
9867c478bd9Sstevel@tonic-gate case 1:
9877c478bd9Sstevel@tonic-gate emitop(OP_LOAD_OCTET);
9887c478bd9Sstevel@tonic-gate break;
9897c478bd9Sstevel@tonic-gate case 2:
9907c478bd9Sstevel@tonic-gate emitop(OP_LOAD_SHORT);
9917c478bd9Sstevel@tonic-gate break;
9927c478bd9Sstevel@tonic-gate case 4:
9937c478bd9Sstevel@tonic-gate emitop(OP_LOAD_LONG);
9947c478bd9Sstevel@tonic-gate break;
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate * Emit code to compare a field in
10007c478bd9Sstevel@tonic-gate * the packet against a constant value.
10017c478bd9Sstevel@tonic-gate */
10027c478bd9Sstevel@tonic-gate static void
compare_value(uint_t offset,uint_t len,uint_t val)10037c478bd9Sstevel@tonic-gate compare_value(uint_t offset, uint_t len, uint_t val)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate load_const(val);
10067c478bd9Sstevel@tonic-gate load_value(offset, len);
10077c478bd9Sstevel@tonic-gate emitop(OP_EQ);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate static void
compare_addr_v4(uint_t offset,uint_t len,uint_t val)10117c478bd9Sstevel@tonic-gate compare_addr_v4(uint_t offset, uint_t len, uint_t val)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate load_const(ntohl(val));
10147c478bd9Sstevel@tonic-gate load_value(offset, len);
10157c478bd9Sstevel@tonic-gate emitop(OP_EQ);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate static void
compare_addr_v6(uint_t offset,uint_t len,struct in6_addr val)10197c478bd9Sstevel@tonic-gate compare_addr_v6(uint_t offset, uint_t len, struct in6_addr val)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate int i;
10227c478bd9Sstevel@tonic-gate uint32_t value;
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate for (i = 0; i < len; i += 4) {
10257c478bd9Sstevel@tonic-gate value = ntohl(*(uint32_t *)&val.s6_addr[i]);
10267c478bd9Sstevel@tonic-gate load_const(value);
10277c478bd9Sstevel@tonic-gate load_value(offset + i, 4);
10287c478bd9Sstevel@tonic-gate emitop(OP_EQ);
10297c478bd9Sstevel@tonic-gate if (i != 0)
10307c478bd9Sstevel@tonic-gate emitop(OP_AND);
10317c478bd9Sstevel@tonic-gate }
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate * Same as above except do the comparison
10367c478bd9Sstevel@tonic-gate * after and'ing a mask value. Useful
10377c478bd9Sstevel@tonic-gate * for comparing IP network numbers
10387c478bd9Sstevel@tonic-gate */
10397c478bd9Sstevel@tonic-gate static void
compare_value_mask(uint_t offset,uint_t len,uint_t val,int mask)10407c478bd9Sstevel@tonic-gate compare_value_mask(uint_t offset, uint_t len, uint_t val, int mask)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate load_value(offset, len);
10437c478bd9Sstevel@tonic-gate load_const(mask);
10447c478bd9Sstevel@tonic-gate emitop(OP_AND);
10457c478bd9Sstevel@tonic-gate load_const(val);
10467c478bd9Sstevel@tonic-gate emitop(OP_EQ);
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate
1049b127ac41SPhilip Kirk /*
1050b127ac41SPhilip Kirk * Compare two zoneid's. The arg val passed in is stored in network
1051b127ac41SPhilip Kirk * byte order.
1052b127ac41SPhilip Kirk */
1053b127ac41SPhilip Kirk static void
compare_value_zone(uint_t offset,uint32_t val)10540a0e9771SDarren Reed compare_value_zone(uint_t offset, uint32_t val)
1055b127ac41SPhilip Kirk {
10567d897698SMilan Jurik load_const(ntohl(val));
10577d897698SMilan Jurik load_value(offset, 4);
10580a0e9771SDarren Reed emitop(OP_EQ);
1059b127ac41SPhilip Kirk }
1060b127ac41SPhilip Kirk
10617c478bd9Sstevel@tonic-gate /* Emit an operator into the code array */
10627c478bd9Sstevel@tonic-gate static void
emitop(enum optype opcode)10637c478bd9Sstevel@tonic-gate emitop(enum optype opcode)
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate if (curr_op >= &oplist[MAXOPS])
10667c478bd9Sstevel@tonic-gate pr_err("expression too long");
10677c478bd9Sstevel@tonic-gate *curr_op++ = opcode;
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate * Remove n operators recently emitted into
10727c478bd9Sstevel@tonic-gate * the code array. Used by alternation().
10737c478bd9Sstevel@tonic-gate */
10747c478bd9Sstevel@tonic-gate static void
unemit(int numops)10757c478bd9Sstevel@tonic-gate unemit(int numops)
10767c478bd9Sstevel@tonic-gate {
10777c478bd9Sstevel@tonic-gate curr_op -= numops;
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate /*
10827c478bd9Sstevel@tonic-gate * Same as emitop except that we're emitting
10837c478bd9Sstevel@tonic-gate * a value that's not an operator.
10847c478bd9Sstevel@tonic-gate */
10857c478bd9Sstevel@tonic-gate static void
emitval(uint_t val)10867c478bd9Sstevel@tonic-gate emitval(uint_t val)
10877c478bd9Sstevel@tonic-gate {
10887c478bd9Sstevel@tonic-gate if (curr_op >= &oplist[MAXOPS])
10897c478bd9Sstevel@tonic-gate pr_err("expression too long");
10907c478bd9Sstevel@tonic-gate *curr_op++ = val;
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate /*
10947c478bd9Sstevel@tonic-gate * Used to chain forward branches together
10957c478bd9Sstevel@tonic-gate * for later resolution by resolve_chain().
10967c478bd9Sstevel@tonic-gate */
10977c478bd9Sstevel@tonic-gate static uint_t
chain(int p)10987c478bd9Sstevel@tonic-gate chain(int p)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate uint_t pos = curr_op - oplist;
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate emitval(p);
11037c478bd9Sstevel@tonic-gate return (pos);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate /*
11077c478bd9Sstevel@tonic-gate * Proceed backward through the code array
11087c478bd9Sstevel@tonic-gate * following a chain of forward references.
11097c478bd9Sstevel@tonic-gate * At each reference install the destination
11107c478bd9Sstevel@tonic-gate * branch offset.
11117c478bd9Sstevel@tonic-gate */
11127c478bd9Sstevel@tonic-gate static void
resolve_chain(uint_t p)11137c478bd9Sstevel@tonic-gate resolve_chain(uint_t p)
11147c478bd9Sstevel@tonic-gate {
11157c478bd9Sstevel@tonic-gate uint_t n;
11167c478bd9Sstevel@tonic-gate uint_t pos = curr_op - oplist;
11177c478bd9Sstevel@tonic-gate
11187c478bd9Sstevel@tonic-gate while (p) {
11197c478bd9Sstevel@tonic-gate n = oplist[p];
11207c478bd9Sstevel@tonic-gate oplist[p] = pos;
11217c478bd9Sstevel@tonic-gate p = n;
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate #define EQ(val) (strcmp(token, val) == 0)
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate char *tkp, *sav_tkp;
11287c478bd9Sstevel@tonic-gate char *token;
1129*cd93bdd3SToomas Soome enum tokentype tokentype;
11307c478bd9Sstevel@tonic-gate uint_t tokenval;
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate * This is the scanner. Each call returns the next
11347c478bd9Sstevel@tonic-gate * token in the filter expression. A token is either:
11357c478bd9Sstevel@tonic-gate * EOL: The end of the line - no more tokens.
11367c478bd9Sstevel@tonic-gate * ALPHA: A name that begins with a letter and contains
11377c478bd9Sstevel@tonic-gate * letters or digits, hyphens or underscores.
11387c478bd9Sstevel@tonic-gate * NUMBER: A number. The value can be represented as
1139*cd93bdd3SToomas Soome * a decimal value (1234) or an octal value
11407c478bd9Sstevel@tonic-gate * that begins with zero (066) or a hex value
11417c478bd9Sstevel@tonic-gate * that begins with 0x or 0X (0xff).
11427c478bd9Sstevel@tonic-gate * FIELD: A name followed by a left square bracket.
11437c478bd9Sstevel@tonic-gate * ADDR_IP: An IP address. Any sequence of digits
11447c478bd9Sstevel@tonic-gate * separated by dots e.g. 109.104.40.13
11457c478bd9Sstevel@tonic-gate * ADDR_ETHER: An ethernet address. Any sequence of hex
11467c478bd9Sstevel@tonic-gate * digits separated by colons e.g. 8:0:20:0:76:39
11477c478bd9Sstevel@tonic-gate * SPECIAL: A special character e.g. ">" or "(". The scanner
11487c478bd9Sstevel@tonic-gate * correctly handles digraphs - two special characters
11497c478bd9Sstevel@tonic-gate * that constitute a single token e.g. "==" or ">=".
11507c478bd9Sstevel@tonic-gate * ADDR_IP6: An IPv6 address.
11517c478bd9Sstevel@tonic-gate *
11527c478bd9Sstevel@tonic-gate * ADDR_AT: An AppleTalk Phase II address. A sequence of two numbers
11537c478bd9Sstevel@tonic-gate * separated by a dot.
11547c478bd9Sstevel@tonic-gate *
11557c478bd9Sstevel@tonic-gate * The current token is maintained in "token" and and its
11567c478bd9Sstevel@tonic-gate * type in "tokentype". If tokentype is NUMBER then the
11577c478bd9Sstevel@tonic-gate * value is held in "tokenval".
11587c478bd9Sstevel@tonic-gate */
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate static const char *namechars =
11617c478bd9Sstevel@tonic-gate "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
11627c478bd9Sstevel@tonic-gate static const char *numchars = "0123456789abcdefABCDEFXx:.";
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gate void
next()11657c478bd9Sstevel@tonic-gate next()
11667c478bd9Sstevel@tonic-gate {
11677c478bd9Sstevel@tonic-gate static int savechar;
11687c478bd9Sstevel@tonic-gate char *p;
11697c478bd9Sstevel@tonic-gate int size, size1;
11707c478bd9Sstevel@tonic-gate int base, colons, dots, alphas, double_colon;
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate colons = 0;
11737c478bd9Sstevel@tonic-gate double_colon = 0;
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate if (*tkp == '\0') {
11767c478bd9Sstevel@tonic-gate token = tkp;
11777c478bd9Sstevel@tonic-gate *tkp = savechar;
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate sav_tkp = tkp;
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate while (isspace(*tkp)) tkp++;
11837c478bd9Sstevel@tonic-gate token = tkp;
11847c478bd9Sstevel@tonic-gate if (*token == '\0') {
11857c478bd9Sstevel@tonic-gate tokentype = EOL;
11867c478bd9Sstevel@tonic-gate return;
11877c478bd9Sstevel@tonic-gate }
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate /* A token containing ':' cannot be ALPHA type */
11907c478bd9Sstevel@tonic-gate tkp = token + strspn(token, numchars);
11917c478bd9Sstevel@tonic-gate for (p = token; p < tkp; p++) {
11927c478bd9Sstevel@tonic-gate if (*p == ':') {
11937c478bd9Sstevel@tonic-gate colons++;
11947c478bd9Sstevel@tonic-gate if (*(p+1) == ':')
11957c478bd9Sstevel@tonic-gate double_colon++;
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate tkp = token;
12007c478bd9Sstevel@tonic-gate if (isalpha(*tkp) && !colons) {
12017c478bd9Sstevel@tonic-gate tokentype = ALPHA;
12027c478bd9Sstevel@tonic-gate tkp += strspn(tkp, namechars);
12037c478bd9Sstevel@tonic-gate if (*tkp == '[') {
12047c478bd9Sstevel@tonic-gate tokentype = FIELD;
12057c478bd9Sstevel@tonic-gate *tkp++ = '\0';
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate } else
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate /*
12107c478bd9Sstevel@tonic-gate * RFC1123 states that host names may now start with digits. Need
12117c478bd9Sstevel@tonic-gate * to change parser to account for this. Also, need to distinguish
12127c478bd9Sstevel@tonic-gate * between 1.2.3.4 and 1.2.3.a where the first case is an IP address
12137c478bd9Sstevel@tonic-gate * and the second is a domain name. 333aaa needs to be distinguished
12147c478bd9Sstevel@tonic-gate * from 0x333aaa. The first is a host name and the second is a number.
12157c478bd9Sstevel@tonic-gate *
12167c478bd9Sstevel@tonic-gate * The (colons > 1) conditional differentiates between ethernet
12177c478bd9Sstevel@tonic-gate * and IPv6 addresses, and an expression of the form base[expr:size],
12187c478bd9Sstevel@tonic-gate * which can only contain one ':' character.
12197c478bd9Sstevel@tonic-gate */
12207c478bd9Sstevel@tonic-gate if (isdigit(*tkp) || colons > 1) {
12217c478bd9Sstevel@tonic-gate tkp = token + strspn(token, numchars);
12227c478bd9Sstevel@tonic-gate dots = alphas = 0;
12237c478bd9Sstevel@tonic-gate for (p = token; p < tkp; p++) {
12247c478bd9Sstevel@tonic-gate if (*p == '.')
12257c478bd9Sstevel@tonic-gate dots++;
12267c478bd9Sstevel@tonic-gate else if (isalpha(*p))
12277c478bd9Sstevel@tonic-gate alphas = 1;
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate if (colons > 1) {
12307c478bd9Sstevel@tonic-gate if (colons == 5 && double_colon == 0) {
12317c478bd9Sstevel@tonic-gate tokentype = ADDR_ETHER;
12327c478bd9Sstevel@tonic-gate } else {
12337c478bd9Sstevel@tonic-gate tokentype = ADDR_IP6;
12347c478bd9Sstevel@tonic-gate }
12357c478bd9Sstevel@tonic-gate } else if (dots) {
12367c478bd9Sstevel@tonic-gate size = tkp - token;
12377c478bd9Sstevel@tonic-gate size1 = strspn(token, "0123456789.");
12387c478bd9Sstevel@tonic-gate if (dots == 1 && size == size1) {
12397c478bd9Sstevel@tonic-gate tokentype = ADDR_AT;
12407c478bd9Sstevel@tonic-gate } else
12417c478bd9Sstevel@tonic-gate if (dots != 3 || size != size1) {
12427c478bd9Sstevel@tonic-gate tokentype = ALPHA;
12437c478bd9Sstevel@tonic-gate if (*tkp != '\0' && !isspace(*tkp)) {
12447c478bd9Sstevel@tonic-gate tkp += strspn(tkp, namechars);
12457c478bd9Sstevel@tonic-gate if (*tkp == '[') {
12467c478bd9Sstevel@tonic-gate tokentype = FIELD;
12477c478bd9Sstevel@tonic-gate *tkp++ = '\0';
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate } else
12517c478bd9Sstevel@tonic-gate tokentype = ADDR_IP;
12527c478bd9Sstevel@tonic-gate } else if (token + strspn(token, namechars) <= tkp) {
12537c478bd9Sstevel@tonic-gate /*
12547c478bd9Sstevel@tonic-gate * With the above check, if there are more
12557c478bd9Sstevel@tonic-gate * characters after the last digit, assume
12567c478bd9Sstevel@tonic-gate * that it is not a number.
12577c478bd9Sstevel@tonic-gate */
12587c478bd9Sstevel@tonic-gate tokentype = NUMBER;
12597c478bd9Sstevel@tonic-gate p = tkp;
12607c478bd9Sstevel@tonic-gate tkp = token;
12617c478bd9Sstevel@tonic-gate base = 10;
12627c478bd9Sstevel@tonic-gate if (*tkp == '0') {
12637c478bd9Sstevel@tonic-gate base = 8;
12647c478bd9Sstevel@tonic-gate tkp++;
12657c478bd9Sstevel@tonic-gate if (*tkp == 'x' || *tkp == 'X')
12667c478bd9Sstevel@tonic-gate base = 16;
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate if ((base == 10 || base == 8) && alphas) {
12697c478bd9Sstevel@tonic-gate tokentype = ALPHA;
12707c478bd9Sstevel@tonic-gate tkp = p;
12717c478bd9Sstevel@tonic-gate } else if (base == 16) {
12727c478bd9Sstevel@tonic-gate size = 2 + strspn(token+2,
1273b127ac41SPhilip Kirk "0123456789abcdefABCDEF");
12747c478bd9Sstevel@tonic-gate size1 = p - token;
12757c478bd9Sstevel@tonic-gate if (size != size1) {
12767c478bd9Sstevel@tonic-gate tokentype = ALPHA;
12777c478bd9Sstevel@tonic-gate tkp = p;
12787c478bd9Sstevel@tonic-gate } else
12797c478bd9Sstevel@tonic-gate /*
12807c478bd9Sstevel@tonic-gate * handles the case of 0x so an error message
12817c478bd9Sstevel@tonic-gate * is not printed. Treats 0x as 0.
12827c478bd9Sstevel@tonic-gate */
12837c478bd9Sstevel@tonic-gate if (size == 2) {
12847c478bd9Sstevel@tonic-gate tokenval = 0;
12857c478bd9Sstevel@tonic-gate tkp = token +2;
12867c478bd9Sstevel@tonic-gate } else {
12877c478bd9Sstevel@tonic-gate tokenval = strtoul(token, &tkp, base);
12887c478bd9Sstevel@tonic-gate }
12897c478bd9Sstevel@tonic-gate } else {
12907c478bd9Sstevel@tonic-gate tokenval = strtoul(token, &tkp, base);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate } else {
12937c478bd9Sstevel@tonic-gate tokentype = ALPHA;
12947c478bd9Sstevel@tonic-gate tkp += strspn(tkp, namechars);
12957c478bd9Sstevel@tonic-gate if (*tkp == '[') {
12967c478bd9Sstevel@tonic-gate tokentype = FIELD;
12977c478bd9Sstevel@tonic-gate *tkp++ = '\0';
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate } else {
13017c478bd9Sstevel@tonic-gate tokentype = SPECIAL;
13027c478bd9Sstevel@tonic-gate tkp++;
13037c478bd9Sstevel@tonic-gate if ((*token == '=' && *tkp == '=') ||
13047c478bd9Sstevel@tonic-gate (*token == '>' && *tkp == '=') ||
13057c478bd9Sstevel@tonic-gate (*token == '<' && *tkp == '=') ||
13067c478bd9Sstevel@tonic-gate (*token == '!' && *tkp == '='))
13077c478bd9Sstevel@tonic-gate tkp++;
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate
13107c478bd9Sstevel@tonic-gate savechar = *tkp;
13117c478bd9Sstevel@tonic-gate *tkp = '\0';
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate
1314b127ac41SPhilip Kirk typedef struct match_type {
13157c478bd9Sstevel@tonic-gate char *m_name;
13167c478bd9Sstevel@tonic-gate int m_offset;
13177c478bd9Sstevel@tonic-gate int m_size;
13187c478bd9Sstevel@tonic-gate int m_value;
13197c478bd9Sstevel@tonic-gate int m_depend;
13207c478bd9Sstevel@tonic-gate enum optype m_optype;
1321b127ac41SPhilip Kirk } match_type_t;
1322b127ac41SPhilip Kirk
1323b127ac41SPhilip Kirk static match_type_t ether_match_types[] = {
13247c478bd9Sstevel@tonic-gate /*
13257c478bd9Sstevel@tonic-gate * Table initialized assuming Ethernet data link headers.
1326605445d5Sdg * m_offset is an offset beyond the offset op, which is why
1327605445d5Sdg * the offset is zero for when snoop needs to check an ethertype.
13287c478bd9Sstevel@tonic-gate */
1329605445d5Sdg "ip", 0, 2, ETHERTYPE_IP, -1, OP_OFFSET_ETHERTYPE,
1330605445d5Sdg "ip6", 0, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ETHERTYPE,
1331605445d5Sdg "arp", 0, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ETHERTYPE,
1332605445d5Sdg "rarp", 0, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ETHERTYPE,
1333605445d5Sdg "pppoed", 0, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ETHERTYPE,
1334605445d5Sdg "pppoes", 0, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ETHERTYPE,
1335605445d5Sdg "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK,
1336605445d5Sdg "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK,
1337605445d5Sdg "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK,
1338605445d5Sdg "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK,
1339605445d5Sdg "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK,
1340605445d5Sdg "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK,
1341605445d5Sdg "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK,
1342605445d5Sdg "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK,
1343605445d5Sdg "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK,
1344605445d5Sdg "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK,
1345605445d5Sdg "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK,
1346605445d5Sdg "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK,
1347605445d5Sdg "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK,
1348605445d5Sdg "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK,
1349605445d5Sdg "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK,
1350605445d5Sdg 0, 0, 0, 0, 0, 0
13517c478bd9Sstevel@tonic-gate };
13527c478bd9Sstevel@tonic-gate
1353b127ac41SPhilip Kirk static match_type_t ipnet_match_types[] = {
1354b127ac41SPhilip Kirk /*
1355b127ac41SPhilip Kirk * Table initialized assuming Ethernet data link headers.
1356b127ac41SPhilip Kirk * m_offset is an offset beyond the offset op, which is why
1357b127ac41SPhilip Kirk * the offset is zero for when snoop needs to check an ethertype.
1358b127ac41SPhilip Kirk */
1359041bde0aSSebastien Roy "ip", 0, 1, IPV4_VERSION, -1, OP_OFFSET_ETHERTYPE,
1360041bde0aSSebastien Roy "ip6", 0, 1, IPV6_VERSION, -1, OP_OFFSET_ETHERTYPE,
1361b127ac41SPhilip Kirk "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK,
1362b127ac41SPhilip Kirk "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK,
1363b127ac41SPhilip Kirk "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK,
1364b127ac41SPhilip Kirk "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK,
1365b127ac41SPhilip Kirk "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK,
1366b127ac41SPhilip Kirk "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK,
1367b127ac41SPhilip Kirk "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK,
1368b127ac41SPhilip Kirk "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK,
1369b127ac41SPhilip Kirk "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK,
1370b127ac41SPhilip Kirk "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK,
1371b127ac41SPhilip Kirk "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK,
1372b127ac41SPhilip Kirk "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK,
1373b127ac41SPhilip Kirk "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK,
1374b127ac41SPhilip Kirk "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK,
1375b127ac41SPhilip Kirk "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK,
1376b127ac41SPhilip Kirk 0, 0, 0, 0, 0, 0
1377b127ac41SPhilip Kirk };
1378b127ac41SPhilip Kirk
13792b24ab6bSSebastien Roy static match_type_t iptun_match_types[] = {
13802b24ab6bSSebastien Roy "ip", 0, 1, IPPROTO_ENCAP, -1, OP_OFFSET_ETHERTYPE,
13812b24ab6bSSebastien Roy "ip6", 0, 1, IPPROTO_IPV6, -1, OP_OFFSET_ETHERTYPE,
13822b24ab6bSSebastien Roy "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK,
13832b24ab6bSSebastien Roy "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK,
13842b24ab6bSSebastien Roy "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK,
13852b24ab6bSSebastien Roy "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK,
13862b24ab6bSSebastien Roy "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK,
13872b24ab6bSSebastien Roy "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK,
13882b24ab6bSSebastien Roy "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK,
13892b24ab6bSSebastien Roy "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK,
13902b24ab6bSSebastien Roy "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK,
13912b24ab6bSSebastien Roy "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK,
13922b24ab6bSSebastien Roy "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK,
13932b24ab6bSSebastien Roy "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK,
13942b24ab6bSSebastien Roy "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK,
13952b24ab6bSSebastien Roy "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK,
13962b24ab6bSSebastien Roy "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK,
13972b24ab6bSSebastien Roy 0, 0, 0, 0, 0, 0
13982b24ab6bSSebastien Roy };
13992b24ab6bSSebastien Roy
14007c478bd9Sstevel@tonic-gate static void
generate_check(match_type_t match_types[],int index,int type)1401b127ac41SPhilip Kirk generate_check(match_type_t match_types[], int index, int type)
14027c478bd9Sstevel@tonic-gate {
1403b127ac41SPhilip Kirk match_type_t *mtp = &match_types[index];
14047c478bd9Sstevel@tonic-gate /*
14057c478bd9Sstevel@tonic-gate * Note: this code assumes the above dependencies are
14067c478bd9Sstevel@tonic-gate * not cyclic. This *should* always be true.
14077c478bd9Sstevel@tonic-gate */
14087c478bd9Sstevel@tonic-gate if (mtp->m_depend != -1)
1409b127ac41SPhilip Kirk generate_check(match_types, mtp->m_depend, type);
14107c478bd9Sstevel@tonic-gate
1411605445d5Sdg emitop(mtp->m_optype);
1412605445d5Sdg load_value(mtp->m_offset, mtp->m_size);
1413605445d5Sdg load_const(mtp->m_value);
1414605445d5Sdg emitop(OP_OFFSET_POP);
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate emitop(OP_EQ);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate if (mtp->m_depend != -1)
14197c478bd9Sstevel@tonic-gate emitop(OP_AND);
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate /*
14237c478bd9Sstevel@tonic-gate * Generate code based on the keyword argument.
14247c478bd9Sstevel@tonic-gate * This word is looked up in the match_types table
14257c478bd9Sstevel@tonic-gate * and checks a field within the packet for a given
14267c478bd9Sstevel@tonic-gate * value e.g. ether or ip type field. The match
14277c478bd9Sstevel@tonic-gate * can also have a dependency on another entry e.g.
14287c478bd9Sstevel@tonic-gate * "tcp" requires that the packet also be "ip".
14297c478bd9Sstevel@tonic-gate */
14307c478bd9Sstevel@tonic-gate static int
comparison(char * s)14317c478bd9Sstevel@tonic-gate comparison(char *s)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate unsigned int i, n_checks = 0;
1434b127ac41SPhilip Kirk match_type_t *match_types;
14357c478bd9Sstevel@tonic-gate
1436b127ac41SPhilip Kirk switch (interface->mac_type) {
1437b127ac41SPhilip Kirk case DL_ETHER:
1438b127ac41SPhilip Kirk match_types = ether_match_types;
1439b127ac41SPhilip Kirk break;
1440b127ac41SPhilip Kirk case DL_IPNET:
1441b127ac41SPhilip Kirk match_types = ipnet_match_types;
1442b127ac41SPhilip Kirk break;
14432b24ab6bSSebastien Roy case DL_IPV4:
14442b24ab6bSSebastien Roy case DL_IPV6:
14452b24ab6bSSebastien Roy case DL_6TO4:
14462b24ab6bSSebastien Roy match_types = iptun_match_types;
14472b24ab6bSSebastien Roy break;
1448b127ac41SPhilip Kirk default:
1449b127ac41SPhilip Kirk return (0);
1450b127ac41SPhilip Kirk }
14517c478bd9Sstevel@tonic-gate
1452b127ac41SPhilip Kirk for (i = 0; match_types[i].m_name != NULL; i++) {
14537c478bd9Sstevel@tonic-gate if (strcmp(s, match_types[i].m_name) != 0)
14547c478bd9Sstevel@tonic-gate continue;
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate n_checks++;
1457b127ac41SPhilip Kirk generate_check(match_types, i, interface->mac_type);
14587c478bd9Sstevel@tonic-gate if (n_checks > 1)
14597c478bd9Sstevel@tonic-gate emitop(OP_OR);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate return (n_checks > 0);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate enum direction dir;
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate /*
14687c478bd9Sstevel@tonic-gate * Generate code to match an IP address. The address
14697c478bd9Sstevel@tonic-gate * may be supplied either as a hostname or in dotted format.
14707c478bd9Sstevel@tonic-gate * For source packets both the IP source address and ARP
14717c478bd9Sstevel@tonic-gate * src are checked.
14727c478bd9Sstevel@tonic-gate * Note: we don't check packet type here - whether IP or ARP.
14737c478bd9Sstevel@tonic-gate * It's possible that we'll do an improper match.
14747c478bd9Sstevel@tonic-gate */
14757c478bd9Sstevel@tonic-gate static void
ipaddr_match(enum direction which,char * hostname,int inet_type)14767c478bd9Sstevel@tonic-gate ipaddr_match(enum direction which, char *hostname, int inet_type)
14777c478bd9Sstevel@tonic-gate {
14787c478bd9Sstevel@tonic-gate bool_t found_host;
14797c478bd9Sstevel@tonic-gate int m = 0, n = 0;
14807c478bd9Sstevel@tonic-gate uint_t *addr4ptr;
14817c478bd9Sstevel@tonic-gate uint_t addr4;
14827c478bd9Sstevel@tonic-gate struct in6_addr *addr6ptr;
14837c478bd9Sstevel@tonic-gate int h_addr_index;
14847c478bd9Sstevel@tonic-gate struct hostent *hp = NULL;
14857c478bd9Sstevel@tonic-gate int error_num = 0;
14867c478bd9Sstevel@tonic-gate boolean_t freehp = B_FALSE;
14877c478bd9Sstevel@tonic-gate boolean_t first = B_TRUE;
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate /*
14907c478bd9Sstevel@tonic-gate * The addr4offset and addr6offset variables simplify the code which
14917c478bd9Sstevel@tonic-gate * generates the address comparison filter. With these two variables,
14927c478bd9Sstevel@tonic-gate * duplicate code need not exist for the TO and FROM case.
14937c478bd9Sstevel@tonic-gate * A value of -1 describes the ANY case (TO and FROM).
14947c478bd9Sstevel@tonic-gate */
14957c478bd9Sstevel@tonic-gate int addr4offset;
14967c478bd9Sstevel@tonic-gate int addr6offset;
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate found_host = 0;
14997c478bd9Sstevel@tonic-gate
15007c478bd9Sstevel@tonic-gate if (tokentype == ADDR_IP) {
1501b127ac41SPhilip Kirk hp = lgetipnodebyname(hostname, AF_INET, 0, &error_num);
15027c478bd9Sstevel@tonic-gate if (hp == NULL) {
1503b127ac41SPhilip Kirk hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
15047c478bd9Sstevel@tonic-gate freehp = 1;
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate if (hp == NULL) {
15077c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
15087c478bd9Sstevel@tonic-gate pr_err("couldn't resolve %s (try again later)",
15097c478bd9Sstevel@tonic-gate hostname);
15107c478bd9Sstevel@tonic-gate } else {
15117c478bd9Sstevel@tonic-gate pr_err("couldn't resolve %s", hostname);
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate inet_type = IPV4_ONLY;
15157c478bd9Sstevel@tonic-gate } else if (tokentype == ADDR_IP6) {
1516b127ac41SPhilip Kirk hp = lgetipnodebyname(hostname, AF_INET6, 0, &error_num);
15177c478bd9Sstevel@tonic-gate if (hp == NULL) {
1518b127ac41SPhilip Kirk hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
15197c478bd9Sstevel@tonic-gate freehp = 1;
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate if (hp == NULL) {
15227c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
15237c478bd9Sstevel@tonic-gate pr_err("couldn't resolve %s (try again later)",
15247c478bd9Sstevel@tonic-gate hostname);
15257c478bd9Sstevel@tonic-gate } else {
15267c478bd9Sstevel@tonic-gate pr_err("couldn't resolve %s", hostname);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate inet_type = IPV6_ONLY;
15307c478bd9Sstevel@tonic-gate } else {
15317c478bd9Sstevel@tonic-gate /* Some hostname i.e. tokentype is ALPHA */
15327c478bd9Sstevel@tonic-gate switch (inet_type) {
15337c478bd9Sstevel@tonic-gate case IPV4_ONLY:
15347c478bd9Sstevel@tonic-gate /* Only IPv4 address is needed */
1535b127ac41SPhilip Kirk hp = lgetipnodebyname(hostname, AF_INET, 0, &error_num);
15367c478bd9Sstevel@tonic-gate if (hp == NULL) {
1537b127ac41SPhilip Kirk hp = getipnodebyname(hostname, AF_INET, 0,
1538b127ac41SPhilip Kirk &error_num);
15397c478bd9Sstevel@tonic-gate freehp = 1;
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate if (hp != NULL) {
15427c478bd9Sstevel@tonic-gate found_host = 1;
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate break;
15457c478bd9Sstevel@tonic-gate case IPV6_ONLY:
15467c478bd9Sstevel@tonic-gate /* Only IPv6 address is needed */
1547b127ac41SPhilip Kirk hp = lgetipnodebyname(hostname, AF_INET6, 0,
1548b127ac41SPhilip Kirk &error_num);
15497c478bd9Sstevel@tonic-gate if (hp == NULL) {
1550b127ac41SPhilip Kirk hp = getipnodebyname(hostname, AF_INET6, 0,
1551b127ac41SPhilip Kirk &error_num);
15527c478bd9Sstevel@tonic-gate freehp = 1;
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate if (hp != NULL) {
15557c478bd9Sstevel@tonic-gate found_host = 1;
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate break;
15587c478bd9Sstevel@tonic-gate case IPV4_AND_IPV6:
15597c478bd9Sstevel@tonic-gate /* Both IPv4 and IPv6 are needed */
15607c478bd9Sstevel@tonic-gate hp = lgetipnodebyname(hostname, AF_INET6,
1561b127ac41SPhilip Kirk AI_ALL | AI_V4MAPPED, &error_num);
15627c478bd9Sstevel@tonic-gate if (hp == NULL) {
15637c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6,
1564b127ac41SPhilip Kirk AI_ALL | AI_V4MAPPED, &error_num);
15657c478bd9Sstevel@tonic-gate freehp = 1;
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate if (hp != NULL) {
15687c478bd9Sstevel@tonic-gate found_host = 1;
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate break;
15717c478bd9Sstevel@tonic-gate default:
15727c478bd9Sstevel@tonic-gate found_host = 0;
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate if (!found_host) {
15767c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
15777c478bd9Sstevel@tonic-gate pr_err("could not resolve %s (try again later)",
15787c478bd9Sstevel@tonic-gate hostname);
15797c478bd9Sstevel@tonic-gate } else {
15807c478bd9Sstevel@tonic-gate pr_err("could not resolve %s", hostname);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate }
15847c478bd9Sstevel@tonic-gate
15857d897698SMilan Jurik if (hp == NULL)
15867d897698SMilan Jurik return;
15877d897698SMilan Jurik
15887c478bd9Sstevel@tonic-gate switch (which) {
15897c478bd9Sstevel@tonic-gate case TO:
15907c478bd9Sstevel@tonic-gate addr4offset = IPV4_DSTADDR_OFFSET;
15917c478bd9Sstevel@tonic-gate addr6offset = IPV6_DSTADDR_OFFSET;
15927c478bd9Sstevel@tonic-gate break;
15937c478bd9Sstevel@tonic-gate case FROM:
15947c478bd9Sstevel@tonic-gate addr4offset = IPV4_SRCADDR_OFFSET;
15957c478bd9Sstevel@tonic-gate addr6offset = IPV6_SRCADDR_OFFSET;
15967c478bd9Sstevel@tonic-gate break;
15977c478bd9Sstevel@tonic-gate case ANY:
15987c478bd9Sstevel@tonic-gate addr4offset = -1;
15997c478bd9Sstevel@tonic-gate addr6offset = -1;
16007c478bd9Sstevel@tonic-gate break;
16017c478bd9Sstevel@tonic-gate }
16027c478bd9Sstevel@tonic-gate
16037c478bd9Sstevel@tonic-gate /*
16047c478bd9Sstevel@tonic-gate * The code below generates the filter.
16057c478bd9Sstevel@tonic-gate */
16067d897698SMilan Jurik if (hp->h_addrtype == AF_INET) {
1607b127ac41SPhilip Kirk ethertype_match(interface->network_type_ip);
16087c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
16097c478bd9Sstevel@tonic-gate n = chain(n);
16107c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
16117c478bd9Sstevel@tonic-gate h_addr_index = 0;
16127c478bd9Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
16137c478bd9Sstevel@tonic-gate while (addr4ptr != NULL) {
16147c478bd9Sstevel@tonic-gate if (addr4offset == -1) {
16157c478bd9Sstevel@tonic-gate compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
16167c478bd9Sstevel@tonic-gate *addr4ptr);
16177c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16187c478bd9Sstevel@tonic-gate m = chain(m);
16197c478bd9Sstevel@tonic-gate compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
16207c478bd9Sstevel@tonic-gate *addr4ptr);
16217c478bd9Sstevel@tonic-gate } else {
16227c478bd9Sstevel@tonic-gate compare_addr_v4(addr4offset, 4, *addr4ptr);
16237c478bd9Sstevel@tonic-gate }
16247c478bd9Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
16257c478bd9Sstevel@tonic-gate if (addr4ptr != NULL) {
16267c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16277c478bd9Sstevel@tonic-gate m = chain(m);
16287c478bd9Sstevel@tonic-gate }
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate if (m != 0) {
16317c478bd9Sstevel@tonic-gate resolve_chain(m);
16327c478bd9Sstevel@tonic-gate }
16337c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
16347c478bd9Sstevel@tonic-gate resolve_chain(n);
16357c478bd9Sstevel@tonic-gate } else {
16367c478bd9Sstevel@tonic-gate /* first pass: IPv4 addresses */
16377c478bd9Sstevel@tonic-gate h_addr_index = 0;
16387c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
16397c478bd9Sstevel@tonic-gate first = B_TRUE;
16407c478bd9Sstevel@tonic-gate while (addr6ptr != NULL) {
16417c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
16427c478bd9Sstevel@tonic-gate if (first) {
1643b127ac41SPhilip Kirk ethertype_match(
1644b127ac41SPhilip Kirk interface->network_type_ip);
16457c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
16467c478bd9Sstevel@tonic-gate n = chain(n);
16477c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
16487c478bd9Sstevel@tonic-gate first = B_FALSE;
16497c478bd9Sstevel@tonic-gate } else {
16507c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16517c478bd9Sstevel@tonic-gate m = chain(m);
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(addr6ptr,
16547c478bd9Sstevel@tonic-gate (struct in_addr *)&addr4);
16557c478bd9Sstevel@tonic-gate if (addr4offset == -1) {
16567c478bd9Sstevel@tonic-gate compare_addr_v4(IPV4_SRCADDR_OFFSET, 4,
16577c478bd9Sstevel@tonic-gate addr4);
16587c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16597c478bd9Sstevel@tonic-gate m = chain(m);
16607c478bd9Sstevel@tonic-gate compare_addr_v4(IPV4_DSTADDR_OFFSET, 4,
16617c478bd9Sstevel@tonic-gate addr4);
16627c478bd9Sstevel@tonic-gate } else {
16637c478bd9Sstevel@tonic-gate compare_addr_v4(addr4offset, 4, addr4);
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate }
16667c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)
16677c478bd9Sstevel@tonic-gate hp->h_addr_list[++h_addr_index];
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate /* second pass: IPv6 addresses */
16707c478bd9Sstevel@tonic-gate h_addr_index = 0;
16717c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
16727c478bd9Sstevel@tonic-gate first = B_TRUE;
16737c478bd9Sstevel@tonic-gate while (addr6ptr != NULL) {
16747c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
16757c478bd9Sstevel@tonic-gate if (first) {
16767c478bd9Sstevel@tonic-gate /*
16777c478bd9Sstevel@tonic-gate * bypass check for IPv6 addresses
16787c478bd9Sstevel@tonic-gate * when we have an IPv4 packet
16797c478bd9Sstevel@tonic-gate */
16807c478bd9Sstevel@tonic-gate if (n != 0) {
16817c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16827c478bd9Sstevel@tonic-gate m = chain(m);
16837c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
16847c478bd9Sstevel@tonic-gate m = chain(m);
16857c478bd9Sstevel@tonic-gate resolve_chain(n);
16867c478bd9Sstevel@tonic-gate n = 0;
16877c478bd9Sstevel@tonic-gate }
1688b127ac41SPhilip Kirk ethertype_match(
1689b127ac41SPhilip Kirk interface->network_type_ipv6);
16907c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
16917c478bd9Sstevel@tonic-gate n = chain(n);
16927c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
16937c478bd9Sstevel@tonic-gate first = B_FALSE;
16947c478bd9Sstevel@tonic-gate } else {
16957c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
16967c478bd9Sstevel@tonic-gate m = chain(m);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate if (addr6offset == -1) {
16997c478bd9Sstevel@tonic-gate compare_addr_v6(IPV6_SRCADDR_OFFSET,
17007c478bd9Sstevel@tonic-gate 16, *addr6ptr);
17017c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
17027c478bd9Sstevel@tonic-gate m = chain(m);
17037c478bd9Sstevel@tonic-gate compare_addr_v6(IPV6_DSTADDR_OFFSET,
17047c478bd9Sstevel@tonic-gate 16, *addr6ptr);
17057c478bd9Sstevel@tonic-gate } else {
17067c478bd9Sstevel@tonic-gate compare_addr_v6(addr6offset, 16,
17077c478bd9Sstevel@tonic-gate *addr6ptr);
17087c478bd9Sstevel@tonic-gate }
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)
17117c478bd9Sstevel@tonic-gate hp->h_addr_list[++h_addr_index];
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate if (m != 0) {
17147c478bd9Sstevel@tonic-gate resolve_chain(m);
17157c478bd9Sstevel@tonic-gate }
17167c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
17177c478bd9Sstevel@tonic-gate resolve_chain(n);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate /* only free struct hostent returned by getipnodebyname() */
17217c478bd9Sstevel@tonic-gate if (freehp) {
17227c478bd9Sstevel@tonic-gate freehostent(hp);
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate
1726b127ac41SPhilip Kirk /*
1727b127ac41SPhilip Kirk * Match on zoneid. The arg zone passed in is in network byte order.
1728b127ac41SPhilip Kirk */
1729b127ac41SPhilip Kirk static void
zone_match(enum direction which,uint32_t zone)17300a0e9771SDarren Reed zone_match(enum direction which, uint32_t zone)
1731b127ac41SPhilip Kirk {
1732b127ac41SPhilip Kirk
1733b127ac41SPhilip Kirk switch (which) {
1734b127ac41SPhilip Kirk case TO:
1735b127ac41SPhilip Kirk compare_value_zone(IPNET_DSTZONE_OFFSET, zone);
1736b127ac41SPhilip Kirk break;
1737b127ac41SPhilip Kirk case FROM:
1738b127ac41SPhilip Kirk compare_value_zone(IPNET_SRCZONE_OFFSET, zone);
1739b127ac41SPhilip Kirk break;
1740b127ac41SPhilip Kirk case ANY:
1741b127ac41SPhilip Kirk compare_value_zone(IPNET_SRCZONE_OFFSET, zone);
1742b127ac41SPhilip Kirk compare_value_zone(IPNET_DSTZONE_OFFSET, zone);
1743b127ac41SPhilip Kirk emitop(OP_OR);
1744b127ac41SPhilip Kirk }
1745b127ac41SPhilip Kirk }
1746b127ac41SPhilip Kirk
17477c478bd9Sstevel@tonic-gate /*
17487c478bd9Sstevel@tonic-gate * Generate code to match an AppleTalk address. The address
17497c478bd9Sstevel@tonic-gate * must be given as two numbers with a dot between
17507c478bd9Sstevel@tonic-gate *
17517c478bd9Sstevel@tonic-gate */
17527c478bd9Sstevel@tonic-gate static void
ataddr_match(enum direction which,char * hostname)17537c478bd9Sstevel@tonic-gate ataddr_match(enum direction which, char *hostname)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate uint_t net;
17567c478bd9Sstevel@tonic-gate uint_t node;
17577c478bd9Sstevel@tonic-gate uint_t m, n;
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate sscanf(hostname, "%u.%u", &net, &node);
17607c478bd9Sstevel@tonic-gate
17617c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
17627c478bd9Sstevel@tonic-gate switch (which) {
17637c478bd9Sstevel@tonic-gate case TO:
17647c478bd9Sstevel@tonic-gate compare_value(AT_DST_NET_OFFSET, 2, net);
17657c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
17667c478bd9Sstevel@tonic-gate m = chain(0);
17677c478bd9Sstevel@tonic-gate compare_value(AT_DST_NODE_OFFSET, 1, node);
17687c478bd9Sstevel@tonic-gate resolve_chain(m);
17697c478bd9Sstevel@tonic-gate break;
17707c478bd9Sstevel@tonic-gate case FROM:
17717c478bd9Sstevel@tonic-gate compare_value(AT_SRC_NET_OFFSET, 2, net);
17727c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
17737c478bd9Sstevel@tonic-gate m = chain(0);
17747c478bd9Sstevel@tonic-gate compare_value(AT_SRC_NODE_OFFSET, 1, node);
17757c478bd9Sstevel@tonic-gate resolve_chain(m);
17767c478bd9Sstevel@tonic-gate break;
17777c478bd9Sstevel@tonic-gate case ANY:
17787c478bd9Sstevel@tonic-gate compare_value(AT_DST_NET_OFFSET, 2, net);
17797c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
17807c478bd9Sstevel@tonic-gate m = chain(0);
17817c478bd9Sstevel@tonic-gate compare_value(AT_DST_NODE_OFFSET, 1, node);
17827c478bd9Sstevel@tonic-gate resolve_chain(m);
17837c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
17847c478bd9Sstevel@tonic-gate n = chain(0);
17857c478bd9Sstevel@tonic-gate compare_value(AT_SRC_NET_OFFSET, 2, net);
17867c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
17877c478bd9Sstevel@tonic-gate m = chain(0);
17887c478bd9Sstevel@tonic-gate compare_value(AT_SRC_NODE_OFFSET, 1, node);
17897c478bd9Sstevel@tonic-gate resolve_chain(m);
17907c478bd9Sstevel@tonic-gate resolve_chain(n);
17917c478bd9Sstevel@tonic-gate break;
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
17947c478bd9Sstevel@tonic-gate }
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate /*
17977c478bd9Sstevel@tonic-gate * Compare ethernet addresses. The address may
17987c478bd9Sstevel@tonic-gate * be provided either as a hostname or as a
17997c478bd9Sstevel@tonic-gate * 6 octet colon-separated address.
18007c478bd9Sstevel@tonic-gate */
18017c478bd9Sstevel@tonic-gate static void
etheraddr_match(enum direction which,char * hostname)18027c478bd9Sstevel@tonic-gate etheraddr_match(enum direction which, char *hostname)
18037c478bd9Sstevel@tonic-gate {
18047c478bd9Sstevel@tonic-gate uint_t addr;
18057c478bd9Sstevel@tonic-gate ushort_t *addrp;
18067c478bd9Sstevel@tonic-gate int to_offset, from_offset;
18077c478bd9Sstevel@tonic-gate struct ether_addr e, *ep = NULL;
18087c478bd9Sstevel@tonic-gate int m;
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate /*
18117c478bd9Sstevel@tonic-gate * First, check the interface type for whether src/dest address
18127c478bd9Sstevel@tonic-gate * is determinable; if not, retreat early.
18137c478bd9Sstevel@tonic-gate */
18147c478bd9Sstevel@tonic-gate switch (interface->mac_type) {
18157c478bd9Sstevel@tonic-gate case DL_ETHER:
18167c478bd9Sstevel@tonic-gate from_offset = ETHERADDRL;
18177c478bd9Sstevel@tonic-gate to_offset = 0;
18187c478bd9Sstevel@tonic-gate break;
18197c478bd9Sstevel@tonic-gate
18207c478bd9Sstevel@tonic-gate case DL_IB:
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate * If an ethernet address is attempted to be used
18237c478bd9Sstevel@tonic-gate * on an IPoIB interface, flag error. Link address
18247c478bd9Sstevel@tonic-gate * based filtering is unsupported on IPoIB, so there
18257c478bd9Sstevel@tonic-gate * is no ipibaddr_match() or parsing support for IPoIB
18267c478bd9Sstevel@tonic-gate * 20 byte link addresses.
18277c478bd9Sstevel@tonic-gate */
18287c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
18297c478bd9Sstevel@tonic-gate break;
18307c478bd9Sstevel@tonic-gate
18317c478bd9Sstevel@tonic-gate case DL_FDDI:
18327c478bd9Sstevel@tonic-gate from_offset = 7;
18337c478bd9Sstevel@tonic-gate to_offset = 1;
18347c478bd9Sstevel@tonic-gate break;
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate default:
18377c478bd9Sstevel@tonic-gate /*
18387c478bd9Sstevel@tonic-gate * Where do we find "ether" address for FDDI & TR?
18397c478bd9Sstevel@tonic-gate * XXX can improve? ~sparker
18407c478bd9Sstevel@tonic-gate */
18417c478bd9Sstevel@tonic-gate load_const(1);
18427c478bd9Sstevel@tonic-gate return;
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate
18457c478bd9Sstevel@tonic-gate if (isxdigit(*hostname))
18467c478bd9Sstevel@tonic-gate ep = ether_aton(hostname);
18477c478bd9Sstevel@tonic-gate if (ep == NULL) {
18487c478bd9Sstevel@tonic-gate if (ether_hostton(hostname, &e))
18497c478bd9Sstevel@tonic-gate if (!arp_for_ether(hostname, &e))
18507c478bd9Sstevel@tonic-gate pr_err("cannot obtain ether addr for %s",
1851b127ac41SPhilip Kirk hostname);
18527c478bd9Sstevel@tonic-gate ep = &e;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate memcpy(&addr, (ushort_t *)ep, 4);
18557c478bd9Sstevel@tonic-gate addrp = (ushort_t *)ep + 2;
18567c478bd9Sstevel@tonic-gate
1857605445d5Sdg emitop(OP_OFFSET_ZERO);
18587c478bd9Sstevel@tonic-gate switch (which) {
18597c478bd9Sstevel@tonic-gate case TO:
18607c478bd9Sstevel@tonic-gate compare_value(to_offset, 4, ntohl(addr));
18617c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
18627c478bd9Sstevel@tonic-gate m = chain(0);
18637c478bd9Sstevel@tonic-gate compare_value(to_offset + 4, 2, ntohs(*addrp));
18647c478bd9Sstevel@tonic-gate resolve_chain(m);
18657c478bd9Sstevel@tonic-gate break;
18667c478bd9Sstevel@tonic-gate case FROM:
18677c478bd9Sstevel@tonic-gate compare_value(from_offset, 4, ntohl(addr));
18687c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
18697c478bd9Sstevel@tonic-gate m = chain(0);
18707c478bd9Sstevel@tonic-gate compare_value(from_offset + 4, 2, ntohs(*addrp));
18717c478bd9Sstevel@tonic-gate resolve_chain(m);
18727c478bd9Sstevel@tonic-gate break;
18737c478bd9Sstevel@tonic-gate case ANY:
18747c478bd9Sstevel@tonic-gate compare_value(to_offset, 4, ntohl(addr));
18757c478bd9Sstevel@tonic-gate compare_value(to_offset + 4, 2, ntohs(*addrp));
18767c478bd9Sstevel@tonic-gate emitop(OP_AND);
18777c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
18787c478bd9Sstevel@tonic-gate m = chain(0);
18797c478bd9Sstevel@tonic-gate
18807c478bd9Sstevel@tonic-gate compare_value(from_offset, 4, ntohl(addr));
18817c478bd9Sstevel@tonic-gate compare_value(from_offset + 4, 2, ntohs(*addrp));
18827c478bd9Sstevel@tonic-gate emitop(OP_AND);
18837c478bd9Sstevel@tonic-gate resolve_chain(m);
18847c478bd9Sstevel@tonic-gate break;
18857c478bd9Sstevel@tonic-gate }
1886605445d5Sdg emitop(OP_OFFSET_POP);
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate
18897c478bd9Sstevel@tonic-gate static void
ethertype_match(int val)18907c478bd9Sstevel@tonic-gate ethertype_match(int val)
18917c478bd9Sstevel@tonic-gate {
1892605445d5Sdg int ether_offset = interface->network_type_offset;
18937c478bd9Sstevel@tonic-gate
1894605445d5Sdg /*
1895605445d5Sdg * If the user is interested in ethertype VLAN,
1896605445d5Sdg * then we need to set the offset to the beginning of the packet.
1897605445d5Sdg * But if the user is interested in another ethertype,
1898605445d5Sdg * such as IPv4, then we need to take into consideration
1899605445d5Sdg * the fact that the packet might be VLAN tagged.
1900605445d5Sdg */
1901605445d5Sdg if (interface->mac_type == DL_ETHER ||
1902605445d5Sdg interface->mac_type == DL_CSMACD) {
1903605445d5Sdg if (val != ETHERTYPE_VLAN) {
1904605445d5Sdg /*
1905605445d5Sdg * OP_OFFSET_ETHERTYPE puts us at the ethertype
1906605445d5Sdg * field whether or not there is a VLAN tag,
1907605445d5Sdg * so ether_offset goes to zero if we get here.
1908605445d5Sdg */
1909605445d5Sdg emitop(OP_OFFSET_ETHERTYPE);
1910605445d5Sdg ether_offset = 0;
1911605445d5Sdg } else {
1912605445d5Sdg emitop(OP_OFFSET_ZERO);
1913605445d5Sdg }
1914605445d5Sdg }
1915b127ac41SPhilip Kirk compare_value(ether_offset, interface->network_type_len, val);
1916605445d5Sdg if (interface->mac_type == DL_ETHER ||
1917605445d5Sdg interface->mac_type == DL_CSMACD) {
1918605445d5Sdg emitop(OP_OFFSET_POP);
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate }
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate /*
19237c478bd9Sstevel@tonic-gate * Match a network address. The host part
19247c478bd9Sstevel@tonic-gate * is masked out. The network address may
19257c478bd9Sstevel@tonic-gate * be supplied either as a netname or in
19267c478bd9Sstevel@tonic-gate * IP dotted format. The mask to be used
19277c478bd9Sstevel@tonic-gate * for the comparison is assumed from the
19287c478bd9Sstevel@tonic-gate * address format (see comment below).
19297c478bd9Sstevel@tonic-gate */
19307c478bd9Sstevel@tonic-gate static void
netaddr_match(enum direction which,char * netname)19317c478bd9Sstevel@tonic-gate netaddr_match(enum direction which, char *netname)
19327c478bd9Sstevel@tonic-gate {
19337c478bd9Sstevel@tonic-gate uint_t addr;
19347c478bd9Sstevel@tonic-gate uint_t mask = 0xff000000;
19357c478bd9Sstevel@tonic-gate uint_t m;
19367c478bd9Sstevel@tonic-gate struct netent *np;
19377c478bd9Sstevel@tonic-gate
19387c478bd9Sstevel@tonic-gate if (isdigit(*netname)) {
19397c478bd9Sstevel@tonic-gate addr = inet_network(netname);
19407c478bd9Sstevel@tonic-gate } else {
19417c478bd9Sstevel@tonic-gate np = getnetbyname(netname);
19427c478bd9Sstevel@tonic-gate if (np == NULL)
19437c478bd9Sstevel@tonic-gate pr_err("net %s not known", netname);
19447c478bd9Sstevel@tonic-gate addr = np->n_net;
19457c478bd9Sstevel@tonic-gate }
19467c478bd9Sstevel@tonic-gate
19477c478bd9Sstevel@tonic-gate /*
19487c478bd9Sstevel@tonic-gate * Left justify the address and figure
19497c478bd9Sstevel@tonic-gate * out a mask based on the supplied address.
19507c478bd9Sstevel@tonic-gate * Set the mask according to the number of zero
19517c478bd9Sstevel@tonic-gate * low-order bytes.
19527c478bd9Sstevel@tonic-gate * Note: this works only for whole octet masks.
19537c478bd9Sstevel@tonic-gate */
19547c478bd9Sstevel@tonic-gate if (addr) {
19557c478bd9Sstevel@tonic-gate while ((addr & ~mask) != 0) {
19567c478bd9Sstevel@tonic-gate mask |= (mask >> 8);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate }
19597c478bd9Sstevel@tonic-gate
19607c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
19617c478bd9Sstevel@tonic-gate switch (which) {
19627c478bd9Sstevel@tonic-gate case TO:
19637c478bd9Sstevel@tonic-gate compare_value_mask(16, 4, addr, mask);
19647c478bd9Sstevel@tonic-gate break;
19657c478bd9Sstevel@tonic-gate case FROM:
19667c478bd9Sstevel@tonic-gate compare_value_mask(12, 4, addr, mask);
19677c478bd9Sstevel@tonic-gate break;
19687c478bd9Sstevel@tonic-gate case ANY:
19697c478bd9Sstevel@tonic-gate compare_value_mask(12, 4, addr, mask);
19707c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
19717c478bd9Sstevel@tonic-gate m = chain(0);
19727c478bd9Sstevel@tonic-gate compare_value_mask(16, 4, addr, mask);
19737c478bd9Sstevel@tonic-gate resolve_chain(m);
19747c478bd9Sstevel@tonic-gate break;
19757c478bd9Sstevel@tonic-gate }
19767c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate * Match either a UDP or TCP port number.
19817c478bd9Sstevel@tonic-gate * The port number may be provided either as
19827c478bd9Sstevel@tonic-gate * port name as listed in /etc/services ("nntp") or as
19837c478bd9Sstevel@tonic-gate * the port number itself (2049).
19847c478bd9Sstevel@tonic-gate */
19857c478bd9Sstevel@tonic-gate static void
port_match(enum direction which,char * portname)19867c478bd9Sstevel@tonic-gate port_match(enum direction which, char *portname)
19877c478bd9Sstevel@tonic-gate {
19887c478bd9Sstevel@tonic-gate struct servent *sp;
19897c478bd9Sstevel@tonic-gate uint_t m, port;
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate if (isdigit(*portname)) {
19927c478bd9Sstevel@tonic-gate port = atoi(portname);
19937c478bd9Sstevel@tonic-gate } else {
19947c478bd9Sstevel@tonic-gate sp = getservbyname(portname, NULL);
19957c478bd9Sstevel@tonic-gate if (sp == NULL)
1996b127ac41SPhilip Kirk pr_err("invalid port number or name: %s", portname);
19977c478bd9Sstevel@tonic-gate port = ntohs(sp->s_port);
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_IP);
20017c478bd9Sstevel@tonic-gate
20027c478bd9Sstevel@tonic-gate switch (which) {
20037c478bd9Sstevel@tonic-gate case TO:
20047c478bd9Sstevel@tonic-gate compare_value(2, 2, port);
20057c478bd9Sstevel@tonic-gate break;
20067c478bd9Sstevel@tonic-gate case FROM:
20077c478bd9Sstevel@tonic-gate compare_value(0, 2, port);
20087c478bd9Sstevel@tonic-gate break;
20097c478bd9Sstevel@tonic-gate case ANY:
20107c478bd9Sstevel@tonic-gate compare_value(2, 2, port);
20117c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
20127c478bd9Sstevel@tonic-gate m = chain(0);
20137c478bd9Sstevel@tonic-gate compare_value(0, 2, port);
20147c478bd9Sstevel@tonic-gate resolve_chain(m);
20157c478bd9Sstevel@tonic-gate break;
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
20187c478bd9Sstevel@tonic-gate }
20197c478bd9Sstevel@tonic-gate
20207c478bd9Sstevel@tonic-gate /*
20217c478bd9Sstevel@tonic-gate * Generate code to match packets with a specific
20227c478bd9Sstevel@tonic-gate * RPC program number. If the progname is a name
20237c478bd9Sstevel@tonic-gate * it is converted to a number via /etc/rpc.
20247c478bd9Sstevel@tonic-gate * The program version and/or procedure may be provided
20257c478bd9Sstevel@tonic-gate * as extra qualifiers.
20267c478bd9Sstevel@tonic-gate */
20277c478bd9Sstevel@tonic-gate static void
rpc_match_prog(enum direction which,char * progname,int vers,int proc)20287c478bd9Sstevel@tonic-gate rpc_match_prog(enum direction which, char *progname, int vers, int proc)
20297c478bd9Sstevel@tonic-gate {
20307c478bd9Sstevel@tonic-gate struct rpcent *rpc;
20317c478bd9Sstevel@tonic-gate uint_t prog;
20327c478bd9Sstevel@tonic-gate uint_t m, n;
20337c478bd9Sstevel@tonic-gate
20347c478bd9Sstevel@tonic-gate if (isdigit(*progname)) {
20357c478bd9Sstevel@tonic-gate prog = atoi(progname);
20367c478bd9Sstevel@tonic-gate } else {
20377c478bd9Sstevel@tonic-gate rpc = (struct rpcent *)getrpcbyname(progname);
20387c478bd9Sstevel@tonic-gate if (rpc == NULL)
20397c478bd9Sstevel@tonic-gate pr_err("invalid program name: %s", progname);
20407c478bd9Sstevel@tonic-gate prog = rpc->r_number;
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_RPC);
20447c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20457c478bd9Sstevel@tonic-gate n = chain(0);
20467c478bd9Sstevel@tonic-gate
20477c478bd9Sstevel@tonic-gate compare_value(12, 4, prog);
20487c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20497c478bd9Sstevel@tonic-gate m = chain(0);
20507c478bd9Sstevel@tonic-gate if (vers >= 0) {
20517c478bd9Sstevel@tonic-gate compare_value(16, 4, vers);
20527c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20537c478bd9Sstevel@tonic-gate m = chain(m);
20547c478bd9Sstevel@tonic-gate }
20557c478bd9Sstevel@tonic-gate if (proc >= 0) {
20567c478bd9Sstevel@tonic-gate compare_value(20, 4, proc);
20577c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20587c478bd9Sstevel@tonic-gate m = chain(m);
20597c478bd9Sstevel@tonic-gate }
20607c478bd9Sstevel@tonic-gate
20617c478bd9Sstevel@tonic-gate switch (which) {
20627c478bd9Sstevel@tonic-gate case TO:
20637c478bd9Sstevel@tonic-gate compare_value(4, 4, CALL);
20647c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20657c478bd9Sstevel@tonic-gate m = chain(m);
20667c478bd9Sstevel@tonic-gate break;
20677c478bd9Sstevel@tonic-gate case FROM:
20687c478bd9Sstevel@tonic-gate compare_value(4, 4, REPLY);
20697c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
20707c478bd9Sstevel@tonic-gate m = chain(m);
20717c478bd9Sstevel@tonic-gate break;
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate resolve_chain(m);
20747c478bd9Sstevel@tonic-gate resolve_chain(n);
20757c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
20767c478bd9Sstevel@tonic-gate }
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate * Generate code to parse a field specification
20807c478bd9Sstevel@tonic-gate * and load the value of the field from the packet
20817c478bd9Sstevel@tonic-gate * onto the operand stack.
20827c478bd9Sstevel@tonic-gate * The field offset may be specified relative to the
20837c478bd9Sstevel@tonic-gate * beginning of the ether header, IP header, UDP header,
20847c478bd9Sstevel@tonic-gate * or TCP header. An optional size specification may
20857c478bd9Sstevel@tonic-gate * be provided following a colon. If no size is given
20867c478bd9Sstevel@tonic-gate * one byte is assumed e.g.
20877c478bd9Sstevel@tonic-gate *
20887c478bd9Sstevel@tonic-gate * ether[0] The first byte of the ether header
20897c478bd9Sstevel@tonic-gate * ip[2:2] The second 16 bit field of the IP header
20907c478bd9Sstevel@tonic-gate */
20917c478bd9Sstevel@tonic-gate static void
load_field()20927c478bd9Sstevel@tonic-gate load_field()
20937c478bd9Sstevel@tonic-gate {
20947c478bd9Sstevel@tonic-gate int size = 1;
20957c478bd9Sstevel@tonic-gate int s;
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate if (EQ("ether"))
20997c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_ZERO);
21007c478bd9Sstevel@tonic-gate else if (EQ("ip") || EQ("ip6") || EQ("pppoed") || EQ("pppoes"))
21017c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
21027c478bd9Sstevel@tonic-gate else if (EQ("udp") || EQ("tcp") || EQ("icmp") || EQ("ip-in-ip") ||
21037c478bd9Sstevel@tonic-gate EQ("ah") || EQ("esp"))
21047c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_IP);
21057c478bd9Sstevel@tonic-gate else
21067c478bd9Sstevel@tonic-gate pr_err("invalid field type");
21077c478bd9Sstevel@tonic-gate next();
21087c478bd9Sstevel@tonic-gate s = opstack;
21097c478bd9Sstevel@tonic-gate expression();
21107c478bd9Sstevel@tonic-gate if (opstack != s + 1)
21117c478bd9Sstevel@tonic-gate pr_err("invalid field offset");
21127c478bd9Sstevel@tonic-gate opstack--;
21137c478bd9Sstevel@tonic-gate if (*token == ':') {
21147c478bd9Sstevel@tonic-gate next();
21157c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
21167c478bd9Sstevel@tonic-gate pr_err("field size expected");
21177c478bd9Sstevel@tonic-gate size = tokenval;
21187c478bd9Sstevel@tonic-gate if (size != 1 && size != 2 && size != 4)
21197c478bd9Sstevel@tonic-gate pr_err("field size invalid");
21207c478bd9Sstevel@tonic-gate next();
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate if (*token != ']')
21237c478bd9Sstevel@tonic-gate pr_err("right bracket expected");
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate load_value(-1, size);
21267c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate
21297c478bd9Sstevel@tonic-gate /*
21307c478bd9Sstevel@tonic-gate * Check that the operand stack
21317c478bd9Sstevel@tonic-gate * contains n arguments
21327c478bd9Sstevel@tonic-gate */
21337c478bd9Sstevel@tonic-gate static void
checkstack(int numargs)21347c478bd9Sstevel@tonic-gate checkstack(int numargs)
21357c478bd9Sstevel@tonic-gate {
21367c478bd9Sstevel@tonic-gate if (opstack != numargs)
21377c478bd9Sstevel@tonic-gate pr_err("invalid expression at \"%s\".", token);
21387c478bd9Sstevel@tonic-gate }
21397c478bd9Sstevel@tonic-gate
21407c478bd9Sstevel@tonic-gate static void
primary()21417c478bd9Sstevel@tonic-gate primary()
21427c478bd9Sstevel@tonic-gate {
2143d04ccbb3Scarlsonj int m, m2, s;
21447c478bd9Sstevel@tonic-gate
21457c478bd9Sstevel@tonic-gate for (;;) {
21467c478bd9Sstevel@tonic-gate if (tokentype == FIELD) {
21477c478bd9Sstevel@tonic-gate load_field();
21487c478bd9Sstevel@tonic-gate opstack++;
21497c478bd9Sstevel@tonic-gate next();
21507c478bd9Sstevel@tonic-gate break;
21517c478bd9Sstevel@tonic-gate }
21527c478bd9Sstevel@tonic-gate
21537c478bd9Sstevel@tonic-gate if (comparison(token)) {
21547c478bd9Sstevel@tonic-gate opstack++;
21557c478bd9Sstevel@tonic-gate next();
21567c478bd9Sstevel@tonic-gate break;
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate if (EQ("not") || EQ("!")) {
21607c478bd9Sstevel@tonic-gate next();
21617c478bd9Sstevel@tonic-gate s = opstack;
21627c478bd9Sstevel@tonic-gate primary();
21637c478bd9Sstevel@tonic-gate checkstack(s + 1);
21647c478bd9Sstevel@tonic-gate emitop(OP_NOT);
21657c478bd9Sstevel@tonic-gate break;
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate if (EQ("(")) {
21697c478bd9Sstevel@tonic-gate next();
21707c478bd9Sstevel@tonic-gate s = opstack;
21717c478bd9Sstevel@tonic-gate expression();
21727c478bd9Sstevel@tonic-gate checkstack(s + 1);
21737c478bd9Sstevel@tonic-gate if (!EQ(")"))
21747c478bd9Sstevel@tonic-gate pr_err("right paren expected");
21757c478bd9Sstevel@tonic-gate next();
21767c478bd9Sstevel@tonic-gate }
21777c478bd9Sstevel@tonic-gate
21787c478bd9Sstevel@tonic-gate if (EQ("to") || EQ("dst")) {
21797c478bd9Sstevel@tonic-gate dir = TO;
21807c478bd9Sstevel@tonic-gate next();
21817c478bd9Sstevel@tonic-gate continue;
21827c478bd9Sstevel@tonic-gate }
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate if (EQ("from") || EQ("src")) {
21857c478bd9Sstevel@tonic-gate dir = FROM;
21867c478bd9Sstevel@tonic-gate next();
21877c478bd9Sstevel@tonic-gate continue;
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate
21907c478bd9Sstevel@tonic-gate if (EQ("ether")) {
21917c478bd9Sstevel@tonic-gate eaddr = 1;
21927c478bd9Sstevel@tonic-gate next();
21937c478bd9Sstevel@tonic-gate continue;
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate
21960990bc30Sdg if (EQ("proto")) {
21970990bc30Sdg next();
21980990bc30Sdg if (tokentype != NUMBER)
21990990bc30Sdg pr_err("IP proto type expected");
22000990bc30Sdg emitop(OP_OFFSET_LINK);
22010990bc30Sdg compare_value(IPV4_TYPE_HEADER_OFFSET, 1, tokenval);
22020990bc30Sdg emitop(OP_OFFSET_POP);
22030990bc30Sdg opstack++;
22047c478bd9Sstevel@tonic-gate next();
22057c478bd9Sstevel@tonic-gate continue;
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate
22087c478bd9Sstevel@tonic-gate if (EQ("broadcast")) {
22097c478bd9Sstevel@tonic-gate /*
22107c478bd9Sstevel@tonic-gate * Be tricky: FDDI ether dst address begins at
22117c478bd9Sstevel@tonic-gate * byte one. Since the address is really six
22127c478bd9Sstevel@tonic-gate * bytes long, this works for FDDI & ethernet.
22137c478bd9Sstevel@tonic-gate * XXX - Token ring?
22147c478bd9Sstevel@tonic-gate */
2215605445d5Sdg emitop(OP_OFFSET_ZERO);
22167c478bd9Sstevel@tonic-gate if (interface->mac_type == DL_IB)
22177c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
22187c478bd9Sstevel@tonic-gate compare_value(1, 4, 0xffffffff);
2219605445d5Sdg emitop(OP_OFFSET_POP);
22207c478bd9Sstevel@tonic-gate opstack++;
22217c478bd9Sstevel@tonic-gate next();
22227c478bd9Sstevel@tonic-gate break;
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate
22257c478bd9Sstevel@tonic-gate if (EQ("multicast")) {
22267c478bd9Sstevel@tonic-gate /* XXX Token ring? */
2227605445d5Sdg emitop(OP_OFFSET_ZERO);
22287c478bd9Sstevel@tonic-gate if (interface->mac_type == DL_FDDI) {
22297c478bd9Sstevel@tonic-gate compare_value_mask(1, 1, 0x01, 0x01);
22307c478bd9Sstevel@tonic-gate } else if (interface->mac_type == DL_IB) {
22317c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
22327c478bd9Sstevel@tonic-gate } else {
22337c478bd9Sstevel@tonic-gate compare_value_mask(0, 1, 0x01, 0x01);
22347c478bd9Sstevel@tonic-gate }
2235605445d5Sdg emitop(OP_OFFSET_POP);
22367c478bd9Sstevel@tonic-gate opstack++;
22377c478bd9Sstevel@tonic-gate next();
22387c478bd9Sstevel@tonic-gate break;
22397c478bd9Sstevel@tonic-gate }
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate if (EQ("decnet")) {
22427c478bd9Sstevel@tonic-gate /* XXX Token ring? */
22437c478bd9Sstevel@tonic-gate if (interface->mac_type == DL_FDDI) {
22447c478bd9Sstevel@tonic-gate load_value(19, 2); /* ether type */
22457c478bd9Sstevel@tonic-gate load_const(0x6000);
22467c478bd9Sstevel@tonic-gate emitop(OP_GE);
22477c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
22487c478bd9Sstevel@tonic-gate m = chain(0);
22497c478bd9Sstevel@tonic-gate load_value(19, 2); /* ether type */
22507c478bd9Sstevel@tonic-gate load_const(0x6009);
22517c478bd9Sstevel@tonic-gate emitop(OP_LE);
22527c478bd9Sstevel@tonic-gate resolve_chain(m);
22537c478bd9Sstevel@tonic-gate } else {
2254605445d5Sdg emitop(OP_OFFSET_ETHERTYPE);
2255605445d5Sdg load_value(0, 2); /* ether type */
22567c478bd9Sstevel@tonic-gate load_const(0x6000);
22577c478bd9Sstevel@tonic-gate emitop(OP_GE);
22587c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
22597c478bd9Sstevel@tonic-gate m = chain(0);
2260605445d5Sdg load_value(0, 2); /* ether type */
22617c478bd9Sstevel@tonic-gate load_const(0x6009);
22627c478bd9Sstevel@tonic-gate emitop(OP_LE);
22637c478bd9Sstevel@tonic-gate resolve_chain(m);
2264605445d5Sdg emitop(OP_OFFSET_POP);
22657c478bd9Sstevel@tonic-gate }
22667c478bd9Sstevel@tonic-gate opstack++;
22677c478bd9Sstevel@tonic-gate next();
22687c478bd9Sstevel@tonic-gate break;
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate
2271605445d5Sdg if (EQ("vlan-id")) {
2272605445d5Sdg next();
2273605445d5Sdg if (tokentype != NUMBER)
2274605445d5Sdg pr_err("vlan id expected");
2275605445d5Sdg emitop(OP_OFFSET_ZERO);
2276605445d5Sdg ethertype_match(ETHERTYPE_VLAN);
2277605445d5Sdg emitop(OP_BRFL);
2278605445d5Sdg m = chain(0);
2279605445d5Sdg compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
2280605445d5Sdg VLAN_ID_MASK);
2281605445d5Sdg resolve_chain(m);
2282605445d5Sdg emitop(OP_OFFSET_POP);
2283605445d5Sdg opstack++;
2284605445d5Sdg next();
2285605445d5Sdg break;
2286605445d5Sdg }
2287605445d5Sdg
22887c478bd9Sstevel@tonic-gate if (EQ("apple")) {
22897c478bd9Sstevel@tonic-gate /*
22907c478bd9Sstevel@tonic-gate * Appletalk also appears in 802.2
22917c478bd9Sstevel@tonic-gate * packets, so check for the ethertypes
22927c478bd9Sstevel@tonic-gate * at offset 12 and 20 in the MAC header.
22937c478bd9Sstevel@tonic-gate */
22947c478bd9Sstevel@tonic-gate ethertype_match(ETHERTYPE_AT);
22957c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
22967c478bd9Sstevel@tonic-gate m = chain(0);
22977c478bd9Sstevel@tonic-gate ethertype_match(ETHERTYPE_AARP);
22987c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
22997c478bd9Sstevel@tonic-gate m = chain(m);
23007c478bd9Sstevel@tonic-gate compare_value(20, 2, ETHERTYPE_AT); /* 802.2 */
23017c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
23027c478bd9Sstevel@tonic-gate m = chain(m);
23037c478bd9Sstevel@tonic-gate compare_value(20, 2, ETHERTYPE_AARP); /* 802.2 */
23047c478bd9Sstevel@tonic-gate resolve_chain(m);
23057c478bd9Sstevel@tonic-gate opstack++;
23067c478bd9Sstevel@tonic-gate next();
23077c478bd9Sstevel@tonic-gate break;
23087c478bd9Sstevel@tonic-gate }
23097c478bd9Sstevel@tonic-gate
2310605445d5Sdg if (EQ("vlan")) {
2311605445d5Sdg ethertype_match(ETHERTYPE_VLAN);
2312605445d5Sdg compare_value_mask(VLAN_ID_OFFSET, 2, 0, VLAN_ID_MASK);
2313605445d5Sdg emitop(OP_NOT);
2314605445d5Sdg emitop(OP_AND);
2315605445d5Sdg opstack++;
2316605445d5Sdg next();
2317605445d5Sdg break;
2318605445d5Sdg }
2319605445d5Sdg
23207c478bd9Sstevel@tonic-gate if (EQ("bootp") || EQ("dhcp")) {
2321b127ac41SPhilip Kirk ethertype_match(interface->network_type_ip);
2322d04ccbb3Scarlsonj emitop(OP_BRFL);
2323d04ccbb3Scarlsonj m = chain(0);
23247c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
2325d04ccbb3Scarlsonj compare_value(9, 1, IPPROTO_UDP);
2326d04ccbb3Scarlsonj emitop(OP_OFFSET_POP);
2327d04ccbb3Scarlsonj emitop(OP_BRFL);
2328d04ccbb3Scarlsonj m = chain(m);
23297c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_IP);
23307c478bd9Sstevel@tonic-gate compare_value(0, 4,
2331d04ccbb3Scarlsonj (IPPORT_BOOTPS << 16) | IPPORT_BOOTPC);
23327c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
2333d04ccbb3Scarlsonj m2 = chain(0);
23347c478bd9Sstevel@tonic-gate compare_value(0, 4,
2335d04ccbb3Scarlsonj (IPPORT_BOOTPC << 16) | IPPORT_BOOTPS);
2336d04ccbb3Scarlsonj resolve_chain(m2);
2337d04ccbb3Scarlsonj emitop(OP_OFFSET_POP);
23387c478bd9Sstevel@tonic-gate resolve_chain(m);
2339d04ccbb3Scarlsonj opstack++;
2340d04ccbb3Scarlsonj dir = ANY;
2341d04ccbb3Scarlsonj next();
2342d04ccbb3Scarlsonj break;
2343d04ccbb3Scarlsonj }
2344d04ccbb3Scarlsonj
2345d04ccbb3Scarlsonj if (EQ("dhcp6")) {
2346b127ac41SPhilip Kirk ethertype_match(interface->network_type_ipv6);
2347d04ccbb3Scarlsonj emitop(OP_BRFL);
2348d04ccbb3Scarlsonj m = chain(0);
2349d04ccbb3Scarlsonj emitop(OP_OFFSET_LINK);
2350d04ccbb3Scarlsonj compare_value(6, 1, IPPROTO_UDP);
2351605445d5Sdg emitop(OP_OFFSET_POP);
2352d04ccbb3Scarlsonj emitop(OP_BRFL);
2353d04ccbb3Scarlsonj m = chain(m);
2354d04ccbb3Scarlsonj emitop(OP_OFFSET_IP);
2355d04ccbb3Scarlsonj compare_value(2, 2, IPPORT_DHCPV6S);
2356d04ccbb3Scarlsonj emitop(OP_BRTR);
2357d04ccbb3Scarlsonj m2 = chain(0);
2358d04ccbb3Scarlsonj compare_value(2, 2, IPPORT_DHCPV6C);
2359d04ccbb3Scarlsonj resolve_chain(m2);
2360605445d5Sdg emitop(OP_OFFSET_POP);
2361d04ccbb3Scarlsonj resolve_chain(m);
23627c478bd9Sstevel@tonic-gate opstack++;
23637c478bd9Sstevel@tonic-gate dir = ANY;
23647c478bd9Sstevel@tonic-gate next();
23657c478bd9Sstevel@tonic-gate break;
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate
23687c478bd9Sstevel@tonic-gate if (EQ("ethertype")) {
23697c478bd9Sstevel@tonic-gate next();
23707c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
23717c478bd9Sstevel@tonic-gate pr_err("ether type expected");
23727c478bd9Sstevel@tonic-gate ethertype_match(tokenval);
23737c478bd9Sstevel@tonic-gate opstack++;
23747c478bd9Sstevel@tonic-gate next();
23757c478bd9Sstevel@tonic-gate break;
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate if (EQ("pppoe")) {
23797c478bd9Sstevel@tonic-gate ethertype_match(ETHERTYPE_PPPOED);
23807c478bd9Sstevel@tonic-gate ethertype_match(ETHERTYPE_PPPOES);
23817c478bd9Sstevel@tonic-gate emitop(OP_OR);
23827c478bd9Sstevel@tonic-gate opstack++;
23837c478bd9Sstevel@tonic-gate next();
23847c478bd9Sstevel@tonic-gate break;
23857c478bd9Sstevel@tonic-gate }
23867c478bd9Sstevel@tonic-gate
23877c478bd9Sstevel@tonic-gate if (EQ("inet")) {
23887c478bd9Sstevel@tonic-gate next();
23897c478bd9Sstevel@tonic-gate if (EQ("host"))
23907c478bd9Sstevel@tonic-gate next();
23917c478bd9Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP)
23927c478bd9Sstevel@tonic-gate pr_err("host/IPv4 addr expected after inet");
23937c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV4_ONLY);
23947c478bd9Sstevel@tonic-gate opstack++;
23957c478bd9Sstevel@tonic-gate next();
23967c478bd9Sstevel@tonic-gate break;
23977c478bd9Sstevel@tonic-gate }
23987c478bd9Sstevel@tonic-gate
23997c478bd9Sstevel@tonic-gate if (EQ("inet6")) {
24007c478bd9Sstevel@tonic-gate next();
24017c478bd9Sstevel@tonic-gate if (EQ("host"))
24027c478bd9Sstevel@tonic-gate next();
24037c478bd9Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP6)
24047c478bd9Sstevel@tonic-gate pr_err("host/IPv6 addr expected after inet6");
24057c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV6_ONLY);
24067c478bd9Sstevel@tonic-gate opstack++;
24077c478bd9Sstevel@tonic-gate next();
24087c478bd9Sstevel@tonic-gate break;
24097c478bd9Sstevel@tonic-gate }
24107c478bd9Sstevel@tonic-gate
24117c478bd9Sstevel@tonic-gate if (EQ("length")) {
24127c478bd9Sstevel@tonic-gate emitop(OP_LOAD_LENGTH);
24137c478bd9Sstevel@tonic-gate opstack++;
24147c478bd9Sstevel@tonic-gate next();
24157c478bd9Sstevel@tonic-gate break;
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate if (EQ("less")) {
24197c478bd9Sstevel@tonic-gate next();
24207c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
24217c478bd9Sstevel@tonic-gate pr_err("packet length expected");
24227c478bd9Sstevel@tonic-gate emitop(OP_LOAD_LENGTH);
24237c478bd9Sstevel@tonic-gate load_const(tokenval);
24247c478bd9Sstevel@tonic-gate emitop(OP_LT);
24257c478bd9Sstevel@tonic-gate opstack++;
24267c478bd9Sstevel@tonic-gate next();
24277c478bd9Sstevel@tonic-gate break;
24287c478bd9Sstevel@tonic-gate }
24297c478bd9Sstevel@tonic-gate
24307c478bd9Sstevel@tonic-gate if (EQ("greater")) {
24317c478bd9Sstevel@tonic-gate next();
24327c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
24337c478bd9Sstevel@tonic-gate pr_err("packet length expected");
24347c478bd9Sstevel@tonic-gate emitop(OP_LOAD_LENGTH);
24357c478bd9Sstevel@tonic-gate load_const(tokenval);
24367c478bd9Sstevel@tonic-gate emitop(OP_GT);
24377c478bd9Sstevel@tonic-gate opstack++;
24387c478bd9Sstevel@tonic-gate next();
24397c478bd9Sstevel@tonic-gate break;
24407c478bd9Sstevel@tonic-gate }
24417c478bd9Sstevel@tonic-gate
24427c478bd9Sstevel@tonic-gate if (EQ("nofrag")) {
24437c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_LINK);
24447c478bd9Sstevel@tonic-gate compare_value_mask(6, 2, 0, 0x1fff);
24457c478bd9Sstevel@tonic-gate emitop(OP_OFFSET_POP);
24467c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
24477c478bd9Sstevel@tonic-gate m = chain(0);
2448b127ac41SPhilip Kirk ethertype_match(interface->network_type_ip);
24497c478bd9Sstevel@tonic-gate resolve_chain(m);
24507c478bd9Sstevel@tonic-gate opstack++;
24517c478bd9Sstevel@tonic-gate next();
24527c478bd9Sstevel@tonic-gate break;
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate
24557c478bd9Sstevel@tonic-gate if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
24567c478bd9Sstevel@tonic-gate if (EQ("dstnet"))
24577c478bd9Sstevel@tonic-gate dir = TO;
24587c478bd9Sstevel@tonic-gate else if (EQ("srcnet"))
24597c478bd9Sstevel@tonic-gate dir = FROM;
24607c478bd9Sstevel@tonic-gate next();
24617c478bd9Sstevel@tonic-gate netaddr_match(dir, token);
24627c478bd9Sstevel@tonic-gate dir = ANY;
24637c478bd9Sstevel@tonic-gate opstack++;
24647c478bd9Sstevel@tonic-gate next();
24657c478bd9Sstevel@tonic-gate break;
24667c478bd9Sstevel@tonic-gate }
24677c478bd9Sstevel@tonic-gate
24687c478bd9Sstevel@tonic-gate if (EQ("port") || EQ("srcport") || EQ("dstport")) {
24697c478bd9Sstevel@tonic-gate if (EQ("dstport"))
24707c478bd9Sstevel@tonic-gate dir = TO;
24717c478bd9Sstevel@tonic-gate else if (EQ("srcport"))
24727c478bd9Sstevel@tonic-gate dir = FROM;
24737c478bd9Sstevel@tonic-gate next();
24747c478bd9Sstevel@tonic-gate port_match(dir, token);
24757c478bd9Sstevel@tonic-gate dir = ANY;
24767c478bd9Sstevel@tonic-gate opstack++;
24777c478bd9Sstevel@tonic-gate next();
24787c478bd9Sstevel@tonic-gate break;
24797c478bd9Sstevel@tonic-gate }
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate if (EQ("rpc")) {
24827c478bd9Sstevel@tonic-gate uint_t vers, proc;
24837c478bd9Sstevel@tonic-gate char savetoken[32];
24847c478bd9Sstevel@tonic-gate
24857c478bd9Sstevel@tonic-gate vers = proc = -1;
24867c478bd9Sstevel@tonic-gate next();
24877c478bd9Sstevel@tonic-gate (void) strlcpy(savetoken, token, sizeof (savetoken));
24887c478bd9Sstevel@tonic-gate next();
24897c478bd9Sstevel@tonic-gate if (*token == ',') {
24907c478bd9Sstevel@tonic-gate next();
24917c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
24927c478bd9Sstevel@tonic-gate pr_err("version number expected");
24937c478bd9Sstevel@tonic-gate vers = tokenval;
24947c478bd9Sstevel@tonic-gate next();
24957c478bd9Sstevel@tonic-gate }
24967c478bd9Sstevel@tonic-gate if (*token == ',') {
24977c478bd9Sstevel@tonic-gate next();
24987c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
24997c478bd9Sstevel@tonic-gate pr_err("proc number expected");
25007c478bd9Sstevel@tonic-gate proc = tokenval;
25017c478bd9Sstevel@tonic-gate next();
25027c478bd9Sstevel@tonic-gate }
25037c478bd9Sstevel@tonic-gate rpc_match_prog(dir, savetoken, vers, proc);
25047c478bd9Sstevel@tonic-gate dir = ANY;
25057c478bd9Sstevel@tonic-gate opstack++;
25067c478bd9Sstevel@tonic-gate break;
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate
25097c478bd9Sstevel@tonic-gate if (EQ("slp")) {
2510b127ac41SPhilip Kirk /* filter out TCP handshakes */
2511b127ac41SPhilip Kirk emitop(OP_OFFSET_LINK);
2512b127ac41SPhilip Kirk compare_value(9, 1, IPPROTO_TCP);
2513b127ac41SPhilip Kirk emitop(OP_LOAD_CONST);
2514b127ac41SPhilip Kirk emitval(52);
2515b127ac41SPhilip Kirk emitop(OP_LOAD_CONST);
2516b127ac41SPhilip Kirk emitval(2);
2517b127ac41SPhilip Kirk emitop(OP_LOAD_SHORT);
2518b127ac41SPhilip Kirk emitop(OP_GE);
2519b127ac41SPhilip Kirk emitop(OP_AND); /* proto == TCP && len < 52 */
2520b127ac41SPhilip Kirk emitop(OP_NOT);
2521b127ac41SPhilip Kirk emitop(OP_BRFL); /* pkt too short to be a SLP call */
2522b127ac41SPhilip Kirk m = chain(0);
2523b127ac41SPhilip Kirk
2524b127ac41SPhilip Kirk emitop(OP_OFFSET_POP);
2525b127ac41SPhilip Kirk emitop(OP_OFFSET_SLP);
2526b127ac41SPhilip Kirk resolve_chain(m);
2527b127ac41SPhilip Kirk opstack++;
2528b127ac41SPhilip Kirk next();
2529b127ac41SPhilip Kirk break;
25307c478bd9Sstevel@tonic-gate }
25317c478bd9Sstevel@tonic-gate
25327c478bd9Sstevel@tonic-gate if (EQ("ldap")) {
25337c478bd9Sstevel@tonic-gate dir = ANY;
25347c478bd9Sstevel@tonic-gate port_match(dir, "ldap");
25357c478bd9Sstevel@tonic-gate opstack++;
25367c478bd9Sstevel@tonic-gate next();
25377c478bd9Sstevel@tonic-gate break;
25387c478bd9Sstevel@tonic-gate }
25397c478bd9Sstevel@tonic-gate
25407c478bd9Sstevel@tonic-gate if (EQ("and") || EQ("or")) {
25417c478bd9Sstevel@tonic-gate break;
25427c478bd9Sstevel@tonic-gate }
25437c478bd9Sstevel@tonic-gate
2544b127ac41SPhilip Kirk if (EQ("zone")) {
2545b127ac41SPhilip Kirk next();
2546b127ac41SPhilip Kirk if (tokentype != NUMBER)
2547b127ac41SPhilip Kirk pr_err("zoneid expected");
25480a0e9771SDarren Reed zone_match(dir, BE_32((uint32_t)(tokenval)));
2549b127ac41SPhilip Kirk opstack++;
2550b127ac41SPhilip Kirk next();
2551b127ac41SPhilip Kirk break;
2552b127ac41SPhilip Kirk }
2553b127ac41SPhilip Kirk
25547c478bd9Sstevel@tonic-gate if (EQ("gateway")) {
25557c478bd9Sstevel@tonic-gate next();
25567c478bd9Sstevel@tonic-gate if (eaddr || tokentype != ALPHA)
25577c478bd9Sstevel@tonic-gate pr_err("hostname required: %s", token);
25587c478bd9Sstevel@tonic-gate etheraddr_match(dir, token);
25597c478bd9Sstevel@tonic-gate dir = ANY;
25607c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
25617c478bd9Sstevel@tonic-gate m = chain(0);
25627c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV4_AND_IPV6);
25637c478bd9Sstevel@tonic-gate emitop(OP_NOT);
25647c478bd9Sstevel@tonic-gate resolve_chain(m);
25657c478bd9Sstevel@tonic-gate opstack++;
25667c478bd9Sstevel@tonic-gate next();
25677c478bd9Sstevel@tonic-gate }
25687c478bd9Sstevel@tonic-gate
25697c478bd9Sstevel@tonic-gate if (EQ("host") || EQ("between") ||
25707c478bd9Sstevel@tonic-gate tokentype == ALPHA || /* assume its a hostname */
25717c478bd9Sstevel@tonic-gate tokentype == ADDR_IP ||
25727c478bd9Sstevel@tonic-gate tokentype == ADDR_IP6 ||
25737c478bd9Sstevel@tonic-gate tokentype == ADDR_AT ||
25747c478bd9Sstevel@tonic-gate tokentype == ADDR_ETHER) {
25757c478bd9Sstevel@tonic-gate if (EQ("host") || EQ("between"))
25767c478bd9Sstevel@tonic-gate next();
25777c478bd9Sstevel@tonic-gate if (eaddr || tokentype == ADDR_ETHER) {
25787c478bd9Sstevel@tonic-gate etheraddr_match(dir, token);
25797c478bd9Sstevel@tonic-gate } else if (tokentype == ALPHA) {
25807c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV4_AND_IPV6);
25817c478bd9Sstevel@tonic-gate } else if (tokentype == ADDR_AT) {
25827c478bd9Sstevel@tonic-gate ataddr_match(dir, token);
25837c478bd9Sstevel@tonic-gate } else if (tokentype == ADDR_IP) {
25847c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV4_ONLY);
25857c478bd9Sstevel@tonic-gate } else {
25867c478bd9Sstevel@tonic-gate ipaddr_match(dir, token, IPV6_ONLY);
25877c478bd9Sstevel@tonic-gate }
25887c478bd9Sstevel@tonic-gate dir = ANY;
25897c478bd9Sstevel@tonic-gate eaddr = 0;
25907c478bd9Sstevel@tonic-gate opstack++;
25917c478bd9Sstevel@tonic-gate next();
25927c478bd9Sstevel@tonic-gate break;
25937c478bd9Sstevel@tonic-gate }
25947c478bd9Sstevel@tonic-gate
25957c478bd9Sstevel@tonic-gate if (tokentype == NUMBER) {
25967c478bd9Sstevel@tonic-gate load_const(tokenval);
25977c478bd9Sstevel@tonic-gate opstack++;
25987c478bd9Sstevel@tonic-gate next();
25997c478bd9Sstevel@tonic-gate break;
26007c478bd9Sstevel@tonic-gate }
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate break; /* unknown token */
26037c478bd9Sstevel@tonic-gate }
26047c478bd9Sstevel@tonic-gate }
26057c478bd9Sstevel@tonic-gate
26067c478bd9Sstevel@tonic-gate struct optable {
26077c478bd9Sstevel@tonic-gate char *op_tok;
26087c478bd9Sstevel@tonic-gate enum optype op_type;
26097c478bd9Sstevel@tonic-gate };
26107c478bd9Sstevel@tonic-gate
26117c478bd9Sstevel@tonic-gate static struct optable
26127c478bd9Sstevel@tonic-gate mulops[] = {
26137c478bd9Sstevel@tonic-gate "*", OP_MUL,
26147c478bd9Sstevel@tonic-gate "/", OP_DIV,
26157c478bd9Sstevel@tonic-gate "%", OP_REM,
26167c478bd9Sstevel@tonic-gate "&", OP_AND,
26177c478bd9Sstevel@tonic-gate "", OP_STOP,
26187c478bd9Sstevel@tonic-gate };
26197c478bd9Sstevel@tonic-gate
26207c478bd9Sstevel@tonic-gate static struct optable
26217c478bd9Sstevel@tonic-gate addops[] = {
26227c478bd9Sstevel@tonic-gate "+", OP_ADD,
26237c478bd9Sstevel@tonic-gate "-", OP_SUB,
26247c478bd9Sstevel@tonic-gate "|", OP_OR,
26257c478bd9Sstevel@tonic-gate "^", OP_XOR,
26267c478bd9Sstevel@tonic-gate "", OP_STOP,
26277c478bd9Sstevel@tonic-gate };
26287c478bd9Sstevel@tonic-gate
26297c478bd9Sstevel@tonic-gate static struct optable
26307c478bd9Sstevel@tonic-gate compareops[] = {
26317c478bd9Sstevel@tonic-gate "==", OP_EQ,
26327c478bd9Sstevel@tonic-gate "=", OP_EQ,
26337c478bd9Sstevel@tonic-gate "!=", OP_NE,
26347c478bd9Sstevel@tonic-gate ">", OP_GT,
26357c478bd9Sstevel@tonic-gate ">=", OP_GE,
26367c478bd9Sstevel@tonic-gate "<", OP_LT,
26377c478bd9Sstevel@tonic-gate "<=", OP_LE,
26387c478bd9Sstevel@tonic-gate "", OP_STOP,
26397c478bd9Sstevel@tonic-gate };
26407c478bd9Sstevel@tonic-gate
26417c478bd9Sstevel@tonic-gate /*
26427c478bd9Sstevel@tonic-gate * Using the table, find the operator
26437c478bd9Sstevel@tonic-gate * that corresponds to the token.
26447c478bd9Sstevel@tonic-gate * Return 0 if not found.
26457c478bd9Sstevel@tonic-gate */
26467c478bd9Sstevel@tonic-gate static int
find_op(char * tok,struct optable * table)26477c478bd9Sstevel@tonic-gate find_op(char *tok, struct optable *table)
26487c478bd9Sstevel@tonic-gate {
26497c478bd9Sstevel@tonic-gate struct optable *op;
26507c478bd9Sstevel@tonic-gate
26517c478bd9Sstevel@tonic-gate for (op = table; *op->op_tok; op++) {
26527c478bd9Sstevel@tonic-gate if (strcmp(tok, op->op_tok) == 0)
26537c478bd9Sstevel@tonic-gate return (op->op_type);
26547c478bd9Sstevel@tonic-gate }
26557c478bd9Sstevel@tonic-gate
26567c478bd9Sstevel@tonic-gate return (0);
26577c478bd9Sstevel@tonic-gate }
26587c478bd9Sstevel@tonic-gate
26597c478bd9Sstevel@tonic-gate static void
expr_mul()26607c478bd9Sstevel@tonic-gate expr_mul()
26617c478bd9Sstevel@tonic-gate {
26627c478bd9Sstevel@tonic-gate int op;
26637c478bd9Sstevel@tonic-gate int s = opstack;
26647c478bd9Sstevel@tonic-gate
26657c478bd9Sstevel@tonic-gate primary();
26667c478bd9Sstevel@tonic-gate while (op = find_op(token, mulops)) {
26677c478bd9Sstevel@tonic-gate next();
26687c478bd9Sstevel@tonic-gate primary();
26697c478bd9Sstevel@tonic-gate checkstack(s + 2);
26707c478bd9Sstevel@tonic-gate emitop(op);
26717c478bd9Sstevel@tonic-gate opstack--;
26727c478bd9Sstevel@tonic-gate }
26737c478bd9Sstevel@tonic-gate }
26747c478bd9Sstevel@tonic-gate
26757c478bd9Sstevel@tonic-gate static void
expr_add()26767c478bd9Sstevel@tonic-gate expr_add()
26777c478bd9Sstevel@tonic-gate {
26787c478bd9Sstevel@tonic-gate int op, s = opstack;
26797c478bd9Sstevel@tonic-gate
26807c478bd9Sstevel@tonic-gate expr_mul();
26817c478bd9Sstevel@tonic-gate while (op = find_op(token, addops)) {
26827c478bd9Sstevel@tonic-gate next();
26837c478bd9Sstevel@tonic-gate expr_mul();
26847c478bd9Sstevel@tonic-gate checkstack(s + 2);
26857c478bd9Sstevel@tonic-gate emitop(op);
26867c478bd9Sstevel@tonic-gate opstack--;
26877c478bd9Sstevel@tonic-gate }
26887c478bd9Sstevel@tonic-gate }
26897c478bd9Sstevel@tonic-gate
26907c478bd9Sstevel@tonic-gate static void
expr_compare()26917c478bd9Sstevel@tonic-gate expr_compare()
26927c478bd9Sstevel@tonic-gate {
26937c478bd9Sstevel@tonic-gate int op, s = opstack;
26947c478bd9Sstevel@tonic-gate
26957c478bd9Sstevel@tonic-gate expr_add();
26967c478bd9Sstevel@tonic-gate while (op = find_op(token, compareops)) {
26977c478bd9Sstevel@tonic-gate next();
26987c478bd9Sstevel@tonic-gate expr_add();
26997c478bd9Sstevel@tonic-gate checkstack(s + 2);
27007c478bd9Sstevel@tonic-gate emitop(op);
27017c478bd9Sstevel@tonic-gate opstack--;
27027c478bd9Sstevel@tonic-gate }
27037c478bd9Sstevel@tonic-gate }
27047c478bd9Sstevel@tonic-gate
27057c478bd9Sstevel@tonic-gate /*
27067c478bd9Sstevel@tonic-gate * Alternation ("and") is difficult because
27077c478bd9Sstevel@tonic-gate * an implied "and" is acknowledge between
27087c478bd9Sstevel@tonic-gate * two adjacent primaries. Just keep calling
27097c478bd9Sstevel@tonic-gate * the lower-level expression routine until
27107c478bd9Sstevel@tonic-gate * no value is added to the opstack.
27117c478bd9Sstevel@tonic-gate */
27127c478bd9Sstevel@tonic-gate static void
alternation()27137c478bd9Sstevel@tonic-gate alternation()
27147c478bd9Sstevel@tonic-gate {
27157c478bd9Sstevel@tonic-gate int m = 0;
27167c478bd9Sstevel@tonic-gate int s = opstack;
27177c478bd9Sstevel@tonic-gate
27187c478bd9Sstevel@tonic-gate expr_compare();
27197c478bd9Sstevel@tonic-gate checkstack(s + 1);
27207c478bd9Sstevel@tonic-gate for (;;) {
27217c478bd9Sstevel@tonic-gate if (EQ("and"))
27227c478bd9Sstevel@tonic-gate next();
27237c478bd9Sstevel@tonic-gate emitop(OP_BRFL);
27247c478bd9Sstevel@tonic-gate m = chain(m);
27257c478bd9Sstevel@tonic-gate expr_compare();
27267c478bd9Sstevel@tonic-gate if (opstack != s + 2)
27277c478bd9Sstevel@tonic-gate break;
27287c478bd9Sstevel@tonic-gate opstack--;
27297c478bd9Sstevel@tonic-gate }
27307c478bd9Sstevel@tonic-gate unemit(2);
27317c478bd9Sstevel@tonic-gate resolve_chain(m);
27327c478bd9Sstevel@tonic-gate }
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate static void
expression()27357c478bd9Sstevel@tonic-gate expression()
27367c478bd9Sstevel@tonic-gate {
27377c478bd9Sstevel@tonic-gate int m = 0;
27387c478bd9Sstevel@tonic-gate int s = opstack;
27397c478bd9Sstevel@tonic-gate
27407c478bd9Sstevel@tonic-gate alternation();
27417c478bd9Sstevel@tonic-gate while (EQ("or") || EQ(",")) {
27427c478bd9Sstevel@tonic-gate emitop(OP_BRTR);
27437c478bd9Sstevel@tonic-gate m = chain(m);
27447c478bd9Sstevel@tonic-gate next();
27457c478bd9Sstevel@tonic-gate alternation();
27467c478bd9Sstevel@tonic-gate checkstack(s + 2);
27477c478bd9Sstevel@tonic-gate opstack--;
27487c478bd9Sstevel@tonic-gate }
27497c478bd9Sstevel@tonic-gate resolve_chain(m);
27507c478bd9Sstevel@tonic-gate }
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate /*
27537c478bd9Sstevel@tonic-gate * Take n args from the argv list
27547c478bd9Sstevel@tonic-gate * and concatenate them into a single string.
27557c478bd9Sstevel@tonic-gate */
27567c478bd9Sstevel@tonic-gate char *
concat_args(char ** argv,int argc)27577c478bd9Sstevel@tonic-gate concat_args(char **argv, int argc)
27587c478bd9Sstevel@tonic-gate {
27597c478bd9Sstevel@tonic-gate int i, len;
27607c478bd9Sstevel@tonic-gate char *str, *p;
27617c478bd9Sstevel@tonic-gate
27627c478bd9Sstevel@tonic-gate /* First add the lengths of all the strings */
27637c478bd9Sstevel@tonic-gate len = 0;
27647c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++)
27657c478bd9Sstevel@tonic-gate len += strlen(argv[i]) + 1;
27667c478bd9Sstevel@tonic-gate
27677c478bd9Sstevel@tonic-gate /* allocate the big string */
27687c478bd9Sstevel@tonic-gate str = (char *)malloc(len);
27697c478bd9Sstevel@tonic-gate if (str == NULL)
27707c478bd9Sstevel@tonic-gate pr_err("no mem");
27717c478bd9Sstevel@tonic-gate
27727c478bd9Sstevel@tonic-gate p = str;
27737c478bd9Sstevel@tonic-gate
27747c478bd9Sstevel@tonic-gate /*
27757c478bd9Sstevel@tonic-gate * Concat the strings into the big
27767c478bd9Sstevel@tonic-gate * string using a space as separator
27777c478bd9Sstevel@tonic-gate */
27787c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) {
27797c478bd9Sstevel@tonic-gate strcpy(p, argv[i]);
27807c478bd9Sstevel@tonic-gate p += strlen(p);
27817c478bd9Sstevel@tonic-gate *p++ = ' ';
27827c478bd9Sstevel@tonic-gate }
27837c478bd9Sstevel@tonic-gate *--p = '\0';
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gate return (str);
27867c478bd9Sstevel@tonic-gate }
27877c478bd9Sstevel@tonic-gate
27887c478bd9Sstevel@tonic-gate /*
27897c478bd9Sstevel@tonic-gate * Take the expression in the string "expr"
27907c478bd9Sstevel@tonic-gate * and compile it into the code array.
27917c478bd9Sstevel@tonic-gate * Print the generated code if the print
27927c478bd9Sstevel@tonic-gate * arg is set.
27937c478bd9Sstevel@tonic-gate */
27947c478bd9Sstevel@tonic-gate void
compile(char * expr,int print)27957c478bd9Sstevel@tonic-gate compile(char *expr, int print)
27967c478bd9Sstevel@tonic-gate {
27977c478bd9Sstevel@tonic-gate expr = strdup(expr);
27987c478bd9Sstevel@tonic-gate if (expr == NULL)
27997c478bd9Sstevel@tonic-gate pr_err("no mem");
28007c478bd9Sstevel@tonic-gate curr_op = oplist;
28017c478bd9Sstevel@tonic-gate tkp = expr;
28027c478bd9Sstevel@tonic-gate dir = ANY;
28037c478bd9Sstevel@tonic-gate
28047c478bd9Sstevel@tonic-gate next();
28057c478bd9Sstevel@tonic-gate if (tokentype != EOL)
28067c478bd9Sstevel@tonic-gate expression();
28077c478bd9Sstevel@tonic-gate emitop(OP_STOP);
28087c478bd9Sstevel@tonic-gate if (tokentype != EOL)
28097c478bd9Sstevel@tonic-gate pr_err("invalid expression");
28107c478bd9Sstevel@tonic-gate optimize(oplist);
28117c478bd9Sstevel@tonic-gate if (print)
28127c478bd9Sstevel@tonic-gate codeprint();
28137c478bd9Sstevel@tonic-gate }
28147c478bd9Sstevel@tonic-gate
28157c478bd9Sstevel@tonic-gate /*
28167c478bd9Sstevel@tonic-gate * Lookup hostname in the arp cache.
28177c478bd9Sstevel@tonic-gate */
28187c478bd9Sstevel@tonic-gate boolean_t
arp_for_ether(char * hostname,struct ether_addr * ep)28197c478bd9Sstevel@tonic-gate arp_for_ether(char *hostname, struct ether_addr *ep)
28207c478bd9Sstevel@tonic-gate {
28217c478bd9Sstevel@tonic-gate struct arpreq ar;
28227c478bd9Sstevel@tonic-gate struct hostent *hp;
28237c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
28247c478bd9Sstevel@tonic-gate int error_num;
28257c478bd9Sstevel@tonic-gate int s;
28267c478bd9Sstevel@tonic-gate
28277c478bd9Sstevel@tonic-gate memset(&ar, 0, sizeof (ar));
28287c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ar.arp_pa;
28297c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET;
28307c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
28317c478bd9Sstevel@tonic-gate if (hp == NULL) {
28327c478bd9Sstevel@tonic-gate return (B_FALSE);
28337c478bd9Sstevel@tonic-gate }
28347c478bd9Sstevel@tonic-gate memcpy(&sin->sin_addr, hp->h_addr, sizeof (sin->sin_addr));
28357c478bd9Sstevel@tonic-gate s = socket(AF_INET, SOCK_DGRAM, 0);
28367c478bd9Sstevel@tonic-gate if (s < 0) {
28377c478bd9Sstevel@tonic-gate return (B_FALSE);
28387c478bd9Sstevel@tonic-gate }
28397c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGARP, &ar) < 0) {
28407c478bd9Sstevel@tonic-gate close(s);
28417c478bd9Sstevel@tonic-gate return (B_FALSE);
28427c478bd9Sstevel@tonic-gate }
28437c478bd9Sstevel@tonic-gate close(s);
28447c478bd9Sstevel@tonic-gate memcpy(ep->ether_addr_octet, ar.arp_ha.sa_data, sizeof (*ep));
28457c478bd9Sstevel@tonic-gate return (B_TRUE);
28467c478bd9Sstevel@tonic-gate }
2847