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