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