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 /*
22*10639SDarren.Reed@Sun.COM * Copyright 2009 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;
948105SSebastien.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[] = {
134*10639SDarren.Reed@Sun.COM { "ip", (DL_IPNETINFO_VERSION << 8 | AF_INET) },
135*10639SDarren.Reed@Sun.COM { "ip6", (DL_IPNETINFO_VERSION << 8 | AF_INET6) },
1368023SPhil.Kirk@Sun.COM { "NULL", -1 }
1378023SPhil.Kirk@Sun.COM
1388023SPhil.Kirk@Sun.COM };
1398023SPhil.Kirk@Sun.COM
1408105SSebastien.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
1598105SSebastien.Roy@Sun.COM static transport_table_t ipnet_transport_mapping_table[] = {
160*10639SDarren.Reed@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1618023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
162*10639SDarren.Reed@Sun.COM {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1638023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
164*10639SDarren.Reed@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1658023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
166*10639SDarren.Reed@Sun.COM {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1678023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
168*10639SDarren.Reed@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1698023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
170*10639SDarren.Reed@Sun.COM {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1718023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
172*10639SDarren.Reed@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1738023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
174*10639SDarren.Reed@Sun.COM {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1758023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
176*10639SDarren.Reed@Sun.COM {IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1778023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
178*10639SDarren.Reed@Sun.COM {IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1798023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
180*10639SDarren.Reed@Sun.COM {IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1818023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
182*10639SDarren.Reed@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1838023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
184*10639SDarren.Reed@Sun.COM {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
1858023SPhil.Kirk@Sun.COM IPV6_TYPE_HEADER_OFFSET},
186*10639SDarren.Reed@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET),
1878023SPhil.Kirk@Sun.COM IPV4_TYPE_HEADER_OFFSET},
188*10639SDarren.Reed@Sun.COM {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
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
1938105SSebastien.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 {
2138105SSebastien.Roy@Sun.COM uint_t dl_type;
2148105SSebastien.Roy@Sun.COM void (*dl_match_fn)(uint_t datatype);
2158105SSebastien.Roy@Sun.COM transport_table_t *dl_trans_map_tbl;
2168105SSebastien.Roy@Sun.COM network_table_t *dl_net_map_tbl;
2178105SSebastien.Roy@Sun.COM int dl_link_header_len;
2188105SSebastien.Roy@Sun.COM int dl_link_type_offset;
2198105SSebastien.Roy@Sun.COM int dl_link_dest_offset;
2208105SSebastien.Roy@Sun.COM int dl_link_src_offset;
2218105SSebastien.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
231*10639SDarren.Reed@Sun.COM #define IPNET_SRCZONE_OFFSET 16
232*10639SDarren.Reed@Sun.COM #define IPNET_DSTZONE_OFFSET 20
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);
2578105SSebastien.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
pf_emit(x)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
pf_codeprint(code,len)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
pf_compare_value(int offset,uint_t len,uint_t val)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
pf_compare_value_v6(int offset,uint_t len,struct in6_addr val)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
pf_compare_value_mask(int offset,uint_t len,uint_t val,int mask)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
pf_compare_value_mask_neq(int offset,uint_t len,uint_t val,int mask)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
pf_compare_value_mask_generic(int offset,uint_t len,uint_t val,int mask,uint_t op)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 /*
580*10639SDarren.Reed@Sun.COM * Like pf_compare_value() but compare on a 32-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
pf_compare_zoneid(int offset,uint32_t val)584*10639SDarren.Reed@Sun.COM pf_compare_zoneid(int offset, uint32_t val)
5858023SPhil.Kirk@Sun.COM {
5868023SPhil.Kirk@Sun.COM int i;
5878023SPhil.Kirk@Sun.COM
588*10639SDarren.Reed@Sun.COM for (i = 0; i < sizeof (uint32_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
pf_ipaddr_match(which,hostname,inet_type)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;
6158105SSebastien.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) {
7078105SSebastien.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) {
7388105SSebastien.Roy@Sun.COM pf_matchfn("ip");
7398023SPhil.Kirk@Sun.COM if (dl.dl_type == DL_ETHER) {
7408023SPhil.Kirk@Sun.COM pf_check_vlan_tag(
7418105SSebastien.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) {
7778105SSebastien.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
pf_compare_address(int offset,uint_t len,uchar_t * addr)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
pf_etheraddr_match(which,hostname)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
pf_netaddr_match(which,netname)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
pf_match_zone(enum direction which,uint32_t zoneid)953*10639SDarren.Reed@Sun.COM pf_match_zone(enum direction which, uint32_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
pf_emit_load_offset(uint_t offset)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
pf_clear_offset_register()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
pf_check_vlan_tag(uint_t offset)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
pf_match_ethertype(uint_t ethertype)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
pf_match_ipnettype(uint_t type)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
pf_match_ibtype(uint_t type)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
pf_check_transport_protocol(uint_t transport_protocol)11452760Sdg199075 pf_check_transport_protocol(uint_t transport_protocol)
11462760Sdg199075 {
11478105SSebastien.Roy@Sun.COM int i;
11482760Sdg199075 uint_t number_of_matches = 0;
11492760Sdg199075
11508105SSebastien.Roy@Sun.COM for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) {
11512760Sdg199075 if (transport_protocol ==
11528105SSebastien.Roy@Sun.COM (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) {
11532760Sdg199075 number_of_matches++;
11548105SSebastien.Roy@Sun.COM dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol);
11552760Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
11568105SSebastien.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
pf_matchfn(const char * proto)11748105SSebastien.Roy@Sun.COM pf_matchfn(const char *proto)
11758023SPhil.Kirk@Sun.COM {
11768105SSebastien.Roy@Sun.COM int i;
11778105SSebastien.Roy@Sun.COM
11788105SSebastien.Roy@Sun.COM for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) {
11798105SSebastien.Roy@Sun.COM if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) {
11808105SSebastien.Roy@Sun.COM dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val);
11818105SSebastien.Roy@Sun.COM break;
11828105SSebastien.Roy@Sun.COM }
11838023SPhil.Kirk@Sun.COM }
11848023SPhil.Kirk@Sun.COM }
11858023SPhil.Kirk@Sun.COM
11868023SPhil.Kirk@Sun.COM static void
pf_primary()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");
1443*10639SDarren.Reed@Sun.COM pf_match_zone(dir, BE_32((uint32_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
pf_alternation()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
pf_expression()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
pf_compile(e,print)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;
15558105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ether_transport_mapping_table;
15568105SSebastien.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;
15718105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ib_transport_mapping_table;
15728105SSebastien.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;
15828105SSebastien.Roy@Sun.COM dl.dl_trans_map_tbl = ipnet_transport_mapping_table;
15838105SSebastien.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