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