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> 458023SPhil.Kirk@Sun.COM #include <inet/ip.h> 468023SPhil.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 858023SPhil.Kirk@Sun.COM typedef struct { 868023SPhil.Kirk@Sun.COM int transport_protocol; 878023SPhil.Kirk@Sun.COM int network_protocol; 888023SPhil.Kirk@Sun.COM /* 898023SPhil.Kirk@Sun.COM * offset is the offset in bytes from the beginning 908023SPhil.Kirk@Sun.COM * of the network protocol header to where the transport 918023SPhil.Kirk@Sun.COM * protocol type is. 928023SPhil.Kirk@Sun.COM */ 938023SPhil.Kirk@Sun.COM int offset; 94*8105SSebastien.Roy@Sun.COM } transport_table_t; 958023SPhil.Kirk@Sun.COM 968023SPhil.Kirk@Sun.COM typedef struct network_table { 978023SPhil.Kirk@Sun.COM char *nmt_name; 988023SPhil.Kirk@Sun.COM int nmt_val; 998023SPhil.Kirk@Sun.COM } network_table_t; 1008023SPhil.Kirk@Sun.COM 1018023SPhil.Kirk@Sun.COM static network_table_t ether_network_mapping_table[] = { 1028023SPhil.Kirk@Sun.COM { "pup", ETHERTYPE_PUP }, 1038023SPhil.Kirk@Sun.COM { "ip", ETHERTYPE_IP }, 1048023SPhil.Kirk@Sun.COM { "arp", ETHERTYPE_ARP }, 1058023SPhil.Kirk@Sun.COM { "revarp", ETHERTYPE_REVARP }, 1068023SPhil.Kirk@Sun.COM { "at", ETHERTYPE_AT }, 1078023SPhil.Kirk@Sun.COM { "aarp", ETHERTYPE_AARP }, 1088023SPhil.Kirk@Sun.COM { "vlan", ETHERTYPE_VLAN }, 1098023SPhil.Kirk@Sun.COM { "ip6", ETHERTYPE_IPV6 }, 1108023SPhil.Kirk@Sun.COM { "slow", ETHERTYPE_SLOW }, 1118023SPhil.Kirk@Sun.COM { "ppoed", ETHERTYPE_PPPOED }, 1128023SPhil.Kirk@Sun.COM { "ppoes", ETHERTYPE_PPPOES }, 1138023SPhil.Kirk@Sun.COM { "NULL", -1 } 1148023SPhil.Kirk@Sun.COM 1158023SPhil.Kirk@Sun.COM }; 1168023SPhil.Kirk@Sun.COM 1178023SPhil.Kirk@Sun.COM static network_table_t ib_network_mapping_table[] = { 1188023SPhil.Kirk@Sun.COM { "pup", ETHERTYPE_PUP }, 1198023SPhil.Kirk@Sun.COM { "ip", ETHERTYPE_IP }, 1208023SPhil.Kirk@Sun.COM { "arp", ETHERTYPE_ARP }, 1218023SPhil.Kirk@Sun.COM { "revarp", ETHERTYPE_REVARP }, 1228023SPhil.Kirk@Sun.COM { "at", ETHERTYPE_AT }, 1238023SPhil.Kirk@Sun.COM { "aarp", ETHERTYPE_AARP }, 1248023SPhil.Kirk@Sun.COM { "vlan", ETHERTYPE_VLAN }, 1258023SPhil.Kirk@Sun.COM { "ip6", ETHERTYPE_IPV6 }, 1268023SPhil.Kirk@Sun.COM { "slow", ETHERTYPE_SLOW }, 1278023SPhil.Kirk@Sun.COM { "ppoed", ETHERTYPE_PPPOED }, 1288023SPhil.Kirk@Sun.COM { "ppoes", ETHERTYPE_PPPOES }, 1298023SPhil.Kirk@Sun.COM { "NULL", -1 } 1308023SPhil.Kirk@Sun.COM 1318023SPhil.Kirk@Sun.COM }; 1328023SPhil.Kirk@Sun.COM 1338023SPhil.Kirk@Sun.COM static network_table_t ipnet_network_mapping_table[] = { 1348023SPhil.Kirk@Sun.COM { "ip", (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION) }, 1358023SPhil.Kirk@Sun.COM { "ip6", (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION) }, 1368023SPhil.Kirk@Sun.COM { "NULL", -1 } 1378023SPhil.Kirk@Sun.COM 1388023SPhil.Kirk@Sun.COM }; 1398023SPhil.Kirk@Sun.COM 140*8105SSebastien.Roy@Sun.COM static transport_table_t ether_transport_mapping_table[] = { 1418023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1428023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1438023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1448023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1458023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1468023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1478023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1488023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1498023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1508023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1518023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1528023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1538023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1548023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1558023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1568023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 1578023SPhil.Kirk@Sun.COM }; 1580Sstevel@tonic-gate 159*8105SSebastien.Roy@Sun.COM static transport_table_t ipnet_transport_mapping_table[] = { 1608023SPhil.Kirk@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1618023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1628023SPhil.Kirk@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1638023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1648023SPhil.Kirk@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1658023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1668023SPhil.Kirk@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1678023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1688023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1698023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1708023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1718023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1728023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1738023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1748023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1758023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1768023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1778023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1788023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1798023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1808023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1818023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1828023SPhil.Kirk@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1838023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1848023SPhil.Kirk@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1858023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1868023SPhil.Kirk@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION), 1878023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET}, 1888023SPhil.Kirk@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION), 1898023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET}, 1908023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 1918023SPhil.Kirk@Sun.COM }; 1928023SPhil.Kirk@Sun.COM 193*8105SSebastien.Roy@Sun.COM static transport_table_t ib_transport_mapping_table[] = { 1948023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1958023SPhil.Kirk@Sun.COM {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1968023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1978023SPhil.Kirk@Sun.COM {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 1988023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 1998023SPhil.Kirk@Sun.COM {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 2008023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 2018023SPhil.Kirk@Sun.COM {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 2028023SPhil.Kirk@Sun.COM {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 2038023SPhil.Kirk@Sun.COM {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 2048023SPhil.Kirk@Sun.COM {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 2058023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 2068023SPhil.Kirk@Sun.COM {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 2078023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 2088023SPhil.Kirk@Sun.COM {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 2098023SPhil.Kirk@Sun.COM {-1, 0, 0} /* must be the final entry */ 2108023SPhil.Kirk@Sun.COM }; 2118023SPhil.Kirk@Sun.COM 2128023SPhil.Kirk@Sun.COM typedef struct datalink { 213*8105SSebastien.Roy@Sun.COM uint_t dl_type; 214*8105SSebastien.Roy@Sun.COM void (*dl_match_fn)(uint_t datatype); 215*8105SSebastien.Roy@Sun.COM transport_table_t *dl_trans_map_tbl; 216*8105SSebastien.Roy@Sun.COM network_table_t *dl_net_map_tbl; 217*8105SSebastien.Roy@Sun.COM int dl_link_header_len; 218*8105SSebastien.Roy@Sun.COM int dl_link_type_offset; 219*8105SSebastien.Roy@Sun.COM int dl_link_dest_offset; 220*8105SSebastien.Roy@Sun.COM int dl_link_src_offset; 221*8105SSebastien.Roy@Sun.COM int dl_link_addr_len; 2228023SPhil.Kirk@Sun.COM } datalink_t; 2238023SPhil.Kirk@Sun.COM 2248023SPhil.Kirk@Sun.COM datalink_t dl; 2258023SPhil.Kirk@Sun.COM 2268023SPhil.Kirk@Sun.COM #define IPV4_SRCADDR_OFFSET (dl.dl_link_header_len + 12) 2278023SPhil.Kirk@Sun.COM #define IPV4_DSTADDR_OFFSET (dl.dl_link_header_len + 16) 2288023SPhil.Kirk@Sun.COM #define IPV6_SRCADDR_OFFSET (dl.dl_link_header_len + 8) 2298023SPhil.Kirk@Sun.COM #define IPV6_DSTADDR_OFFSET (dl.dl_link_header_len + 24) 2308023SPhil.Kirk@Sun.COM 2318023SPhil.Kirk@Sun.COM #define IPNET_SRCZONE_OFFSET 8 2328023SPhil.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); 2528023SPhil.Kirk@Sun.COM static void pf_match_ipnettype(uint_t type); 2538023SPhil.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); 257*8105SSebastien.Roy@Sun.COM static void pf_matchfn(const char *name); 2582760Sdg199075 2592760Sdg199075 /* 2602760Sdg199075 * This pointer points to the function that last generated 2612760Sdg199075 * instructions to change the offset register. It's used 2622760Sdg199075 * for comparisons to see if we need to issue more instructions 2632760Sdg199075 * to change the register. 2642760Sdg199075 * 2652760Sdg199075 * It's initialized to pf_clear_offset_register because the offset 2662760Sdg199075 * register in pfmod is initialized to zero, similar to the state 2672760Sdg199075 * it would be in after executing the instructions issued by 2682760Sdg199075 * pf_clear_offset_register. 2692760Sdg199075 */ 2702760Sdg199075 static void *last_offset_operation = (void*)pf_clear_offset_register; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate static void 2730Sstevel@tonic-gate pf_emit(x) 2740Sstevel@tonic-gate ushort_t x; 2750Sstevel@tonic-gate { 2760Sstevel@tonic-gate if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1]) 2770Sstevel@tonic-gate longjmp(env, 1); 2780Sstevel@tonic-gate *pfp++ = x; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate static void 2820Sstevel@tonic-gate pf_codeprint(code, len) 2830Sstevel@tonic-gate ushort_t *code; 2840Sstevel@tonic-gate int len; 2850Sstevel@tonic-gate { 2860Sstevel@tonic-gate ushort_t *pc; 2870Sstevel@tonic-gate ushort_t *plast = code + len; 2880Sstevel@tonic-gate int op, action; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate if (len > 0) { 2910Sstevel@tonic-gate printf("Kernel Filter:\n"); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate for (pc = code; pc < plast; pc++) { 2950Sstevel@tonic-gate printf("\t%3d: ", pc - code); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate op = *pc & 0xfc00; /* high 10 bits */ 2980Sstevel@tonic-gate action = *pc & 0x3ff; /* low 6 bits */ 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate switch (action) { 3010Sstevel@tonic-gate case ENF_PUSHLIT: 3020Sstevel@tonic-gate printf("PUSHLIT "); 3030Sstevel@tonic-gate break; 3040Sstevel@tonic-gate case ENF_PUSHZERO: 3050Sstevel@tonic-gate printf("PUSHZERO "); 3060Sstevel@tonic-gate break; 3070Sstevel@tonic-gate #ifdef ENF_PUSHONE 3080Sstevel@tonic-gate case ENF_PUSHONE: 3090Sstevel@tonic-gate printf("PUSHONE "); 3100Sstevel@tonic-gate break; 3110Sstevel@tonic-gate #endif 3120Sstevel@tonic-gate #ifdef ENF_PUSHFFFF 3130Sstevel@tonic-gate case ENF_PUSHFFFF: 3140Sstevel@tonic-gate printf("PUSHFFFF "); 3150Sstevel@tonic-gate break; 3160Sstevel@tonic-gate #endif 3170Sstevel@tonic-gate #ifdef ENF_PUSHFF00 3180Sstevel@tonic-gate case ENF_PUSHFF00: 3190Sstevel@tonic-gate printf("PUSHFF00 "); 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate #endif 3220Sstevel@tonic-gate #ifdef ENF_PUSH00FF 3230Sstevel@tonic-gate case ENF_PUSH00FF: 3240Sstevel@tonic-gate printf("PUSH00FF "); 3250Sstevel@tonic-gate break; 3260Sstevel@tonic-gate #endif 3272760Sdg199075 case ENF_LOAD_OFFSET: 3282760Sdg199075 printf("LOAD_OFFSET "); 3292760Sdg199075 break; 3302760Sdg199075 case ENF_BRTR: 3312760Sdg199075 printf("BRTR "); 3322760Sdg199075 break; 3332760Sdg199075 case ENF_BRFL: 3342760Sdg199075 printf("BRFL "); 3352760Sdg199075 break; 3362760Sdg199075 case ENF_POP: 3372760Sdg199075 printf("POP "); 3382760Sdg199075 break; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if (action >= ENF_PUSHWORD) 3420Sstevel@tonic-gate printf("PUSHWORD %d ", action - ENF_PUSHWORD); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate switch (op) { 3450Sstevel@tonic-gate case ENF_EQ: 3460Sstevel@tonic-gate printf("EQ "); 3470Sstevel@tonic-gate break; 3480Sstevel@tonic-gate case ENF_LT: 3490Sstevel@tonic-gate printf("LT "); 3500Sstevel@tonic-gate break; 3510Sstevel@tonic-gate case ENF_LE: 3520Sstevel@tonic-gate printf("LE "); 3530Sstevel@tonic-gate break; 3540Sstevel@tonic-gate case ENF_GT: 3550Sstevel@tonic-gate printf("GT "); 3560Sstevel@tonic-gate break; 3570Sstevel@tonic-gate case ENF_GE: 3580Sstevel@tonic-gate printf("GE "); 3590Sstevel@tonic-gate break; 3600Sstevel@tonic-gate case ENF_AND: 3610Sstevel@tonic-gate printf("AND "); 3620Sstevel@tonic-gate break; 3630Sstevel@tonic-gate case ENF_OR: 3640Sstevel@tonic-gate printf("OR "); 3650Sstevel@tonic-gate break; 3660Sstevel@tonic-gate case ENF_XOR: 3670Sstevel@tonic-gate printf("XOR "); 3680Sstevel@tonic-gate break; 3690Sstevel@tonic-gate case ENF_COR: 3700Sstevel@tonic-gate printf("COR "); 3710Sstevel@tonic-gate break; 3720Sstevel@tonic-gate case ENF_CAND: 3730Sstevel@tonic-gate printf("CAND "); 3740Sstevel@tonic-gate break; 3750Sstevel@tonic-gate case ENF_CNOR: 3760Sstevel@tonic-gate printf("CNOR "); 3770Sstevel@tonic-gate break; 3780Sstevel@tonic-gate case ENF_CNAND: 3790Sstevel@tonic-gate printf("CNAND "); 3800Sstevel@tonic-gate break; 3810Sstevel@tonic-gate case ENF_NEQ: 3820Sstevel@tonic-gate printf("NEQ "); 3830Sstevel@tonic-gate break; 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3862760Sdg199075 if (action == ENF_PUSHLIT || 3872760Sdg199075 action == ENF_LOAD_OFFSET || 3882760Sdg199075 action == ENF_BRTR || 3892760Sdg199075 action == ENF_BRFL) { 3900Sstevel@tonic-gate pc++; 3910Sstevel@tonic-gate printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate printf("\n"); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * Emit packet filter code to check a 4000Sstevel@tonic-gate * field in the packet for a particular value. 4010Sstevel@tonic-gate * Need different code for each field size. 4020Sstevel@tonic-gate * Since the pf can only compare 16 bit quantities 4030Sstevel@tonic-gate * we have to use masking to compare byte values. 4040Sstevel@tonic-gate * Long word (32 bit) quantities have to be done 4050Sstevel@tonic-gate * as two 16 bit comparisons. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate static void 4080Sstevel@tonic-gate pf_compare_value(int offset, uint_t len, uint_t val) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * If the property being filtered on is absent in the media 4120Sstevel@tonic-gate * packet, error out. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate if (offset == -1) 4150Sstevel@tonic-gate pr_err("filter option unsupported on media"); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate switch (len) { 4180Sstevel@tonic-gate case 1: 4190Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4200Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4210Sstevel@tonic-gate if (offset % 2) 4220Sstevel@tonic-gate #else 4230Sstevel@tonic-gate if (!(offset % 2)) 4240Sstevel@tonic-gate #endif 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate #ifdef ENF_PUSH00FF 4270Sstevel@tonic-gate pf_emit(ENF_PUSH00FF | ENF_AND); 4280Sstevel@tonic-gate #else 4290Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 4300Sstevel@tonic-gate pf_emit(0x00FF); 4310Sstevel@tonic-gate #endif 4320Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4330Sstevel@tonic-gate pf_emit(val); 4340Sstevel@tonic-gate } else { 4350Sstevel@tonic-gate #ifdef ENF_PUSHFF00 4360Sstevel@tonic-gate pf_emit(ENF_PUSHFF00 | ENF_AND); 4370Sstevel@tonic-gate #else 4380Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 4390Sstevel@tonic-gate pf_emit(0xFF00); 4400Sstevel@tonic-gate #endif 4410Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4420Sstevel@tonic-gate pf_emit(val << 8); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate case 2: 4470Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4480Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4490Sstevel@tonic-gate pf_emit((ushort_t)val); 4500Sstevel@tonic-gate break; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate case 4: 4530Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 4540Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4550Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4560Sstevel@tonic-gate pf_emit(val >> 16); 4570Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 4580Sstevel@tonic-gate pf_emit(val & 0xffff); 4590Sstevel@tonic-gate #else 4600Sstevel@tonic-gate #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined 4610Sstevel@tonic-gate #endif 4620Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 4630Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4640Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4650Sstevel@tonic-gate pf_emit(val & 0xffff); 4660Sstevel@tonic-gate #else 4670Sstevel@tonic-gate pf_emit(val >> 16); 4680Sstevel@tonic-gate #endif 4690Sstevel@tonic-gate pf_emit(ENF_AND); 4700Sstevel@tonic-gate break; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4750Sstevel@tonic-gate * same as pf_compare_value, but only for emiting code to 4760Sstevel@tonic-gate * compare ipv6 addresses. 4770Sstevel@tonic-gate */ 4780Sstevel@tonic-gate static void 4790Sstevel@tonic-gate pf_compare_value_v6(int offset, uint_t len, struct in6_addr val) 4800Sstevel@tonic-gate { 4810Sstevel@tonic-gate int i; 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate for (i = 0; i < len; i += 2) { 4840Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2 + i / 2); 4850Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ); 4860Sstevel@tonic-gate pf_emit(*(uint16_t *)&val.s6_addr[i]); 4870Sstevel@tonic-gate if (i != 0) 4880Sstevel@tonic-gate pf_emit(ENF_AND); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * Same as above except mask the field value 4952760Sdg199075 * before doing the comparison. The comparison checks 4962760Sdg199075 * to make sure the values are equal. 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate static void 4990Sstevel@tonic-gate pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) 5000Sstevel@tonic-gate { 5012760Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ); 5022760Sdg199075 } 5032760Sdg199075 5042760Sdg199075 /* 5052760Sdg199075 * Same as above except the values are compared to see if they are not 5062760Sdg199075 * equal. 5072760Sdg199075 */ 5082760Sdg199075 static void 5092760Sdg199075 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask) 5102760Sdg199075 { 5112760Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ); 5122760Sdg199075 } 5132760Sdg199075 5142760Sdg199075 /* 5152760Sdg199075 * Similar to pf_compare_value. 5162760Sdg199075 * 5172760Sdg199075 * This is the utility function that does the actual work to compare 5182760Sdg199075 * two values using a mask. The comparison operation is passed into 5192760Sdg199075 * the function. 5202760Sdg199075 */ 5212760Sdg199075 static void 5222760Sdg199075 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask, 5232760Sdg199075 uint_t op) 5242760Sdg199075 { 5250Sstevel@tonic-gate /* 5260Sstevel@tonic-gate * If the property being filtered on is absent in the media 5270Sstevel@tonic-gate * packet, error out. 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate if (offset == -1) 5300Sstevel@tonic-gate pr_err("filter option unsupported on media"); 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate switch (len) { 5330Sstevel@tonic-gate case 1: 5340Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5350Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 5360Sstevel@tonic-gate if (offset % 2) 5370Sstevel@tonic-gate #else 5380Sstevel@tonic-gate if (!offset % 2) 5390Sstevel@tonic-gate #endif 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5420Sstevel@tonic-gate pf_emit(mask & 0x00ff); 5432760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5440Sstevel@tonic-gate pf_emit(val); 5450Sstevel@tonic-gate } else { 5460Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5470Sstevel@tonic-gate pf_emit((mask << 8) & 0xff00); 5482760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5490Sstevel@tonic-gate pf_emit(val << 8); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate break; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate case 2: 5540Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5550Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5560Sstevel@tonic-gate pf_emit(htons((ushort_t)mask)); 5572760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5580Sstevel@tonic-gate pf_emit(htons((ushort_t)val)); 5590Sstevel@tonic-gate break; 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate case 4: 5620Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2); 5630Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5640Sstevel@tonic-gate pf_emit(htons((ushort_t)((mask >> 16) & 0xffff))); 5652760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5660Sstevel@tonic-gate pf_emit(htons((ushort_t)((val >> 16) & 0xffff))); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 5690Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND); 5700Sstevel@tonic-gate pf_emit(htons((ushort_t)(mask & 0xffff))); 5712760Sdg199075 pf_emit(ENF_PUSHLIT | op); 5720Sstevel@tonic-gate pf_emit(htons((ushort_t)(val & 0xffff))); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate pf_emit(ENF_AND); 5750Sstevel@tonic-gate break; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* 5808023SPhil.Kirk@Sun.COM * Like pf_compare_value() but compare on a 64-bit zoneid value. 5818023SPhil.Kirk@Sun.COM * The argument val passed in is in network byte order. 5828023SPhil.Kirk@Sun.COM */ 5838023SPhil.Kirk@Sun.COM static void 5848023SPhil.Kirk@Sun.COM pf_compare_zoneid(int offset, uint64_t val) 5858023SPhil.Kirk@Sun.COM { 5868023SPhil.Kirk@Sun.COM int i; 5878023SPhil.Kirk@Sun.COM 5888023SPhil.Kirk@Sun.COM for (i = 0; i < sizeof (uint64_t) / 2; i ++) { 5898023SPhil.Kirk@Sun.COM pf_emit(ENF_PUSHWORD + offset / 2 + i); 5908023SPhil.Kirk@Sun.COM pf_emit(ENF_PUSHLIT | ENF_EQ); 5918023SPhil.Kirk@Sun.COM pf_emit(((uint16_t *)&val)[i]); 5928023SPhil.Kirk@Sun.COM if (i != 0) 5938023SPhil.Kirk@Sun.COM pf_emit(ENF_AND); 5948023SPhil.Kirk@Sun.COM } 5958023SPhil.Kirk@Sun.COM } 5968023SPhil.Kirk@Sun.COM 5978023SPhil.Kirk@Sun.COM /* 5980Sstevel@tonic-gate * Generate pf code to match an IPv4 or IPv6 address. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate static void 6010Sstevel@tonic-gate pf_ipaddr_match(which, hostname, inet_type) 6020Sstevel@tonic-gate enum direction which; 6030Sstevel@tonic-gate char *hostname; 6040Sstevel@tonic-gate int inet_type; 6050Sstevel@tonic-gate { 6060Sstevel@tonic-gate bool_t found_host; 6070Sstevel@tonic-gate uint_t *addr4ptr; 6080Sstevel@tonic-gate uint_t addr4; 6090Sstevel@tonic-gate struct in6_addr *addr6ptr; 6100Sstevel@tonic-gate int h_addr_index; 6110Sstevel@tonic-gate struct hostent *hp = NULL; 6120Sstevel@tonic-gate int error_num = 0; 6130Sstevel@tonic-gate boolean_t first = B_TRUE; 6140Sstevel@tonic-gate int pass = 0; 615*8105SSebastien.Roy@Sun.COM int i; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * The addr4offset and addr6offset variables simplify the code which 6190Sstevel@tonic-gate * generates the address comparison filter. With these two variables, 6200Sstevel@tonic-gate * duplicate code need not exist for the TO and FROM case. 6210Sstevel@tonic-gate * A value of -1 describes the ANY case (TO and FROM). 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate int addr4offset; 6240Sstevel@tonic-gate int addr6offset; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate found_host = 0; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate if (tokentype == ADDR_IP) { 6290Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 6300Sstevel@tonic-gate if (hp == NULL) { 6310Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6320Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6330Sstevel@tonic-gate hostname); 6340Sstevel@tonic-gate } else { 6350Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate inet_type = IPV4_ONLY; 6390Sstevel@tonic-gate } else if (tokentype == ADDR_IP6) { 6400Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 6410Sstevel@tonic-gate if (hp == NULL) { 6420Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6430Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6440Sstevel@tonic-gate hostname); 6450Sstevel@tonic-gate } else { 6460Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate inet_type = IPV6_ONLY; 6500Sstevel@tonic-gate } else if (tokentype == ALPHA) { 6510Sstevel@tonic-gate /* Some hostname i.e. tokentype is ALPHA */ 6520Sstevel@tonic-gate switch (inet_type) { 6530Sstevel@tonic-gate case IPV4_ONLY: 6540Sstevel@tonic-gate /* Only IPv4 address is needed */ 6550Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 6560Sstevel@tonic-gate if (hp != NULL) { 6570Sstevel@tonic-gate found_host = 1; 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate case IPV6_ONLY: 6610Sstevel@tonic-gate /* Only IPv6 address is needed */ 6620Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 6630Sstevel@tonic-gate if (hp != NULL) { 6640Sstevel@tonic-gate found_host = 1; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate case IPV4_AND_IPV6: 6680Sstevel@tonic-gate /* Both IPv4 and IPv6 are needed */ 6690Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 6700Sstevel@tonic-gate AI_ALL | AI_V4MAPPED, &error_num); 6710Sstevel@tonic-gate if (hp != NULL) { 6720Sstevel@tonic-gate found_host = 1; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate break; 6750Sstevel@tonic-gate default: 6760Sstevel@tonic-gate found_host = 0; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (!found_host) { 6800Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 6810Sstevel@tonic-gate pr_err("could not resolve %s (try again later)", 6820Sstevel@tonic-gate hostname); 6830Sstevel@tonic-gate } else { 6840Sstevel@tonic-gate pr_err("could not resolve %s", hostname); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate } else { 6880Sstevel@tonic-gate pr_err("unknown token type: %s", hostname); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate switch (which) { 6920Sstevel@tonic-gate case TO: 6930Sstevel@tonic-gate addr4offset = IPV4_DSTADDR_OFFSET; 6940Sstevel@tonic-gate addr6offset = IPV6_DSTADDR_OFFSET; 6950Sstevel@tonic-gate break; 6960Sstevel@tonic-gate case FROM: 6970Sstevel@tonic-gate addr4offset = IPV4_SRCADDR_OFFSET; 6980Sstevel@tonic-gate addr6offset = IPV6_SRCADDR_OFFSET; 6990Sstevel@tonic-gate break; 7000Sstevel@tonic-gate case ANY: 7010Sstevel@tonic-gate addr4offset = -1; 7020Sstevel@tonic-gate addr6offset = -1; 7030Sstevel@tonic-gate break; 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate if (hp != NULL && hp->h_addrtype == AF_INET) { 707*8105SSebastien.Roy@Sun.COM pf_matchfn("ip"); 7088023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) 7098023SPhil.Kirk@Sun.COM pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 7100Sstevel@tonic-gate h_addr_index = 0; 7110Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; 7120Sstevel@tonic-gate while (addr4ptr != NULL) { 7130Sstevel@tonic-gate if (addr4offset == -1) { 7140Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 7150Sstevel@tonic-gate *addr4ptr); 7160Sstevel@tonic-gate if (h_addr_index != 0) 7170Sstevel@tonic-gate pf_emit(ENF_OR); 7180Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 7190Sstevel@tonic-gate *addr4ptr); 7200Sstevel@tonic-gate pf_emit(ENF_OR); 7210Sstevel@tonic-gate } else { 7220Sstevel@tonic-gate pf_compare_value(addr4offset, 4, 7230Sstevel@tonic-gate *addr4ptr); 7240Sstevel@tonic-gate if (h_addr_index != 0) 7250Sstevel@tonic-gate pf_emit(ENF_OR); 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index]; 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate pf_emit(ENF_AND); 7300Sstevel@tonic-gate } else { 7310Sstevel@tonic-gate /* first pass: IPv4 addresses */ 7320Sstevel@tonic-gate h_addr_index = 0; 7330Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 7340Sstevel@tonic-gate first = B_TRUE; 7350Sstevel@tonic-gate while (addr6ptr != NULL) { 7360Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 7370Sstevel@tonic-gate if (first) { 738*8105SSebastien.Roy@Sun.COM pf_matchfn("ip"); 7398023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) { 7408023SPhil.Kirk@Sun.COM pf_check_vlan_tag( 741*8105SSebastien.Roy@Sun.COM ENCAP_ETHERTYPE_OFF/2); 7428023SPhil.Kirk@Sun.COM } 7430Sstevel@tonic-gate pass++; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(addr6ptr, 7460Sstevel@tonic-gate (struct in_addr *)&addr4); 7470Sstevel@tonic-gate if (addr4offset == -1) { 7480Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 7490Sstevel@tonic-gate addr4); 7500Sstevel@tonic-gate if (!first) 7510Sstevel@tonic-gate pf_emit(ENF_OR); 7520Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 7530Sstevel@tonic-gate addr4); 7540Sstevel@tonic-gate pf_emit(ENF_OR); 7550Sstevel@tonic-gate } else { 7560Sstevel@tonic-gate pf_compare_value(addr4offset, 4, 7570Sstevel@tonic-gate addr4); 7580Sstevel@tonic-gate if (!first) 7590Sstevel@tonic-gate pf_emit(ENF_OR); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate if (first) 7620Sstevel@tonic-gate first = B_FALSE; 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate addr6ptr = (struct in6_addr *) 7650Sstevel@tonic-gate hp->h_addr_list[++h_addr_index]; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate if (!first) { 7680Sstevel@tonic-gate pf_emit(ENF_AND); 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate /* second pass: IPv6 addresses */ 7710Sstevel@tonic-gate h_addr_index = 0; 7720Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 7730Sstevel@tonic-gate first = B_TRUE; 7740Sstevel@tonic-gate while (addr6ptr != NULL) { 7750Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 7760Sstevel@tonic-gate if (first) { 777*8105SSebastien.Roy@Sun.COM pf_matchfn("ip6"); 7788023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) { 7798023SPhil.Kirk@Sun.COM pf_check_vlan_tag( 7808023SPhil.Kirk@Sun.COM ENCAP_ETHERTYPE_OFF/2); 7818023SPhil.Kirk@Sun.COM } 7820Sstevel@tonic-gate pass++; 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate if (addr6offset == -1) { 7850Sstevel@tonic-gate pf_compare_value_v6(IPV6_SRCADDR_OFFSET, 7860Sstevel@tonic-gate 16, *addr6ptr); 7870Sstevel@tonic-gate if (!first) 7880Sstevel@tonic-gate pf_emit(ENF_OR); 7890Sstevel@tonic-gate pf_compare_value_v6(IPV6_DSTADDR_OFFSET, 7900Sstevel@tonic-gate 16, *addr6ptr); 7910Sstevel@tonic-gate pf_emit(ENF_OR); 7920Sstevel@tonic-gate } else { 7930Sstevel@tonic-gate pf_compare_value_v6(addr6offset, 16, 7940Sstevel@tonic-gate *addr6ptr); 7950Sstevel@tonic-gate if (!first) 7960Sstevel@tonic-gate pf_emit(ENF_OR); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate if (first) 7990Sstevel@tonic-gate first = B_FALSE; 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate addr6ptr = (struct in6_addr *) 8020Sstevel@tonic-gate hp->h_addr_list[++h_addr_index]; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate if (!first) { 8050Sstevel@tonic-gate pf_emit(ENF_AND); 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate if (pass == 2) { 8080Sstevel@tonic-gate pf_emit(ENF_OR); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if (hp != NULL) { 8130Sstevel@tonic-gate freehostent(hp); 8140Sstevel@tonic-gate } 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate static void 8190Sstevel@tonic-gate pf_compare_address(int offset, uint_t len, uchar_t *addr) 8200Sstevel@tonic-gate { 8210Sstevel@tonic-gate uint32_t val; 8220Sstevel@tonic-gate uint16_t sval; 8230Sstevel@tonic-gate boolean_t didone = B_FALSE; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * If the property being filtered on is absent in the media 8270Sstevel@tonic-gate * packet, error out. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate if (offset == -1) 8300Sstevel@tonic-gate pr_err("filter option unsupported on media"); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate while (len > 0) { 8330Sstevel@tonic-gate if (len >= 4) { 8340Sstevel@tonic-gate (void) memcpy(&val, addr, 4); 8350Sstevel@tonic-gate pf_compare_value(offset, 4, val); 8360Sstevel@tonic-gate addr += 4; 8370Sstevel@tonic-gate offset += 4; 8380Sstevel@tonic-gate len -= 4; 8390Sstevel@tonic-gate } else if (len >= 2) { 8400Sstevel@tonic-gate (void) memcpy(&sval, addr, 2); 8410Sstevel@tonic-gate pf_compare_value(offset, 2, sval); 8420Sstevel@tonic-gate addr += 2; 8430Sstevel@tonic-gate offset += 2; 8440Sstevel@tonic-gate len -= 2; 8450Sstevel@tonic-gate } else { 8460Sstevel@tonic-gate pf_compare_value(offset++, 1, *addr++); 8470Sstevel@tonic-gate len--; 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate if (didone) 8500Sstevel@tonic-gate pf_emit(ENF_AND); 8510Sstevel@tonic-gate didone = B_TRUE; 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /* 8560Sstevel@tonic-gate * Compare ethernet addresses. 8570Sstevel@tonic-gate */ 8580Sstevel@tonic-gate static void 8590Sstevel@tonic-gate pf_etheraddr_match(which, hostname) 8600Sstevel@tonic-gate enum direction which; 8610Sstevel@tonic-gate char *hostname; 8620Sstevel@tonic-gate { 8630Sstevel@tonic-gate struct ether_addr e, *ep = NULL; 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate if (isxdigit(*hostname)) 8660Sstevel@tonic-gate ep = ether_aton(hostname); 8670Sstevel@tonic-gate if (ep == NULL) { 8680Sstevel@tonic-gate if (ether_hostton(hostname, &e)) 8690Sstevel@tonic-gate if (!arp_for_ether(hostname, &e)) 8700Sstevel@tonic-gate pr_err("cannot obtain ether addr for %s", 8710Sstevel@tonic-gate hostname); 8720Sstevel@tonic-gate ep = &e; 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8752760Sdg199075 pf_clear_offset_register(); 8762760Sdg199075 8770Sstevel@tonic-gate switch (which) { 8780Sstevel@tonic-gate case TO: 8798023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 8800Sstevel@tonic-gate (uchar_t *)ep); 8810Sstevel@tonic-gate break; 8820Sstevel@tonic-gate case FROM: 8838023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 8840Sstevel@tonic-gate (uchar_t *)ep); 8850Sstevel@tonic-gate break; 8860Sstevel@tonic-gate case ANY: 8878023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 8880Sstevel@tonic-gate (uchar_t *)ep); 8898023SPhil.Kirk@Sun.COM pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 8900Sstevel@tonic-gate (uchar_t *)ep); 8910Sstevel@tonic-gate pf_emit(ENF_OR); 8920Sstevel@tonic-gate break; 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * Emit code to compare the network part of 8980Sstevel@tonic-gate * an IP address. 8990Sstevel@tonic-gate */ 9000Sstevel@tonic-gate static void 9010Sstevel@tonic-gate pf_netaddr_match(which, netname) 9020Sstevel@tonic-gate enum direction which; 9030Sstevel@tonic-gate char *netname; 9040Sstevel@tonic-gate { 9050Sstevel@tonic-gate uint_t addr; 9060Sstevel@tonic-gate uint_t mask = 0xff000000; 9070Sstevel@tonic-gate struct netent *np; 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (isdigit(*netname)) { 9100Sstevel@tonic-gate addr = inet_network(netname); 9110Sstevel@tonic-gate } else { 9120Sstevel@tonic-gate np = getnetbyname(netname); 9130Sstevel@tonic-gate if (np == NULL) 9140Sstevel@tonic-gate pr_err("net %s not known", netname); 9150Sstevel@tonic-gate addr = np->n_net; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /* 9190Sstevel@tonic-gate * Left justify the address and figure 9200Sstevel@tonic-gate * out a mask based on the supplied address. 9210Sstevel@tonic-gate * Set the mask according to the number of zero 9220Sstevel@tonic-gate * low-order bytes. 9230Sstevel@tonic-gate * Note: this works only for whole octet masks. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate if (addr) { 9260Sstevel@tonic-gate while ((addr & ~mask) != 0) { 9270Sstevel@tonic-gate mask |= (mask >> 8); 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate 9312760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 9322760Sdg199075 9330Sstevel@tonic-gate switch (which) { 9340Sstevel@tonic-gate case TO: 9350Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 9360Sstevel@tonic-gate break; 9370Sstevel@tonic-gate case FROM: 9380Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 9390Sstevel@tonic-gate break; 9400Sstevel@tonic-gate case ANY: 9410Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 9420Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 9430Sstevel@tonic-gate pf_emit(ENF_OR); 9440Sstevel@tonic-gate break; 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9482760Sdg199075 /* 9498023SPhil.Kirk@Sun.COM * Emit code to match on src or destination zoneid. 9508023SPhil.Kirk@Sun.COM * The zoneid passed in is in network byte order. 9518023SPhil.Kirk@Sun.COM */ 9528023SPhil.Kirk@Sun.COM static void 9538023SPhil.Kirk@Sun.COM pf_match_zone(enum direction which, uint64_t zoneid) 9548023SPhil.Kirk@Sun.COM { 9558023SPhil.Kirk@Sun.COM if (dl.dl_type != DL_IPNET) 9568023SPhil.Kirk@Sun.COM pr_err("zone filter option unsupported on media"); 9578023SPhil.Kirk@Sun.COM 9588023SPhil.Kirk@Sun.COM switch (which) { 9598023SPhil.Kirk@Sun.COM case TO: 9608023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 9618023SPhil.Kirk@Sun.COM break; 9628023SPhil.Kirk@Sun.COM case FROM: 9638023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 9648023SPhil.Kirk@Sun.COM break; 9658023SPhil.Kirk@Sun.COM case ANY: 9668023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 9678023SPhil.Kirk@Sun.COM pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 9688023SPhil.Kirk@Sun.COM pf_emit(ENF_OR); 9698023SPhil.Kirk@Sun.COM break; 9708023SPhil.Kirk@Sun.COM } 9718023SPhil.Kirk@Sun.COM } 9728023SPhil.Kirk@Sun.COM 9738023SPhil.Kirk@Sun.COM /* 9742760Sdg199075 * A helper function to keep the code to emit instructions 9752760Sdg199075 * to change the offset register in one place. 9762760Sdg199075 * 9772760Sdg199075 * INPUTS: offset - An value representing an offset in 16-bit 9782760Sdg199075 * words. 9792760Sdg199075 * OUTPUTS: If there is enough room in the storage for the 9802760Sdg199075 * packet filtering program, instructions to load 9812760Sdg199075 * a constant to the offset register. Otherwise, 9822760Sdg199075 * nothing. 9832760Sdg199075 */ 9842760Sdg199075 static void 9852760Sdg199075 pf_emit_load_offset(uint_t offset) 9862760Sdg199075 { 9872760Sdg199075 pf_emit(ENF_LOAD_OFFSET | ENF_NOP); 9882760Sdg199075 pf_emit(offset); 9892760Sdg199075 } 9902760Sdg199075 9912760Sdg199075 /* 9922760Sdg199075 * Clear pfmod's offset register. 9932760Sdg199075 * 9942760Sdg199075 * INPUTS: none 9952760Sdg199075 * OUTPUTS: Instructions to clear the offset register if 9962760Sdg199075 * there is enough space remaining in the packet 9972760Sdg199075 * filtering program structure's storage, and 9982760Sdg199075 * the last thing done to the offset register was 9992760Sdg199075 * not clearing the offset register. Otherwise, 10002760Sdg199075 * nothing. 10012760Sdg199075 */ 10022760Sdg199075 static void 10032760Sdg199075 pf_clear_offset_register() 10042760Sdg199075 { 10052760Sdg199075 if (last_offset_operation != (void*)pf_clear_offset_register) { 10062760Sdg199075 pf_emit_load_offset(0); 10072760Sdg199075 last_offset_operation = (void*)pf_clear_offset_register; 10082760Sdg199075 } 10092760Sdg199075 } 10102760Sdg199075 10112760Sdg199075 /* 10122760Sdg199075 * This function will issue opcodes to check if a packet 10132760Sdg199075 * is VLAN tagged, and if so, update the offset register 10142760Sdg199075 * with the appropriate offset. 10152760Sdg199075 * 10162760Sdg199075 * Note that if the packet is not VLAN tagged, then the offset 10172760Sdg199075 * register will be cleared. 10182760Sdg199075 * 10192760Sdg199075 * If the interface type is not an ethernet type, then this 10202760Sdg199075 * function returns without doing anything. 10212760Sdg199075 * 10222760Sdg199075 * If the last attempt to change the offset register occured because 10232760Sdg199075 * of a call to this function that was called with the same offset, 10242760Sdg199075 * then we don't issue packet filtering instructions. 10252760Sdg199075 * 10262760Sdg199075 * INPUTS: offset - an offset in 16 bit words. The function 10272760Sdg199075 * will set the offset register to this 10282760Sdg199075 * value if the packet is VLAN tagged. 10292760Sdg199075 * OUTPUTS: If the conditions are met, packet filtering instructions. 10302760Sdg199075 */ 10312760Sdg199075 static void 10322760Sdg199075 pf_check_vlan_tag(uint_t offset) 10332760Sdg199075 { 10342760Sdg199075 static uint_t last_offset = 0; 10352760Sdg199075 10362760Sdg199075 if ((interface->mac_type == DL_ETHER || 10372760Sdg199075 interface->mac_type == DL_CSMACD) && 10382760Sdg199075 (last_offset_operation != (void*)pf_check_vlan_tag || 10392760Sdg199075 last_offset != offset)) { 10402760Sdg199075 /* 10412760Sdg199075 * First thing is to clear the offset register. 10422760Sdg199075 * We don't know what state it is in, and if it 10432760Sdg199075 * is not zero, then we have no idea what we load 10442760Sdg199075 * when we execute ENF_PUSHWORD. 10452760Sdg199075 */ 10462760Sdg199075 pf_clear_offset_register(); 10472760Sdg199075 10482760Sdg199075 /* 10492760Sdg199075 * Check the ethertype. 10502760Sdg199075 */ 10518023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, 10528023SPhil.Kirk@Sun.COM htons(ETHERTYPE_VLAN)); 10532760Sdg199075 10542760Sdg199075 /* 10552760Sdg199075 * And if it's not VLAN, don't load offset to the offset 10562760Sdg199075 * register. 10572760Sdg199075 */ 10582760Sdg199075 pf_emit(ENF_BRFL | ENF_NOP); 10592760Sdg199075 pf_emit(3); 10602760Sdg199075 10612760Sdg199075 /* 10622760Sdg199075 * Otherwise, load offset to the offset register. 10632760Sdg199075 */ 10642760Sdg199075 pf_emit_load_offset(offset); 10652760Sdg199075 10662760Sdg199075 /* 10672760Sdg199075 * Now get rid of the results of the comparison, 10682760Sdg199075 * we don't want the results of the comparison to affect 10692760Sdg199075 * other logic in the packet filtering program. 10702760Sdg199075 */ 10712760Sdg199075 pf_emit(ENF_POP | ENF_NOP); 10722760Sdg199075 10732760Sdg199075 /* 10742760Sdg199075 * Set the last operation at the end, or any time 10752760Sdg199075 * after the call to pf_clear_offset because 10762760Sdg199075 * pf_clear_offset uses it. 10772760Sdg199075 */ 10782760Sdg199075 last_offset_operation = (void*)pf_check_vlan_tag; 10792760Sdg199075 last_offset = offset; 10802760Sdg199075 } 10812760Sdg199075 } 10822760Sdg199075 10832760Sdg199075 /* 10842760Sdg199075 * Utility function used to emit packet filtering code 10852760Sdg199075 * to match an ethertype. 10862760Sdg199075 * 10872760Sdg199075 * INPUTS: ethertype - The ethertype we want to check for. 10882760Sdg199075 * Don't call htons on the ethertype before 10892760Sdg199075 * calling this function. 10902760Sdg199075 * OUTPUTS: If there is sufficient storage available, packet 10912760Sdg199075 * filtering code to check an ethertype. Otherwise, 10922760Sdg199075 * nothing. 10932760Sdg199075 */ 10942760Sdg199075 static void 10952760Sdg199075 pf_match_ethertype(uint_t ethertype) 10962760Sdg199075 { 10972760Sdg199075 /* 10982760Sdg199075 * If the user wants to filter on ethertype VLAN, 10992760Sdg199075 * then clear the offset register so that the offset 11002760Sdg199075 * for ENF_PUSHWORD points to the right place in the 11012760Sdg199075 * packet. 11022760Sdg199075 * 11032760Sdg199075 * Otherwise, call pf_check_vlan_tag to set the offset 11042760Sdg199075 * register such that the contents of the offset register 11052760Sdg199075 * plus the argument for ENF_PUSHWORD point to the right 11062760Sdg199075 * part of the packet, whether or not the packet is VLAN 11072760Sdg199075 * tagged. We call pf_check_vlan_tag with an offset of 11082760Sdg199075 * two words because if the packet is VLAN tagged, we have 11092760Sdg199075 * to move past the ethertype in the ethernet header, and 11102760Sdg199075 * past the lower two octets of the VLAN header to get to 11112760Sdg199075 * the ethertype in the VLAN header. 11122760Sdg199075 */ 11132760Sdg199075 if (ethertype == ETHERTYPE_VLAN) 11142760Sdg199075 pf_clear_offset_register(); 11152760Sdg199075 else 11162760Sdg199075 pf_check_vlan_tag(2); 11172760Sdg199075 11188023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype)); 11192760Sdg199075 } 11202760Sdg199075 11218023SPhil.Kirk@Sun.COM static void 11228023SPhil.Kirk@Sun.COM pf_match_ipnettype(uint_t type) 11238023SPhil.Kirk@Sun.COM { 11248023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 11258023SPhil.Kirk@Sun.COM } 11262760Sdg199075 11278023SPhil.Kirk@Sun.COM static void 11288023SPhil.Kirk@Sun.COM pf_match_ibtype(uint_t type) 11298023SPhil.Kirk@Sun.COM { 11308023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 11318023SPhil.Kirk@Sun.COM } 11322760Sdg199075 11332760Sdg199075 /* 11342760Sdg199075 * This function uses the table above to generate a 11352760Sdg199075 * piece of a packet filtering program to check a transport 11362760Sdg199075 * protocol type. 11372760Sdg199075 * 11382760Sdg199075 * INPUTS: tranport_protocol - the transport protocol we're 11392760Sdg199075 * interested in. 11402760Sdg199075 * OUTPUTS: If there is sufficient storage, then packet filtering 11412760Sdg199075 * code to check a transport protocol type. Otherwise, 11422760Sdg199075 * nothing. 11432760Sdg199075 */ 11442760Sdg199075 static void 11452760Sdg199075 pf_check_transport_protocol(uint_t transport_protocol) 11462760Sdg199075 { 1147*8105SSebastien.Roy@Sun.COM int i; 11482760Sdg199075 uint_t number_of_matches = 0; 11492760Sdg199075 1150*8105SSebastien.Roy@Sun.COM for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) { 11512760Sdg199075 if (transport_protocol == 1152*8105SSebastien.Roy@Sun.COM (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) { 11532760Sdg199075 number_of_matches++; 1154*8105SSebastien.Roy@Sun.COM dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol); 11552760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 1156*8105SSebastien.Roy@Sun.COM pf_compare_value(dl.dl_trans_map_tbl[i].offset + 11578023SPhil.Kirk@Sun.COM dl.dl_link_header_len, 1, 11586631Sss150715 transport_protocol); 11592760Sdg199075 pf_emit(ENF_AND); 11602760Sdg199075 if (number_of_matches > 1) { 11612760Sdg199075 /* 11622760Sdg199075 * Since we have two or more matches, in 11632760Sdg199075 * order to have a correct and complete 11642760Sdg199075 * program we need to OR the result of 11652760Sdg199075 * each block of comparisons together. 11662760Sdg199075 */ 11672760Sdg199075 pf_emit(ENF_OR); 11682760Sdg199075 } 11692760Sdg199075 } 11702760Sdg199075 } 11712760Sdg199075 } 11722760Sdg199075 11730Sstevel@tonic-gate static void 1174*8105SSebastien.Roy@Sun.COM pf_matchfn(const char *proto) 11758023SPhil.Kirk@Sun.COM { 1176*8105SSebastien.Roy@Sun.COM int i; 1177*8105SSebastien.Roy@Sun.COM 1178*8105SSebastien.Roy@Sun.COM for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) { 1179*8105SSebastien.Roy@Sun.COM if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) { 1180*8105SSebastien.Roy@Sun.COM dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val); 1181*8105SSebastien.Roy@Sun.COM break; 1182*8105SSebastien.Roy@Sun.COM } 11838023SPhil.Kirk@Sun.COM } 11848023SPhil.Kirk@Sun.COM } 11858023SPhil.Kirk@Sun.COM 11868023SPhil.Kirk@Sun.COM static void 11870Sstevel@tonic-gate pf_primary() 11880Sstevel@tonic-gate { 11890Sstevel@tonic-gate for (;;) { 11900Sstevel@tonic-gate if (tokentype == FIELD) 11910Sstevel@tonic-gate break; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate if (EQ("ip")) { 11948023SPhil.Kirk@Sun.COM pf_matchfn("ip"); 11950Sstevel@tonic-gate opstack++; 11960Sstevel@tonic-gate next(); 11970Sstevel@tonic-gate break; 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate if (EQ("ip6")) { 12018023SPhil.Kirk@Sun.COM pf_matchfn("ip6"); 12020Sstevel@tonic-gate opstack++; 12030Sstevel@tonic-gate next(); 12040Sstevel@tonic-gate break; 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate if (EQ("pppoe")) { 12088023SPhil.Kirk@Sun.COM pf_matchfn("pppoe"); 12092760Sdg199075 pf_match_ethertype(ETHERTYPE_PPPOES); 12100Sstevel@tonic-gate pf_emit(ENF_OR); 12110Sstevel@tonic-gate opstack++; 12120Sstevel@tonic-gate next(); 12130Sstevel@tonic-gate break; 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate if (EQ("pppoed")) { 12178023SPhil.Kirk@Sun.COM pf_matchfn("pppoed"); 12180Sstevel@tonic-gate opstack++; 12190Sstevel@tonic-gate next(); 12200Sstevel@tonic-gate break; 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate if (EQ("pppoes")) { 12248023SPhil.Kirk@Sun.COM pf_matchfn("pppoes"); 12250Sstevel@tonic-gate opstack++; 12260Sstevel@tonic-gate next(); 12270Sstevel@tonic-gate break; 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate if (EQ("arp")) { 12318023SPhil.Kirk@Sun.COM pf_matchfn("arp"); 12322760Sdg199075 opstack++; 12332760Sdg199075 next(); 12342760Sdg199075 break; 12352760Sdg199075 } 12362760Sdg199075 12372760Sdg199075 if (EQ("vlan")) { 12388023SPhil.Kirk@Sun.COM pf_matchfn("vlan"); 12392760Sdg199075 pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2, 12402760Sdg199075 0, VLAN_ID_MASK); 12412760Sdg199075 pf_emit(ENF_AND); 12422760Sdg199075 opstack++; 12432760Sdg199075 next(); 12442760Sdg199075 break; 12452760Sdg199075 } 12462760Sdg199075 12472760Sdg199075 if (EQ("vlan-id")) { 12482760Sdg199075 next(); 12492760Sdg199075 if (tokentype != NUMBER) 12502760Sdg199075 pr_err("VLAN ID expected"); 12518023SPhil.Kirk@Sun.COM pf_matchfn("vlan-id"); 12522760Sdg199075 pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, 12532760Sdg199075 VLAN_ID_MASK); 12542760Sdg199075 pf_emit(ENF_AND); 12550Sstevel@tonic-gate opstack++; 12560Sstevel@tonic-gate next(); 12570Sstevel@tonic-gate break; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate if (EQ("rarp")) { 12618023SPhil.Kirk@Sun.COM pf_matchfn("rarp"); 12620Sstevel@tonic-gate opstack++; 12630Sstevel@tonic-gate next(); 12640Sstevel@tonic-gate break; 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate if (EQ("tcp")) { 12682760Sdg199075 pf_check_transport_protocol(IPPROTO_TCP); 12690Sstevel@tonic-gate opstack++; 12700Sstevel@tonic-gate next(); 12710Sstevel@tonic-gate break; 12720Sstevel@tonic-gate } 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate if (EQ("udp")) { 12752760Sdg199075 pf_check_transport_protocol(IPPROTO_UDP); 12760Sstevel@tonic-gate opstack++; 12770Sstevel@tonic-gate next(); 12780Sstevel@tonic-gate break; 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate if (EQ("ospf")) { 12822760Sdg199075 pf_check_transport_protocol(IPPROTO_OSPF); 12830Sstevel@tonic-gate opstack++; 12840Sstevel@tonic-gate next(); 12850Sstevel@tonic-gate break; 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate if (EQ("sctp")) { 12902760Sdg199075 pf_check_transport_protocol(IPPROTO_SCTP); 12910Sstevel@tonic-gate opstack++; 12920Sstevel@tonic-gate next(); 12930Sstevel@tonic-gate break; 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate if (EQ("icmp")) { 12972760Sdg199075 pf_check_transport_protocol(IPPROTO_ICMP); 12980Sstevel@tonic-gate opstack++; 12990Sstevel@tonic-gate next(); 13000Sstevel@tonic-gate break; 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate if (EQ("icmp6")) { 13042760Sdg199075 pf_check_transport_protocol(IPPROTO_ICMPV6); 13050Sstevel@tonic-gate opstack++; 13060Sstevel@tonic-gate next(); 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate if (EQ("ip-in-ip")) { 13112760Sdg199075 pf_check_transport_protocol(IPPROTO_ENCAP); 13120Sstevel@tonic-gate opstack++; 13130Sstevel@tonic-gate next(); 13140Sstevel@tonic-gate break; 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate if (EQ("esp")) { 13182760Sdg199075 pf_check_transport_protocol(IPPROTO_ESP); 13190Sstevel@tonic-gate opstack++; 13200Sstevel@tonic-gate next(); 13210Sstevel@tonic-gate break; 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate if (EQ("ah")) { 13252760Sdg199075 pf_check_transport_protocol(IPPROTO_AH); 13260Sstevel@tonic-gate opstack++; 13270Sstevel@tonic-gate next(); 13280Sstevel@tonic-gate break; 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate if (EQ("(")) { 13320Sstevel@tonic-gate inBrace++; 13330Sstevel@tonic-gate next(); 13340Sstevel@tonic-gate pf_expression(); 13350Sstevel@tonic-gate if (EQ(")")) { 13360Sstevel@tonic-gate if (inBrace) 13370Sstevel@tonic-gate inBraceOR--; 13380Sstevel@tonic-gate inBrace--; 13390Sstevel@tonic-gate next(); 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate break; 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if (EQ("to") || EQ("dst")) { 13450Sstevel@tonic-gate dir = TO; 13460Sstevel@tonic-gate next(); 13470Sstevel@tonic-gate continue; 13480Sstevel@tonic-gate } 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate if (EQ("from") || EQ("src")) { 13510Sstevel@tonic-gate dir = FROM; 13520Sstevel@tonic-gate next(); 13530Sstevel@tonic-gate continue; 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate 13560Sstevel@tonic-gate if (EQ("ether")) { 13570Sstevel@tonic-gate eaddr = 1; 13580Sstevel@tonic-gate next(); 13590Sstevel@tonic-gate continue; 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate if (EQ("inet")) { 13630Sstevel@tonic-gate next(); 13640Sstevel@tonic-gate if (EQ("host")) 13650Sstevel@tonic-gate next(); 13660Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP) 13670Sstevel@tonic-gate pr_err("host/IPv4 addr expected after inet"); 13680Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY); 13690Sstevel@tonic-gate opstack++; 13700Sstevel@tonic-gate next(); 13710Sstevel@tonic-gate break; 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate if (EQ("inet6")) { 13750Sstevel@tonic-gate next(); 13760Sstevel@tonic-gate if (EQ("host")) 13770Sstevel@tonic-gate next(); 13780Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP6) 13790Sstevel@tonic-gate pr_err("host/IPv6 addr expected after inet6"); 13800Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY); 13810Sstevel@tonic-gate opstack++; 13820Sstevel@tonic-gate next(); 13830Sstevel@tonic-gate break; 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate if (EQ("proto")) { 13870Sstevel@tonic-gate next(); 13880Sstevel@tonic-gate if (tokentype != NUMBER) 13890Sstevel@tonic-gate pr_err("IP proto type expected"); 13902760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 13913220Sdg199075 pf_compare_value( 13928023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1, 13933220Sdg199075 tokenval); 13940Sstevel@tonic-gate opstack++; 13950Sstevel@tonic-gate next(); 13960Sstevel@tonic-gate break; 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate if (EQ("broadcast")) { 14002760Sdg199075 pf_clear_offset_register(); 14018023SPhil.Kirk@Sun.COM pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff); 14020Sstevel@tonic-gate opstack++; 14030Sstevel@tonic-gate next(); 14040Sstevel@tonic-gate break; 14050Sstevel@tonic-gate } 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate if (EQ("multicast")) { 14082760Sdg199075 pf_clear_offset_register(); 14098023SPhil.Kirk@Sun.COM pf_compare_value_mask( 14108023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset, 1, 0x01, 0x01); 14110Sstevel@tonic-gate opstack++; 14120Sstevel@tonic-gate next(); 14130Sstevel@tonic-gate break; 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate if (EQ("ethertype")) { 14170Sstevel@tonic-gate next(); 14180Sstevel@tonic-gate if (tokentype != NUMBER) 14190Sstevel@tonic-gate pr_err("ether type expected"); 14202760Sdg199075 pf_match_ethertype(tokenval); 14210Sstevel@tonic-gate opstack++; 14220Sstevel@tonic-gate next(); 14230Sstevel@tonic-gate break; 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate if (EQ("net") || EQ("dstnet") || EQ("srcnet")) { 14270Sstevel@tonic-gate if (EQ("dstnet")) 14280Sstevel@tonic-gate dir = TO; 14290Sstevel@tonic-gate else if (EQ("srcnet")) 14300Sstevel@tonic-gate dir = FROM; 14310Sstevel@tonic-gate next(); 14320Sstevel@tonic-gate pf_netaddr_match(dir, token); 14330Sstevel@tonic-gate dir = ANY; 14340Sstevel@tonic-gate opstack++; 14350Sstevel@tonic-gate next(); 14360Sstevel@tonic-gate break; 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate 14398023SPhil.Kirk@Sun.COM if (EQ("zone")) { 14408023SPhil.Kirk@Sun.COM next(); 14418023SPhil.Kirk@Sun.COM if (tokentype != NUMBER) 14428023SPhil.Kirk@Sun.COM pr_err("zoneid expected after inet"); 14438023SPhil.Kirk@Sun.COM pf_match_zone(dir, BE_64((uint64_t)(tokenval))); 14448023SPhil.Kirk@Sun.COM opstack++; 14458023SPhil.Kirk@Sun.COM next(); 14468023SPhil.Kirk@Sun.COM break; 14478023SPhil.Kirk@Sun.COM } 14488023SPhil.Kirk@Sun.COM 14490Sstevel@tonic-gate /* 14500Sstevel@tonic-gate * Give up on anything that's obviously 14510Sstevel@tonic-gate * not a primary. 14520Sstevel@tonic-gate */ 14530Sstevel@tonic-gate if (EQ("and") || EQ("or") || 14540Sstevel@tonic-gate EQ("not") || EQ("decnet") || EQ("apple") || 14550Sstevel@tonic-gate EQ("length") || EQ("less") || EQ("greater") || 14560Sstevel@tonic-gate EQ("port") || EQ("srcport") || EQ("dstport") || 14570Sstevel@tonic-gate EQ("rpc") || EQ("gateway") || EQ("nofrag") || 14583431Scarlsonj EQ("bootp") || EQ("dhcp") || EQ("dhcp6") || 14593431Scarlsonj EQ("slp") || EQ("ldap")) { 14600Sstevel@tonic-gate break; 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (EQ("host") || EQ("between") || 14640Sstevel@tonic-gate tokentype == ALPHA || /* assume its a hostname */ 14650Sstevel@tonic-gate tokentype == ADDR_IP || 14660Sstevel@tonic-gate tokentype == ADDR_IP6 || 14670Sstevel@tonic-gate tokentype == ADDR_ETHER) { 14680Sstevel@tonic-gate if (EQ("host") || EQ("between")) 14690Sstevel@tonic-gate next(); 14700Sstevel@tonic-gate if (eaddr || tokentype == ADDR_ETHER) { 14710Sstevel@tonic-gate pf_etheraddr_match(dir, token); 14720Sstevel@tonic-gate } else if (tokentype == ALPHA) { 14730Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_AND_IPV6); 14740Sstevel@tonic-gate } else if (tokentype == ADDR_IP) { 14750Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY); 14760Sstevel@tonic-gate } else { 14770Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY); 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate dir = ANY; 14800Sstevel@tonic-gate eaddr = 0; 14810Sstevel@tonic-gate opstack++; 14820Sstevel@tonic-gate next(); 14830Sstevel@tonic-gate break; 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate break; /* unknown token */ 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate } 14890Sstevel@tonic-gate 14900Sstevel@tonic-gate static void 14910Sstevel@tonic-gate pf_alternation() 14920Sstevel@tonic-gate { 14930Sstevel@tonic-gate int s = opstack; 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate pf_primary(); 14960Sstevel@tonic-gate for (;;) { 14970Sstevel@tonic-gate if (EQ("and")) 14980Sstevel@tonic-gate next(); 14990Sstevel@tonic-gate pf_primary(); 15000Sstevel@tonic-gate if (opstack != s + 2) 15010Sstevel@tonic-gate break; 15020Sstevel@tonic-gate pf_emit(ENF_AND); 15030Sstevel@tonic-gate opstack--; 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate static void 15080Sstevel@tonic-gate pf_expression() 15090Sstevel@tonic-gate { 15100Sstevel@tonic-gate pf_alternation(); 15110Sstevel@tonic-gate while (EQ("or") || EQ(",")) { 15120Sstevel@tonic-gate if (inBrace) 15130Sstevel@tonic-gate inBraceOR++; 15140Sstevel@tonic-gate else 15150Sstevel@tonic-gate foundOR++; 15160Sstevel@tonic-gate next(); 15170Sstevel@tonic-gate pf_alternation(); 15180Sstevel@tonic-gate pf_emit(ENF_OR); 15190Sstevel@tonic-gate opstack--; 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * Attempt to compile the expression 15250Sstevel@tonic-gate * in the string "e". If we can generate 15260Sstevel@tonic-gate * pf code for it then return 1 - otherwise 15270Sstevel@tonic-gate * return 0 and leave it up to the user-level 15280Sstevel@tonic-gate * filter. 15290Sstevel@tonic-gate */ 15300Sstevel@tonic-gate int 15310Sstevel@tonic-gate pf_compile(e, print) 15320Sstevel@tonic-gate char *e; 15330Sstevel@tonic-gate int print; 15340Sstevel@tonic-gate { 15350Sstevel@tonic-gate char *argstr; 15360Sstevel@tonic-gate char *sav_str, *ptr, *sav_ptr; 15370Sstevel@tonic-gate int inBr = 0, aheadOR = 0; 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate argstr = strdup(e); 15400Sstevel@tonic-gate sav_str = e; 15410Sstevel@tonic-gate tkp = argstr; 15420Sstevel@tonic-gate dir = ANY; 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate pfp = &pf.Pf_Filter[0]; 15450Sstevel@tonic-gate if (setjmp(env)) { 15460Sstevel@tonic-gate return (0); 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate /* 15500Sstevel@tonic-gate * Set media specific packet offsets that this code uses. 15510Sstevel@tonic-gate */ 15528023SPhil.Kirk@Sun.COM if (interface->mac_type == DL_ETHER) { 15538023SPhil.Kirk@Sun.COM dl.dl_type = DL_ETHER; 15548023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ethertype; 1555*8105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ether_transport_mapping_table; 1556*8105SSebastien.Roy@Sun.COM dl.dl_net_map_tbl = ether_network_mapping_table; 15578023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 14; 15588023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 12; 15598023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = 0; 15608023SPhil.Kirk@Sun.COM dl.dl_link_src_offset = 6; 15618023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = 6; 15628023SPhil.Kirk@Sun.COM } 15638023SPhil.Kirk@Sun.COM 15640Sstevel@tonic-gate if (interface->mac_type == DL_IB) { 15658023SPhil.Kirk@Sun.COM dl.dl_type = DL_IB; 15668023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 4; 15678023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 0; 15688023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 15698023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = 20; 15708023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ibtype; 1571*8105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ib_transport_mapping_table; 1572*8105SSebastien.Roy@Sun.COM dl.dl_net_map_tbl = ib_network_mapping_table; 15738023SPhil.Kirk@Sun.COM } 15748023SPhil.Kirk@Sun.COM 15758023SPhil.Kirk@Sun.COM if (interface->mac_type == DL_IPNET) { 15768023SPhil.Kirk@Sun.COM dl.dl_type = DL_IPNET; 15778023SPhil.Kirk@Sun.COM dl.dl_link_header_len = 24; 15788023SPhil.Kirk@Sun.COM dl.dl_link_type_offset = 0; 15798023SPhil.Kirk@Sun.COM dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 15808023SPhil.Kirk@Sun.COM dl.dl_link_addr_len = -1; 15818023SPhil.Kirk@Sun.COM dl.dl_match_fn = pf_match_ipnettype; 1582*8105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ipnet_transport_mapping_table; 1583*8105SSebastien.Roy@Sun.COM dl.dl_net_map_tbl = ipnet_network_mapping_table; 15840Sstevel@tonic-gate } 15850Sstevel@tonic-gate 15860Sstevel@tonic-gate next(); 15870Sstevel@tonic-gate pf_expression(); 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate if (tokentype != EOL) { 15900Sstevel@tonic-gate /* 15910Sstevel@tonic-gate * The idea here is to do as much filtering as possible in 15920Sstevel@tonic-gate * the kernel. So even if we find a token we don't understand, 15930Sstevel@tonic-gate * we try to see if we can still set up a portion of the filter 15940Sstevel@tonic-gate * in the kernel and use the userland filter to filter the 15950Sstevel@tonic-gate * remaining stuff. Obviously, if our filter expression is of 15960Sstevel@tonic-gate * type A AND B, we can filter A in kernel and then apply B 15970Sstevel@tonic-gate * to the packets that got through. The same is not true for 15980Sstevel@tonic-gate * a filter of type A OR B. We can't apply A first and then B 15990Sstevel@tonic-gate * on the packets filtered through A. 16000Sstevel@tonic-gate * 16010Sstevel@tonic-gate * (We need to keep track of the fact when we find an OR, 16020Sstevel@tonic-gate * and the fact that we are inside brackets when we find OR. 16030Sstevel@tonic-gate * The variable 'foundOR' tells us if there was an OR behind, 16040Sstevel@tonic-gate * 'inBraceOR' tells us if we found an OR before we could find 16050Sstevel@tonic-gate * the end brace i.e. ')', and variable 'aheadOR' checks if 16060Sstevel@tonic-gate * there is an OR in the expression ahead. if either of these 16070Sstevel@tonic-gate * cases become true, we can't split the filtering) 16080Sstevel@tonic-gate */ 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate if (foundOR || inBraceOR) { 16110Sstevel@tonic-gate /* FORGET IN KERNEL FILTERING */ 16120Sstevel@tonic-gate return (0); 16130Sstevel@tonic-gate } else { 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate /* CHECK IF NO OR AHEAD */ 16160Sstevel@tonic-gate sav_ptr = (char *)((uintptr_t)sav_str + 16170Sstevel@tonic-gate (uintptr_t)sav_tkp - 16180Sstevel@tonic-gate (uintptr_t)argstr); 16190Sstevel@tonic-gate ptr = sav_ptr; 16200Sstevel@tonic-gate while (*ptr != '\0') { 16210Sstevel@tonic-gate switch (*ptr) { 16220Sstevel@tonic-gate case '(': 16230Sstevel@tonic-gate inBr++; 16240Sstevel@tonic-gate break; 16250Sstevel@tonic-gate case ')': 16260Sstevel@tonic-gate inBr--; 16270Sstevel@tonic-gate break; 16280Sstevel@tonic-gate case 'o': 16290Sstevel@tonic-gate case 'O': 16300Sstevel@tonic-gate if ((*(ptr + 1) == 'R' || 16310Sstevel@tonic-gate *(ptr + 1) == 'r') && !inBr) 16320Sstevel@tonic-gate aheadOR = 1; 16330Sstevel@tonic-gate break; 16340Sstevel@tonic-gate case ',': 16350Sstevel@tonic-gate if (!inBr) 16360Sstevel@tonic-gate aheadOR = 1; 16370Sstevel@tonic-gate break; 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate ptr++; 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate if (!aheadOR) { 16420Sstevel@tonic-gate /* NO OR AHEAD, SPLIT UP THE FILTERING */ 16430Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 16440Sstevel@tonic-gate pf.Pf_Priority = 5; 16450Sstevel@tonic-gate if (print) { 16460Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0], 16470Sstevel@tonic-gate pf.Pf_FilterLen); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate compile(sav_ptr, print); 16500Sstevel@tonic-gate return (2); 16510Sstevel@tonic-gate } else 16520Sstevel@tonic-gate return (0); 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate } 16550Sstevel@tonic-gate 16560Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 16570Sstevel@tonic-gate pf.Pf_Priority = 5; /* unimportant, so long as > 2 */ 16580Sstevel@tonic-gate if (print) { 16590Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen); 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate return (1); 16620Sstevel@tonic-gate } 1663