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