10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52760Sdg199075 * Common Development and Distribution License (the "License"). 62760Sdg199075 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 226631Sss150715 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <stdio.h> 272760Sdg199075 #include <stddef.h> 280Sstevel@tonic-gate #include <ctype.h> 290Sstevel@tonic-gate #include <string.h> 300Sstevel@tonic-gate #include <fcntl.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/time.h> 340Sstevel@tonic-gate #include <sys/isa_defs.h> 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <sys/socket.h> 372760Sdg199075 #include <sys/vlan.h> 380Sstevel@tonic-gate #include <net/if.h> 390Sstevel@tonic-gate #include <netinet/in_systm.h> 400Sstevel@tonic-gate #include <netinet/in.h> 410Sstevel@tonic-gate #include <netinet/ip.h> 420Sstevel@tonic-gate #include <netinet/if_ether.h> 430Sstevel@tonic-gate #include <netinet/tcp.h> 440Sstevel@tonic-gate #include <netinet/udp.h> 45*8023SPhil.Kirk@Sun.COM #include <inet/ip.h> 46*8023SPhil.Kirk@Sun.COM #include <inet/ip6.h> 470Sstevel@tonic-gate #include <netdb.h> 480Sstevel@tonic-gate #include <rpc/rpc.h> 490Sstevel@tonic-gate #include <setjmp.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <sys/pfmod.h> 520Sstevel@tonic-gate #include "snoop.h" 532760Sdg199075 #include "snoop_vlan.h" 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * This module generates code for the kernel packet filter. 570Sstevel@tonic-gate * The kernel packet filter is more efficient since it 580Sstevel@tonic-gate * operates without context switching or moving data into 590Sstevel@tonic-gate * the capture buffer. On the other hand, it is limited 600Sstevel@tonic-gate * in its filtering ability i.e. can't cope with variable 610Sstevel@tonic-gate * length headers, can't compare the packet size, 1 and 4 octet 620Sstevel@tonic-gate * comparisons are awkward, code space is limited to ENMAXFILTERS 630Sstevel@tonic-gate * halfwords, etc. 640Sstevel@tonic-gate * The parser is the same for the user-level packet filter though 650Sstevel@tonic-gate * more limited in the variety of expressions it can generate 660Sstevel@tonic-gate * code for. If the pf compiler finds an expression it can't 670Sstevel@tonic-gate * handle, it tries to set up a split filter in kernel and do the 680Sstevel@tonic-gate * remaining filtering in userland. If that also fails, it resorts 690Sstevel@tonic-gate * to userland filter. (See additional comment in pf_compile) 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate extern struct Pf_ext_packetfilt pf; 730Sstevel@tonic-gate static ushort_t *pfp; 740Sstevel@tonic-gate jmp_buf env; 750Sstevel@tonic-gate 760Sstevel@tonic-gate int eaddr; /* need ethernet addr */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate int opstack; /* operand stack depth */ 790Sstevel@tonic-gate 800Sstevel@tonic-gate #define EQ(val) (strcmp(token, val) == 0) 810Sstevel@tonic-gate #define IPV4_ONLY 0 820Sstevel@tonic-gate #define IPV6_ONLY 1 830Sstevel@tonic-gate #define IPV4_AND_IPV6 2 840Sstevel@tonic-gate 85*8023SPhil.Kirk@Sun.COM typedef struct { 86*8023SPhil.Kirk@Sun.COM int transport_protocol; 87*8023SPhil.Kirk@Sun.COM int network_protocol; 88*8023SPhil.Kirk@Sun.COM /* 89*8023SPhil.Kirk@Sun.COM * offset is the offset in bytes from the beginning 90*8023SPhil.Kirk@Sun.COM * of the network protocol header to where the transport 91*8023SPhil.Kirk@Sun.COM * protocol type is. 92*8023SPhil.Kirk@Sun.COM */ 93*8023SPhil.Kirk@Sun.COM int offset; 94*8023SPhil.Kirk@Sun.COM } transport_protocol_table_t; 95*8023SPhil.Kirk@Sun.COM 96*8023SPhil.Kirk@Sun.COM typedef struct network_table { 97*8023SPhil.Kirk@Sun.COM char *nmt_name; 98*8023SPhil.Kirk@Sun.COM int nmt_val; 99*8023SPhil.Kirk@Sun.COM } network_table_t; 100*8023SPhil.Kirk@Sun.COM 101*8023SPhil.Kirk@Sun.COM static network_table_t ether_network_mapping_table[] = { 102*8023SPhil.Kirk@Sun.COM { "pup", ETHERTYPE_PUP }, 103*8023SPhil.Kirk@Sun.COM { "ip", ETHERTYPE_IP }, 104*8023SPhil.Kirk@Sun.COM { "arp", ETHERTYPE_ARP }, 105*8023SPhil.Kirk@Sun.COM { "revarp", ETHERTYPE_REVARP }, 106*8023SPhil.Kirk@Sun.COM { "at", ETHERTYPE_AT }, 107*8023SPhil.Kirk@Sun.COM { "aarp", ETHERTYPE_AARP }, 108*8023SPhil.Kirk@Sun.COM { "vlan", ETHERTYPE_VLAN }, 109*8023SPhil.Kirk@Sun.COM { "ip6", ETHERTYPE_IPV6 }, 110*8023SPhil.Kirk@Sun.COM { "slow", ETHERTYPE_SLOW }, 111*8023SPhil.Kirk@Sun.COM { "ppoed", ETHERTYPE_PPPOED }, 112*8023SPhil.Kirk@Sun.COM { "ppoes", ETHERTYPE_PPPOES }, 113*8023SPhil.Kirk@Sun.COM { "NULL", -1 } 114*8023SPhil.Kirk@Sun.COM 115*8023SPhil.Kirk@Sun.COM }; 116*8023SPhil.Kirk@Sun.COM 117*8023SPhil.Kirk@Sun.COM static network_table_t ib_network_mapping_table[] = { 118*8023SPhil.Kirk@Sun.COM { "pup", ETHERTYPE_PUP }, 119*8023SPhil.Kirk@Sun.COM { "ip", ETHERTYPE_IP }, 120*8023SPhil.Kirk@Sun.COM { "arp", ETHERTYPE_ARP }, 121*8023SPhil.Kirk@Sun.COM { "revarp", ETHERTYPE_REVARP }, 122*8023SPhil.Kirk@Sun.COM { "at", ETHERTYPE_AT }, 123*8023SPhil.Kirk@Sun.COM { "aarp", ETHERTYPE_AARP }, 124*8023SPhil.Kirk@Sun.COM { "vlan", ETHERTYPE_VLAN }, 125*8023SPhil.Kirk@Sun.COM { "ip6", ETHERTYPE_IPV6 }, 126*8023SPhil.Kirk@Sun.COM { "slow", ETHERTYPE_SLOW }, 127*8023SPhil.Kirk@Sun.COM { "ppoed", ETHERTYPE_PPPOED }, 128*8023SPhil.Kirk@Sun.COM { "ppoes", ETHERTYPE_PPPOES }, 129*8023SPhil.Kirk@Sun.COM { "NULL", -1 } 130*8023SPhil.Kirk@Sun.COM 131*8023SPhil.Kirk@Sun.COM }; 132*8023SPhil.Kirk@Sun.COM 133*8023SPhil.Kirk@Sun.COM static network_table_t ipnet_network_mapping_table[] = { 134*8023SPhil.Kirk@Sun.COM { "ip", (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION) }, 135*8023SPhil.Kirk@Sun.COM { "ip6", (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION) }, 136*8023SPhil.Kirk@Sun.COM { "NULL", -1 } 137*8023SPhil.Kirk@Sun.COM 138*8023SPhil.Kirk@Sun.COM }; 139*8023SPhil.Kirk@Sun.COM 140*8023SPhil.Kirk@Sun.COM static transport_protocol_table_t ether_transport_mapping_table[] = { 141*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 142*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 143*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 144*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 145*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 146*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 147*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 148*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 149*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 150*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 151*8023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 152*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 153*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 154*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 155*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 156*8023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 157*8023SPhil.Kirk@Sun.COM }; 1580Sstevel@tonic-gate 159*8023SPhil.Kirk@Sun.COM static transport_protocol_table_t ipnet_transport_mapping_table[] = { 160*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 161*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 162*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 163*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 164*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 165*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 166*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 167*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 168*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 169*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 170*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 171*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 172*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 173*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 174*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 175*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 176*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 177*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 178*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 179*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 180*8023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 181*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 182*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 183*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 184*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 185*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 186*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 187*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 188*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 189*8023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 190*8023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 191*8023SPhil.Kirk@Sun.COM }; 192*8023SPhil.Kirk@Sun.COM 193*8023SPhil.Kirk@Sun.COM static transport_protocol_table_t ib_transport_mapping_table[] = { 194*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 195*8023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 196*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 197*8023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 198*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 199*8023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 200*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 201*8023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 202*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 203*8023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 204*8023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 205*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 206*8023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 207*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 208*8023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 209*8023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 210*8023SPhil.Kirk@Sun.COM }; 211*8023SPhil.Kirk@Sun.COM 212*8023SPhil.Kirk@Sun.COM typedef struct datalink { 213*8023SPhil.Kirk@Sun.COM uint_t dl_type; 214*8023SPhil.Kirk@Sun.COM void (*dl_match_fn)(uint_t datatype); 215*8023SPhil.Kirk@Sun.COM transport_protocol_table_t *dl_transport_mapping_table; 216*8023SPhil.Kirk@Sun.COM network_table_t *dl_net_map_tbl; 217*8023SPhil.Kirk@Sun.COM int dl_link_header_len; 218*8023SPhil.Kirk@Sun.COM int dl_link_type_offset; 219*8023SPhil.Kirk@Sun.COM int dl_link_dest_offset; 220*8023SPhil.Kirk@Sun.COM int dl_link_src_offset; 221*8023SPhil.Kirk@Sun.COM int dl_link_addr_len; 222*8023SPhil.Kirk@Sun.COM } datalink_t; 223*8023SPhil.Kirk@Sun.COM 224*8023SPhil.Kirk@Sun.COM datalink_t dl; 225*8023SPhil.Kirk@Sun.COM 226*8023SPhil.Kirk@Sun.COM #define IPV4_SRCADDR_OFFSET (dl.dl_link_header_len + 12) 227*8023SPhil.Kirk@Sun.COM #define IPV4_DSTADDR_OFFSET (dl.dl_link_header_len + 16) 228*8023SPhil.Kirk@Sun.COM #define IPV6_SRCADDR_OFFSET (dl.dl_link_header_len + 8) 229*8023SPhil.Kirk@Sun.COM #define IPV6_DSTADDR_OFFSET (dl.dl_link_header_len + 24) 230*8023SPhil.Kirk@Sun.COM 231*8023SPhil.Kirk@Sun.COM #define IPNET_SRCZONE_OFFSET 8 232*8023SPhil.Kirk@Sun.COM #define IPNET_DSTZONE_OFFSET 16 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate static int inBrace = 0, inBraceOR = 0; 2350Sstevel@tonic-gate static int foundOR = 0; 2360Sstevel@tonic-gate char *tkp, *sav_tkp; 2370Sstevel@tonic-gate char *token; 2380Sstevel@tonic-gate enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL, 2390Sstevel@tonic-gate ADDR_IP6 } tokentype; 2400Sstevel@tonic-gate uint_t tokenval; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate enum direction { ANY, TO, FROM }; 2430Sstevel@tonic-gate enum direction dir; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate extern void next(); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate static void pf_expression(); 2482760Sdg199075 static void pf_check_vlan_tag(uint_t offset); 2492760Sdg199075 static void pf_clear_offset_register(); 2502760Sdg199075 static void pf_emit_load_offset(uint_t offset); 2512760Sdg199075 static void pf_match_ethertype(uint_t ethertype); 252*8023SPhil.Kirk@Sun.COM static void pf_match_ipnettype(uint_t type); 253*8023SPhil.Kirk@Sun.COM static void pf_match_ibtype(uint_t type); 2542760Sdg199075 static void pf_check_transport_protocol(uint_t transport_protocol); 2552760Sdg199075 static void pf_compare_value_mask_generic(int offset, uint_t len, 2562760Sdg199075 uint_t val, int mask, uint_t op); 2572760Sdg199075 2582760Sdg199075 /* 2592760Sdg199075 * This pointer points to the function that last generated 2602760Sdg199075 * instructions to change the offset register. It's used 2612760Sdg199075 * for comparisons to see if we need to issue more instructions 2622760Sdg199075 * to change the register. 2632760Sdg199075 * 2642760Sdg199075 * It's initialized to pf_clear_offset_register because the offset 2652760Sdg199075 * register in pfmod is initialized to zero, similar to the state 2662760Sdg199075 * it would be in after executing the instructions issued by 2672760Sdg199075 * pf_clear_offset_register. 2682760Sdg199075 */ 2692760Sdg199075 static void *last_offset_operation = (void*)pf_clear_offset_register; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate static void 2720Sstevel@tonic-gate pf_emit(x) 2730Sstevel@tonic-gate ushort_t x; 2740Sstevel@tonic-gate { 2750Sstevel@tonic-gate if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1]) 2760Sstevel@tonic-gate longjmp(env, 1); 2770Sstevel@tonic-gate *pfp++ = x; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate static void 2810Sstevel@tonic-gate pf_codeprint(code, len) 2820Sstevel@tonic-gate ushort_t *code; 2830Sstevel@tonic-gate int len; 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate ushort_t *pc; 2860Sstevel@tonic-gate ushort_t *plast = code + len; 2870Sstevel@tonic-gate int op, action; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if (len > 0) { 2900Sstevel@tonic-gate printf("Kernel Filter:\n"); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate for (pc = code; pc < plast; pc++) { 2940Sstevel@tonic-gate printf("\t%3d: ", pc - code); 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate op = *pc & 0xfc00; /* high 10 bits */ 2970Sstevel@tonic-gate action = *pc & 0x3ff; /* low 6 bits */ 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate switch (action) { 3000Sstevel@tonic-gate case ENF_PUSHLIT: 3010Sstevel@tonic-gate printf("PUSHLIT "); 3020Sstevel@tonic-gate break; 3030Sstevel@tonic-gate case ENF_PUSHZERO: 3040Sstevel@tonic-gate printf("PUSHZERO "); 3050Sstevel@tonic-gate break; 3060Sstevel@tonic-gate #ifdef ENF_PUSHONE 3070Sstevel@tonic-gate case ENF_PUSHONE: 3080Sstevel@tonic-gate printf("PUSHONE "); 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate #endif 3110Sstevel@tonic-gate #ifdef ENF_PUSHFFFF 3120Sstevel@tonic-gate case ENF_PUSHFFFF: 3130Sstevel@tonic-gate printf("PUSHFFFF "); 3140Sstevel@tonic-gate break; 3150Sstevel@tonic-gate #endif 3160Sstevel@tonic-gate #ifdef ENF_PUSHFF00 3170Sstevel@tonic-gate case ENF_PUSHFF00: 3180Sstevel@tonic-gate printf("PUSHFF00 "); 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate #endif 3210Sstevel@tonic-gate #ifdef ENF_PUSH00FF 3220Sstevel@tonic-gate case ENF_PUSH00FF: 3230Sstevel@tonic-gate printf("PUSH00FF "); 3240Sstevel@tonic-gate break; 3250Sstevel@tonic-gate #endif 3262760Sdg199075 case ENF_LOAD_OFFSET: 3272760Sdg199075 printf("LOAD_OFFSET "); 3282760Sdg199075 break; 3292760Sdg199075 case ENF_BRTR: 3302760Sdg199075 printf("BRTR "); 3312760Sdg199075 break; 3322760Sdg199075 case ENF_BRFL: 3332760Sdg199075 printf("BRFL "); 3342760Sdg199075 break; 3352760Sdg199075 case ENF_POP: 3362760Sdg199075 printf("POP "); 3372760Sdg199075 break; 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (action >= ENF_PUSHWORD) 3410Sstevel@tonic-gate printf("PUSHWORD %d ", action - ENF_PUSHWORD); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate switch (op) { 3440Sstevel@tonic-gate case ENF_EQ: 3450Sstevel@tonic-gate printf("EQ "); 3460Sstevel@tonic-gate break; 3470Sstevel@tonic-gate case ENF_LT: 3480Sstevel@tonic-gate printf("LT "); 3490Sstevel@tonic-gate break; 3500Sstevel@tonic-gate case ENF_LE: 3510Sstevel@tonic-gate printf("LE "); 3520Sstevel@tonic-gate break; 3530Sstevel@tonic-gate case ENF_GT: 3540Sstevel@tonic-gate printf("GT "); 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate case ENF_GE: 3570Sstevel@tonic-gate printf("GE "); 3580Sstevel@tonic-gate break; 3590Sstevel@tonic-gate case ENF_AND: 3600Sstevel@tonic-gate printf("AND "); 3610Sstevel@tonic-gate break; 3620Sstevel@tonic-gate case ENF_OR: 3630Sstevel@tonic-gate printf("OR "); 3640Sstevel@tonic-gate break; 3650Sstevel@tonic-gate case ENF_XOR: 3660Sstevel@tonic-gate printf("XOR "); 3670Sstevel@tonic-gate break; 3680Sstevel@tonic-gate case ENF_COR: 3690Sstevel@tonic-gate printf("COR "); 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate case ENF_CAND: 3720Sstevel@tonic-gate printf("CAND "); 3730Sstevel@tonic-gate break; 3740Sstevel@tonic-gate case ENF_CNOR: 3750Sstevel@tonic-gate printf("CNOR "); 3760Sstevel@tonic-gate break; 3770Sstevel@tonic-gate case ENF_CNAND: 3780Sstevel@tonic-gate printf("CNAND "); 3790Sstevel@tonic-gate break; 3800Sstevel@tonic-gate case ENF_NEQ: 3810Sstevel@tonic-gate printf("NEQ "); 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3852760Sdg199075 if (action == ENF_PUSHLIT || 3862760Sdg199075 action == ENF_LOAD_OFFSET || 3872760Sdg199075 action == ENF_BRTR || 3882760Sdg199075 action == ENF_BRFL) { 3890Sstevel@tonic-gate pc++; 3900Sstevel@tonic-gate printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate printf("\n"); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /* 3980Sstevel@tonic-gate * Emit packet filter code to check a 3990Sstevel@tonic-gate * field in the packet for a particular value. 4000Sstevel@tonic-gate * Need different code for each field size. 4010Sstevel@tonic-gate * Since the pf can only compare 16 bit quantities 4020Sstevel@tonic-gate * we have to use masking to compare byte values. 4030Sstevel@tonic-gate * Long word (32 bit) quantities have to be done 4040Sstevel@tonic-gate * as two 16 bit comparisons. 4050Sstevel@tonic-gate */ 4060Sstevel@tonic-gate static void 4070Sstevel@tonic-gate pf_compare_value(int offset, uint_t len, uint_t val) 4080Sstevel@tonic-gate { 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * If the property being filtered on is absent in the media 4110Sstevel@tonic-gate * packet, error out. 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate if (offset == -1) 4140Sstevel@tonic-gate pr_err("filter option unsupported on media"); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate switch (len) { 4170Sstevel@tonic-gate case 1: 4180Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4190Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4200Sstevel@tonic-gate if (offset % 2) 4210Sstevel@tonic-gate #else 4220Sstevel@tonic-gate if (!(offset % 2)) 4230Sstevel@tonic-gate #endif 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate #ifdef ENF_PUSH00FF 4260Sstevel@tonic-gate pf_emit(ENF_PUSH00FF | ENF_AND); 4270Sstevel@tonic-gate #else 4280Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 4290Sstevel@tonic-gate pf_emit(0x00FF); 4300Sstevel@tonic-gate #endif 4310Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4320Sstevel@tonic-gate pf_emit(val); 4330Sstevel@tonic-gate } else { 4340Sstevel@tonic-gate #ifdef ENF_PUSHFF00 4350Sstevel@tonic-gate pf_emit(ENF_PUSHFF00 | ENF_AND); 4360Sstevel@tonic-gate #else 4370Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 4380Sstevel@tonic-gate pf_emit(0xFF00); 4390Sstevel@tonic-gate #endif 4400Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4410Sstevel@tonic-gate pf_emit(val << 8); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate break; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate case 2: 4460Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4470Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4480Sstevel@tonic-gate pf_emit((ushort_t)val); 4490Sstevel@tonic-gate break; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate case 4: 4520Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4530Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4540Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4550Sstevel@tonic-gate pf_emit(val >> 16); 4560Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 4570Sstevel@tonic-gate pf_emit(val & 0xffff); 4580Sstevel@tonic-gate #else 4590Sstevel@tonic-gate #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined 4600Sstevel@tonic-gate #endif 4610Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 4620Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4630Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4640Sstevel@tonic-gate pf_emit(val & 0xffff); 4650Sstevel@tonic-gate #else 4660Sstevel@tonic-gate pf_emit(val >> 16); 4670Sstevel@tonic-gate #endif 4680Sstevel@tonic-gate pf_emit(ENF_AND); 4690Sstevel@tonic-gate break; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * same as pf_compare_value, but only for emiting code to 4750Sstevel@tonic-gate * compare ipv6 addresses. 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate static void 4780Sstevel@tonic-gate pf_compare_value_v6(int offset, uint_t len, struct in6_addr val) 4790Sstevel@tonic-gate { 4800Sstevel@tonic-gate int i; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate for (i = 0; i < len; i += 2) { 4830Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2 + i / 2); 4840Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4850Sstevel@tonic-gate pf_emit(*(uint16_t *)&val.s6_addr[i]); 4860Sstevel@tonic-gate if (i != 0) 4870Sstevel@tonic-gate pf_emit(ENF_AND); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* 4930Sstevel@tonic-gate * Same as above except mask the field value 4942760Sdg199075 * before doing the comparison. The comparison checks 4952760Sdg199075 * to make sure the values are equal. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate static void 4980Sstevel@tonic-gate pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) 4990Sstevel@tonic-gate { 5002760Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ); 5012760Sdg199075 } 5022760Sdg199075 5032760Sdg199075 /* 5042760Sdg199075 * Same as above except the values are compared to see if they are not 5052760Sdg199075 * equal. 5062760Sdg199075 */ 5072760Sdg199075 static void 5082760Sdg199075 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask) 5092760Sdg199075 { 5102760Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ); 5112760Sdg199075 } 5122760Sdg199075 5132760Sdg199075 /* 5142760Sdg199075 * Similar to pf_compare_value. 5152760Sdg199075 * 5162760Sdg199075 * This is the utility function that does the actual work to compare 5172760Sdg199075 * two values using a mask. The comparison operation is passed into 5182760Sdg199075 * the function. 5192760Sdg199075 */ 5202760Sdg199075 static void 5212760Sdg199075 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask, 5222760Sdg199075 uint_t op) 5232760Sdg199075 { 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * If the property being filtered on is absent in the media 5260Sstevel@tonic-gate * packet, error out. 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate if (offset == -1) 5290Sstevel@tonic-gate pr_err("filter option unsupported on media"); 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate switch (len) { 5320Sstevel@tonic-gate case 1: 5330Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5340Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 5350Sstevel@tonic-gate if (offset % 2) 5360Sstevel@tonic-gate #else 5370Sstevel@tonic-gate if (!offset % 2) 5380Sstevel@tonic-gate #endif 5390Sstevel@tonic-gate { 5400Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5410Sstevel@tonic-gate pf_emit(mask & 0x00ff); 5422760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5430Sstevel@tonic-gate pf_emit(val); 5440Sstevel@tonic-gate } else { 5450Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5460Sstevel@tonic-gate pf_emit((mask << 8) & 0xff00); 5472760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5480Sstevel@tonic-gate pf_emit(val << 8); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate break; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate case 2: 5530Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5540Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5550Sstevel@tonic-gate pf_emit(htons((ushort_t)mask)); 5562760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5570Sstevel@tonic-gate pf_emit(htons((ushort_t)val)); 5580Sstevel@tonic-gate break; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate case 4: 5610Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5620Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5630Sstevel@tonic-gate pf_emit(htons((ushort_t)((mask >> 16) & 0xffff))); 5642760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5650Sstevel@tonic-gate pf_emit(htons((ushort_t)((val >> 16) & 0xffff))); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 5680Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5690Sstevel@tonic-gate pf_emit(htons((ushort_t)(mask & 0xffff))); 5702760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5710Sstevel@tonic-gate pf_emit(htons((ushort_t)(val & 0xffff))); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate pf_emit(ENF_AND); 5740Sstevel@tonic-gate break; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* 579*8023SPhil.Kirk@Sun.COM * Like pf_compare_value() but compare on a 64-bit zoneid value. 580*8023SPhil.Kirk@Sun.COM * The argument val passed in is in network byte order. 581*8023SPhil.Kirk@Sun.COM */ 582*8023SPhil.Kirk@Sun.COM static void 583*8023SPhil.Kirk@Sun.COM pf_compare_zoneid(int offset, uint64_t val) 584*8023SPhil.Kirk@Sun.COM { 585*8023SPhil.Kirk@Sun.COM int i; 586*8023SPhil.Kirk@Sun.COM 587*8023SPhil.Kirk@Sun.COM for (i = 0; i < sizeof (uint64_t) / 2; i ++) { 588*8023SPhil.Kirk@Sun.COM pf_emit(ENF_PUSHWORD + offset / 2 + i); 589*8023SPhil.Kirk@Sun.COM pf_emit(ENF_PUSHLIT | ENF_EQ); 590*8023SPhil.Kirk@Sun.COM pf_emit(((uint16_t *)&val)[i]); 591*8023SPhil.Kirk@Sun.COM if (i != 0) 592*8023SPhil.Kirk@Sun.COM pf_emit(ENF_AND); 593*8023SPhil.Kirk@Sun.COM } 594*8023SPhil.Kirk@Sun.COM } 595*8023SPhil.Kirk@Sun.COM 596*8023SPhil.Kirk@Sun.COM /* 5970Sstevel@tonic-gate * Generate pf code to match an IPv4 or IPv6 address. 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate static void 6000Sstevel@tonic-gate pf_ipaddr_match(which, hostname, inet_type) 6010Sstevel@tonic-gate enum direction which; 6020Sstevel@tonic-gate char *hostname; 6030Sstevel@tonic-gate int inet_type; 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate bool_t found_host; 6060Sstevel@tonic-gate uint_t *addr4ptr; 6070Sstevel@tonic-gate uint_t addr4; 6080Sstevel@tonic-gate struct in6_addr *addr6ptr; 6090Sstevel@tonic-gate int h_addr_index; 6100Sstevel@tonic-gate struct hostent *hp = NULL; 6110Sstevel@tonic-gate int error_num = 0; 6120Sstevel@tonic-gate boolean_t first = B_TRUE; 6130Sstevel@tonic-gate int pass = 0; 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * The addr4offset and addr6offset variables simplify the code which 6170Sstevel@tonic-gate * generates the address comparison filter. With these two variables, 6180Sstevel@tonic-gate * duplicate code need not exist for the TO and FROM case. 6190Sstevel@tonic-gate * A value of -1 describes the ANY case (TO and FROM). 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate int addr4offset; 6220Sstevel@tonic-gate int addr6offset; 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate found_host = 0; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate if (tokentype == ADDR_IP) { 6270Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 6280Sstevel@tonic-gate if (hp == NULL) { 6290Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6300Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6310Sstevel@tonic-gate hostname); 6320Sstevel@tonic-gate } else { 6330Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate inet_type = IPV4_ONLY; 6370Sstevel@tonic-gate } else if (tokentype == ADDR_IP6) { 6380Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 6390Sstevel@tonic-gate if (hp == NULL) { 6400Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6410Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6420Sstevel@tonic-gate hostname); 6430Sstevel@tonic-gate } else { 6440Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate inet_type = IPV6_ONLY; 6480Sstevel@tonic-gate } else if (tokentype == ALPHA) { 6490Sstevel@tonic-gate /* Some hostname i.e. tokentype is ALPHA */ 6500Sstevel@tonic-gate switch (inet_type) { 6510Sstevel@tonic-gate case IPV4_ONLY: 6520Sstevel@tonic-gate /* Only IPv4 address is needed */ 6530Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 6540Sstevel@tonic-gate if (hp != NULL) { 6550Sstevel@tonic-gate found_host = 1; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate case IPV6_ONLY: 6590Sstevel@tonic-gate /* Only IPv6 address is needed */ 6600Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 6610Sstevel@tonic-gate if (hp != NULL) { 6620Sstevel@tonic-gate found_host = 1; 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate break; 6650Sstevel@tonic-gate case IPV4_AND_IPV6: 6660Sstevel@tonic-gate /* Both IPv4 and IPv6 are needed */ 6670Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 6680Sstevel@tonic-gate AI_ALL | AI_V4MAPPED, &error_num); 6690Sstevel@tonic-gate if (hp != NULL) { 6700Sstevel@tonic-gate found_host = 1; 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate break; 6730Sstevel@tonic-gate default: 6740Sstevel@tonic-gate found_host = 0; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate if (!found_host) { 6780Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6790Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6800Sstevel@tonic-gate hostname); 6810Sstevel@tonic-gate } else { 6820Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate } else { 6860Sstevel@tonic-gate pr_err("unknown token type: %s", hostname); 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate switch (which) { 6900Sstevel@tonic-gate case TO: 6910Sstevel@tonic-gate addr4offset = IPV4_DSTADDR_OFFSET; 6920Sstevel@tonic-gate addr6offset = IPV6_DSTADDR_OFFSET; 6930Sstevel@tonic-gate break; 6940Sstevel@tonic-gate case FROM: 6950Sstevel@tonic-gate addr4offset = IPV4_SRCADDR_OFFSET; 6960Sstevel@tonic-gate addr6offset = IPV6_SRCADDR_OFFSET; 6970Sstevel@tonic-gate break; 6980Sstevel@tonic-gate case ANY: 6990Sstevel@tonic-gate addr4offset = -1; 7000Sstevel@tonic-gate addr6offset = -1; 7010Sstevel@tonic-gate break; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if (hp != NULL && hp->h_addrtype == AF_INET) { 705*8023SPhil.Kirk@Sun.COM for (; dl.dl_net_map_tbl->nmt_val != -1; 706*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl++) { 707*8023SPhil.Kirk@Sun.COM if (strcmp("ip", 708*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl->nmt_name) == 0) { 709*8023SPhil.Kirk@Sun.COM dl.dl_match_fn( 710*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl->nmt_val); 711*8023SPhil.Kirk@Sun.COM } 712*8023SPhil.Kirk@Sun.COM } 713*8023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) 714*8023SPhil.Kirk@Sun.COM pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 7150Sstevel@tonic-gate h_addr_index = 0; 7160Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; 7170Sstevel@tonic-gate while (addr4ptr != NULL) { 7180Sstevel@tonic-gate if (addr4offset == -1) { 7190Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 7200Sstevel@tonic-gate *addr4ptr); 7210Sstevel@tonic-gate if (h_addr_index != 0) 7220Sstevel@tonic-gate pf_emit(ENF_OR); 7230Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 7240Sstevel@tonic-gate *addr4ptr); 7250Sstevel@tonic-gate pf_emit(ENF_OR); 7260Sstevel@tonic-gate } else { 7270Sstevel@tonic-gate pf_compare_value(addr4offset, 4, 7280Sstevel@tonic-gate *addr4ptr); 7290Sstevel@tonic-gate if (h_addr_index != 0) 7300Sstevel@tonic-gate pf_emit(ENF_OR); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index]; 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate pf_emit(ENF_AND); 7350Sstevel@tonic-gate } else { 7360Sstevel@tonic-gate /* first pass: IPv4 addresses */ 7370Sstevel@tonic-gate h_addr_index = 0; 7380Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 7390Sstevel@tonic-gate first = B_TRUE; 7400Sstevel@tonic-gate while (addr6ptr != NULL) { 7410Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 7420Sstevel@tonic-gate if (first) { 743*8023SPhil.Kirk@Sun.COM for (; dl.dl_net_map_tbl->nmt_val != -1; 744*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl++) { 745*8023SPhil.Kirk@Sun.COM if (strcmp("ip", 746*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl-> 747*8023SPhil.Kirk@Sun.COM nmt_name) == 0) { 748*8023SPhil.Kirk@Sun.COM dl.dl_match_fn( 749*8023SPhil.Kirk@Sun.COM dl. 750*8023SPhil.Kirk@Sun.COM dl_net_map_tbl-> 751*8023SPhil.Kirk@Sun.COM nmt_val); 752*8023SPhil.Kirk@Sun.COM } 753*8023SPhil.Kirk@Sun.COM } 754*8023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) { 755*8023SPhil.Kirk@Sun.COM pf_check_vlan_tag( 756*8023SPhil.Kirk@Sun.COM ENCAP_ETHERTYPE_OFF/2); 757*8023SPhil.Kirk@Sun.COM } 7580Sstevel@tonic-gate pass++; 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(addr6ptr, 7610Sstevel@tonic-gate (struct in_addr *)&addr4); 7620Sstevel@tonic-gate if (addr4offset == -1) { 7630Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 7640Sstevel@tonic-gate addr4); 7650Sstevel@tonic-gate if (!first) 7660Sstevel@tonic-gate pf_emit(ENF_OR); 7670Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 7680Sstevel@tonic-gate addr4); 7690Sstevel@tonic-gate pf_emit(ENF_OR); 7700Sstevel@tonic-gate } else { 7710Sstevel@tonic-gate pf_compare_value(addr4offset, 4, 7720Sstevel@tonic-gate addr4); 7730Sstevel@tonic-gate if (!first) 7740Sstevel@tonic-gate pf_emit(ENF_OR); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate if (first) 7770Sstevel@tonic-gate first = B_FALSE; 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate addr6ptr = (struct in6_addr *) 7800Sstevel@tonic-gate hp->h_addr_list[++h_addr_index]; 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate if (!first) { 7830Sstevel@tonic-gate pf_emit(ENF_AND); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate /* second pass: IPv6 addresses */ 7860Sstevel@tonic-gate h_addr_index = 0; 7870Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 7880Sstevel@tonic-gate first = B_TRUE; 7890Sstevel@tonic-gate while (addr6ptr != NULL) { 7900Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 7910Sstevel@tonic-gate if (first) { 792*8023SPhil.Kirk@Sun.COM for (; dl.dl_net_map_tbl->nmt_val != -1; 793*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl++) { 794*8023SPhil.Kirk@Sun.COM if (strcmp("ip6", 795*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl-> 796*8023SPhil.Kirk@Sun.COM nmt_name) == 0) { 797*8023SPhil.Kirk@Sun.COM dl.dl_match_fn( 798*8023SPhil.Kirk@Sun.COM dl. 799*8023SPhil.Kirk@Sun.COM dl_net_map_tbl-> 800*8023SPhil.Kirk@Sun.COM nmt_val); 801*8023SPhil.Kirk@Sun.COM } 802*8023SPhil.Kirk@Sun.COM } 803*8023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) { 804*8023SPhil.Kirk@Sun.COM pf_check_vlan_tag( 805*8023SPhil.Kirk@Sun.COM ENCAP_ETHERTYPE_OFF/2); 806*8023SPhil.Kirk@Sun.COM } 8070Sstevel@tonic-gate pass++; 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate if (addr6offset == -1) { 8100Sstevel@tonic-gate pf_compare_value_v6(IPV6_SRCADDR_OFFSET, 8110Sstevel@tonic-gate 16, *addr6ptr); 8120Sstevel@tonic-gate if (!first) 8130Sstevel@tonic-gate pf_emit(ENF_OR); 8140Sstevel@tonic-gate pf_compare_value_v6(IPV6_DSTADDR_OFFSET, 8150Sstevel@tonic-gate 16, *addr6ptr); 8160Sstevel@tonic-gate pf_emit(ENF_OR); 8170Sstevel@tonic-gate } else { 8180Sstevel@tonic-gate pf_compare_value_v6(addr6offset, 16, 8190Sstevel@tonic-gate *addr6ptr); 8200Sstevel@tonic-gate if (!first) 8210Sstevel@tonic-gate pf_emit(ENF_OR); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate if (first) 8240Sstevel@tonic-gate first = B_FALSE; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate addr6ptr = (struct in6_addr *) 8270Sstevel@tonic-gate hp->h_addr_list[++h_addr_index]; 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate if (!first) { 8300Sstevel@tonic-gate pf_emit(ENF_AND); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate if (pass == 2) { 8330Sstevel@tonic-gate pf_emit(ENF_OR); 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate if (hp != NULL) { 8380Sstevel@tonic-gate freehostent(hp); 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate static void 8440Sstevel@tonic-gate pf_compare_address(int offset, uint_t len, uchar_t *addr) 8450Sstevel@tonic-gate { 8460Sstevel@tonic-gate uint32_t val; 8470Sstevel@tonic-gate uint16_t sval; 8480Sstevel@tonic-gate boolean_t didone = B_FALSE; 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * If the property being filtered on is absent in the media 8520Sstevel@tonic-gate * packet, error out. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate if (offset == -1) 8550Sstevel@tonic-gate pr_err("filter option unsupported on media"); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate while (len > 0) { 8580Sstevel@tonic-gate if (len >= 4) { 8590Sstevel@tonic-gate (void) memcpy(&val, addr, 4); 8600Sstevel@tonic-gate pf_compare_value(offset, 4, val); 8610Sstevel@tonic-gate addr += 4; 8620Sstevel@tonic-gate offset += 4; 8630Sstevel@tonic-gate len -= 4; 8640Sstevel@tonic-gate } else if (len >= 2) { 8650Sstevel@tonic-gate (void) memcpy(&sval, addr, 2); 8660Sstevel@tonic-gate pf_compare_value(offset, 2, sval); 8670Sstevel@tonic-gate addr += 2; 8680Sstevel@tonic-gate offset += 2; 8690Sstevel@tonic-gate len -= 2; 8700Sstevel@tonic-gate } else { 8710Sstevel@tonic-gate pf_compare_value(offset++, 1, *addr++); 8720Sstevel@tonic-gate len--; 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate if (didone) 8750Sstevel@tonic-gate pf_emit(ENF_AND); 8760Sstevel@tonic-gate didone = B_TRUE; 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate /* 8810Sstevel@tonic-gate * Compare ethernet addresses. 8820Sstevel@tonic-gate */ 8830Sstevel@tonic-gate static void 8840Sstevel@tonic-gate pf_etheraddr_match(which, hostname) 8850Sstevel@tonic-gate enum direction which; 8860Sstevel@tonic-gate char *hostname; 8870Sstevel@tonic-gate { 8880Sstevel@tonic-gate struct ether_addr e, *ep = NULL; 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate if (isxdigit(*hostname)) 8910Sstevel@tonic-gate ep = ether_aton(hostname); 8920Sstevel@tonic-gate if (ep == NULL) { 8930Sstevel@tonic-gate if (ether_hostton(hostname, &e)) 8940Sstevel@tonic-gate if (!arp_for_ether(hostname, &e)) 8950Sstevel@tonic-gate pr_err("cannot obtain ether addr for %s", 8960Sstevel@tonic-gate hostname); 8970Sstevel@tonic-gate ep = &e; 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9002760Sdg199075 pf_clear_offset_register(); 9012760Sdg199075 9020Sstevel@tonic-gate switch (which) { 9030Sstevel@tonic-gate case TO: 904*8023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 9050Sstevel@tonic-gate (uchar_t *)ep); 9060Sstevel@tonic-gate break; 9070Sstevel@tonic-gate case FROM: 908*8023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 9090Sstevel@tonic-gate (uchar_t *)ep); 9100Sstevel@tonic-gate break; 9110Sstevel@tonic-gate case ANY: 912*8023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 9130Sstevel@tonic-gate (uchar_t *)ep); 914*8023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 9150Sstevel@tonic-gate (uchar_t *)ep); 9160Sstevel@tonic-gate pf_emit(ENF_OR); 9170Sstevel@tonic-gate break; 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate /* 9220Sstevel@tonic-gate * Emit code to compare the network part of 9230Sstevel@tonic-gate * an IP address. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate static void 9260Sstevel@tonic-gate pf_netaddr_match(which, netname) 9270Sstevel@tonic-gate enum direction which; 9280Sstevel@tonic-gate char *netname; 9290Sstevel@tonic-gate { 9300Sstevel@tonic-gate uint_t addr; 9310Sstevel@tonic-gate uint_t mask = 0xff000000; 9320Sstevel@tonic-gate struct netent *np; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate if (isdigit(*netname)) { 9350Sstevel@tonic-gate addr = inet_network(netname); 9360Sstevel@tonic-gate } else { 9370Sstevel@tonic-gate np = getnetbyname(netname); 9380Sstevel@tonic-gate if (np == NULL) 9390Sstevel@tonic-gate pr_err("net %s not known", netname); 9400Sstevel@tonic-gate addr = np->n_net; 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate /* 9440Sstevel@tonic-gate * Left justify the address and figure 9450Sstevel@tonic-gate * out a mask based on the supplied address. 9460Sstevel@tonic-gate * Set the mask according to the number of zero 9470Sstevel@tonic-gate * low-order bytes. 9480Sstevel@tonic-gate * Note: this works only for whole octet masks. 9490Sstevel@tonic-gate */ 9500Sstevel@tonic-gate if (addr) { 9510Sstevel@tonic-gate while ((addr & ~mask) != 0) { 9520Sstevel@tonic-gate mask |= (mask >> 8); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9562760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 9572760Sdg199075 9580Sstevel@tonic-gate switch (which) { 9590Sstevel@tonic-gate case TO: 9600Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 9610Sstevel@tonic-gate break; 9620Sstevel@tonic-gate case FROM: 9630Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 9640Sstevel@tonic-gate break; 9650Sstevel@tonic-gate case ANY: 9660Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 9670Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 9680Sstevel@tonic-gate pf_emit(ENF_OR); 9690Sstevel@tonic-gate break; 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9732760Sdg199075 /* 974*8023SPhil.Kirk@Sun.COM * Emit code to match on src or destination zoneid. 975*8023SPhil.Kirk@Sun.COM * The zoneid passed in is in network byte order. 976*8023SPhil.Kirk@Sun.COM */ 977*8023SPhil.Kirk@Sun.COM static void 978*8023SPhil.Kirk@Sun.COM pf_match_zone(enum direction which, uint64_t zoneid) 979*8023SPhil.Kirk@Sun.COM { 980*8023SPhil.Kirk@Sun.COM if (dl.dl_type != DL_IPNET) 981*8023SPhil.Kirk@Sun.COM pr_err("zone filter option unsupported on media"); 982*8023SPhil.Kirk@Sun.COM 983*8023SPhil.Kirk@Sun.COM switch (which) { 984*8023SPhil.Kirk@Sun.COM case TO: 985*8023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 986*8023SPhil.Kirk@Sun.COM break; 987*8023SPhil.Kirk@Sun.COM case FROM: 988*8023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 989*8023SPhil.Kirk@Sun.COM break; 990*8023SPhil.Kirk@Sun.COM case ANY: 991*8023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 992*8023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 993*8023SPhil.Kirk@Sun.COM pf_emit(ENF_OR); 994*8023SPhil.Kirk@Sun.COM break; 995*8023SPhil.Kirk@Sun.COM } 996*8023SPhil.Kirk@Sun.COM } 997*8023SPhil.Kirk@Sun.COM 998*8023SPhil.Kirk@Sun.COM /* 9992760Sdg199075 * A helper function to keep the code to emit instructions 10002760Sdg199075 * to change the offset register in one place. 10012760Sdg199075 * 10022760Sdg199075 * INPUTS: offset - An value representing an offset in 16-bit 10032760Sdg199075 * words. 10042760Sdg199075 * OUTPUTS: If there is enough room in the storage for the 10052760Sdg199075 * packet filtering program, instructions to load 10062760Sdg199075 * a constant to the offset register. Otherwise, 10072760Sdg199075 * nothing. 10082760Sdg199075 */ 10092760Sdg199075 static void 10102760Sdg199075 pf_emit_load_offset(uint_t offset) 10112760Sdg199075 { 10122760Sdg199075 pf_emit(ENF_LOAD_OFFSET | ENF_NOP); 10132760Sdg199075 pf_emit(offset); 10142760Sdg199075 } 10152760Sdg199075 10162760Sdg199075 /* 10172760Sdg199075 * Clear pfmod's offset register. 10182760Sdg199075 * 10192760Sdg199075 * INPUTS: none 10202760Sdg199075 * OUTPUTS: Instructions to clear the offset register if 10212760Sdg199075 * there is enough space remaining in the packet 10222760Sdg199075 * filtering program structure's storage, and 10232760Sdg199075 * the last thing done to the offset register was 10242760Sdg199075 * not clearing the offset register. Otherwise, 10252760Sdg199075 * nothing. 10262760Sdg199075 */ 10272760Sdg199075 static void 10282760Sdg199075 pf_clear_offset_register() 10292760Sdg199075 { 10302760Sdg199075 if (last_offset_operation != (void*)pf_clear_offset_register) { 10312760Sdg199075 pf_emit_load_offset(0); 10322760Sdg199075 last_offset_operation = (void*)pf_clear_offset_register; 10332760Sdg199075 } 10342760Sdg199075 } 10352760Sdg199075 10362760Sdg199075 /* 10372760Sdg199075 * This function will issue opcodes to check if a packet 10382760Sdg199075 * is VLAN tagged, and if so, update the offset register 10392760Sdg199075 * with the appropriate offset. 10402760Sdg199075 * 10412760Sdg199075 * Note that if the packet is not VLAN tagged, then the offset 10422760Sdg199075 * register will be cleared. 10432760Sdg199075 * 10442760Sdg199075 * If the interface type is not an ethernet type, then this 10452760Sdg199075 * function returns without doing anything. 10462760Sdg199075 * 10472760Sdg199075 * If the last attempt to change the offset register occured because 10482760Sdg199075 * of a call to this function that was called with the same offset, 10492760Sdg199075 * then we don't issue packet filtering instructions. 10502760Sdg199075 * 10512760Sdg199075 * INPUTS: offset - an offset in 16 bit words. The function 10522760Sdg199075 * will set the offset register to this 10532760Sdg199075 * value if the packet is VLAN tagged. 10542760Sdg199075 * OUTPUTS: If the conditions are met, packet filtering instructions. 10552760Sdg199075 */ 10562760Sdg199075 static void 10572760Sdg199075 pf_check_vlan_tag(uint_t offset) 10582760Sdg199075 { 10592760Sdg199075 static uint_t last_offset = 0; 10602760Sdg199075 10612760Sdg199075 if ((interface->mac_type == DL_ETHER || 10622760Sdg199075 interface->mac_type == DL_CSMACD) && 10632760Sdg199075 (last_offset_operation != (void*)pf_check_vlan_tag || 10642760Sdg199075 last_offset != offset)) { 10652760Sdg199075 /* 10662760Sdg199075 * First thing is to clear the offset register. 10672760Sdg199075 * We don't know what state it is in, and if it 10682760Sdg199075 * is not zero, then we have no idea what we load 10692760Sdg199075 * when we execute ENF_PUSHWORD. 10702760Sdg199075 */ 10712760Sdg199075 pf_clear_offset_register(); 10722760Sdg199075 10732760Sdg199075 /* 10742760Sdg199075 * Check the ethertype. 10752760Sdg199075 */ 1076*8023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, 1077*8023SPhil.Kirk@Sun.COM htons(ETHERTYPE_VLAN)); 10782760Sdg199075 10792760Sdg199075 /* 10802760Sdg199075 * And if it's not VLAN, don't load offset to the offset 10812760Sdg199075 * register. 10822760Sdg199075 */ 10832760Sdg199075 pf_emit(ENF_BRFL | ENF_NOP); 10842760Sdg199075 pf_emit(3); 10852760Sdg199075 10862760Sdg199075 /* 10872760Sdg199075 * Otherwise, load offset to the offset register. 10882760Sdg199075 */ 10892760Sdg199075 pf_emit_load_offset(offset); 10902760Sdg199075 10912760Sdg199075 /* 10922760Sdg199075 * Now get rid of the results of the comparison, 10932760Sdg199075 * we don't want the results of the comparison to affect 10942760Sdg199075 * other logic in the packet filtering program. 10952760Sdg199075 */ 10962760Sdg199075 pf_emit(ENF_POP | ENF_NOP); 10972760Sdg199075 10982760Sdg199075 /* 10992760Sdg199075 * Set the last operation at the end, or any time 11002760Sdg199075 * after the call to pf_clear_offset because 11012760Sdg199075 * pf_clear_offset uses it. 11022760Sdg199075 */ 11032760Sdg199075 last_offset_operation = (void*)pf_check_vlan_tag; 11042760Sdg199075 last_offset = offset; 11052760Sdg199075 } 11062760Sdg199075 } 11072760Sdg199075 11082760Sdg199075 /* 11092760Sdg199075 * Utility function used to emit packet filtering code 11102760Sdg199075 * to match an ethertype. 11112760Sdg199075 * 11122760Sdg199075 * INPUTS: ethertype - The ethertype we want to check for. 11132760Sdg199075 * Don't call htons on the ethertype before 11142760Sdg199075 * calling this function. 11152760Sdg199075 * OUTPUTS: If there is sufficient storage available, packet 11162760Sdg199075 * filtering code to check an ethertype. Otherwise, 11172760Sdg199075 * nothing. 11182760Sdg199075 */ 11192760Sdg199075 static void 11202760Sdg199075 pf_match_ethertype(uint_t ethertype) 11212760Sdg199075 { 11222760Sdg199075 /* 11232760Sdg199075 * If the user wants to filter on ethertype VLAN, 11242760Sdg199075 * then clear the offset register so that the offset 11252760Sdg199075 * for ENF_PUSHWORD points to the right place in the 11262760Sdg199075 * packet. 11272760Sdg199075 * 11282760Sdg199075 * Otherwise, call pf_check_vlan_tag to set the offset 11292760Sdg199075 * register such that the contents of the offset register 11302760Sdg199075 * plus the argument for ENF_PUSHWORD point to the right 11312760Sdg199075 * part of the packet, whether or not the packet is VLAN 11322760Sdg199075 * tagged. We call pf_check_vlan_tag with an offset of 11332760Sdg199075 * two words because if the packet is VLAN tagged, we have 11342760Sdg199075 * to move past the ethertype in the ethernet header, and 11352760Sdg199075 * past the lower two octets of the VLAN header to get to 11362760Sdg199075 * the ethertype in the VLAN header. 11372760Sdg199075 */ 11382760Sdg199075 if (ethertype == ETHERTYPE_VLAN) 11392760Sdg199075 pf_clear_offset_register(); 11402760Sdg199075 else 11412760Sdg199075 pf_check_vlan_tag(2); 11422760Sdg199075 1143*8023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype)); 11442760Sdg199075 } 11452760Sdg199075 1146*8023SPhil.Kirk@Sun.COM static void 1147*8023SPhil.Kirk@Sun.COM pf_match_ipnettype(uint_t type) 1148*8023SPhil.Kirk@Sun.COM { 1149*8023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 1150*8023SPhil.Kirk@Sun.COM } 11512760Sdg199075 1152*8023SPhil.Kirk@Sun.COM static void 1153*8023SPhil.Kirk@Sun.COM pf_match_ibtype(uint_t type) 1154*8023SPhil.Kirk@Sun.COM { 1155*8023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 1156*8023SPhil.Kirk@Sun.COM } 11572760Sdg199075 11582760Sdg199075 /* 11592760Sdg199075 * This function uses the table above to generate a 11602760Sdg199075 * piece of a packet filtering program to check a transport 11612760Sdg199075 * protocol type. 11622760Sdg199075 * 11632760Sdg199075 * INPUTS: tranport_protocol - the transport protocol we're 11642760Sdg199075 * interested in. 11652760Sdg199075 * OUTPUTS: If there is sufficient storage, then packet filtering 11662760Sdg199075 * code to check a transport protocol type. Otherwise, 11672760Sdg199075 * nothing. 11682760Sdg199075 */ 11692760Sdg199075 static void 11702760Sdg199075 pf_check_transport_protocol(uint_t transport_protocol) 11712760Sdg199075 { 11722760Sdg199075 int i = 0; 11732760Sdg199075 uint_t number_of_matches = 0; 11742760Sdg199075 1175*8023SPhil.Kirk@Sun.COM for (; dl.dl_transport_mapping_table->transport_protocol != -1; 1176*8023SPhil.Kirk@Sun.COM dl.dl_transport_mapping_table++) { 11772760Sdg199075 if (transport_protocol == 1178*8023SPhil.Kirk@Sun.COM (uint_t)dl.dl_transport_mapping_table->transport_protocol) { 11792760Sdg199075 number_of_matches++; 1180*8023SPhil.Kirk@Sun.COM dl.dl_match_fn(dl.dl_transport_mapping_table-> 1181*8023SPhil.Kirk@Sun.COM network_protocol); 11822760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 11832760Sdg199075 pf_compare_value( 1184*8023SPhil.Kirk@Sun.COM dl.dl_transport_mapping_table->offset + 1185*8023SPhil.Kirk@Sun.COM dl.dl_link_header_len, 1, 11866631Sss150715 transport_protocol); 11872760Sdg199075 pf_emit(ENF_AND); 11882760Sdg199075 if (number_of_matches > 1) { 11892760Sdg199075 /* 11902760Sdg199075 * Since we have two or more matches, in 11912760Sdg199075 * order to have a correct and complete 11922760Sdg199075 * program we need to OR the result of 11932760Sdg199075 * each block of comparisons together. 11942760Sdg199075 */ 11952760Sdg199075 pf_emit(ENF_OR); 11962760Sdg199075 } 11972760Sdg199075 } 11982760Sdg199075 } 11992760Sdg199075 } 12002760Sdg199075 12010Sstevel@tonic-gate static void 1202*8023SPhil.Kirk@Sun.COM pf_matchfn(char *proto) 1203*8023SPhil.Kirk@Sun.COM { 1204*8023SPhil.Kirk@Sun.COM for (; dl.dl_net_map_tbl->nmt_val != -1; dl.dl_net_map_tbl++) { 1205*8023SPhil.Kirk@Sun.COM if (strcmp(proto, dl.dl_net_map_tbl->nmt_name) == 0) 1206*8023SPhil.Kirk@Sun.COM dl.dl_match_fn(dl.dl_net_map_tbl->nmt_val); 1207*8023SPhil.Kirk@Sun.COM } 1208*8023SPhil.Kirk@Sun.COM } 1209*8023SPhil.Kirk@Sun.COM 1210*8023SPhil.Kirk@Sun.COM static void 12110Sstevel@tonic-gate pf_primary() 12120Sstevel@tonic-gate { 12130Sstevel@tonic-gate for (;;) { 12140Sstevel@tonic-gate if (tokentype == FIELD) 12150Sstevel@tonic-gate break; 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate if (EQ("ip")) { 1218*8023SPhil.Kirk@Sun.COM pf_matchfn("ip"); 12190Sstevel@tonic-gate opstack++; 12200Sstevel@tonic-gate next(); 12210Sstevel@tonic-gate break; 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate if (EQ("ip6")) { 1225*8023SPhil.Kirk@Sun.COM pf_matchfn("ip6"); 12260Sstevel@tonic-gate opstack++; 12270Sstevel@tonic-gate next(); 12280Sstevel@tonic-gate break; 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate if (EQ("pppoe")) { 1232*8023SPhil.Kirk@Sun.COM pf_matchfn("pppoe"); 12332760Sdg199075 pf_match_ethertype(ETHERTYPE_PPPOES); 12340Sstevel@tonic-gate pf_emit(ENF_OR); 12350Sstevel@tonic-gate opstack++; 12360Sstevel@tonic-gate next(); 12370Sstevel@tonic-gate break; 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (EQ("pppoed")) { 1241*8023SPhil.Kirk@Sun.COM pf_matchfn("pppoed"); 12420Sstevel@tonic-gate opstack++; 12430Sstevel@tonic-gate next(); 12440Sstevel@tonic-gate break; 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (EQ("pppoes")) { 1248*8023SPhil.Kirk@Sun.COM pf_matchfn("pppoes"); 12490Sstevel@tonic-gate opstack++; 12500Sstevel@tonic-gate next(); 12510Sstevel@tonic-gate break; 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate if (EQ("arp")) { 1255*8023SPhil.Kirk@Sun.COM pf_matchfn("arp"); 12562760Sdg199075 opstack++; 12572760Sdg199075 next(); 12582760Sdg199075 break; 12592760Sdg199075 } 12602760Sdg199075 12612760Sdg199075 if (EQ("vlan")) { 1262*8023SPhil.Kirk@Sun.COM pf_matchfn("vlan"); 12632760Sdg199075 pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2, 12642760Sdg199075 0, VLAN_ID_MASK); 12652760Sdg199075 pf_emit(ENF_AND); 12662760Sdg199075 opstack++; 12672760Sdg199075 next(); 12682760Sdg199075 break; 12692760Sdg199075 } 12702760Sdg199075 12712760Sdg199075 if (EQ("vlan-id")) { 12722760Sdg199075 next(); 12732760Sdg199075 if (tokentype != NUMBER) 12742760Sdg199075 pr_err("VLAN ID expected"); 1275*8023SPhil.Kirk@Sun.COM pf_matchfn("vlan-id"); 12762760Sdg199075 pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, 12772760Sdg199075 VLAN_ID_MASK); 12782760Sdg199075 pf_emit(ENF_AND); 12790Sstevel@tonic-gate opstack++; 12800Sstevel@tonic-gate next(); 12810Sstevel@tonic-gate break; 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate if (EQ("rarp")) { 1285*8023SPhil.Kirk@Sun.COM pf_matchfn("rarp"); 12860Sstevel@tonic-gate opstack++; 12870Sstevel@tonic-gate next(); 12880Sstevel@tonic-gate break; 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate if (EQ("tcp")) { 12922760Sdg199075 pf_check_transport_protocol(IPPROTO_TCP); 12930Sstevel@tonic-gate opstack++; 12940Sstevel@tonic-gate next(); 12950Sstevel@tonic-gate break; 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate if (EQ("udp")) { 12992760Sdg199075 pf_check_transport_protocol(IPPROTO_UDP); 13000Sstevel@tonic-gate opstack++; 13010Sstevel@tonic-gate next(); 13020Sstevel@tonic-gate break; 13030Sstevel@tonic-gate } 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate if (EQ("ospf")) { 13062760Sdg199075 pf_check_transport_protocol(IPPROTO_OSPF); 13070Sstevel@tonic-gate opstack++; 13080Sstevel@tonic-gate next(); 13090Sstevel@tonic-gate break; 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate if (EQ("sctp")) { 13142760Sdg199075 pf_check_transport_protocol(IPPROTO_SCTP); 13150Sstevel@tonic-gate opstack++; 13160Sstevel@tonic-gate next(); 13170Sstevel@tonic-gate break; 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate if (EQ("icmp")) { 13212760Sdg199075 pf_check_transport_protocol(IPPROTO_ICMP); 13220Sstevel@tonic-gate opstack++; 13230Sstevel@tonic-gate next(); 13240Sstevel@tonic-gate break; 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate if (EQ("icmp6")) { 13282760Sdg199075 pf_check_transport_protocol(IPPROTO_ICMPV6); 13290Sstevel@tonic-gate opstack++; 13300Sstevel@tonic-gate next(); 13310Sstevel@tonic-gate break; 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate if (EQ("ip-in-ip")) { 13352760Sdg199075 pf_check_transport_protocol(IPPROTO_ENCAP); 13360Sstevel@tonic-gate opstack++; 13370Sstevel@tonic-gate next(); 13380Sstevel@tonic-gate break; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate if (EQ("esp")) { 13422760Sdg199075 pf_check_transport_protocol(IPPROTO_ESP); 13430Sstevel@tonic-gate opstack++; 13440Sstevel@tonic-gate next(); 13450Sstevel@tonic-gate break; 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate if (EQ("ah")) { 13492760Sdg199075 pf_check_transport_protocol(IPPROTO_AH); 13500Sstevel@tonic-gate opstack++; 13510Sstevel@tonic-gate next(); 13520Sstevel@tonic-gate break; 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if (EQ("(")) { 13560Sstevel@tonic-gate inBrace++; 13570Sstevel@tonic-gate next(); 13580Sstevel@tonic-gate pf_expression(); 13590Sstevel@tonic-gate if (EQ(")")) { 13600Sstevel@tonic-gate if (inBrace) 13610Sstevel@tonic-gate inBraceOR--; 13620Sstevel@tonic-gate inBrace--; 13630Sstevel@tonic-gate next(); 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate break; 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate if (EQ("to") || EQ("dst")) { 13690Sstevel@tonic-gate dir = TO; 13700Sstevel@tonic-gate next(); 13710Sstevel@tonic-gate continue; 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate if (EQ("from") || EQ("src")) { 13750Sstevel@tonic-gate dir = FROM; 13760Sstevel@tonic-gate next(); 13770Sstevel@tonic-gate continue; 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate if (EQ("ether")) { 13810Sstevel@tonic-gate eaddr = 1; 13820Sstevel@tonic-gate next(); 13830Sstevel@tonic-gate continue; 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate if (EQ("inet")) { 13870Sstevel@tonic-gate next(); 13880Sstevel@tonic-gate if (EQ("host")) 13890Sstevel@tonic-gate next(); 13900Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP) 13910Sstevel@tonic-gate pr_err("host/IPv4 addr expected after inet"); 13920Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY); 13930Sstevel@tonic-gate opstack++; 13940Sstevel@tonic-gate next(); 13950Sstevel@tonic-gate break; 13960Sstevel@tonic-gate } 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate if (EQ("inet6")) { 13990Sstevel@tonic-gate next(); 14000Sstevel@tonic-gate if (EQ("host")) 14010Sstevel@tonic-gate next(); 14020Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP6) 14030Sstevel@tonic-gate pr_err("host/IPv6 addr expected after inet6"); 14040Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY); 14050Sstevel@tonic-gate opstack++; 14060Sstevel@tonic-gate next(); 14070Sstevel@tonic-gate break; 14080Sstevel@tonic-gate } 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate if (EQ("proto")) { 14110Sstevel@tonic-gate next(); 14120Sstevel@tonic-gate if (tokentype != NUMBER) 14130Sstevel@tonic-gate pr_err("IP proto type expected"); 14142760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 14153220Sdg199075 pf_compare_value( 1416*8023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1, 14173220Sdg199075 tokenval); 14180Sstevel@tonic-gate opstack++; 14190Sstevel@tonic-gate next(); 14200Sstevel@tonic-gate break; 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate 14230Sstevel@tonic-gate if (EQ("broadcast")) { 14242760Sdg199075 pf_clear_offset_register(); 1425*8023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff); 14260Sstevel@tonic-gate opstack++; 14270Sstevel@tonic-gate next(); 14280Sstevel@tonic-gate break; 14290Sstevel@tonic-gate } 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate if (EQ("multicast")) { 14322760Sdg199075 pf_clear_offset_register(); 1433*8023SPhil.Kirk@Sun.COM pf_compare_value_mask( 1434*8023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset, 1, 0x01, 0x01); 14350Sstevel@tonic-gate opstack++; 14360Sstevel@tonic-gate next(); 14370Sstevel@tonic-gate break; 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate if (EQ("ethertype")) { 14410Sstevel@tonic-gate next(); 14420Sstevel@tonic-gate if (tokentype != NUMBER) 14430Sstevel@tonic-gate pr_err("ether type expected"); 14442760Sdg199075 pf_match_ethertype(tokenval); 14450Sstevel@tonic-gate opstack++; 14460Sstevel@tonic-gate next(); 14470Sstevel@tonic-gate break; 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate if (EQ("net") || EQ("dstnet") || EQ("srcnet")) { 14510Sstevel@tonic-gate if (EQ("dstnet")) 14520Sstevel@tonic-gate dir = TO; 14530Sstevel@tonic-gate else if (EQ("srcnet")) 14540Sstevel@tonic-gate dir = FROM; 14550Sstevel@tonic-gate next(); 14560Sstevel@tonic-gate pf_netaddr_match(dir, token); 14570Sstevel@tonic-gate dir = ANY; 14580Sstevel@tonic-gate opstack++; 14590Sstevel@tonic-gate next(); 14600Sstevel@tonic-gate break; 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate 1463*8023SPhil.Kirk@Sun.COM if (EQ("zone")) { 1464*8023SPhil.Kirk@Sun.COM next(); 1465*8023SPhil.Kirk@Sun.COM if (tokentype != NUMBER) 1466*8023SPhil.Kirk@Sun.COM pr_err("zoneid expected after inet"); 1467*8023SPhil.Kirk@Sun.COM pf_match_zone(dir, BE_64((uint64_t)(tokenval))); 1468*8023SPhil.Kirk@Sun.COM opstack++; 1469*8023SPhil.Kirk@Sun.COM next(); 1470*8023SPhil.Kirk@Sun.COM break; 1471*8023SPhil.Kirk@Sun.COM } 1472*8023SPhil.Kirk@Sun.COM 14730Sstevel@tonic-gate /* 14740Sstevel@tonic-gate * Give up on anything that's obviously 14750Sstevel@tonic-gate * not a primary. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate if (EQ("and") || EQ("or") || 14780Sstevel@tonic-gate EQ("not") || EQ("decnet") || EQ("apple") || 14790Sstevel@tonic-gate EQ("length") || EQ("less") || EQ("greater") || 14800Sstevel@tonic-gate EQ("port") || EQ("srcport") || EQ("dstport") || 14810Sstevel@tonic-gate EQ("rpc") || EQ("gateway") || EQ("nofrag") || 14823431Scarlsonj EQ("bootp") || EQ("dhcp") || EQ("dhcp6") || 14833431Scarlsonj EQ("slp") || EQ("ldap")) { 14840Sstevel@tonic-gate break; 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate if (EQ("host") || EQ("between") || 14880Sstevel@tonic-gate tokentype == ALPHA || /* assume its a hostname */ 14890Sstevel@tonic-gate tokentype == ADDR_IP || 14900Sstevel@tonic-gate tokentype == ADDR_IP6 || 14910Sstevel@tonic-gate tokentype == ADDR_ETHER) { 14920Sstevel@tonic-gate if (EQ("host") || EQ("between")) 14930Sstevel@tonic-gate next(); 14940Sstevel@tonic-gate if (eaddr || tokentype == ADDR_ETHER) { 14950Sstevel@tonic-gate pf_etheraddr_match(dir, token); 14960Sstevel@tonic-gate } else if (tokentype == ALPHA) { 14970Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_AND_IPV6); 14980Sstevel@tonic-gate } else if (tokentype == ADDR_IP) { 14990Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY); 15000Sstevel@tonic-gate } else { 15010Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY); 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate dir = ANY; 15040Sstevel@tonic-gate eaddr = 0; 15050Sstevel@tonic-gate opstack++; 15060Sstevel@tonic-gate next(); 15070Sstevel@tonic-gate break; 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate break; /* unknown token */ 15110Sstevel@tonic-gate } 15120Sstevel@tonic-gate } 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate static void 15150Sstevel@tonic-gate pf_alternation() 15160Sstevel@tonic-gate { 15170Sstevel@tonic-gate int s = opstack; 15180Sstevel@tonic-gate 15190Sstevel@tonic-gate pf_primary(); 15200Sstevel@tonic-gate for (;;) { 15210Sstevel@tonic-gate if (EQ("and")) 15220Sstevel@tonic-gate next(); 15230Sstevel@tonic-gate pf_primary(); 15240Sstevel@tonic-gate if (opstack != s + 2) 15250Sstevel@tonic-gate break; 15260Sstevel@tonic-gate pf_emit(ENF_AND); 15270Sstevel@tonic-gate opstack--; 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate static void 15320Sstevel@tonic-gate pf_expression() 15330Sstevel@tonic-gate { 15340Sstevel@tonic-gate pf_alternation(); 15350Sstevel@tonic-gate while (EQ("or") || EQ(",")) { 15360Sstevel@tonic-gate if (inBrace) 15370Sstevel@tonic-gate inBraceOR++; 15380Sstevel@tonic-gate else 15390Sstevel@tonic-gate foundOR++; 15400Sstevel@tonic-gate next(); 15410Sstevel@tonic-gate pf_alternation(); 15420Sstevel@tonic-gate pf_emit(ENF_OR); 15430Sstevel@tonic-gate opstack--; 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * Attempt to compile the expression 15490Sstevel@tonic-gate * in the string "e". If we can generate 15500Sstevel@tonic-gate * pf code for it then return 1 - otherwise 15510Sstevel@tonic-gate * return 0 and leave it up to the user-level 15520Sstevel@tonic-gate * filter. 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate int 15550Sstevel@tonic-gate pf_compile(e, print) 15560Sstevel@tonic-gate char *e; 15570Sstevel@tonic-gate int print; 15580Sstevel@tonic-gate { 15590Sstevel@tonic-gate char *argstr; 15600Sstevel@tonic-gate char *sav_str, *ptr, *sav_ptr; 15610Sstevel@tonic-gate int inBr = 0, aheadOR = 0; 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate argstr = strdup(e); 15640Sstevel@tonic-gate sav_str = e; 15650Sstevel@tonic-gate tkp = argstr; 15660Sstevel@tonic-gate dir = ANY; 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate pfp = &pf.Pf_Filter[0]; 15690Sstevel@tonic-gate if (setjmp(env)) { 15700Sstevel@tonic-gate return (0); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate /* 15740Sstevel@tonic-gate * Set media specific packet offsets that this code uses. 15750Sstevel@tonic-gate */ 1576*8023SPhil.Kirk@Sun.COM if (interface->mac_type == DL_ETHER) { 1577*8023SPhil.Kirk@Sun.COM dl.dl_type = DL_ETHER; 1578*8023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ethertype; 1579*8023SPhil.Kirk@Sun.COM dl.dl_transport_mapping_table = 1580*8023SPhil.Kirk@Sun.COM ðer_transport_mapping_table[0]; 1581*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl = 1582*8023SPhil.Kirk@Sun.COM ðer_network_mapping_table[0]; 1583*8023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 14; 1584*8023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 12; 1585*8023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = 0; 1586*8023SPhil.Kirk@Sun.COM dl.dl_link_src_offset = 6; 1587*8023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = 6; 1588*8023SPhil.Kirk@Sun.COM } 1589*8023SPhil.Kirk@Sun.COM 15900Sstevel@tonic-gate if (interface->mac_type == DL_IB) { 1591*8023SPhil.Kirk@Sun.COM dl.dl_type = DL_IB; 1592*8023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 4; 1593*8023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 0; 1594*8023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 1595*8023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = 20; 1596*8023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ibtype; 1597*8023SPhil.Kirk@Sun.COM dl.dl_transport_mapping_table = 1598*8023SPhil.Kirk@Sun.COM &ib_transport_mapping_table[0]; 1599*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl = 1600*8023SPhil.Kirk@Sun.COM &ib_network_mapping_table[0]; 1601*8023SPhil.Kirk@Sun.COM } 1602*8023SPhil.Kirk@Sun.COM 1603*8023SPhil.Kirk@Sun.COM if (interface->mac_type == DL_IPNET) { 1604*8023SPhil.Kirk@Sun.COM dl.dl_type = DL_IPNET; 1605*8023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 24; 1606*8023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 0; 1607*8023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 1608*8023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = -1; 1609*8023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ipnettype; 1610*8023SPhil.Kirk@Sun.COM dl.dl_transport_mapping_table = 1611*8023SPhil.Kirk@Sun.COM &ipnet_transport_mapping_table[0]; 1612*8023SPhil.Kirk@Sun.COM dl.dl_net_map_tbl = 1613*8023SPhil.Kirk@Sun.COM &ipnet_network_mapping_table[0]; 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate next(); 16170Sstevel@tonic-gate pf_expression(); 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate if (tokentype != EOL) { 16200Sstevel@tonic-gate /* 16210Sstevel@tonic-gate * The idea here is to do as much filtering as possible in 16220Sstevel@tonic-gate * the kernel. So even if we find a token we don't understand, 16230Sstevel@tonic-gate * we try to see if we can still set up a portion of the filter 16240Sstevel@tonic-gate * in the kernel and use the userland filter to filter the 16250Sstevel@tonic-gate * remaining stuff. Obviously, if our filter expression is of 16260Sstevel@tonic-gate * type A AND B, we can filter A in kernel and then apply B 16270Sstevel@tonic-gate * to the packets that got through. The same is not true for 16280Sstevel@tonic-gate * a filter of type A OR B. We can't apply A first and then B 16290Sstevel@tonic-gate * on the packets filtered through A. 16300Sstevel@tonic-gate * 16310Sstevel@tonic-gate * (We need to keep track of the fact when we find an OR, 16320Sstevel@tonic-gate * and the fact that we are inside brackets when we find OR. 16330Sstevel@tonic-gate * The variable 'foundOR' tells us if there was an OR behind, 16340Sstevel@tonic-gate * 'inBraceOR' tells us if we found an OR before we could find 16350Sstevel@tonic-gate * the end brace i.e. ')', and variable 'aheadOR' checks if 16360Sstevel@tonic-gate * there is an OR in the expression ahead. if either of these 16370Sstevel@tonic-gate * cases become true, we can't split the filtering) 16380Sstevel@tonic-gate */ 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate if (foundOR || inBraceOR) { 16410Sstevel@tonic-gate /* FORGET IN KERNEL FILTERING */ 16420Sstevel@tonic-gate return (0); 16430Sstevel@tonic-gate } else { 16440Sstevel@tonic-gate 16450Sstevel@tonic-gate /* CHECK IF NO OR AHEAD */ 16460Sstevel@tonic-gate sav_ptr = (char *)((uintptr_t)sav_str + 16470Sstevel@tonic-gate (uintptr_t)sav_tkp - 16480Sstevel@tonic-gate (uintptr_t)argstr); 16490Sstevel@tonic-gate ptr = sav_ptr; 16500Sstevel@tonic-gate while (*ptr != '\0') { 16510Sstevel@tonic-gate switch (*ptr) { 16520Sstevel@tonic-gate case '(': 16530Sstevel@tonic-gate inBr++; 16540Sstevel@tonic-gate break; 16550Sstevel@tonic-gate case ')': 16560Sstevel@tonic-gate inBr--; 16570Sstevel@tonic-gate break; 16580Sstevel@tonic-gate case 'o': 16590Sstevel@tonic-gate case 'O': 16600Sstevel@tonic-gate if ((*(ptr + 1) == 'R' || 16610Sstevel@tonic-gate *(ptr + 1) == 'r') && !inBr) 16620Sstevel@tonic-gate aheadOR = 1; 16630Sstevel@tonic-gate break; 16640Sstevel@tonic-gate case ',': 16650Sstevel@tonic-gate if (!inBr) 16660Sstevel@tonic-gate aheadOR = 1; 16670Sstevel@tonic-gate break; 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate ptr++; 16700Sstevel@tonic-gate } 16710Sstevel@tonic-gate if (!aheadOR) { 16720Sstevel@tonic-gate /* NO OR AHEAD, SPLIT UP THE FILTERING */ 16730Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 16740Sstevel@tonic-gate pf.Pf_Priority = 5; 16750Sstevel@tonic-gate if (print) { 16760Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0], 16770Sstevel@tonic-gate pf.Pf_FilterLen); 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate compile(sav_ptr, print); 16800Sstevel@tonic-gate return (2); 16810Sstevel@tonic-gate } else 16820Sstevel@tonic-gate return (0); 16830Sstevel@tonic-gate } 16840Sstevel@tonic-gate } 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 16870Sstevel@tonic-gate pf.Pf_Priority = 5; /* unimportant, so long as > 2 */ 16880Sstevel@tonic-gate if (print) { 16890Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate return (1); 16920Sstevel@tonic-gate } 1693